单片机
返回首页

【GD32H757Z海棠派开发板使用手册】第四讲 FMC-片内Flash擦写读实验

2024-12-04 来源:elecfans

4.1实验内容

通过本实验主要学习以下内容:

  • FMC控制器原理;

  • FMC擦写读操作;

4.2实验原理

4.2.1FMC控制器原理

FMC即Flash控制器,其提供了片上Flash操作所需要的所有功能,在GD32H7XX系列MCU中,具有高达3840KB字节的片上闪存可用于存储指令或数据。FMC也提供了扇区擦除和整片擦除操作以及编程操作。

Flash读取可以支持64字节双字、32位整字、16位半字或字节读操作;Flash编程可以支持64位双字、32位整字编程;Flash擦除支持扇区擦除和整片擦除操作。

Flash具有仅执行的专用代码读保护区域,便于芯片代码保护以及二次合作开发。

FMC框图如下所示,FMC支持用以访问代码或数据的64位AXI接口以及用以访问寄存器的32位AHB从机接口。

wKgZomYh0M2ASXBaAABWBI1KHf8769.png

闪存包括3840KB字节主闪存,分为960个扇区,扇区大小为4KB,和64KB用于引导加载程序的信息块。主存储闪存的每个扇区都可以单独擦除 。

wKgZomYh0NmADs3jAACHzfMnsTQ573.png

有关Flash擦写操作均需要先解锁Flash,然后进行擦写操作,擦写完成后再进行锁Flash,注意Flash特性只能由1写0,也就是Flash需要先擦除才能写入新的数据,如果确保写入地址的数据为全0xFF,也可以直接写入。读取Flash数据可以采取直接寻址的方式进行读取。

下面为各位读者介绍Flash擦写读的相关操作。

4.2.2Flash擦除操作原理

Flash擦除可分为块擦除以及整片擦除,如下图所示,扇区擦除时间典型值为100ms,整片擦除也根据容量大小会有差异。

wKgaomYh0PGAK-fYAAEQucyDXmc569.png

有关Flash的相关操作均在gd32h7xx_fmc.c中实现,下面介绍下擦除实现的函数,如下表所示。

wKgZomYh0P6AaAOHAABYIxnVQHU429.png

4.2.3Flash写入编程操作原理

GD32H7系列MCU可支持64位双字/32位整字编程,如下图所示,Flash 32位整字编程时间典型值为1us。

wKgaomYh0PGAK-fYAAEQucyDXmc569.png


有关Flash编程实现函数如下表所示。

wKgaomYh0SuAdNZjAACGC3qGvsg217.png


4.2.4Flash读取操作原理

Flash读取可以采用直接寻址的方式进行操作,具体可参考以下示例代码。

C
uint32_t read_data;
read_data = *(uint32_t *)0x08001000;

注意:有关Flash有以下参数读者需要了解,GD32H7xx系列MCU的内部Flash具有至少10万次的擦写次数以及20年的数据保持能力,但需注意,随着擦写次数的增加数据保持时间会下降。

4.3硬件设计

本例程不涉及硬件电路。

4.4代码解析

4.4.1Flash写入多字节函数

Flash写入多字节操作函数如下所示,写入的过程主要分为擦写两个操作,由于Flash特有特性,需要先擦除才可以写入,因而需要确保写入地址的初识数据为0xFF。本函数可以实现根据地址识别对应页并进行擦除的功能,使用上非常方便,使用者只需要关心擦写的起始地址以及数据和长度即可,擦写的位置函数中会进行实现。

C
void fmc_write_data(uint32_t write_start_addr, uint8_t *data_buf, uint16_t data_lengh)
{
uint32_t write_addr,erase_addr;
uint16_t data_write_num=0,data_lengh_word=data_lengh/4;
int32_t data_earse_num;
uint32_t* pbuff=(uint32_t*)data_buf;

if(data_lengh%4 !=0)
{
data_lengh_word++;
}


fmc_unlock(); /* 解锁FMC */
/* 清除错误标志 */
fmc_flag_clear(FMC_FLAG_WPERR);
fmc_flag_clear(FMC_FLAG_PGSERR);
fmc_flag_clear(FMC_FLAG_RPERR);
fmc_flag_clear(FMC_FLAG_RSERR);
fmc_flag_clear(FMC_FLAG_ECCCOR);
fmc_flag_clear(FMC_FLAG_ECCDET);
fmc_flag_clear(FMC_FLAG_OBMERR);

erase_addr = write_start_addr;
data_earse_num = data_lengh;

if(write_start_addr%FLAG_PAGE_SIZE == 0) /* 若写入地址为页起始地址 */
{
for(;data_earse_num>0;)
{
fmc_sector_erase(erase_addr);
/* 清除错误标志 */
fmc_flag_clear(FMC_FLAG_WPERR);
fmc_flag_clear(FMC_FLAG_PGSERR);
fmc_flag_clear(FMC_FLAG_RPERR);
fmc_flag_clear(FMC_FLAG_RSERR);
fmc_flag_clear(FMC_FLAG_ECCCOR);
fmc_flag_clear(FMC_FLAG_ECCDET);
fmc_flag_clear(FMC_FLAG_OBMERR);
erase_addr+=FLAG_PAGE_SIZE;
data_earse_num-=FLAG_PAGE_SIZE;
}
}else{
/*若写入地址不是页起始地址*/
for(;(data_earse_num>0||erase_addr>=write_start_addr+data_lengh);)
{
fmc_sector_erase(erase_addr);
/* 清除错误标志 */
fmc_flag_clear(FMC_FLAG_WPERR);
fmc_flag_clear(FMC_FLAG_PGSERR);
fmc_flag_clear(FMC_FLAG_RPERR);
fmc_flag_clear(FMC_FLAG_RSERR);
fmc_flag_clear(FMC_FLAG_ECCCOR);
fmc_flag_clear(FMC_FLAG_ECCDET);
fmc_flag_clear(FMC_FLAG_OBMERR);
erase_addr+=FLAG_PAGE_SIZE;
data_earse_num-=FLAG_PAGE_SIZE;
}
}

/* 写入数据 */
write_addr = write_start_addr;

for(data_write_num = 0; data_write_num{
fmc_word_program(write_addr, pbuff[data_write_num]);
/* 清除错误标志 */
fmc_flag_clear(FMC_FLAG_WPERR);
fmc_flag_clear(FMC_FLAG_PGSERR);
fmc_flag_clear(FMC_FLAG_RPERR);
fmc_flag_clear(FMC_FLAG_RSERR);
fmc_flag_clear(FMC_FLAG_ECCCOR);
fmc_flag_clear(FMC_FLAG_ECCDET);
fmc_flag_clear(FMC_FLAG_OBMERR);

write_addr+=4;
}
fmc_lock();
}

4.4.2Flash读取数据函数

Flash读取数据函数如下所示,采用直接寻址的方式,读取字节数据。

C
uint8_t fmc_read_data(uint32_t write_read_addr)
{
return *(uint8_t *)write_read_addr;
}

4.4.3主函数

主函数如下所示,通过该函数实现对flash起始地址为0x080A0000的前10个字节擦写以及读取的验证。

C
int main(void)
{
uint16_t read_num =0;
uint8_t i_num;
driver_init();
bsp_led_group_init();
bsp_uart_init(&BOARD_UART); /* 板载UART初始化 */
printf_log('Example of internal Flash read-write demo.rn');
printf_log('Write data to internal Flash.rn');
fmc_write_data(WRITE_START_ADDR,write_data,sizeof(write_data)); /* 向WRITE_START_ADDR地址写入10个双字节数据 */
printf_log('Read data from internal Flash.rn');
for(read_num=0;read_num{
read_data[read_num] = fmc_read_data(WRITE_START_ADDR+read_num); /* 从WRITE_START_ADDR读取10个双字节数据 */
}
printf_log('Verify the written and read data.rn');
for(i_num=0;i_num{
/* 校验数据 */
if(read_data[i_num]!=write_data[i_num])
{
/* 校验数据出错 */
printf_log('Error in verifying data.rn');
printf_log('Turn on LED1.rn');
bsp_led_on(&LED1);
while(1);
}else{
}
}
/* 校验数据成功 */
printf_log('Turn on LED1.rn');
bsp_led_on(&LED1);
printf_log('Verify that the data is correct and that the written and read data are consistent.rn');

while (1)
{
}
}

4.5实验结果

将本实验烧录到海棠派实验板中,运行后可以观察到LED1常亮,表明擦写以及读取实验正常。


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章