在做stm32 iap升級固件的時(shí)候通常需要多份中斷向量表。比如bootloader的中斷向量表在0x00000000位置,應(yīng)用程序的中斷向量表則會放在flash的另一個(gè)地方或者是放在RAM中運(yùn)行。
要維護(hù)向量表位置就需要用VTOR這個(gè)東西,那么就要先從VTOR來聊聊, 先弄清這個(gè)東西又是干嘛的。
VTOR是arm內(nèi)核的一個(gè)寄存器,叫做中斷向量偏移量寄存器。當(dāng)系統(tǒng)上電啟動(dòng)的時(shí)候CPU會從先找到中斷向量表的位置,然后從表中找到復(fù)位中斷Reset_Handler,而main函數(shù)的執(zhí)行實(shí)際上就是在復(fù)位中斷函數(shù)中的。如下匯編代碼就是復(fù)位中斷服務(wù)函數(shù),該函數(shù)在啟動(dòng)文件中定義。在Reset_Handler 中會執(zhí)行__main(),而main函數(shù)又是被__main()調(diào)用了。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
前面復(fù)習(xí)一下ARM處理器啟動(dòng)到執(zhí)行main的一個(gè)大概流程。再回歸正題繼續(xù)探討這個(gè)VTOR。當(dāng)來一個(gè)中斷時(shí),cpu就會從0x0000000+VTOR位置找到中斷向量表,然后再查表跳轉(zhuǎn)到對應(yīng)的中斷服務(wù)函數(shù)去執(zhí)行。所以你代碼里面存在多份中斷向量表是可以的,只需要?jiǎng)討B(tài)改變VTOR的值就可以了。
APP的中斷向量放在flash中:
如下圖所示,在運(yùn)行bootloader的時(shí)候用的是他自己的bootloader,當(dāng)從bootloader跳轉(zhuǎn)到app以后就需要用app的向量表了。所以進(jìn)入APP的首要任務(wù)就是設(shè)置VTOR值為0x0x8001000,再產(chǎn)生中斷的時(shí)候讓cpu去app的向量表里找中斷服務(wù)函數(shù)入口。
所以從在app中重定義向量表是不是很簡單。但是有個(gè)前提,就是要有VTOR寄存器。實(shí)際上,并不是所有stm32都帶有VTOR的。準(zhǔn)確的說是因?yàn)锳RM-CORTEX-M0內(nèi)核的芯片沒有,所以stm32F0系列所采用M0內(nèi)核的芯片就沒有VTOR。但是還有需要注意的就是L0系列使用的M0+內(nèi)核和M0內(nèi)核又是不同的,是有VTOR的。
這就意味著stm32F0系列沒有辦法使用這種簡單的修改VTOR的方式重新定位APP的中斷向量表。那肯定還有其他思路,就是稍微麻煩一點(diǎn)。
中斷向量放在RAM中:
那就是把中斷向量表放在RAM中去,并且針對F0沒有VTOR的還必須把中斷向量表拷貝到RAM的起始地址。
為什么這樣做,因?yàn)榍懊嫖覀兲岬竭^CPU默認(rèn)會認(rèn)為0x00000000處放的就是向量表。那么我們換種思路可以把RAM的地址映射到0x00000000處。這個(gè)通過配置SYSCFG寄存器的MEM_MODE就可以把RAM地址映射到0x00000000處。
這時(shí)候再進(jìn)入到APP以后首要任務(wù)就是把APP的中斷向量表拷貝到RAM的起始地址,并且修改MEM_MODE位。
在代碼里面比較簡單的做法就是在ram起始地址處定義一個(gè)數(shù)組,上電以后把向量表拷貝到這個(gè)數(shù)組中。如下代碼是在MDK中定義的方法,在IAR或者GCC定義的方式會有區(qū)別。
__IO uint32_t vector_t[48] __attribute__((at(0x20000000)));
但是要編譯通過還需要在mdk配置里面把ram的起始地址設(shè)置為0x200000c0,前面的0xc0的空間騰出來存放定義的這個(gè)數(shù)組。
有VTOR的系列向量表放在RAM中
stm32F0系列內(nèi)核決定了即便把向量表放在RAM中也只能放在RAM的起始位置而不能任意放。但是有VTOR的型號就可以隨便放。這樣分配存放向量表的數(shù)組也可以不用定位在0x20000000位置了??梢匀缦路绞蕉x:
__align(256) uint32_t vector_t[48];
可以看到雖然沒有了必須放在ram起始地址的限制,但是還是要遵守一定的規(guī)則。就是對齊有要求的。比如L0系列有48個(gè)中斷向量,一共占用內(nèi)存為48*4=192bytes。擴(kuò)大為2的整次方為256:28=256。所以就要求向量存儲的地址必須是256對齊的。存放在0x0或者0x20000100都可以滿足要求。
另外這種方式雖然更靈活了一些,但是卻造成了一定RAM空間的浪費(fèi)。我在這樣定義編譯以后查看MAP文件如下,紅色的區(qū)域空出來的一段內(nèi)存空間就會被浪費(fèi)掉:
關(guān)于0X00000000地址
前面說過默認(rèn)cpu會從0x00000000地址來取向量表,那么stm32的flash都是從0x8000000地址開始的,這時(shí)候不設(shè)置VTOR偏移為什么也可以正常運(yùn)行。實(shí)際上當(dāng)從用戶flash啟動(dòng)的時(shí)候,從0x8000000或者0x00000000訪問的都是同一片區(qū)域。所以cpu從0x0取向量表相當(dāng)于取的就是0x8000000地址處的數(shù)據(jù)。
更進(jìn)一步理解,stm32通過配置boot腳(或者SYSCFG中MEM_MODE位)有三種啟動(dòng)模式選擇,這三種模式的本質(zhì)就是看把那個(gè)區(qū)域重映射為0x00000000地址。這樣CPU取第一條指令就是從哪里?。?/p>
- 從用戶flash區(qū)啟動(dòng),用戶flash起始地址被映射到0x00000000上
- 從系統(tǒng)flash區(qū)啟動(dòng),系統(tǒng)flash起始地址被映射到0x00000000上,上電就執(zhí)行內(nèi)置的bootloader
- 從RAM區(qū)啟動(dòng),RAM起始地址被映射到0x00000000上,這時(shí)候你再回過去看我剛才說的F0無VTOR寄存器實(shí)現(xiàn)IAP就是這樣的思路。向量表放在了RAM區(qū)域的起始地址。
(正文已結(jié)束)
推薦閱讀:每日江蘇
免責(zé)聲明及提醒:此文內(nèi)容為本網(wǎng)所轉(zhuǎn)載企業(yè)宣傳資訊,該相關(guān)信息僅為宣傳及傳遞更多信息之目的,不代表本網(wǎng)站觀點(diǎn),文章真實(shí)性請瀏覽者慎重核實(shí)!任何投資加盟均有風(fēng)險(xiǎn),提醒廣大民眾投資需謹(jǐn)慎!