1. 概念
??IAP 的作用,網(wǎng)上其他資料已經(jīng)有很多介紹了,這里放一個鏈接,不進(jìn)行深入的介紹。本文的關(guān)注重點(diǎn)是Bootloader在跳轉(zhuǎn)APP程序中出現(xiàn)的問題。
IAP的實(shí)現(xiàn)原理講解以及中斷向量表的偏移
2. 程序
??本人主要做應(yīng)用層的開發(fā),所有Bootloader和APP程序使用的是STM32CubeMX工具生成代碼后,然后進(jìn)行修改。
2.1 Bootloader 程序
? 1. CubeMX 配置
??步驟1:使用的芯片為STM32F407ZGT6
??步驟2:選擇時鐘源(根據(jù)自己的板子進(jìn)行選擇)
??步驟3:時鐘配置
??步驟4:項(xiàng)目配置
? 2. 代碼(只介紹跳轉(zhuǎn)函數(shù))
??完整代碼
void IAP_ExecuteApp ( uint32_t ulAddr_App )
{
int i = 0;
pIapFun_TypeDef pJump2App;
if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 ) //@1 //檢查棧頂?shù)刂肥欠窈戏?
{
HAL_SPI_MspDeInit(&hspi1); //@2
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOG_CLK_DISABLE();
/* 設(shè)置所有時鐘到默認(rèn)狀態(tài),使用HSI時鐘 */
HAL_RCC_DeInit(); //@3
__set_BASEPRI(0x20); //@4
__set_PRIMASK(1);
__set_FAULTMASK(1);
/* 關(guān)閉所有中斷,清除所有中斷掛起標(biāo)志 */
for (i = 0; i < 8; i++) //@5
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
SysTick->CTRL = 0; //@6
SysTick->LOAD = 0;
SysTick->VAL = 0;
__set_BASEPRI(0); //@7
__set_PRIMASK(0);
__set_FAULTMASK(0);
//@8
/*
1)不使用OS時: 只用到MSP(中斷和非中斷都使用MSP);
2)使用OS時(如UCOSII): main函數(shù)和中斷使用MSP; 各個Task(線程)使用PSP(即任務(wù)棧);
*/
__set_MSP(*(uint32_t*)ulAddr_App);//當(dāng)帶操作系統(tǒng)從APP區(qū)跳轉(zhuǎn)到BOOT區(qū)的時候需要將SP設(shè)置為MSP,否則在BOOT區(qū)中使用中斷將會引發(fā)硬件錯誤!
__set_PSP(*(uint32_t*)ulAddr_App);
__set_CONTROL(0); /* 在RTOS工程,這條語句很重要,設(shè)置為特權(quán)級模式,使用MSP指針 */
__ISB();//指令同步隔離。最嚴(yán)格:它會清洗流水線,以保證所有它前面的指令都執(zhí)行完畢之后,才執(zhí)行它后面的指令。
//@9
pJump2App = ( pIapFun_TypeDef ) * ( __IO uint32_t * ) ( ulAddr_App + 4 ); //用戶代碼區(qū)第二個字為程序開始地址(復(fù)位地址)
pJump2App (); //跳轉(zhuǎn)到APP.
}
}
? @1 代碼作用:檢查棧頂?shù)刂肥欠窈戏?0x20000000是sram的起始地址,也是程序的棧頂?shù)刂罚?/p>
if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 )
? @2 代碼作用:下面這幾個關(guān)閉的是在Bootloader中初始化過的外設(shè),如果沒有初始化過其他外設(shè),則不需要;
HAL_SPI_MspDeInit(&hspi1);
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOG_CLK_DISABLE();
? @3 代碼作用:PLL在Bootloader中已經(jīng)配置啟動了,在APP程序中如果想再進(jìn)行配置啟動的話會返回錯誤。
?問題現(xiàn)象
??將Bootloader和APP程序分別下載到板子上,Bootlader程序可以正常運(yùn)行,而APP程序會死在Error_Handler()的while(1)循環(huán)中。具體調(diào)試發(fā)現(xiàn)程序是在執(zhí)行HAL_RCC_OscConfig()函數(shù)的PLL 配置部分檢測到當(dāng)前PLL已經(jīng)被配置為了系統(tǒng)時鐘而返回了HAL_ERROR的返回值導(dǎo)致進(jìn)入了Error_Handler()。
?方案一: 網(wǎng)上有人的建議是不使用PLL,使用HSI作為系統(tǒng)的時鐘源,經(jīng)過測試可以正常運(yùn)行;但是這樣會有個問題是,使用STM32F4的HSI是16M,這顯然和通過PLL倍頻之后使用的168M不在一個數(shù)量級上。
?方案二: 通過查找資料發(fā)現(xiàn),可以在Bootloader啟動的時候配置PLL倍頻到168M,然后在跳轉(zhuǎn)程序之前將RCC的配置反初始化為默認(rèn)設(shè)置(使用HSI時鐘)。
HAL_RCC_DeInit();
? @4 代碼作用:關(guān)閉所有的中斷;此處的特殊寄存器設(shè)置值,可以看如下鏈接: 嵌入式–Keil5–調(diào)試狀態(tài)下Registers界面解析(nrf52832–Cortex-M4內(nèi)核)
__set_BASEPRI(0x20);
__set_PRIMASK(1);
__set_FAULTMASK(1);
? @5 代碼作用:清除所有中斷掛起標(biāo)志,防止在APP中觸發(fā)該中斷,導(dǎo)致運(yùn)行錯誤;
/* 關(guān)閉所有中斷,清除所有中斷掛起標(biāo)志 */
for (i = 0; i < 8; i++) //@5
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
? @6 代碼作用:關(guān)閉掉系統(tǒng)滴答定時器,該定時器會在APP的程序中重新啟動,調(diào)用HAL_Init();函數(shù)會啟動;
?注意:@6 的代碼一定要放到@3 之后,因?yàn)镠AL_RCC_DeInit();函數(shù)會再次開啟滴答定時器。
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
? @7 代碼作用:重新啟動中斷開關(guān);
__set_BASEPRI(0);
__set_PRIMASK(0);
__set_FAULTMASK(0);
?注意:必須重新啟動中斷的開關(guān),本人調(diào)試過程中沒有開啟__set_FAULTMASK(0) ;的中斷,導(dǎo)致滴答定時器(SysTick)無法正常運(yùn)行,執(zhí)行HAL_Delay();,死循環(huán)在了延時中,耽誤了一天的時間查找問題。
? @8 和@9 代碼都有詳細(xì)的注釋;
?注意: __set_PSP((uint32_t)ulAddr_App); 和 __set_CONTROL(0); 函數(shù)是使用RTOS(實(shí)時操作系統(tǒng)的讀者必須要添加的)
2.2. APP程序
??CubeMX 配置基本和Bootloader 基本相同,不贅述。本人使用的FreeRTOS的實(shí)時操作系統(tǒng)。
? 1. Keil 配置
? ? 步驟1:配置程序的起始位置(根據(jù)自己的需要修改),配置的時候發(fā)現(xiàn)只配置這塊沒用,需要配置步驟2才行;
? ? 步驟2:Linker 中修改ScatterFile 文件;
? 這是本人的配置,每個人的可能都不一樣,本人是需要用ccmram,所以使用自己的ScatterFile 文件,修改的內(nèi)容如下圖。
? ? 步驟2:設(shè)置APP的中斷向量表的位置;
??首先找到 startup_stm32f407xx.s 文件中調(diào)用 SystemInit 函數(shù)的地方,找到SystemInit 函數(shù)的實(shí)現(xiàn),然后 找到 USER_VECT_TAB_ADDRESS 的宏定義的地方,取消注釋。先修改下圖 1的位置,然后修改 2的位置,2的位置根據(jù)自己的APP偏移位置來修改。
? 2. 代碼
?? 在main 函數(shù)的一開始添加如下代碼。
/* USER CODE BEGIN 1 */
HAL_DeInit();
HAL_RCC_DeInit();
/* USER CODE END 1 */
HAL_DeInit(); HAL庫反初始化;
HAL_RCC_DeInit(); RCC配置反初始化;
??注意: 如果直接查找HAL_RCC_DeInit() 的實(shí)現(xiàn),發(fā)現(xiàn)是個空函數(shù),實(shí)際這是HAL庫的一個機(jī)制,實(shí)際編譯使用的另外一個文件中的,如下圖1和2文章來源:http://www.zghlxwxcb.cn/news/detail-679140.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-679140.html
4. 其他問題
4.1 可能導(dǎo)致APP死機(jī)的原因
- Bootloader啟動的外設(shè)比APP的多,導(dǎo)致死機(jī),需要在跳轉(zhuǎn)到APP時清理不需要的外設(shè)配置;
- Bootloader開啟了某個終端,在APP中沒有配置相應(yīng)的處理函數(shù),導(dǎo)致死機(jī);該問題可通過Bootloader程序的@4 @5 @7來解決;
到了這里,關(guān)于STM32F4 IAP 跳轉(zhuǎn) APP問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!