前言
上一篇介紹完如何在程序中添加版本信息后,這篇介紹一下如何在 MCU 程序中固定位置添加程序的版本信息等。
了解
首先了解一下__attribute__
機制,它是個編譯器指令,告訴編譯器聲明的特性,或者讓編譯器進行更多的錯誤檢查和高級優(yōu)化。
GUN C中可以使用__attribute__()
給變量、函數(shù)和類型設(shè)置各種屬性,而__attribute__
的section選項可以改變段的特性;
其中__attribute__((section("section_name")))
的作用是將該定義的函數(shù)或數(shù)據(jù)變量放入指定名為”section_name”段中。
無論是 GNU 還是 ARM 的編譯器, 都支持
__attribute__
所指定的編譯屬性。
打開keil的options…,取消勾選下圖所示,然后點擊“Edit…”。
自動彈出“*.sct”文件(先編譯通過再操作),下面就是 Keil 中 STM32 的鏈接文件,編譯器會根據(jù)鏈接文件和__attribute__
的section選項(可以自己添加一個段,分配地址和大小)等分配函數(shù)和數(shù)據(jù)變量在程序固件中的地址。
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00010000 { ; load region size_region
ER_IROM1 0x08000000 0x00010000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00005000 { ; RW data
.ANY (+RW +ZI)
}
}
這里不做過多介紹了,下面介紹的方式不需要自己修改“*.sct”文件,還是采用__attribute__
的section選項,只不過在section選項中指定位置即可。
__attribute__ ((section(".ARM.__at_0x08000020")))
實現(xiàn)方式
1.同樣的定義一個結(jié)構(gòu)體,里面定義一些軟件版本相關(guān)的信息
typedef struct
{
char szVersion[32]; // 軟件版本
char szBuildDate[32]; // 程序編譯日期
char szBuildTime[32]; // 程序編譯時間
}AppInfo_t;
2.通過__attribute__
定義一個只讀結(jié)構(gòu)體變量(只讀的目的:防止程序改變、節(jié)約RAM)并固定變量在程序固件中的位置,賦初值(其中__DATE_
和__TIME__
是C語言中的內(nèi)置宏,分別是當(dāng)前的編譯日期和編譯時間)。
const AppInfo_t __attribute__ ((section(".ARM.__at_0x08002000"))) sg_tAppInfo =
{
"STM32_V0.1.5",
__DATE__,
__TIME__,
};
注:STM32的代碼起始地址是從0x08000000開始的,且存儲中斷向量表信息,因此在選擇程序地址的時候一定要繞開,也不能太靠后,不然生成的bin文件超出了實際的代碼固件大小,在實現(xiàn)bin文件升級的時候就會耗時太長。
3.編譯成功后打開hex文件,查看一下0x08002000所在的內(nèi)容,版本信息和編譯時間(之后可以通過新增代碼或者變量驗證是不是位置變了)
4.在主函數(shù)添加打印,將版本信息輸出到終端上,打印結(jié)果就不演示了,有興趣的朋友可以翻開上一章。
映像工具實現(xiàn)固件打包
這里采用的映像工具是srec_cat,網(wǎng)上有源碼(點擊閱讀原文下載srec_cat.exe),可以編譯成 Windows 或 Linux 的可執(zhí)行文件;這里用這個工具來打包固件信息,比如版本號,同時修改文件名,即文件名=版本號。
通過Bat腳本實現(xiàn)以下功能:
- 不需要修改代碼即可修改程序版本信息
- 按照當(dāng)前固件打包時間作為程序的版本信息,同時按照版本信息命名文件
- 版本命名格式為:STM32_T2206111526
根據(jù)目錄結(jié)構(gòu)樹編寫指定腳本
MDK_STM32
---- CORE
---- STM32F10x_FWLib
---- OBJ(編譯生成的hex文件)
---- USER
tool
---- srec_cat.exe
---- pack.bat
實現(xiàn) pack.bat:
:: 版本信息前綴和長度
set strPrefix=STM32_
set strPrefixlen=6
:: hex 文件路徑和文件名
set hexFilePath=..\\MDK_STM32\\OBJ
set hexFileName=main.hex
:: 版本信息信息起始地址
set verStringAddr=0x08002000
if %time:~0,2% leq 9 (set hour=0%time:~1,1%) else (set hour=%time:~0,2%)
if %time:~0,2% leq 9 (set minute=%time:~2,2%) else (set minute=%time:~3,2%)
:: 打包時間格式為年月日時分 T2206111526
set strTime=T%date:~2,2%%date:~5,2%%date:~8,2%%hour%%minute%
set strVersion=%strPrefix%%strTime%
:: 版本信息的起始和結(jié)束位置
set /a InfoEnd=%verStringAddr%+%strPrefixlen%+11
:: 拷貝臨時文件進行處理
copy %hexFilePath%\\%hexFileName% .\\
.\\srec_cat.exe -generate %verStringAddr% %InfoEnd% -repeat-string %strVersion% %hexFilePath%\\main.hex -intel -exclude %verStringAddr% %InfoEnd% -o .\\%strVersion%.hex -intel
:: 刪除臨時文件
del %hexFileName%
編譯完成后,雙擊 pack.bat 生成添加版本信息后的固件,之后需要通過J-LINK工具包打開生成的固件進行燒錄(通過Keil編譯下載的沒有用)。
擴展
如果實現(xiàn)了 bootloader 程序,那么一定會用到寄存器SCB->VTOR
重新設(shè)置中斷向量表的起始地址了,所以干脆可以將版本信息放在 APP 程序區(qū)中的最開始位置,后面緊跟中斷向量表的起始地址。
這樣做的好處是不用擔(dān)心程序編譯后版本信息的位置超出了APP可執(zhí)行程序的實際大小,而且在實現(xiàn)升級的時候bootloader程序在一開始就可以直接對版本信息進行校驗等。
同時通過映像工具 srec_cat 將 bootloader 和 APP 程序固件進行合并。
也能通過 keil 在編譯后自動執(zhí)行腳本。
-
mcu
+關(guān)注
關(guān)注
146文章
17162瀏覽量
351309 -
程序
+關(guān)注
關(guān)注
117文章
3787瀏覽量
81069 -
版本
+關(guān)注
關(guān)注
0文章
15瀏覽量
9480
發(fā)布評論請先 登錄
相關(guān)推薦
評論