STM32之FLASH读写


 

stm32内部flash主要用于存储代码,应用程序就是通过下载器sh烧录到内部flash的,flash掉电不会丢失,芯片ch重新商店内核从flash中加载代码运行的。还可以在运行过程中对flash进行读写操作。

区域  名称  块地址  大小
主存储器
 
0x0800 0000 - 0x0800 07FF  2 Kbytes
0x0800 0800 - 0x0800 0FFF  2 Kbytes
0x0800 1000 - 0x0801 17FF  2 Kbytes
0x0800 1800 - 0x0801 FFFF  2 Kbytes
.
.
.
255  0x0807 F800 - 0x0807 FFFF  2 Kbytes
系统存储区  0x1FFF F000 - 0x1FFF F7FF  2 Kbytes
选项字节  0x1FFF F800 - 0x1FFF F80F  16 bytes

对内部 FLASH 的写入过程
1. 解锁
由于内部 FLASH 空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给控制寄存器 FLASH_CR 上锁,这个时候不允许设置FLASH 的控制寄存器,从而不能修改 FLASH 中的内容。
所以对 FLASH 写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) 往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
2. 页擦除
在写入新的数据前,需要先擦除存储区域, STM32 提供了页(扇区)擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
页擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活页擦除寄存器位 PER ”置 1,
(3) 用 FLASH_AR 寄存器选择要擦除的页;
(4) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(5) 等待 BSY 位被清零时,表示擦除完成。
3. 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 向指定的 FLASH 存储器地址执行数据写入操作, 每次只能以 16 位的方式写入;
(4) 等待 BSY 位被清零时,表示写入完成。
 

可以在map中看到使用情况

Unused ranges:(未使用的空间)

     From                To                        Size

         ----                --                           ----
  0x800'a620         0x803'ffff               0x3'59e0
  0x2000'6ac4       0x2000'6ac7         0x4
  0x2000'fac8        0x2000'ffff             0x538

(1) 调用 FLASH_Unlock 解锁;
(2) 根据起始地址及结束地址计算要擦除多少页;
(3) 调用 FLASH_ClearFlag 清除各种标志位;
(4) 使用循环调用 FLASH_ErasePage 擦除页, 每次擦除一页;
(5) 使用循环调用 FLASH_ProgramWord 函数向起始地址至结束地址的存储区域都写入变量 “Data” 存储的数值数值;
(6) 调用 FLASH_Lock 上锁;
(7) 使用指针读取写入的数据内容并校验。


写入数据

/* 解锁 */
FLASH_Unlock();
/* 计算要擦除多少页 */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* 清空所有标志位 */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR |
FLASH_FLAG_WRPRTERR);
/* 按页擦除*/
for (EraseCounter = 0; (EraseCounter < NbrOfPage) &&
(FLASHStatus == FLASH_COMPLETE); EraseCounter++) {
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR +
(FLASH_PAGE_SIZE * EraseCounter));
}
/* 向内部 FLASH 写入数据 */
Address = WRITE_START_ADDR;
while ((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE)) {
FLASHStatus = FLASH_ProgramWord(Address, Data);
Address = Address + 4;
}
FLASH_Lock();

读取数据

/* 检查写入的数据是否正确 */
Address = WRITE_START_ADDR;
while ((Address < WRITE_END_ADDR) && (MemoryProgramStatus != FAILED)) {
if ((*(__IO uint32_t*) Address) != Data) {
MemoryProgramStatus = FAILED;
}
Address += 4;
}
return MemoryProgramStatus;
}

猜你喜欢

转载自blog.csdn.net/c1063891514/article/details/81805928