记录一次stm32F429 IAP跳转到SDRAM内执行程序的DEBUG过程

 某个项目需要用到bootloader更新app到sdram内执行程序,不能选ARM9,领导又喜欢stm32,不差钱所以选了stm32f427这个芯片,最主要原因就是可以挂上sdram。

以前做过stm32F1系列的iap程序,基本就是bootloader跳转前关一下中断,app运行前设置一下中断向量表就ok了,这次换了427本以为也很简单,只不过是跳转位置从flash更改到sdram罢了,想想自己还是naive了一点偷笑,首先是按老套路设置,然后跳转立马死翘,debug半天无果,后来一顿百度谷歌翻芯片手册之后才发现要stm32f4要能在sdram运行用户程序,必须将sdram地址映射到0x90000000,因为芯片的默认sdram地址是不能执行指令的,所以修改一下跳转代码如下

void M3Jump( uint32_t dwJumpAddr )
{
    volatile uint32_t JumpAddress;
     
    SYSCFG->MEMRMP = SYSCFG->MEMRMP | 0x400;            //SDRAM_BANK_ADDR = 0xD0000000 重映射后为 0x90000000 ,只有90000000的地址可以执行代码,所以必须remap
       
    JumpAddress = *(vu32*) (0x90000000+4);<span style="white-space:pre">		</span>//取入口地址
    Jump_To_Application = (user_app) JumpAddress;
    __set_MSP(*(vu32*) 0x90000000 );<span style="white-space:pre">			</span>//设置堆栈指针
    Jump_To_Application();   <span style="white-space:pre">				</span>//go !
             
}


改完心情大好,想着必须能跑了,结果自己又图样图森破了,还是死机啊!又是一顿搜索研究,毫无头绪,后来想起以前玩S3C2440片子移植ucos的时候搞很久就是不行,后来发现是ARM执行模式的问题,

(1)用户模式(usr , User Mode)。ARM处理器正常的程序执行状态。

(2)快速中断模式(fiq , Fast Interrupt Request Mode)。用于高速数据传输或通道处理。当触发快速中断时进入此模式。

(3)外部中断模式 ( irq , Interrupt Request Mode )。用于通用的中断处理。当触发外部中断时进入此模式。

(4)管理模式 ( svc , Supervisor Mode )。操作系统使用的保护模式。在系统复位或者执行软件中断指令SWI时进入。

(5)数据访问终止模式 ( abt , Abort Mode )。当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护。

(6)系统模式(sys , System Mode )。运行具有特权的操作系统任务。

(7)未定义指令中止模式 ( und , Undefined Mode )。当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。

差不多就是上面这些意思,bootloader和app处于不同的运行模式,两种模式下的msp和psp是不一样的,因此直接由bootloader杀入app是会死翘的。所以我想了个笨办法,跳转前人为引发一个svc中断,然后在svc内强行切换系统模式,貌似强奸这种事情不太光彩,但是总算是有点眉目了,代码修改如下

void M3Jump( uint32_t dwJumpAddr )
{
    volatile uint32_t JumpAddress;   
    __asm("SVC 0x0");  //这条指令很重要,引发一个svc中断,在里面切换cpu工作模式,从用户模式切换为特权模式,否则app跳转必死无疑
    __asm("CPSID   I"); //跳转前关中断      
    SYSCFG->MEMRMP = SYSCFG->MEMRMP | 0x400; //SDRAM_BANK_ADDR = 0xD0000000 重映射后为 0x90000000 ,只有90000000的地址可以执行代码,所以必须remap      
   JumpAddress = *(vu32*) (0x90000000+4);
    Jump_To_Application = (user_app) JumpAddress;
    __set_MSP(*(vu32*) 0x90000000 );
    Jump_To_Application();   
             
}

void SVC_Handler(void) //os系统执行在用户模式下,app跳转后要运行在特权模式才可以,因此用svc服务来切换用户模式到特权模式
{
    __set_MSP(__get_PSP());//保存当前用户模式的PSP到MSP,因为svc中断返回后要使用MSP,如果没有这条指令,svc将找不到返回的路了,死机是必须的
    __asm("MOV R14, #0xFFFFFFF9");//强行修改LR寄存器,让svc中断服务返回后使用MSP并且进入特权模式,这样app跳转后才能正常运行 
}
修改跳转代码强行引发一个svc中断进入特权模式,只有在特权模式里面才能修改成其他模式,经过上面的修改后测试,debug查看各个寄存器数值,模式全部ok,尼玛还是不能运行啊,都快要怀疑人生了,没办法,一个一个下断点慢慢调试,最终断点下到remap语句后面的时候成功运行了,艹!原来remap也是需要执行时间的,remap没完成就jump也是会死的。最终jump函数修改如下

void M3Jump( uint32_t dwJumpAddr )
{
    volatile uint32_t JumpAddress;
    
    __asm("SVC 0x0");                                                           //这条指令很重要,引发一个svc中断,在里面切换cpu工作模式,从用户模式切换为特权模式,否则app跳转必死无疑
    __asm("CPSID   I");                                                         //跳转前关中断
     <span style="font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 25.2px;"> </span>
    SYSCFG->MEMRMP = SYSCFG->MEMRMP | 0x400;                                    //SDRAM_BANK_ADDR = 0xD0000000 重映射后为 0x90000000 ,只有90000000的地址可以执行代码,所以必须remap
    
    for(JumpAddress=0;JumpAddress<0xfffff;JumpAddress++);                       //等待映射完成才能读90000000地址,否则死翘
    
    JumpAddress = *(vu32*) (0x90000000+4);
    Jump_To_Application = (user_app) JumpAddress;
    __set_MSP(*(vu32*) 0x90000000 );
    Jump_To_Application();   
             
}

世界终于清静了!





你可能感兴趣的:(跳转,stm32,bootloader,sdram,ucos,iap)