一步一步构建的STM32工程

前篇

Linux下使用VSCode配置STM32的集成开发环境
解读startup_stm32f407xx.s和STM32F407x_FLASH.ld文件
解读STM32CubeMX生成的Makefile文件

一、所需的源文件

首先新建一个工程目录,把Makefile中编译用到的源文件先拷贝到工程目录下,具体工程目录的设置可以自行设置,但我这里就模仿STM32CubeMX创建的工程目录创建属于自己的工程目录。
请添加图片描述
请添加图片描述

二、所需的头文件

再把Makefile中编译用到的头文件先拷贝到工程目录下,根据头文件所在路径以及源文件所需的头文件选择所需的头文件

main.c ——》main.h
stm32f4xx_hal_msp.c——》main.h
stm32f4xx_it.c——》main.h、stm32f4xx_it.h
system_stm32f4xx.c——》stm32f4xx.h
stm32f4xx_hal.c——》stm32f4xx_hal.h    
stm32f4xx_hal_cortex.c——》stm32f4xx_hal.h
stm32f4xx_hal_dma.c——》stm32f4xx_hal.h
stm32f4xx_hal_dma_ex.c——》stm32f4xx_hal.h
stm32f4xx_hal_exti.c——》stm32f4xx_hal.h
stm32f4xx_hal_flash.c——》stm32f4xx_hal.h
stm32f4xx_hal_flash_ex.c——》stm32f4xx_hal.h
stm32f4xx_hal_flash_ramfunc.c——》stm32f4xx_hal.h
stm32f4xx_hal_gpio.c——》stm32f4xx_hal.h
stm32f4xx_hal_pwr.c——》stm32f4xx_hal.h
stm32f4xx_ha_pwr_ex.c——》stm32f4xx_hal.h
stm32f4xx_hal_rcc.c——》stm32f4xx_hal.h
stm32f4xx_hal_rcc_ex.c——》stm32f4xx_hal.h
stm32f4xx_hal_tim.c——》stm32f4xx_hal.h
stm32f4xx_hal_tim_ex.c——》stm32f4xx_hal.h

main.h——》stm32f4xx_hal.h
stm32f4xx_it.h——》None
stm32f4xx.h——》stm32f407xx.h、stm32f4xx_hal.h(因为定义了STM32F407xx和USE_HAL_DRIVER)
stm32f4xx_hal.h——》stm32f4xx_hal_conf.h

stm32f407xx.h——》core_m4.h、system_stm32f4xx.h、stdint.h
stm32f407_hal_conf.h——》stm32f4xx_hal_cortex.h、stm32f4xx_hal_dma.h、stm32f4xx_hal_dma_ex.h、stm32f4xx_hal_exti.h、stm32f4xx_hal_flash.h、stm32f4xx_hal_flash_ex.h、stm32f4xx_hal_flash_ramfunc.h、stm32f4xx_hal_gpio.h、stm32f4xx_hal_gpio_ex.h、stm32f4xx_hal_pwr.h、stm32f4xx_hal_pwr_ex.h、stm32f4xx_hal_rcc.h、stm32f4xx_hal_rcc_ex.h

core_m4.h——》cmsis_version.h、cmsis_compiler.h、mpu_armv7.h、stdint.h
system_stm32f4xx.h——》None
stm32f4xx_hal_def.h——》stm32f4xx.h、Legacy/stm32_hal_legacy.h、stddef.h

cmsis_version.h——》None
mpu_armv7.h——》None
cmsis_compiler.h——》cmsis_gcc.h、stdint.h
stm32_hal_legacy.h——》None

cmsis_gcc.h——》None

请添加图片描述
请添加图片描述

stdint.h和stddef.h头文件

在ARM GCC中,标准库通常位于<toolchain_install_path>/lib/gcc/arm-none-eabi/version/include目录下。其中<toolchain_install_path>是ARM GCC编译工具链的安装路径,version是GCC的版本号。

在编译过程中,ARM GCC会搜索标准库的路径,找到stdint.h和stddef.h文件并将其包含到编译环境中,以便编译器能够正确地识别和使用这些标准库头文件中的定义和类型。
请添加图片描述

三、配置c_cpp_properties.json文件

c_cpp_properties.json文件

——这里需要注意c_cpp_properites.json文件只是方便VS Code软件对整个工程进行检查分析,但不会影响工程的编译链接过程(编译链接过程不需要使用到这个文件);
——不对c_cpp_properites.json文件进行设置,打开源文件会报错;
——设置好c_cpp_properites.json文件后,打开每个源文件就不会报错;
——设置好c_cpp_properites.json文件后,也能跳转到stddef.h和stdint.h文件
(注意defines、compilerPath和intelliSenseMode字段的设置)

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "USE_HAL_DRIVER",
                "STM32F407xx"
            ],
            "compilerPath": "/usr/local/arm/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc",
            "cStandard": "c11",
            "cppStandard": "c++98",
            "intelliSenseMode": "gcc-arm"
        }
    ],
    "version": 4
}

请添加图片描述
请添加图片描述

workspace.json文件

把整个文件夹保存为工作区后,会生成一个workspace.json文件

{
	"folders": [
		{
			"path": ".."
		}
	],
	"settings": {
		"files.associations": {
			"stddef.h": "c",
			"stdint.h": "c",
		}
	}
}

到这一步时的工程目录

请添加图片描述
请添加图片描述

四、添加.s启动文件

/* 告诉汇编器使用统一的语法规则 */
.syntax unified
/* 指定目标处理器为Cortex-M4 */
.cpu cortex-m4
/* 指定浮点运算单元为SoftVFP */
.fpu softvfp
/* 指定使用thumb指令集 */
.thumb

/* 定义全局符号ptfVectors */
.global ptfVectors
/* 定义全局符号Default_Handler */
.global Default_Handler

/* .word是ARM汇编语言的一个伪指令,用于声明一个32位的数据项 */
/* .data section的初始化值的起始地址,在链接脚本中定义 */
.word _sidata
/* .data section的起始地址,在链接脚本中定义 */
.word _sdata
/* .data section的结束地址,在链接脚本中定义 */
.word _edata
/* .bss section的起始地址,在链接脚本中定义 */
.word _sbss
/* .bss section的结束地址,在链接脚本中定义 */
.word _ebss

/* 创建一个代码段(.text)的子节,名为Reset_Handler */
.section .text.Reset_Handler
/* 声明Reset_Handler为弱符号 */
.weak Reset_Handler
/* 声明Reset_Handler为函数类型 */
.type Reset_Handler, %function
Reset_Handler:
    ldr sp, =_estack        /* 设置堆栈指针 */

/* 将数据段初始化程序从Flash复制到SRAM */
    ldr r0, =_sdata         /* 将_sdata的值存入r0 */
    ldr r1, =_edata         /* 将_edata的值存入r1 */
    ldr r2, =_sidata        /* 将_sidata的值存入r2 */
    movs r3, #0             /* 将立即数0存入r3 */
    b LoopCopyDataInit      /* 跳转到LoopCopyDataInit */

CopyDataInit:
    ldr r4, [r2,r3]         /* (r2的值加上r3的值)对应内存地址存放的值存入r4 */
    str r4, [r0,r3]         /* r4的值存入(r0的值加上r3的值)对应内存地址 */
    adds r3, r3, #4         /* 将r3的值加4存入r3 */

LoopCopyDataInit:   
    adds r4, r0, r3         /* 将r0的值和r3的值相加存入r4 */
    cmp r4, r1              /* 比较r4和r1的值,改变CPSR寄存器的标志位 */
    bcc CopyDataInit        /* 当r4比r1小时,发生跳转 */

    
/* 零填充bss段 */
    ldr r2, =_sbss
    ldr r4, =_ebss
    movs r3, #0
    b LoopFillZerobss

FillZerobss:
    str r3, [r2]
    adds r2, r2, #4

LoopFillZerobss:
    cmp r2, r4
    bcc FillZerobss

/* 调用时钟系统初始化函数 */
bl SystemInit
/* 调用静态构造函数 */
bl __libc_init_array
/* 调用应用程序的入口 */
bl main
/* bl指令将返回地址保存到lr寄存器中,然后跳转到指定的地址执行代码 */
/* bx指令跳转到保存到lr寄存器中的返回地址,继续执行原来的代码 */
bx lr
.size Reset_Handler, .-Reset_Handler




/* 创建一个代码段(.text)的子节Default_Handler,"a"表示该段是可分配的,"x"表示该段是可执行的,%progbits表示该段包含程序代码或数据 */
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
    b Infinite_Loop
.size Default_Handler, .-Default_Handler


/* 创建一个.isr_vector的段,"a"表示该段是可分配的,%progbits表示该段包含程序代码或数据 */
.section .isr_vector,"a",%progbits
/* 声明ptfVectors为对象类型 */
.type ptfVectors, %object

ptfVectors:
    .word _estack                           
    .word Reset_Handler                         /* Reset */
    .word NMI_Handler                           /* Non maskable interrupt */
    .word HardFault_Handler                     /* All class of fault */
    .word MemManage_Handler                     /* Memory management */
    .word BusFault_Handler                      /* Pre-fetch fault,memory access fault */
    .word UsageFault_Handler                    /* Undefined instruction or illegal state */
    .word 0
    .word 0
    .word 0
    .word 0
    .word SVC_Handler                           /* System service call via SWI instruction */
    .word DebugMon_Handler                      /* Debug Monitor */
    .word 0 
    .word PendSV_Handler                        /* Pendable request for system service */
    .word SysTick_Handler                       /* System tick timer */

    /* 外部中断 */
    .word     WWDG_IRQHandler                   /* Window WatchDog              */                                        
    .word     PVD_IRQHandler                    /* PVD through EXTI Line detection */                        
    .word     TAMP_STAMP_IRQHandler             /* Tamper and TimeStamps through the EXTI line */            
    .word     RTC_WKUP_IRQHandler               /* RTC Wakeup through the EXTI line */                      
    .word     FLASH_IRQHandler                  /* FLASH                        */                                          
    .word     RCC_IRQHandler                    /* RCC                          */                                            
    .word     EXTI0_IRQHandler                  /* EXTI Line0                   */                        
    .word     EXTI1_IRQHandler                  /* EXTI Line1                   */                          
    .word     EXTI2_IRQHandler                  /* EXTI Line2                   */                          
    .word     EXTI3_IRQHandler                  /* EXTI Line3                   */                          
    .word     EXTI4_IRQHandler                  /* EXTI Line4                   */                          
    .word     DMA1_Stream0_IRQHandler           /* DMA1 Stream 0                */                  
    .word     DMA1_Stream1_IRQHandler           /* DMA1 Stream 1                */                   
    .word     DMA1_Stream2_IRQHandler           /* DMA1 Stream 2                */                   
    .word     DMA1_Stream3_IRQHandler           /* DMA1 Stream 3                */                   
    .word     DMA1_Stream4_IRQHandler           /* DMA1 Stream 4                */                   
    .word     DMA1_Stream5_IRQHandler           /* DMA1 Stream 5                */                   
    .word     DMA1_Stream6_IRQHandler           /* DMA1 Stream 6                */                   
    .word     ADC_IRQHandler                    /* ADC1, ADC2 and ADC3s         */                   
    .word     CAN1_TX_IRQHandler                /* CAN1 TX                      */                         
    .word     CAN1_RX0_IRQHandler               /* CAN1 RX0                     */                          
    .word     CAN1_RX1_IRQHandler               /* CAN1 RX1                     */                          
    .word     CAN1_SCE_IRQHandler               /* CAN1 SCE                     */                          
    .word     EXTI9_5_IRQHandler                /* External Line[9:5]s          */                          
    .word     TIM1_BRK_TIM9_IRQHandler          /* TIM1 Break and TIM9          */         
    .word     TIM1_UP_TIM10_IRQHandler          /* TIM1 Update and TIM10        */         
    .word     TIM1_TRG_COM_TIM11_IRQHandler     /* TIM1 Trigger and Commutation and TIM11 */
    .word     TIM1_CC_IRQHandler                /* TIM1 Capture Compare         */                          
    .word     TIM2_IRQHandler                   /* TIM2                         */                   
    .word     TIM3_IRQHandler                   /* TIM3                         */                   
    .word     TIM4_IRQHandler                   /* TIM4                         */                   
    .word     I2C1_EV_IRQHandler                /* I2C1 Event                   */                          
    .word     I2C1_ER_IRQHandler                /* I2C1 Error                   */                          
    .word     I2C2_EV_IRQHandler                /* I2C2 Event                   */                          
    .word     I2C2_ER_IRQHandler                /* I2C2 Error                   */                            
    .word     SPI1_IRQHandler                   /* SPI1                         */                   
    .word     SPI2_IRQHandler                   /* SPI2                         */                   
    .word     USART1_IRQHandler                 /* USART1                       */                   
    .word     USART2_IRQHandler                 /* USART2                       */                   
    .word     USART3_IRQHandler                 /* USART3                       */                   
    .word     EXTI15_10_IRQHandler              /* External Line[15:10]s        */                          
    .word     RTC_Alarm_IRQHandler              /* RTC Alarm (A and B) through EXTI Line */                 
    .word     OTG_FS_WKUP_IRQHandler            /* USB OTG FS Wakeup through EXTI line */                       
    .word     TIM8_BRK_TIM12_IRQHandler         /* TIM8 Break and TIM12         */         
    .word     TIM8_UP_TIM13_IRQHandler          /* TIM8 Update and TIM13        */         
    .word     TIM8_TRG_COM_TIM14_IRQHandler     /* TIM8 Trigger and Commutation and TIM14 */
    .word     TIM8_CC_IRQHandler                /* TIM8 Capture Compare         */                          
    .word     DMA1_Stream7_IRQHandler           /* DMA1 Stream7                 */                          
    .word     FSMC_IRQHandler                   /* FSMC                         */                   
    .word     SDIO_IRQHandler                   /* SDIO                         */                   
    .word     TIM5_IRQHandler                   /* TIM5                         */                   
    .word     SPI3_IRQHandler                   /* SPI3                         */                   
    .word     UART4_IRQHandler                  /* UART4                        */                   
    .word     UART5_IRQHandler                  /* UART5                        */                   
    .word     TIM6_DAC_IRQHandler               /* TIM6 and DAC1&2 underrun errors */                   
    .word     TIM7_IRQHandler                   /* TIM7                         */
    .word     DMA2_Stream0_IRQHandler           /* DMA2 Stream 0                */                   
    .word     DMA2_Stream1_IRQHandler           /* DMA2 Stream 1                */                   
    .word     DMA2_Stream2_IRQHandler           /* DMA2 Stream 2                */                   
    .word     DMA2_Stream3_IRQHandler           /* DMA2 Stream 3                */                   
    .word     DMA2_Stream4_IRQHandler           /* DMA2 Stream 4                */                   
    .word     ETH_IRQHandler                    /* Ethernet                     */                   
    .word     ETH_WKUP_IRQHandler               /* Ethernet Wakeup through EXTI line */                     
    .word     CAN2_TX_IRQHandler                /* CAN2 TX                      */                          
    .word     CAN2_RX0_IRQHandler               /* CAN2 RX0                     */                          
    .word     CAN2_RX1_IRQHandler               /* CAN2 RX1                     */                          
    .word     CAN2_SCE_IRQHandler               /* CAN2 SCE                     */                          
    .word     OTG_FS_IRQHandler                 /* USB OTG FS                   */                   
    .word     DMA2_Stream5_IRQHandler           /* DMA2 Stream 5                */                   
    .word     DMA2_Stream6_IRQHandler           /* DMA2 Stream 6                */                   
    .word     DMA2_Stream7_IRQHandler           /* DMA2 Stream 7                */                   
    .word     USART6_IRQHandler                 /* USART6                       */                    
    .word     I2C3_EV_IRQHandler                /* I2C3 event                   */                          
    .word     I2C3_ER_IRQHandler                /* I2C3 error                   */                          
    .word     OTG_HS_EP1_OUT_IRQHandler         /* USB OTG HS End Point 1 Out   */                   
    .word     OTG_HS_EP1_IN_IRQHandler          /* USB OTG HS End Point 1 In    */                   
    .word     OTG_HS_WKUP_IRQHandler            /* USB OTG HS Wakeup through EXTI */                         
    .word     OTG_HS_IRQHandler                 /* USB OTG HS                   */                   
    .word     DCMI_IRQHandler                   /* DCMI                         */                   
    .word     0                                 /* CRYP crypto                  */                   
    .word     HASH_RNG_IRQHandler               /* Hash and Rng                 */
    .word     FPU_IRQHandler                    /* FPU                          */



    /* .thumb_set symbol,value 用于为value取一个别名 */
    .weak      NMI_Handler
    .thumb_set NMI_Handler,Default_Handler
    
    .weak      HardFault_Handler
    .thumb_set HardFault_Handler,Default_Handler
    
    .weak      MemManage_Handler
    .thumb_set MemManage_Handler,Default_Handler
    
    .weak      BusFault_Handler
    .thumb_set BusFault_Handler,Default_Handler

    .weak      UsageFault_Handler
    .thumb_set UsageFault_Handler,Default_Handler

    .weak      SVC_Handler
    .thumb_set SVC_Handler,Default_Handler

    .weak      DebugMon_Handler
    .thumb_set DebugMon_Handler,Default_Handler

    .weak      PendSV_Handler
    .thumb_set PendSV_Handler,Default_Handler

    .weak      SysTick_Handler
    .thumb_set SysTick_Handler,Default_Handler              
    
    .weak      WWDG_IRQHandler                   
    .thumb_set WWDG_IRQHandler,Default_Handler      
                    
    .weak      PVD_IRQHandler      
    .thumb_set PVD_IRQHandler,Default_Handler
                
    .weak      TAMP_STAMP_IRQHandler            
    .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
                
    .weak      RTC_WKUP_IRQHandler                  
    .thumb_set RTC_WKUP_IRQHandler,Default_Handler
                
    .weak      FLASH_IRQHandler         
    .thumb_set FLASH_IRQHandler,Default_Handler
                    
    .weak      RCC_IRQHandler      
    .thumb_set RCC_IRQHandler,Default_Handler
                    
    .weak      EXTI0_IRQHandler         
    .thumb_set EXTI0_IRQHandler,Default_Handler
                    
    .weak      EXTI1_IRQHandler         
    .thumb_set EXTI1_IRQHandler,Default_Handler
                        
    .weak      EXTI2_IRQHandler         
    .thumb_set EXTI2_IRQHandler,Default_Handler 
                    
    .weak      EXTI3_IRQHandler         
    .thumb_set EXTI3_IRQHandler,Default_Handler
                            
    .weak      EXTI4_IRQHandler         
    .thumb_set EXTI4_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream0_IRQHandler               
    .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
            
    .weak      DMA1_Stream1_IRQHandler               
    .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream2_IRQHandler               
    .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream3_IRQHandler               
    .thumb_set DMA1_Stream3_IRQHandler,Default_Handler 
                    
    .weak      DMA1_Stream4_IRQHandler              
    .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream5_IRQHandler               
    .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream6_IRQHandler               
    .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
                    
    .weak      ADC_IRQHandler      
    .thumb_set ADC_IRQHandler,Default_Handler
                
    .weak      CAN1_TX_IRQHandler   
    .thumb_set CAN1_TX_IRQHandler,Default_Handler
                
    .weak      CAN1_RX0_IRQHandler                  
    .thumb_set CAN1_RX0_IRQHandler,Default_Handler
                            
    .weak      CAN1_RX1_IRQHandler                  
    .thumb_set CAN1_RX1_IRQHandler,Default_Handler
                
    .weak      CAN1_SCE_IRQHandler                  
    .thumb_set CAN1_SCE_IRQHandler,Default_Handler
                
    .weak      EXTI9_5_IRQHandler   
    .thumb_set EXTI9_5_IRQHandler,Default_Handler
                
    .weak      TIM1_BRK_TIM9_IRQHandler            
    .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
                
    .weak      TIM1_UP_TIM10_IRQHandler            
    .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
        
    .weak      TIM1_TRG_COM_TIM11_IRQHandler      
    .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
        
    .weak      TIM1_CC_IRQHandler   
    .thumb_set TIM1_CC_IRQHandler,Default_Handler
                    
    .weak      TIM2_IRQHandler            
    .thumb_set TIM2_IRQHandler,Default_Handler
                    
    .weak      TIM3_IRQHandler            
    .thumb_set TIM3_IRQHandler,Default_Handler
                    
    .weak      TIM4_IRQHandler            
    .thumb_set TIM4_IRQHandler,Default_Handler
                    
    .weak      I2C1_EV_IRQHandler   
    .thumb_set I2C1_EV_IRQHandler,Default_Handler
                        
    .weak      I2C1_ER_IRQHandler   
    .thumb_set I2C1_ER_IRQHandler,Default_Handler
                        
    .weak      I2C2_EV_IRQHandler   
    .thumb_set I2C2_EV_IRQHandler,Default_Handler
                    
    .weak      I2C2_ER_IRQHandler   
    .thumb_set I2C2_ER_IRQHandler,Default_Handler
                            
    .weak      SPI1_IRQHandler            
    .thumb_set SPI1_IRQHandler,Default_Handler
                            
    .weak      SPI2_IRQHandler            
    .thumb_set SPI2_IRQHandler,Default_Handler
                    
    .weak      USART1_IRQHandler      
    .thumb_set USART1_IRQHandler,Default_Handler
                        
    .weak      USART2_IRQHandler      
    .thumb_set USART2_IRQHandler,Default_Handler
                        
    .weak      USART3_IRQHandler      
    .thumb_set USART3_IRQHandler,Default_Handler
                    
    .weak      EXTI15_10_IRQHandler               
    .thumb_set EXTI15_10_IRQHandler,Default_Handler
                
    .weak      RTC_Alarm_IRQHandler               
    .thumb_set RTC_Alarm_IRQHandler,Default_Handler
                
    .weak      OTG_FS_WKUP_IRQHandler         
    .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
                
    .weak      TIM8_BRK_TIM12_IRQHandler         
    .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
            
    .weak      TIM8_UP_TIM13_IRQHandler            
    .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
            
    .weak      TIM8_TRG_COM_TIM14_IRQHandler      
    .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
        
    .weak      TIM8_CC_IRQHandler   
    .thumb_set TIM8_CC_IRQHandler,Default_Handler
                    
    .weak      DMA1_Stream7_IRQHandler               
    .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
                        
    .weak      FSMC_IRQHandler            
    .thumb_set FSMC_IRQHandler,Default_Handler
                        
    .weak      SDIO_IRQHandler            
    .thumb_set SDIO_IRQHandler,Default_Handler
                     
    .weak      TIM5_IRQHandler            
    .thumb_set TIM5_IRQHandler,Default_Handler
                     
    .weak      SPI3_IRQHandler            
    .thumb_set SPI3_IRQHandler,Default_Handler
                        
    .weak      UART4_IRQHandler         
    .thumb_set UART4_IRQHandler,Default_Handler
                    
    .weak      UART5_IRQHandler         
    .thumb_set UART5_IRQHandler,Default_Handler
                    
    .weak      TIM6_DAC_IRQHandler                  
    .thumb_set TIM6_DAC_IRQHandler,Default_Handler
                
    .weak      TIM7_IRQHandler            
    .thumb_set TIM7_IRQHandler,Default_Handler
            
    .weak      DMA2_Stream0_IRQHandler               
    .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
                
    .weak      DMA2_Stream1_IRQHandler               
    .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
                    
    .weak      DMA2_Stream2_IRQHandler               
    .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
                
    .weak      DMA2_Stream3_IRQHandler               
    .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
                
    .weak      DMA2_Stream4_IRQHandler               
    .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
                
    .weak      ETH_IRQHandler      
    .thumb_set ETH_IRQHandler,Default_Handler
                    
    .weak      ETH_WKUP_IRQHandler                  
    .thumb_set ETH_WKUP_IRQHandler,Default_Handler
                
    .weak      CAN2_TX_IRQHandler   
    .thumb_set CAN2_TX_IRQHandler,Default_Handler
                            
    .weak      CAN2_RX0_IRQHandler                  
    .thumb_set CAN2_RX0_IRQHandler,Default_Handler
                            
    .weak      CAN2_RX1_IRQHandler                  
    .thumb_set CAN2_RX1_IRQHandler,Default_Handler
                            
    .weak      CAN2_SCE_IRQHandler                  
    .thumb_set CAN2_SCE_IRQHandler,Default_Handler
                            
    .weak      OTG_FS_IRQHandler      
    .thumb_set OTG_FS_IRQHandler,Default_Handler
                        
    .weak      DMA2_Stream5_IRQHandler               
    .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
                    
    .weak      DMA2_Stream6_IRQHandler               
    .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
                    
    .weak      DMA2_Stream7_IRQHandler               
    .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
                    
    .weak      USART6_IRQHandler      
    .thumb_set USART6_IRQHandler,Default_Handler
                            
    .weak      I2C3_EV_IRQHandler   
    .thumb_set I2C3_EV_IRQHandler,Default_Handler
                            
    .weak      I2C3_ER_IRQHandler   
    .thumb_set I2C3_ER_IRQHandler,Default_Handler
                            
    .weak      OTG_HS_EP1_OUT_IRQHandler         
    .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
                
    .weak      OTG_HS_EP1_IN_IRQHandler            
    .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
                
    .weak      OTG_HS_WKUP_IRQHandler         
    .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
                
    .weak      OTG_HS_IRQHandler      
    .thumb_set OTG_HS_IRQHandler,Default_Handler
                    
    .weak      DCMI_IRQHandler            
    .thumb_set DCMI_IRQHandler,Default_Handler
                                    
    .weak      HASH_RNG_IRQHandler                  
    .thumb_set HASH_RNG_IRQHandler,Default_Handler   

    .weak      FPU_IRQHandler                  
    .thumb_set FPU_IRQHandler,Default_Handler

/* 声明ptfVectors这个符号的大小就是从ptfVectors符号的位置到.所指向的位置之间的字节数 */
/* .首先指向ptfVectors符号的位置,随着数据的写入,.的位置向后移动 */
.size ptfVectors, .-ptfVectors

五、添加.ld链接脚本

/* 程序运行的入口点 */
ENTRY(Reset_Handler)

/* 用户模式栈的最高地址 */
/* _estack在启动文件中定义 */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* RAM的末尾地址 */
_Min_Heap_Size = 0x200;     /* 需要的堆空间大小 */
_Min_Stack_Size = 0x400;    /* 需要的栈空间大小 */

/* 指定内存区域 */
MEMORY
{
RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw)    : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K 
}

/* 定义各个程序段 */
SECTIONS
{
    /* 启动代码 */
    .isr_vector :
    {
        . = ALIGN(4);           /* .代表当前地址 ALIGN(4)代表4字节地址对齐*/
        KEEP(*(.isr_vector))    /* KEEP指示链接器保留指定的段,*代表匹配所有输入段,(.isr_vector)是要匹配的段名 */
        . = ALIGN(4);             
    } >FLASH                    /* >代表存储到哪个区域 */

    /* 程序代码和其他数据 */
    .text :
    {
        . = ALIGN(4); 
        *(.text)                /* 匹配.text段,不使用KEEP链接器指令,可能被优化掉 */
        *(.text*)               /* 匹配.text*段,这里的*代表通配符 */
        *(.glue_7)              /* 匹配.glue_7段,.glue_7段是从ARM模式切换到Thumb模式的代码 */
        *(.glue_7t)             /* 匹配.glue_7t段,.glue_7t段是从Thumb模式切换到ARM模式的代码 */
        *(.eh_frame)            /* 匹配.eh_frame段,.eh_frame段通常包含异常处理所需的信息 */
        
        KEEP(*(.init))          /* 匹配.init段,.init段包含程序初始化代码 */
        KEEP(*(.fini))          /* 匹配.fini段,.fini段包含程序终止代码 */

        . = ALIGN(4);   
        _etext = .;             /* 定义一个全局符号表示.text段的末尾地址 */
    } >FLASH

    /* 常量数据 */
    .rodata :
    {
        . = ALIGN(4);        
        *(.rodata)              /* 匹配.rodata段 */
        *(.rodata*)             /* 匹配.rodata*段 */
        . = ALIGN(4);
    } >FLASH 

    /* 将所有名称以 .ARM.extab 或 .gnu.linkonce.armextab. 开头的输入段
    合并到一个名为 .ARM.extab 的输出段,并将该输出段放置在 FLASH 内存区域。*/
    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*) /* .ARM.extab*和.gnu.linkonce.armextab.*段是与ARM架构的异常处理表相关的代码和数据 */
    } >FLASH
    .ARM :
    {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
    } >FLASH

    .preinit_array :
    {
        PROVIDE_HIDDEN (__preinit_array_start = .);/* PROVIDE_HIDDEN用于定义一个符号并将该符号标记为隐藏的 */
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
    } >FLASH
    .init_array :
    {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
    } >FLASH
    .fini_array :
    {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(SORT(.fini_array.*)))
        KEEP (*(.fini_array*))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >FLASH

    _sidata = LOADADDR(.data);      /* _sidata指的是.data段被加载到RAM区域后的首地址 */

    /* 初始化数据 */
    .data :
    {
        . = ALIGN(4);
        _sdata = .;
        *(.data)                    /* 匹配.data段 */
        *(.data*)                   /* 匹配.data*段 */
        . = ALIGN(4);
        _edata = .;
    } >RAM AT> FLASH                /* 表示该段存储在FLASH区域,但运行时被加载到RAM区域,该加载操作是在.s启动文件中执行的 */

    _siccmram = LOADADDR(.ccmram);

    .ccmram :
    {
        . = ALIGN(4);
        _sccmram = .;
        *(.ccmram)
        *(.ccmram*)
        . = ALIGN(4);
        _eccmram = .;
    } >CCMRAM AT> FLASH

    /* 未初始化数据 */
    .bss :
    {
        . = ALIGN(4);
        _sbss = .;
        __bss_start = _sbss;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
        __bss_end = _ebss;
    } >RAM

    /* 用于检查堆栈大小是否溢出RAM区域空间 */
    .user_heap_stack :
    {
        . = ALIGN(8);
        PROVIDE (end = .);
        PROVIDE (_end = .);
        . = . + _Min_Heap_Size;
        . = . + _Min_Stack_Size;
        . = ALIGN(8);
    } >RAM

    /* 将从libc.a、libm.a、libgcc.a标准库中移除的对象文件放入/DISCARD/段,链接器链接过程会忽略这个段 */
    /DISCARD/ :
    {
        libc.a (*)
        libm.a (*)
        libgcc.a (*)
    }

    /* 将.ARM.attributes段放在地址为0的位置 */
    .ARM.attributes 0 :
    {
        *(.ARM.attributes)

    }
}


/*
_estack
_etext
_sidata
_sdata
_edata
_sbss
_ebss

.isr_vector
.text
.rodata
.data
.ccmram
.bss
.user_heap_stack
*/

六、添加Makefile文件

1.修改TARGET变量

2.修改.c源文件和.s启动文件路径

3.修改头文件路径

4.修改.ld链接脚本路径

######################################
# target
######################################
# TARGET = 工程文件夹名
TARGET = Proof

#######################################
# build path
#######################################
# BUILD_DIR = 编译过程生成的文件存放的文件夹名
BUILD_DIR = build

######################################
# sources
######################################
# C sources
## "\"代表行继续;多个值之间需要使用空格或其他空白字符作为分隔符
C_SOURCES = \
Core/Src/main.c \
Core/Src/stm32f4xx_it.c \
Core/Src/stm32f4xx_hal_msp.c \
Core/Src/system_stm32f4xx.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c \

# ASM sources
ASM_SOURCES = \
startup.s

#######################################
# binaries
#######################################
# GCC工具链所在路径
# 1.可以通过GCC_PATH变量在make命令中定义,命令格式:make GCC_PATH=xxx
# 2.可以将其添加到PATH环境变量中
PREFIX = arm-none-eabi-
ifdef GCC_PATH
# 编译器
CC = $(GCC_PATH)/$(PREFIX)gcc
# 汇编器
## -x assembler-with-cpp选项,指示编译器先执行预处理,并将预处理后的代码进行汇编
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
# 从目标文件复制内容到另一个文件,如.elf文件生成.hex和.bin文件
CP = $(GCC_PATH)/$(PREFIX)objcopy
# 报告目标文件的大小
SZ = $(GCC_PATH)/$(PERFIX)size
else
# 编译器
CC = $(PREFIX)gcc
# 汇编器
AS = $(PREFIX)gcc -x assembler-with-cpp
# 从目标文件复制内容到另一个文件,如.elf文件生成.hex和.bin文件
CP = $(PREFIX)objcopy
# 报告目标文件的大小
SZ = $(PERFIX)size
endif
HEX = $(CP) -O ihex
## -S选项,移除符号表和调试信息,从而减小文件大小
BIN = $(CP) -O binary -S

#######################################
# FLAGS
#######################################
# cpu
CPU = -mcpu=cortex-m4

# instruction-set
INSTRUCTION-SET = -mthumb

# fpu
FPU = -mfpu=fpv4-sp-d16

# float-abi
FLOAT-ABI = -mfloat-abi=hard

# mcu
MCU = $(CPU) $(INSTRUCTION-SET) $(FPU) $(FLOAT-ABI)

# ASM defines
ASM_DEFS = 

# C defines
C_DEFS = \
-DUSE_HAL_DRIVER \
-DSTM32F407xx

# ASM includes
ASM_INCLUDES = 

# C includes
C_INCLUDES = \
-ICore/Inc \
-IDrivers/STM32F4xx_HAL_Driver/Inc \
-IDrivers/STM32F4xx_HAL_Driver/Inc/Legacy \
-IDrivers/CMSIS

# 是否要生成调试文件的标志
DEBUG = 1
# -O(即-O0)代表关闭编译器所有对代码的优化
OPT = -O

# compile flags
## -Wall选项,用于启用所有警告
## -fdata-sections/-ffunction-sections选项,将未使用的数据段、函数段放置在单独的数据段、函数段,在链接过程若未被使用,链接器可以将它们从可执行文件中删除
CFLAGS  = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

ifeq ($(DEBUG),1)
# -g:用于告诉编译器生成调试信息
# -gdwarf-2:用于指定生成调试信息的格式,DWARF是一种用于表示调试信息的标准格式
# -gdwarf-2表示使用DWARF-2版本的格式来生成调试信息
CFLAGS += -g -gdwarf-2
endif

# Generate dependency information
# -MMD:告诉编译器生成目标文件(.o文件)的同时,生成一个与之对应的依赖文件(.d文件)。依赖文件包含了目标文件所依赖的头文件信息
# -MP:告诉编译器为每个头文件生成一个伪目标规则。这样,即使某个头文件被删除了,make也不会因为找不到头文件而停止
# -MF:用于指定生成的依赖文件的名称
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

# assemble flags
# -Wa:表示将后续参数传递给汇编器进行处理
# -a:让汇编器生成汇编和源代码混合的文件
# -ad:让汇编器生成带有本地符号表的汇编代码文件
# -alms:指定生成带有扩展信息的汇编代码文件,并保存到指定路径
ASFLAGS = -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst))

#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = FLASH_SRAM.ld

# libraries
# -lc:链接C标准库
# -lm:链接数学库
# -lnosys:不链接操作系统相关功能的库
LIBS = -lc -lm -lnosys
LIBDIR = 
# -specs=nano.specs:告诉链接器使用nano版本的规范文件,这些文件定义了链接器如何处理程序的内存布局和运行时功能
# -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref 生成一个目标文件映射(map)文件,并通过 -Wl,--cref 选项生成有关交叉引用信息的报告。
# -Wl,--gc-sections 通过此选项告诉链接器进行无用代码剪裁,以减小最终可执行文件的大小。
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections


# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
#######################################
# build the application
#######################################
# list of C program objects
# addprefix函数
# 用法:$(addprefix <prefix>,<names...>)
# 功能:把前缀<prefix>加到<names>中的每个字符串前面
# 返回:加过前缀的文件名序列
# 示例:$(addprefix src/,foo bar) 返回值是src/foo src/bar
# notdir函数
# 用法:$(nordir <names...>)
# 功能:从文件名序列<names>中取出非目录部分
# 返回:文件名序列<names>的非目录部分
# 示例:$(notdir src/foo.c hacks) 返回值是foo.c hacks
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
# vpath特殊变量
# 功能:给make工具指定文件的搜索路径

# sort函数
# 用法:$(sort <list>)
# 功能:给字符串<list>中的单词排序,并去掉相同的单词
# 返回:排序后的字符串
# 示例:$(sort foo bar lost) 返回值是bar foo lost
# dir函数
# 用法:$(dir <names...>)
# 功能:从文件名序列<names>中取出目录部分
# 返回:文件名序列<names>的目录部分
# 示例:$(dir src/foo.c hacks) 返回值是src/ ./
vpath %.c $(sort $(dir $(C_SOURCES))) 
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	$(SZ) $@

# | $(BUILD_DIR) 表示当构建目标文件 $(BUILD_DIR)/%.o 时,$(BUILD_DIR) 是一个延迟依赖项。
# 这意味着在构建目标文件之前,会首先检查构建目录 $(BUILD_DIR) 是否存在,但构建目录的更新不会触发重新构建目标文件。这在确保构建目录存在的同时,避免了不必要的重新编译。
# 例如,如果 $(BUILD_DIR)/%.o: %.c Makefile 规则中只指定了 .c 文件和 Makefile 作为依赖项,当 .c 文件和 Makefile 更新时都会触发重新编译对应的目标文件。
# 而通过添加 | $(BUILD_DIR) 来延迟对构建目录的依赖性(只检查是否存在),可以确保当构建目录不存在或需要创建新的目录时才进行操作,并避免了不必要的重新编译。

# $(CC)是一个变量,表示编译器的路径
# -c是编译器选项,表示只进行编译而不进行链接
# $(CFLAGS)是传递给编译器的
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) $(ASFLAGS) $< -o $@
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
	$(AS) -c $(CFLAGS) $< -o $@

$(BUILD_DIR):
	mkdir $@

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@

$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@

# #######################################
# # clean up
# #######################################
clean:
	-rm -rf $(BUILD_DIR)


#######################################
# dependencies
#######################################
# 这句命令是在 makefile 中用于包含所有生成的依赖文件。以便 make 工具能够正确地处理依赖关系。
# $(wildcard $(BUILD_DIR)/*.d):这是一个 makefile 的函数,用于匹配 $(BUILD_DIR) 目录下所有的 .d 文件。$(BUILD_DIR) 是一个变量,通常用于指定生成的目标文件和依赖文件的目录。
# -include:这是一个 makefile 的指令,用于包含指定的依赖文件。加上 - 前缀表示即使这些依赖文件不存在,也不会导致 make 失败。

-include $(wildcard $(BUILD_DIR)/*.d)

七、编译、烧录、调试

1.编译

在当前文件夹下新建终端,输入make
请添加图片描述
请添加图片描述
仔细比对原先工程和此工程的编译结果text、data、bss、dec和hex的数值会发现有细微差别,是因为此工程我设置了关闭编译器所有对代码的优化!!!!
请添加图片描述

2.烧录

首先烧录器连上STM32,另外单独打开一个终端,输入以下指令:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg
回到VS Code的内置终端,分别输入:
program hex文件的绝对路径
reset
exit

3.调试

在VS Code内置终端,分别输入,可以进行调试
arm-none-eabi-gdb elf文件的路径
target remote localhost:3333

八、配置tasks.json和launch.json文件

1.tasks.json文件

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "shell",
			"label": "Build",
			"command": "/usr/bin/make",
			"args": [],
			"options": {
				"cwd": "${workspaceFolder}"
			},
			"group": {
				"kind": "build",
				"isDefault": true
			},
			"detail": "编译器: make",
			"problemMatcher": []
		},
	]
}

2.launch.json文件(修改程序可执行文件路径)

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
            {
                    "name":"ARM Debug",
                    "cwd":"${workspaceFolder}",
                    "request":"launch",
                    "type":"cppdbg",
                    "miDebuggerPath": "/usr/local/arm/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb",
                    "program":"${workspaceFolder}/build/Proof.elf",
                    "targetArchitecture": "arm",
                    "setupCommands": [
                            {
                                    "text":"file '${workspaceFolder}/build/Proof.elf'"
                            },
                            {
                                    "text":"target remote localhost:3333"
                            },
                            {
                                    "text":"monitor reset"
                            },
                            {
                                    "text":"monitor halt"
                            },
                            {
                                    "text":"load"
                            },
                    ]
            },
    ]
}

八、填坑

1.在.s启动文件里,汇编器不支持分号作为注释符号

错误写法

;告诉汇编器使用统一的语法规则
.syntax unified
;指定目标处理器为Cortex-M4
.cpu cortex-m4
;指定浮点运算单元为SoftVFP
.fpu softvfp
;指定使用thumb指令集
.thumb

;定义全局符号ptfVectors
.global ptfVectors
;定义全局符号Default_Handler
.global Default_Handler

正确写法

/* 告诉汇编器使用统一的语法规则 */
.syntax unified
/* 指定目标处理器为Cortex-M4 */
.cpu cortex-m4
/* 指定浮点运算单元为SoftVFP */
.fpu softvfp
/* 指定使用thumb指令集 */
.thumb

/* 定义全局符号ptfVectors */
.global ptfVectors
/* 定义全局符号Default_Handler */
.global Default_Handler

最后

到此完成了整个工程的构建,代码是可以成功烧录的;我也把.s文件、.ld文件和Makefile文件的内容都写在上面了,需要这个工程的下载链接的话私信我!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值