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()打印,现在换了 ,还真是有点不习惯哈。

还是有些不懂的地方,希望大家能指出来,大家共同学习,分享下。

 

你可能感兴趣的:(MCU)