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