stm32f4 - 启动过程
来源:互联网 发布:nginx epoll 编辑:程序博客网 时间:2024/04/27 04:21
stm32的启动一般是:芯片在上电后,外部的晶振开始起振,给芯片提供时钟源,然后芯片开始执行内部的初始化程序,主要是对系统的时钟分频配置,中断向量表创建,堆栈的设置,初始pc指针,指向复位程序,最后运行main函数执行用户写的程序。
芯片的初始过程的程序是arm公司用汇编语言写的,它在arm公司提供的CMSIS微控制标准接口文件里面,这里面包含的arm cortex-m 的内核库文件,一个启动初始化的汇编文件和一个配置系统时钟的c文件。stm32f4xx.h文件包含了所有需要的头文件,只要在main函数前导入它就可以了,跟启动相关是初始化汇编文件和配置系统时钟的c文件。
芯片在初始化时首先会执行用汇编写的启动文件来初始化,启动文件的汇编代码的第一段是对栈区和堆区的空间配置,栈的大小设置为1KB,堆设置为512字节。
Stack_Size EQU 0x00000400 // EQU是一个宏的定义,跟C语言的define一样 ,定义栈大小的宏为1KBAREA STACK, NOINIT, READWRITE, ALIGN=3 //AREA指令是汇编一个代码段或数据段,这里是栈区,NOINIT是不初始化,READWRITE是可读可写,ALIGN对齐Stack_Mem SPACE Stack_Size // space指令是分配一定的内存空间,单位字节,这里是分配栈的大小__initial_sp // 指向栈顶,栈是从高到低的Heap_Size EQU 0x00000200 //分配堆的空间,512字节AREA HEAP, NOINIT, READWRITE, ALIGN=3 //配置堆区,不初始化,可读可写,__heap_base // 堆的起始地址Heap_Mem SPACE Heap_Size // 分配堆的空间__heap_limit // 限制堆的大小 PRESERVE8 // 指定当前文件的堆栈按照8字节对齐 THUMB // 表示后面的指令为thumb指令集,是以前arm的指令集,16bit
第二段汇编代码是分配一个数据段,段名叫RESET,是一个复位段,属性为只读。EXPROT指令为声明一个全局的符号。
AREA RESET, DATA, READONLY // 分配一个数据段RESET,是一个复位段,只读EXPORT __Vectors // 声明一个全局符号_vectors,向量表的开始EXPORT __Vectors_End // 声明一个全局符号_vector_End,向量表的结束EXPORT __Vectors_Size //声明一个全局符号_vector_Size,向量表的大小
第三段汇编代码是创建向量表,向量表相当于一个数组,里面存的元素对应一个异常,元素是一个32为整型,存的是异常处理的入口地址。DCD指令为分配一个或多个以字为单位的空间,并以异常的入口地址初始化他们,一字为4个字节。简单的说向量表存是中断函数名,而函数名就是函数的地址。向量表在保存FLASH的起始地址0X00000000,系统启动时会向量表的第0个值开始取值。
_Vectors DCD __initial_sp ; 栈顶的地址值 DCD 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 SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler // 外部中断 DCD WWDG_IRQHandler ; Window WatchDog DCD PVD_IRQHandler ; PVD through EXTI Line detection DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line DCD FLASH_IRQHandler ; FLASH DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line0 DCD EXTI1_IRQHandler ; EXTI Line1 DCD EXTI2_IRQHandler ; EXTI Line2 DCD EXTI3_IRQHandler ; EXTI Line3 DCD EXTI4_IRQHandler ; EXTI Line4 DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0 DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1 DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2 DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3 DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4 DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5 DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6 DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s DCD CAN1_TX_IRQHandler ; CAN1 TX DCD CAN1_RX0_IRQHandler ; CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; External Line[9:5]s DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9 DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10 DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11 DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; External Line[15:10]s DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12 DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13 DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14 DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7 DCD FMC_IRQHandler ; FMC DCD SDIO_IRQHandler ; SDIO DCD TIM5_IRQHandler ; TIM5 DCD SPI3_IRQHandler ; SPI3 DCD UART4_IRQHandler ; UART4 DCD UART5_IRQHandler ; UART5 DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors DCD TIM7_IRQHandler ; TIM7 DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0 DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1 DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2 DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3 DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4 DCD ETH_IRQHandler ; Ethernet DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line DCD CAN2_TX_IRQHandler ; CAN2 TX DCD CAN2_RX0_IRQHandler ; CAN2 RX0 DCD CAN2_RX1_IRQHandler ; CAN2 RX1 DCD CAN2_SCE_IRQHandler ; CAN2 SCE DCD OTG_FS_IRQHandler ; USB OTG FS DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5 DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6 DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7 DCD USART6_IRQHandler ; USART6 DCD I2C3_EV_IRQHandler ; I2C3 event DCD I2C3_ER_IRQHandler ; I2C3 error DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI DCD OTG_HS_IRQHandler ; USB OTG HS DCD DCMI_IRQHandler ; DCMI DCD CRYP_IRQHandler ; CRYP crypto DCD HASH_RNG_IRQHandler ; Hash and Rng DCD FPU_IRQHandler ; FPU DCD UART7_IRQHandler ; UART7 DCD UART8_IRQHandler ; UART8 DCD SPI4_IRQHandler ; SPI4 DCD SPI5_IRQHandler ; SPI5 DCD SPI6_IRQHandler ; SPI6 DCD SAI1_IRQHandler ; SAI1 DCD LTDC_IRQHandler ; LTDC DCD LTDC_ER_IRQHandler ; LTDC error DCD DMA2D_IRQHandler ; DMA2D __Vectors_End__Vectors_Size EQU __Vectors_End - __Vectors AREA |.text|, CODE, READONLY
第四段汇编代码是Reset_Handler的函数的定义,也就是复位程序,这是上电后第一个程序,复位函数先是调用SystemInit函数来初始化系统时钟,最后调用_main函数,_main函数不是C语言的main函数,这是编译器定义的一个库函数,但是最终会跳到C语言的main函数。
Reset_Handler PROC //PROC指令和ENDP指令一起使用,定义一个过程子程序。 EXPORT Reset_Handler [WEAK] //声明一个标号具有全局属性,属于弱定义,外部没有定义时使用 IMPORT SystemInit // 声明一个来自的外部文件,为了调用SystemInit函数 IMPORT __main // <span style="font-family: Arial, Helvetica, sans-serif;">声明一个来自的外部文件,</span><span style="font-family: Arial, Helvetica, sans-serif;">为了调用_main函数</span> LDR R0, =SystemInit // 从存储器加载一个字到寄存器中,就是SystemInit的地址 BLX R0 // 跳转到寄存器指向的地址,就是执行函数 LDR R0, =__main // <span style="font-family: Arial, Helvetica, sans-serif;">从存储器加载一个字到寄存器中,就是_main的地址</span> BX R0 //<span style="font-family: Arial, Helvetica, sans-serif;">跳转到寄存器指向的地址,不用返回</span> ENDP //跟PROC一起使用第五段是定义系统的中断函数,空定义,弱定义,若外部定义这些函数就使用外部的函数,外部没有定义及调用这里定义的函数,如果没有外部定义调用这些函数会死循环。
NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDPHardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDPMemManage_Handler\ PROC EXPORT MemManage_Handler [WEAK] B . ENDPBusFault_Handler\ PROC EXPORT BusFault_Handler [WEAK] B . ENDPUsageFault_Handler\ PROC EXPORT UsageFault_Handler [WEAK] B . ENDPSVC_Handler PROC EXPORT SVC_Handler [WEAK] B . ENDPDebugMon_Handler\ PROC EXPORT DebugMon_Handler [WEAK] B . ENDPPendSV_Handler PROC EXPORT PendSV_Handler [WEAK] B . ENDPSysTick_Handler PROC EXPORT SysTick_Handler [WEAK] B . ENDP
第六段是定义全局外部中断的函数,也是弱定义,外部有定义优先调用外部的函数。
Default_Handler PROC EXPORT WWDG_IRQHandler [WEAK] EXPORT PVD_IRQHandler [WEAK] EXPORT TAMP_STAMP_IRQHandler [WEAK] EXPORT RTC_WKUP_IRQHandler [WEAK] EXPORT FLASH_IRQHandler [WEAK] EXPORT RCC_IRQHandler [WEAK] EXPORT EXTI0_IRQHandler [WEAK] EXPORT EXTI1_IRQHandler [WEAK] EXPORT EXTI2_IRQHandler [WEAK] EXPORT EXTI3_IRQHandler [WEAK] EXPORT EXTI4_IRQHandler [WEAK] EXPORT DMA1_Stream0_IRQHandler [WEAK] EXPORT DMA1_Stream1_IRQHandler [WEAK] EXPORT DMA1_Stream2_IRQHandler [WEAK] EXPORT DMA1_Stream3_IRQHandler [WEAK] EXPORT DMA1_Stream4_IRQHandler [WEAK] EXPORT DMA1_Stream5_IRQHandler [WEAK] EXPORT DMA1_Stream6_IRQHandler [WEAK] EXPORT ADC_IRQHandler [WEAK] EXPORT CAN1_TX_IRQHandler [WEAK] EXPORT CAN1_RX0_IRQHandler [WEAK] EXPORT CAN1_RX1_IRQHandler [WEAK] EXPORT CAN1_SCE_IRQHandler [WEAK] EXPORT EXTI9_5_IRQHandler [WEAK] EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK] EXPORT TIM1_UP_TIM10_IRQHandler [WEAK] EXPORT TIM1_TRG_COM_TIM11_IRQHandler [WEAK] EXPORT TIM1_CC_IRQHandler [WEAK] EXPORT TIM2_IRQHandler [WEAK] EXPORT TIM3_IRQHandler [WEAK] EXPORT TIM4_IRQHandler [WEAK] EXPORT I2C1_EV_IRQHandler [WEAK] EXPORT I2C1_ER_IRQHandler [WEAK] EXPORT I2C2_EV_IRQHandler [WEAK] EXPORT I2C2_ER_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT SPI2_IRQHandler [WEAK] EXPORT USART1_IRQHandler [WEAK] EXPORT USART2_IRQHandler [WEAK] EXPORT USART3_IRQHandler [WEAK] EXPORT EXTI15_10_IRQHandler [WEAK] EXPORT RTC_Alarm_IRQHandler [WEAK] EXPORT OTG_FS_WKUP_IRQHandler [WEAK] EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK] EXPORT TIM8_UP_TIM13_IRQHandler [WEAK] EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK] EXPORT TIM8_CC_IRQHandler [WEAK] EXPORT DMA1_Stream7_IRQHandler [WEAK] EXPORT FMC_IRQHandler [WEAK] EXPORT SDIO_IRQHandler [WEAK] EXPORT TIM5_IRQHandler [WEAK] EXPORT SPI3_IRQHandler [WEAK] EXPORT UART4_IRQHandler [WEAK] EXPORT UART5_IRQHandler [WEAK] EXPORT TIM6_DAC_IRQHandler [WEAK] EXPORT TIM7_IRQHandler [WEAK] EXPORT DMA2_Stream0_IRQHandler [WEAK] EXPORT DMA2_Stream1_IRQHandler [WEAK] EXPORT DMA2_Stream2_IRQHandler [WEAK] EXPORT DMA2_Stream3_IRQHandler [WEAK] EXPORT DMA2_Stream4_IRQHandler [WEAK] EXPORT ETH_IRQHandler [WEAK] EXPORT ETH_WKUP_IRQHandler [WEAK] EXPORT CAN2_TX_IRQHandler [WEAK] EXPORT CAN2_RX0_IRQHandler [WEAK] EXPORT CAN2_RX1_IRQHandler [WEAK] EXPORT CAN2_SCE_IRQHandler [WEAK] EXPORT OTG_FS_IRQHandler [WEAK] EXPORT DMA2_Stream5_IRQHandler [WEAK] EXPORT DMA2_Stream6_IRQHandler [WEAK] EXPORT DMA2_Stream7_IRQHandler [WEAK] EXPORT USART6_IRQHandler [WEAK] EXPORT I2C3_EV_IRQHandler [WEAK] EXPORT I2C3_ER_IRQHandler [WEAK] EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK] EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK] EXPORT OTG_HS_WKUP_IRQHandler [WEAK] EXPORT OTG_HS_IRQHandler [WEAK] EXPORT DCMI_IRQHandler [WEAK] EXPORT CRYP_IRQHandler [WEAK] EXPORT HASH_RNG_IRQHandler [WEAK] EXPORT FPU_IRQHandler [WEAK] EXPORT UART7_IRQHandler [WEAK] EXPORT UART8_IRQHandler [WEAK] EXPORT SPI4_IRQHandler [WEAK] EXPORT SPI5_IRQHandler [WEAK] EXPORT SPI6_IRQHandler [WEAK] EXPORT SAI1_IRQHandler [WEAK] EXPORT LTDC_IRQHandler [WEAK] EXPORT LTDC_ER_IRQHandler [WEAK] EXPORT DMA2D_IRQHandler [WEAK]WWDG_IRQHandler PVD_IRQHandler TAMP_STAMP_IRQHandler RTC_WKUP_IRQHandler FLASH_IRQHandler RCC_IRQHandler EXTI0_IRQHandler EXTI1_IRQHandler EXTI2_IRQHandler EXTI3_IRQHandler EXTI4_IRQHandler DMA1_Stream0_IRQHandler DMA1_Stream1_IRQHandler DMA1_Stream2_IRQHandler DMA1_Stream3_IRQHandler DMA1_Stream4_IRQHandler DMA1_Stream5_IRQHandler DMA1_Stream6_IRQHandler ADC_IRQHandler CAN1_TX_IRQHandler CAN1_RX0_IRQHandler CAN1_RX1_IRQHandler CAN1_SCE_IRQHandler EXTI9_5_IRQHandler TIM1_BRK_TIM9_IRQHandler TIM1_UP_TIM10_IRQHandler TIM1_TRG_COM_TIM11_IRQHandler TIM1_CC_IRQHandler TIM2_IRQHandler TIM3_IRQHandler TIM4_IRQHandler I2C1_EV_IRQHandler I2C1_ER_IRQHandler I2C2_EV_IRQHandler I2C2_ER_IRQHandler SPI1_IRQHandler SPI2_IRQHandler USART1_IRQHandler USART2_IRQHandler USART3_IRQHandler EXTI15_10_IRQHandler RTC_Alarm_IRQHandler OTG_FS_WKUP_IRQHandler TIM8_BRK_TIM12_IRQHandler TIM8_UP_TIM13_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler TIM8_CC_IRQHandler DMA1_Stream7_IRQHandler FMC_IRQHandler SDIO_IRQHandler TIM5_IRQHandler SPI3_IRQHandler UART4_IRQHandler UART5_IRQHandler TIM6_DAC_IRQHandler TIM7_IRQHandler DMA2_Stream0_IRQHandler DMA2_Stream1_IRQHandler DMA2_Stream2_IRQHandler DMA2_Stream3_IRQHandler DMA2_Stream4_IRQHandler ETH_IRQHandler ETH_WKUP_IRQHandler CAN2_TX_IRQHandler CAN2_RX0_IRQHandler CAN2_RX1_IRQHandler CAN2_SCE_IRQHandler OTG_FS_IRQHandler DMA2_Stream5_IRQHandler DMA2_Stream6_IRQHandler DMA2_Stream7_IRQHandler USART6_IRQHandler I2C3_EV_IRQHandler I2C3_ER_IRQHandler OTG_HS_EP1_OUT_IRQHandler OTG_HS_EP1_IN_IRQHandler OTG_HS_WKUP_IRQHandler OTG_HS_IRQHandler DCMI_IRQHandler CRYP_IRQHandler HASH_RNG_IRQHandlerFPU_IRQHandler UART7_IRQHandler UART8_IRQHandler SPI4_IRQHandler SPI5_IRQHandler SPI6_IRQHandler SAI1_IRQHandler LTDC_IRQHandler LTDC_ER_IRQHandler DMA2D_IRQHandler B . ENDP第七段是用户堆栈的初始化,IF ELSE 语句跟C语言的一样,如果定义__MICROLIB这个宏就使用上面定义的栈顶和堆起始地址堆大小,实际上我们没有定义这个宏,所以会执行ELSE的程序,ELSE程序是在C库函数里的,也就是使用C语言的方式初始化堆栈,在初始完堆栈之后就会进入C程序的世界。
IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR ALIGN // 对指令和数据存放的地址对齐,缺省就是4字节 ENDIF END系统启动的完整过程:
1,从0x00000000地址取出MSP的初始值,就是向量表的第0个元素
2,从地址0x00000004地址取出PC的初始值,也就是向量表的第1个复位程序
3,执行Reset_Handler复位程序,初始化时钟,最后来到C语言的世界
第一步先取出MSP的值是必须的,因为在执行后面的程序时,必须要先准备好堆栈,防止指令还没来的及执行就发生异常。第二步是取程序计数器的值,执行第一个程序,第一个程序就是复位程序,复位程序的地址保存在向量表的第1个元素中。复位程序先调用System_Init函数对系统时钟的初始化,等待时钟稳定后最终会进入C语言的世界。
- stm32f4 - 启动过程
- STM32F4启动代码分析
- STM32F4启动文件分析
- STM32F4
- STM32F4的启动文件startup_stm32f4xx.s说明
- 2-SnailBoard之STM32F4-Fly启动
- stm32f4启动代码分析(一)
- 启动过程
- 启动过程
- 启动过程
- STM32F4板子使用LWIP进行组播收发数据的完整过程,附代码
- STM32F4 FSMC
- stm32f4 FSMC
- STM32F4 systick
- STM32F4 DAC
- STM32F4 时钟
- rtems stm32f4
- stm32f4时钟
- mysql必知必会——GROUP BY和HAVING
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
- java中String、StringBuffer、StringBuilder的区别
- AsSystemRum 系统提权工具 实现思路及其源码
- python:字符串中的转义字符
- stm32f4 - 启动过程
- PackageKit概述
- Spawning a TTY Shell
- 一个据说第一次接触都会做错的Java面试题和类加载器的介绍
- 一个有意思的题目:单循环实现乘法表
- [ACM湖南省赛] CSU 1806 动态最短路的积分
- UVa 10976 Fraction Again?! 分数拆解 (例题7-3)
- 51单片机 指纹模块 波特率问题解决和命令分析2
- stl remove 和 erase