[其他ST产品] STM32学习笔记 - 启动代码

[复制链接]
 楼主| qn7a12 发表于 2023-7-27 23:46 | 显示全部楼层 |阅读模式
STM32学习笔记 - 启动代码常用汇编指令 517964c291693ae09.png


 楼主| qn7a12 发表于 2023-7-27 23:47 | 显示全部楼层
启动代码
看一下startup_stm32f4429_439xx.s文件前面的copyright内容
  1. ;******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
  2. ;* File Name          : startup_stm32f429_439xx.s
  3. ;* Author             : MCD Application Team
  4. ;* [url=home.php?mod=space&uid=895143]@version[/url]           : V1.8.0
  5. ;* [url=home.php?mod=space&uid=212281]@date[/url]              : 09-November-2016
  6. ;* Description        : STM32F429xx/439xx devices vector table for MDK-ARM toolchain.
  7. ;*                      This module performs:
  8. ;*                      - Set the initial SP                                                                                        初始化指针sp
  9. ;*                      - Set the initial PC == Reset_Handler                                                         初始化指针pc
  10. ;*                      - Set the vector table entries with the exceptions ISR address                初始化向量终端表
  11. ;*                      - Configure the system clock and the external SRAM/SDRAM mounted          配置系统时钟
  12. ;*                        on STM324x9I-EVAL boards to be used as data memory  
  13. ;*                        (optional, to be enabled by user)
  14. ;*                      - Branches to __main in the C library (which eventually                                调用C库
  15. ;*                        calls main()).
  16. ;*                      After Reset the CortexM4 processor is in Thread mode,
  17. ;*                      priority is Privileged, and the Stack is set to Main.
 楼主| qn7a12 发表于 2023-7-27 23:47 | 显示全部楼层
STM32启动代码由汇编编写,会在系统上电后执行,可以认为启动代码就是整个系统启动的引导程序,功能主要分如下几个:

初始化栈指针SP = _initial_sp;
初始化PC指针 = Rest_Handler ;
初始化中断向量表;
配置系统时钟;
调用C库函数_main初始化用户栈,从而真正转到C的main函数中。
 楼主| qn7a12 发表于 2023-7-27 23:47 | 显示全部楼层

  1. Stack_Size      EQU     0x00000400        ;给0x00000400这个立即数一个别名Stack_Size,从名字上可以看出来这是给栈分配空间为1KB,如果不够的话可以修改这里

  2.                 AREA    STACK, NOINIT, READWRITE, ALIGN=3 ;栈名称为STACK,NOINIT为不初始化,READWRIT:可读写,ALIGN=3,表示已2^3(8)字节对齐
  3. Stack_Mem       SPACE   Stack_Size                ;指定了内存大小等于Stack_Size
  4. __initial_sp                                                  ;标号__initial_sp紧挨着SPACE放置,表示栈的结束地址,及栈顶地址
 楼主| qn7a12 发表于 2023-7-27 23:47 | 显示全部楼层
打开map文件可以看到关于栈的相关信息
4505264c291a2a90a2.png
 楼主| qn7a12 发表于 2023-7-27 23:48 | 显示全部楼层

  1. Heap_Size       EQU     0x00000200        ;给0x00000200这个立即数一个别名Heap_Size,从名字上可以看出来这是给栈分配空间为512B,如果不够的话可以修改这里

  2.                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3 ;堆名称为HEAP,NOINIT为不初始化,READWRIT:可读写,ALIGN=3,表示已2^3(8)字节对齐
  3. __heap_base                                                                ;堆的起始地址
  4. Heap_Mem        SPACE   Heap_Size                  ;指定对的内存大小等于Heap_Size
  5. __heap_limit                                                        ;堆的结束地址

  6.                 PRESERVE8                                 ;指定当前文件的堆按照8字节对齐
  7.                 THUMB                                        ;后面指令兼容THUMB指令

 楼主| qn7a12 发表于 2023-7-27 23:48 | 显示全部楼层
向量表
  1. ; 重映射向量表
  2.                 AREA    RESET, DATA, READONLY                ;定义数据段,名称为RESET,只读模式,
  3.                 EXPORT  __Vectors                                   ;声明可被外部访问的标号
  4.                 EXPORT  __Vectors_End
  5.                 EXPORT  __Vectors_Size       
  6. ;这里我自己理解就类似于一个数组,__Vectors是数组的起始地址,__Vectors_End是数组结束地址,__Vectors_Size在最后做了计算,是起始地址与结束地址的差值
  7. ;向量表中记录了系统所有中断向量地址,当内核响应了发生的异常(中断或事件)后,对应的异常服务例程就会执行,所以这里的向量表就是为异常服务机制提供入口地址
  8. __Vectors       DCD     __initial_sp               ; Top of Stack
  9.                 DCD     Reset_Handler              ; Reset Handler
  10.                 DCD     NMI_Handler                ; NMI Handler
  11.                 DCD     HardFault_Handler          ; Hard Fault Handler
  12.                 DCD     MemManage_Handler          ; MPU Fault Handler
  13.                 DCD     BusFault_Handler           ; Bus Fault Handler
  14.                 DCD     UsageFault_Handler         ; Usage Fault Handler
  15.                 DCD     0                          ; Reserved
  16.                 DCD     0                          ; Reserved
  17.                 DCD     0                          ; Reserved
  18.                 DCD     0                          ; Reserved
  19.                 DCD     SVC_Handler                ; SVCall Handler
  20.                 DCD     DebugMon_Handler           ; Debug Monitor Handler
  21.                 DCD     0                          ; Reserved
  22.                 DCD     PendSV_Handler             ; PendSV Handler
  23.                 DCD     SysTick_Handler            ; SysTick Handler

  24.                 ; External Interrupts
  25.                 DCD     WWDG_IRQHandler                   ; Window WatchDog                                       
  26.                 DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection                        
  27.                 DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line            
  28.                 DCD     RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line                       
  29.                 DCD     FLASH_IRQHandler                  ; FLASH                                          
  30.                 DCD     RCC_IRQHandler                    ; RCC                                             
  31.                 DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
  32.                 DCD     EXTI1_IRQHandler                  ; EXTI Line1                  
  33.                            ;由于篇幅原因,中间就删掉了
  34.                 DCD     SPI4_IRQHandler                   ; SPI4
  35.                 DCD     SPI5_IRQHandler                   ; SPI5
  36.                 DCD     SPI6_IRQHandler                   ; SPI6
  37.                 DCD     SAI1_IRQHandler                   ; SAI1
  38.                 DCD     LTDC_IRQHandler                   ; LTDC
  39.                 DCD     LTDC_ER_IRQHandler                ; LTDC error
  40.                 DCD     DMA2D_IRQHandler                  ; DMA2D
  41.                                          
  42. __Vectors_End                        ;这里表示向量表的结束地址

  43. __Vectors_Size  EQU  __Vectors_End - __Vectors                ;计算向量表的容量并赋值给__Vectors_Size
 楼主| qn7a12 发表于 2023-7-27 23:48 | 显示全部楼层
复位程序
  1.                 AREA    |.text|, CODE, READONLY                ;定义了名称为.text的代码段,只读
  2. ; Reset handler定义名为Reset_Handler的子程序
  3. Reset_Handler    PROC
  4.                                 ;导入Reset_Handler子程序,这里用WEAK修饰表示弱定义,优先定义外部定义的程序,如果没有,也不会报错,
  5.                  EXPORT  Reset_Handler             [WEAK]
  6.         IMPORT  SystemInit                                ;表示SystemInit函数来自外部
  7.         IMPORT  __main                                        ;表示__main函数来自外部

  8.                  LDR     R0, =SystemInit        ;将SystemInit加载到R0寄存器中
  9.                  BLX     R0                                        ;跳转到R0给出的地址
  10.                  LDR     R0, =__main                ;将__main加载到R0寄存器中
  11.                  BX      R0                                        ;跳转到R0给出的地址
  12.                  ENDP                                           ;程序结束
 楼主| qn7a12 发表于 2023-7-27 23:48 | 显示全部楼层
SystemInit是标准库函数,在system_stm32f4xx.c中定义,主要是用来配置系统时钟,我现在用的F429的开发板,在调用SystemInit后,会将系统时钟配置到180MHz。

__main是个标准C库函数,但是这里要主义的是,这个main不是我们在C语言中的main函数,__main作用是初始化用户栈,完成后在最后调用main转到C语言中。
 楼主| qn7a12 发表于 2023-7-27 23:48 | 显示全部楼层
中断服务程序
  1. ; Dummy Exception Handlers (infinite loops which can be modified)

  2. NMI_Handler     PROC                                                                        ;定义了NMI_Handler中断子程序
  3.                 EXPORT  NMI_Handler                [WEAK]        ;弱定义,若外部定义了则优先使用,如果未定义,也不报错,以下相同
  4.                 B       .                                                                ;跳转到.,在这里.表示无限循环
  5.                 ENDP
  6. ;省略了一部分详细看原文档
  7. SysTick_Handler PROC
  8.                 EXPORT  SysTick_Handler            [WEAK]
  9.                 B       .
  10.                 ENDP
  11. Default_Handler PROC                                                                                        ;外部中断,同样是弱定义
  12.                 EXPORT  WWDG_IRQHandler                   [WEAK]                                       
  13.                 EXPORT  PVD_IRQHandler                    [WEAK]                     
  14.                 EXPORT  TAMP_STAMP_IRQHandler             [WEAK]         
  15.                 EXPORT  RTC_WKUP_IRQHandler               [WEAK]                     
  16.                 EXPORT  FLASH_IRQHandler                  [WEAK]                                         
  17.                 EXPORT  RCC_IRQHandler                    [WEAK]                                            
  18.                 EXPORT  EXTI0_IRQHandler                  [WEAK]                                            
  19.               ;篇幅省略
  20.                 EXPORT  LTDC_ER_IRQHandler                [WEAK]
  21.                 EXPORT  DMA2D_IRQHandler                  [WEAK]

  22. WWDG_IRQHandler                                                      
  23. PVD_IRQHandler                                      
  24. TAMP_STAMP_IRQHandler                  
  25. ;篇幅省略  
  26. LTDC_IRQHandler                  
  27. LTDC_ER_IRQHandler                 
  28. DMA2D_IRQHandler                  
  29.                 B       .                                ;跳转到.,在这里.表示无限循环
  30.                 ENDP
 楼主| qn7a12 发表于 2023-7-27 23:49 | 显示全部楼层
这里需要注意的是,使用中断的时候,应为是弱定义的中断服务子程序,因此会优先调用外部定义的服务程序,当我们在外部没有编写配套的中断服务子程序或者编写的服务子程序与启动文件中的程序名不一致时,系统会自动跳转到启动文件中默认的中断服务子程序中,B .然后就在此处无限循环,程序就卡死到这里了
 楼主| qn7a12 发表于 2023-7-27 23:49 | 显示全部楼层
用户堆与栈的初始化
  1.                 ALIGN                ;用来指定符号的对齐方式,默认按照4字节对齐
  2. ;*******************************************************************************
  3. ; User Stack and Heap initialization
  4. ;*******************************************************************************
  5.                  IF      :DEF:__MICROLIB        ;这里会判断是否定义了__MICROLIB,即表示是否使用MicroLib库,可以看仙女棒中是否勾选
  6.                  EXPORT  __initial_sp                ;如果使用MicroLib库,则给__initial_sp、__heap_base、__heap_limit给全局属性,可以让外部文件调用
  7.                  EXPORT  __heap_base
  8.                  EXPORT  __heap_limit
  9.                  ELSE
  10.                  ;如果没有使用MicroLib库,则使用双段存储器模式,并且声明__user_initial_stackheap全局属性,由用户自行初始化堆栈
  11.                  IMPORT  __use_two_region_memory       
  12.                  EXPORT  __user_initial_stackheap
  13.                  ;以下就是没有使用MicroLib库,由用户自行初始化堆栈的程序
  14. __user_initial_stackheap
  15.                  LDR     R0, =  Heap_Mem
  16.                  LDR     R1, =(Stack_Mem + Stack_Size)
  17.                  LDR     R2, = (Heap_Mem +  Heap_Size)
  18.                  LDR     R3, = Stack_Mem
  19.                  BX      LR
  20.                  ALIGN
  21.                  ENDIF
  22.                  END
 楼主| qn7a12 发表于 2023-7-27 23:49 | 显示全部楼层

9315464c2920121f83.png
配置使用MircroLib库

本节内容中需要主要,后续使用的中断的时候,一定要检查中断服务子程序是否写错或者未定义,否则很容易出现中断服务程序无限循环的情况。


您需要登录后才可以回帖 登录 | 注册

本版积分规则

40

主题

542

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部

40

主题

542

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部