(转载)关于IAP与APP互相跳转的实现
最近一個項目用到了IAP功能,在21IC看到的這個文章很有幫助,分享一下
關于IAP與APP互相跳轉的實現
?
首先,在您動手做這個實驗之前,先要弄清除咱倆的軟硬件有什么不同:
1.?我的CPU是STM32F103ZET6,里面有512K的FLASH,您的CPU如果是其它類型,也不要緊,只是在程序里面,地址上限可能不一樣。但是,個人覺得,最好能用256K以下的FLASH。
2.?我的外部存儲介質是U盤,如果您的外部存儲介質是SD卡,那也應該一樣用,只是它們必須是FAT16,FAT32文件系統。如果您的板上沒有外部存儲介質,那也能做跳轉實驗,只是不能做加載APP實驗。
3.?我的仿真器是JLINK7,如果您的仿真器是其它的,估計也沒多大問題,只要您會用它就行了。什么?沒有仿真器,那還是別做這個實驗吧,出錯了沒法調試。
4.?我的開發環境是RVMDK?3。7,STM庫是V2。03。使用其它開發環境的話,您要是能找到MDK中的設置對應到您那里怎么設置,估計也沒問題。至于庫嘛,您現在是用哪個就哪個吧,全部包在您的工程里,沒問題的。
?
好了,開始啦。
先找個你以前調好的工程,當然,最好是非常可靠的,內容很精彩的,帶液晶顯示的,這樣比較容易知道你后面有沒有調好。這個工程還最好是在FLASH里面運行的,如果不是,要將它改回來。
至于什么開發文檔,太麻煩了,不用看。我之前看了STM的IAP應用筆記AN2557,就覺得一個字“亂”,特別是心里還沒譜的時候,更是越看越糊涂,這么大個工程,到最后對我有幫助的,就是一小段,就是如何擦除,如何編程那小段。當然,STM32的庫還是非常有用的,如果不用庫的話,學習、工作進度會慢很多。
說多啦,找好工程沒有?找好工程咱就開工了。將這個工程復制兩份,一份命名為IAP,一份命名為APP。
?
第一步:規劃好你兩個程序的存放位置。
IAP程序肯定是從0X08000000開始的,因為它是引導程序。將IAP程序放在0X08000000-0X0800FFFF的位置,給它64K空間,足夠了。
APP程序從0X08010000-0X0807FFFF,給它448K空間。
如果您的CPU不同,那APP程序的空間小一點,也沒問題。
?
?
第二步:制作你的APP程序。
1.?將程序定位在0X08010000開始的位置。
點魔術棒,打開目標選項設置。
選Target選項卡,IROM1改成從0X08010000開始,尺寸0X00070000;
Debug選項卡,Load?Application?at?Startup打上勾,Run?to?main()打上勾;
Utilitiles選項卡,點settings按紐,彈出Flash?download卡,Erase?sectors打上勾,點你的編程算法,將底下的的起始地址改成0X08010000,尺寸0X00070000。
2.?制作一個RunInFlashOffset.ini文件。文件內容為:
SP?=?_RDWORD(0x08010000);???????????//?Setup?Stack?Pointer
PC?=?_RDWORD(0x08010004);???????????//?Setup?Program?Counter
目的是在用JLINK調試的時候,引導程序運行。
點魔術棒,打開目標選項設置。
選Debug選項卡,Initialization?File:項,選擇上面的RunInFlashOffset.ini。?
?
3.?為了從IAP程序跳來運行APP的時候正常開始,初始化時要恢復RCC為復位狀態,恢復NVIC為復位狀態。
在你的RCC初始化部分,第一句加上:
RCC_DeInit();
在你的NVIC初始化部分,第一句加上:
NVIC_DeInit?();
4.?重定位中斷表到0X08010000位置。
在上面NVIC_DeInit?();后面加上:
NVIC_SetVectorTable?(NVIC_VectTab_FLASH,?0x00010000);
如果原來有其它的定位語句,將它刪掉。
5.?編寫跳轉IAP函數:
/**************************************************************************************************
函數:?運行IAP程序.
輸入:?無
返回:?無.不再返回.
說明:???由于APP是在IAP的基礎上運行的,因此,IAP一定是有效的,這里不再作IAP有效性檢查.
**************************************************************************************************/
#define?IAP_ADDR????????0X08000000
void?IapProgramRun(void)
{
????INT32U??IapSpInitVal;???????????//IAP程序的SP初值.
????INT32U??IapJumpAddr;????????????//IAP程序的跳轉地址.即,IAP程序的入口.
????void????(*pIapFun)(void);???????//定義一個函數指針.用于指向APP程序入口.
????
????NVIC_DeInit?();?????????????????????????????????//恢復NVIC為復位狀態.使中斷不再發生.
????
????IapSpInitVal?=?*(INT32U?*)IAP_ADDR;?????????????//取APP的SP初值.
????IapJumpAddr?=?*(INT32U?*)(IAP_ADDR?+?4);????????//取程序入口.
????
????__MSR_MSP?(IapSpInitVal);???????????????????????//設置SP.
????pIapFun?=?(void?(*)(void))IapJumpAddr;??????????????//生成跳轉函數.
????(*pIapFun)?();??????????????????????????????????//跳轉.不再返回.
?
}
?
6.?編寫在一定條件下跳轉IAP的部分。比如按下某個鍵,就跳到IAP去。
完成上述幾步后,編譯調試,用JLINK調試,可以直接運行的,跟你原來的工程應該沒區別。有問題的話,將它解決。
?
?
第三步:制作您的IAP程序。
1.?將程序定位在0X08000000開始的位置。如果您的程序本來就是在這個位置的,不用改了。
點魔術棒,打開目標選項設置。
選Target選項卡,IROM1改成從0X08000000開始,尺寸0X00010000;
Debug選項卡,Load?Application?at?Startup打上勾,Run?to?main()打上勾;
Utilitiles選項卡,點settings按紐,彈出Flash?download卡,Erase?sectors打上勾,點你的編程算法,將底下的的起始地址改成0X08000000,尺寸0X00010000。
2.?為了從APP程序跳回來運行IAP的時候正常開始,初始化時要恢復RCC為復位狀態,恢復NVIC為復位狀態。
在你的RCC初始化部分,第一句加上:
RCC_DeInit();
在你的NVIC初始化部分,第一句加上:
NVIC_DeInit?();
3.?重定位中斷表到0X08000000位置。
在上面NVIC_DeInit?();后面加上:
NVIC_SetVectorTable?(NVIC_VectTab_FLASH,?0x0);
如果原來有其它的定位語句,將它刪掉。
4.?編寫在一定條件下跳轉APP的部分。比如按下某個鍵,就跳到APP去。
5.?編寫跳轉APP函數:
#define??APP_ADDR????????????????0X08010000
OP_RESULT?AppProgramRun(void)
{
????INT32U??AppSpInitVal;???????????//App程序的SP初值.
????INT32U??AppJumpAddr;????????????//APP程序的跳轉地址.即,APP程序的入口.
????void????(*pAppFun)(void);???????//定義一個函數指針.用于指向APP程序入口.
????
????AppSpInitVal?=?*(INT32U?*)APP_ADDR;?????????????//取APP的SP初值.
????if?(AppSpInitVal?&?0XFFFF?0000?!=?0X20?00?00?00)????//APP未寫入.不能跳.
????{
????????FaceEnterDialog?(&OpFailDialog);
????????return?OP_FAIL;
????}
????AppJumpAddr?=?*(INT32U?*)(APP_ADDR?+?4);????????//取程序入口.
????if?((AppJumpAddr?&?0X?FF?F8?00?00)?!=?0X?08?00?00?00)???//APP無效.不能跳.
????{
????????FaceEnterDialog?(&OpFailDialog);
????????return?OP_FAIL;
????}
????
????NVIC_DeInit?();?????????????????????????????????//恢復NVIC為復位狀態.使中斷不再發生.
????__MSR_MSP?(AppSpInitVal);???????????????????????//設置SP.
????pAppFun?=?(void?(*)(void))AppJumpAddr;??????????//生成跳轉函數.
????(*pAppFun)?();??????????????????????????????????//跳轉.不再返回.
?
????return?OP_SUCCESS;
}
?
?
完成上述幾步后,編譯調試,OK。
?
?
第四步:雙程序調試:
1.?用仿真器運行IAP程序,然后按下按鍵,轉到APP去。如果你正常轉到APP,說明成功。不能的話,用仿真器跟一下,把問題解決。
2.?用仿真器運行APP程序,然后按下按鍵,轉到IAP去。如果你正常轉到IAP,說明成功。不能的話,用仿真器跟一下,把問題解決。
3.?用仿真器運行IAP程序,然后按下按鍵,轉到APP。
在APP中又按下按鍵,轉回IAP。如此反復。
可以在IAP第一句設個斷點,每次轉回來的時候,都應該會停在那里的。
?
注意:在跳到另一個程序中運行的時候,要停止不能直接點“停止調試按紐”,就是那個放大鏡一樣的按紐,否則MDK立馬出錯退出。要停止的話,要先打開反匯編觀察窗口,然后按下“停止”按紐,就是左上角紅圓圈里一把叉那個,
再按下“停止調試按紐”。
?
第五步:在IAP中加載APP。
如果你的板子上沒有USB,或都SD卡,這后面的就做不了了。
1.?改IAP程序,加上加載APP程序功能。就是按下某個鍵時,從U盤讀取APP程序,并把它寫到FLASH中。這個參考附件。
2.?在APP程序中,選擇輸出HEX文件。目前來說,HEX文件是比較方便處理的文件。
點魔術棒,打開目標選項設置。
選Output選項卡,Create?HEX?File打上勾。
?
編譯,生成HEX文件。
3.?把APP。HEX拷到U盤中,然后用IAP程序加載。
?
第六步:讓IAP區分是復位運行,還是從APP轉過來運行的。
打開你的啟動文件(我這里是stm32f10x_vector.s),看一下它里面棧空間是多大,堆空間是多大。在IAP程序主函數第一句設個斷點,記下此時的SP值,一般這個值比?棧+堆+全局變量還要大一些。在這個值+8之上的內部RAM空間,是程序用不上的。所以可以讓APP程序在RAM空間的頂端設置一個標志,然I后讓AP程序去根據這個標志來區別復位運行、從APP轉過來的運行。
區分IAP的運行方式有一個特殊的用途,那就是從APP程序中,跳轉IAP程序,來更新APP程序。這是真正的在線升級。
?
最后,我總結一下,要做IAP和APP間的互相跳轉,要注間以下幾點:
1.?APP程序是放在FLASH的中間位置運行的,所以在編譯、下載、調試時,都要指定它的入口(本例是0X08010000)。具體實現就是在魔術棒中的設置。
2.?程序可以是從另外一個程序轉來的,而另外一個程序的RCC,NVIC設置不可知,所以必須在初始化時,恢復RCC,NVIC為復位狀態,并且設置正確的NVIC向量表。
3.?在要跳到別的程序之前,要恢復NVIC為復位狀態,防止在跳轉過程中出現中斷。
4.?如果IAP要判斷是復位開始運行的,還是從APP跳轉過來的,應該用程序啟動部分不會被改變的內存、外存存儲一個標志,用它來判定從哪跳來的。
總結
以上是生活随笔為你收集整理的(转载)关于IAP与APP互相跳转的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用STM32F103C8T6的做IAP时
- 下一篇: STM32L152RC 在keil4中使