IAP ( In Application Programming )功能為產品軟件升級提供了一個方便快捷的接口。用戶可以通過串口、USB、CAN總線[1]而無需使用編程器即可實現產品的軟件更新,甚至可以通過以太網[2]或者無線網絡[3]實現產品軟件的遠程升級,大大方便了產品的功能迭代,提升了產品的易用性。
Bootloader(以下簡稱Boot)俗稱引導程序,是實現IAP功能的核心。Application(簡稱App)即用戶應用程序,負責實現產品功能。Boot和App這兩個獨立的程序在同一芯片中運行,有各自的中斷向量表,但中斷號相同。在由Boot進入到App后,如何使App下的中斷能正確響應?這是所有IAP都需要面對的問題,而解決問題的關鍵在于實現中斷向量的重定位。不同MCU根據自身硬件特性不同,實現中斷向量重定位的方法存在著重大區別。
1Cortex-M3 架構MCU中斷向量重定位
Nested Vectored Interrupt Controller(NVIC)即嵌套向量中斷控制器,是Cortex-M內核的一部分,它管理和處理所有的異常和中斷。Cortex-M3中的NVIC,在地址0xE000 ED08處是一個Vector Table Offset Register(VTOR)即中斷向量表偏移量寄存器,通過修改它的值就能重新定位向量表[4]。
進入App運行后,只要在使能中斷功能前設置VTOR寄存器值為App起始地址即可實現中斷向量表的重定位。參考文獻[5]分析了Cortex-M3 單片機中斷向量重定位的執行過程。Cortex-M4內核中也有VTOR寄存器,因而在這些內核MCU上實現中斷向量的重定位十分便捷、高效。
2Cortex-M0 架構MCU中斷向量重定位
適中的性能、極低的能耗、低廉的價格使得Cortex-M0架構MCU應用非常廣泛,尤其是在物聯網傳感器、電動工具、電子測量、家電行業[6]。因為Cortex-M0中的NVIC沒有VTOR寄存器,所以此類型的MCU中斷向量重定位變得不容易。
2.1STM32F030中斷向量重定位
STM32F030基于Cortex-M0架構,廠商為該系列的MCU賦予了一個特性:啟動地址支持重映射。通過設置芯片Boot引腳電平,使得程序可從內部Flash或內部RAM啟動。芯片的SYSCFG_CFGR1寄存器也保存了設置狀態,通過修改這個寄存器的值,即可重新引導程序[7]。
基于地址可以重新映射的特性,在App使能中斷功能前,將中斷向量表復制到內部RAM的起始地址,再設置SYSCFG_CFGR1寄存器,使其從RAM中啟動,即可以實現中斷向量的重定位。
2.2普通Cortex-M0架構MCU實現IAP的困境
并非所有Cortex-M0內核的單片機都支持地址重映射,因為這并不是內核功能的一部分[8]。市場上存在大量使用Cortex-M0內核的專用MCU,如某些電機控制的專用MCU。它們不像STM32F030那樣具備地址重新映射的特性,因此不能使用2.1中的方法實現中斷向量的重定位。
因此,實現中斷向量的重定位成為此類基于Cortex-M0架構MCU實現IAP功能的最大障礙。相關研究資料較少,參考文獻[9]給出了一種基于RAM的中斷跳轉方法,不過效率有待提升。
3中斷向量重定位的通用方法
本文給出了實現中斷向量重定位的一種通用方法。該方法不依賴于MCU自身硬件特性,而是基于純軟件實現。同時結合STM32F030和Keil開發環境,詳細介紹了該方法的原理,給出了相關代碼。
3.1梯子函數
給每一個中斷向量增加這樣一段程序:該程序負責獲取App中對應中斷服務函數的入口地址,然后跳轉到該地址運行,從而運行App的中斷服務程序。這種功能的程序像是從Boot中斷向量通向App中斷服務函數的梯子,因此稱它為“梯子函數”。Boot中斷向量表中的每一個中斷向量保存的是對應梯子函數的入口地址。
3.2中斷向量重定位過程
圖1給出了基于該方法進行中斷向量重定位的跳轉流程圖。App運行期間產生中斷,仍會從Boot中斷向量表取得相應的中斷向量。不過此時實際獲取的是梯子函數的入口地址,然后借助梯子函數實現向App中斷服務程序跳轉的目標。
圖1中斷向量表重定位通用方法
以RTC中斷為例,當App運行時產生了該中斷,則會從Boot的中斷向量表找到RTC中斷的梯子函數入口地址并跳轉到該地址運行,如箭頭①和②所示。RTC中斷的梯子函數則會從App中的RTC中斷向量加載對應的RTC中斷服務程序的入口地址,如箭頭③所示。最后跳轉到該地址,運行App的RTC中斷服務程序,如箭頭④所示。
3.3梯子函數的實現
梯子函數是實現從Boot中斷向量到App中斷服務程序跳轉的關鍵。程序采用匯編代碼實現,一個中斷向量對應著一個梯子函數。部分梯子函數編寫的示例如下:
同樣以RTC_IRQHandler為例,0x0800 2000為App的起始地址,對應圖1中APP_BASE的值。0x48為RTC中斷向量的偏移地址。Line7將RTC中斷向量偏移地址加載到r0寄存器。Line8將App的RTC中斷處理函數地址加載到r1寄存器。Line9通過bx指令實現跳轉到App的RTC_IRQHandler中斷服務程序入口處的目標。
通過在Boot中為各個中斷向量設置梯子函數,借助梯子函數的橋梁作用實現中斷向量表的重定位?;谠摲椒ㄔ赟TM32F030上進行了IAP功能驗證,App的中斷功能運行正常,驗證了這一方法的可行性。
4 中斷向量重定位改進方法1
4.1存在的問題
一個梯子函數需要兩條ldr指令和一條bx指令,分別需要2個和3個指令周期[10],因此一個梯子函數共需要7個指令周期。此外Flash的時鐘頻率一般比CPU時鐘低很多。如STM32F030的CPU時鐘頻率高于24 MHz時,訪問Flash需要插入一個等待周期[11]。
綜上,進入App中斷服務函數運行前,將會引入較大的時間開銷。當要求中斷能快速響應或者存在諸如ADC采樣之類的高頻中斷,這種中斷向量重定位方法會引發系統性能的明顯下降,為此需要對中斷向量重定位的方法進行改進。
4.2改進原理
改進分為兩方面:一是減少梯子函數所需的指令,二是將梯子函數移到內部RAM中運行。
Boot與App中各有一份梯子函數用于中斷向量的重定位。Boot中的梯子函數用于對無速度要求的中斷向量重定位,其工作原理和執行效果與前文相同。App中的梯子函數為需要降低中斷響應延遲,提高中斷處理性能的中斷重定位。改進方法1中斷向量表重定位執行過程如圖2所示。
圖2改進方法1中斷向量表重定位執行過程
仍以RTC_IRQHandler中斷為例,此時該中斷向量的梯子函數RTC_IRQHandler_App位于RAM中,且地址固定為0x2000 0001。同時Boot中對應RTC_IRQHandler中斷向量的單元保存了該地址。當App運行過程中發生了RTC中斷時,MCU會從Boot中的RTC_IRQHandler中斷向量取得0x2000 0001地址,并跳轉到App下RTC中斷的梯子函數入口運行,對應箭頭①和②。梯子函數會從App的中斷向量表中取得RTC_IRQHandler中斷服務函數地址,如箭頭③所示,最終跳轉到App的RTC中斷服務程序入口處運行,如箭頭④所示。
4.3App中的梯子函數
App所使用的梯子函數示例如下:
其中,Line1定義了名為“ladder_app”的代碼段。Lin6定義了RTC_IRQHandler_App函數,共兩條匯編指令。首先將App下的RTC_IRQHandler中斷服務函數地址加載到R0寄存器中,接著跳轉到該地址運行。相比于改進之前,此時只需要LDR和BX兩條指令,總計只需要5個指令周期。同時該段代碼在RAM中運行,不受Flash等待周期限制。
4.4App的分散加載設置
通過分散加載可使得APP中的梯子函數始終位于RAM固定地址,而與具體的應用程序無關。STM32F030在Keil下的分散加載文件如下:
其中Line10將“ladder_app”代碼段加載到0x2000 0000地址,長度為128字節。若App中梯子函數較多,則預留空間需要相應增大,反之亦然。
梯子函數的入口地址可以從工程編譯成功后的map文件獲取。如圖3所示,RTC_IRQHandler_App函數的入口地址為0x2000 0001,這就是前文Boot中RTC_IRQHandler向量保存的地址來源。
圖3 梯子函數與中斷服務函數入口地址
5中斷向量重定位改進方法2
前文討論了將梯子函數搬移到RAM中運行,從而大幅降低進入用戶中斷服務程序的時間開銷的改進方法。本節討論再改進的方法,進一步壓縮梯子函數的時間開銷,提高進入中斷程序的效率。
5.1梯子函數的改進
經過改進的梯子函數代碼如下:
可以看出,只需要通過一條B指令,就可以跳轉到中斷服務函數入口。該指令執行只需要3個時鐘周期,進一步降低了梯子函數運行所需要的時間開銷。
B指令是相對跳轉指令,用于無條件跳轉,其支持跳轉地址范圍為PC-2046~PC+2046[4]。因此中斷服務函數必須也位于內部RAM中,且距對應的梯子函數的跳轉指令地址必須在2046字節之內。這一條件是容易滿足的,畢竟不是所有的中斷服務程序都需要這么做,而只是個別時間敏感、高頻的中斷需要按照這種方法處理。
5.2中斷服務函數約束條件
為實現中斷處理函數的地址約束,在編寫相關中斷處理函數時,需要添加約束屬性。通過為函數設置section屬性將中斷服務程序放入自定義名稱為“ramfunc_isr”的輸入段。除此之外,與普通的中斷處理函數無其他差別。如在Keil環境下,對于RTC中斷處理函數寫法如下:
5.3分散加載文件
改進方法2的分散加載文件設置如下:
與改進方法1的分散加載文件相比,多了Line12的內容,即將“ramfunc_isr”段的內容從地址0x2000 0080開始放置。
圖4給出了map文件的部分內容,可以看出,梯子函數RTC_IRQHandler_App入口地址為0x2000 0001,Timer3_IRQHandler_App入口地址為0x2000 0003。此時App的一個中斷梯子函數占用存儲空間大小僅為2字節。實際的中斷處理函數的入口地址分別為0x200 00081和0x2000 008d,均位于RAM中,緊接在梯子函數之后,相對地址也遠小于2046 B,滿足該改進方法的使用要求。
圖4 梯子函數與中斷服務函數入口地址
6結 語
表1對文中提出的中斷向量重定位的通用方法及其兩種改進方法進行了對比,總結了3種方法的各自特點,實際上3三種方法可以混合使用。比如將高頻的ADC采樣中斷使用改進方法2進行ADC中斷向量的重定位,此時ADC中斷額外的時間開銷最小,同時由于該中斷服務程序在RAM中運行,性能也將大幅提高。將中頻的定時器中斷使用改進方法1進行中斷向量重定位,其他普通的中斷向量采樣通用方法進行重定位。
表1 中斷向量重定位3種方法對比
基于本文提出的中斷向量表重定位方法,在STM32F030和Keil開發環境下進行了驗證,結果正確。此外,在其他品牌的基于Cortex-M0內核的MCU上進行了驗證,也取得了成功。目前基于該方法實現的IAP功能已經在產品上批量使用,效果較好。
文中提出的中斷向量重定位的方法雖然是以Cortex-M0內核的MCU為對象進行討論和測試的,但是其不依賴于硬件的特殊性,因此也可以在其他內核的MCU上進行推廣應用。
審核編輯:湯梓紅
-
mcu
+關注
關注
146文章
16991瀏覽量
350310 -
控制器
+關注
關注
112文章
16203瀏覽量
177403 -
嵌入式
+關注
關注
5068文章
19019瀏覽量
303265 -
中斷
+關注
關注
5文章
895瀏覽量
41393 -
Cortex-M0
+關注
關注
4文章
124瀏覽量
38640
原文標題:Cortex-M0中斷向量重定位的高效方法
文章出處:【微信號:麥克泰技術,微信公眾號:麥克泰技術】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論