前言
用单片机做开发时,为了实现产品的某些功能,我们通常都需要记录一些数据并放在单片机掉电不丢失的区域中。在现在的主流8位机中,一般为EEPROM和FLASH存储区。这些存储区一般与我们的代码存储区是分开来的且一般不大(多数在1KB以内)。EEPROM是可以按字节读、写的,而FLASH则是以块为单位擦除、写入的。而在32位单片机中,一般不会为单独的数据存储再开辟一个区域,即存代码的和存这些数据的是同一个区域。所以,如果你看过其他有关32位机内部FLASH读写操作的,它们基本都是从FLASH最后一个或几个区块操作的,本文给出的示例也是如此。
RAM与ROM
讲内部FLASH读、写之前,咱们先简单聊聊单片机的RAM与ROM。RAM就是我们所说的内存,具有读写快的特点,但是掉电数据丢失。ROM为只读存储器,在这里指的就是FLASH,具有掉电不丢失的特性。选择FLASH型MCU的好处在于便于前中期调试与后期维护,与之相对的还有OTP与MTP型MCU。它们之间最大的区别在于可重复烧录次数的限制,这也导致了在整个代码调试上有很多区别。
各模块程序编写
在配置前,请确保你已经有一个GD32F303包含其对应标准库的keil工程,工程可使用官方的例程或可按照GD32F303调试小记(零)之工程创建与编译创建。
一、片内FLASH映射关系
![请添加图片描述](https://img-blog.csdnimg.cn/1d5cf08f7a8a4d62abf90a68e8c9161c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5qyi5ZacNjY2Ng==,size_20,color_FFFFFF,t_70,g_se,x_16)
根据上面的描述,我们知道整个FLASH区的地址范围。整个FALSH分为两个BANK区,对于FLASH容量不大于512K的都在BANK0区,每页大小为2KB。对于FLASH容量大于512的除去前512KB在BANK0以外,后面的都在BANK1中,每页大小为4KB。由于FLASH区更多是用来存储代码的,你编写烧录的代码会从FLASH的第0页,也就是从0x-0800-0000开始占用一定的FLASH页数。要是你操作到这些地方,我们可以想象会发生什么样的后果。所以,我们一般根据你手上的芯片大小,往往都从最后一个或最后几个FLASH页上操作:
/*
* bank0--2kB一页 bank1--4KB一页
* 前512K在Bank0中,后面在Bank1中
* 前256K CPU执行指令零等待
*/
/* 256KB FLASH */
//#define FMC_PAGE_SIZE ((uint16_t)0x800U)
//#define FMC_WRITE_START_ADDR ((uint32_t)0x0803F800U)
//#define FMC_WRITE_END_ADDR ((uint32_t)0x0803FFFFU)
/* 1MB FLASH */
#define FMC_PAGE_SIZE ((uint16_t)0x1000U) /* bank1 4kB each page */
#define FMC_WRITE_START_ADDR ((uint32_t)0x080FF000U)
#define FMC_WRITE_END_ADDR ((uint32_t)0x080FFFFFU)
二、FLASH擦除
直接套用官方例程中的擦除函数,这里我使用了BANK1中的FALSH页,对应FMC_FLAG_BANK1_END、FMC_FLAG_BANK1_WPERR、和FMC_FLAG_BANK1_PGERR这三个标志位。BANK0的话修改这三个即可。这里是多页擦除,PageNum 这个变量算的就是页数,这里我是擦除一页。
/* calculate the number of page to be programmed/erased */
uint32_t PageNum = (FMC_WRITE_END_ADDR - FMC_WRITE_START_ADDR + 1) / FMC_PAGE_SIZE;
void fmc_erase_pages(void)
{
uint32_t EraseCounter;
/* unlock the flash program/erase controller */
fmc_unlock();
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_BANK1_END);
fmc_flag_clear(FMC_FLAG_BANK1_WPERR);
fmc_flag_clear(FMC_FLAG_BANK1_PGERR);
/* erase the flash pages */
for(EraseCounter = 0; EraseCounter |