当前位置: 首页 > news >正文

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)时&#xff0c;调试发现该函数返回HAL_ERROR&#xff0c;最后定位到FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE)函数出现错误&#xff0c;pFlash.ErrorCode为0xA0&#xff0c;即FLASH错误标…...

08.02_111期_Linux_NAT技术

NAT(network address translation)技术说明 IP报文在转发的时候需要考虑 源IP地址 和 目的IP地址&#xff0c; IP报文每到达一个节点&#xff0c;就会更改一次IP地址和目的IP地址&#xff0c;其中节点是指主机、服务器、路由器 那么这个更改是如何进行的呢&#xff1f; 除了…...

【2024蓝桥杯/C++/B组/小球反弹】

题目 分析 Sx 2 * k1 * x; Sy 2 * k2 * y; &#xff08;其中k1, k2为整数&#xff09; Vx * t Sx; Vy * t Sy; k1 / k2 (15 * y) / (17 * x)&#xff1b; 目标1&#xff1a;根据k1与k2的关系&#xff0c;找出一组最小整数组&#xff08;k1, k2&#xff09;&#xff…...

PHP中如何实现函数的可变参数列表

在PHP中&#xff0c;实现函数的可变参数列表主要有两种方式&#xff1a;使用func_get_args()函数和使用可变数量的参数&#xff08;通过...操作符&#xff0c;自PHP 5.6.0起引入&#xff09;。 1. 使用func_get_args()函数 func_get_args()函数用于获取传递给函数的参数列表&…...

串---链串实现

链串详解 本文档将详细介绍链串的基本概念、实现原理及其在 C 语言中的具体应用。通过本指南&#xff0c;读者将了解如何使用链串进行各种字符串操作。 1. 什么是链串&#xff1f; 链串是一种用于存储字符串的数据结构&#xff0c;它使用一组动态分配的节点来保存字符串中的…...

科技赋能生活——便携气象站

传统气象站往往庞大而复杂&#xff0c;需要专业人员维护&#xff0c;它小巧玲珑&#xff0c;设计精致&#xff0c;可以轻松放入背包或口袋&#xff0c;随身携带&#xff0c;不占空间。无论是城市白领穿梭于高楼大厦间&#xff0c;还是户外爱好者深入山林湖海&#xff0c;都能随…...

Golang——GC原理

1.垃圾回收的目的 将未被引用到的对象销毁&#xff0c;回收其所占的内存空间。 2.根对象是什么 全局变量&#xff1a;在编译器就能确定的存在于程序整个生命周期的变量。 执行栈&#xff1a;每个goroutine都包含自己的执行栈&#xff0c;这些执行栈上包含栈上的变量及指向分配…...

OpenStack概述

一、初识OpenStack OpenStack Docs: 概况 一&#xff09;OpenStack架构简述 1、理解OpenStack OpenStack既是一个社区&#xff0c;也是一个项目和一个开源软件&#xff0c;提供开放源码软件&#xff0c;建立公共和私有云&#xff0c;它提供了一个部署云的操作平台或工具集&…...

机器学习练手(三):基于决策树的iris 多分类和波士顿房价预测

总结&#xff1a;本文为和鲸python 可视化探索训练营资料整理而来&#xff0c;加入了自己的理解&#xff08;by GPT4o&#xff09; 原活动链接 原作者&#xff1a;vgbhfive&#xff0c;多年风控引擎研发及金融模型开发经验&#xff0c;现任某公司风控研发工程师&#xff0c;对…...

PS 2024 百种常用插件下载安装教程【免费使用,先到先得】

文章目录 软件介绍软件下载安装步骤 专栏推荐&#xff1a; 超多精品软件&#xff08;持续更新中…&#xff09; 软件推荐&#xff1a; PS 2024 PR 2024 软件介绍 PS常用插件 此软件整合了市面近百款ps处理插件&#xff0c;可实现&#xff1a;一键制作背景&#xff0c;一键抠图…...

逻辑推理之lora微调

逻辑推理微调 比赛介绍准备内容lora微调lora微调介绍lora优势代码内容 start_vllm相关介绍调用 运行主函数提交结果总结相应连接 比赛介绍 本比赛旨在测试参与者的逻辑推理和问题解决能力。参与者将面对一系列复杂的逻辑谜题&#xff0c;涵盖多个领域的推理挑战。 比赛的连接:…...

前端-防抖代码

//防抖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

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 让 LLM 自动选择不同的 Prompt 在上一篇文章中&#xff0c;我们学会了如何让 langchain 来自动选择不同的 LLM Chain&#xff0c;以便回…...

web浏览器播放rtsp视频流,海康监控API

概述 这里记录一下如何让前端播放rtsp协议的视频流 ​ 项目中调用海康API&#xff0c;生成的视频流(hls、ws、rtmp等)通过PotPlayer播放器都无法播放&#xff0c;说明视频流有问题&#xff0c;唯独rtsp视频流可以播放。 但是浏览器本身是无法播放rtsp视频的&#xff0c;即使…...

操作系统原理:程序、进程、线程的概念

文章目录 程序、进程、线程的概念程序&#xff08;Program&#xff09;进程&#xff08;Process&#xff09;线程&#xff08;Thread&#xff09;关系总结 在日常对操作系统的使用中&#xff0c;大家肯定对程序、进程和线程多少有所耳闻。作为操作系统的重要一部分&#xff0c;…...

Golang是如何实现动态数组功能的?Slice切片原理解析

Hi 亲爱的朋友们&#xff0c;我是 k 哥。今天&#xff0c;咱们聊一聊Golang 切片。 当我们需要使用数组&#xff0c;但是又不能提前定义数组大小时&#xff0c;可以使用golang的动态数组结构&#xff0c;slice切片。在 Go 语言的众多特性里&#xff0c;slice 是我们经常用到的数…...

SQL注入 报错注入+附加拓展知识,一篇文章带你轻松入门

第5关--------------------------------------------> 前端直接不会显示账号密码的打印&#xff1b;但是在接收前端的数据的那部分后端那里&#xff0c;会看前端传递过来的值是否正确&#xff0c;如果不正确&#xff0c;后端接收值那里就会当MySQL语句执行错误&#xff0c;…...

springboot项目里的包spring-boot-dependencies依赖介绍

springboot项目里的包’spring-boot-dependencies‘依赖 我们一般是在项目的pom dependencyManagement标签里引入spring-boot-dependencies&#xff0c;或者根spring-boot-starter-parent里也是继承了它,也正是因为继承了这个依赖&#xff0c;所以我们在写依赖时才不需要写版本…...

C# 下的限定符运算详解(全部,任意,包含)与示例

文章目录 1.限定符概述2. 全部限定符运算&#xff08;All&#xff09;3. 任意限定符运算&#xff08;Any&#xff09;4. 包含限定符运算&#xff08;Contains&#xff09;总结 当我们在C#编程中需要进行条件判断或集合操作时&#xff0c;限定符&#xff08;qualifiers&#xff…...

消息队列RabbitMQ部分知识

1.简述RabbitMQ的架构设计 RabbitMQ 是一个开源的消息代理&#xff0c;采用了高级消息队列协议&#xff08;AMQP&#xff09;&#xff0c;其架构设计主要包括以下几个关键组件和概念&#xff1a; 1.消息生产者&#xff08; Producer&#xff09;&#xff1a; 负责发送消息到…...

OpenClaw定时任务:利用GLM-4.7-Flash实现智能日程管理

OpenClaw定时任务&#xff1a;利用GLM-4.7-Flash实现智能日程管理 1. 为什么需要智能化的定时任务 记得上个月我连续错过了三个重要会议&#xff0c;原因很简单——手动设置的日历提醒被其他通知淹没了。这种经历让我开始寻找更智能的解决方案。传统定时工具只能机械地执行预…...

深入理解Matplotlib中的plt、fig、axes与axis:从基础到高级应用

1. Matplotlib绘图基础&#xff1a;从plt到figure的认知跃迁 第一次接触Matplotlib时&#xff0c;最让人困惑的就是plt.plot()和ax.plot()到底有什么区别。这就像学做菜时&#xff0c;有人告诉你"用锅炒菜"和"先用电磁炉加热再放锅炒菜"两种方式都能做出青…...

Mojo调用Python模块性能翻倍?深度剖析混合编程内存管理、GIL绕过与ABI兼容性(附实测基准数据)

第一章&#xff1a;Mojo与Python混合编程案例源码分析Mojo 作为兼具 Python 兼容性与系统级性能的新一代编程语言&#xff0c;其与 Python 的混合编程能力是实际工程落地的关键。以下通过一个典型场景——在 Python 主程序中调用 Mojo 实现的高性能向量加法函数——展开源码级剖…...

VSCode党必看!用轻量级方案玩转LaTeX:2024年TexLive+VSCode配置全攻略

VSCode党必看&#xff01;用轻量级方案玩转LaTeX&#xff1a;2024年TexLiveVSCode配置全攻略 对于习惯在VSCode中高效编码的开发者而言&#xff0c;切换到传统LaTeX编辑器往往意味着要放弃熟悉的快捷键、扩展生态和流畅的代码体验。本文将带你用完全基于VSCode的轻量级方案构建…...

C语言回调函数在TCP客户端中的实现与应用

C语言回调函数在TCP客户端中的实现与应用1. 回调函数基础概念回调函数是一种通过函数指针实现的编程机制&#xff0c;允许将一个函数作为参数传递给另一个函数。在C语言中&#xff0c;回调函数的实现完全依赖于函数指针&#xff0c;这与C、Python等现代语言中可能使用仿函数或匿…...

三相桥式整流电路有源逆变状态的研究:基于Matlab仿真的直流发电机电动系统电能流转关系分析

三相桥式整流电路有源逆变状态 Matlab仿真可写报告 直流发电机电动系统入手&#xff0c;研究电能流转关系&#xff0c;再转入变流器分析交流和直流电之间流转&#xff0c;掌握有源逆变条件。玩过直流电机调速的朋友可能遇到过这样的情况&#xff1a;明明在减速状态&#xff0c;…...

SGLang-v0.5.6实战体验:5种预装镜像,哪个最适合你的项目?

SGLang-v0.5.6实战体验&#xff1a;5种预装镜像&#xff0c;哪个最适合你的项目&#xff1f; 选型会上&#xff0c;技术负责人又抛出了那个经典问题&#xff1a;“我们到底用哪个环境来部署SGLang&#xff1f;” 会议室里立刻热闹起来。有人坚持用PyTorch 2.1&#xff0c;说它…...

揭秘League Akari:如何通过LCU API革新英雄联盟游戏体验?

揭秘League Akari&#xff1a;如何通过LCU API革新英雄联盟游戏体验&#xff1f; 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit …...

基于CYBER-VISION零号协议构建智能技术文档翻译与摘要系统

基于CYBER-VISION零号协议构建智能技术文档翻译与摘要系统 1. 引言 对于很多开发者来说&#xff0c;阅读英文技术文档是件挺头疼的事。尤其是遇到一些前沿的开源项目&#xff0c;官方文档全是英文&#xff0c;里面还夹杂着大量的专业术语和复杂的配置说明。有时候&#xff0c…...

Android音频输出流实战:从AudioFlinger到HAL层的完整调用链解析

Android音频输出流深度解析&#xff1a;从框架设计到硬件交互 1. Android音频系统架构概览 Android音频子系统采用分层设计&#xff0c;每一层都有明确的职责划分。理解这个架构是分析音频输出流的基础。 核心层级结构&#xff1a; 应用层&#xff1a;通过AudioTrack、MediaPla…...