一步一步實現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實驗