前言
回顾下之前的章节:
- 第一章节中我们描述了整个框架的核心设计思路以及主要的文件架构
- 第二章节中我们基于一个简单的定时器OS实现了串口的数据打印,并完成了通用crc模块的设计和测试
- 第三章节中我们给出了真随机数和伪随机数的概念和代码示例,并在架构上对接口进行了重构
本文我们将回顾下FMC的知识,并给出Flash读写的接口设计和示例,这在设计升级程序时十分重要。
闪存结构
闪存控制器(FMC),提供了片上闪存需要的所有功能。一般而言,MCU的Flash包括4个部分:
- 主存储区(Main memory),其特点是可读可写,存放的是程序;如果空间足够,也可以用来存放数据(参数,记录等)。
- 系统存储区(System memory),有的翻译叫存储块,实际上就是Boot Loader,只读。
- 一次性存储区OTP(One Time Program),其特点是只能由1写为0,不能由0写为1,可以用来存储保护性或防伪性内容。
- 选项字节(Option bytes),存放的是系统的一些配置数据,上电时加载到寄存器中。
Flash读写的流程和注意事项在芯片手册中写的清清白白,就不赘述了;如果大家感兴趣,可以对着厂家给的API接口比对着看,理解会更好一点。
FMC测试
FMC的操作实际上比较简单,厂家给的API都很成熟,需要注意的几个点:
- FMC不能“自杀”,即不能由程序自己写自己,所以FMC只能写非程序区的Flash。
- FMC操作上需要先unlock,操作完之后记得lock。
- STM和GD的接口略微有些不一样,使用上需要注意。
主存读写测试
配置Flash程序区:
flash配置
接口封装统一(io_fmc.h
):
#ifdef STM32
#define fmc_sector_erase FLASH_ErasePage
#define fmc_unlock FLASH_Unlock
#define fmc_lock FLASH_Lock
#define fmc_word_program FLASH_ProgramWord
#endif
测试函数:
多嘴一句,STM32给的擦除扇区接口的入口参数是扇区首地址,GD32给的接口是扇区编号,从软件使用的角度来看,GD32的更优。
代码语言:javascript复制static uint8_t fmc_test_flag = 0;
static void fmc_test(void)
{
#ifdef FMC_TEST
#define FMC_TEST_DATA_COUNT 5
uint32_t index = 0;
#ifdef GD32
uint32_t addr = 0x08100000;
uint32_t sector = CTL_SECTOR_NUMBER_12;
#endif
#ifdef STM32
uint32_t addr = 0x08040000;
uint32_t sector = addr;
#endif
uint32_t *pdata = (uint32_t *)addr;
int32_t fmc_state;
if (fmc_test_flag)
{
return;
}
fmc_test_flag = 1;
/* 1. before erase */
printf("before erase,tdata = ");
for (index = 0; index < FMC_TEST_DATA_COUNT; index )
{
printf("0x%X ", pdata[index]);
}
printf("rn");
/* 2. after erase */
fmc_unlock();
fmc_state = fmc_sector_erase(sector);
fmc_lock();
printf("after erase[%d]tdata = ", fmc_state);
for (index = 0; index < FMC_TEST_DATA_COUNT; index )
{
printf("0x%X ", pdata[index]);
}
printf("rn");
/* 2. after program */
fmc_unlock();
for (index = 0; index < FMC_TEST_DATA_COUNT; index )
{
fmc_state = fmc_word_program(addr, index 9);
addr = 4;
printf("programing [0x%0X] state = [%d]rn", addr, fmc_state);
}
fmc_lock();
printf("after program,tdata = ");
for (index = 0; index < FMC_TEST_DATA_COUNT; index )
{
printf("0x%X ", pdata[index]);
}
printf("rn");
#endif
}
测试结果(GD32,正常状态返回值是0):
代码语言:javascript复制before erase, data = 0x9 0xA 0xB 0xC 0xD
after erase[0] data = 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF
programing [0x8100004] state = [0]
programing [0x8100008] state = [0]
programing [0x810000C] state = [0]
programing [0x8100010] state = [0]
programing [0x8100014] state = [0]
after program, data = 0x9 0xA 0xB 0xC 0xD
测试结果(STM32,正常状态返回值是4):
代码语言:javascript复制before erase, data = 0x9 0xA 0xB 0xC 0xD
after erase[4] data = 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF
programing [0x8040004] state = [4]
programing [0x8040008] state = [4]
programing [0x804000C] state = [4]
programing [0x8040010] state = [4]
programing [0x8040014] state = [4]
after program, data = 0x9 0xA 0xB 0xC 0xD
OTP和OB展示
注:STM32F103不包含OTP区。
通过Keil的调试功能可以查看Flash地址的数据,当然也可以直接在程序中读取。
STM OB的描述:
STM OB数据:
GD32 OB数据:
GD32 OPT数据:
--EOF--