日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

IAP升级功能编写初期的一些困惑与疑问---完成功能后的总结

發布時間:2025/3/21 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IAP升级功能编写初期的一些困惑与疑问---完成功能后的总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IAP的源碼等資料我上傳了,壓縮包內有12個文件,,鏈接地址(要積分的辛苦收集的你們就給點積分吧)

還有另一篇博客總結的IAP:http://www.aiuxian.com/article/p-2010781.html

?

一,網上下載的例程,跳轉部分的代碼有差異,尤其是用的匯編那句

eg:

①Jump_To_Application ?= (pFunction)(*(vu32*) (IAPSTART + 4));
__MSR_MSP(*(vu32*) IAPSTART);
Jump_To_Application();

跟蹤__MSR_MSP(一般這個函數都在庫文件里有,跟蹤不到就用搜索找)找到匯編函數為

__MSR_MSP?
?
? ??MSR MSP, r0 ; set Main Stack value
? ??BX r14

?

②//跳轉到應用程序段
//appxaddr:用戶代碼起始地址.
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//檢查棧頂地址是否合法.
{?
jump2app=(iapfun)*(vu32*)(appxaddr+4);//用戶代碼區第二個字為程序開始地址(復位地址)
MSR_MSP(*(vu32*)appxaddr);//初始化APP堆棧指針(用戶代碼區的第一個字用于存放棧頂地址)
jump2app(); ?//跳轉到APP.
}
}

跟蹤MSR_MSP找到函數為

//設置棧頂地址
//addr:棧頂地址
__asm void MSR_MSP(u32 addr)?
{
? ??MSR MSP, r0? //set Main Stack value
? ??BX r14
}

?

③ ?//判斷用戶是否已經下載程序,因為正常情況下此地址是棧地址。
? ? ? ? //若沒有這一句的話,即使沒有下載程序也會進入而導致跑飛。
? ? ? ? if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
? ? ? ? {
? ? ? ? ? ? SerialPutString("Execute user Program\r\n\n");
? ? ? ? ? ? //跳轉至用戶代碼
? ? ? ? ? ? JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
? ? ? ? ? ? Jump_To_Application = (pFunction) JumpAddress;


? ? ? ? ? ? //初始化用戶程序的堆棧指針
? ? ? ? ? ? __set_MSP(*(__IO uint32_t*) ApplicationAddress);
? ? ? ? ? ? Jump_To_Application();
? ? ? ? }

跟蹤__set_MSP找到函數為

__ASM void __set_MSP(uint32_t mainStackPointer)
{
? msr msp, r0
? bx lr
}

總結以上發現都是操作ARM的R0跟R14(LR)寄存器。

還有一種不太一樣的,就是stm32F4的庫函數中的跳轉,如下所示

④ //測試用戶app地址是不是在APPLICATION_ADDRESS位置。檢測棧頂的地址,來檢驗app是否下載成功
? ? if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
? ? {?
? ? //APPLICATION_ADDRESS + 4對應的是app中斷向量表的第二項,復位地址
? ? JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
//把地址強轉為函數指針
? ? Jump_To_Application = (pFunction) JumpAddress;
? ? //設置主函數棧指針
? ? __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
//調用函數,實際失去app復位地址去執行復位操作
? ? Jump_To_Application();
? ? }

跟蹤__set_MSP找到函數為

static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
? register uint32_t __regMainStackPointer ? ? __ASM("msp");
? __regMainStackPointer = topOfMainStack;
}

對于M4的這個庫函數我也不太懂,感覺最終的操作應該跟其他的一樣吧

二,關于跳轉部分的代碼的理解(轉)

?

這里重點說一下幾句經典且非常重要的代碼:

第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) ? //判斷棧定地址值是否在0x2000 0000 - 0x 2000 2000之間

怎么理解呢? (1),在程序里#define ApplicationAddress ? ?0x8003000 ,*(__IO uint32_t*)ApplicationAddress) ?即取0x8003000開始到0x8003003 的4個字節的值, 因為我們的應用程序APP中設置把?中斷向量表?放置在0x08003000 開始的位置;而中斷向量表里第一個放的就是棧頂地址的值

也就是說,這句話即通過判斷棧頂地址值是否正確(是否在0x2000 0000 - 0x 2000 2000之間) 來判斷是否應用程序已經下載了,因為應用程序的啟動文件剛開始就去初始化化棧空間,如果棧頂值對了,說應用程已經下載了啟動文件的初始化也執行了;

?

第二句:? ??JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); ??[ ?common.c文件第18行定義了: ?pFunction ? Jump_To_Application;]
? ? ? ? ? ? ? ? ? ? ??

ApplicationAddress + 4 ?即為0x0800 3004 ,里面放的是中斷向量表的第二項“復位地址” ?JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此時JumpAddress

第三句:?? ?Jump_To_Application = (pFunction) JumpAddress;
?startup_stm32f10x_md_lv.?文件中別名??typedef ?void (*pFunction)(void); ? ? 這個看上去有點奇怪;正常第一個整型變量 ? typedef ?int ?a; ?就是給整型定義一個別名 a

?void (*pFunction)(void); ? 是聲明一個函數指針,加上一個typedef 之后 ?pFunction只不過是類型?void (*)(void) 的一個別名;例如:

?

[cpp]??http://www.aiuxian.com/article/p-864872.html?http://www.aiuxian.com/article/p-864872.html

  • pFunction???a1,a2,a3;??
  • ??
  • void??fun(void)??
  • {??
  • ????......??
  • }??
  • ??
  • a1?=?fun;??
  • ?

    所以,Jump_To_Application = (pFunction) JumpAddress; ?此時Jump_To_Application指向了復位函數所在的地址;

    第四 、五句:?__set_MSP(*(__IO uint32_t*) ApplicationAddress); ? ? ?\\設置主函數棧指針
    ? ? ? ? ? ??? ?Jump_To_Application(); ? ? ? ? ? ? ? ? ? ? ? ? \\執行復位函數

    Jump_To_Application()是把用戶代碼的復位地址付給PC指針,我看到Jump_To_Application()這句代碼debug的時候對應的匯編代碼是

    LDR r0,[pc,#12] ;相對PC的數據加載,去函數指針的地址
    LDR r0,[r0,#00] ;R0做索引,無偏移,數據裝載到R0,這個內容就是函數指針指向的內容,也就是函數的地址了,用戶程序的起始地址;
    BLX r0? ?? ?? ?? ???;這個不解釋,說了是跳轉

    我們看一下啟動文件startup_stm32f10x_md_vl.s 中的啟動代碼,更容易理解

    ?

    ?

    三,關于跳轉時能否不用按鍵,用軟件標志位以及APP與IAP之間的互跳

    完全可以不用按鍵,可以模擬一個按鍵信號,或者用軟件的一個標志位來判斷是否更新。。我設計的在flash中中存儲一個值,當APP運行中需要更新時串口發來更新命令,然后在flash中存一個值之后跳到IAP部分,來讀取flash中存儲的那個值,如果是需要更新則更新,如果不是需要跟新標志位就直接跳轉到APP部分。。。這樣也不用重復上電,斷電。

    ?

    四,關于APP與IAP互跳之間的中斷處理問題

    跳轉時中斷問題還是一個比較棘手的問題。。經常跳轉之后無法進入中斷,然后百度了一下,自己理解大概是,跳轉時只是強制改變了PC指正的位置,但是里面的中斷寄存器什么的都沒有變,這樣中斷存在,但是中斷函數什么的都沒有了,造成程序死掉。。我在寫的過程中也遇到了問題,第一次從iap跳到app正常,但是從app跳回iap的時候由于殘留的中斷太多,在iap中程序死了。我的處理方式是把app中的跳轉命令換成了系統復位NVIC_SystemReset();(不同的固件庫可能函數名不同)其他的處理理的方式據我所知還有有①跳轉之前復位或者關閉所有打開的中斷②跳轉后在初始化時加入RCC_DeInit();,,NVIC_DeInit?();等讓中斷恢復默認值。。具體可參考下面這篇文章鏈接地址

    關于stm32的軟件復位:

    STM32軟件復位(基于庫文件V3.5) ,對于STM32來說軟件復位有兩種方式: ? ?

    1)采用官方自帶的軟件庫 ?
    ? ? 在官方軟件庫的 core_cm3.h 文件里 直接提供了 系統復位的函數 ? ?

    static __INLINE void NVIC_SystemReset(void)?

    {?
    SCB->AIRCR ?= ( (0x5FA << SCB_AIRCR_VECTKEY_Pos) ? ?| ??

    (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) ? | ?

    SCB_AIRCR_SYSRESETREQ_Msk); ? ? ? ? ? ? ? ? ? /* Keep priority group unchanged */?
    ? __DSB(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* Ensure completion of memory access */ ? ? ? ? ? ? ??
    ??while(1); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* wait until reset */

    ?}?
    ? 但是不是直接調用這個函數就OK了? ? ?在Cortex-M3權威指南中有這么一句話: ? ??
    這里有一個要注意的問題:從SYSRESETREQ 被置為有效,到復位發生器執行復位命令, ?往往會有一個延時。在此延時期間,處理器仍然可以響應中斷請求。但我們的本意往往是要 ?讓此次執行到此為止,不要再做任何其它事情了。所以,最好在發出復位請求前,先把 ?FAULTMASK 置位。 ?

    ? 所以最好在將FAULTMASK 置位才萬無一失。 ? ?同樣官方 core_cm3.h 文件里也直接提供了該函數 ?
    ? static __INLINE void __set_FAULTMASK(uint32_t faultMask)?

    {?

    register uint32_t __regFaultMask ? ? ? __ASM("faultmask"); ??

    __regFaultMask = (faultMask & 1);

    ?}?
    ? 把上面這兩個函數寫在一起就可以實現軟件復位了~~?

    void SoftReset(void)?

    {?
    __set_FAULTMASK(1); ? ? ?// 關閉所有中端?

    NVIC_SystemReset();// 復位?

    }?
    ?/*------

    總結

    以上是生活随笔為你收集整理的IAP升级功能编写初期的一些困惑与疑问---完成功能后的总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。