stm32基本知识的梳理

背景

一下内容是在ubuntu使用gcc自己编译stm32得出的自己的总结,使用keil的时候很多东西,都已经由keil做好了,包括启动文件就是不同的,链接脚本是不需要自己管的。只是为了更加深入的理解整个系统。

链接脚本

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

1.设置入口ENTRY

stm32设置的入口即是,中断向量表里的系统复位向量。

 32 /* Entry Point */                                                                                                            
 33 ENTRY(Reset_Handler)                                                                                                         
 34                                                                                                                              
 35 /* Highest address of the user mode stack */                                                                                 
 36 _estack = 0x2001FFFF;    /* end of RAM */                                                                                    
 37 /* Generate a link error if heap and stack don't fit into RAM */                                                             
 38 _Min_Heap_Size = 0x200;;      /* required amount of heap  */                                                                 
 39 _Min_Stack_Size = 0x400;; /* required amount of stack */  

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

2.设置MEMORY

 37 /* Generate a link error if heap and stack don't fit into RAM */                                                             
 38 _Min_Heap_Size = 0x200;;      /* required amount of heap  */                                                                 
 39 _Min_Stack_Size = 0x400;; /* required amount of stack */                                                                     
 40                                                                                                                              
 41 /* Specify the memory areas */                                                                                               
 42 MEMORY                                                                                                                       
 43 {                                                                                                                            
 44 FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K                                                                         
 45 RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K                                                                          
 46 CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K                                                                         
 47 } 

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

3.设置SECTIONS

接下来主要是看sections这个部分,通过这个部分我们就可以看到整个映像的各个部分的内容是放在哪里的。

 52   /* The startup code goes first into FLASH */                                                                               
 53   .isr_vector :                                                                                                              
 54   {                                                                                                                          
 55     . = ALIGN(4);                                                                                                            
 56     KEEP(*(.isr_vector)) /* Startup code */                                                                                  
 57     . = ALIGN(4);                                                                                                            
 58   } >FLASH  

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

  1. 放到rom里面的内容
 60   /* The program code and other data goes into FLASH */                                                                      
 61   .text :                                                                                                                    
 62   {                                                                                                                          
 63     . = ALIGN(4);                                                                                                            
 64     *(.text)           /* .text sections (code) */                                                                           
 65     *(.text*)          /* .text* sections (code) */                                                                          
 66     *(.glue_7)         /* glue arm to thumb code */                                                                          
 67     *(.glue_7t)        /* glue thumb to arm code */                                                                          
 68     *(.eh_frame)                                                                                                             
 69                                                                                                                              
 70     KEEP (*(.init))                                                                                                          
 71     KEEP (*(.fini))                                                                                                          
 72                                                                                                                              
 73     . = ALIGN(4);                                                                                                            
 74     _etext = .;        /* define a global symbols at end of code */                                                          
 75   } >FLASH 
  77   /* Constant data goes into FLASH */                                                                                        
 78   .rodata :                                                                                                                  
 79   {                                                                                                                          
 80     . = ALIGN(4);                                                                                                            
 81     *(.rodata)         /* .rodata sections (constants, strings, etc.) */                                                     
 82     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */                                                    
 83     . = ALIGN(4);                                                                                                            
 84   } >FLASH  
 

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

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

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

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

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

启动文件

在单片机跑到mian函数,应用程序之前的代码就是启动文件的代码。
下面我们来具体分析一下这个里面包含的内容:

143 g_pfnVectors:                                                                                                                                                                       
144   .word  _estack                                                                                                                                      
145   .word  Reset_Handler                                                                                                                                
146   .word  NMI_Handler                                                                                                                                  
147   .word  HardFault_Handler                                                                                                                            
148   .word  MemManage_Handler                                                                                                                            
149   .word  BusFault_Handler                                                                                                                             
150   .word  UsageFault_Handler                                                                                                                           
151   .word  0                                                                                                                                            
152   .word  0                                                                                                                                            
153   .word  0                                                                                                                                            
154   .word  0                                                                                                                                            
155   .word  SVC_Handler                                                                                                                                  
156   .word  DebugMon_Handler                                                                                                                             
157   .word  0                                                                                                                                            
158   .word  PendSV_Handler                                                                                                                               
159   .word  SysTick_Handler                                                                                                                              
160                                                                                                                                                       
161   /* External Interrupts */                                                                                                                           
162   .word     WWDG_IRQHandler                   /* Window WatchDog              */                                                                      
163   .word     PVD_IRQHandler                    /* PVD through EXTI Line detection */                                                                   
164   .word     TAMP_STAMP_IRQHandler   
...

以上可以看出来,flash最开头的地方就是,中断向量表,从地址0x0800000,开始,第一个就是栈顶指针,第二个就是,Reset_Handler,地址0x08000004。系统复位进入Reset_Handler对应的中断函数,接下来我们看一下,中断函数里面有什么。

 79 Reset_Handler:                                                                                                                                        
 80   ldr   sp, =_estack     /* set stack pointer */                                                                                                      
 81                                                                                                                                                       
 82 /* Copy the data segment initializers from flash to SRAM */                                                                                           
 83   movs  r1, #0                                                                                                                                                                      
 84   b  LoopCopyDataInit                                                                                                                                 
 85                                                                                                                                                       
 86 CopyDataInit:                                                                                                                                         
 87   ldr  r3, =_sidata                                                                                                                                   
 88   ldr  r3, [r3, r1]                                                                                                                                   
 89   str  r3, [r0, r1]                                                                                                                                   
 90   adds  r1, r1, #4                                                                                                                                    
 91                                                                                                                                                       
 92 LoopCopyDataInit:                                                                                                                                     
 93   ldr  r0, =_sdata                                                                                                                                    
 94   ldr  r3, =_edata                                                                                                                                    
 95   adds  r2, r0, r1                                                                                                                                    
 96   cmp  r2, r3                                                                                                                                         
 97   bcc  CopyDataInit                                                                                                                                   
 98   ldr  r2, =_sbss                                                                                                                                     
 99   b  LoopFillZerobss                                                                                                                                  
100 /* Zero fill the bss segment. */                                                                                                                      
101 FillZerobss:                                                                                                                                          
102   movs  r3, #0                                                                                                                                        
103   str  r3, [r2], #4                                                                                                                                   
104                                                                                                                                                       
105 LoopFillZerobss:                                                                                                                                      
106   ldr  r3, = _ebss                                                                                                                                    
107   cmp  r2, r3                                                                                                                                         
108   bcc  FillZerobss                                                                                                                                    
109                                                                                                                                                       
110 /* Call the clock system intitialization function.*/                                                                                                  
111   bl  SystemInit                                                                                                                                      
112 /* Call static constructors */                                                                                                                        
113 //  bl __libc_init_array                                                                                                                              
114 /* Call the application's entry point.*/                                                                                                              
115   bl  main                                                                                                                                            
116   bx  lr                                                                                                                                              
117 .size  Reset_Handler, .-Reset_Handler    

怎么样,片子怎么跑起来的是不是非常清晰。

  1. 首先设置栈顶指针
  2. 拷贝数据段
  3. 清bss段
  4. 执行函数SystemInit ,初始化系统时钟等等。
  5. 跳转到main函数

IAP远程升级

中断向量表的重定位(摘自cotex3权威指南):
在这里插入图片描述
有了以上的背景知识,其实远程升级是一件很简单的事情。具体思路如下:

  1. 有一份iap代码,中断向量表在0x08000000,主要工作就是对升级数据包即app程序的代码,进行接收(也可以在app代码里面接收),校验。并将校验通过的代码写进0x08000000之后的app的地址,最后跳转到该地址。
  2. 重新设置app中断向量表地址,设置的地方就在SystemInit 里设置向量偏移寄存器就可以了。这样APP的代码就可以跑起来了。iap的代码不变,可以不断地升级app的代码。

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

实际应用举例

stm32的map文件

某个工程的文件编译出的文件
在这里插入图片描述
对应的map文件
在这里插入图片描述
可以看出来: 使用的ram的大小 ram = 7728 + 408 = 8136;
根据map文件,计算栈顶指针为:20001ac8 + 1280 = 0x20001fc8; 而 1fc8的大小刚好是8136。
所以实际的运行视图为,依次为:

内存起始地址
全局变量
静态变量
堆
堆内容
栈内容
栈
内存结束地址

可以看出来,堆的生长方向为,由小达大
栈的生长方向为,由大到小。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是由ST公司生产的一系列微控制器单片机(MCU),采用ARM的CPU架构。它包括多个系列,如STM32F10x、STM32F2xx、STM32F3xx、STM32F4xx和STM32F7xx,根据FLASH容量的不同可以分为大容量、中容量和小容量。\[1\] 学习STM32的资料包括中文参考手册、STM32F103ZET数据手册和Cortex-M3权威指南。中文参考手册主要讲解寄存器说明和各个模块的框图,STM32F103ZET数据手册则介绍了电气特性和资源信息。Cortex-M3权威指南则详细介绍了内核的结构和寄存器。此外,还可以参考ST官方网站www.stmcu.com获取更多资料。\[1\] STM32的外部管脚命名方式与51单片机不同。51单片机使用P0-P3端口名和P0.x管脚名称,而STM32使用PA-PG端口名和PA.x管脚名称。\[1\] STM32具有强大的中断支持,支持256个中断,其中包括16个内核中断和240个外部中断。但实际上,STM32并没有使用CM3内核的全部功能,而是只用了一部分。STM32有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。在STM32F103系列上,可屏蔽中断数量为60个。\[2\] STM32的芯片由两部分组成,即Cortex-M3微控制器内核和ST公司开发的片上外设。Cortex-M3微控制器内核是ARM公司推出的基于ARMv7架构的32位微控制器内核,而ST公司则在此基础上开发了STM32单片机的片上外设。\[3\] 以上是关于STM32基础知识的入门介绍。如果您有更具体的问题,我可以为您提供更详细的解答。 #### 引用[.reference_title] - *1* [STM32入门之基础知识](https://blog.csdn.net/qq_41174320/article/details/80717363)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [STM32开发基础知识入门](https://blog.csdn.net/weixin_44918105/article/details/129690074)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [STM32入门基础知识点](https://blog.csdn.net/STM89C56/article/details/105937019)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值