一、存储器结构
1.1 STM32内存结构
型号说明
以STM32F103RBT6这个型号的芯片为例,该型号的组成为7个部分,其命名规则如下:
ST 是公司名,意法半导体。M 代表Cortex-M内核。32 代表32位微控制器。
F103 是芯片系列。
R 代表引脚数。B 代表内嵌FLASH容量。128K字节的内嵌FLASH。
T 代表封装方式。6 代表工作温度范围。
内存空间
以STM32F103RBT6为例,内部存储空间包括128KB的FLASH,20KB的SRAM。
由于FLASH每次写入前都要擦除,适合存放代码和只读数据。SRAM读写快速,但是断电丢失,适合存放临时数据。
通过 Keil 的 target 设置界面,可以看到内部FLASH和内部RAM的起始映射地址和大小设置,这里一般选择了芯片型号会有默认值。
关于下载地址,在IAP使用BootLoader程序,跳转到APP程序的方式下,比如用户自设BootLoader的代码大小为0x4000,那么就应该把BootLoader放在内部Flash起始地址0x0800 0000的位置,大小设置为0x4000(可以给大);对应的把APP程序放在起始地址0x0800 4000的位置,大小设置为对应程序大小。
FLASH用来存储编译好的程序文件,SRAM用来存储程序运行所需的临时数据。
0x0000 0000 ~ 0x0007 FFFF,也就是代码区的这512KB的字节启动内存空间,是预留的。
STM32有三种启动方式,
FLASH启动,代码存放在0x0800 0000
系统存储器启动,代码存放在0x1FFF F000
SRAM启动,代码存放在0x2000 0000
可以通过BOOT引脚设置。
Boot引脚决定了字节启动内存空间被映射到哪一块区域。
不管是FLASH启动、系统存储区启动还是RAM启动,代码第一步都是去0x0000 0000去找MSP指针,去0x0000 0004去找PC指针。
根据映射关系,实际找的位置可以是FLASH的0x0800 0000,系统存储区的0x1FFF F000,SRAM的0x2000 0000。
另外,系统自带的BootLoader程序,是放在0x1FFF F000的,固定大小,禁止修改。
内存映射
STM32的内存和外设的地址,不管内部还是外部,都被映射在一个4GB的虚拟地址空间内。
可访问的存储器空间被分为 8个主要块,每个块为512MB。
分别作为 代码区、SRAM区、片上外设、1G的外部存储器扩展、1G的片外外设、不同厂商的专用外设总线(包括NVIC、调试组件等)。
其中1G的外部存储器扩展,拿来给FSMC1、FMSC2使用。1G的片外外设,高位拿了512M给FSMC使用。
CCM RAM:
CCM RAM,核心耦合内存,是给F4系列专用的全速 64KB RAM,官方文档指出芯片的SRAM大小为128K+64K,后面的64K就是指CCM RAM。
CCM RAM 大小为 0x1000_0000 ~ 0x1000_FFFF,不经过总线矩阵,直接与内核相连,仅供内核访问。其地址位于代码区,与常规SRAM区不连续,DMA与外设也无法直接使用它们。可以用编译器指令去写链接脚本文件(.icf),把数据定义在CCM RAM中,extern出来使用。
以F429系列为例,典型的存储器映射布局:
代码区的 0x0800 0000 ~0x080F FFFF (1MB),存储程序代码
SRAM区的 0x20000 0000~0x2003 FFFF (256KB),作为堆栈
片上外设的 0x4000 0000~0x4000 FFFF,用于APB1上的外设;
0x4001 0000~0x400F FFFF,用于APB2上的外设。
关于 FSMC 和 FMC:
FMC是STM32F429/439专有的,因为驱动SDRAM时需要定时刷新,而FSMC存在于F1和F4中我们常用的芯片中。FMC 支持 8/16/32位数据宽度,LCD一般是16位宽度的,
FMC 将外部存储器划分为 6 个固定大小为 256M 字节的存储块,也就是总共管理 1.5GB 空间。每个块又被分为 4 个存储区,一个区 64 M。
FSMC 只支持 BANK1~4。
0x6000 0000~0x6FFF FFFF BANK1 SRAM使用
0x7000 0000~0x7FFF FFFF BANK2
0x8000 0000~0x8FFF FFFF BANK3 FLASH使用
0x9000 0000~0x9FFF FFFF BANK4 PC卡使用
0xC000 0000~0xCFFF FFFF BANK5
0xD000 0000~0xDFFF FFFF BANK6 SDRAM使用
1.2 STM32启动过程
概括
.s启动文件,汇编程序,系统上电复位后首先执行。
1、初始化主堆栈指针MSP,指向栈顶
2、初始化 PC 指针,指向下一条要执行的指令地址
3、初始化中断向量表(复位中断服务函数中初始化中断向量表)
4、调用SystemInit函数初始化系统时钟
5、调用 C 库函数 _main 初始化用户堆栈,调用main函数
ResetHandler是弱定义,用户可以自己实现。
如果KEIL勾选了使用微库,则.s文件的__MICROLIB宏被定义,由_main初始化堆栈。如果没有定义 __MICROLIB,则才用双段存储器模式,且声明标号 __user_initial_stackheap 具有全局属性,让用户自己来初始化堆栈。
C语言内存管理分为:代码段、数据段、BSS段、堆、栈、mmap映射
_main初始化用户堆栈,片上SRAM区作为 数据段、BSS段、堆、栈、mmap映射 的区域。
mmap是linux系统编程涉及的映射文件
系统ISP启动流程
正常情况下,程序从Flash启动时的流程如下:
1. 程序从Flash启动,根据中断向量表找到复位中断处理函数的地址。(0x0800 0004处是中断向量表的起始地址,也是中断向量表的起始,记录了复位中断处理函数的地址)。配置系统时钟。执行_main,完成堆栈的初始化。
2. 执行复位中断处理函数,初始化系统环境后跳转到main函数。
3. 在main函数的死循环中运行,直到有中断发生。
4. 中断发生时,跳转到中断向量表起始处,根据中断信号源跳找到相应的中断处理函数。
5. 中断处理函数执行完后返回到main函数继续运行。
系统IAP启动流程
在Flash中存储了两套程序:
Bootloader程序:自举程序。负责接收数据(APP应用程序代码)并将其存储到Flash中。
APP应用程序:我们真正的应用程序。
程序从Flash启动,根据中断向量表找到复位中断处理函数的地址。
执行复位中断处理函数后,跳转到Bootloader的main函数。该函数检查并保存新的APP程序到Flash,然后跳转到第二套程序运行。
一旦进入新的APP程序,根据中断向量表找到复位中断处理函数,进入App程序的main函数运行。
为确保中断能正确跳转到APP程序的中断处理函数,需要在APP程序中修改中断向量表的偏移,确保中断发生时能正确执行APP程序的中断处理函数。
SCB->VTOR寄存器存放中断向量表的偏移量
二、 系统架构
STM32主系统由AHB总线矩阵构成。
AHB总线矩阵,可以实现主控总线到被控总线的访问。
2.1 主控和被控总线
八条主控总线包括:
Cotex内核的 I、D、S 总线。也就是指令、数据、系统总线。
DMA-存储器总线。 DMA-存储器总线有2条。
DMA-外设总线。
以太网-DMA总线。
USB-DMA总线。
七条被控总线包括:
内部FLASH ICode总线
内部FLASH DCode总线
主要内部 SRAM1 (112KB)
辅助内部 SRAM2 (16KB)
辅助内部 SRAM3 (64KB) (仅适用于F42x和F43x)
AHB总线
FSMC总线
主控总线通过总线矩阵来连接被控总线, 总线矩阵用于主控总线之间的访问仲裁管理,仲裁采用循环调度算法。 其实就是外设请求先来后到。
通过指令总线获取程序指令。访问对象是内部FLASH/SRAM。
通过数据总线获取常量和调试访问。访问对象是内部FLASH。
通过系统总线获取内部SRAM和片上外设,访问对象是内部SRAM和AHB/APB的外设数据。
通过DMA-存储器总线(1、2)访问内部SRAM和FSMC。
通过DMA-外设总线访问AHB/APB外设,内部SRAM和FSMC。
通过以太网-DMA总线访问内部SRAM和FSMC。
通过USB-DMA总线访问内部SRAM和FSMC。
SRAM可放程序缓存,因此 I 总线可访问内部FLASH和SRAM。
I、D、S总线都能依靠依靠FSMC访问外部存储器。I、D、S总线各自都有自己的地址线、数据线、控制线。
立即数不放在存储器或内存中,一般是常数。
FLASH放程序和指令。SRAM只可能放指令的缓存。
外部存储器可能放代码也可能放指令,因此 I、D、S总线均可依靠FSMC访问外部存储器。
2.2 AHB/APB 总线桥和时钟源
外设分为高速外设和低速外设。
1、高速外设
由于高速外设实在是太多了,一个总线不够,所以分了三个,分别是 AHB1/AHB2/AHB3,所有“高速外设”寄存器组分批挂接在 AHB1/AHB2/AHB3 上。
2、低速外设
“低速外设”的速度比较低,不能直接挂在“总线矩阵”上,所以先经过“桥”后再引出“低速总线”,挂在低速总线上。由于“低速外设”比较多,所以就分了两个低速总线,分别是 APB1/APB2,所有的“低速外设”分批挂接在 APB1/APB2 上。
AHB-APB总线桥,
将系统时钟分频后,传递到APB1、APB2两条总线,再传递到挂载的外设上。
APB1总线、APB2总线
负责外设时钟使能,并为外设提供时钟信号。
MCU 的系统时钟可以选择 HSI、LSI、HSE、LSE 四种时钟源,
一般设置为16M、32K、8M、32.768K,单位(HZ)
系统时钟F1一般是72MHZ,
F429的SYSCLK根据板子功率有
SYSCLK 180MHZ,AHB是1分频,180MHZ,APB2是90MHZ,APB1是45MHZ
SYSCLK 168MHZ,AHB是1分频,168MHZ,APB2是84MHZ,APB1是42MHZ
HSE和HSI经过 /M 分频之后传递到锁相环,
锁相环会使晶振走过*N倍频器,
之后如果再走过/P分频则可以直接作为系统时钟SYSCLC,
如果走过/Q分频则可以作为其他外设的时钟。
系统时钟之后会去到AHB总线的时钟
AHB时钟经过总线桥会去到APB1和APB2(这俩实际上是由AHB1桥接过来的)