1 概述
采用 LoRa 技術(shù)進行無線通訊,考慮到產(chǎn)品的實際需求,增加了產(chǎn)品的 OTA 固件升級的功能。因為 LoRa 通訊速度較慢,合理的減小 APP 區(qū)域固件的大小加快固件升級的速度變的尤為重要,于是就開啟了優(yōu)化調(diào)整 APP 區(qū)域固件大小之旅。
代碼中使用到了 STM32_Cryptographic_Library、STM32_Std_Library 和 LoRa 驅(qū)動庫,這些庫編譯之后的體積較大,猜想能不能將所有的這些庫文件放在 Bootload 進行固化,然后封裝好接口供 APP 調(diào)用,順著這個思路開啟了優(yōu)化之路。
2 調(diào)試之路
2.1 想法
常見的固件升級是將片內(nèi) Flash 分為 Bootload 區(qū)域和 APP 區(qū)域(如下圖所示),由 APP 區(qū)域接收新固件存儲在片內(nèi)或者片外 Flash,然后置升級的標志位并跳轉(zhuǎn)到 Bootload,在 Bootload 完成新固件的更新工作。這樣實現(xiàn)比較常規(guī),但是由于 APP 中包含了多種庫導(dǎo)致目標文件比較大,LoRa 通訊速率又不高會使整個升級時間很長。
為了減小 APP 的大小,考慮將使用到庫文件都固化在 Bootload 內(nèi),將片內(nèi) Flash 分為三個區(qū)域(如下圖所示),增加一個共有函數(shù)區(qū)域,用于存放 Bootload 中封裝好的接口。在函數(shù)調(diào)用時,如果 APP 調(diào)用的是共有函數(shù),那么首先去共有函數(shù)區(qū)域找到函數(shù)在 Flash 中的地址,然后到 Bootload 中的對應(yīng)位置執(zhí)行相應(yīng)的代碼,再講執(zhí)行結(jié)果返回給 APP 區(qū)域,整個調(diào)用過程如下所示。
2.2 函數(shù)和變量定義在絕對地址的實現(xiàn)
有了上面的想法,首先需要驗證的是如何將函數(shù)和變量放置在 Flash 的固定位置處,這樣每次在調(diào)用固定位置處的接口就能找到 Bootload 中固化的代碼接口。查閱相關(guān)資料,了解到 IAR 中的具體實現(xiàn)如下:
2.2.1 IAR的擴展關(guān)鍵字
??@ 用于函數(shù)變量的絕對地址定位,將函數(shù)變量等放到指定的 section
??__no_init禁止系統(tǒng)啟動時初始化變量
??__root 保證沒有使用的函數(shù)或者變量也能夠包含在目標代碼中
2.2.2 函數(shù)的絕對定位
要將函數(shù)定義在絕對位置,需要在函數(shù)定義時后面加上
1voidfun1(inta,intb)@".MY_SECTION"
2{
3...//函數(shù)內(nèi)容
4}
然后在鏈接文件 .icf 中添加如下內(nèi)容。其中 0x08010000 表示在 Flash 中的地址,.MY_SECTION 必須與函數(shù) @ 后面雙引號中內(nèi)容一致
1placeataddressmem:0x08010000{readonlysection.MY_SECTION};
2.2.3 變量的絕對定位
示例如下,變量絕對定位,無須修改 .icf 鏈接文件,直接指定具體位置即可。
1__no_initchararray1[100]@0x2000B000;
2.2.4 常量的絕對定位
常量的絕對定位示例如下:
1__rootconstintstr1[4]@".MYSEG"={1,2,3,4};
常量絕對定位,需要改.icf文件,示例如下:
1placeataddressmem:0x08018500{readonlysection.MYSEG};
2.2.4 .c文件的絕對定位
要將 test.c 文件定位到 Flash 的絕對地址,那么在 .icf文件中應(yīng)該按照如下格式添加:
1placeataddressmem:0x08018000{section.textobjecttest.o};
編譯完成后整個 test.c 文件的所有函數(shù),都在 0x08018000 之后。
2.3 Bootload 共有函數(shù)的實現(xiàn)
考慮到在初期編寫代碼時共有函數(shù)是可能發(fā)生變化的,如果按照上述的方法一個一個將函數(shù)放在固定的位置不是很方便,因此采用數(shù)組的方式將所有的共有函數(shù)放置在一起,如下所示:
1__rootconstuint32_tfunc_table[]@".COMMON_FUNC_SEG"={
2
3(uint32_t)&fun1,/**00*/
4
5(uint32_t)&fun2,/**01*/
6
7(uint32_t)&fun3,/**02*/
8
9}
按照上面數(shù)組的方式將所有共有函數(shù)集合在一起,然后再 .icf 鏈接文件中將該數(shù)組放置在固定位置處,這樣在 0x08010000 位置處依次就能找到定義的所有共有函數(shù)(每個成員是函數(shù)對象的地址,占 4 個字節(jié))。
1/**將數(shù)組放置在固定位置*/
2
3placeataddressmem:0x08010000{readonlysection.COMMON_FUNC_SEG};
2.4 APP 共有函數(shù)的使用
按照上述的方法可以將所有的庫函數(shù)封裝好并固化在 Bootload 中,并且實現(xiàn)了將所有的共有函數(shù)接口放置在固定的位置,在 APP 區(qū)可以使用函數(shù)指針的方式進行訪問,示例如下:
1/**1.聲明*/
2
3typedefint(*app_fun1)(inta,intb);
4
5typedefvoid(*app_fun2)(void);
6
7typedefchar*(*app_fun3)(char*p);
8
9/**2.定義函數(shù)指針類型的變量*/
10
11app_fun1fun1;
12
13app_fun2fun2;
14
15app_fun1fun3;
16
17/**3.共有函數(shù)的重定義*/
18
19#defineFUNC_TABLE_ADDR(0x08010000)/**共有函數(shù)的首地址*/
20
21voidredefine_common_function(void)
22
23{
24
25uint32_t*func_table_addr=(uint32_t*)FUNC_TABLE_ADDR;
26
27fun1=(app_fun1)func_table_addr[0];/*00*/
28
29fun2=(app_fun2)func_table_addr[1];/*01*/
30
31fun3=(app_fun3)func_table_addr[2];/*02*/
32
33}
通過上面的方式就能在 APP 區(qū)域調(diào)用 Bootload 中固化的接口了,不過要注意這種方式調(diào)試起來不是很方便,需要前期驗證好 Bootload 中封裝的接口有沒有問題。
3 注意事項
按照上述的方法操作時有一些注意事項如下:
1. 固件更新區(qū)的絕對定位的函數(shù),不能隨意調(diào)用其他庫函數(shù),那些被調(diào)用的函數(shù)也必須是絕對定位的。
2. 絕對定位的函數(shù),如果要使用常量,那么被使用的常量也必須是絕對定位的。
3. 絕對定位的函數(shù),如果要使用全局變量,那么被使用的常量也必須是絕對定位的,而局部變量則不受此限制。
4 調(diào)試坎坷之路
上面的想法很有新意,在調(diào)試時自己封裝的接口文件也經(jīng)過了驗證,但是在 APP 調(diào)用共有函數(shù)時程序還是跑飛了,經(jīng)過不斷的分析現(xiàn)實線現(xiàn)象,找到了問題的根源所在。STM32 標準庫在進行時鐘配置時定義了兩個全局的數(shù)組如下,由于開始沒有注意到這兩個全局數(shù)組,而這兩個全局數(shù)組是在 Bootload 區(qū)域定義的,跳轉(zhuǎn)到 APP 區(qū)域后會對棧空間重新初始化,原本放這兩個數(shù)組的位置就被初始化其他數(shù)值了,到時時鐘配置出錯。
1/**stm32f10x_rcc.c*/
2
3static__Iuint8_tAPBAHBPrescTable[16]={0,0,0,0,1,2,3,4,1,2,3,4,6,7,8,9};
4
5static__Iuint8_tADCPrescTable[4]={2,4,6,8};
分析后的解決辦法如下,因為這兩個全局數(shù)據(jù)需要在 Bootload 區(qū)域中使用,而 Bootload 需要進行固化,所以需要將這兩個數(shù)組放置固定的位置,這樣每次使用到該數(shù)組時就回去固定的位置找,就不會出現(xiàn)被誤修改的情況了。修改方式如下:
1__rootconstuint8_tAPBAHBPrescTable[16]@".AHBAPB_PRESC_TABLE"={0,0,0,0,1,2,3,4,1,2,3,4,6,7,8,9};
2
3__rootconstuint8_tADCPrescTable[4]@".ADC_PRESC_TABLE"={2,4,6,8};
4
5/**對應(yīng)的修改.icf文件*/
6
7placeataddressmem:0x08010000{readonlysection.AHBAPB_PRESC_TABLE};
8
9placeataddressmem:0x08010010{readonlysection.ADC_PRESC_TABLE};
5 補充
上述講解了在 Bootload 和 APP 中共有函數(shù)的定義和使用,怎么驗證是不是將其定義在絕對地址了呢?我們可以查看編譯后生成的 map 文件,如下所示,可以看到在 map 文件中可以找到定義的 section。
————————————————
版權(quán)聲明:本文為RT-Thread論壇用戶「crystal266」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://club.rt-thread.org/ask/article/fa68bea40877eec3.html
點擊閱讀原文進入官網(wǎng)
原文標題:一種有趣的 OTA 升級思路(基于 LoRa 通信的 OTA 固件升級的調(diào)試記錄)
文章出處:【微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
RT-Thread
+關(guān)注
關(guān)注
31文章
1296瀏覽量
40241
原文標題:一種有趣的 OTA 升級思路(基于 LoRa 通信的 OTA 固件升級的調(diào)試記錄)
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論