STM32F103 内部片上flash读写操作实现掉电保存数据(附代码)

一:前言

        有些项目中,需要实现保存参数设置,掉电后,下次开机时无需重复设置。当数据量小的时候,可以通过内部flash实现。本文主要介绍STM32内部Flash读写方式的功能函数怎样编写。

二: 准备工作

        首先,需要对该芯片的flash有基本了解,比如大小? 地址? 可以通过芯片手册了解。以STM32F103C8 为例。参考: STM32F103C8 数据手册   以及:F1x 参考手册  

找到其中Memory map 章节,可以看到flash每一页有1K bytes 。

那如何知道还有多少空闲flash能用呢? 以STM32Cube IDE为例,可通过Build Analyzer查看。

如下图,可以看到还有10几K可以使用。 

三: 代码设计

从STM32 官方github上找参考代码:

STM32F1 FLASH 例程

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 项输入地址查看:

五:注意事项

  1.  写Flash时,需注意先要擦除;
  2.  地址要输入正确;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值