Air32

2023-10-27

Air32 | 合宙Air001单片机内部FLASH读写示例


代码已经通过测试,开发环境KEIL-MDK 5.36。

测试代码

void FLASH_RdWrTest(void)
{
	uint32_t Address;
	uint32_t PageReadBuffer[FLASH_PAGE_SIZE >> 2];
	uint32_t PageWriteBuffer[FLASH_PAGE_SIZE >> 2];

	memset(PageWriteBuffer, 0XAA, sizeof(PageWriteBuffer));

	for(Address = 0x08003000; Address < 0x08008000; Address += FLASH_PAGE_SIZE)  // 16K~32K
	{
		FLASH_Write(Address, PageWriteBuffer, sizeof(PageReadBuffer) >> 2);

		memset(PageReadBuffer, 0, sizeof(PageReadBuffer));

		FLASH_Read(Address, PageReadBuffer, sizeof(PageReadBuffer) >> 2);

		if(memcmp(PageReadBuffer, PageWriteBuffer, sizeof(PageReadBuffer)) == 0)
		{
			printf("page[%04d]  0x%08X read & write %s \r\n", (Address - FLASH_BASE) / FLASH_PAGE_SIZE, Address, "ok");
		}
		else
		{
			printf("page[%04d]  0x%08X read & write %s \r\n", (Address - FLASH_BASE) / FLASH_PAGE_SIZE, Address, "failed");
		}
	}
}


头文件


/**
 * @brief Create by AnKun on 2019/10/10
 */

#ifndef FLASH_H__
#define FLASH_H__

#include "air001xx_hal.h"

/// 导出函数声明 
void FLASH_Init(void);
void FLASH_Read(uint32_t Address, uint32_t *Buffer, uint32_t NumToRead);
void FLASH_Write(uint32_t Address, const uint32_t *Buffer, uint32_t NumToWrite);
void FLASH_WritePage_NoCheck(uint32_t Address, const uint32_t* Buffer);
void FLASH_ErasePage(uint32_t Address);
void FLASH_SetReadProtectionState(int state);

#endif // !__FLASH_H

源文件


/**
 * @file  flash.c
 *
 * @brief Create by AnKun on 2023/7/20
 *
 */

#include "flash.h"
#include <string.h>


static uint32_t FlashBuffer[FLASH_PAGE_SIZE >> 2];


void FLASH_Init(void)
{
	HAL_FLASH_Unlock();
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);  /* Clear SR register */
	HAL_FLASH_Lock();
}

void FLASH_Read(uint32_t Address, uint32_t *Buffer, uint32_t NumToRead)
{
	while(NumToRead--)
	{
		*Buffer++ = (*((volatile unsigned int *)Address));
		Address += 4;
	}
}

void FLASH_WritePage_NoCheck(uint32_t Address, const uint32_t* Buffer)
{
	HAL_FLASH_Lock();    //解锁
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, Address, (uint32_t *)Buffer);
	HAL_FLASH_Unlock();  //上锁
}

void FLASH_ErasePage(uint32_t Address)
{
	uint32_t PageError = 0;
	FLASH_EraseInitTypeDef EraseInitStruct = {0};
	HAL_FLASH_Unlock();
	EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGEERASE;
	EraseInitStruct.PageAddress = Address;
	EraseInitStruct.NbPages     = 1;  /* erase nums pages. */
	HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
	HAL_FLASH_Lock();
}

void FLASH_Write(uint32_t Address, const uint32_t *Buffer, uint32_t NumToWrite)
{
	uint32_t secpos;	   //页地址
	uint32_t secoff;	   //页内偏移地址(16位字计算)
	uint32_t secremain;    //页内剩余地址(16位字计算)
	uint32_t i;
	uint32_t offaddr;    //去掉0X08000000后的地址
	HAL_FLASH_Unlock();  //解锁
	offaddr = Address - FLASH_BASE;		              //实际偏移地址.
	secpos = offaddr / FLASH_PAGE_SIZE;			       //页地址
	secoff = (offaddr % FLASH_PAGE_SIZE) >> 2;		   //在页内的偏移(2个字节为基本单位.)
	secremain = (FLASH_PAGE_SIZE >> 2) - secoff;		   //页剩余空间大小
	if(NumToWrite <= secremain)secremain = NumToWrite; //不大于该页范围
	while(1)
	{
		FLASH_Read(secpos * FLASH_PAGE_SIZE + FLASH_BASE, FlashBuffer, FLASH_PAGE_SIZE >> 2); //读出整个页的内容
		for(i = 0; i < (FLASH_PAGE_SIZE >> 2); i++) //校验数据
		{
			if(FlashBuffer[i] != 0XFFFFFFFF)
			{
				uint32_t PageError = 0;
				FLASH_EraseInitTypeDef EraseInitStruct = {0};
				EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGEERASE;
				EraseInitStruct.PageAddress = Address;
				EraseInitStruct.NbPages     = 1;  /* erase nums pages. */
				HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
				break;
			}
		}
		for(i = 0; i < secremain; i++) //复制
		{
			FlashBuffer[i + secoff] = Buffer[i];
		}
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, secpos * FLASH_PAGE_SIZE + FLASH_BASE, (uint32_t *)FlashBuffer);  //写入整个页
		if(NumToWrite == secremain)break; //写入结束了
		else//写入未结束
		{
			secpos++;				//页地址增1
			secoff = 0;				//偏移位置为0
			Buffer += secremain;  	//指针偏移
			Address += secremain;	//写地址偏移
			NumToWrite -= secremain;	//字节(16位)数递减
			if(NumToWrite > (FLASH_PAGE_SIZE >> 2)) secremain = (FLASH_PAGE_SIZE >> 2); //下一个页还是写不完
			else secremain = NumToWrite; //下一个页可以写完了
		}
	}
	HAL_FLASH_Lock();  //解锁
}

void FLASH_SetReadProtectionState(int onoff)
{
	FLASH_OBProgramInitTypeDef OptionsBytesStruct;
	HAL_FLASH_Unlock();
	HAL_FLASH_OB_Unlock();
	HAL_FLASH_OBGetConfig(&OptionsBytesStruct);
	if(onoff)
	{
		if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_0)
		{
			OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
			OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_1;
			HAL_FLASH_OBProgram(&OptionsBytesStruct);
			HAL_FLASH_OB_Launch();
		}
	}
	else
	{
		if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_1)
		{
			OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
			OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_0;
			HAL_FLASH_OBProgram(&OptionsBytesStruct);
			HAL_FLASH_OB_Launch();
		}
	}
	HAL_FLASH_OB_Lock();
	HAL_FLASH_Lock();
}

void FLASH_RdWrTest(void)
{
	uint32_t Address;
	uint32_t PageReadBuffer[FLASH_PAGE_SIZE >> 2];
	uint32_t PageWriteBuffer[FLASH_PAGE_SIZE >> 2];

	memset(PageWriteBuffer, 0XAA, sizeof(PageWriteBuffer));

	for(Address = 0x08003000; Address < 0x08008000; Address += FLASH_PAGE_SIZE)  // 16K~32K
	{
		FLASH_Write(Address, PageWriteBuffer, sizeof(PageReadBuffer) >> 2);

		memset(PageReadBuffer, 0, sizeof(PageReadBuffer));

		FLASH_Read(Address, PageReadBuffer, sizeof(PageReadBuffer) >> 2);

		if(memcmp(PageReadBuffer, PageWriteBuffer, sizeof(PageReadBuffer)) == 0)
		{
			printf("page[%04d]  0x%08X read & write %s \r\n", (int)((Address - FLASH_BASE) / FLASH_PAGE_SIZE), Address, "ok");
		}
		else
		{
			printf("page[%04d]  0x%08X read & write %s \r\n", (int)((Address - FLASH_BASE) / FLASH_PAGE_SIZE), Address, "failed");
		}
	}
}

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

Air32 的相关文章

随机推荐

  • java8之lambda表达式简介

    文章目录 1 概念 2 基础语法 2 1 语法格式一 2 2 语法格式二 2 3 语法格式三 2 4 语法格式四 2 5 语法格式五 2 6 语法格式六 3 Lambda 表达式需要 函数式接口 的支持 4 java内置四大核心函数式接口
  • python的split分割数组_NumPy数组的分割

    在 NumPy 中 利用 split hsplit 和 vsplit 等函数可实现数组的分割操作 split 函数 该函数可沿特定的轴将数组分割为子数组 使用 split 函数的方法如下 numpy split arr indices or
  • K8S安装Master教程(亲测成功)

    配置hosts vim etc hosts 追加如下内容 192 168 18 10 k8s master 192 168 18 11 k8s node1 192 168 18 12 k8s node2 192 168 18 13 k8s
  • 搭建nginx+php后访问不到项目

    记在虚拟机搭建php nginx mysql踩到的坑 首先因为工作原因 离开了上家公司 然后入职xx后 由于没有开发机只能自己搭建了一个虚拟机 搭建好后使用一键安装式工具安装了lnmp环境 之后访问nginx是可以访问通的 但是指定了项目目
  • TCP、UDP、HTTP、SOCKET之间的区别

    IP 网络层协议 TCP和UDP 传输层协议 HTTP 应用层协议 SOCKET TCP IP网络的API TCP IP代表传输控制协议 网际协议 指的是一系列协议 TCP和UDP使用IP协议从一个网络传送数据包到另一个网络 把IP想像成一
  • 二手服务器还是组装机,我表弟不懂电脑,老板竟然给他组装这种电脑:没坑人,明码标价!...

    说到组装电脑 大家都不陌生了 它是多硬件组合的产物 它对硬件搭配有要求 对于动手能力也有一定的要求 于是很多朋友为了省麻烦就会去找熟人或者是电脑店进行咨询组装电脑 前几天 我的表弟就在他居住附近的一家电脑店咨询组装了一台电脑 最后发现被坑惨
  • 原创打造 Claude网页 接口

    先进入App unavailable Anthropic 新建聊天聊起来 在聊之前就要打开f12 监听请求 相关参数打开f12即可找到 注意 需要在打开f12后发送几条信息给claude才有相关链接显示 这两个参数就是我们需要的 cooki
  • Code Blocks IDE在linux下添加include & lib路径

    摘自 url http bbs csdn net topics 350101552 url size large 第一步 编译第三方库 得到头文件和库 例如路径关系 D MyLib include D MyLib lib 在include中
  • 抖音直播间弹幕rpc学习

    目标url 随便找个直播间即可 https live douyin com 198986091107 接口分析 首先并没有在xhr下找到对应的接口 因为采用了websocket来传输信息 切换到ws即可看到 消息下 可以看到16进制的数据在
  • 连接被拒绝 因为没有授权此用户账户进行远程登录

    背景 有时想远程连接某服务器进行操作 但是远程登陆时 却报错 解决办法 在服务器上进行设置 允许用户登录 步骤 1 用允许登录的用户 远程连接服务器 在这里用v liyh登录 点击 开始 图标 运行 如图 在对话框中输入 mstsc 如图
  • 【Linux命令详解

    文章标题 简介 一 参数列表 二 使用介绍 1 显示文件内容 2 创建文件 3 连接文件 4 显示行号 5 压缩空行 6 显示特殊字符 7 显示行号和特殊字符 8 从标准输入读取 9 显示文件开头或结尾 10 备份文件 11 显示文件内容至
  • Redis 配置详解 —— 全网最新最全

    文章目录 一 撰文目的 二 配置详解 1 EXAMPLE 概要说明 2 INCLUDES 配置包含 3 MODULES 加载模块 4 NETWORK 网络配置 5 TLS SSL 通讯协议 6 GENERAL 常规配置 7 SNAPSHOT
  • 【合作 】联通、壳牌、联想、国金证券等众多企业签约 Eolink !

    联通 壳牌 联想 华润置地 中国铁塔等多家知名企业签约 Eolink 携手落地 API 全生命周期管理 感谢广大企业对 Eolink 的信任和选择 Eolink 致力于为企业提供最全面的 API 研发管理解决方案 提供高效 可靠的工具以及服
  • lua文件读写

    文件读写 文件读写对制作游戏很有帮助 可以调用别的文件中的代码 保存最高分 游戏存档 玩家状态等信写到文件中 首先 让我们看一个简单的命令 dofile 这个命令会读入另一个文件的代码并立即执行 代码 dofile test lua 很简单
  • 记录一个vue项目报错UnhandledPromiseRejectionWarning: Unhandled promise rejection.

    使用vue cli创建vue项目 加入一些之前的代码 然后打包运行报错 node 4892 UnhandledPromiseRejectionWarning Unhandled promise rejection This error or
  • 一种复杂业务场景的解决方案(代码结构)

    背景 我个人负责交易线的一些服务优化工作 如购物车 预购单等 这些服务是前台服务 需要基于很多中台服务能力来实现业务功能 中台服务如商品中心 协议中心 用户中心 营销活动等 前台服务通过RPC调用中台服务获取数据 在2020年度的优化工作汇
  • 如何做好nodejs服务在服务器上的安全防护?

    Web服务器安全问题仍然是IT部门最关心的问题之一 因为频发的网络攻击已被证明 由于存在托管敏感数据 Web服务器是一个组织中最容易被黑客针对攻击的地方 因此 本篇文章结合nodejs服务对如何提高Web服务器安全性给出了下面几条提示 一
  • 2023蓝桥杯C++A组题解(第十四届)

    今年广东省三中游 按New Oj估分 前5题估分17 第1题 3 4 5题暴力 第2题 B dfs写错了 第7题 G 并查集 多了个以前没见过的要求 找不到思路 面向爆零选手 水平有限 将就着看 有空再补充后5题 目录 吐槽 A 2067
  • Vue全家桶(四)之ES6模块化与webpack打包

    Vue全家桶 Vue全家桶 地址 Vue全家桶 一 之基础指令 https blog csdn net m0 55990909 article details 123917809 Vue全家桶 一 之常用特性 https blog csdn
  • Air32

    Air32 合宙Air001单片机内部FLASH读写示例 代码已经通过测试 开发环境KEIL MDK 5 36 测试代码 void FLASH RdWrTest void uint32 t Address uint32 t PageRead