你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

梳理STM32的基本知识

[复制链接]
攻城狮Melo 发布时间:2023-3-17 18:19
背景
一下内容是在ubuntu使用gcc自己编译stm32得出的自己的总结,使用keil的时候很多东西,都已经由keil做好了,包括启动文件就是不同的,链接脚本是不需要自己管的。只是为了更加深入的理解整个系统。

链接脚本
编译生成的各个静态库文件.a文件。需要使用链接脚本一起,才可以,链接(重新组织出)出一个,完整有序的,包含所有信息的bin文件。
以下以stm32f407的链接脚本为例

1.设置入口ENTRY
stm32设置的入口即是,中断向量表里的系统复位向量。
  1. 32 /* Entry Point */                                                                                                            
  2. 33 ENTRY(Reset_Handler)                                                                                                         
  3. 34                                                                                                                              
  4. 35 /* Highest address of the user mode stack */                                                                                 
  5. 36 _estack = 0x2001FFFF;    /* end of RAM */                                                                                    
  6. 37 /* Generate a link error if heap and stack don't fit into RAM */                                                            
  7. 38 _Min_Heap_Size = 0x200;;      /* required amount of heap  */                                                                 
  8. 39 _Min_Stack_Size = 0x400;; /* required amount of stack */  
复制代码

stm32上电时会做两件事,将0x080000000这个栈顶地址放到,msp寄存器。将第二个地址Reset_Handler赋给,pc指针。这样我们上电debug的时候会发现,单片机第一步就会停留在启动文件里的Reset_Handler哪里。


2.设置MEMORY
  1. 37 /* Generate a link error if heap and stack don't fit into RAM */                                                            
  2. 38 _Min_Heap_Size = 0x200;;      /* required amount of heap  */                                                                 
  3. 39 _Min_Stack_Size = 0x400;; /* required amount of stack */                                                                     
  4. 40                                                                                                                              
  5. 41 /* Specify the memory areas */                                                                                               
  6. 42 MEMORY                                                                                                                       
  7. 43 {                                                                                                                           
  8. 44 FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K                                                                        
  9. 45 RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K                                                                          
  10. 46 CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K                                                                        
  11. 47 }
复制代码

链接脚本基本就分为两个部分,memory和sections。其中memory规定了单片机rom和ram的地址和大小。每种芯片的这一部分的内容应该都是不一样的。


3.设置SECTIONS
接下来主要是看sections这个部分,通过这个部分我们就可以看到整个映像的各个部分的内容是放在哪里的。
  1. 52   /* The startup code goes first into FLASH */                                                                              
  2. 53   .isr_vector :                                                                                                              
  3. 54   {                                                                                                                          
  4. 55     . = ALIGN(4);                                                                                                            
  5. 56     KEEP(*(.isr_vector)) /* Startup code */                                                                                 
  6. 57     . = ALIGN(4);                                                                                                            
  7. 58   } >FLASH  
复制代码

第一部分当然是启动文件,其中最重要的就是中断向量表。启动文件里,规定了有哪些中断函数,发生中断时间时,会自动跳转到对应的中断函数,不同的芯片定义的函数是不一样的。
需要注意的是bin文件里面,包含了,代码段,只读数据段,数据段,bss段(未初始化的全局变量,只有bss段的地址大小描述信息,并不真正改变bin文件的大小),堆栈(同样不会真正占用bin文件的大小)等全部信息。这只是加载的镜像文件,真正在执行的时候,并不是所有的文件都是在rom里面执行的。链接脚本会将数据段等,从rom里面拷贝到ram里面执行。

放到rom里面的内容
  1. 60   /* The program code and other data goes into FLASH */                                                                     
  2. 61   .text :                                                                                                                    
  3. 62   {                                                                                                                          
  4. 63     . = ALIGN(4);                                                                                                            
  5. 64     *(.text)           /* .text sections (code) */                                                                           
  6. 65     *(.text*)          /* .text* sections (code) */                                                                          
  7. 66     *(.glue_7)         /* glue arm to thumb code */                                                                          
  8. 67     *(.glue_7t)        /* glue thumb to arm code */                                                                          
  9. 68     *(.eh_frame)                                                                                                            
  10. 69                                                                                                                              
  11. 70     KEEP (*(.init))                                                                                                         
  12. 71     KEEP (*(.fini))                                                                                                         
  13. 72                                                                                                                              
  14. 73     . = ALIGN(4);                                                                                                            
  15. 74     _etext = .;        /* define a global symbols at end of code */                                                         
  16. 75   } >FLASH
  17.   77   /* Constant data goes into FLASH */                                                                                       
  18. 78   .rodata :                                                                                                                  
  19. 79   {                                                                                                                          
  20. 80     . = ALIGN(4);                                                                                                            
  21. 81     *(.rodata)         /* .rodata sections (constants, strings, etc.) */                                                     
  22. 82     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */                                                   
  23. 83     . = ALIGN(4);                                                                                                            
  24. 84   } >FLASH  

复制代码

可以看出放到rom里面的是代码段,和只读的数据段,例如字符串。

放到ram里面的内容
  1. 117   /* Initialized data sections goes into RAM, load LMA copy after code */
  2. 118   .data :
  3. 119   {
  4. 120     . = ALIGN(4);
  5. 121     _sdata = .;        /* create a global symbol at data start */
  6. 122     *(.data)           /* .data sections */
  7. 123     *(.data*)          /* .data* sections */
  8. 124                                                                                                                              
  9. 125     . = ALIGN(4);                                                                                                            
  10. 126     _edata = .;        /* define a global symbol at data end */                                                              
  11. 127   } >RAM AT> FLASH  

  12. 151   .bss :                                                            
  13. 152   {                                                                 
  14. 153     /* This is used by the startup in order to initialize the .bss s    ecion */                                                            
  15. 154     _sbss = .;         /* define a global symbol at bss start */   
  16. 155     __bss_start__ = _sbss;                                          
  17. 156     *(.bss)                                                         
  18. 157     *(.bss*)
  19. 158     *(COMMON)
  20. 159
  21. 160     . = ALIGN(4);
  22. 161     _ebss = .;         /* define a global symbol at bss end */
  23. 162     __bss_end__ = _ebss;
  24. 163   } >RAM

复制代码


可以看出来,数据段和bss段最终都是放到ram里面的。
注意:其中>RAM AT>FLASH这个命令告诉连接器,这段内容是需要搬运的,下载地址和实际运行的地址是不一样的。需要从flash复制到ram里面才可以跑的。

以上就是最终编译链接出的bin文件,是如何在单片机里面跑的。整个bin文件都会放到rom里面,包含了许多的信息,最终跑起来的时候会将,数据段从rom里面,拷贝到ram里面去执行。根据bin文件里的信息,也会知道,bss段,堆栈的地址和大小,这样整个系统就可以跑起来了。(切记不是直接放到ram里面的,因为整个bin文件都是放到rom里面的,要在ram里面使用的时候,是需要拷贝的。也就是说加载的和执行的是不一样的)

20190314185539724.png


启动文件
在单片机跑到mian函数,应用程序之前的代码就是启动文件的代码。
下面我们来具体分析一下这个里面包含的内容:
  1. 143 g_pfnVectors:                                                                                                                                                                       
  2. 144   .word  _estack                                                                                                                                      
  3. 145   .word  Reset_Handler                                                                                                                                
  4. 146   .word  NMI_Handler                                                                                                                                 
  5. 147   .word  HardFault_Handler                                                                                                                           
  6. 148   .word  MemManage_Handler                                                                                                                           
  7. 149   .word  BusFault_Handler                                                                                                                             
  8. 150   .word  UsageFault_Handler                                                                                                                           
  9. 151   .word  0                                                                                                                                            
  10. 152   .word  0                                                                                                                                            
  11. 153   .word  0                                                                                                                                            
  12. 154   .word  0                                                                                                                                            
  13. 155   .word  SVC_Handler                                                                                                                                 
  14. 156   .word  DebugMon_Handler                                                                                                                             
  15. 157   .word  0                                                                                                                                            
  16. 158   .word  PendSV_Handler                                                                                                                              
  17. 159   .word  SysTick_Handler                                                                                                                              
  18. 160                                                                                                                                                      
  19. 161   /* External Interrupts */                                                                                                                           
  20. 162   .word     WWDG_IRQHandler                   /* Window WatchDog              */                                                                     
  21. 163   .word     PVD_IRQHandler                    /* PVD through EXTI Line detection */                                                                  
  22. 164   .word     TAMP_STAMP_IRQHandler   
  23. ...
复制代码

以上可以看出来,flash最开头的地方就是,中断向量表,从地址0x0800000,开始,第一个就是栈顶指针,第二个就是,Reset_Handler,地址0x08000004。系统复位进入Reset_Handler对应的中断函数,接下来我们看一下,中断函数里面有什么。
  1. 79 Reset_Handler:                                                                                                                                       
  2. 80   ldr   sp, =_estack     /* set stack pointer */                                                                                                      
  3. 81                                                                                                                                                      
  4. 82 /* Copy the data segment initializers from flash to SRAM */                                                                                          
  5. 83   movs  r1, #0                                                                                                                                                                     
  6. 84   b  LoopCopyDataInit                                                                                                                                 
  7. 85                                                                                                                                                      
  8. 86 CopyDataInit:                                                                                                                                         
  9. 87   ldr  r3, =_sidata                                                                                                                                   
  10. 88   ldr  r3, [r3, r1]                                                                                                                                   
  11. 89   str  r3, [r0, r1]                                                                                                                                   
  12. 90   adds  r1, r1, #4                                                                                                                                    
  13. 91                                                                                                                                                      
  14. 92 LoopCopyDataInit:                                                                                                                                    
  15. 93   ldr  r0, =_sdata                                                                                                                                    
  16. 94   ldr  r3, =_edata                                                                                                                                    
  17. 95   adds  r2, r0, r1                                                                                                                                    
  18. 96   cmp  r2, r3                                                                                                                                         
  19. 97   bcc  CopyDataInit                                                                                                                                   
  20. 98   ldr  r2, =_sbss                                                                                                                                    
  21. 99   b  LoopFillZerobss                                                                                                                                 
  22. 100 /* Zero fill the bss segment. */                                                                                                                     
  23. 101 FillZerobss:                                                                                                                                          
  24. 102   movs  r3, #0                                                                                                                                       
  25. 103   str  r3, [r2], #4                                                                                                                                   
  26. 104                                                                                                                                                      
  27. 105 LoopFillZerobss:                                                                                                                                      
  28. 106   ldr  r3, = _ebss                                                                                                                                    
  29. 107   cmp  r2, r3                                                                                                                                         
  30. 108   bcc  FillZerobss                                                                                                                                    
  31. 109                                                                                                                                                      
  32. 110 /* Call the clock system intitialization function.*/                                                                                                  
  33. 111   bl  SystemInit                                                                                                                                      
  34. 112 /* Call static constructors */                                                                                                                        
  35. 113 //  bl __libc_init_array                                                                                                                              
  36. 114 /* Call the application's entry point.*/                                                                                                              
  37. 115   bl  main                                                                                                                                            
  38. 116   bx  lr                                                                                                                                             
  39. 117 .size  Reset_Handler, .-Reset_Handler   
复制代码

怎么样,片子怎么跑起来的是不是非常清晰。
首先设置栈顶指针
拷贝数据段
清bss段
执行函数SystemInit ,初始化系统时钟等等。
跳转到main函数

IAP远程升级
中断向量表的重定位(摘自cotex3权威指南):

20190315153701342.png

有了以上的背景知识,其实远程升级是一件很简单的事情。具体思路如下:
1.有一份iap代码,中断向量表在0x08000000,主要工作就是对升级数据包即app程序的代码,进行接收(也可以在app代码里面接收),校验。并将校验通过的代码写进0x08000000之后的app的地址,最后跳转到该地址。
2.重新设置app中断向量表地址,设置的地方就在SystemInit 里设置向量偏移寄存器就可以了。这样APP的代码就可以跑起来了。iap的代码不变,可以不断地升级app的代码。

值得注意的是:工程里正在使用的只有一份中断向量表,在app中就不会使用iap的中断向量表。系统复位之后,设置的中断向量表没用了。因此每次复位之后都会,执行iap的代码,最终跳转到app。

20190315154842840.png


实际应用举例
stm32的map文件

某个工程的文件编译出的文件

20210311205914888.png

对应的map文件

20210311210320145.png

可以看出来: 使用的ram的大小 ram = 7728 + 408 = 8136;
根据map文件,计算栈顶指针为:20001ac8 + 1280 = 0x20001fc8; 而 1fc8的大小刚好是8136。
所以实际的运行视图为,依次为:
内存起始地址
全局变量
静态变量

堆内容
栈内容

内存结束地址

可以看出来,堆的生长方向为,由小达大
栈的生长方向为,由大到小。
————————————————
版权声明:raoxu_1154492168
如有侵权请联系删除




收藏 评论0 发布时间:2023-3-17 18:19

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版