STM32G030F6P6读写flash失败问题(HAL)

STM32G030是F0系列的升级版,其在性能上比F0要好很多,具体G0参数如下:

        最开始做项目选用的单片机是STM32F030F4P6,但是在后期使用中发现,我的FLASH(16K)不够用了,就选择了STM32G030F6P6来进行项目使用,主要是价格便宜,资源够用。

        在F030使用的flash拿到G030上来发现不可使用,就进行了一些修改,但是这个时候就出现了报错,在进行flash擦除的时候报错

HAL_FLASHEx_Erase(&EraseInitStruct,&PageError);

通过发现擦除有问题,我就去查看其底层函数。

HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
{HAL_StatusTypeDef status;uint32_t index;/* Check the parameters */assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));/* Process Locked */__HAL_LOCK(&pFlash);/* Reset error code */pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);if (status == HAL_OK){
#if !defined(FLASH_DBANK_SUPPORT)/* For single bank product force Banks to Bank 1 */pEraseInit->Banks = FLASH_BANK_1;
#endif /* FLASH_DBANK_SUPPORT */if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASS){/* Proceed to Mass Erase */FLASH_MassErase(pEraseInit->Banks);/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);}else{/*Initialization of PageError variable*/*PageError = 0xFFFFFFFFU;for (index = pEraseInit->Page; index < (pEraseInit->Page + pEraseInit->NbPages); index++){/* Start erase page */FLASH_PageErase(pEraseInit->Banks, index);/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);if (status != HAL_OK){/* In case of error, stop erase procedure and return the faulty address */*PageError = index;break;}}/* If operation is completed or interrupted, disable the Page Erase Bit */CLEAR_BIT(FLASH->CR, FLASH_CR_PER);}}/* Process Unlocked */__HAL_UNLOCK(&pFlash);/* return status */return status;
}

        其大致意思就是两种擦除方式,片擦除以及全部擦除。然后发现其status是在  FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);   里面进行报错,其函数实现如下:

HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout)
{uint32_t error;/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.Even if the FLASH operation fails, the BUSY flag will be reset and an errorflag will be set */uint32_t timeout = HAL_GetTick() + Timeout;/* Wait if any operation is ongoing */
#if defined(FLASH_DBANK_SUPPORT)error = (FLASH_SR_BSY1 | FLASH_SR_BSY2);
#elseerror = FLASH_SR_BSY1;
#endif /* FLASH_DBANK_SUPPORT */while ((FLASH->SR & error) != 0x00U){if (HAL_GetTick() >= timeout){return HAL_TIMEOUT;}}/* check flash errors */error = (FLASH->SR & FLASH_SR_ERRORS);/* Clear SR register */FLASH->SR = FLASH_SR_CLEAR;if (error != 0x00U){/*Save the error code*/pFlash.ErrorCode = error;return HAL_ERROR;}/* Wait for control register to be written */timeout = HAL_GetTick() + Timeout;while ((FLASH->SR & FLASH_SR_CFGBSY) != 0x00U){if (HAL_GetTick() >= timeout){return HAL_TIMEOUT;}}return HAL_OK;
}

发现其在这里进行报错,然后从下面返回错误码上来。

返回我打印了这个error到底是多少,发现其值为0x80,发现报的错误是   FLASH_SR_PGSERR

然后查看数据手册以及使用手册,发现这个是编程错误。然后继续查找问题,发现G030的一个bank是2K,修改之后发现还是报这个错误。

        在详细查看数据手册后,发现G030进行Flash读写是uint64_t进行读写的,如下:

        在此情况下,对读写函数进行修改,将数据等改为uint64_t。在将这些修改过后,发现问题没有在flash擦除那里进行报错,而是在FLASH写入那里卡死。

HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST,addr,Data[i])!=HAL_OK

上述函数错误的地方是        FLASH_TYPEPROGRAM_FAST   ,因为其意思是32位写

Fast program a 32 row double-word (64-bit) at a specified address

但是手册给出是64位写,所以这里进行了报错,然后将这里改成下面函数,整个程序的读写就没有问题了,在此问题就得到了解决。

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,addr,Data[i])!=HAL_OK

以下则是G030F6P6单片机的FLASH的程序

读:

/*******************************************************************************
* Function Name  : 读取Flash数据
* Description    : Read packed message form flash
* Input          : buff:point to first location of received buffer.length:Maxmum length of reception
* Output         : 
* Return         : reception length
*******************************************************************************/
uint16_t Read_Flash( uint64_t *Data, uint16_t num, uint32_t addr)
{uint16_t i=0;uint32_t add=0;if(num == 0){return 0;}add = addr;i=0;while((add < FLASH_USER_END_ADDR1) && (i<num)){Data[i++] = *(__IO uint64_t *)add;add = add+8;}return i;
}

写:

/*******************************************************************************
* Function Name  : Flash写数据
* Description    : Write a group of datas to flash.
* Input          : buff:pointer of first data, length: write length
* Output         : 
* Return         : true/false
*******************************************************************************/
uint16_t Write_Flash( uint64_t *Data , uint16_t num, uint32_t add)
{uint16_t i=0;uint32_t addr=0;FLASH_EraseInitTypeDef EraseInitStruct={0};uint32_t PageError=0;//擦除错误地址EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;//仅擦除页EraseInitStruct.Banks = FLASH_BANK_1;EraseInitStruct.Page = 15;		//注:该page为0-15页EraseInitStruct.NbPages = 1;	//擦除一页HAL_FLASH_Unlock();HAL_FLASHEx_Erase(&EraseInitStruct,&PageError);if(PageError != 0xFFFFFFFF) {return 1;}addr = add;i=0;while((addr < FLASH_USER_END_ADDR1) && (i<num)){if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,addr,Data[i])!=HAL_OK){addr = addr + 8;}else{i++;}}HAL_FLASH_Lock();return 0;    
}

        在这里使用的是uint64_t进行数据的读写,但是如果用在其他程序,就会出现error。因为单片机是32位的出现uint64_t参与的函数就报错。

        在这里我写了一个简易的flash内存管理,因为我们在写flash数据的时候,往往很多数据,并不是单一数据,但是每写一次flash则需要进行flash擦除,我这里采用一个数组进行使用,如下:

实现原理:一次性读取一定数量的数据出来,将自己需要的数据修改过后,再讲修改后的数据全部写入,在实际项目中还是比较实用的。

读:

/*
*********************************************************************************************************
*	函 数 名:uint8_t data_read(uint16_t *data,uint16_t datalen,uint16_t save_addr,uint32_t bank_addr)
*	功能说明:数据读取
*	形    参:data 数据   datalen 长度   save_addr数组中保存的地址    bank_addr  地址
*	返 回 值:
*********************************************************************************************************
*/ 
uint8_t data_read(uint16_t *data,uint16_t datalen,uint16_t save_addr,uint32_t bank_addr) 
{uint64_t buf[READ_NUM]={0}; //根据实际数据量进行设置if(datalen == 0){return 1;}Read_Flash(buf,READ_NUM,bank_addr);  //读数据for(int i=0;i<datalen;i++)   //数据更新{data[i] = buf[save_addr+i];}return 0;
}

写:

/*
*********************************************************************************************************
*	函 数 名:uint8_t data_save(uint16_t *data,uint16_t datalen,uint16_t save_addr,uint32_t bank_addr) 
*	功能说明:数据保存
*	形    参:data 数据   datalen 长度   save_addr数组中保存的地址    bank_addr  地址
*	返 回 值:
*********************************************************************************************************
*/ 
uint8_t data_save(uint16_t *data,uint16_t datalen,uint16_t save_addr,uint32_t bank_addr) 
{uint64_t buf[READ_NUM]={0}; //根据实际数据量进行设置if(datalen == 0){return 1;}Read_Flash(buf,READ_NUM,bank_addr);  //读数据if(buf[0]==0xffffffff){for(int i=0;i<READ_NUM;i++){buf[i] = 1;}Write_Flash(buf,READ_NUM,bank_addr);  //写数据}for(int i=0;i<datalen;i++)   //数据更新{buf[save_addr+i] = data[i];}Write_Flash(buf,READ_NUM,bank_addr);  //写数据return 0;
}

其他宏定义相关代码:

//数组大小
#define READ_NUM	30
//地址
#define ADDR_FLASH_PAGE_0  	((uint32_t)0x08000000)   //第一页
#define ADDR_FLASH_PAGE(n) (ADDR_FLASH_PAGE_0 + (uint32_t)(n)*FLASH_PAGE_SIZE)#define FLASH_USER_PAGE_NUM		1
#define FLASH_USER_START_ADDR1  ADDR_FLASH_PAGE(16-1)
#define FLASH_USER_END_ADDR1    (FLASH_USER_START_ADDR1 + FLASH_USER_PAGE_NUM*FLASH_PAGE_SIZE)

基本上可以实现功能:主要的问题就是那个必须64位读写,不然数据就有问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/591755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Matlab】LSTM长短期记忆神经网络时序预测算法(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88688439 一&#xff0c;概述 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种常用的循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;结构&#xff0c;由于其对于…

java常见面试题:什么是泛型?泛型有哪些应用场景?

泛型是程序设计语言的一种特性&#xff0c;它允许程序员在强类型程序设计语言中编写代码时定义一些可变部分&#xff0c;那些部分在使用前必须作出指明。 泛型的应用场景主要包括以下几个方面&#xff1a; 集合类和数据结构&#xff1a;泛型最常见的用途是在集合类&#xff0…

ros2基础学习13 DDS 通信得学习

ROS2中最为重大的变化——DDS&#xff0c;我们在前边课程中学习的话题、服务、动作&#xff0c;他们底层通信的具体实现过程&#xff0c;都是靠DDS来完成的&#xff0c;它相当于是ROS机器人系统中的神经网络。 通信模型 DDS的核心是通信&#xff0c;能够实现通信的模型和软件框…

科技云报道:2024年六大科技趋势前瞻,最热门的技术都在这里了!

科技云报道原创。 物之生也&#xff0c;若骤若驰&#xff0c;无动而不变&#xff0c;无时而不移。 技术创新的步伐丝毫没有放缓的迹象&#xff0c;在这个日新月异的时代&#xff0c;科技创新在改变人们生活、推动社会进步方面扮演着关键的角色。2024年有望成为又一个开创性的…

不停止业务的情况下优化 Elasticsearch Reindex

在使用 Elasticsearch 时,我们总有需要修改索引映射的时候,这时我们只能进行 _reindex。事实上,这是一个相当昂贵的操作,因为根据数据量和分片数量,完整复制一个索引可能需要几个小时。 花费的时间不是大问题,但更严重的是,它会影响生产环境的性能甚至功能。 相信大家…

高效管理文件夹:使用重命名进行文件夹名称大小写转换的技巧

在计算机管理中&#xff0c;文件夹名称的大小写规范是一个经常被忽视的细节。然而&#xff0c;文件夹名称的大小写有时可能会影响工作流程&#xff0c;例如在某些文件搜索或识别过程中。掌握文件夹名称大小写转换的技巧&#xff0c;可以更高效地管理文件夹。现在一起来看看云炫…

yolov8 速度测试

yolov8 速度测试 T4显卡 1&#xff0c;1280 1280 yolov8x6 推理速度 Speed: 7.4ms preprocess, 156.8ms inference, 1.1ms postprocess per image at shape (1, 3, 960, 1280) 2.fp16打开 0: 960x1280 1 bj_bpmh, 159.6ms Speed: 7.5ms preprocess, 159.6ms inference, 1.2m…

分布式定时任务Xxl_Job详细使用手册

看了很多网上的版本&#xff0c;思路描述的都不是很清晰&#xff0c;都只是几步操作就完成了&#xff0c;看效果&#xff0c;导致容易走入弯路&#xff08;不排除是自己理解能力把&#xff09;&#xff0c;最开始以为是把admin模块集成到项目&#xff0c;后来测试了会&#xff…

我敢说,这是你必会的网络端口知识

下午好&#xff0c;我的网工朋友&#xff0c;新年快乐&#xff01; 端口是计算机网络技术中非常基础的概念&#xff0c;不管是网络实施、运维、还是软件开发&#xff0c;总是能听到端口二字。 理论上来说&#xff0c;端口数最多可以有65535个。 端口概念在网络技术中&#x…

结构体的一些小技巧

有一天在写洛谷的一道题的时候&#xff0c;我想出来大概思路&#xff0c;但是有几步我想破头也无法实现。 后来看了题解&#xff0c;发现原来结构体可以这样使用。 比如&#xff0c;现在有一个结构体&#xff1a; struct person {char gender;int age, high, height; };它表…

【WPF.NET开发】弱事件模式

本文内容 先决条件为什么要实现弱事件模式&#xff1f;应该由谁实现弱事件模式&#xff1f;如何实现弱事件模式 在应用程序中&#xff0c;附加到事件源的处理程序可能不会与将处理程序附加到源的侦听器对象一同销毁。 这种情况下会导致内存泄漏。 Windows Presentation Found…

DDoS 攻击并不是全部来自于PC组成的僵尸网络

DDoS&#xff0c;分布式拒绝服务攻击&#xff0c;是指处于不同位置的多个攻击者同时向一个或数个目标发动攻击&#xff0c;或者一个攻击者控制了位于不同位置的多台机器并利用这些机器对受害者同时实施攻击。很多人会以为DDoS 攻击&#xff0c;全都是攻击者控制PC肉鸡发起的攻击…

ELF文件信息一览

准备开个专栏&#xff0c;记录《从零开始实现链接器》的学习过程&#xff0c;先占个坑。 之前一直想把自己的学习过程记录在个人博客网站上&#xff0c;但这个要自己维护&#xff0c;上传图片什么的比较麻烦。关键是没有人互动&#xff0c;自己也没有怎么去看&#xff0c;慢慢的…

柯桥专业会计学校之相关财税知识,2023年新版增值税税率表

一、增值税税率 一般纳税人增值税税率&#xff1a;13%&#xff0c;9%&#xff0c;6%&#xff0c;0%&#xff0c;都适用于哪些项目&#xff1f;我们具体来看&#xff1a;&#xff08;目前小规模纳税人3%征收率减按1%执行&#xff09; 二、扣除率 扣除率是指增值税计征中法定扣除…

什么是DDOS 攻击?常见的DDOS攻击有哪些?

什么是DDoS攻击&#xff1f; DDoS攻击&#xff08;分布式拒绝服务攻击&#xff09;是一种旨在使计算机或网络资源不可用的恶意尝试。它通过使用多个受感染计算机&#xff08;称为僵尸网络&#xff09;同时向目标发送大量流量来实现这一目的&#xff0c;从而使目标不堪重负并崩溃…

【Bootstrap学习 day7】

Bootstrap按钮 按钮样式 使用.btn相关类实现 <button type"button" class"btn">基本按钮</button> <button type"button" class"btn btn-primary">主要按钮</button> <button type"button" cl…

【数据结构-单链表】(C语言版本)

今天分享的是数据结构有关单链表的操作和实践&#xff08;图解法&#xff0c;图变化更利于理解&#xff09; 记录宗旨&#x1f4dd;&#xff1a; 眼&#xff08;脑&#xff09;过千遍&#xff0c;不如手过一遍。 我们都知道单链表是一种常见的链表数据结构&#xff0c;由一系列…

【大数据】修复 Linux 错误 - 内存不足

修复 Linux 错误 - 内存不足 在使用 Linux 操作系统时,您可能会遇到内存不足的错误。这种错误通常会导致系统运行缓慢或崩溃。本文将介绍如何识别和修复 Linux 中的内存不足问题。 1. 检查内存使用情况 首先,您需要检查系统的内存使用情况。可以使用以下命令来查看当前内存…

【Java进阶篇】String中 intern 的原理是什么?

String中 intern 的原理 ✔️ 典型解析✔️小思考&#xff08;回顾&#xff09; ✔️字面量✔️intern✔️ intern原理✔️a和1有什么不同✔️答案 ✔️ 典型解析 字符串常量池中的常量有两种来源&#xff1a; 1、 字面量会在编译期先进入到Class常量池&#xff0c;然后再在运行…

配置ssh免密登录

1、cd ~ cd .ssh 输入ssh-keygen -t rsa 敲三次回车 [rootcdh-hadoop3 .ssh]# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase…