從代碼寫入單片機(jī)的方式上去區(qū)分主要分為3種:ICP、ISP、IAP
一、ICP(In Circuit Programing):在電路編程,可通過CPU的Debug Access Port 燒錄代碼,比如ARM Cortex的Debug Interface主要是SWD(Serial Wire Debug)或JTAG(Joint Test Action Group);
ICP 主要通過CPU的DAP(Debug Access Port) 燒錄代碼,下面以ARM Cortex-M3/M4 為例,展示Debug Interface 如下:
?ARM Cortex 內(nèi)部包含了CoreSight 調(diào)試架構(gòu),CoreSight 包括調(diào)試接口協(xié)議、調(diào)試總線協(xié)議、對(duì)調(diào)試組件的控制、安全特性、跟蹤接口等。以前的ARM 處理器都提供JTAG 接口,通過它來控制對(duì)寄存器和存儲(chǔ)器的訪問,CoreSight 則通過DAP(Debug Access Port) 來控制處理器上的總線邏輯。從上圖也可以看出,CoreSight 除了提供Debug Interface,還提供了Trace Interface,Trace Interface 主要用來觀察數(shù)據(jù)中間值的變化、跟蹤指令的執(zhí)行狀態(tài)等,只能單向讀取跟蹤數(shù)據(jù),屬于非侵入式調(diào)試,不能用于燒錄代碼,因此本文不對(duì)此做過多介紹。
常見的DAP仿真器就是這個(gè)原理,主要是配合一些程序開發(fā)軟件,例如 keil5 等實(shí)現(xiàn)將開發(fā)程序存儲(chǔ)到單片機(jī)的flash里。
那什么是SWD端口和JTAG端口呢?
通俗點(diǎn)理解可以理解為硬件端口的不同,JTAG接口是一種標(biāo)準(zhǔn)的測(cè)試協(xié)議,可以實(shí)現(xiàn)編程時(shí)在線調(diào)試,利用單步追蹤可以很方便的查找代碼的Bug,大多數(shù)的單片機(jī)都支持這種接口。這種接口除了電源線和復(fù)位引腳之外,還要用到單片機(jī)的四個(gè)引腳,分別是:TDI、TMS、TCK、TDO,他們所代表的含義如下所示:
TDI–數(shù)據(jù)輸入,所有寫入寄存器的數(shù)據(jù)都是通過TDI接口串行輸入的;
TMS–模式選擇,Jlink輸出給目標(biāo)CPU的時(shí)鐘信號(hào);
TCK–時(shí)鐘信號(hào),所有數(shù)據(jù)的輸入輸出都是以該時(shí)鐘信號(hào)為基準(zhǔn)的;
TDO–數(shù)據(jù)輸出,所有從寄存器讀出的數(shù)據(jù)都是通過TDO接口串行輸出的;
以上這四個(gè)引腳都是協(xié)議里強(qiáng)制要求的,而且協(xié)議建議在設(shè)計(jì)電路時(shí)要選用上拉電阻。JTAG接口有多種形式,常用的20引腳、14引腳和10引腳。
SWD是一種串行調(diào)試接口,與JTAG相比,SWD只需要兩根線,分別為:SWCLK和SWDIO。他們的含義如下:
SWDIO–串行數(shù)據(jù)線,用于數(shù)據(jù)的讀出和寫入;
SWDCLK–串行時(shí)鐘線,提供所需要的時(shí)鐘信號(hào);
一般來說,大多數(shù)單片機(jī)的JTAG接口和SWDIO接口是復(fù)用的,SWD也是用J-Link工具來實(shí)現(xiàn)的。所以在使用的時(shí)候,只需要在軟件界面做一下選擇,使用SWD方式還是JTAG方式,硬件上無需改動(dòng)。除了J-Link外,意法半導(dǎo)體的ST-Link也是支持SWD模式的。
SWD的接口如上圖所示,可以看出,SWD和JTAG是相互復(fù)用的,由于SWD只需要兩根線所以大大減少了對(duì)單片機(jī)GPIO口的占用,SWD方式也是可以在線調(diào)試的。
?STM32 同時(shí)支持SWD 和 JTAG接口,也即支持的是SWJ-DP 調(diào)試接口協(xié)議,STM32-L4 的SWJ Debug Port 如下圖所示:
從上圖中可以看出,JTAG-DP 與SW-DP 兩個(gè)接口都需要提供Clock 驅(qū)動(dòng)信號(hào),二者的數(shù)據(jù)傳輸引腳不同,SW-DP 接口使用半雙工的SWDIO 引腳傳輸數(shù)據(jù),JTAG-DP 接口使用兩個(gè)單工的JTDI 和JTDO 引腳組成全雙工通信。JTAP-DP 除了時(shí)鐘引腳和數(shù)據(jù)傳輸引腳外,還有個(gè)重要的引腳JTMS 測(cè)試模式選擇引腳,可以控制TAP(Test Access Port) 狀態(tài)機(jī)的切換,JTRST 主要用來對(duì)TAP 狀態(tài)機(jī)進(jìn)行復(fù)位,為可選引腳(因此有四線JTAG 與五線JTAG 之分),JTMS 也可以實(shí)現(xiàn)TAP 狀態(tài)機(jī)的復(fù)位。JTAG-DP 與SW-DP 引腳的功能描述如下:
?二、ISP(In System Programing):在系統(tǒng)編程,可借助MCU廠商預(yù)置的Bootloader 實(shí)現(xiàn)通過板載UART或USB接口燒錄代碼,比如STM32存儲(chǔ)映射Code分區(qū)中的System memory可以預(yù)置廠商的Bootloader,讓MCU支持通過UART下載(不限于UART,具體由廠商預(yù)置Bootloader實(shí)現(xiàn)而定);
我們先來看一下STM32的幾種啟動(dòng)模式:
STM32 有三種Boot modes 開始執(zhí)行代碼:
- Main Flash memory:STM32內(nèi)置的Flash,一般我們使用JTAG / SWD 燒錄代碼都是直接燒錄到這個(gè)存儲(chǔ)區(qū)間,重啟后也直接從這里的代碼開始執(zhí)行;
- System memory:這種模式啟動(dòng)的程序功能是由廠家設(shè)置的,STM32 在出廠時(shí)由ST 在這個(gè)存儲(chǔ)區(qū)間內(nèi)部預(yù)置了一段BootLoader(也即ISP 程序),這段程序出廠后無法修改。廠家提供的BootLoader 一般支持UART 協(xié)議,可以讓我們直接通過串口將程序代碼燒錄到Main Flash memory 中;
- SRAM1:這個(gè)啟動(dòng)模式一般用于程序調(diào)試,假如我只修改了代碼中一個(gè)很小的地方,重新燒錄到Flash比較費(fèi)時(shí),可以從STM32 內(nèi)存中啟動(dòng)代碼,進(jìn)行快速的程序調(diào)試,等程序調(diào)試完成后,再將程序燒錄到Main Flash memory 中。
?Main Flash memory、System memory、SRAM1 的存儲(chǔ)區(qū)間分布如下圖所示:
?從STM32 的啟動(dòng)模式可以看出,ISP 通過USB 接口直接燒錄代碼,主要是靠System memory 中被廠家預(yù)置的Bootloader 代碼提供的UART 協(xié)議實(shí)現(xiàn)的,要想使用System memory 中的ISP 代碼,需要將BOOT0 設(shè)置為高電平、BOOT1 設(shè)置為低電平,然后按下復(fù)位鍵,MCU 從System memory 啟動(dòng)BootLoader,靠ISP 代碼中提供的UART 協(xié)議,用戶可以通過串口將程序代碼燒錄到Main Flash memory 中。通過串口燒錄代碼完成后,需要將BOOT0 設(shè)置為低電平,然后按下復(fù)位鍵,MCU 就可以從剛才燒錄進(jìn)去的代碼處(也即Main Flash memory)開始執(zhí)行了。
?
?借用串口的兩個(gè)流控引腳DTR、RTS 信號(hào),分別控制STM32 的復(fù)位(需要復(fù)位才能切換啟動(dòng)模式)和BOOT0 (從Main Flash memory 啟動(dòng)與從System memory 啟動(dòng)主要看BOOT0 電平高低,跟BOOT1 電平無關(guān)),配合上位機(jī)軟件FlyMcu,就可以通過軟件控制流控引腳DTR 和RTS 的信號(hào)電平,實(shí)現(xiàn)通過軟件控制RESET 和 BOOT0 電平高低的效果。這樣就不再需要用戶來回拔插跳線帽,直接通過軟件比如FlyMcu 自動(dòng)控制RESET 與BOOT0 的電平高低,從而實(shí)現(xiàn)一鍵燒錄功能,對(duì)開發(fā)者燒錄代碼更友好。
上圖FlyMcu 設(shè)置“DTR的低電平復(fù)位,RTS高電平進(jìn)BootLoader” 和“編程后執(zhí)行”,在右側(cè)Log 數(shù)據(jù)中可以看到MCU 復(fù)位、選擇進(jìn)入Bootloader、燒錄程序代碼的過程,待燒錄完成后還會(huì)看到MCU 復(fù)位、選擇進(jìn)入Main Flash memory 開始執(zhí)行代碼的過程。
ISP 使用哪種接口燒錄程序代碼取決于廠商預(yù)置的ISP 代碼支持哪種通訊協(xié)議,UART 算是最簡單且的比較常用的通訊協(xié)議,如果廠商的ISP 代碼支持,ISP 還可以使用SPI、CAN、IIC、USB 等通訊協(xié)議燒錄代碼到Main Flash memory 存儲(chǔ)區(qū)間。廠商的ISP 代碼是怎么預(yù)置到System memory 中的呢?答案正是靠前面介紹的處理器Debug Interface(比如ARM 的JTAG / SWD 接口) 實(shí)現(xiàn)ISP 代碼燒錄的。
如果ISP 指的是MCU / CPU 不用脫離電路板,可以直接通過電路板上預(yù)留的接口燒錄或擦除程序代碼的話,前面介紹ICP 時(shí)提到的直接在電路板上預(yù)留JTAG / SWD 接口、甚至直接將JLINK / STLINK 仿真模塊預(yù)置到開發(fā)板上只留出USB接口,都可以通過電路板上預(yù)留的接口燒錄或擦除程序代碼,雖然仍是通過Debug Interface 燒錄代碼的,卻可以稱之為ISP。
? 三、IAP(In Applicating Programing):在應(yīng)用編程,由開發(fā)者實(shí)現(xiàn)Bootloader功能,比如STM32存儲(chǔ)映射Code分區(qū)中的Flash本是存儲(chǔ)用戶應(yīng)用程序的區(qū)間(上電從此處執(zhí)行用戶代碼),開發(fā)者可以將自己實(shí)現(xiàn)的Bootloader存放到Flash區(qū)間,MCU上電啟動(dòng)先執(zhí)行用戶的Bootloader代碼,該代碼可為用戶應(yīng)用程序的下載、校驗(yàn)、增量/補(bǔ)丁更新、升級(jí)、恢復(fù)等提供支持,如果用戶代碼提供了網(wǎng)絡(luò)訪問功能,IAP 還能通過無線網(wǎng)絡(luò)下載更新代碼,實(shí)現(xiàn)OTA空中升級(jí)功能。
IAP 可以在系統(tǒng)運(yùn)行過程中完成內(nèi)部程序代碼的更新,由Main Flash memory 存儲(chǔ)區(qū)間內(nèi)運(yùn)行的程序自身實(shí)現(xiàn)更新代碼的下載、校驗(yàn)、燒錄等工作。IAP 并不是通過Debug Interface 完成更新代碼燒錄的,自然也需要類似ISP 代碼的Bootloader 完成這些工作,看起來IAP 就相當(dāng)于將ISP 中廠商預(yù)置到System memory 中的Bootloader 搬移到Main Flash memory 中了,MCU / CPU 不再需要切換BOOT Mode,直接從Main Flash memory 啟動(dòng)即可。
將Bootloader 搬移到Main Flash memory 中,最明顯的好處就是Bootloader 的功能可以由開發(fā)者自由實(shí)現(xiàn)(ISP 中廠家預(yù)置到System memory 的Bootloader 出廠后不可修改),如果存儲(chǔ)資源足夠,可以增加很多功能,比如增量更新、空中升級(jí)、數(shù)據(jù)線燒錄、SD卡燒錄、系統(tǒng)恢復(fù)等。
由于Bootloader 主要是在代碼燒錄和更新過程中用到,并不涉及處理業(yè)務(wù)邏輯,需要將Bootloader 和用戶的Application 分割開來,將二者分割最簡單的方式就是將Bootloader 與Application 存放在不同的存儲(chǔ)區(qū)間,而且Bootloader 應(yīng)該放置到Main Flash memory 開始位置,便于上電從Bootloader 代碼開始執(zhí)行,Application 放置到Bootloader 后面。舉例說明,比如Bootloader 占用存儲(chǔ)空間64KB,存放在Main Flash memory 初始地址0x0800 0000 開始的一段存儲(chǔ)區(qū)間內(nèi),將 Application 存放在0x0800 0000 向后偏移Bootloader 占用的64KB 距離處的0x0801 0000 開始的一段存儲(chǔ)區(qū)間內(nèi),同時(shí)要在Bootloader 中設(shè)置要跳轉(zhuǎn)到Application 代碼的起始地址0x0801 0000,這里的地址只是舉了個(gè)例子,Application 存放的起始地址可由開發(fā)者設(shè)定,并能被Bootloader 識(shí)別并跳轉(zhuǎn)過去即可。
IAP 中由開發(fā)者實(shí)現(xiàn)的Bootloader (也稱IAP 程序)是怎樣燒錄到Main Flash memory 存儲(chǔ)區(qū)間的呢?答案自然是前面介紹的ICP 或 ISP 方式,也即通過JTAG /SWD 接口或者ISP 程序?qū)⒂脩舻腂ootloader 燒錄到Main Flash memory 內(nèi)。由于MCU / CPU 上電后默認(rèn)從Main Flash memory 開始執(zhí)行,也即從開發(fā)者實(shí)現(xiàn)的Bootloader 代碼處開始執(zhí)行,處理業(yè)務(wù)邏輯的Application 代碼如何燒錄到對(duì)應(yīng)存儲(chǔ)區(qū)間呢?
Application 代碼既可以使用前面介紹的JTAG /SWD 接口或者ISP 程序燒錄到Main Flash memory 內(nèi)指定地址區(qū)間(記得修改默認(rèn)的燒錄地址,為用戶Bootloader 預(yù)留出空間,如果從默認(rèn)的Main Flash memory 起始地址開始燒錄,將會(huì)覆蓋用戶的Bootloader 代碼,運(yùn)行時(shí)由于Application 代碼修改了中斷向量表偏移地址,不燒錄到設(shè)定地址會(huì)導(dǎo)致指令執(zhí)行錯(cuò)誤),也可以使用IAP 代碼燒錄到Main Flash memory 內(nèi)指定地址區(qū)間。燒錄Application 代碼使用哪種接口,就要在Bootloader 中實(shí)現(xiàn)相應(yīng)的通訊協(xié)議,如果ISP 代碼中不支持想要的通訊協(xié)議,可以在IAP 代碼中添加相應(yīng)的通訊協(xié)議,然后借助IAP 代碼將Application 代碼燒錄到Main Flash memory 內(nèi)指定地址區(qū)間。
IAP 燒錄的應(yīng)用程序代碼在IAP 代碼后面,也即默認(rèn)的Main Flash memory 起始地址向后偏移一段距離之后(假如偏移量64KB,Application 代碼應(yīng)存儲(chǔ)在0x0801 0000 起始的地址區(qū)間內(nèi))。如果通過IAP 程序來燒錄Application 代碼,可以在IAP 程序中控制Application 代碼應(yīng)被存儲(chǔ)的區(qū)間地址,Application 代碼文件可以使用bin 格式的純數(shù)據(jù)文件以減小文件大小;如果使用ISP代碼或JTAG/SWD 接口燒錄Application 代碼,燒錄文件一般使用包含地址信息的Hex格式,以便將代碼數(shù)據(jù)正確燒錄到指定地址區(qū)間。
以Keil MDK 開發(fā)環(huán)境為例,編譯生成hex 文件或者借助JLINK / STLINK 仿真器直接燒錄Application 代碼到指定的地址區(qū)間(也即0x0800 0000 + Offset 起始的地址區(qū)間),相比直接燒錄到Main Flash memory 起始的地址空間應(yīng)該修改哪些配置呢?答案是修改ROM 地址區(qū)間(一般Bootloader 與Application 并不同時(shí)運(yùn)行,可以不用修改RAM 地址區(qū)間),Keil MDK 主要在Target 和Linker 兩個(gè)地方修改ROM 起始地址和區(qū)間大小參數(shù)。以STM32 L475為例,Main Flash memory 的起始地址Start 為0x0800 0000,區(qū)間大小Size 為0x80000(也即512KB),現(xiàn)在IAP 代碼存儲(chǔ)在0x0800 0000 處,占用地址區(qū)間長度為0x10000(也即64KB),Application 代碼應(yīng)存儲(chǔ)在IAP 代碼之后,也即起始地址Start 為0x0801 0000,剩余地址空間大小為0x70000,地址區(qū)間配置界面如下圖示:
?
點(diǎn)擊上圖Linker 界面的“Edit” 按鈕,即可編輯鏈接腳本文件“l(fā)ink.sct”,按照Target 地址區(qū)間配置修改鏈接腳本中的ROM 地址區(qū)間如下:
// .\link.sct
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08010000 0x00070000 { ; load region size_region
ER_IROM1 0x08010000 0x00070000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00018000 { ; RW data
.ANY (+RW +ZI)
}
}
將Application 代碼燒錄到指定的位置(也即IAP 代碼之后)還不足以保證代碼的正常運(yùn)行,首先遇到的問題是MCU/CPU 怎么找到并跳轉(zhuǎn)至Application 代碼處開始執(zhí)行?MCU / CPU 運(yùn)行過程中怎么找到并跳轉(zhuǎn)至中斷、異常等服務(wù)函數(shù)的入口地址?
ARM Cortex 使用中斷向量表來管理main函數(shù)、中斷/異常服務(wù)函數(shù)的入口地址,每個(gè)獨(dú)立的程序代碼都有自己的中斷向量表,某程序所屬的中斷向量表位于該程序代碼的起始地址處(可參考博文:系統(tǒng)啟動(dòng)和中斷管理)。ARM Cortex 中斷向量表的前幾項(xiàng)及中斷服務(wù)程序跳轉(zhuǎn)過程如下圖示:
中斷向量表的前兩項(xiàng)分別保存了MSP與PC的初始值,處理器剛上電復(fù)位后,硬件會(huì)自動(dòng)根據(jù)向量表偏移地址(查詢VTOR向量表偏移量寄存器)找到中斷向量表,硬件會(huì)自動(dòng)從向量表首地址(初始地址0x0000 0000,設(shè)置BOOT Modes從Main Flash memory啟動(dòng)時(shí)則映射到0x0800 0000,設(shè)置BOOT Modes從System memory啟動(dòng)時(shí)則映射到0x1FFF 0000)處讀取數(shù)據(jù)并賦給棧指針SP,然后自動(dòng)從向量表第二項(xiàng)地址處(向量表每一項(xiàng)占用4 字節(jié),也即向量表首地址 + 4 字節(jié)處)讀取數(shù)據(jù)賦給程序計(jì)數(shù)器PC,開始執(zhí)行PC地址上存儲(chǔ)的指令,PC初始值指向復(fù)位向量,所以剛上電后首先執(zhí)行的是復(fù)位指令。
中斷向量表中的異常 / 中斷向量也都是基于中斷向量表首地址偏移一定字節(jié)得到的,我們只需要讓MCU / CPU 能正確找到中斷向量表的首地址就可以讓Application 代碼正確執(zhí)行,中斷向量表首地址是通過查詢VTOR 寄存器獲得的,自然也可以通過設(shè)置VTOR(Vector Table Offset Register)讓MCU / CPU 能找到Application 的中斷向量表,VTOR 寄存器結(jié)構(gòu)如下:
ARM Cortex M3與M4的VTOR 寄存器結(jié)構(gòu)還有些區(qū)別,以M4 為例,要求VTOR 的bit 6:0為0(由于向量表起始地址要求對(duì)齊到2 的整次冪,比如MCU 共使用了31 個(gè)系統(tǒng)異常與中斷向量,也即占用31*4 = 124 字節(jié),對(duì)齊到2 的整次冪就是27 = 128 = 0x80 字節(jié),VTOR 低7 位就是0 了),只有bit 31:7 為向量表偏移值TBLOFF,我們可是使用掩碼將bit 6:0 設(shè)置為0,設(shè)置SCB->VTOR 寄存器的代碼如下:
/* 將中斷向量表起始地址重新設(shè)置為 app 分區(qū)的起始地址 */
#define NVIC_VTOR_MASK 0xFFFFFF80
#define APP_START_ADDR 0x08010000
/* 根據(jù)應(yīng)用設(shè)置向量表 */
SCB->VTOR = APP_START_ADDR & NVIC_VTOR_MASK;
對(duì)于STM32L475 芯片,一共有98 個(gè)異常與中斷向量,中斷向量表占用空間 98*4 = 392 字節(jié),對(duì)齊到2 的整次冪為 29 = 512 = 0x200 字節(jié),因此對(duì)于STM32L475 的Application 代碼及其中斷向量表起始地址應(yīng)設(shè)置為0x200 的整數(shù)倍,也可以將STM32L475 的NVIC_VTOR_MASK 設(shè)置為0xFFFF FE00,每個(gè)芯片支持的中斷向量數(shù)不同,因此需要根據(jù)情況設(shè)置。
為什么我們不使用IAP 代碼時(shí)不需要設(shè)置VTOR 寄存器呢?還記得前面介紹的BOOT Mode 吧,我們?cè)O(shè)置BOOT Modes從Main Flash memory啟動(dòng)時(shí),MCU 硬件會(huì)自動(dòng)從Main Flash memory 起始地址處讀取中斷向量表的值;設(shè)置BOOT Modes從System memory啟動(dòng)時(shí),MCU 硬件會(huì)自動(dòng)從System memory 起始地址處讀取中斷向量表的值。當(dāng)我們使用IAP 代碼管理Application 代碼的燒錄、升級(jí)時(shí),MCU 硬件不會(huì)到Application 代碼起始地址處讀取中斷向量表,默認(rèn)依然從Main Flash memory 起始地址處(也即IAP 代碼起始地址)讀取中斷向量表。這就需要我們?cè)贏pplication 代碼中通過設(shè)置VTOR 寄存器的值,告訴MCU 應(yīng)該到哪去讀取Application 程序的中斷向量表,將Application 代碼的起始地址設(shè)置到VTOR 寄存器,MCU 就可以通過讀取VTOR 的值找到Application 程序的中斷向量表,Application 代碼就可以正確執(zhí)行了。
四、Bootloader 與 OTA
ISP 與IAP 燒錄代碼都用到了Bootloader 程序,不同的是ISP 的Bootloader 是廠家預(yù)置的,功能比較簡單且固定,IAP 的Bootloader 是開發(fā)者自己實(shí)現(xiàn)的,功能比較靈活且豐富。那么,Bootloader 都能實(shí)現(xiàn)哪些功能呢?
Bootloader 實(shí)際上就是一段代碼,跟我們編寫裸機(jī)程序差不多,ISP 代碼比較簡單,以UART Bootloader 為例,主要實(shí)現(xiàn)UART 驅(qū)動(dòng),可以通過UART 通訊協(xié)議傳輸數(shù)據(jù),當(dāng)然也要能夠解析出HEX 文件中的地址信息,將UART 接收到的數(shù)據(jù)寫入到特定的地址區(qū)間。
IC 廠商預(yù)置的ISP 代碼一般只實(shí)現(xiàn)了通過常用的UART 或USB 等通訊協(xié)議燒錄Application 代碼的功能,有些場(chǎng)景我們需要使用其它的通訊接口比如CAN 通訊實(shí)現(xiàn)代碼燒錄與更新,這就需要我們自己實(shí)現(xiàn)IAP 代碼,由IAP 代碼實(shí)現(xiàn)通過CAN 通訊協(xié)議燒錄Application 代碼的功能。如果你對(duì)手機(jī)進(jìn)行過刷機(jī)操作,應(yīng)該了解過fastboot 刷機(jī)功能,fastboot 的功能實(shí)際就是由IAP 代碼實(shí)現(xiàn)的,如果要使用fastboot 功能需要先通過ISP 代碼提供的USB 通訊協(xié)議向CPU 中刷入Bootloader 代碼(一般Bootloader 代碼與Application 代碼一起通過USB 通訊協(xié)議燒錄進(jìn)CPU 中)。
IAP 代碼可以實(shí)現(xiàn)ISP 代碼的功能,但開發(fā)者既然選擇自己實(shí)現(xiàn)Bootloader,IAP 代碼就不只是具有燒錄Application 代碼的功能,更多的是為了升級(jí)代碼,甚至是空中升級(jí)代碼。
我們應(yīng)該已經(jīng)習(xí)慣升級(jí)系統(tǒng)版本或者給系統(tǒng)打補(bǔ)丁解決Bug等,不管是版本升級(jí)還是打補(bǔ)丁,都涉及到在系統(tǒng)運(yùn)行過程中,重新燒錄部分代碼數(shù)據(jù)。如果沒有IAP 代碼,我們只能借助ISP 代碼使用第三方設(shè)備和燒錄工具,完全覆蓋先前的代碼,這對(duì)普通用戶是極不友好的。我們借助IAP 代碼就可以不依賴第三方設(shè)備與燒錄工具,僅靠自身就可以完成版本升級(jí)或打補(bǔ)丁的功能,不管是PC 還是手機(jī)操作系統(tǒng)也都是依靠系統(tǒng)開發(fā)商提供的Bootloader 實(shí)現(xiàn)系統(tǒng)版本或補(bǔ)丁升級(jí)的。
IAP 代碼怎么實(shí)現(xiàn)系統(tǒng)版本升級(jí)的呢?回想我們?cè)赑C 或手機(jī)上升級(jí)應(yīng)用軟件,都是先將軟件安裝包下載到本地存儲(chǔ)介質(zhì)中,然后再運(yùn)行軟件安裝包將軟件執(zhí)行代碼復(fù)制到系統(tǒng)安裝目錄下,也即需要占用存儲(chǔ)介質(zhì)中一定的存儲(chǔ)空間來暫存軟件安裝包。升級(jí)Application 程序版本的過程與此類似,也是將Application 代碼文件暫存到某個(gè)存儲(chǔ)介質(zhì)中(可以是RAM、ROM、SD卡、U盤等存儲(chǔ)介質(zhì)),Bootloader 會(huì)先校驗(yàn)Application 代碼文件的有效性,通過校驗(yàn)后再將Application 代碼從存儲(chǔ)介質(zhì)搬移到特定的存儲(chǔ)區(qū)間(比如Main Flash memory 中IAP 代碼后的存儲(chǔ)區(qū)間)。
如果我們開發(fā)的產(chǎn)品不具備網(wǎng)絡(luò)連接能力,也只能先用電腦下載好固件升級(jí)包,暫存到SD卡或者U盤中,再插到我們的產(chǎn)品上。在IAP 代碼中可以實(shí)現(xiàn)SD卡通訊協(xié)議或USB 通訊協(xié)議,支持從SD卡或U盤讀取固件升級(jí)包,校驗(yàn)通過后搬移到Main Flash memory 的特定存儲(chǔ)區(qū)間,實(shí)現(xiàn)Application 版本升級(jí)的目的。
隨著物聯(lián)網(wǎng)設(shè)備的普及,開發(fā)的產(chǎn)品越來越多支持網(wǎng)絡(luò)訪問能力,我們可以將Application 版本升級(jí)過程設(shè)計(jì)的更簡單。直接借助產(chǎn)品的網(wǎng)絡(luò)訪問能力,從特定服務(wù)器將系統(tǒng)升級(jí)包下載到本地存儲(chǔ)介質(zhì)特定分區(qū)內(nèi)(可以是RAM、片內(nèi)Flash、片外Flash、SD卡等本地存儲(chǔ)介質(zhì)),校驗(yàn)通過后再將代碼搬移到Main Flash memory 的特定存儲(chǔ)區(qū)間。如果系統(tǒng)升級(jí)包是通過無線網(wǎng)絡(luò)(比如移動(dòng)蜂窩網(wǎng)、WLAN、WPAN等無線協(xié)議)下載的,這種通過無線網(wǎng)絡(luò)下載升級(jí)包,并通過Bootloader 實(shí)現(xiàn)版本升級(jí)的技術(shù)稱為OTA(Over-the-air programming)空中升級(jí)或空中編程技術(shù)。
要具備OTA 空中升級(jí)能力,只有負(fù)責(zé)固件升級(jí)包校驗(yàn)升級(jí)的Bootloader 分區(qū)和負(fù)責(zé)業(yè)務(wù)邏輯的Application 分區(qū)是不夠的,還需要有暫存固件升級(jí)包的Downloader 分區(qū)。每次MCU / CPU 上電啟動(dòng)都從Bootloader 開始執(zhí)行代碼,Bootloader 會(huì)到Downloader 分區(qū)檢查是否有可升級(jí)的固件包,如果沒有則直接跳轉(zhuǎn)到Application 代碼執(zhí)行,如果有則對(duì)固件升級(jí)包校驗(yàn)通過后,將新的固件代碼搬移到Application 分區(qū),完成Application 代碼更新后,再跳轉(zhuǎn)到新的Application 代碼執(zhí)行。
?
為了增強(qiáng)系統(tǒng)更新包網(wǎng)絡(luò)傳輸?shù)陌踩?,防止被網(wǎng)絡(luò)攻擊者篡改,可以對(duì)通過網(wǎng)絡(luò)下載的固件升級(jí)包先進(jìn)行加密認(rèn)證(包括數(shù)據(jù)加密、數(shù)據(jù)完整性校驗(yàn)、客戶端與服務(wù)器身份校驗(yàn)等),Bootloader 就要能對(duì)固件升級(jí)包進(jìn)行解密和認(rèn)證校驗(yàn)。為了減少網(wǎng)絡(luò)傳輸開銷(也即減少消耗的網(wǎng)絡(luò)流量),可以對(duì)固件升級(jí)包進(jìn)行壓縮后傳輸,Bootloader 就要能夠?qū)碳?jí)包進(jìn)行解壓縮。
有時(shí)候我們只是想升級(jí)Application 的部分代碼,如果將全部代碼下載后升級(jí)比較耗費(fèi)資源且效率較低,這時(shí)候就需要Bootloader 提供只更新部分代碼的能力。將更新代碼做成差分升級(jí)包(相當(dāng)于補(bǔ)丁文件),通過網(wǎng)絡(luò)將差分升級(jí)包下載到Downloader 分區(qū),Bootloader 對(duì)其解壓縮、解密、校驗(yàn)通過后,將要更新的那部分代碼搬移到Application 特定的存儲(chǔ)區(qū)間內(nèi)(差分升級(jí)包包含了要更新代碼的地址信息,Bootloader 可以解析出地址信息,并將更新代碼搬移到目標(biāo)存儲(chǔ)區(qū)間)。差分升級(jí)包一般比整個(gè)固件升級(jí)包占用的存儲(chǔ)空間小得多,可以極大節(jié)省存儲(chǔ)空間和網(wǎng)絡(luò)流量,也為整個(gè)升級(jí)過程節(jié)約了不少時(shí)間,效率更高。
使用OTA 空中編程技術(shù)對(duì)產(chǎn)品進(jìn)行固件升級(jí)對(duì)用戶是比較友好的,只要能訪問網(wǎng)絡(luò),就可以實(shí)現(xiàn)一鍵升級(jí)功能。但Application 代碼運(yùn)行過程中有可能會(huì)出現(xiàn)一些預(yù)料之外的Bug,比如某些重要文件被刪除或篡改、被網(wǎng)絡(luò)攻擊、中病毒、垃圾過多耗盡資源等,這就需要具備一鍵恢復(fù)能力。PC 和手機(jī)上都提供了recovery 恢復(fù)功能,該功能是怎么實(shí)現(xiàn)的呢?原理跟升級(jí)類似,可以再劃分出一個(gè)recovery 分區(qū),將出廠的軟件版本壓縮后存放到該分區(qū)內(nèi),如果系統(tǒng)運(yùn)行出現(xiàn)了錯(cuò)誤,可以將recovery 分區(qū)內(nèi)的代碼搬移到Application 分區(qū),相當(dāng)于實(shí)現(xiàn)了恢復(fù)出廠設(shè)置的功能。recovery 分區(qū)內(nèi)也不一定一直存儲(chǔ)出廠版本,可以同步更新為前一個(gè)比較穩(wěn)定的系統(tǒng)版本,使用recovery 恢復(fù)功能就相當(dāng)于回退到了前一個(gè)穩(wěn)定版本,即便系統(tǒng)因?yàn)橹胁《净蚓W(wǎng)絡(luò)攻擊等特殊情況,也能恢復(fù)過來繼續(xù)正常使用。
Bootloader 除了具備固件升級(jí)和固件恢復(fù)外,還應(yīng)針對(duì)升級(jí)過程中突然中斷(比如斷電了)的情況妥善處理,盡量減少返廠的機(jī)會(huì)。Bootloader 該怎么應(yīng)對(duì)升級(jí)突然被打斷的情況呢?正常情況下RAM 中的數(shù)據(jù)斷電后就消失了,我們可以借鑒斷點(diǎn)續(xù)傳技術(shù)的實(shí)現(xiàn)方案,Bootloader 在升級(jí)代碼過程中,在ROM 中同步記錄升級(jí)進(jìn)度與狀態(tài),可以讓MCU 再次上電從Bootloader 啟動(dòng)時(shí),從ROM 中讀取升級(jí)進(jìn)度與狀態(tài),繼續(xù)完成先前的升級(jí)過程。
?文章來源:http://www.zghlxwxcb.cn/news/detail-762927.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-762927.html
到了這里,關(guān)于STM32 ICP、ISP、IAP、Bootloader、SWD、JTAG究竟是什么?它們之間有什么關(guān)系?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!