STM32f030f4p6 内部flash 打包读写
最近做到的项目在运行需要把一组uint8_t(unsigned char)的数据进行掉电储存,想到单片机STM32f030f4p6内部flash可以直接由程序操作,写了以下代码用于uint8_t数据打包保存和读取。
1、程序清单 与 测试结果
本程序包含5个文件,分别是:
1、Flash.c:内部flash读取储存相关函数
2、Flash.h:flash头文件
3、USART1.c:STM32F030F4P6的串口驱动,串口仅用于打印数据观察。
4、USART1.h:串口头文件
5、main.c:防止程序主入口
1、Flash.c
#include "Flash.h" #include "USART1.h"
/*******************************************************************************
* Function Name : doseFlashHasPackedMessage
* Description : Does flash has packed messages
* Input : None
* Output :
* Return : ture/false
*******************************************************************************/
bool doseFlashHasPackedMessage(void)
{
uint16_t length;
uint16_t getHead; /*Is head matched*/
getHead = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR ));
if( EEPPROM_PACKAGEHEAD != getHead )
{
return false;
} /*Is length zero*/
length = (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+));
if( == length)
{
return false;
} return true;
}
/*******************************************************************************
* Function Name : getValuablePackedMessageLengthofFlash
* Description : Get valuable packed message length of flash
* Input : None
* Output :
* Return : valuable length
*******************************************************************************/
uint16_t getValuablePackedMessageLengthofFlash( void )
{
uint16_t length; /*Is head matched*/
if( EEPPROM_PACKAGEHEAD != (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR )) )
{
return ;
} /*Get length*/
length = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+)); return length;
}
/*******************************************************************************
* Function Name : readPackedMessageFromFlash
* 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 readPackedMessageFromFlash( uint8_t *buff , uint16_t length)
{
int i;
uint16_t getLength; if( !doseFlashHasPackedMessage() )
return ; /*Get valuable length*/
getLength = getValuablePackedMessageLengthofFlash(); /*Read out message*/
for(i=;i<MIN(getLength,length);i++)
{
buff[i]= *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR++i);
} return MIN(getLength,length);
}
/*******************************************************************************
* Function Name : isItOddNumber
* Description : is input data an odd number?
* Input : number:input data
* Output :
* Return : true/false
*******************************************************************************/
bool isItOddNumber(uint16_t number)
{
if( != number%)
{
return true;
}
return false;
}
/*******************************************************************************
* Function Name : Flash_eeprom_WriteWithPacked
* Description : Write a group of datas to flash.
* Input : buff:pointer of first data, length: write length
* Output :
* Return : true/false
*******************************************************************************/
bool writeMessageToFlash( uint8_t *buff , uint16_t length)
{
uint16_t temp;
int i; /*Protection*/
if( (length+) > STM32F0xx_PAGE_SIZE )
{
return false;
} FLASH_Unlock( ); /*Clear all flags*/
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR ); /*Erase first . Do not rember.*/
if(FLASH_COMPLETE != FLASH_ErasePage(STM32F0xx_FLASH_PAGE15_STARTADDR))//°üº¬Á˵ȴýbusy
{
return false;
} /*Write head*/
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR, EEPPROM_PACKAGEHEAD );
/*Write length*/
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR+ , length ); /*Write datas*/
for(i= ;i<length/ ;i++)
{
temp = buff[*i]|(uint16_t)buff[*i+]<<;
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR++*i , temp);
}
if( isItOddNumber(length) )//Write one more if length is odd number.
{
temp = (uint16_t)buff[length-];
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR++(length-) , temp);
} /*Read out and check*/
for(i= ;i<length ;i++)
{
if( *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR++i) != buff[i] )
{
FLASH_Lock();
return false;
}
} FLASH_Lock();
return true;
} /*******************************************************************************
* Function Name : flashReadWriteTest
* Description : Flash read write test.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void flashReadWriteTest( void )
{
#define testReadWriteNumber 200
uint8_t buff_write[testReadWriteNumber]={};
uint8_t buff_read[testReadWriteNumber]={};
uint16_t length;
int i; for( i=;i<testReadWriteNumber;i++)
{
buff_write[i]=i;
} writeMessageToFlash( buff_write , testReadWriteNumber);
length = readPackedMessageFromFlash( buff_read , testReadWriteNumber);
printf("length=%d\r\n",length);
for(i=;i<length;i++)
{
printf("read[%d]=%d\r\n",i,buff_read[i]);
} while();
}
2、Flash.h
#ifndef __FLASH_H
#define __FLASH_H #include "stm32f0xx.h"
#include <stdbool.h> //Message head
#define EEPPROM_PACKAGEHEAD 0xAA55// //Flash page head
#define STM32F0xx_PAGE_SIZE 0x400
#define STM32F0xx_FLASH_PAGE0_STARTADDR 0x8000000
#define STM32F0xx_FLASH_PAGE1_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE2_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+2*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE3_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+3*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE4_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+4*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE5_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+5*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE6_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+6*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE7_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+7*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE8_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+8*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE9_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+9*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE10_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+10*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE11_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+11*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE12_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+12*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE13_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+13*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE14_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+14*STM32F0xx_PAGE_SIZE)
#define STM32F0xx_FLASH_PAGE15_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+15*STM32F0xx_PAGE_SIZE) #define MIN(A,B) (A<B?A:B) void flashReadWriteTest( void ) ; #endif
3、USART1.c
#include "USART1.h" void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE); } void USART1_IRQHandler(void)
{ } /**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch); /* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{} return ch;
}
4、USART1.h
#ifndef __BSP_USART1_H
#define __BSP_USART1_H #include "stm32f0xx.h"
#include <stdio.h> #ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */ void USART1_Init(void); #endif
5、main.c
#include "stm32f0xx.h"
#include "USART1.h"
#include "Flash.h"
int main(void)
{
USART1_Init();
flashReadWriteTest();
while()
{
}
}
测试结果:
第54-199省略..
2、程序详解
2.1、内存结构:
STM32F0xx的flash结构如下:最多具有64页,每页1KByte大小。
我使用的STM32F030F4P6 flash区域有16K,所以实际上只有0-15页,本程序中把需要保存的数据数据存放在最后一页(第15页)中。
2.2、定义数据包结构
为了保证储存和读出flash的数据是正确的,本程序将写入flash数据分为3个区域
- 报头区:写入数据的时候,将第15页的第1、2字节写入0xaa55,在读出的时候如果此位置不是0xaa55,则表示这段数据数据无效,不是由自己存入的数据或者程序出现了异常;
- 长度:写入数据的时候,第15页的第3、4字节写入有效数据的长度,读出这个字段,就知道上次自己一共存入了多少数据;
- 数据段:从第15页的第5字节开始,全部字节(1020byte)用于储存uint8_t类型的数据;
2.3、写操作
写操作有如下步骤:
- 保护:由于我们只有1Kbyte空间,出去4个字节的报头和长度,实际只能存储1020个u8类型,写太多返回失败。
- 解flash锁
- 页擦除
- 写入数据包
- 上锁
/*******************************************************************************
* Function Name : Flash_eeprom_WriteWithPacked
* Description : Write a group of datas to flash.
* Input : buff:pointer of first data, length: write length
* Output :
* Return : true/false
*******************************************************************************/
bool writeMessageToFlash( uint8_t *buff , uint16_t length)
{
uint16_t temp;
int i; /*Protection*/
if( (length+) > STM32F0xx_PAGE_SIZE )
{
return false;
} FLASH_Unlock( ); /*Clear all flags*/
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR ); /*Erase first . Do not rember.*/
if(FLASH_COMPLETE != FLASH_ErasePage(STM32F0xx_FLASH_PAGE15_STARTADDR))//°üº¬Á˵ȴýbusy
{
return false;
} /*Write head*/
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR, EEPPROM_PACKAGEHEAD );
/*Write length*/
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR+ , length ); /*Write datas*/
for(i= ;i<length/ ;i++)
{
temp = buff[*i]|(uint16_t)buff[*i+]<<;
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR++*i , temp);
}
if( isItOddNumber(length) )//Write one more if length is odd number.
{
temp = (uint16_t)buff[length-];
FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR++(length-) , temp);
} /*Read out and check*/
for(i= ;i<length ;i++)
{
if( *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR++i) != buff[i] )
{
FLASH_Lock();
return false;
}
} FLASH_Lock();
return true;
}
2.3.1、解锁操作:
用户手册描述如下:
在(芯片)重置过后,为了防止多余的擦写操作flash会被保护。除了OBL_LAUNCH位用于重载option bit,FLASH_CR寄存器的其他部分都不可以访问。
需要把以下两个解锁序列写入FLASH_KEY寄存器,才能访问FLASH_CR:
- 0x45670123
- 0xCDEF89AB
检索官方库定位FLASH_Unlock()这个函数,它的底层实现与文档描述相符,另外增加了防止重复解锁的操作,直接使用FLASH_Unlock()这个函数即可以完成解锁。
2.3.2、页擦除
用户手册描述如下:
1、通过检查FLASH_SR寄存器的BSY位来确认flash没有使用
2、把FLASH_CR寄存器的PER位置SET
3、通过编写FLASH_AR寄存器来确认要擦除的页
4、将FLASH_CR寄存器的STRT位置SET
5、等待BSY位rst
6、检查FLASH_SR寄存器中的EOP标记(成功会置SET)(流程图没有、库函数没检查)
7、清除EOP标记(流程图没有、库函数没清除)
检索官方库定位到FLASH_ErasePage(uint32_t Page_Address)这个函数,它的底层实现与文档流程图描述相符,值得注意的是,手册描述中6、7步并没有出现在手册的流程图和库函数中(库版本V1.2.0)。但在使用中没有出现问题,这里先记录看以后使用中会不会出现问题
2.3.3、往flash中写入数据
用户手册描述如下
1、通过检查FLASH_SR寄存器的BSY位来确认flash没有使用
2、设置FLASH_CR寄存器的PG位
3、在目标地址上写入半个word的数据
4、等BSY位reset
5、检查FLASH_SR寄存器的EOP标记(SET表示成功)(流程图没有出现、库函数中没检查)
检索官方库定位到FLASH_ErasePage(uint32_t Page_Address)这个函数,它的底层实现与文档流程图描述相符,同样地,库函数没有检查第五步的EOP标记
2.3.4、上锁操作
根据手册提示,定位到库函数void FLASH_Lock(void)。只要置位LOCK位就上锁了。
2.4、读操作
程序如下
/*******************************************************************************
* Function Name : readPackedMessageFromFlash
* 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 readPackedMessageFromFlash( uint8_t *buff , uint16_t length)
{
int i;
uint16_t getLength; if( !doseFlashHasPackedMessage() )
return ; /*Get valuable length*/
getLength = getValuablePackedMessageLengthofFlash(); /*Read out message*/
for(i=;i<MIN(getLength,length);i++)
{
buff[i]= *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR++i);
} return MIN(getLength,length);
}
根据用户手册提示,读操作是可以直接取址的,所以读操作实际只有如下一句只要用uint8_t类型取出目标地址再取值就可以了。
但是,我们的数据是打包的(详见2.2),所以还需要:
1、根据报头判断是不是有效数据
2、根据长度判断要读取多少数据
3、最后才是读出数据
2.4.1、判断数据有效性:
我们通过报头来判断数据是不是自己写入的。
也就是判断flash第15页的第1、2个字节是不是0xaa55,如果不是,那这段数据是无效的。
另外再判断一下长度字段,如果长度等于0,也就是后面没有数据,那这段数据也是无效的。
/*******************************************************************************
* Function Name : doseFlashHasPackedMessage
* Description : Does flash has packed messages
* Input : None
* Output :
* Return : ture/false
*******************************************************************************/
bool doseFlashHasPackedMessage(void)
{
uint16_t length;
uint16_t getHead; /*Is head matched*/
getHead = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR ));
if( EEPPROM_PACKAGEHEAD != getHead )
{
return false;
} /*Is length zero*/
length = (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+));
if( == length)
{
return false;
} return true;
}
2.4.2、根据长度读出数据:
在读Flash程序中,getLength是从flash中读出的长度,length是我们指定的最大读取长度。如果getLength大于我们指定读取长度,很可能会造成溢出,所以两者取小的一个防止溢出。
到此为止程序写完了,要是有什么错误或不足的地方还望各位大佬指出,要是使用中出现什么BUG也希望大家回来反馈一下,十分感谢
STM32f030f4p6 内部flash 打包读写的更多相关文章
- STM32 内部flash的读写程序
/* Base address of the Flash sectors */ #define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base ...
- STM32 实现内部Flash的读写(HAL库版)
Flash 中文名字叫闪存,是一种长寿命的非易失性(断电数据不丢失)的存储器.可以对称为块的存储器单元块进行擦写和再编程,在进行写入操作之前必须先执行擦除.一个Nand Flash由多个块(Block ...
- 第50章 读写内部FLASH—零死角玩转STM32-F429系列
第50章 读写内部FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...
- STM32F103使用内部Flash保存参数
在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数.这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能.将这类数据存在指定的 ...
- STM32F4读写内部FLASH【使用库函数】
STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多.平时写的代码,烧写完之后还有大量的剩余.有效利用这剩余的FLASH能存储不少数据.因此研究了一下S ...
- STM32 对内部FLASH读写接口函数(转)
源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...
- STM32学习笔记:读写内部Flash(介绍+附代码)
一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...
- [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写
一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...
- STM32 对内部FLASH读写接口函数
因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. 原理:先要把整页FLASH的内容搬到RAM中 ...
随机推荐
- AngularJS进阶(二十三)ANGULAR三宗罪之版本陷阱
ANGULAR三宗罪之版本陷阱 坑!碰到个大坑,前面由于绑定日期时将angular版本换为angular-1.3.0-beta.1时,后来午睡后,登录系统,发现无论如何都登陆不进去了,经过调试,发现数 ...
- 供应商信息全SQL
SELECT hou.name, pv.vendor_name 供应商, pv.party_id, pvs.vendor_site_id, pvs.terms_id, pv.vendor_name_a ...
- Cocos2D的随机数生成函数
有很多种方法生成随机数.但是只有arc4random函数生成的最接近于"真随机(truly random)"数.(而且不需要种子) 其变体函数arc4random_uniform生 ...
- android wheelview实现三级城市选择
很早之前看淘宝就有了ios那种的城市选择控件,当时也看到网友有分享,不过那个写的很烂,后来(大概是去年吧),我们公司有这么一个项目,当时用的还是网上比较流行的那个黑框的那个,感觉特别的丑,然后我在那个 ...
- gtk+2.0中GtkObject结构中没有klass成员的解决办法
gtk+2.0中一些较老的程序中会有如下的代码: #define EVENT_METHOD(obj, method) GTK_WIDGET_CLASS(GTK_OBJECT(obj)->klas ...
- Hadoop RPC
hadoop rpc机制 && 将avro引入hadoop rpc机制初探 1 RPC RPC(Remote Procedure Call)--远程过程调用,它是一种通过网络从远程计算 ...
- Android Studio 错误 Duplicate files copied in APK META-INF/LICENSE.txt解决方案
My logcat: log Execution failed for task ':Prog:packageDebug'. Duplicate files copied in APK META-IN ...
- SharePoint 添加BCD菜单
前言:在SharePoint中,我们常见的操作就是添加我们的自定义BCD菜单,下面,简单介绍下添加自定义BCD菜单的操作.主要介绍两种熟悉的方法,一种通过xml方式,另一种是通过js的方式. 环境:S ...
- MaterialDesign学习项目
概述 该项目主要用来学习Material Design Support Library和一些android其他技术,也借鉴了网上一些其他优秀的学习资源.该项目目前主要分为俩大部分(后期可能会有一些增加 ...
- 关于gcc的一点小人性化提示
现在对于大多数平台的C编译器来说都会有很多种选择,而gcc和clang无疑是2个非常优秀的C编译器.当然他们也不只是C编译器.我最近用clang的比较多,原因有很多.不过一些小的细节很让我喜欢,比如O ...