STM32F4XX IAP跳轉到app uCOSIII上卡死的問題

最近在搞一個SD卡的IAP升級,首先弄了個bootloader,再寫一個APP,他們必須存儲在不同的FLASH地址裏,這裏我就不講了,關於IAP升級的方法網上很多,我說下我做這個時遇到的問題

     單個的Bootloader 和APP在地址0x800000上運行的時候都是OK的,且Bootloader + app(無uCOSIII系統),運行也是沒有問題的;但是但Bootloader + app(有uCOSIII系統)時就卡死了。調試發現卡死分別在兩個地方:

     1、卡死在printf()函數打印,也初始化了串口函數;

     2、卡死在OSStart(&err);進入不了線程;

   網上查了很多關於STM32 Bootloader + app(有uCOSIII系統)卡死的問題,大都的方法都是關中斷,指定app中斷向量表。

void iap_load_app(void)
{    
    uint8_t i;
    
    __set_PRIMASK(1);    
    __set_BASEPRI(0);
    __set_FAULTMASK(0);
    __set_PSP(*(volatile uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS);
    __set_MSP(*(volatile uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS);
    __set_CONTROL(0);
    if(((*(vu32*)USER_FLASH_FIRST_PAGE_ADDRESS)&0x2FFE0000)==0x20000000)    //¼ì²éÕ»¶¥µØÖ·ÊÇ·ñºÏ·¨
    {         
        printf("JumpAddress = %x\r\n",*(vu32*)USER_FLASH_FIRST_PAGE_ADDRESS);
        jump_addr = *(vu32*)(USER_FLASH_FIRST_PAGE_ADDRESS+4);        //Óû§´úÂëÇøµÚ¶þ¸ö×ÖΪ³ÌÐò¿ªÊ¼µØÖ·£¨¸´Î»µØÖ·£©    
        jump2app = (FunVoidType)jump_addr;
        printf("jump_addr = %x\r\n",jump_addr);
        USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
//        __disable_irq();
//        RCC_DeInit();
//        // Disable IRQs
//        for( i = 0;i < 8;i++)
//        {
//                NVIC->ICER[i] = 0xFFFFFFFF;
//        }
//        // Clear pending IRQs
//        for( i = 0;i < 8;i++)
//        {
//                NVIC->ICPR[i] = 0xFFFFFFFF;
//        }

////        __enable_irq();

//        SysTick->CTRL =0;
//        SysTick->LOAD=0;
//        SysTick->VAL=0;

        /* Reconfigure vector table offset register to match the application location */
//        SCB->VTOR = USER_FLASH_FIRST_PAGE_ADDRESS;

//        __set_BASEPRI(0); __set_FAULTMASK(0);
//        __set_PSP(*(volatile uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS);
//        __set_CONTROL(0);
        MSR_MSP(*(volatile uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS);  //³õʼ»¯APP¶ÑÕ»Ö¸Õë(Óû§´úÂëÇøµÄµÚÒ»¸ö×ÖÓÃÓÚ´æ·ÅÕ»¶¥µØÖ·)    

//        __set_PRIMASK(1);        //¹ØÖжÏ
//        __ISB(); __disable_irq();
        jump2app();                    //Ìøתµ½APP.    
    }
}

然而並沒什麼用,後來比較了一下別人的bsp.c程序,發現這個地方不同,就是系統時鐘的獲取方法不同

CPU_INT32U  BSP_CPU_ClkFreq (void)
{
//    CPU_INT32U  hclk_freq;

//    hclk_freq = SystemCoreClock;這個我自己改的,直接調用系統時鐘。
//        printf("hclk_freq=%d\r\n",hclk_freq);
//    return (hclk_freq);
      RCC_ClocksTypeDef  rcc_clocks;

    RCC_GetClocksFreq(&rcc_clocks);        //»ñÈ¡¸÷¸öʱÖÓƵÂÊ

    return ((CPU_INT32U)rcc_clocks.HCLK_Frequency);
}
將原來的註釋掉,用這個再測試,居然可以進入線程了,程序也跑起來了,在此之前關閉了所有的printf打印。

hclk_freq = SystemCoreClock;這個我自己改的,直接調用系統時鐘,從0x800000上啓動是沒問題的,但是IAP跳轉回來就不行了,估計是跳轉回來要重新設置滴答時鐘吧,這兩者還是有很大區別的;uint32_t SystemCoreClock = 180000000;是系統初始定義的時候就定義好的。並不是真實的系統CPU跑起來的時鐘,而 RCC_GetClocksFreq(&rcc_clocks);纔是真實頻率。

下個問題就是printf()打印的問題了,很多人也說是沒有對fputc()函數進行重構,也重構了fputc()函數,而且就是死在

int fputc(int ch, FILE *f)
{     
    while((USART1->SR&0X40)==0);//Ñ­»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
    USART1->DR = (u8) ch;      
    return ch;
}

這個while循環裏了;也有的說要在KEIL編譯環境里加上use MicroLIB,這個也是勾選的,但就是死在這個while裏了

首先這個printf()在app(帶系統時),起始地址是0x800000的時候運行時是正常的,沒有問題,程序也跑得正常,就是從IAP跳轉回來後就死機了

   網上說printf()是dos的服務,不可重入,是涉及到硬件部分的,必須改成可重入的函數,如:

OS_CRITICAL_ENTER();

printf("float_num: %.4f\r\n",float_num);

OS_CRITICAL_EXIT();

但還是卡死了。

也不知道具體原因是什麼,乾脆就用uart的程序打印了

void USART1_Putc(unsigned char c)
{
    USART_SendData(USART1, c);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET );
}

void USART1_Puts(char * str)
{

    while(*str)
    {
            USART_SendData(USART1, *str++);
            while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }
}

改爲這個打印就沒問題了,但是一直用printf()打印,現在換了 ,還真是有點不習慣哈。

還是有些不懂的地方,希望大家能指出來,大家共同學習,分享下。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章