一步一步实现STM32-FOTA系列教程之FLASH静态区读写

一步一步实现STM32-FOTA系列教程之FLASH静态区读写

文章系列链接

《一步一步实现STM32-FOTA系列教程之bin文件生成》

《一步一步实现STM32-FOTA系列教程之STM32-FLASH分区说明》
《一步一步实现STM32-FOTA系列教程之Bootloader编写》

前言

在上一篇文章《一步一步实现STM32-FOTA系列教程之STM32-FLASH分区说明》中,对STM32的FLASH进行了人为了分区,分成了 Bootloader分区、主分区、备份分区和静态区四个区域。其中静态区是用来存放系统一些参数信息的,该分区的内容可以通过编程进行读写,如果不人为的破坏该分区,分区里面的信息会一直保存,掉电不丢失,也就是所谓的FLASH模拟EEPROM的功能。
这篇文章就来说说如何在程序中进行FLASH静态区的读写操作,以方便后续的使用。

FLASH静态区使用

我们在FLASH中给静态区分配了32KB大小的空间,即从0x0803 8000 ~ 0x0804 0000 一共 32 * 1024 字节。

对於单片机而言,能够拥有这么大静态区存储空间已经非常大了,当然我们也不能浪费了。但从Bootloder的分区启动选择而言,利用一个字节的空间用来存储启动分区标志位就已经足够了。考虑到在应用程序中还要公用这一块FLASH静态区,我们还是将这块区域进行结构化定义,才能更为方便的使用。

这里,我们就根据自己的项目实际需求,定义一个静态区变量存储的结构体,用于进行参数读写。

#pragma pack(1)

//静态区参数 配置信息
typedef struct STM32_STATIC_FLASH_SAVE
{
	char firmware_info[64];   //固件信息
	char hardwareversion[32]; //硬件版本
	char softwareversion[64]; //软件版本
	char device_sn[20];   //设备SN
	char device_imei[20]; //设备IMEI
	char updateflag;  //flash信息更新标志
	unsigned int  runcounts;  //运行次数
	char bootinfo[32];//系统启动相关参数信息
}STM32_SFS;

#pragma pack()

定义完成FLASH 静态区参数结构体后,每一次进行的 FLASH 静态区操作,都利用该结构体进行编解码,即可对我们代码中的参数进行实时的读取写入,非常方便。

该结构体中定义的 updateflag 即为系统启动分区标志位,Bootloader 启动之后,读取完静态区FLASH信息,就会判断该标志位的值,如果该标志位为1,则会从主分区启动程序,如果为2,则会从备份分区启动程序,如果为0,则代表主分区和备份分区还没有烧写软件,需要先进行烧写。

STM32-FLASH的编程接口

有关 STM32 中 FLASH 的编程接口,在STM32的库函数中,已经为我们提供了 stm32f10x_flash.c 和 stm32f10x_flash.h 两个 FLASH 操作的库文件,如果要在程序中对FLASH进行操作,需要在工程中引入这两个库文件。

除此之外,原子大哥也将 STM32 FLASH 的读写操作流程编写出来一份C文件,我们在使用的时候,可以直接移植到自己的工程中来 即stmflash.c 和 stmflash.h 两个文件。
为了更为快速的实现Bootloader功能,这里就直接使用这几份 FLASH 操作的函数库来对FLASH进行操作。

FLASH 静态区参数读写实现

首先定义一个 FLASH 静态区参数的全局结构体。

// FLASH 静态区参数信息
STM32_SFS nbdevice_sfs;

然后编写一个获取FLASH静态区参数的函数。

//得到设备信息
void GetDeviceInfo(void)
{
	u8 i=0;
	STM32_SFS *nbsfs = &nbdevice_sfs; 
	
	memset(&nbdevice_sfs,0,sizeof(STM32_SFS));

	printf("Static Params Address :0x%08X\r\n",CONFIG_PARAM_START_ADDR);
	//STMFLASH_Read(CONFIG_PARAM_ADDR, &buf, 1);
	STMFLASH_Read(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
	//静态区没有初始化
	if(NULL==strstr(nbdevice_sfs.firmware_info,"NBIOT_SMART_STREET_V2.0"))
	{
		printf("static flash not init\r\n");
		printf("start to init flash\r\n");
		memset(&nbdevice_sfs,0,sizeof(STM32_SFS));
		STMFLASH_Write(CONFIG_PARAM_START_ADDR,(u16*)&nbdevice_sfs,sizeof(STM32_SFS));
		
	}
	memset(&nbdevice_sfs,0,sizeof(STM32_SFS));
	STMFLASH_Read(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
	if(nbdevice_sfs.updateflag ==0)
	{
		sprintf(nbsfs->firmware_info,"%s","NBIOT_SMART_STREET_V2.0");
		nbdevice_sfs.updateflag = 1;
		printf("please upload firmware to stm32\r\n");
		STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
	}
	else if(nbdevice_sfs.updateflag ==1)
	{
		bootflag=nbdevice_sfs.updateflag;
		printf("start to boot firmware one\r\n");
		printf("Testing...\r\n");
		printf("set updateflag 2\r\n");
		nbdevice_sfs.updateflag = 2;
		STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
	}
	else if(nbdevice_sfs.updateflag ==2)
	{
		bootflag=nbdevice_sfs.updateflag;
		printf("start to boot firmware two\r\n");
		
		
		printf("Testing...\r\n");
		printf("set updateflag 1\r\n");
		nbdevice_sfs.updateflag = 1;
		STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
	}	

}

该函数实现非常简单,就是读取FLASH静态区信息,然后判断程序启动分区标志位,如果启动分区标志位为1,则将其改写为2,如果为2,怎将其改写为1,如果为0,则打印出下载固件的提示信息,如此以来,该函数能够实现两个分区的程序交替运行。

主函数实现

int main()
{
	
	ledInit();
	uart1_init(9600);

	delay_init();
	printf("-----------------------------------\r\n");
	printf("------------Bootloader-------------\r\n");
	printf("-----------------------------------\r\n");
	LOG_COMPILE();
	printf("Version: V1.0\r\n");
	LED0_Blink(100);
	GetDeviceInfo();

}

日志打印

这里我重启了3次,分别打印出来3次 bootloader 的打印信息,请参考。

-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
static flash not init
start to init flash
please upload firmware to stm32
-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
start to boot firmware one
Testing...
set updateflag 2
-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
start to boot firmware two
Testing...
set updateflag 1

源码

编写教程不易,还请到CSDN下载区下载源码。
源码下载链接

参考文档

正点原子 STM32 系列开发板FLASH模拟EEPROM实验

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章