FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二

STM32F10x.s 启动文件分析

FreeRTOS的源代码里,采用了自编写的启动文件,而不是用的官方的启动文件(也就是以前创建工程时必须要添加的一个.s汇编文件,文件名格式大概是startup_stm32f10x_hd.s),但其内容基本只是对这个启动文件进行简单的编辑而已,主要是自定义了中断处理函数(比如TIM2_Handle())的名称而已。关于这个文件的分析可以先学习Cortex-M3权威手册(有中文版的),大概200多页。看完这个手册可以对CM3内核有很清楚的认识,对分析操作系统的底层是很有帮助也是必要的!

                IMPORT xPortPendSVHandler
                IMPORT xPortSysTickHandler
                IMPORT vPortSVCHandler
                IMPORT vUARTInterruptHandler
                IMPORT vTimer2IntHandler

__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     vPortSVCHandler           ; SVCall Handler
                DCD     DebugMon_Handler          ; Debug Monitor Handler
                DCD     0                         ; Reserved
                DCD     xPortPendSVHandler        ; PendSV Handler
                DCD     xPortSysTickHandler       ; SysTick Handler

对比官方的startup_stm32f10x_hd.s,可以发现,只是把默认的几个handle函数的名称给改成了自定义的名称比如vPortSVCHandler,vPortUARTInterruptHandler等。因此在写对应的终端处理函数时,得使用对应的自定义名称,比如串口1的中断处理函数void USART1_IRQHandler() 要改为void vPortUARTInterruptHandle()。
关于这一连续的汇编代码的作用参考权威手册,是设置中断向量表的,按照STM32F10x参考手册里的中断编号顺序,定义每一个中断的处理函数的位置也就是中断向量表,并且给出了默认的处理函数。
比如复位中断处理:Reset_Handler

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                LDR     R0, =__main
                BX      R0
                ENDP

可以看到,复位中断处理里就是转接到外部的main函数,这也是为什么主函数要叫main的原因,如果这里把main改成word,那么在main.c里就要把void main改成void word才行。
而外部中断(这里是指相对内核的外部主要是各种外设的中断比如定时器,串口等),都有同一个默认的中断处理

RTCAlarm_IRQHandler
USBWakeUp_IRQHandler

                B       .

                ENDP


                ALIGN

也就是什么都不做,系统死机。所以对于中断的开启与配置一定要小心,如果开启了中断则一定要写出相应的中断处理函数才行,即使这个函数是个空函数也要写出来,因为空函数里有中断返回的汇编代码这样就不会死机。

在main()主函数里的prvHardwareSetup()函数里有两行是设置向量表和优先级分组(见上一篇),

    /* Set the Vector Table base address at 0x08000000 */
    NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );

    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

设置的向量表的地址是内部Flash的起始地址0x08000000,在启动后会映射到地址0x00000000(见CM3权威手册),而启动文件里的向量地址表是:

; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors

__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler

看顶行注释就知道向量表是放在地址0里,READONLY就是指的ROM,也就是内部FLASH区域,从0地址开始申请一系列4字节空间并赋值来存储向量表,其中__initial_sp即是在文件开头时在READWRITE区(也就是RAM内存区)申请的栈地址,下面的各种handler对应的是各个中断函数的代码首地址。进入debug模式,用jlink(或者stlink)调试时,可以查看各个handler的地址值,也可以在下面的Memory窗口中查看0x00000000或者0x08000000地址的内容,会发现与之对应。
FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二_第1张图片
会发现Reset_Handler函数的代码地址是0x08000198,但是在ROM里存储的是0x08000199,后面的所有的代码地址都是相应的加了1,这是因为CM3只有Thumb状态,其代码地址要保证是奇数也就是LSB要是1,见CM3权威手册(中文版)40页。
FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二_第2张图片

而设置向量表地址的下一行设置优先级分组,CM3内核支持256级优先级与128级抢占优先级,除了复位,NMI和硬fault三个中断有固定的最高负优先级分别为-3,-2,-1外,其他异常(中断)的优先级均可编程,详见权威手册(中文版)107页。抢占优先级只有128个(所谓抢占优先级是指一个低优先级异常在响应时,另一个高优先级异常发生时,系统会挂起正在响应的低优先级异常转而去响应高优先级异常),是因为优先级又被分为抢占优先级与亚优先级(见 权威手册111页),亚优先级不会发生抢占(抢占优先级相同的两个异常同时挂起时会先响应高亚优先级)并且至少有1位,这样抢占优先级最多7位也就是128级。抢占优先级可以设为0位,这个在NVIC的AIRCR寄存器里的优先级分组3个位来设置,共8种情况。
FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二_第3张图片

对于STM32F10X,优先级被精简为只用4位(详见《 STM32F10xxx Cortex-M3编程手册》纯英文的,118页),也就是0到15共16个优先级,使用高4位,也就是对于优先级位11的其值为0xb0(b后面的可以是任意值,写入无效,但读取总是0)。优先级分组共5组(见编程手册135页)
FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二_第4张图片
源代码默认用的是Group_4,右键查看定义可以知道

/* Preemption Priority Group -------------------------------------------------*/
#define NVIC_PriorityGroup_0         ((u32)0x700) /* 0 bits for pre-emption priority
                                                     4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((u32)0x600) /* 1 bits for pre-emption priority
                                                     3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((u32)0x500) /* 2 bits for pre-emption priority
                                                     2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((u32)0x400) /* 3 bits for pre-emption priority
                                                     1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((u32)0x300) /* 4 bits for pre-emption priority
                                                     0 bits for subpriority */

代表的是这前4位全是抢占优先级,没有亚优先级,也就是优先级分成0到15个抢占优先级。

你可能感兴趣的:(嵌入式,FreeRTOS,STM32)