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