内存映射
stm32的flash起始地址为0x0800 0000,结束地址为0x0800 0000加上芯片实际的Flash大小,不同芯片Flash大小不同,RAM同理。
对于STM32F103RCT6,Flash256KB,所以结束地址为0x0803 ffff。
Flash中的内容一般用来存储代码和一些定义为const的数据,断电不丢失。
RAM可以理解为内存,用来存储代码运行时的数据,变量等等,掉电数据丢失。
STM32将外设等映射为地址的形式,对地址的操作就是对外设的操作。
stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。
一般情况下,程序文件是从0x0800 0000地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。
在使用keil进行编写程序时,其编程地址的设置一般是:
程序的写入地址从0x0800 0000开始的,其大小为0x40000也就是256K的空间,换句话说就是告诉编译器Flash的空间是从0x0800 0000~0x0804 0000,RAM的地址从0x2000 0000开始,大小为48KB。
M3复位后,从0x0800 0004取出复位中断的地址,并且跳转到复位中断程序,中断执行完之后会跳到main函数,main函数里面一般是一个死循环,进去后就不会再退出,当有中断发生的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进入对应的中断函数,执行完中断函数之后,再次返回main函数。
内部Flash的构成
- 主存储器:一般说STM32内部FLASH的时候,都是指这个主存储器区域存储用户应用程序的空间,芯片型号说明中的 1M FLASH、 2M FLASH 都是指这个区域的大小。与其它 FLASH 一样,在写入数据前,要先按扇区擦除。
- 系统存储区:系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,负责实现串口、USB以及CAN等ISP烧录功能。
- OTP区域:One Time Program,只能写入一次的存储区域,容量为512字节,写入后数据就无法再更改,OTP常用于存储应用程序的加密秘钥。
- 选项字节:选项字节用于配置 FLASH 的读写保护、电源管理中的 BOR 级别、软件/硬件看门狗等功能,这部分共 32 字节。可以通过修改 FLASH 的选项控制寄存器修改。
对内部Flash的写入过程
- 解锁(固定的KEY值)
往FLASH秘钥寄存器FLASH_KEYR中写入KEY1=0x45670123
再往FLASH密钥寄存器FLASH_KEYR中写入KEY2=0xCDEF89AB - 数据操作位数:大部分应用场合都是32位的宽度。
- 擦除扇区
在写入新的数据前,需要先擦除存储区域,STM32提供了扇区擦除指令和整个FLASH擦除质量。
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何
Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位 SER ”置 1,并设置“扇
区编号寄存器位 SNB”,选择要擦除的扇区;
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(4) 等待 BSY 位被清零时,表示擦除完成。 - 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;
(4) 等待 BSY 位被清零时,表示写入完成。
查看工程内存的分布
由于内部 FLASH 本身存储有程序数据,若不是有意删除某段程序代码,一般不应修改程序空间的内容,在使用内部FLASH存储其他数据前需要了解哪一些空间已经写入了程序代码。
通过查询应用程序编译时产生的“*.map”后缀文件,打开map文件后,查看文件最后部分的区域,Memory Map of the image
这段代码提供了一张镜像的内存映射(Memory Map),其中包含了入口点地址以及主要的加载和执行区域信息。
镜像的入口点(Entry point)地址是0x08000131。
加载区域(Load Region) LR_IROM1(基地址:0x08000000,大小:0x00001cec,最大大小:0x00040000)用于存放程序代码和只读数据。它是一个绝对地址的加载区域。
执行区域(Execution Region) ER_IROM1(基地址:0x08000000,大小:0x00001cd0,最大大小:0x00040000)用于存放实际执行的代码。它也是一个绝对地址的执行区域。
这个内存映射中的加载和执行区域都是基于基地址0x0800 0000,并且大小相等。意味着整个镜像都被加载到该地址范围,并且执行也发生在相同的地址范围内。