RT_Thread版本:4.1.0
主控:STM32L471
4G模塊:L610模塊(AT指令方式)
這周花了一點時間,使用ota_downloader組件實現(xiàn)http_ota升級功能,在使用時遇到了一些坑,特別是到了搭建外網(wǎng)服務(wù)器部分,教程一般都是講到本地使用webserve軟件來當(dāng)http服務(wù)器的。所以今天簡單整理一下開發(fā)思路和我遇到的坑。
此處我只是提供思路以及參考文檔鏈接,根據(jù)這些文檔就可以實現(xiàn)想要的功能的。
1.制作Bootloader
此處如果不想自己寫的話,可以用兩個選擇。
使用RT_Thread提供的通用bootloader
選擇芯片系列,ROM,RAM大小,引腳即可自動生成一個bin文件。
優(yōu)點:
? 一站式處理,十分簡單,資源占用較小
? 缺點:
? 閉源,無法看到源代碼,不支持QSPI(?)這點不是很確定,目前只支持STM32部分系列
使用Qboot等軟件包
優(yōu)點:
可以看到源代碼出現(xiàn)問題可以自己改(個人看重的點),如果使用型號沒有適配可以自己適配
缺點:
占用資源相對更大一些
由于本人還是比較看重程序的可控性,出現(xiàn)問題希望自己可以看到代碼解決因此就選擇Qboot的方案
此處需要注意的是加入FAL組件后,發(fā)現(xiàn)沒有添加drv_flash_l4.c是因為沒有在Kconfig中增加
menu "On-chip Peripheral Drivers"
config BSP_USING_ON_CHIP_FLASH
bool "Enable on-chip FLASH"
default y
此處已經(jīng)默認(rèn)使能了,直接scons --target=cmake即可
2.APP程序
此處主要使能ota_downloader軟件包
修改中斷向量表和鏈接腳本
鏈接腳本修改
MEMORY
{
ROM (rx) : ORIGIN = 0x08010000, LENGTH = 1024k /* 1024KB flash /
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 96k / 96KB sram */
}
中斷向量表修改
/* 將中斷向量表起始地址重新設(shè)置為 app 分區(qū)的起始地址 /
static int ota_app_vtor_reconfig(void)
{
#define NVIC_VTOR_MASK 0xFFFFFF80
#define RT_APP_PART_ADDR (0x08000000 + 641024)//app partition begin address
/* 根據(jù)應(yīng)用設(shè)置向量表 */
SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK;
return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);
之后如果使用ST-Link的話可以選擇STM32CubeProg指定地址燒錄固件
或者可以使用Jlink使用J-Flash進行燒錄
需要注意此處燒錄起始地址為app區(qū)地址,不要把bootloader擦除了。
下載后就可以使用RT的rbl打包工具進行固件打包放在服務(wù)器中了
打包工具在ota_downloader組件中
打包工具可以選擇為固件進行加密,壓縮等操作
并且為固件頭增加了96字節(jié)的頭,固件標(biāo)識rbl頭,固件大小,CRC,Hash值用于固件校驗
typedef struct {
char type[4]; /* RBL字符頭 /
rt_uint16_t fota_algo; / 算法配置: 表示是否加密或者使用了壓縮算法 /
rt_uint8_t fm_time[6]; / 原始bin文件的時間戳, 6位時間戳, 使用了4字節(jié), 包含年月日信息 /
char app_part_name[16]; / app執(zhí)行分區(qū)名 /
char download_version[24]; / 固件代碼版本號 /
char current_version[24]; / 這個域在rbl文件生成時都是一樣的,我用于表示app分區(qū)當(dāng)前運行固件的版本號,判斷是否固件需要升級 /
rt_uint32_t code_crc; / 代碼的CRC32校驗值,它是的打包后的校驗值,即rbl文件96字節(jié)后的數(shù)據(jù) /
rt_uint32_t hash_val; / 估計這個域是指的原始代碼本身的校驗值,但不知道算法,無法確認(rèn),故在程序中未使用 /
rt_uint32_t raw_size; / 原始代碼的大小 /
rt_uint32_t com_size; / 打包代碼的大小 /
rt_uint32_t head_crc; / rbl文件頭的CRC32校驗值,即rbl文件的前96字節(jié) */
} rt_fota_part_head, *rt_fota_part_head_t
由于4G模塊連接的外網(wǎng),本地直接使用webserver是無法訪問的,因此我這個白嫖了一個月的阿里云服務(wù)器來部署
一開始我是使用了python的Flask框架來寫后端程序,但是后面遇到了一些問題,因此就暫時放棄了。
這個加深了一下教訓(xùn),調(diào)試時一定要控制變量,當(dāng)時我不能確定是STM32程序的問題,還是后端的問題,兩頭排查還是比較痛苦的
因此這里我建議先使用mywebserver+內(nèi)網(wǎng)穿透工具來驗證stm32的程序。
這里內(nèi)網(wǎng)穿透我建議用Copolar,免費并且目前仍在提供服務(wù)。
之后選擇部署在服務(wù)器中的話,我這邊使用的是Nginx可以很方便的搭建一個http服務(wù)器
遇到最大的坑:
在調(diào)試過程中發(fā)現(xiàn)OTA下載一次之后,想要OTA升級第二次時bootloader就提示app區(qū)寫入固件失敗,但是明明日志中說明Flash擦除成功,為何呢?
使用STM32CubeProg讀取Flash時發(fā)現(xiàn)確實沒有將APP區(qū)擦除
在packages/ota_downloader的static int http_ota_fw_download(const char* uri)
經(jīng)過排查原來我用的芯片F(xiàn)lash使用雙Bank模式,可用于備份升級的。
我當(dāng)時分區(qū)的時候沒有考慮這一點
#define FAL_PART_TABLE
{
{FAL_PART_MAGIC_WORD, "download", "onchip_flash", 1281024, 2981024, 0},
{FAL_PART_MAGIC_WORD, "app", "onchip_flash", 4261024, 2981024, 0},
{FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 7241024, 2981024, 0}
}
剛好app區(qū)是跨bank的,在擦除時其實沒有考慮到擦除跨bank的情況,導(dǎo)致擦除失敗。
int stm32_flash_erase(rt_uint32_t addr, size_t size)
{
rt_err_t result = RT_EOK;
uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0;
uint32_t PAGEError = 0;
if ((addr + size) > STM32_FLASH_END_ADDRESS)
{
LOG_E("ERROR: erase outrange flash size! addr is (0x%p)n", (void*)(addr + size));
return -RT_EINVAL;
}
/ Variable used for Erase procedure /
FLASH_EraseInitTypeDef EraseInitStruct;
/* Unlock the Flash to enable the flash control register access ********** * /
HAL_FLASH_Unlock();
/ Clear OPTVERR bit set on virgin samples /
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_PGSERR);
/ Get the 1st page to erase /
FirstPage = GetPage(addr);
/ Get the number of pages to erase from 1st page /
NbOfPages = GetPage(addr + size - 1) - FirstPage + 1;
/ Get the bank /
BankNumber = GetBank(addr);
/ Fill EraseInit structure /
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = BankNumber;
EraseInitStruct.Page = FirstPage;
EraseInitStruct.NbPages = NbOfPages;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
{
result = -RT_ERROR;
goto __exit;
}
__exit:
HAL_FLASH_Lock();
if (result != RT_EOK)
{
return result;
}
LOG_D("erase done: addr (0x%p), size %d", (void* )addr, size);
return size;
}
目前簡單的解決辦法是修改分區(qū),然后分區(qū)跨bank,之后有空的話可以提個PR修復(fù)一下。
#define FAL_PART_TABLE
{
{FAL_PART_MAGIC_WORD, "app", "onchip_flash", 641024, 4481024, 0},
{FAL_PART_MAGIC_WORD, "download", "onchip_flash", 5121024, 2561024, 0},
{FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 7681024, 2561024, 0}
}
-
FlaSh
+關(guān)注
關(guān)注
10文章
1644瀏覽量
148775 -
OTA
+關(guān)注
關(guān)注
7文章
588瀏覽量
35405 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1306瀏覽量
40436 -
STM32L4
+關(guān)注
關(guān)注
1文章
42瀏覽量
9449 -
4G模塊
+關(guān)注
關(guān)注
1文章
69瀏覽量
9209
發(fā)布評論請先 登錄
相關(guān)推薦
怎么實現(xiàn)RT_thread STM32通用Bootloader做OTA升級?
RT_Thread Studio進行RT_Thread Setting保存后自己創(chuàng)建的文件夾會消失是何原因
基于正點原子精英版stm32f103zet6進行rt_thread(3.0.3)的移植
![基于正點原子精英版stm32f103zet6進行<b class='flag-5'>rt_thread</b>(3.0.3)的移植](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
RT—thread線程調(diào)度詳解
N32WB452系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32WB452系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32G4FR系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32G4FR系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32G455系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32G455系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32G452系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32G452系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32G435系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32G435系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32G432系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32G432系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32L43x系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32L43x系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
N32L40x系列通用MCU RT_Thread設(shè)備注冊應(yīng)用筆記
![N32L40x系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊應(yīng)用筆記](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論