1. 程式人生 > >一步一步實現STM32-FOTA系列教程之FLASH靜態區讀寫

一步一步實現STM32-FOTA系列教程之FLASH靜態區讀寫

一步一步實現STM32-FOTA系列教程之FLASH靜態區讀寫

文章系列連結

《一步一步實現STM32-FOTA系列教程之bin檔案生成》

《一步一步實現STM32-FOTA系列教程之STM32-FLASH分割槽說明》

前言

在上一篇文章《一步一步實現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實驗