片上flash在一些低成本产品上使用居多,不过唯一要注意的的是,在存储瞬间,芯片不能掉电,否则单片机就会崩溃,需要重新格式化芯片,再次进行重刷代码。当然该问题不仅是单片机flash上面有,小可不才,在w25qxxflash以及AT45DBXX芯片上都出现过该问题,只是外部flash只是读取不到数据,解决方式还是格式化flash。
本次使用的芯片是stmxxxxxCBT6,工程是stm32cubemx生成的工程。.c代码如下:
#include "flash.h"
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_OPERR | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR | \
FLASH_FLAG_PGAERR | FLASH_FLAG_SIZERR | FLASH_FLAG_PGSERR | \
FLASH_FLAG_MISERR | FLASH_FLAG_FASTERR | \
FLASH_FLAG_OPTVERR | FLASH_FLAG_ECCC | FLASH_FLAG_ECCD)
uint16_t t;
u64 WriteData;
//ADD:0-200 存储200个系统关键数据
static u8 Flash_ReadBuffer[32];
static u8 Flash_WriteBuffer[32];
u16 SumFan;//校验和
//读取FLASH内内容到数组
void Flash_Read(uint32_t Addr,uint8_t *Buffer,uint16_t Length)
{
uint8_t *wAddr;
wAddr=(uint8_t *)(Addr);
while(Length--)
{
*Buffer++=*wAddr++;
}
}
//写入4个字节的数据到FLASH
HAL_StatusTypeDef flash_write_4Byte(uint32_t address, uint64_t data)
{
HAL_StatusTypeDef ret = HAL_OK;
HAL_FLASH_Unlock();
ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address , data);
HAL_FLASH_Lock();
return ret;
}
//写数组到FLASH
//数组必须为4个倍数
void flash_write(uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
{
//uint16_t t;
HAL_FLASH_Unlock();
// u64 WriteData;
for(t = 0;t < (NumToWrite/8);t++)
{
WriteData = 0;
for(int8_t i = 7; i >= 0; i--)
{
WriteData <<= 8;
WriteData |= pBuffer[t*8+i];
}
// WriteData = *(__IO uint64_t *)(&WriteData);//4byte 0x1FFF7590UL
//WriteData = 0x123445789abcedf;
// + (uint64_t)pBuffer[t*8+7]<<56) ) ;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,WriteAddr + t*8,WriteData);
}
HAL_FLASH_Lock();
}
///**
// * @brief Gets the page of a given address
// * @param Addr: Address of the FLASH Memory
// * @retval The page of a given address
// */
//static uint32_t GetPage(uint32_t Addr)
//{
// return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;;
//}
void flash_page_erase(uint32_t page)
{
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY) != 0x00U)
{
*(uint32_t *)(Flash_Page63_StartAddr+240) = 12323;//flash随意写入一个值,使flash触发错误
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS) ;
}
HAL_StatusTypeDef test = HAL_FLASH_Unlock();
test = FLASH_WaitForLastOperation(1000); //1s timeout
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
FLASH_PageErase(FLASH_BANK_1,page);
test = FLASH_WaitForLastOperation(1000);
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
HAL_FLASH_Lock();
}
//写参数
void Writedatatoeeprom(void)
{
u8 i,j,error;
u16 Keepdata[11];
Keepdata[0] = xxxxxxxxxx; // 在开辟的空间存数据 先定义11个u16数组
Keepdata[1] = 2; // 依次在这里存入1 、2、3....11,最大到31
Keepdata[2] =3;
Keepdata[3] = 4;
Keepdata[5] = 6;
Keepdata[6] =7;
Keepdata[7] = 8;
Keepdata[8] =9;
Keepdata[9] =10;
Keepdata[10] =11;
//发送数据缓冲区清零
for(i=0; i<32; i++)
{
Flash_WriteBuffer[i] =0;
}
//分解数据,因为数据存储类型是u8,所以需要将u16数组转化为u8,高八位低八位依次存储
for(i=0; i<11; i++)
{
Flash_WriteBuffer[i*2+0] =(u8)(Keepdata[i]/256);
Flash_WriteBuffer[i*2+1] =(u8)(Keepdata[i]%256);
}
//计算校验和
SumFan = 0;
for(i=0; i<30; i++)
{
SumFan = SumFan + Flash_WriteBuffer[i];
}
SumFan = 65535 - SumFan;
Flash_WriteBuffer[30] =(u8)(SumFan/256);
Flash_WriteBuffer[31] =(u8)(SumFan%256);
//存3次数据
for(i=0; i<3; i++)
{
error = 0;
flash_page_erase(63);
flash_write(Flash_Page63_StartAddr,Flash_WriteBuffer,32);
Flash_Read(Flash_Page63_StartAddr,Flash_ReadBuffer,32);
for(j=0; j<32; j++)
{
if(Flash_WriteBuffer[i] != Flash_ReadBuffer[i]) error = error + 1;
}
if(error==0)break;
}
//说明写入失败
if(i>=3)
{
i=0;
}
}
//读参数
void Readdatatoeeprom(void)
{
u8 i;
//u16 Restdata[200];
//读取数据
Flash_Read(Flash_Page63_StartAddr,Flash_ReadBuffer,32);
//计算校验和
SumFan = 0;
for(i=0; i<30; i++)
{
SumFan = SumFan + Flash_ReadBuffer[i];
}
SumFan = 65535 - SumFan;
//判断校验和是否正确
if((Flash_ReadBuffer[30] == (u8)(SumFan/256))&&(Flash_ReadBuffer[31] == (u8)(SumFan%256)))
{
xxxxxxxxxxxxx = Flash_ReadBuffer[0]*256 + Ex_Flash_ReadBuffer[1];
//这里为读取到的数组,读取到的数组为u8,依次转化为刚存入的
}
//校验和错误,给出默认数据并写入
else
{
xxxxxxx= 0;
Writedatatoeeprom();
}
}
上述代码为片上内存存储和读取源代码。c文件。与之对应的还有H文件。h文件代码如下:
#ifndef __FLASH_H
#define __FLASH_H
#include "core_cm0plus.h"
//总共128K
//FLASH_BANK_1: 前64K
//FLASH_BANK_2: 后64K
#define Flash_Page60_StartAddr 0x0801e000
#define Flash_Page61_StartAddr 0x0801e800
#define Flash_Page62_StartAddr 0x0801f000
#define Flash_Page63_StartAddr 0x0801f800
extern void Readdatatoeeprom(void);
extern void Writedatatoeeprom(void);
#endif
依据.h文件,不难看出,使用片上存储空间存储数据时,不需要进行硬件资源上的初始化,也没有软件上的外设资源初始化。只需要直接调用写,和读两个指令。