STM32-内部Flash读写

  1. STM32的内部Flash操作
    1. 1 内部储存空间
    2. 2 内部Flash的构成
    3. 3 Flash的读写操作
      1. 3.1 Flash写入
        1. 3.1.1解锁
        2. 3.1.2 擦除操作
      2. 3.1.3 写入操作

STM32的内部Flash操作

我们在设计单片机程序的时候,部分的需求是需要有掉电不丢失的功能。我们可能会使用EEPROM这种存储设备来进行数据的存储保证数据掉电不丢失。而在实际的应用场景中,我们并没有太多的数据量需要进行存储,可能只是一些程序上的参数需要保存。这个使用使用EEPROM就显得有点大材小用,从产品的角度思考这个模块也会给整个项目增加较大的成本。

此时使用单片机内部自带的flash来进行部分数据的掉电不丢失就非常极具性价比(虽然内部flash的读写寿命要少于EEPROM)

1 内部储存空间

stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同。

RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯片的RAM大小。不同的芯片RAM也不同。

stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。

一般情况下,程序文件是从 0x0800 0000 地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。

程序的写入地址从0x0800 0000开始的,其大小为0x80000也就是512K的空间,换句话说就是告诉编译器flash的空间是从0x0800 0000-0x0808 0000,RAM的地址从0x2000 0000开始,大小为0x10000也就是64K的RAM。这与STM32的内存地址映射关系是对应的。

M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执行完之后会跳到我们的main函数,main函数里边一般是一个死循环,进去后就不会再退出,当有中断发生的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进入对应的中断函数,执行完中断函数之后,再次返回main函数中。

2 内部Flash的构成

以STM32F103C8T6为例。它的Flash大小为64K x 8bit,即64k个字节的数据。

我们通常Page的方式来区分这些存储空间。在STM32的中容量和小容量的型号中,一般以1K字节作为一个扇区;在大容量的型号中,会以2K作为一个扇区的容量。

内部Flash的启始地址是0x8000 0000,那么以1K作为扇区的容量,那么第0页的范围就是0x8000 0000 ~ 0x8000 03FF(即是1024-1=1023=0x03FF)。那么STM32F103C8T6的内部Flash空间是64K的大小,所以它的最大页为。以下是部分页的范围:


page0: 0x8000 0000 ~ 0x8000 03FF

page1: 0x8000 0400 ~ 0x8000 07FF

page2: 0x8000 0800 ~ 0x8000 0BFF

page3: 0x8000 0C00 ~ 0x8000 0FFF

page4: 0X8000 1000 ~ 0X8000 13FF

…….

page62: 0x8000 F800 ~ 0x8000 FBFF

page63: 0x8000 FC00 ~ 0x8000 FFFF


3 Flash的读写操作

3.1 Flash写入

3.1.1解锁

为了防止误操作,在修改内存的时候需要我们对控制寄存器FLASH_CR进行解锁。解锁的方法是对FPEC键寄存器FLASH_KEYR写入解锁的秘钥。

秘钥的内容是0x4567 0123 CDEF 89AB,需要按顺序分别写入才能进行解锁。

1
2
3
4
5
6
7
8
9
10
11

/*Flash解锁函数*/
void Flash_unlock(void) {
if ((FLASH->CR & FLASH_CR_LOCK) != RESET) {//判断LOCK位
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
/*若LOCK位不为1,则执行解锁程序,向Flash_KEYR寄存器写入解锁密钥,密钥是唯一的,
一旦写错,就会锁死,只能复位后才能操作Flash*/
}
}

3.1.2 擦除操作

擦除和写入操作都需要先对Flash进行解锁,毕竟Flash擦除写入是一个比较严谨的过程,操作不当可能会导致系统故障单片机卡死。

1
2
3
4
5
6
7
8
9
10
11
12
/*Flash擦除函数*/
void EraseFlash(void)
{
Flash_unlock(); //解锁
SET_BIT(FLASH->CR, FLASH_CR_PER); //置位扇区擦除控制位
WRITE_REG(FLASH->AR, 0x08007C00); //对应扇区起始地址
SET_BIT(FLASH->CR, FLASH_CR_STRT); //开始扇区清除
while ((FLASH->SR & (FLASH_SR_BSY | FLASH_SR_EOP)) != 0x20) //等待擦除完毕
;
FLASH->SR |= FLASH_SR_EOP; //清除标志位
FLASH->CR = 0x80; //重新上锁,擦除完成
}

在程序中,擦除操作其实是以扇区为单位进行的,上方的代码中则是固定的擦除操作。其实原理就是首先将擦除控制位置位,接着讲扇区的启始地址写入ADDR寄存器(代码中是AR),扇区的单位是以单片机型号界定。接着置位擦除开始寄存器。等待擦除完成即可。完成后需要重新上锁。

3.1.3 写入操作

写入操作建立在擦除之后,因为在写入之前需要进行擦除。

1
2
3
4
5
6
7
8
9
10
11
12
13
/*Flash写入函数*/
void putFlash(void)
{
EraseFlash();
Flash_unlock(); //解锁
flashPtr = (__IO uint16_t *) 0x08007C00; //选择写入地址,只能是擦除的扇区内
SET_BIT(FLASH->CR, FLASH_CR_PG); //置位Flash写入控制位
*flashPtr = Flash_Data; //写入数据到flashPrt地址对应空间中
while ((FLASH->SR & (FLASH_SR_BSY | FLASH_SR_EOP)) != 0x20) //等待写入完成
;
FLASH->SR |= FLASH_SR_EOP; //清除标志位
FLASH->CR = 0x80; //重新上锁
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1186703947@qq.com

💰

×

Help us with donation

相册 动态菜单1