12.1.FMC 基础知识
闪存控制器(FMC),提供了片上闪存需要的所有功能。FMC 也提供了页擦除,整片擦除,以及32 位整字或 16 位半字编程闪存等操作。 GD32 MCU 支持不同类型编程的具体说明如下表 GD32 MCU 不同系列编程区别所示。

12.2.FMC 功能
支持 32 位整字或 16 位半字编程,页擦除和整片擦除操作;
支持 CPU 执行指令零等待区域(code area)和非零等待区域(data area); 大小为 16 字节的可选字节块可根据用户需求配置;
具有安全保护状态,可阻止对代码或数据的非法读访问;
相关术语说明
GD32F10x 和 F30x 分别有 MD(中容量) 、HD(大容量)、XD(超大容量) 、CL(互联型)系列,不同的系列外设资源有差异,使用固件库(Firmware)也要作相应的选择和定义。 中容量产品指Flash 容量为小于 256K 字节的系列;
大容量产品指 Flash 容量为 256K 至 512K 字节之间的 系列; 超大容量产品指 Flash 容量为 768K 至 3072K 字节之间的系列。
GD32F10X/F30X 系列容量汇总

不同容量工程选择说明,固件库是通过宏定义来区分的。

不同的系列 MCU flash 架构不一样,其中 GD32F 系列的 MCU flash 分 code area 和 data area, code area CPU 执行指令是零等待, GD32E 系列 flash 不分 code area 和 data are,但都要插入等待周期。 GD32 系列 Code area&Data area 汇总

读操作 闪存可以像普通存储空间一样直接寻址访问。对闪存取指令和取数据分别使用 CPU 的 IBUS 或 DBUS总线。
代码操作如:
uint32_t readflash[3] readflash [0] = *(__IO uint32_t*)(0x8004000); readflash [1] = *(__IO uint32_t*)((0x8004004); readflash [2] = *(__IO uint32_t*)((0x8004008);
页擦除
FMC 的页擦除功能使得主存储闪存的页内容初始化为高电平。 每一页都可以被独立擦除,而不影响其他页内容。
FMC 擦除页步骤如下:
◼ 确保 FMC_CTLx 寄存器不处于锁定状态;
◼ 检查 FMC_STATx 寄存器的 BUSY 位来判定闪存是否正处于擦写访问状态,若 BUSY 位为 1,则需等待该操作结束, BUSY 位变为 0;
◼ 置位 FMC_CTLx 寄存器的 PER 位;
◼ 将待擦除页的绝对地址( 0x08XX XXXX)写到 FMC_ADDRx 寄存器;
◼ 通过将 FMC_CTLx 寄存器的 START 位置 1 来发送页擦除命令到 FMC;
◼ 等待擦除指令执行完毕, FMC_STATx 寄存器的 BUSY 位清 0;
◼ 如果需要,使用 DBUS 读并验证该页是否擦除成功。

整片擦除
FMC 提供了整片擦除功能可以初始化主存储闪存块的内容。当设置 MER0 为 1 时,擦除过程仅作用于 Bank0,当设置 MER1 为 1 时,擦除过程仅作用于 Bank1,当设置 MER0 和 MER1 为 1 时,擦除过程作用于整片闪存。
整片擦除操作,寄存器设置具体步骤如下:
◼ 确保 FMC_CTLx 寄存器不处于锁定状态;
◼ 等待 FMC_STATx 寄存器的 BUSY 位变为 0;
◼ 如果单独擦除 Bank0,置位 FMC_CTL0 寄存器的 MER 位。如果单独擦除 Bank1,置位 FMC_CTL1 寄存器的 MER 位。如果整片擦除闪存,同时置位 FMC_CTL0 和 FMC_CTL1 寄存器的 MER 位;
◼ 通过将 FMC_CTLx 寄存器的 START 位置 1 来发送整片擦除命令到 FMC;
◼ 等待擦除指令执行完毕, FMC_STATx 寄存器的 BUSY 位清 0;
◼ 如果需要,使用 DBUS 读并验证是否擦除成功。

字编程操作
FMC 提供了一个 64 位、32 位整字/16 位半字编程功能,用来修改主存储闪存块内容。
编程操作使用各寄存器流程如下。
◼ 确保 FMC_CTLx 寄存器不处于锁定状态;
◼ 等待 FMC_STATx 寄存器的 BUSY 位变为 0;
◼ 置位 FMC_CTLx 寄存器的 PG 位;
◼ DBUS 写一个 32 位整字/16 位半字到目的绝对地址(0x08XXXXXX);
◼ 等待编程指令执行完毕, FMC_STATx 寄存器的 BUSY 位清 0;
◼ 如果需要,使用 DBUS 读并验证是否编程成功。

可选字节块擦除
FMC 提供了一个擦除功能用来初始化闪存中的可选字节块。
可选字节块擦除过程如下所示。
◼ 确保 FMC_CTL0 寄存器不处于锁定状态;
◼ 等待 FMC_STAT0 寄存器的 BUSY 位变为 0;
◼ 解锁 FMC_CTL0 寄存器的可选字节操作位;
◼ 等待 FMC_CTL0 寄存器的 OBWEN 位置 1;
◼ 置位 FMC_CTL0 寄存器的 OBER 位;
◼ 通过将 FMC_CTL0 寄存器的 START 位置 1 来发送可选字节块擦除命令到 FMC;
◼ 等待擦除指令执行完毕, FMC_STAT 寄存器的 BUSY 位清 0;
◼ 如果需要,使用 DBUS 读并验证是否擦除成功。当可选字节块擦除成功执行, FMC_STAT 寄存器的 ENDF 位置位。若 FMC_CTL0 寄存器的 ENDIE 位被置 1, FMC 将触发一个中断。
可选字节块编程
FMC 提供了一个 32 位整字/16 位半字编程功能,可用来修改可选字节块内容。可选字节块共有8 对可选字节。每对可选字节的高字节是低字节的补。当低字节被修改时, FMC 自动生成该选项字节的高字节。
字节块编程操作过程如下。
◼ 确保 FMC_CTL0 寄存器不处于锁定状态;
◼ 等待 FMC_STAT0 寄存器的 BUSY 位变为 0;
◼ 解锁 FMC_CTL0 寄存器的可选字节操作位;
◼ 等待 FMC_CTL0 寄存器的 OBWEN 位置 1;
◼ 置位 FMC_CTL0 寄存器的 OBPG 位;
◼ DBUS 写一个 32 位整字/16 位半字到目的地址;
◼ 等待编程指令执行完毕, FMC_STAT 寄存器的 BUSY 位清 0;
可选字节块说明
每次系统复位后,闪存的可选字节块被重加载到 FMC_OBSTAT 和 FMC_WP 寄存器,可选字节生效。可选字节的补字节具体为可选字节取反。当可选字节被重装载时,如果可选字节的补字节和可选字节不匹配, FMC_OBSTAT 寄存器的 OBERR 位将被置 1,可选字节被强制设置为 0xFF。若可选字节和其补字节同为 0xFF,则 OBERR 位不置位。
页擦除/编程保护
FMC 的页擦除/编程保护功能可以阻止对闪存的意外操作。当 FMC 对被保护页进行页擦除或编程操作时,操作本身无效且 FMC_STAT 寄存器的 WPERR 位将被置 1。如果 WPERR 位被置 1 且 FMC_CTL 寄存器的 ERRIE 位也被置 1 来使能相应的中断, FMC 将触发闪存操作出错中断,等待 CPU 处理。配置可选字节块的 WP [31:0]某位为 0 可以单独使能某几页的保护功能。如果在可选字节块执行了擦除操作,所有的闪存页擦除和编程保护功能都将失效。当可选字节的 WP 被改变时,需要系统复位使之生效。
12.3.软件配置说明
FMC 以 Program 配置为例来说明
Demo 一 (flash 编程)
demo 功能说明: MCU 上电启动后,对 MCU flash 的 0x8004000~ 0x08004800 的 2K 的区域写 0x01234567 数据,当编写错误的时候,LED 会亮。
软件配置步骤如下:
1)配置 led 指示灯;
gd_eval_led_init(LED2); gd_eval_led_init(LED3);
2)进行 page erase
void fmc_erase_pages(void) { uint32_t EraseCounter; fmc_unlock(); //FMC 解锁 fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR ); //清除标志 for(EraseCounter = 0; EraseCounter < PageNum; EraseCounter++){ fmc_page_erase(FMC_WRITE_START_ADDR + (FMC_PAGE_SIZE * EraseCounter)); //page 擦除 fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR ); //清除标志 } fmc_lock(); //FMC 加锁 }
- page erase 检查
void fmc_erase_pages_check(void) { uint32_t i; ptrd = (uint32_t *)FMC_WRITE_START_ADDR;//将写地址赋值指针 for(i = 0; i < WordNum; i++) { if(0xFFFFFFFF != (*ptrd)) //判断地址是否擦除成功 { lednum = LED2; gd_eval_led_on(lednum); //不成功的时候 LED2 会亮 break; }else { ptrd++; // 指针地址++ 再进行下一个地址判断 } } }
- flash 编程
void fmc_program(void) { fmc_unlock(); //FMC 解锁 address = FMC_WRITE_START_ADDR; while(address < FMC_WRITE_END_ADDR){ fmc_word_program(address, data0); //word 编程 address += 4; fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR );//清除标志 } fmc_lock(); //FMC 加锁 }
- 字编程检查
void fmc_program_check(void) { uint32_t i; ptrd = (uint32_t *)FMC_WRITE_START_ADDR; //将写地址赋值指针 for(i = 0; i < WordNum; i++) { if((*ptrd) != data0) //判断写入的数据是否一致 { lednum = LED3; gd_eval_led_on(lednum); //不相等的时候 LED3 会亮 break; }else { ptrd++; // 指针地址++ 再进行下一个地址判断 } } }
12.4.FMC 使用注意事项
(1)操作 flash 之前需要 fmc_unlock();
(2)flash 编程之前需要 page 擦除;
(3)Page erase 和 program 之前需要先清空标志位;
(4)避免在 erase 或者 program 过程中出现掉电情况,用 flash 作为 eeprom 来用时,需要做好数据备份;
(5)在擦除 code data flash 过程中,擦除的优先级最高,此时任何中断都不响应。这时需要注意 MCU 与外界通讯时,数据丢失情况。
本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网
-
单片机
+关注
关注
6074文章
45333浏览量
663280 -
mcu
+关注
关注
147文章
18603浏览量
386517 -
嵌入式
+关注
关注
5186文章
20141浏览量
328637 -
FMC
+关注
关注
0文章
111浏览量
20616 -
开发板
+关注
关注
25文章
6118浏览量
113131
发布评论请先 登录
GD32 MCU移植
《GD32 MCU原理及固件库开发指南》+读后感
兆易创新GD32 MCU选型手册,适用于GD32全系列MCU
GD32 MCU ISP失败的原因
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(1)使用Keil开发GD32
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(2)使用 IAR 开发 GD32
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(3)使用 Embedded Builder 开发 GD32
【GD32 MCU 入门教程】二、GD32 MCU 烧录说明(1)ISP 烧录
【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(14)RTC 模块介绍
【GD32 MCU入门教程】GD32 MCU GPIO 结构与使用注意事项

GD32 MCU 入门教程】GD32 MCU 常见外设介绍(12)FMC 模块介绍
评论