STM32G070系列芯片擦除、写入Flash错误解决
在用G070KBT6芯片调用HAL_FLASHEx_Erase(&EraseInitStruct, &PageError)时,调试发现该函数返回HAL_ERROR,最后定位到FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE)函数出现错误,pFlash.ErrorCode为0xA0,即FLASH错误标志位 FLASH_SR_PGSERR和FLASH_SR_PGAERR被置位;
static void Flash_EraseSector(uint32_t PageAddress) {FLASH_EraseInitTypeDef EraseInitStruct;uint32_t PageError = 0;/* Fill EraseInit structure */EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;EraseInitStruct.Page = (PageAddress - FLASH_BASE) / FLASH_PAGE_SIZE;EraseInitStruct.NbPages = 1;EraseInitStruct.Banks = FLASH_BANK_1;//FLASH->SR = FLASH_SR_CLEAR;if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) {/* Error occurred while page erase */Flash_Error_Handler();}
}
在网上找半天找不到问题原因,最后在【问题】STM32G0芯片擦除flash失败,发现死在FLASH_SR_CFGBSY一直为1(已解决)_读出的选项字节:芯片做全片擦除失败-CSDN博客
博客和评论区中发现是由于我程序中调用了看门狗喂狗函数,但是为了调试就把看门狗初始化函数注释调了,导致出现FLASH标志位错误,我把喂狗函数也一起注释掉再调试就发现能够正常对FLASH进行擦除。
然后就是对FLASH进行写和读,当我以32位数据为单位对FLASH进行读写时会进入HardFAULT_Handle,后面在这篇博客中发现要改为以64位数据为单位读写才可以;STM32G030F6P6读写flash失败问题(HAL)-CSDN博客
至此,就能对FLASH进行正常擦除和读写,可以用这个将单片机板载FLASH中的一部份区域用作用户数据掉电保存,功能实现和测试代码如下(包括64字节读写和FLASH结构体读写):
User_Flash.c:#include "User_Flash.h"
#include <string.h>
#include "usart.h"static void Flash_Error_Handler(void) {while (1) {// Error handling}
}/*
* @function: flash页擦除函数,擦除指定地址所处的页(扇区)
* @parm1: uint32_t PageAddress 要擦除的页中的任意地址
*/
static void Flash_EraseSector(uint32_t PageAddress) {FLASH_EraseInitTypeDef EraseInitStruct;uint32_t PageError = 0;/* Fill EraseInit structure */EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;EraseInitStruct.Page = (PageAddress - FLASH_BASE) / FLASH_PAGE_SIZE;EraseInitStruct.NbPages = 1;EraseInitStruct.Banks = FLASH_BANK_1;//FLASH->SR = FLASH_SR_CLEAR;if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) {/* Error occurred while page erase */Flash_Error_Handler();}
}/*
* @function: 在指定地址写入32位数据先解锁flash,再擦除指定地址对应页,写入数据,最后重新上锁Flash
* @parm1: uint32_t Address 要写入的数据起始地址
* @parm2: uint32_t Data 要写入的数据
*/
void Flash_WriteData(uint32_t Address, uint64_t Data) {HAL_FLASH_Unlock(); //先解锁FLASHFlash_EraseSector(Address); //擦除要写入的扇区(页)if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data) == HAL_OK) {/* Check the written value */if (*(uint64_t*)Address != Data) {/* Error occurred while writing data */Flash_Error_Handler();}} else {/* Error occurred while writing data */Flash_Error_Handler();}HAL_FLASH_Lock(); //重新上锁FLASH
}/*
* @function: 读取Flash指定地址的32位数据
* @parm1: uint32_t Address 要读取的地址
*
* @return: 读取的32位数据
*/
uint64_t Flash_ReadData(uint32_t Address) {return *(uint64_t*)Address;
}/*
* @function: 在指定地址写入结构体数据先解锁flash,再擦除指定地址对应页,写入数据,最后重新上锁Flash
* @parm1: uint32_t Address 要写入的数据起始地址
* @parm2: MyData_t *data 要写入的结构体数据的指针
*/
void Flash_WriteStruct(uint32_t Address, MyData_t *data) {HAL_FLASH_Unlock(); //先解锁FLASHFlash_EraseSector(Address); //擦除要写入的扇区(页)uint64_t *dataPtr = (uint64_t*)data;size_t size = sizeof(MyData_t) / 8; // Number of 64-bit wordsif (sizeof(MyData_t) % 8 != 0) size++; // handle cases where size is not multiple of 4// Write the datafor (size_t i = 0; i < size; i++) {if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address + (i * 8), dataPtr[i]) == HAL_OK){if (*(uint64_t*)(Address + (i * 8)) != dataPtr[i]) {Flash_Error_Handler();}} else {Flash_Error_Handler();}}HAL_FLASH_Lock(); //重新上锁FLASH
}/*
* @function: 读取Flash指定地址的结构体数据
* @parm1: uint32_t Address 要读取的地址
* @parm2: MyData_t *data 读取的结构体数据保存地址
*/
void Flash_ReadStruct(uint32_t Address, MyData_t *data) {uint64_t *pData = (uint64_t*)data;uint32_t size = sizeof(MyData_t) / 8; // assuming size is a multiple of 4if (sizeof(MyData_t) % 8 != 0) size++; // handle cases where size is not multiple of 4for (uint32_t i = 0; i < size; i++) {pData[i] = *(uint64_t*)(Address + (i * 8));}
}/******测试代码******/
uint64_t data;
void Flash_Test(void)
{//EraseFlash(63,1);Flash_WriteData(FLASH_USER_START_ADDR, DATA_64);data = Flash_ReadData(FLASH_USER_START_ADDR);if (data == DATA_64) {myprintf("Flash_WriteData OK");} else {myprintf("Flash_WriteData ERROR");// Data write error}MyData_t myData = {0x12345678, 0xABCD, 0xEF, "Hello"};MyData_t readData;/* Program the user Flash area */Flash_WriteStruct(FLASH_USER_START_ADDR, &myData);/* Verify the data */Flash_ReadStruct(FLASH_USER_START_ADDR, &readData);// 验证数据if (memcmp(&myData, &readData, sizeof(MyData_t)) == 0) {myprintf("Flash_WriteStruct OK");// Data written and read correctly} else {myprintf("Flash_WriteStruct ERROR");// Data write or read error}
}User_Flash.h:
#ifndef __USER_FLASH_H__
#define __USER_FLASH_H__#include "stm32g0xx_hal.h"#define FLASH_USER_START_ADDR 0x0801F800 /* G070KBT6 flash大小为128KB,每页2KB,这里用最后一页作为用户数据保存区域 */
#define FLASH_USER_END_ADDR (0x08020000 - 1) /* End address of Flash */
//#define FLASH_PAGE_SIZE 2048 /* Page size of 2 KB */
#define DATA_32 ((uint32_t)0x12345678)
#define DATA_64 ((uint64_t)0x12345678)typedef struct {uint32_t field1;uint16_t field2;uint8_t field3;char field4[10];
} MyData_t;static void Flash_Error_Handler(void) ;
static void Flash_EraseSector(uint32_t PageAddress) ;
void Flash_WriteData(uint32_t Address, uint64_t Data);
uint64_t Flash_ReadData(uint32_t Address);
void Flash_WriteStruct(uint32_t Address, MyData_t *data) ;
void Flash_ReadStruct(uint32_t Address, MyData_t *data) ;
void Flash_Test(void);#endif
参考文章:STM32G030F6P6读写flash失败问题(HAL)-CSDN博客
【问题】STM32G0芯片擦除flash失败,发现死在FLASH_SR_CFGBSY一直为1(已解决)_读出的选项字节:芯片做全片擦除失败-CSDN博客
相关文章:
STM32G070系列芯片擦除、写入Flash错误解决
在用G070KBT6芯片调用HAL_FLASHEx_Erase(&EraseInitStruct, &PageError)时,调试发现该函数返回HAL_ERROR,最后定位到FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE)函数出现错误,pFlash.ErrorCode为0xA0,即FLASH错误标…...
08.02_111期_Linux_NAT技术
NAT(network address translation)技术说明 IP报文在转发的时候需要考虑 源IP地址 和 目的IP地址, IP报文每到达一个节点,就会更改一次IP地址和目的IP地址,其中节点是指主机、服务器、路由器 那么这个更改是如何进行的呢? 除了…...
【2024蓝桥杯/C++/B组/小球反弹】
题目 分析 Sx 2 * k1 * x; Sy 2 * k2 * y; (其中k1, k2为整数) Vx * t Sx; Vy * t Sy; k1 / k2 (15 * y) / (17 * x); 目标1:根据k1与k2的关系,找出一组最小整数组(k1, k2)ÿ…...
PHP中如何实现函数的可变参数列表
在PHP中,实现函数的可变参数列表主要有两种方式:使用func_get_args()函数和使用可变数量的参数(通过...操作符,自PHP 5.6.0起引入)。 1. 使用func_get_args()函数 func_get_args()函数用于获取传递给函数的参数列表&…...
串---链串实现
链串详解 本文档将详细介绍链串的基本概念、实现原理及其在 C 语言中的具体应用。通过本指南,读者将了解如何使用链串进行各种字符串操作。 1. 什么是链串? 链串是一种用于存储字符串的数据结构,它使用一组动态分配的节点来保存字符串中的…...
科技赋能生活——便携气象站
传统气象站往往庞大而复杂,需要专业人员维护,它小巧玲珑,设计精致,可以轻松放入背包或口袋,随身携带,不占空间。无论是城市白领穿梭于高楼大厦间,还是户外爱好者深入山林湖海,都能随…...
Golang——GC原理
1.垃圾回收的目的 将未被引用到的对象销毁,回收其所占的内存空间。 2.根对象是什么 全局变量:在编译器就能确定的存在于程序整个生命周期的变量。 执行栈:每个goroutine都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配…...
OpenStack概述
一、初识OpenStack OpenStack Docs: 概况 一)OpenStack架构简述 1、理解OpenStack OpenStack既是一个社区,也是一个项目和一个开源软件,提供开放源码软件,建立公共和私有云,它提供了一个部署云的操作平台或工具集&…...
机器学习练手(三):基于决策树的iris 多分类和波士顿房价预测
总结:本文为和鲸python 可视化探索训练营资料整理而来,加入了自己的理解(by GPT4o) 原活动链接 原作者:vgbhfive,多年风控引擎研发及金融模型开发经验,现任某公司风控研发工程师,对…...
PS 2024 百种常用插件下载安装教程【免费使用,先到先得】
文章目录 软件介绍软件下载安装步骤 专栏推荐: 超多精品软件(持续更新中…) 软件推荐: PS 2024 PR 2024 软件介绍 PS常用插件 此软件整合了市面近百款ps处理插件,可实现:一键制作背景,一键抠图…...
逻辑推理之lora微调
逻辑推理微调 比赛介绍准备内容lora微调lora微调介绍lora优势代码内容 start_vllm相关介绍调用 运行主函数提交结果总结相应连接 比赛介绍 本比赛旨在测试参与者的逻辑推理和问题解决能力。参与者将面对一系列复杂的逻辑谜题,涵盖多个领域的推理挑战。 比赛的连接:…...
前端-防抖代码
//防抖debounce(fn, time 1000) {let timer null;return function (...args) {if (timer) clearTimeout(timer);timer setTimeout(() > {fn.apply(this, args);}, time);};},// 输入变化处理函数async inputChange(value) {if (!this.debouncedInputChange) {this.deboun…...
langchain 入门指南 - 让 LLM 自动选择不同的 Prompt
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 让 LLM 自动选择不同的 Prompt 在上一篇文章中,我们学会了如何让 langchain 来自动选择不同的 LLM Chain,以便回…...
web浏览器播放rtsp视频流,海康监控API
概述 这里记录一下如何让前端播放rtsp协议的视频流 项目中调用海康API,生成的视频流(hls、ws、rtmp等)通过PotPlayer播放器都无法播放,说明视频流有问题,唯独rtsp视频流可以播放。 但是浏览器本身是无法播放rtsp视频的,即使…...
操作系统原理:程序、进程、线程的概念
文章目录 程序、进程、线程的概念程序(Program)进程(Process)线程(Thread)关系总结 在日常对操作系统的使用中,大家肯定对程序、进程和线程多少有所耳闻。作为操作系统的重要一部分,…...
Golang是如何实现动态数组功能的?Slice切片原理解析
Hi 亲爱的朋友们,我是 k 哥。今天,咱们聊一聊Golang 切片。 当我们需要使用数组,但是又不能提前定义数组大小时,可以使用golang的动态数组结构,slice切片。在 Go 语言的众多特性里,slice 是我们经常用到的数…...
SQL注入 报错注入+附加拓展知识,一篇文章带你轻松入门
第5关--------------------------------------------> 前端直接不会显示账号密码的打印;但是在接收前端的数据的那部分后端那里,会看前端传递过来的值是否正确,如果不正确,后端接收值那里就会当MySQL语句执行错误,…...
springboot项目里的包spring-boot-dependencies依赖介绍
springboot项目里的包’spring-boot-dependencies‘依赖 我们一般是在项目的pom dependencyManagement标签里引入spring-boot-dependencies,或者根spring-boot-starter-parent里也是继承了它,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本…...
C# 下的限定符运算详解(全部,任意,包含)与示例
文章目录 1.限定符概述2. 全部限定符运算(All)3. 任意限定符运算(Any)4. 包含限定符运算(Contains)总结 当我们在C#编程中需要进行条件判断或集合操作时,限定符(qualifiersÿ…...
消息队列RabbitMQ部分知识
1.简述RabbitMQ的架构设计 RabbitMQ 是一个开源的消息代理,采用了高级消息队列协议(AMQP),其架构设计主要包括以下几个关键组件和概念: 1.消息生产者( Producer): 负责发送消息到…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
