GD32F103读写内部FLASH


测试环境:

  • GD32F103C8
  • 20KBytes RAM
  • 64KBytes FLASH

2021年11月24日10:01:49更新,修复擦除FLASH的bug,具体在:

应改为:

感谢评论区 @qq_29872523和@蜗牛爬上屋顶啦两位提醒~!



头文件

/*** @brief Create by AnKun on 2019/10/10*/#ifndef GDFLASH_H__
#define GDFLASH_H__#include "gd32f10x.h"/// 移植修改区 ////* FLASH大小:64K */
#define GD32FLASH_SIZE  0X00010000UL/* FLASH起始地址 */
#define GD32FLASH_BASE  FLASH_BASE/* FLASH结束地址 */
#define GD32FLASH_END   (GD32FLASH_BASE | GD32FLASH_SIZE)/* FLASH页大小:1K */
#define GD32FLASH_PAGE_SIZE (1024U)/* FLASH总页数 */
#define GD32FLASH_PAGE_NUM  (GD32FLASH_SIZE / GD32FLASH_PAGE_SIZE)/// 导出函数声明
void FLASH_Init(void);
uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);
uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);
uint32_t FLASH_WriteNotErase(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);#endif // !GDFLASH_H__

源文件

/*** @file  flash.c** @brief Create by AnKun on 2019/10/10**/#include "gdflash.h"
#include <string.h>__align(4) static uint16_t FlashBuffer[GD32FLASH_PAGE_SIZE >> 1];/// 初始化FLASH
void FLASH_Init(void)
{fmc_unlock();fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);fmc_lock();
}/*** 读FLASH* @param  Address 地址* @param  Buffer  存放读取的数据* @param  Size    要读取的数据大小,单位字节* @return         读出成功的字节数*/
uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
{uint32_t nread = Size;uint8_t* d = (uint8_t *)Buffer;const uint8_t* s = (const uint8_t *)Address;if (!Buffer || Address < GD32FLASH_BASE || Address >= GD32FLASH_END)return 0;while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (GD32FLASH_END - 4))){*(volatile uint32_t *)d = *(volatile uint32_t *)s;d += sizeof(uint32_t);s += sizeof(uint32_t);nread -= sizeof(uint32_t);}while (nread && (((uint32_t)s) < GD32FLASH_END)){*d++ = *s++;nread--;}return Size - nread;
}/*** 写FLASH* @param  Address    写入起始地址,!!!要求2字节对齐!!!* @param  Buffer     待写入的数据,!!!要求2字节对齐!!!* @param  NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!* @return            实际写入的数据量,单位:字节*/
uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
{uint32_t i = 0;uint32_t pagepos = 0;         // 页位置uint32_t pageoff = 0;         // 页内偏移地址uint32_t pagefre = 0;         // 页内空余空间uint32_t offset = 0;          // Address在FLASH中的偏移uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量const uint16_t *pBuffer = (const uint16_t *)Buffer;/* 非法地址 */if (Address < GD32FLASH_BASE || Address > (GD32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)return 0;/* 解锁FLASH */fmc_unlock();/* 计算偏移地址 */offset = Address - GD32FLASH_BASE;/* 计算当前页位置 */pagepos = offset / GD32FLASH_PAGE_SIZE;/* 计算要写数据的起始地址在当前页内的偏移地址 */pageoff = ((offset % GD32FLASH_PAGE_SIZE) >> 1);/* 计算当前页内空余空间 */pagefre = ((GD32FLASH_PAGE_SIZE >> 1) - pageoff);/* 要写入的数据量低于当前页空余量 */if (nwrite <= pagefre)pagefre = nwrite;while (nwrite != 0){/* 检查是否超页 */if (pagepos >= GD32FLASH_PAGE_NUM)break;/* 读取一页 */FLASH_Read(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE);/* 检查是否需要擦除 */for (i = 0; i < pagefre; i++){if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */break;}if (i < pagefre){uint32_t count = 0;uint32_t index = 0;if(FLASH_ErasePage(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, 1) < 0)break;/* 复制到缓存 */for (index = 0; index < pagefre; index++){*(FlashBuffer + pageoff + index) = *(pBuffer + index);}/* 写回FLASH */count = FLASH_WriteNotErase(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE >> 1);if (count != (GD32FLASH_PAGE_SIZE >> 1)){nwrite -= count;break;}}else{/* 无需擦除,直接写 */uint32_t count = FLASH_WriteNotErase(Address, pBuffer, pagefre);if (count != pagefre){nwrite -= count;break;}}pBuffer += pagefre;         /* 读取地址递增         */Address += (pagefre << 1);  /* 写入地址递增         */nwrite -= pagefre;          /* 更新剩余未写入数据量 */pagepos++;     /* 下一页           */pageoff = 0;   /* 页内偏移地址置零  *//* 根据剩余量计算下次写入数据量 */pagefre = nwrite >= (GD32FLASH_PAGE_SIZE >> 1) ? (GD32FLASH_PAGE_SIZE >> 1) : nwrite;}/* 加锁FLASH */fmc_lock();return ((NumToWrite - nwrite) << 1);
}uint32_t FLASH_WriteNotErase(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
{uint32_t nwrite = NumToWrite;uint32_t addrmax = GD32FLASH_END - 2;while (nwrite){if (Address > addrmax)break;fmc_halfword_program(Address, *Buffer);if ((*(__IO uint16_t*) Address) != *Buffer)break;nwrite--;Buffer++;Address += 2;}return (NumToWrite - nwrite);
}int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)
{while(NbPages--){if(fmc_page_erase(PageAddress) != FMC_READY){return -1;}PageAddress += GD32FLASH_PAGE_SIZE;}return 0;
}

ends…

GD32F103读写内部FLASH相关推荐

  1. STM32F4读写内部FLASH【使用库函数】

    STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多.平时写的代码,烧写完之后还有大量的剩余.有效利用这剩余的FLASH能存储不少数据.因此研究了一下S ...

  2. 第50章 读写内部FLASH—零死角玩转STM32-F429系列

    第50章     读写内部FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  3. STM32学习笔记:读写内部Flash。

    首先我们需要了解一个内存映射:    stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起始地 ...

  4. STM32学习笔记:读写内部Flash(介绍+附代码)

    一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...

  5. STM32读写内部flash

    概念:计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是1个字节, 1个存储单元存放1个字节,每个存储单元对应一个32位(bit)地址,所以重要的话说三遍:对于32 ...

  6. STM32学习笔记:读写内部FLASH

    ST提供的库函数基本能搞定 简介 由于 FLASH 存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部 FLASH 中加载代码并运行,亦可当做EEROM来使用保存所需要的数据,以便下次启用 ...

  7. STM32读写内部Flash(介绍+附代码)

    概述 内部flash读写详解 一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片 ...

  8. STM32F103 读写内部FLASH—学习笔记(野火)

    STM32F103的Flash类型是NOR Flash 烧录过程:调试器→STM32的SRAM→运行→Flash 内部Flash比外部Flash更高效,原因是使用了内部总线,且工作频率是72MHz 2 ...

  9. 图文介绍STM32L4读写内部flash

    型号:STM32L431KBU6: 该型号内存 = 128KB,起始地址 = 0x0800_0000;只有63页: 在L4的user manual手册的第三章详细介绍了FLASH的操作细节,我挑一些重 ...

  10. 【dsPIC33E】内部Flash读写

    基于某些安全考虑或者降成本,我们不希望使用外部存储器件,但有时我们由需要记录一下参数,确保断电不丢失,这时,富余的内部代码存储Flash就派上用场了. 不同于外部存储器,几乎所有的内部Flash读写都 ...

最新文章

  1. 超图桌面版下载、安装、使用入门
  2. Cassandra HBase和MongoDb性能比较
  3. 微软Scott CIO也要代表公司拜访客户
  4. 各种水龙头拆卸图解_[各种水龙头拆卸图解]水龙头漏水怎么办
  5. sql azure 语法_深入了解Azure Data Studio:扩展和Azure SQL DB开发
  6. node如何输出html页面,【自己的整理】node.js直接输出一个非常简单的HTML页面-Go语言中文社区...
  7. 【Oracle】详解10053事件
  8. Error:Failed to open zip file. Re-download dependencies and sync project
  9. 数据分析之参数检验与非参数检验
  10. unity 模型加点击事件
  11. censo7安装mysql_centos7环境下在线安装mysql
  12. dax和m的区别_动态股票K线图----从M语言到DAX表达式
  13. dede taglist模板中调用自定义字段
  14. Ubuntu 18.04 16.04 设置输入法切换方法 中文输入法
  15. 骐骥一跃 驽马十驾-数据库触发器
  16. java反射一篇搞定
  17. HTTP LIVE Streams
  18. 海思HI35xx平台软件开发快速入门之背景知识
  19. node读取excel
  20. Socket客户端读取信息不全

热门文章

  1. HTML5 - WebSQL
  2. 舒尔特注意力训练表格_为什么那些常见的专注力训练方式,给娃用了好像效果不大?...
  3. 喜讯 | 大势智慧获得全球软件领域最高权威CMMI5认证
  4. 鲁宾逊微积分是什么?
  5. java 后端开发好吗_Java语言哪里好?为什么那么多人选择Java后端开发?
  6. java math类 平方_Java Math类
  7. lg android平台驱动程序,lg g3刷KDZ教程-KDZ线刷工具及USB驱动下载
  8. linux readelf,Linux readelf命令使用
  9. java加密 js解密_【Java】JavaScript 加密 Java 解密
  10. 《深入浅出通信原理》连载1-562合集