【GD32F303红枫派使用手册】第五节 FMC-片内Flash擦写读实验

news2024/10/6 16:28:36

5.1 实验内容

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

  • FMC控制器原理;
  • FMC擦写读操作;

5.2 实验原理

5.2.1 FMC控制器原理

FMC即Flash控制器,其提供了片上Flash操作所需要的所有功能,在GD32F303系列MCU中,Flash前256K字节空间内, CPU执行指令零等待,具有相同主频下最快的代码执行效率。FMC也提供了页擦除,整片擦除,以及32位整字/16位半字/位编程等闪存操作。GD32F303系列MCU支持最大3M Flash空间,可以提供业内最大Flash的相关产品。

GD32F303系列MCU的Flash结构如下图所示。由该图可知,GD32F303系列MCU可以支持最大3M的Flash空间,前256页为2KB每页,共512KB空间,后面的空间为4KB每页,信息块为存储内部出厂BOOTLOADER,中容量的GD32F303系列产品空间为2KB,大容量的GD32F303系列产品空间为6KB,互联型的GD32F305/307系列产品空间为18KB,主要是由于不同的产品所支持的ISP烧录接口不同,所需要的代码空间也会有差别。可选字节块存储的是选项字节,其空间大小为16个字节,地址范围为0x1FFFF800-0x1FFFF80F,本章主要讲解FMC的操作,有关选项字节操作可以参考选项字节操作实验。

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

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

5.2.2 Flash擦除操作原理

Flash擦除可分为页擦除以及整片擦除,如下图所示,页擦除时间典型值为48ms,256KB Flash的块擦除时间典型值为2S。

有关Flash的相关操作均在gd32f30x_fmc.c中实现,下面介绍下擦除实现的函数,如下表所示。 5.2.3 Flash写入编程操作原理

GD32F303系列MCU可支持32位整字编程/16位板字以及位编程,如下图所示,Flash 32位整字编程时间典型值为47.5us。

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

  • 注意:fmc_word_reprogram可以在不用擦除的情况下直接进行位编程,但仅可实现将1编程为0,比如若调用以上fmc_word_reprogram(0x08001000,0xFE)语句,即实现将最低位编程为0,若0x08001000原始数据为0x81,则执行完后改地址数据为0x80。

5.2.4 Flash读取操作原理

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

C
uint32_t read_data;
read_data = *(uint32_t *)0x08001000;
  • 注意:有关Flash有以下参数读者需要了解,GD32F303系列MCU的内部Flash具有至少10万次的擦写次数以及20年的数据保持能力,但需注意,随着擦写次数的增加数据保持时间会下降。

5.3 硬件设计

本例程不涉及硬件电路。

5.4 代码解析

5.4.1 Flash写入16bit双字节函数

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

C
void fmc_write_data_16b(uint32_t write_start_addr, uint16_t *data_buf, uint16_t data_lengh)
{
        uint32_t write_addr,erase_addr;
        uint16_t data_write_num=0;
        int16_t data_earse_num;
        /* 解锁FMC */
        fmc_unlock();
        /* 清除BANK0和BANK1的错误标志 */
        fmc_flag_clear(FMC_FLAG_BANK0_PGERR|FMC_FLAG_BANK0_WPERR|FMC_FLAG_BANK0_END);
        fmc_flag_clear(FMC_FLAG_BANK1_PGERR|FMC_FLAG_BANK1_WPERR|FMC_FLAG_BANK1_END);
        
        
        erase_addr = write_start_addr;
        data_earse_num = data_lengh;
        /* 若写入起始地址加上总长*2小于0x08080000,说明需要擦写的数据均在BANK0,页大小为2K/页 */
        if((write_start_addr+data_lengh*2)<0x08080000)
        {
                /* 若写入地址为页起始地址 */
                if(write_start_addr%2048 == 0)
                {
                  for(;data_earse_num>0;)
                  {
                          fmc_page_erase(erase_addr);
                          erase_addr+=2048;
                          data_earse_num-=1024;
                  }
                        /*若写入地址不是页起始地址*/
          }else{
        for(;(data_earse_num>0||erase_addr>=write_start_addr+data_lengh*2);)
                    {
                            fmc_page_erase(erase_addr);
                            erase_addr+=2048;
                            data_earse_num-=1024;
                    }
            }
                /* 若写入地址加上写入长度*2大于0x08080000,说明擦写的数据可能跨BANK或者均在BANK1,页大小有差别 */
  }else{
                /* 如果起始地址小于0x08080000,说明跨BANK */
                if(write_start_addr<0x08080000)
                {
                        /* 首先擦除BANK0部分所需页 */
                        for(;erase_addr<0x08080000;)
                        {
                                        fmc_page_erase(erase_addr);
                            erase_addr+=2048;
                        }
                        /* 然后擦除BANK1部分所需页 */
                        erase_addr = 0x08080000;
                        for(;erase_addr<=write_start_addr+data_lengh*2;)
                        {
                                        fmc_page_erase(erase_addr);
                            erase_addr+=4096;
                        }
                }else{
                        /*若写入地址大于等于0x08080000,说明均在BANK1,页大小为4K/页*/
                if(write_start_addr%4096 == 0)  /* 若写入地址为页起始地址 */
                {
                  for(;data_earse_num>0;)
                  {
                          fmc_page_erase(erase_addr);
                          erase_addr+=4096;
                          data_earse_num-=2048;
                  }
                }else{
                          /*若写入地址不是页起始地址*/
        for(;(data_earse_num>0||erase_addr>=write_start_addr+data_lengh*2);)
                    {
                            fmc_page_erase(erase_addr);
                            erase_addr+=4096;
                            data_earse_num-=2048;
                    }
                        }
                }
        }
        
        /* 写入数据 */
        write_addr = write_start_addr;
        for(data_write_num = 0; data_write_num<data_lengh;data_write_num++)
        {
                fmc_halfword_program(write_addr, data_buf[data_write_num]);
                write_addr += 2;
        }
        fmc_lock();
}

 5.4.2 Flash读取数据函数

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

C
uint16_t fmc_read_data_16b(uint32_t write_read_addr)
{
        return *(uint16_t *)write_read_addr;
}

5.4.3 主函数

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

C
int main(void)
{
        uint16_t read_num =0;
        uint8_t i_num;
        bsp_led_group_init();    
        fmc_write_data_16b(WRITE_START_ADDR,write_data,10);
        for(read_num=0;read_num<10;read_num++)
        {
                read_data[read_num] = fmc_read_data_16b(WRITE_START_ADDR+read_num*2);
        }
        for(i_num=0;i_num<10;i_num++)
        {
                if(read_data[i_num]!=write_data[i_num])
                {
                        bsp_led_on(&LED0);
                }else{
                        bsp_led_on(&LED1);
                }
        }
        
        while (1)
        {
        }
}

5.5 实验结果

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

由聚沃科技原创,来源于

【红枫派开发板】第五讲 FMC-片内Flash擦写读实验 - 苏州聚沃电子科技有限公司 (gd32bbs.com)

GD32MCU技术交流群:859440462  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1721403.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

环卫车北斗GPS视频监控定位解决方案的应用与优势

一、引言 随着城市化进程的加快&#xff0c;环卫车作为城市环境卫生的重要保障力量&#xff0c;其运行效率与安全性直接关系到城市形象与居民生活品质。然而&#xff0c;传统的环卫车管理模式往往存在信息不对称、调度不合理、行驶不规范等问题&#xff0c;导致城市道路污染和…

Java中的软引用,你了解吗?

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

打工人福音,办公神器软件

今天分享2个免VIP的办公神器app&#xff0c;建议所有手机安装&#xff0c;第一个布丁扫描http://www.budingscan.com &#xff0c;无广告不收费&#xff0c;这是VIVO 推出的一款完全免费的扫描APP&#xff0c;支持文档&#xff06;证件扫描、OCR文字&#xff06;表格识别提取、…

解决Windows 10通过SSH连接Ubuntu 20.04时的“Permission Denied”错误

在使用SSH连接远程服务器时&#xff0c;我们经常可能遇到各种连接错误&#xff0c;其中“Permission denied, please try again”是较为常见的一种。本文将分享一次实际案例的解决过程&#xff0c;帮助你理解如何排查并解决这类问题。 问题描述 在尝试从Windows 10系统通过SS…

js:flex弹性布局

目录 代码&#xff1a; 1、 flex-direction 2、flex-wrap 3、justify-content 4、align-items 5、align-content 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewp…

Mysql基础教程(13):GROUP BY

MySQL GROUP BY 【 GROUP BY】 子句用于将结果集根据指定的字段或者表达式进行分组。 有时候&#xff0c;我们需要将结果集按照某个维度进行汇总。这在统计数据的时候经常用到&#xff0c;考虑以下的场景&#xff1a; 按班级求取平均成绩。按学生汇总某个人的总分。按年或者…

【spring】Spring Boot3.3.0发布啦

spring最新版本 springboot官网&#xff1a;Spring Boot :: Spring Boot Spring Boot 3.3 发行说明&#xff1a;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.3-Release-Notes 开发环境的要求对比表 Spring BootJDKSpringMavenGradle3.3.017 ~ 226.1…

Nginx实战:LUA脚本_环境配置安装

目录 一、什么是LUA脚本 二、Nginx中的LUA脚本 1、主要特点 2、用途 三、如何在nginx中使用LUA脚本 1、原生nginx 2、OpenResty 3、nginx lua配置验证 一、什么是LUA脚本 Nginx Lua 脚本是 Nginx 与 Lua 语言集成的结果&#xff0c;它允许你使用 Lua 语言编写Nginx 模块…

【Redis】List源码剖析

大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#xff0c;但是也想日更的人。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4aa;&#x1f4aa;&#x1f4aa…

使用第三方工具percona-xtrabackup进行数据备份与恢复

目录 准备工作 开始安装 innobackupex的使用 完全备份 增量备份 数据恢复 本次需要用到的软件 mysql 5.7.35percona-xtrabackup-24-2.4.8 ps&#xff1a;---MySQL必须是5.7的版本&#xff0c;在8.0之后已经不支持 percona-xtrabackup-24 系统版本CentOS7.9 准备工作 …

面试题 17.05. 字母与数字(前缀和)

给定一个放有字母和数字的数组&#xff0c;找到最长的子数组&#xff0c;且包含的字母和数字的个数相同。 返回该子数组&#xff0c;若存在多个最长子数组&#xff0c;返回左端点下标值最小的子数组。若不存在这样的数组&#xff0c;返回一个空数组。 示例 1: 输入: ["…

SpringBoot+layui实现Excel导入操作

excel导入步骤 第三方插件引入插件 效果图 &#xff08;方法1&#xff09;代码实现&#xff08;方法1&#xff09;Html代码&#xff08; 公共&#xff09;下载导入模板 js实现 &#xff08;方法1&#xff09;上传文件实现 效果图&#xff08;方法2&#xff09;代码实现&#xf…

一碗米线火了24年,蒙自源六一再献新作

当一碗热气腾腾的米线在餐桌上飘香四溢&#xff0c;你是否会想起那个陪伴了无数食客24年的名字——蒙自源&#xff1f;在这个充满欢笑与童真的六一儿童节&#xff0c;蒙自源米线品牌再度发力&#xff0c;用全新的儿童餐系列为孩子们带来了一份特别的节日礼物。 蒙自源&#xf…

性价比为王,物流商怎么选择高效的国际物流管理平台

在全球化贸易日益繁荣的今天&#xff0c;国际物流行业作为链接国内商家和海外市场的重要桥梁&#xff0c;发挥着极其重要的作用。 然而&#xff0c;随着国际物流市场竞争的加剧&#xff0c;对物流商来说&#xff0c;也面临着成本管控和效率提升的双重挑战。今天我们会重点探讨…

AI之下 360让PC商业生态大象起舞

时隔7年&#xff0c;淘宝PC版在前不久迎来重磅升级&#xff0c;在产品体验、商品供给、内容供给等方面做了全面优化&#xff0c;以全面提升PC端的用户体验&#xff1b;当大家都以为移动互联网时代下APP将成为主流时&#xff0c;PC端却又成为了香饽饽。其实PC端被重视&#xff0…

【Qt】【模型视图架构】代理模型示例

文章目录 1. 基本排序/过滤模型Basic Sort/Filter Model Example2. 自定义排序/过滤模型Custom Sort/Filter Model ExampleFilterLineEdit类定义及实现MySortFilterProxyModel类定义及实现 1. 基本排序/过滤模型Basic Sort/Filter Model Example 官方提供的基本排序/过滤模型示…

LeetCode42:接雨水

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 代码 单调栈 class Solution { public:int trap(vector<int>& height) {stack<int> stk;int result 0;stk.push(0);for (int …

Android设备获取OAID调研和实现

什么是OAID、AAID、VAID OAID OAID是"Android ID"&#xff08;安卓ID&#xff09;的一种替代方案&#xff0c;其全称为"Open Anonymous Identifier"&#xff08;开放匿名标识符&#xff09;。 因传统的移动终端设备标识如国际移动设备识别码&#xff08;…

【Python内功心法】:深挖内置函数,释放语言潜能

文章目录 &#x1f680;一、常见内置函数&#x1f308;二、高级内置函数⭐1. enumerate函数&#x1f44a;2. eval函数❤️3. exec函数&#x1f4a5;4. eval与exec 中 globals与locals如何用☔4-1 globals 参数&#x1f3ac;4-2 locals 参数 ❤️5. filter函数&#x1f44a;6. z…

发电机组故障的原因、解决方案及解决措施

发电机组故障的原因、解决方案及解决措施可以总结如下&#xff1a; 一、故障原因 供电中断 原因&#xff1a;电网故障、线路短路或电力负荷过重等。 燃油问题 原因&#xff1a;燃油供应系统问题&#xff0c;如燃油管路堵塞、燃油质量不佳等。 轴承过热 原因&#xff1a;轴承过…