stm32零碎漫谈----启动流程

启动文件

1、几种启动方式

STM32芯片自带的启动方式有3种,通过设置BOOT1、BOOT0的引脚的高低电平即可选择。

  • 通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处。主闪存启动是将程序下载到内置的Flash进行启动(该flash可运行程序),该程序可以掉电保存,下次开机可自动启动。
  • 通过boot引脚设置可以将中断向量表定位于内置Bootloader区。系统存储器启动是将程序写入到一块特定的区域,一般由厂家直接写入,不能被随意更改或擦除。
  • 通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处。内置SRAM启动,由于SRAM掉电丢失,不能保存程序,一般只用于程序的调试。

2、启动前的准备

stm32的汇编启动文件(部分)

1.设置堆栈

 __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
 Stack_Size      EQU     0x00000400  		
                 AREA    STACK, NOINIT, READWRITE, ALIGN=3  
 Stack_Mem       SPACE   Stack_Size  
__initial_sp  
;  Heap Configuration  
;  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>    
Heap_Size       EQU     0x00000200  
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3  
__heap_base  
Heap_Mem        SPACE   Heap_Size  
__heap_limit 

此条语句即设置栈Stack_Size EQU 0x00000400;此条语句即设置堆Heap_Size EQU 0x00000200

这一段代码在单片机运行前设置好了程序的堆栈,一般来说,裸机程序中不对内存进行管理,堆栈设置是静态的,程序初始化后不会再进行修改。

2.初始化中断向量表

__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     SVC_Handler                ; SVCall Handler  
                DCD     DebugMon_Handler           ; Debug Monitor Handler  
                DCD     0                          ; Reserved  
                DCD     PendSV_Handler             ; PendSV Handler  
                DCD     SysTick_Handler            ; SysTick Handler  
                ; External Interrupts  
                DCD     WWDG_IRQHandler            ; Window Watchdog  
                DCD     PVD_IRQHandler         ; PVD through EXTI Line detect  
                DCD     TAMPER_IRQHandler          ; Tamper  
                DCD     RTC_IRQHandler             ; RTC  
                DCD     FLASH_IRQHandler           ; Flash  
                DCD     RCC_IRQHandler             ; RCC  
                DCD     EXTI0_IRQHandler           ; EXTI Line 0  
                DCD     EXTI1_IRQHandler           ; EXTI Line 1  
                DCD     EXTI2_IRQHandler           ; EXTI Line 2  27                DCD     EXTI3_IRQHandler           ; EXTI Line 3  
                DCD     EXTI4_IRQHandler           ; EXTI Line 4  
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1  
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2  
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3  
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4  
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5  
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6  
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7  
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2  
                DCD     USB_HP_CAN1_TX_IRQHandler  
                DCD     USB_LP_CAN1_RX0_IRQHandler
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1  
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE  
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5  
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break  
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update  
                DCD     TIM1_TRG_COM_IRQHandler   
                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  
               /***    很多    不一一列举   ***/ 

这个是作为其他所有中断的默认处理函数,作用就是死循环,所以你假如开启了某个中断,请按照这里面的中断函数名给它写中断处理函数,例如串口中断处理函数名是 USART1_IRQHandler,你开了串口中断,如果不重写USART1_IRQHandler,就默认执行Default_Handler,死循环了。而如果你有重写,那么中断向量表中的处理函数的地址就会更新为你自己写的那个函数的地址了。为什么会这样呢?因为此文件的末尾用了类似这样的语句:

weak    USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler

它给中断处理函数提供了弱(weak)别名(Default_Handler),如果不重写,中断了默认执行Default_Handler,如果重写了,因为是弱别名,所以会被你写的同名函数覆盖WEAK声明其他的同名标号优先于该标号被引用,就是说如果外面声明了的话,;会调用外面的

最后定义了一个中断向量表的段(.section .isr_vector,“a”,%progbits),这个表将会放置在0x0000 0000那里,第二个字(0x0000 0004)是复位向量,复位之后从这地址所指的函数执行。

3、main()执行前过程

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

这个文件里面首先定义了复位中断(复位入口矢量被硬件固定在地址0x0000_0004)的处理函数:Reset_Handler,它的作用就是将保存于flash中的初始化数据复制到sram中,调用上面说到的SystemInit来初始化时钟,接着跳转到main执行。

在进入main函数之前,我们要进行系统初始化:SystemInit( ),这个函数在system_stm32f10x.c中。

SystemInit():在"startup_stm32f10x_xx.s"文件中被调用,功能是设置系统时钟(包括时钟源,PLL系数,AHB/APBx的预分频系数还有 flash的设定),这个函数会在系统复位之后首先被执行。文件中默认的一些设置:允许HSE(外部时钟),FLASH(允许预取缓冲区,设置2个等待周期),PLL系数为9,开启PLL并选择PLL输出作为时钟源(SYSCLK),后续设置SYSCLK = HCLK = APB2 = 72MHz,APB1 = HCLK/2 = 36MHz,HCLK即AHB的时钟。

SystemCoreClockUpdate():在系统时钟HCLK变化的时候调用,以更新一个全局变量SystemCoreClock,这个变量可以为应用程序使用,必须保证正确。默认不调用这个函数,因为SystemCoreClock默认被设置为设定的频率了。

4、整个过程

stm32零碎漫谈----启动流程_第1张图片
在.s文件中,已经将中断向量表定义完整,系统会跳转到固定地址进行执行。第一条执行 Reset_handler。接着执行SystemInit设置运行时钟信息(72MHz)。

__main函数是内部的一个库函数,在此函数中调用了_scatter_load, _scatterload_null, _scatterload_copy 等函数,负责初始化堆栈,RW-DATA搬运,ZI段初始化等等操作。(编译后的镜像下载文件包含Code:代表程序代码段、RO_DATA:代表只读数据段、RW_DATA:代表已经初始化全局数据、ZI_DATA:代表未初始化全局数据,其中ZI不会被下载,其他的都会被下载到单片机的Flash,stm32在运行时会把RW从Flash搬运到RAM,RO不会搬运。)

走完前面的路最终跳转到 main 函数,执行用户程序。

你可能感兴趣的:(stm32零碎漫谈,stm32,嵌入式,单片机)