GD32F103读写内部FLASH

2023-10-29

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…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GD32F103读写内部FLASH 的相关文章

  • 我有两个类型定义,如何确定一个类型是否是另一个的基类型?

    我在 ActionScript 3 中有两个类型定义 Class 类型的引用 我需要确定其中一个是否是另一个的基类型 类或接口 我本来希望像下面这样的东西会起作用 但遗憾的是它没有 var isBaseClass Boolean Mouse
  • ActionScript 的 File.upload 不适用于 iOS 设备的 Air SDK

    我尝试使用 ActionScript 的 File upload 在 Air SDK for iOS 环境中上传文件 但 File upload 无法正常工作 调用 File upload 后 不会执行有关文件上传的处理程序 也不会捕获任何
  • HTML5 画布/Flash。如何访问儿童影片剪辑并使其转到AndPlay?

    在 Flash 中 我的主时间轴中有 2 帧 第一个是选择语言 第二个包含导航栏 该导航栏是一个影片剪辑 其中包含项目 影片剪辑 这些 item movieclips 包含 2 个帧 每种语言一个 在 navigation bar movi
  • 如何确定应用程序是作为移动应用程序还是桌面应用程序运行?

    我怎样才能知道当前的应用程序类型是什么 即它是在移动设备上运行还是作为桌面 Air 应用程序运行 我试过这个 if FlexGlobals topLevelApplicatoin as WindowedApplication desktop
  • Bootstrap-modal 在 Flash 顶部弹出

    我正在使用 Twitter 的 Bootstrap 插件bootstrap modal 除非后面有闪光灯元件 否则它效果很好 当引导模式对话框出现并且其后面有一个 Flash 元素时 Flash 元素位于其他所有元素之上 我该如何解决 您需
  • Flash AS3 - 如何访问其他帧(也称为非一帧)中的显示对象

    只要该子项位于第一帧中 getChildByName name 就会起作用 其他框架中的显示对象还没有被实例化 所以并不是说不能访问它们 它们不存在可供访问的地方 当播放头进入具有特定对象的关键帧时 会创建该对象并将其添加到舞台中 当播放头
  • Flex/AS3很奇怪的简单数字运算问题

    我的问题在 Flex 中描述起来非常简单 0 8 0 2 0 6000000000000001 以前有人得到过这个 我确定前两个成员是 0 8 和 0 2 并且是 Number 类 为什么会发生这种情况 另一件事 我从 像这样输入 var
  • 如何调整外部 SWF 的大小以适合容器?

    我想要完成的是调整外部 SWF 的大小 使其适合在舞台上作为容器呈现的显示对象 现在它显示在容器外部 重要提示 我不希望外部 SWF 占据整个舞台 我在舞台上为它准备了一个特殊的地方 那个容器 public function loaderC
  • 我应该将 FLV 文件放在哪里才能在本地 Red5 服务器上进行流式传输?

    我安装了最新的 Red5 服务器 但我不确定将 flv 文件放在哪里来进行流式传输 没有像我在网上找到的一些教程那样的 streams 或 ofla 目录 我应该将 flv 文件放在哪里来进行流式传输 Red5 附带了一些演示 但默认情况下
  • 在 Flash 对象上方显示图像

    我在这里面临着一个棘手的情况 这就是问题 我有一个 Flash 对象 我想在其上显示图像这些是我尝试过的技巧 1 玩转z index 没用 2 将wmode参数设置为透明 不透明 同样没有用 3 使用javascript并仅在页面加载后显示
  • 有没有办法覆盖动作脚本运算符,特别是我想覆盖等于运算符

    是否可以覆盖 equals 运算符 即 对于可以通过 2 个或更多字段匹配来确定相等性的客户类别 如果您的意思是重载 作为 equals 的同义词 那么您不能 因为 ActionScript 不提供运算符重载 只需为您的类编写一个 equa
  • 检查用户的 Flash 播放器是否具有音频功能。 (功能.hasAudio)

    是否可以检查用户是否有声卡 我找到了 Capability hasAudio 但不知道这是否是我应该查看的值 trace Capabilities hasAudio 指定系统是否具有音频功能 此属性始终true 文档对此并不清楚 但我认为
  • 将数据/变量从 Visual Basic 表单传递到 Flash 对象

    我很确定这个问题可以在 stackOverflow 上的某个地方得到解答 但我对此没有选择 我有一个 VisualBasic 窗体 上面有一个按钮对象 我希望该按钮有一个 onClick 过程 以便单击它可以将变量或其他命令传递到另一个正在
  • ActionScript 3 中的圆形滑块

    我希望在 ActionScript 中添加一个圆形滑块 非常类似于这一页 http interface eyecon ro demos drag vr html shows 它最终会改变对象的色调 返回 CMY 值 但如果它只是吐出程度 我
  • 更改 AS3 中的 TextField 选择颜色

    如何更改 ActionScript 3 中 TextField 的选择 突出显示 颜色 我有一个输入文本字段 黑色背景上有白色文本 因此 选择是不可见的 这对于可用性来说非常糟糕 谢谢 另一种方法是使用文本布局框架 特别是使用 Select
  • 在 WordPress 页面上嵌入 swf

    我正在尝试将 swf 嵌入到 WordPress 页面中 这听起来很简单 但它不起作用 我不明白为什么 我已将所有相关文件上传到服务器上 并且我相当确定所有文件路径都是正确的 包含 fla 和 swf 文件的文件夹还包含一个 index h
  • Facebook 聊天在打开时隐藏 Flash 应用程序

    运行 Flash 应用程序时 如果我打开新的或现有的 Facebook 聊天窗口 我的 Flash 内容就会消失 我可以继续听到应用程序中播放的音乐 并且当我关闭 最小化 Facebook 聊天窗口时 我的 Flash 内容会重新出现 这是
  • Flash 照片上传 - 从网络摄像头拍摄照片 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 使用 flash 或 java servlet 将麦克风数据从浏览器上传到服务器的教程? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 There was a question on how to get data from a microphone on a client
  • Youtube as3 API 似乎不再起作用

    我正在使用 as3 Youtube 官方 API 我需要在 swf 文件中加载 API 播放器 我已经在几个项目上完成了 一切都很好 但几个小时后 我的所有项目现在都坏了 这是崩溃的代码片段 Security allowDomain www

随机推荐