【举报再看养成习惯,噢 不对,点赞再看 养成习惯。感谢支持】
STM32的Flash操作分为读写:读写。
一、读操作
读取比较简单,直接指针解引用地址就可以读取。注意一下读取的单位即可
/*************************************************************
** Function name: STMFLASH_ReadWord
** Descriptions: 读操作
** Input parameters: 要读取的地址
** Output parameters: None
** Returned value: None
** Remarks: None
*************************************************************/
uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
return *(uint32_t*)faddr;
}
/*************************************************************
** Function name: STMFLASH_Read
** Descriptions: 连续读取操作
** Input parameters: NumToRead 要读取的数据个数,单位为uint32
** Output parameters: None
** Returned value: None
** Remarks: None
*************************************************************/
void STMFLASH_Read(uint32_t ReadAddr, uint32_t *pBuffer, uint32_t NumToRead)
{
uint32_t i;
for(i = 0; i < NumToRead; i++)
{
pBuffer[i]=STMFLASH_ReadWord(ReadAddr); //读取4个字节.
ReadAddr+=4; //偏移4个字节.
}
}
二、写操作
注意事项:写操作之前需要先对扇区进行擦除,以STM32G030F6举例,打开JFlash可以看到芯片的具体分区,2K为一个扇区,一共16个扇区。
?所以之后我们擦除的时候每次就要擦除2K数据。接下来看代码
// G030F6P6 Flash共计32K 16个扇区 计划使用后后两个扇区,即4K存储数据 ,单次最小擦除2K数据?有待确定
#define FLASH_SECTOR14_START 0x08007000
#define FLASH_SECTOR14_END 0x080077FF
#define FLASH_SECTOR15_START 0x08007800
#define FLASH_SECTOR15_END 0x08007FFF
#define FLASH_DATA_ADDR_MIN FLASH_SECTOR14_START
#define FLASH_DATA_ADDR_MAX FLASH_SECTOR15_END
#define FLASH_DATA_ADDR_BASE FLASH_DATA_ADDR_MIN
#define CALIBRATION_L_LR_VALUE_ADDR FLASH_DATA_ADDR_BASE+0
#define CALIBRATION_L_UD_VALUE_ADDR FLASH_DATA_ADDR_BASE+12
#define CALIBRATION_R_LR_VALUE_ADDR FLASH_DATA_ADDR_BASE+24
#define CALIBRATION_R_UD_VALUE_ADDR FLASH_DATA_ADDR_BASE+36
#define FLASH_WAITETIME 1000
// bind addr长度为5字节 实际占用2个uint32
#define BIND_MSG_BASE FLASH_SECTOR15_START
#define BIND_ADDR BIND_MSG_BASE+0
/*************************************************************
** Function name: STM32G0_GetFlashSector
** Descriptions: 获取G030芯片中addr所在的扇区
** Input parameters: None
** Output parameters: None
** Returned value: None
** Remarks: None
*************************************************************/
uint8_t STM32G0_GetFlashSector(uint32_t addr){
if (addr >= FLASH_SECTOR14_START && addr <= FLASH_SECTOR14_END){
return 14;
}else if (addr >= FLASH_SECTOR15_START && addr <= FLASH_SECTOR15_END){
return 15;
}
return 16;
}
/*************************************************************
** Function name: STMFLASH_Write
** Descriptions: STM32写操作
** Input parameters: pBuffer 传入需要存储的指针、 NumToWrite 需要写入的字节数量/8(单次最少写入双字大小 8字节)
** Output parameters: None
** Returned value: None
** Remarks: None
*************************************************************/
void STMFLASH_Write(uint32_t WriteAddr, uint32_t *pBuffer, uint32_t NumToWrite)
{
FLASH_EraseInitTypeDef FlashEraseInit;
HAL_StatusTypeDef FlashStatus = HAL_OK;
uint32_t PageError = 0;
uint32_t addrx = 0;
uint32_t endaddr = 0;
if(WriteAddr < FLASH_DATA_ADDR_MIN || WriteAddr % 4) return; //非法地址 禁止写入的范围
HAL_FLASH_Unlock(); //解锁
addrx = WriteAddr; //写入的起始地址
endaddr = WriteAddr + NumToWrite * 8; //写入的结束地址
if(addrx < FLASH_DATA_ADDR_MAX)
{
while(addrx < endaddr) //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
{
if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF) //有非0XFFFFFFFF的地方,要擦除这个扇区
{
FlashEraseInit.TypeErase = FLASH_TYPEERASE_PAGES; //擦除类型,页擦除
FlashEraseInit.Page = STM32G0_GetFlashSector(addrx); //从哪页开始擦除
FlashEraseInit.NbPages = 1; //一次只擦除一页
SEGGER_RTT_printf(0,"Flash Erase page is %d\r\n",FlashEraseInit.Page);
if(HAL_FLASHEx_Erase(&FlashEraseInit, &PageError) != HAL_OK)
{
SEGGER_RTT_printf(0,"Flash Erase err\r\n");
break; //发生错误了
}
FLASH_WaitForLastOperation(FLASH_WAITETIME); //等待上次操作完成
}else {
addrx += 4;
}
}
}
FlashStatus = FLASH_WaitForLastOperation(FLASH_WAITETIME); //等待上次操作完成
if(FlashStatus == HAL_OK)
{
while(WriteAddr < endaddr) //写数据
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, WriteAddr, *(uint64_t*)pBuffer) != HAL_OK)//写入数据
{
break; //写入异常
}
WriteAddr += 8; //地址加8
pBuffer += 2; //buff传进来的是32位的,所以这里+2 便是8个字节
}
SEGGER_RTT_printf(0,"Flash write ok\r\n");
}
FLASH_WaitForLastOperation(FLASH_WAITETIME); //等待上次操作完成
HAL_FLASH_Lock(); //上锁
}
STM32G0_GetFlashSector函数可以获取输入地址在芯片的那个扇区,需要根据具体的芯片信息来更改。
STMFLASH_Write函数主要注意存储数据大小,函数注释中写了。要根据不同的芯片的Program函数来更改。
注意这里贴出的函数只能进行一些简单的存储操作,如果往同一个扇区的不同地方写入数据,第一次会写入成功,第二次会失败。函数中下图圈起来的地方应该检测要写入的扇区所有的地址才对,这里只检测了起始地址到结束地址的数据。如果写入数据在同一个扇区,但是不在同一个位置就会出现BUG。写入失败
?
|