IAR启动代码分析 – main()之前

IAR在运行到main()函数之前,要运行一段启动代码来初初始化寄存器、中断向量表以及系统时钟的初始化。我们先来了解一下中断向量表,可以再自己的工作空间找到相应的启动文件,我的叫startup_stm32f412vx.s,我们只要了解两个重要的。

__vector_table  
        DCD     sfe(CSTACK)  
        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  
...............省略..........  

首先我们了解“__vector_table”这个的含义,看一下此文件中的对这个的描述。

; The name "__vector_table" has special meaning for C-SPY:  
; it is where the SP start value is found, and the NVIC vector  
; table register (VTOR) is initialized to this address if != 0.  
;  

在stm32f412vx_flash.icf文件中是这个值(根据自己设定):

define symbol __ICFEDIT_intvec_start__ = 0x0800C000;  

接下来在了解第一个向量CSTACK指针,第二个是复位地址Reset_Handler指针。CSTACK是在“stm32f412vx_flash.icf”文件定义的一个快用来存放栈数据,看下定义:

define symbol __ICFEDIT_size_cstack__ = 0x600;  
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };  

sfe(CSTACK)代表取这个块的最后一个地址的下一个地址,因为栈有先进后出的特性,栈数据的存储是从下而上的,栈数据的读取是由上而下的。

第二个是单片机开始(复位)地址,Reset_Handler,我们先在IAR设置一下,把勾去掉,如图:

之后下载运行,界面如图:


系统跑到复位地址执行一些操作,来粗略解释下这个流程:

Reset_Handler  
        LDR     R0, =SystemInit  
        BLX     R0  
        LDR     R0, =__iar_program_start  
        BX      R0  

line1:表明执行的地址。
line2:将SystemInit函数地址给R0寄存器
line3:跳到R0寄存器保存的地址去执行(也就是执行SystemInit这个函数)
line4 、line5 同上。

所以单片机上电的顺序就是初始化SP、PC寄存器,接下来跳到PC寄存器指向的方向执行程序。顺着这个思路,如果你有好几个程序,在上电的时候通过外部触发初始化SP以及PC,就可以分别进入不同的程序。

接下来去看SystemInit这个函数做了什么:

/**  
  * @brief  Setup the microcontroller system  
  *         Initialize the FPU setting, vector table location and External memory   
  *         configuration.  
  * @param  None  
  * @retval None  
  */  
void SystemInit(void)  
{  
  /* FPU settings ------------------------------------------------------------*/  
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)  
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */  
  #endif  
  /* Reset the RCC clock configuration to the default reset state ------------*/  
  /* Set HSION bit */  
  RCC->CR |= (uint32_t)0x00000001;  
  
  /* Reset CFGR register */  
  RCC->CFGR = 0x00000000;  
  
  /* Reset HSEON, CSSON and PLLON bits */  
  RCC->CR &= (uint32_t)0xFEF6FFFF;  
  
  /* Reset PLLCFGR register */  
  RCC->PLLCFGR = 0x24003010;  
  
  /* Reset HSEBYP bit */  
  RCC->CR &= (uint32_t)0xFFFBFFFF;  
  
  /* Disable all interrupts */  
  RCC->CIR = 0x00000000;  
  
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)  
  SystemInit_ExtMemCtl();   
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */  
  
  /* Configure the Vector Table location add offset address ------------------*/  
#ifdef VECT_TAB_SRAM  
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */  
#else  
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */  
#endif  
}  

本想到此结束的,还是在解释一波吧,首先是进行了FPU(Float Point Unit)的初始化,SCB->CPACR(System control block -> Coprocessor access control register)系统控制块的协处理器访问控制器,看下这个寄存器的样子。

CP10和CP11设置
00 拒绝访问。任何访问都会产生使用错误(类型为NOCP – 无协处理器)
01 只支持特权访问,非特权访问会产生使用错误。
10 保留-结果无法预测
11 全访问


下面就是RCC时钟的初始化以及内部FLASH中的向量表重定位。

详情请参考此文章,点我!!!

351 Comments

Add a Comment

电子邮件地址不会被公开。