一:前言
有些项目中,需要实现保存参数设置,掉电后,下次开机时无需重复设置。当数据量小的时候,可以通过内部flash实现。本文主要介绍STM32内部Flash读写方式的功能函数怎样编写。
二: 准备工作
首先,需要对该芯片的flash有基本了解,比如大小? 地址? 可以通过芯片手册了解。以STM32F103C8 为例。参考: STM32F103C8 数据手册 以及:F1x 参考手册
找到其中Memory map 章节,可以看到flash每一页有1K bytes 。
那如何知道还有多少空闲flash能用呢? 以STM32Cube IDE为例,可通过Build Analyzer查看。
如下图,可以看到还有10几K可以使用。
三: 代码设计
从STM32 官方github上找参考代码:
A. 读操作
uint32_t flash_read ( uint32_t address, uint8_t* pdata, uint32_t size )
{
uint32_t read_index = 0;
uint8_t value;
uint32_t start_addr;
uint32_t end_addr;
if ( !pdata || size < 1 )
{
return 0;//FLASH_PARAM_ERROR;
}
// start_addr = address+FLASH_BASE_ADDRESS;
start_addr = address;
end_addr = start_addr + size;
if ( start_addr < FLASH_USER_START_ADDR || end_addr > FLASH_USER_END_ADDR )
{
return 0;//FLASH_ADDR_ERROR;
}
read_index = 0;
while ( read_index < size )
{
value = * ( __IO uint8_t* ) start_addr;
start_addr = start_addr + 1;
* ( pdata + read_index ) = value;
read_index++;
}
return read_index;
}
B.擦除操作
FLASH_ERROR_CODE_E flash_erase( uint32_t start_addr,uint32_t end_addr)
{
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t PageError = 0;
//printf("start_addr = %lx,end_addr=%lx,FLASH_USER_START_ADDR = %lx,FLASH_USER_END_ADDR = %lx\r\n",start_addr,end_addr,FLASH_USER_START_ADDR,FLASH_USER_END_ADDR);
if((start_addr > end_addr) || (start_addr < FLASH_USER_START_ADDR) || (end_addr > FLASH_USER_END_ADDR))
{
return FLASH_ADDR_ERROR;
}
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = start_addr;
EraseInitStruct.NbPages = (end_addr - start_addr+(FLASH_PAGE_SIZE-1))/FLASH_PAGE_SIZE;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
{
HAL_FLASH_Lock();
return FLASH_ERASE_ERROR;
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return FLASH_SUCCESS;
}
C.写操作
FLASH_ERROR_CODE_E flash_write(uint32_t address, const uint8_t* pdata, uint32_t size)
{
HAL_StatusTypeDef result = HAL_ERROR;
uint32_t end_addr = 0;
uint32_t start_addr;
// uint16_t page_num;
uint32_t word_num;
uint8_t half_word_num;
uint8_t byte_num;
uint32_t write_index = 0;
//parameter check
if((!pdata) || (size<1))
{
return FLASH_PARAM_ERROR;
}
// page_num = (size % FLASH_PAGE_SIZE)?(size / FLASH_PAGE_SIZE+1):(size / FLASH_PAGE_SIZE);
word_num = (size >> 2); // size/4
half_word_num = (size % 4)>>1; // (size%4)>>1
byte_num = (size % 2); // size % 2
start_addr = address;
end_addr = ( start_addr + size );
if ( start_addr < FLASH_USER_START_ADDR || end_addr > FLASH_USER_END_ADDR )
{
return FLASH_ADDR_ERROR;
}
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
write_index = 0;
while(write_index < word_num)
{
result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, start_addr, BUILD_UINT32 ( * ( pdata ), * ( pdata + 1 ), * ( pdata + 2 ), * ( pdata + 3 ) ));
if(HAL_OK == result)
{
start_addr = start_addr + 4;
pdata = pdata + 4;
write_index++;
}
else
{
return FLASH_WRITE_WORD_ERROR;
}
}
write_index = 0;
while(write_index < half_word_num)
{
result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,start_addr,BUILD_UINT16 ( * ( pdata ), * ( pdata + 1 ) ));
if ( HAL_OK == result )
{
start_addr = start_addr + 2;
pdata = pdata + 2;
write_index++;
}
else
{
return FLASH_WRITE_HALF_WORD_ERROR;
}
}
write_index = 0;
while(write_index < byte_num)
{
result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,start_addr,BUILD_UINT16 ( * ( pdata ), 0xFFFF ));
if ( HAL_OK == result )
{
start_addr = start_addr + 2;
pdata = pdata + 2;
write_index++;
}
else
{
return FLASH_WRITE_BYTE_ERROR;
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return FLASH_SUCCESS;
}
以上代码参考:stm32f0_flash/STM32/STM32F0/STM32F0_CUBE_FLASH at master · GreatWall51/stm32f0_flash · GitHub
四: 结果验证
在STM32CubeIDE debug 中memory 项输入地址查看:
五:注意事项
- 写Flash时,需注意先要擦除;
- 地址要输入正确;