FreeRTOS 第二课(启动文件分析)

1. 简介:

对 stm32f103 工程的分析,需要从启动文件开始
2. 固件库中 stm32f103 的启动文件: 文件的名字:startup_stm32f10xhd.s
前边是段的声明

MODULE?cstartup; ; Forward declaration of sections. SECTION CSTACK:DATA:NOROOT(3)SECTION .intvec:CODE:NOROOT(2)EXTERN__iar_program_start EXTERNSystemInit PUBLIC__vector_table



【1】MODULE 控制指令是用来标记 modules 源码的开始和结束,后边的 ?cstartup 是模块的名字,此文档的最后的 END 表明模块的结束
【2】SECTION 指令是声明段,一个段不能同时包含 public symbol 和 pubweak symbol ,模块只有在相同的名字的模块没有被链接进来的时候才会被链接进来。
语法格式:SECTION section:type [flag] [(align)]
align,是用于指定地址对齐到 2^align,他的取值是 0 到 30
flag,取值NOROOT、ROOT、REORDER、NOREORDER,默认是ROOT,NOROOT表示如果这个段中的符号没有被引用,将会被连接器舍弃,即可被优化。ROOT表示不可被优化。REORDER表示开始一个新的名字是 section 的段(section),NOREORDER表示开始一个新的名字为 section 的片段(fragment),多个片段组成一个段(section)
type,memory 的类型,取值是 CODE、CONST、DATA
section,段的名字
【3】EXTERN 用导入其他模块的 symbol(符号)
【4】PUBLIC 导出 symbol(符号)



DATA__vector_table DCDsfe(CSTACK) DCDReset_Handler; Reset Handler DCDNMI_Handler; NMI Handler DCDHardFault_Handler; Hard Fault Handler DCDMemManage_Handler; MPU Fault Handler DCDBusFault_Handler; Bus Fault Handler DCDUsageFault_Handler; Usage Fault Handler DCD0; Reserved DCD0; Reserved DCD0; Reserved DCD0; Reserved DCDSVC_Handler; SVCall Handler DCDDebugMon_Handler; Debug Monitor Handler DCD0; Reserved DCDPendSV_Handler; PendSV Handler DCDSysTick_Handler; SysTick Handler; External Interrupts DCDWWDG_IRQHandler; Window Watchdog DCDPVD_IRQHandler; PVD through EXTI Line detect DCDTAMPER_IRQHandler; Tamper DCDRTC_IRQHandler; RTC DCDFLASH_IRQHandler; Flash DCDRCC_IRQHandler; RCC DCDEXTI0_IRQHandler; EXTI Line 0 DCDEXTI1_IRQHandler; EXTI Line 1 DCDEXTI2_IRQHandler; EXTI Line 2 DCDEXTI3_IRQHandler; EXTI Line 3 DCDEXTI4_IRQHandler; EXTI Line 4 DCDDMA1_Channel1_IRQHandler; DMA1 Channel 1 DCDDMA1_Channel2_IRQHandler; DMA1 Channel 2 DCDDMA1_Channel3_IRQHandler; DMA1 Channel 3 DCDDMA1_Channel4_IRQHandler; DMA1 Channel 4 DCDDMA1_Channel5_IRQHandler; DMA1 Channel 5 DCDDMA1_Channel6_IRQHandler; DMA1 Channel 6 DCDDMA1_Channel7_IRQHandler; DMA1 Channel 7 DCDADC1_2_IRQHandler; ADC1 & ADC2 DCDUSB_HP_CAN1_TX_IRQHandler; USB High Priority or CAN1 TX DCDUSB_LP_CAN1_RX0_IRQHandler ; USB LowPriority or CAN1 RX0 DCDCAN1_RX1_IRQHandler; CAN1 RX1 DCDCAN1_SCE_IRQHandler; CAN1 SCE DCDEXTI9_5_IRQHandler; EXTI Line 9..5 DCDTIM1_BRK_IRQHandler; TIM1 Break DCDTIM1_UP_IRQHandler; TIM1 Update DCDTIM1_TRG_COM_IRQHandler; TIM1 Trigger and Commutation DCDTIM1_CC_IRQHandler; TIM1 Capture Compare DCDTIM2_IRQHandler; TIM2 DCDTIM3_IRQHandler; TIM3 DCDTIM4_IRQHandler; TIM4 DCDI2C1_EV_IRQHandler; I2C1 Event DCDI2C1_ER_IRQHandler; I2C1 Error DCDI2C2_EV_IRQHandler; I2C2 Event DCDI2C2_ER_IRQHandler; I2C2 Error DCDSPI1_IRQHandler; SPI1 DCDSPI2_IRQHandler; SPI2 DCDUSART1_IRQHandler; USART1 DCDUSART2_IRQHandler; USART2 DCDUSART3_IRQHandler; USART3 DCDEXTI15_10_IRQHandler; EXTI Line 15..10 DCDRTCAlarm_IRQHandler; RTC Alarm through EXTI Line DCDUSBWakeUp_IRQHandler; USB Wakeup from suspend DCDTIM8_BRK_IRQHandler; TIM8 Break DCDTIM8_UP_IRQHandler; TIM8 Update DCDTIM8_TRG_COM_IRQHandler; TIM8 Trigger and Commutation DCDTIM8_CC_IRQHandler; TIM8 Capture Compare DCDADC3_IRQHandler; ADC3 DCDFSMC_IRQHandler; FSMC DCDSDIO_IRQHandler; SDIO DCDTIM5_IRQHandler; TIM5 DCDSPI3_IRQHandler; SPI3 DCDUART4_IRQHandler; UART4 DCDUART5_IRQHandler; UART5 DCDTIM6_IRQHandler; TIM6 DCDTIM7_IRQHandler; TIM7 DCDDMA2_Channel1_IRQHandler; DMA2 Channel1 DCDDMA2_Channel2_IRQHandler; DMA2 Channel2 DCDDMA2_Channel3_IRQHandler; DMA2 Channel3 DCDDMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5 ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

【1】DATA 表示下边中的标签是 32 位的标签,THUMB 表示下边的标签是 16 位的标签,所谓的标签是 地址的别名,不占用代码空间,给编译器看的
【2】 DCD 是数据定义或者 重定位指令,为的是定义一个值,或者保留 memory,DCD 别名是 DC32,用于声明一个 32 位的常量,这部分是中断向量表的内容,需要注意的是,他们的顺序不能改变,此部分会放到 flash 的最开始部分,当系统启动的时候会加载前另个地址,第一个地址是 c 程序的栈的栈顶地址,第二个地址是向量表的开始地址,中断发生时会根据向量表的首地址和偏移量来找到程序的入口
【3】sfe 指令作用是返回栈的结尾,因为栈的增长方向是反方向的


; ; ; ; Default interrupt handlers. ; ; THUMBPUBWEAK Reset_Handler SECTION .text:CODE:REORDER(2) Reset_Handler LDRR0, =SystemInit BLXR0 LDRR0, =__iar_program_start BXR0PUBWEAK NMI_Handler SECTION .text:CODE:REORDER(1) NMI_Handler B NMI_HandlerPUBWEAK HardFault_Handler SECTION .text:CODE:REORDER(1) HardFault_Handler B HardFault_HandlerPUBWEAK MemManage_Handler SECTION .text:CODE:REORDER(1) MemManage_Handler B MemManage_HandlerPUBWEAK BusFault_Handler SECTION .text:CODE:REORDER(1) BusFault_Handler B BusFault_HandlerPUBWEAK UsageFault_Handler SECTION .text:CODE:REORDER(1) UsageFault_Handler B UsageFault_HandlerPUBWEAK SVC_Handler SECTION .text:CODE:REORDER(1) SVC_Handler B SVC_HandlerPUBWEAK DebugMon_Handler SECTION .text:CODE:REORDER(1) DebugMon_Handler B DebugMon_HandlerPUBWEAK PendSV_Handler SECTION .text:CODE:REORDER(1) PendSV_Handler B PendSV_HandlerPUBWEAK SysTick_Handler SECTION .text:CODE:REORDER(1) SysTick_Handler B SysTick_HandlerPUBWEAK WWDG_IRQHandler SECTION .text:CODE:REORDER(1) WWDG_IRQHandler B WWDG_IRQHandlerPUBWEAK PVD_IRQHandler SECTION .text:CODE:REORDER(1) PVD_IRQHandler B PVD_IRQHandlerPUBWEAK TAMPER_IRQHandler SECTION .text:CODE:REORDER(1) TAMPER_IRQHandler B TAMPER_IRQHandlerPUBWEAK RTC_IRQHandler SECTION .text:CODE:REORDER(1) RTC_IRQHandler B RTC_IRQHandlerPUBWEAK FLASH_IRQHandler SECTION .text:CODE:REORDER(1) FLASH_IRQHandler B FLASH_IRQHandlerPUBWEAK RCC_IRQHandler SECTION .text:CODE:REORDER(1) RCC_IRQHandler B RCC_IRQHandlerPUBWEAK EXTI0_IRQHandler SECTION .text:CODE:REORDER(1) EXTI0_IRQHandler B EXTI0_IRQHandlerPUBWEAK EXTI1_IRQHandler SECTION .text:CODE:REORDER(1) EXTI1_IRQHandler B EXTI1_IRQHandlerPUBWEAK EXTI2_IRQHandler SECTION .text:CODE:REORDER(1) EXTI2_IRQHandler B EXTI2_IRQHandlerPUBWEAK EXTI3_IRQHandler SECTION .text:CODE:REORDER(1) EXTI3_IRQHandler B EXTI3_IRQHandlerPUBWEAK EXTI4_IRQHandler SECTION .text:CODE:REORDER(1) EXTI4_IRQHandler B EXTI4_IRQHandlerPUBWEAK DMA1_Channel1_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel1_IRQHandler B DMA1_Channel1_IRQHandlerPUBWEAK DMA1_Channel2_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel2_IRQHandler B DMA1_Channel2_IRQHandlerPUBWEAK DMA1_Channel3_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel3_IRQHandler B DMA1_Channel3_IRQHandlerPUBWEAK DMA1_Channel4_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel4_IRQHandler B DMA1_Channel4_IRQHandlerPUBWEAK DMA1_Channel5_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel5_IRQHandler B DMA1_Channel5_IRQHandlerPUBWEAK DMA1_Channel6_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel6_IRQHandler B DMA1_Channel6_IRQHandlerPUBWEAK DMA1_Channel7_IRQHandler SECTION .text:CODE:REORDER(1) DMA1_Channel7_IRQHandler B DMA1_Channel7_IRQHandlerPUBWEAK ADC1_2_IRQHandler SECTION .text:CODE:REORDER(1) ADC1_2_IRQHandler B ADC1_2_IRQHandlerPUBWEAK USB_HP_CAN1_TX_IRQHandler SECTION .text:CODE:REORDER(1) USB_HP_CAN1_TX_IRQHandler B USB_HP_CAN1_TX_IRQHandlerPUBWEAK USB_LP_CAN1_RX0_IRQHandler SECTION .text:CODE:REORDER(1) USB_LP_CAN1_RX0_IRQHandler B USB_LP_CAN1_RX0_IRQHandlerPUBWEAK CAN1_RX1_IRQHandler SECTION .text:CODE:REORDER(1) CAN1_RX1_IRQHandler B CAN1_RX1_IRQHandlerPUBWEAK CAN1_SCE_IRQHandler SECTION .text:CODE:REORDER(1) CAN1_SCE_IRQHandler B CAN1_SCE_IRQHandlerPUBWEAK EXTI9_5_IRQHandler SECTION .text:CODE:REORDER(1) EXTI9_5_IRQHandler B EXTI9_5_IRQHandlerPUBWEAK TIM1_BRK_IRQHandler SECTION .text:CODE:REORDER(1) TIM1_BRK_IRQHandler B TIM1_BRK_IRQHandlerPUBWEAK TIM1_UP_IRQHandler SECTION .text:CODE:REORDER(1) TIM1_UP_IRQHandler B TIM1_UP_IRQHandlerPUBWEAK TIM1_TRG_COM_IRQHandler SECTION .text:CODE:REORDER(1) TIM1_TRG_COM_IRQHandler B TIM1_TRG_COM_IRQHandlerPUBWEAK TIM1_CC_IRQHandler SECTION .text:CODE:REORDER(1) TIM1_CC_IRQHandler B TIM1_CC_IRQHandlerPUBWEAK TIM2_IRQHandler SECTION .text:CODE:REORDER(1) TIM2_IRQHandler B TIM2_IRQHandlerPUBWEAK TIM3_IRQHandler SECTION .text:CODE:REORDER(1) TIM3_IRQHandler B TIM3_IRQHandlerPUBWEAK TIM4_IRQHandler SECTION .text:CODE:REORDER(1) TIM4_IRQHandler B TIM4_IRQHandlerPUBWEAK I2C1_EV_IRQHandler SECTION .text:CODE:REORDER(1) I2C1_EV_IRQHandler B I2C1_EV_IRQHandlerPUBWEAK I2C1_ER_IRQHandler SECTION .text:CODE:REORDER(1) I2C1_ER_IRQHandler B I2C1_ER_IRQHandlerPUBWEAK I2C2_EV_IRQHandler SECTION .text:CODE:REORDER(1) I2C2_EV_IRQHandler B I2C2_EV_IRQHandlerPUBWEAK I2C2_ER_IRQHandler SECTION .text:CODE:REORDER(1) I2C2_ER_IRQHandler B I2C2_ER_IRQHandlerPUBWEAK SPI1_IRQHandler SECTION .text:CODE:REORDER(1) SPI1_IRQHandler B SPI1_IRQHandlerPUBWEAK SPI2_IRQHandler SECTION .text:CODE:REORDER(1) SPI2_IRQHandler B SPI2_IRQHandlerPUBWEAK USART1_IRQHandler SECTION .text:CODE:REORDER(1) USART1_IRQHandler B USART1_IRQHandlerPUBWEAK USART2_IRQHandler SECTION .text:CODE:REORDER(1) USART2_IRQHandler B USART2_IRQHandlerPUBWEAK USART3_IRQHandler SECTION .text:CODE:REORDER(1) USART3_IRQHandler B USART3_IRQHandlerPUBWEAK EXTI15_10_IRQHandler SECTION .text:CODE:REORDER(1) EXTI15_10_IRQHandler B EXTI15_10_IRQHandlerPUBWEAK RTCAlarm_IRQHandler SECTION .text:CODE:REORDER(1) RTCAlarm_IRQHandler B RTCAlarm_IRQHandlerPUBWEAK USBWakeUp_IRQHandler SECTION .text:CODE:REORDER(1) USBWakeUp_IRQHandler B USBWakeUp_IRQHandlerPUBWEAK TIM8_BRK_IRQHandler SECTION .text:CODE:REORDER(1) TIM8_BRK_IRQHandler B TIM8_BRK_IRQHandlerPUBWEAK TIM8_UP_IRQHandler SECTION .text:CODE:REORDER(1) TIM8_UP_IRQHandler B TIM8_UP_IRQHandlerPUBWEAK TIM8_TRG_COM_IRQHandler SECTION .text:CODE:REORDER(1) TIM8_TRG_COM_IRQHandler B TIM8_TRG_COM_IRQHandlerPUBWEAK TIM8_CC_IRQHandler SECTION .text:CODE:REORDER(1) TIM8_CC_IRQHandler B TIM8_CC_IRQHandlerPUBWEAK ADC3_IRQHandler SECTION .text:CODE:REORDER(1) ADC3_IRQHandler B ADC3_IRQHandlerPUBWEAK FSMC_IRQHandler SECTION .text:CODE:REORDER(1) FSMC_IRQHandler B FSMC_IRQHandlerPUBWEAK SDIO_IRQHandler SECTION .text:CODE:REORDER(1) SDIO_IRQHandler B SDIO_IRQHandlerPUBWEAK TIM5_IRQHandler SECTION .text:CODE:REORDER(1) TIM5_IRQHandler B TIM5_IRQHandlerPUBWEAK SPI3_IRQHandler SECTION .text:CODE:REORDER(1) SPI3_IRQHandler B SPI3_IRQHandlerPUBWEAK UART4_IRQHandler SECTION .text:CODE:REORDER(1) UART4_IRQHandler B UART4_IRQHandlerPUBWEAK UART5_IRQHandler SECTION .text:CODE:REORDER(1) UART5_IRQHandler B UART5_IRQHandlerPUBWEAK TIM6_IRQHandler SECTION .text:CODE:REORDER(1) TIM6_IRQHandler B TIM6_IRQHandlerPUBWEAK TIM7_IRQHandler SECTION .text:CODE:REORDER(1) TIM7_IRQHandler B TIM7_IRQHandlerPUBWEAK DMA2_Channel1_IRQHandler SECTION .text:CODE:REORDER(1) DMA2_Channel1_IRQHandler B DMA2_Channel1_IRQHandlerPUBWEAK DMA2_Channel2_IRQHandler SECTION .text:CODE:REORDER(1) DMA2_Channel2_IRQHandler B DMA2_Channel2_IRQHandlerPUBWEAK DMA2_Channel3_IRQHandler SECTION .text:CODE:REORDER(1) DMA2_Channel3_IRQHandler B DMA2_Channel3_IRQHandlerPUBWEAK DMA2_Channel4_5_IRQHandler SECTION .text:CODE:REORDER(1) DMA2_Channel4_5_IRQHandler B DMA2_Channel4_5_IRQHandlerEND


【1】THUMB 表明下边是 thumb 指令
【2】Reset_Handler 在开机或者复位的时候执行
R0 = SystemInit
跳转到 SystemInit 函数,并将处理器切换到 thumb 状态
R0 = __iar_program_start
跳转到 __iar_program_start 函数,状态也是切换到 thumb 状态
【3】此处的 __iar_program_start 在程序中找不到是因为它已经被封装到了 IAR 自带的C库启动代码中了,当我们编译的时候,在项目属性的 linker,library中勾选了 Automatic runtime library ,就告诉了编译器用库中的 __iar_program_start ,具体实现了什么,我们可以查看 IAR 工具为我们提供的源码,具体路径在 IAR 安装目录下的 arm\src\lib\thumb ,我们可以看到有的文件分别的提供了 汇编代码和 c 代码。
其中的 cstartup_M.s 文件中有

#pragma required=__vector_table void __iar_program_start( void ) { __iar_init_core(); __iar_init_vfp(); __cmain(); }



【1】此段的程序中前两个函数是弱函数,在工程共没有定义
【2】__cmain 函数作用是初始化段和底层硬件,最后调用main


至此,库文件中的启动文件先分析到这里


3. FreeRTOS 中的汇编代码: 当 FreeRTOS 和 stm32 移植好后,会用到 FreeRTOS 中的源码文件portasm.s 中的函数
xPortPendSVHandler 函数:


xPortPendSVHandler: mrs r0, psp isb ldr r3, =pxCurrentTCB/* 获取当前任务的控制块(TCB)指针. */ ldr r2, [r3] stmdb r0!, {r4-r11}/* 保存 R4-R11 到该任务的堆栈. */ str r0, [r2]/* 将最后的堆栈指针保存到任务控制块的 pxTopOfStack. */ stmdb sp!, {r3, r14} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY /* 关闭中断 */ msr basepri, r0 dsb isb bl vTaskSwitchContext /* 切换任务上下文,pxCurrentTCB 已指向新的任务 */ mov r0, #0 msr basepri, r0 ldmia sp!, {r3, r14} ldr r1, [r3]/* 恢复新任务的上下文到各寄存器 */ ldr r0, [r1]/* The first item in pxCurrentTCB is the task top of stack. */ ldmia r0!, {r4-r11} /* Pop the registers. */ msr psp, r0 isb bx r14

【1】这个函数的功能是请求切换任务
【2】任务切换的示意图如下:

【FreeRTOS 第二课(启动文件分析)】FreeRTOS 第二课(启动文件分析)
文章图片




vPortSVCHandler 函数:直接切换任务用于vPortStartFirstTask第一次启动任务时初始化堆栈和各寄存器


vPortSVCHandler: /* Get the location of the current TCB. */ ldr r3, =pxCurrentTCB ldr r1, [r3] ldr r0, [r1] /* Pop the core registers. */ ldmia r0!, {r4-r11} msr psp, r0 isb mov r0, #0 msr basepri, r0 orr r14, r14, #13 bx r14



函数:启动第一个任务的汇编实现

vPortStartFirstTask /* Use the NVIC offset register to locate the stack. */ ldr r0, =0xE000ED08 /* 向量表偏移量寄存器 (VTOR) */ ldr r0, [r0] ldr r0, [r0] /* Set the msp back to the start of the stack. */ msr msp, r0 /* 将堆栈地址保存到主堆栈指针msp中 */ /* Call SVC to start the first task, ensuring interrupts are enabled. */ cpsie i /* 触发SVC软中断,由vPortSVCHandler()完成第一个任务的具体切换工作 */ cpsie f dsb isb svc 0

【1】此部分参照 (伟研科技 http://www.gzweiyan.com) 资料
【2】内核调度器启动的流程如下:
FreeRTOS 第二课(启动文件分析)
文章图片





    推荐阅读