0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

求一種基于U盤拖拽更新固件的解決方案

痞子衡嵌入式 ? 來源:安德魯?shù)脑O計筆記本 ? 2023-09-20 09:16 ? 次閱讀

引言

我們在向一些非專業(yè)開發(fā)者發(fā)放開發(fā)板時,有時對方沒有調試器,開發(fā)者就無法下載體驗在后續(xù)發(fā)布支持新功能的固件。并且,對于非專業(yè)開發(fā)者的用戶來說,僅僅是體驗新功能,而不介入開發(fā)工作,專門搭建一套開發(fā)環(huán)境,性價比實在不高。即使有調試器硬件,在不同操作系統(tǒng)平臺上,還需要安裝專門的工具軟件配合工作,才能實現(xiàn)下載固件的功能,操作比較繁瑣。為了簡化下載固件的操作,本例使用MM32F5270微控制器,基于芯片自帶的USB外設,實現(xiàn)了一個基于U盤拖拽更新固件的解決方案。我期望實現(xiàn)的結果是:

將開發(fā)板同PC連接后,PC將識別出一個U盤

可將開發(fā)板的固件(bin 格式)文件拖拽存放至該U盤中

復位開發(fā)板后,開發(fā)板能夠執(zhí)行新的固件程序

相對于板載帶有U盤拖拽下載功能的daplink方案,本例節(jié)約了一個專門運行daplink程序的芯片,利用微控制器自帶的USB外設直接建立同PC的連接,更可有機會被實現(xiàn)成ROM,固化在芯片內部。

原理

MM32F5270片內集成了256KB Flash,但可通過QSPI接口外擴spiflash存儲設備,并可在外擴spiflash中執(zhí)行程序(XIP)。本例實際將運行bootloader的片內Flash當做BOOT ROM,而將可執(zhí)行程序的固件存放在對接的spiflash存儲介質中。當芯片上電后,通過一些外部控制手段(例如使用一個按鍵選擇啟動模式),先運行帶有USB功能的bootloader程序,由bootloader的程序將芯片模擬成U盤(U盤的物理存儲空間位于外擴spiflash的后半段)。PC可以看到模擬U盤中的現(xiàn)存文件,也可以向其中拖拽新文件。當拖拽新文件后,bootloader程序會繼續(xù)將新文件的程序內容復制到程序的執(zhí)行區(qū)域,覆蓋掉之前的程序,然后再跳轉到程序的執(zhí)行區(qū)域執(zhí)行程序。

這里專門使用一塊物理存儲區(qū)域(spiflash存儲器的后半段)的原因是,USB協(xié)議棧模擬U盤時,對文件系統(tǒng)的管理操作全部交由PC完成,這就意味著,PC向模擬U盤發(fā)送包含文件內容的數(shù)據(jù)包時,不一定是按照物理上的先后順序發(fā)送的,微控制器端難以通過數(shù)據(jù)包本身解析出數(shù)據(jù)包的先后順序。但是,bootloader向程序執(zhí)行區(qū)域復制可執(zhí)行程序的內容必須是順序且連續(xù)的。PC在同U盤的通信過程中,數(shù)據(jù)包之間的內容可能不連續(xù),但最終發(fā)送完成的文件內容一定是完整的。因此,這里使用使用了一個能包含整個固件文件大小的區(qū)域作為緩沖區(qū),先緩沖下來整個完整的文件,然后再將完整的文件內容按順序復制到程序的可執(zhí)行區(qū)域。

理想情況下,如果能用一塊RAM作為整個文件的緩沖區(qū),通過U盤拖拽下載過程將會非???。但本例中使用spiflash作為緩沖區(qū),雖然擦除spiflash并向其寫入數(shù)據(jù)需要花費更多的時間,但能容納更大的程序文件。

如果芯片內部集成足夠大的片內Flash,也可以不依賴外擴spiflash,對內部的Flash做分區(qū),分別作為bootloader、運行程序及文件緩存的存儲區(qū)。

實現(xiàn)

硬件相關

本例使用BIRD-F5270開發(fā)板,開發(fā)板基本情況如下:

晶振 12MHz

使用QSPI接口對接外擴spiflash存儲芯片F(xiàn)M25Q16(2MB Flash),引腳與MM32F5280片內合封所使用的引腳保持一致:

QSPI_NSS - PF6

QSPI_SCK - PG7

QSPI_D0 - PG6

QSPI_D1 - PF8

QSPI_D2 - PF10

QSPI_D3 - PG8

USB 引腳

USB_DP - PA12

USB_DM - PA11

按鍵引腳

SW1 - RESET

SW2 - BOOT0

SW3 - PA0

軟件相關

啟動到2nd bootloader

芯片上電復位后,默認是直接執(zhí)行到用戶程序中,但也可以通過指定的手段改為執(zhí)行bootloader,執(zhí)行U盤程序。本例使用一個按鍵,綁定到一個指定的GPIO輸入(BOOT引腳),芯片在啟動過程中判定啟動模式:默認啟動到用戶程序,當按鍵按下時,啟動到帶有U盤程序的bootloader。

MM32F5芯片自帶的BOOT0引腳雖然在微控制器復位后可作為普通GPIO使用,但可能會將芯片引導到芯片內部已經固化到ROM中的bootloader程序中,因此不適合作為2nd bootloader的BOOT引腳。BIRD-F5270開發(fā)板上除RESET和BOOT0 之外,還有PA0引腳實現(xiàn)按鍵(SW3)功能,可作為2nd bootloader中的BOOT引腳。

當 SW3 被按下時,PA0 為低電平,可執(zhí)行 U 盤任務,當 SW3 松開時,PA0 為高電平,可執(zhí)行跳轉程序的任務,具體實現(xiàn)代碼如下:

/*readgpiopinlevel,selectbootmode.*/
if(GPIO_ReadInDataBit(BOARD_BTN_PORT,BOARD_BTN_PIN))
{
/*updateapp&run.*/
jump_to_app();
}
else
{
/*runusbmsctask.*/
msc_task();
}

/*cannotrunhere.*/
while(1)
{}

基于USB外設模擬U盤

MM32F5270微控制器集成了USB外設,配合TinyUSB協(xié)議棧,可模擬U盤(MSC設備)。

當運行模擬U盤的程序時,需要指定一塊存儲區(qū)域作為U盤的存儲空間,在本例中,將外擴的spiflash存儲區(qū)域一分為二,前半部分作為執(zhí)行程序區(qū)域,存儲需要執(zhí)行的應用程序,后半部分作為U盤的物理存儲空間,將用于緩存用戶通過拖拽方式下載的固件。

注意,spiflash作為U盤的存儲介質時需要解決一個問題,spiflash的最小擦除塊大小是4KB,而U盤設備對存儲介質的擦除塊大小是512B,擦除塊大小不匹配。該問題有兩種解法:

每次修改spiflash前,先將包含目標操作空間的4KB大小的數(shù)據(jù)塊讀取數(shù)據(jù)到RAM中緩存,修改指定位置的數(shù)據(jù)內容后,擦除spiflash中對應的整塊,再將修改后的數(shù)據(jù)塊寫入到spiflash中。

每次修改spiflash前,先將包含目標操作空間的4KB大小的數(shù)據(jù)塊讀取數(shù)據(jù)到RAM中緩存,修改指定位置的數(shù)據(jù)內容后,暫不寫回到spiflash中。如果接下來要寫入的數(shù)據(jù)仍在該塊中,則繼續(xù)寫入RAM緩存。只有當將要新寫入的數(shù)據(jù)不在緩存的數(shù)據(jù)塊中時,才寫回最近緩存的數(shù)據(jù)塊,并讀出新的數(shù)據(jù)塊到RAM緩存中。另外,每次在寫操作之后的讀操作,也都會重新清空RAM緩存中的數(shù)據(jù)。

第一種方法簡單易實現(xiàn),但會頻繁擦寫spiflash,消耗存儲器件的壽命。第二種方法相當于實現(xiàn)了一個cache機制,操作行為較為復雜。當前暫時選擇第一種做法,先驗證原理,如果后續(xù)考慮將這個帶U盤功能的bootloader集成到芯片內部,到時也可以專門集成一塊以512B作為操作單元的dflash作為固件的緩存存儲設備。

運行TinyUSB協(xié)議棧的程序中,在執(zhí)行MSC任務時,會執(zhí)行對spiflash存儲設備進行讀寫操作的回調函數(shù),如下:

從spiflash讀數(shù)據(jù):

//CallbackinvokedwhenreceivedREAD10command.
//Copydisk'sdatatobuffer(uptobufsize)andreturnnumberofcopiedbytes.
int32_ttud_msc_read10_cb(uint8_tlun,uint32_tlba,uint32_toffset,void*buffer,uint32_tbufsize)
{
(void)lun;

uint8_t*addr=(uint8_t*)(BOARD_MEM_BASE+lba*512+offset);
memcpy(buffer,addr,bufsize);

returnbufsize;
}

向spiflash寫數(shù)據(jù):

staticuint8_tflash_buf[4096];

//CallbackinvokedwhenreceivedWRITE10command.
//Processdatainbuffertodisk'sstorageandreturnnumberofwrittenbytes
int32_ttud_msc_write10_cb(uint8_tlun,uint32_tlba,uint32_toffset,uint8_t*buffer,uint32_tbufsize)
{
(void)lun;

/*readthe4Ksectorfromspiflashtolocalbuff.*/
uint8_t*flash_addr=(uint8_t*)((BOARD_MEM_BASE+lba*512)&0xFFFFF000);
memcpy(flash_buf,flash_addr,4096);
/*erasethesectorinspiflash.*/
BOARD_EraseSector4KB((uint32_t)flash_addr);
/*writethenewdataintolocalbuff.*/
uint8_t*block=flash_buf+((lba*512)&0xFFF)+offset;
memcpy(block,buffer,bufsize);
/*writethedatafromlocalbufftospiflash.*/
BOARD_WriteSector4KB((uint32_t)flash_addr,flash_buf);

returnbufsize;
}

另外,還有一種做法是不需要真實存在的物理存儲空間作為U盤的存儲介質,而是實時解算PC發(fā)過來的要存儲在Flash上的數(shù)據(jù)包,解析其中哪些數(shù)據(jù)是文件系統(tǒng)相關的信息,哪些數(shù)據(jù)是文件本身內容。此時,可丟棄文件系統(tǒng)相關的信息,而將文件本身內容按順序存放在spiflash的指定區(qū)域。該方法不需要將spiflash空間一分為二,可提高對spiflash的空間利用率,但該實現(xiàn)該方法需要十分熟悉FAT文件系統(tǒng)格式,且萬一電腦未按照指定的序列發(fā)數(shù)數(shù)據(jù)時,該方法無法正確解算出文件內容,造成更新固件失敗,因此,在本例中未實現(xiàn)該功能。

判斷是否存在新固件

前文中實現(xiàn)的U盤功能,將包括文件系統(tǒng)信息的新固件儲存在了spiflash的后半段空間中,bootloader程序要讀取新固件中的內容也需要能夠操作文件系統(tǒng),本例中為bootloader程序性集成了嵌入式系統(tǒng)上常見的文件系統(tǒng)組件為 FatFs(http://elm-chan.org/fsw/ff/00index_e.html)

本項目中,僅需要 FatFs 實現(xiàn)文件的讀功能,不需要對文件進行寫操作,因此只需要在適配接口上實現(xiàn)讀操作即可, 配置文件ff_conf.h中配置宏選項 FF_FS_READONLY 的值為1。然后在diskio.c文件中適配文件系統(tǒng)對具體物理介質的讀操作函數(shù)disk_read()如下:

DRESULTdisk_read(
BYTEpdrv,/*Physicaldrivenmubertoidentifythedrive*/
BYTE*buff,/*Databuffertostorereaddata*/
LBA_tsector,/*StartsectorinLBA*/
UINTcount/*Numberofsectorstoread*/
)
{
(void)pdrv;

BYTE*flash_addr=(BYTE*)(BOARD_MEM_BASE+sector*FF_MAX_SS);
memcpy(buff,flash_addr,count*FF_MAX_SS);

return0;
}

如何在文件系統(tǒng)中的眾多文件中識別微控制器可執(zhí)行程序的固件呢?本例采用通過文件名來確定是否為固件。

通過 FatFs 嘗試打開一個有宏BOARD_APP_NAME指定名稱的文件,若能成功打開該文件,則說明有可用的固件文件存在。

if(FR_OK==f_open(&file,"0:/"BOARD_APP_NAME,FA_READ))
{
...
}

為什么不能使用任意bin判斷文件作為固件呢?這里考慮到,當文件系統(tǒng)中有多個bin文件時,bootloader 沒有依據(jù)判斷哪一個固件為新固件(根據(jù)修改日期判斷是否可行,作為可移動存儲設備,會插在不同電腦上,如果不同電腦的時間不一致,則會出現(xiàn)判斷失誤的情況,因此不選擇使用修改日期作為新固件的判斷依據(jù)),指定固定文件名的方式判斷固件,最簡單有效,問題最少。

驗證固件的有效性

不少人都應該有這樣的經歷,在網上下載大文件如大型游戲時,往往下載頁面會提供一串 MD5 碼,這段 MD5 碼的作用是驗證下載的文件是否完整,當用戶在網上下載大文件完成后,可在 CMD 中使用 certutil -hashfile MD5 指令求出該文件的 MD5 碼,與下載頁面提供的 MD5 進行對比,判斷文件是否下載完整。

MicrosoftWindows[版本10.0.22621.1848]
(c) Microsoft Corporation。保留所有權利。

E:>certutil-hashfileproject.binMD5
MD5的project.bin哈希:
615ca0da12d496b7a8b1bd6c21876a97
CertUtil:-hashfile 命令成功完成。

E:>

嵌入式領域,Arm的MbedTLS加解密算法庫中提供了MD5的計算方法,因此可使用MbedTLS計算MD5,有程序如下:

/*calcmd5.*/
mbedtls_md5_contextmd5_ctx;

mbedtls_md5_init(&md5_ctx);
mbedtls_md5_starts(&md5_ctx);

while(1)
{
UINTbr=0;
f_read(&file,app_buf,sizeof(app_buf),&br);

mbedtls_md5_update(&md5_ctx,app_buf,br);

if(br

除了 MD5 以外,還可以使用如 SHA1,SHA2 或者 SM3 等更高安全等級的散列值算法作為新固件的判斷依據(jù)。

復制固件到執(zhí)行區(qū)域

復制固件到執(zhí)行區(qū)域的做法較為簡單,就是使用 f_read() 函數(shù)讀取數(shù)據(jù),再寫入到spiflash的指定區(qū)域即可。

但除了復制固件文件內容本身,其文件的MD5值也要寫入到Flash中。應在寫新固件之前將之前的MD5值擦除,寫新固件完成之后,再將新MD5值寫入,如此一來,MD5除了作為檢查新固件的完整性的方法外,還可作為執(zhí)行區(qū)域固件完整性檢查的重要依據(jù)。

本例中,將MD5值存放在片內flash的末尾。

檢查新固件和復制固件到執(zhí)行區(qū)域的代碼如下:

/*checkmd5,themd5lengthis16byte.*/
if(memcmp((uint8_t*)BOARD_MD5_BASE,md5_val,sizeof(md5_val))!=0)
{
/*newfile,update.*/
BOARD_EraseSector4KB(BOARD_MD5_BASE);

uint32_thas_write=0;
while(1)
{
UINTbr=0;
memset(app_buf,0xff,sizeof(app_buf));
f_read(&file,app_buf,sizeof(app_buf),&br);

BOARD_EraseSector4KB(has_write);
BOARD_WriteSector4KB(has_write,app_buf);
has_write+=4096;

if(br

需要使用完整的一個塊存放MD5值,MD5必須保證單獨擦除,單獨寫入。除了MD5以外,該區(qū)域還可以可根據(jù)需要存放一些固件相關的信息,比如說修改時間,固件大小等信息,充分利用空間。

跳轉執(zhí)行

跳轉程序需要做的事情包括:恢復系統(tǒng)時鐘,修改中斷向量表位置,復位棧指針,執(zhí)行應用程序的復位程序等。具體操作如下:

voidjump_to_app(void)
{
...
/*jumptoapp.*/
CLOCK_ResetToDefault();

vtor=(uint32_t*)BOARD_APP_BASE;

__disable_irq();
SCB->VTOR=BOARD_APP_BASE;

__ISB();
__DSB();

__set_MSP(vtor[0]);
__set_PSP(vtor[0]);

__enable_irq();
((void(*)(void))vtor[1])();
}

用戶應用程序

為了配合bootloader正常工作,需要用戶在自己的應用程序需調整以下內容:

在Linker File中指定可執(zhí)行程序在分塊后的存儲區(qū)

避免誤配置GPIO和QSPI導致BOOT按鍵或外擴spiflash失效

本例實現(xiàn)的bootloader,spiflash作為應用程序的執(zhí)行區(qū)域,代碼段的起始位置位于spiflash的起始映射地址0x90000000,不是片內Flash的0x08000000,因此,需要調整Linker中對應的配置如下:

/*---------------------FlashConfiguration----------------------------------
;FlashConfiguration
;FlashBaseAddress<0x0-0xFFFFFFFF:8>
;FlashSize(inBytes)<0x0-0xFFFFFFFF:8>
;
*----------------------------------------------------------------------------*/
#define__ROM_BASE0x90000000
#define__ROM_SIZE0x00100000

若使用spiflash存儲應用程序,bootloader在執(zhí)行應用程序前就應該將 QSPI 接口和 GPIO 引腳配置好。在用戶應用程序中,如果需要操作QSPI或者bootloader中使用的GPIO,要特別注意避開。

總結

通過USB接口將BIRD-F5270連接電腦,保持SW3按鍵按下時,再按下并松開RESET按鍵,稍后會在PC上看到一個大小約為1MB的U盤,將新編譯好的名為 “project.bin” 的固件文件拖拽存放至該U盤中,然后保持SW3按鍵松開的狀態(tài)下再次按下并松開RESET按鍵,稍后即可發(fā)現(xiàn)微控制器已經在執(zhí)行新固件中的應用程序了。

作為下載新固件的 U 盤,還可以存放一些別的文件,供應用程序使用,例如一張圖片,一首音樂,或一段文字,但需要注意的是,應用程序對該文件系統(tǒng)只有讀操作的權限,不能進行寫操作(或者在bootloader中實現(xiàn)安全寫操作的接口,讓應用程序去調用相應的寫操作接口)

known issue

開發(fā)板通過 USB 連接電腦,保持 SW3 按鍵按下的狀態(tài),多次快速按下復位鍵,可能會造成文件系統(tǒng)損壞,文件丟失,需重新格式化才能正常使用,其原因是兩次按下復位鍵中間,電腦正在修改 Flash 中的內容,但復位操作打斷了寫操作,造成文件系統(tǒng)損壞。因此需避免快速多次按下復位鍵的操作。這里可考慮使用一個可編程的指示燈,指示芯片內部程序的工作狀態(tài):當拖拽固件文件到芯片時,指示燈快速閃爍;當復制新固件文件到程序運行區(qū)域時,指示燈保持常亮;當復制完畢后,指示燈熄滅。僅當指示燈熄滅后,方可重新復位芯片執(zhí)行新程序。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 微控制器
    +關注

    關注

    48

    文章

    7454

    瀏覽量

    150853
  • ROM
    ROM
    +關注

    關注

    4

    文章

    562

    瀏覽量

    85623
  • 調試器
    +關注

    關注

    1

    文章

    300

    瀏覽量

    23667
  • SPI Flash
    +關注

    關注

    1

    文章

    13

    瀏覽量

    10328
  • QSPI接口
    +關注

    關注

    0

    文章

    14

    瀏覽量

    3328

原文標題:定制帶U盤功能的bootloader實現(xiàn)拖拽下載固件

文章出處:【微信號:pzh_mcu,微信公眾號:痞子衡嵌入式】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一種PCIe接口的視頻采集解決方案

    一種PCIe接口的視頻采集解決方案。
    發(fā)表于 04-30 06:29

    一種基于ZigBee的駕駛輔助系統(tǒng)解決方案

    一種基于ZigBee的駕駛輔助系統(tǒng)解決方案
    發(fā)表于 05-14 06:22

    一種單芯片低功耗藍牙BLE解決方案

    一種單芯片低功耗藍牙BLE解決方案
    發(fā)表于 05-21 07:01

    一種射頻開關的解決方案

    一種射頻開關的解決方案
    發(fā)表于 05-21 06:46

    一種NXP最新的NFC電子錢包解決方案

    NFC電子錢包總體結構是怎樣構成的?一種NXP最新的NFC電子錢包解決方案
    發(fā)表于 05-24 06:44

    一種可網絡化管理和配置機頂盒的網絡解決方案

    一種可網絡化管理和配置機頂盒的網絡解決方案
    發(fā)表于 05-25 07:10

    一種基于ARM Cortex-M處理器的音頻解決方案

    一種基于ARM Cortex-M處理器的音頻解決方案
    發(fā)表于 06-01 06:32

    一種應對壓電效應失效的電容器解決方案

    一種應對壓電效應失效的電容器解決方案
    發(fā)表于 06-08 06:39

    一種STM32仿真調試時復位后需要run多次的解決方案

    一種STM32仿真調試時復位后需要run多次的解決方案
    發(fā)表于 12-01 07:11

    一種MCU Specific Package單片機的具體解決方案

    一種MCU Specific Package單片機的具體解決方案
    發(fā)表于 12-10 07:46

    一種LCD和LED沖突的解決方案

    一種LCD和LED沖突的解決方案
    發(fā)表于 01-25 07:12

    一種用RK818實現(xiàn)電源管理的解決方案

    RK818是什么?一種用RK818實現(xiàn)電源管理的解決方案
    發(fā)表于 02-10 06:21

    一種基于RK3288的人臉識別測溫解決方案

    一種基于RK3288的人臉識別測溫解決方案
    發(fā)表于 03-03 12:21

    CH32X035實現(xiàn)U固件更新

    CH32X035的開發(fā)板上有個USB-A口, 實現(xiàn)U固件更新功能還是比較容易的,廠家有自己的U
    發(fā)表于 10-30 17:52

    通過U更新arm程序

    通過U更新arm程序
    發(fā)表于 03-21 15:24 ?14次下載