最近选型使用STM32G030这款芯片,由于做的功能需要频繁读写flash,最开始没有注意到芯片的擦写次数是1000次,为了确保功能实现,只能是每次写入flash时判断当前页是否写满,写满才擦除重新开始写;
每次需要写入flash的数据长度小于128字节,以128字节计算,每一页可以写入16=2048/128 次; STM32G030C8T6最少可以写入16000次;如果对写入次数需求高的,可以减少每次写入数据的长度;
STM32G030C8T6写入特性参考:stm32g030 内部flash存储一些用户数据的方法 - 简书
stm32F103
可编程flash区,以页为单位,每页1K,共128页, 擦写次数>1万次;
写入以16位“半字”为最小单位,擦除以页为单位;
先解锁,清标志,擦除,写,上锁;
进行flash操作时,必须打开内部HSI;
stm32G030
用时 \/
64-bit program 85~125us;
32 Double word program X ms
page(2k) program X ms
bank(64k) program X s
page(2k) erase 40ms
Mass erase X ms
擦写次数 仅>= 1K次!!! 需考虑坏页情况;
写数据时,一般建议关闭所有中断!
stm32g030 双字写时,不仅要求是双字形式, 而且要求8字节对齐。 否则进入硬件错误!
测试部分代码:
//从指定地址开始写入指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:写入数据长度
void STMFLASH_Write_64(u32 WriteAddr,u8*pBuffer,u16 NumToWrite)
{
u16 i;
u64 data_write;
u16 len =NumToWrite;
u8 len_flag=0;
if(NumToWrite>FLASH_PAGE_SIZE)return;
if( (WriteAddr<FLASH_BASE) ||(WriteAddr>=(FLASH_BASE+FLASH_PAGE_SIZE*FLASH_PAGE_NB)))return;//非法地址
HAL_FLASH_Unlock(); //解锁
len_flag=len%8;
len=len+get_rem_data(len_flag); //数据长度8字节对齐判断
if(WriteAddr%FLASH_PAGE_SIZE==0) //写满了从一页开始地址写需要擦除
{
FLASH_EraseInitTypeDef My_Flash={0}; //声明 FLASH_EraseInitTypeDef 结构体为 My_Flash
My_Flash.TypeErase = FLASH_TYPEERASE_PAGES; //标明Flash执行页面只做擦除操作
My_Flash.Page = (WriteAddr - FLASH_BASE) / FLASH_PAGE_SIZE;
My_Flash.NbPages = 1; //说明要擦除的页数,此参数必须是Min_Data = 1和Max_Data =(最大页数-初始页的值)之间的值
uint32_t PageError = 0; //设置PageError,如果出现错误这个变量会被设置为出错的FLASH地址
HAL_FLASHEx_Erase(&My_Flash, &PageError); //调用擦除函数擦除
}
for(i=0;i<len/8;i++)//复制 //8字节数据对齐组包
{
u32 data_1=0;
u64 data_2=0;
data_1=(pBuffer[8*i+0])|(pBuffer[8*i+1]<<8)|(pBuffer[8*i+2]<<16)|(pBuffer[8*i+3]<<24); //
data_2=(pBuffer[8*i+4])|(pBuffer[8*i+5]<<8)|(pBuffer[8*i+6]<<16)|(pBuffer[8*i+7]<<24);
data_write= data_1| (data_2<<32);
if( HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,WriteAddr,data_write) == HAL_OK)
WriteAddr+=8;//地址增加2.
}
HAL_FLASH_Lock(); //上锁
}
u8 get_rem_data(u8 data) //长度判断
{
u8 re_data=0;
switch (data)
{
case 0: re_data=0; break;
case 1: re_data=7; break;
case 2: re_data=6; break;
case 3: re_data=5; break;
case 4: re_data=4; break;
case 5: re_data=3; break;
case 6: re_data=2; break;
case 7: re_data=1; break;
}
return re_data;
}
void stm32_FLASH_ErasePage(u32 WriteAddr) //擦除
{
if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+FLASH_PAGE_SIZE*FLASH_PAGE_NB)))return;//非法地址
HAL_FLASH_Unlock(); //解锁
if(WriteAddr%FLASH_PAGE_SIZE==0)
{
// FLASH_PageErase(WriteAddr);//擦除这个扇区
FLASH_EraseInitTypeDef My_Flash={0}; //声明 FLASH_EraseInitTypeDef 结构体为 My_Flash
My_Flash.TypeErase = FLASH_TYPEERASE_PAGES; //标明Flash执行页面只做擦除操作
My_Flash.Page = (WriteAddr - FLASH_BASE) / FLASH_PAGE_SIZE;
My_Flash.NbPages = 1; //说明要擦除的页数,此参数必须是Min_Data = 1和Max_Data =(最大页数-初始页的值)之间的值
uint32_t PageError = 0; //设置PageError,如果出现错误这个变量会被设置为出错的FLASH地址
HAL_FLASHEx_Erase(&My_Flash, &PageError); //调用擦除函数擦除
}
HAL_FLASH_Lock();//上锁
}
u8 STMFLASH_ReadByte(u32 faddr)
{
return *(__IO uint8_t*) (faddr);
// return *(u8*) faddr;
}
//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read_Byte(u32 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STMFLASH_ReadByte(ReadAddr);//读1个字节.
ReadAddr+=1;//偏移1个字节.
}
}
#define FLASH_SAVE_ADDR_MAX_31 0X0800f800
u8 data_flash[64];
static u16 count_delay=0;
u8 flag_v_a=0;
int main(void)
{
HAL_Init();
SystemClock_Config();
// led_gpio_config();
// d_out_gpio_config();
// d_in_gpio_config();
// rs485_en_gpio_config();
UART1_init(115200);
UART2_init(115200);
printf("******************sys begain **************\r\n");
data_flash[0]=0x55;
fauil_delay_work=30;
IWDG_Init(4,625*6); // 频率:32K/64/1 Tout= ((prer分频)* rlr /32) 7
while (1)
{
printf("\r\n\r\nwrite falsh data \r\n");
for(u8 i=0;i<sizeof(data_flash);i++)
{
if(i==0) data_flash[0]=0x55;
else data_flash[i]=i+data_coun;
printf("%02x ",data_flash[i] );
}
data_coun++;
HAL_Delay(1000);
stm32_save_flash(FLASH_SAVE_ADDR_MAX_31,data_flash,sizeof(data_flash));
IWDG_Feed();
HAL_Delay(1000);
if(stm32_read_flash(FLASH_SAVE_ADDR_MAX_31,data_flash,sizeof(data_flash)))
{
printf("\r\n\r\nread falsh data \r\n");
for(u8 i=0;i<sizeof(data_flash);i++)
{
printf("%02x ",data_flash[i] );
}
}
}
}
运行效果:测试代码单次写入数据长度使用的是64字节
完整demo下载路径:STM32G030C8T6读写flash-单片机文档类资源-CSDN下载