打印
[STM32F4]

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

[复制链接]
1348|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
傲视群熊|  楼主 | 2016-11-6 22:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
某个项目需要用到bootloader更新app到sdram内执行程序,不能选ARM9,领导又喜欢stm32,不差钱所以选了stm32f427这个芯片,最主要原因就是可以挂上sdram。
以前做过stm32F1系列的iap程序,基本就是bootloader跳转前关一下中断,app运行前设置一下中断向量表就ok了,这次换了427本以为也很简单,只不过是跳转位置从flash更改到sdram罢了,想想自己还是naive了一点,首先是按老套路设置,然后跳转立马死翘,debug半天无果,后来一顿百度谷歌翻芯片手册之后才发现要stm32f4要能在sdram运行用户程序,必须将sdram地址映射到0x90000000,因为芯片的默认sdram地址是不能执行指令的,所以修改一下跳转代码如下

[cpp] view plain copy


  • 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内强行切换系统模式,貌似**这种事情不太光彩,但是总算是有点眉目了,代码修改如下

[cpp] view plain copy


  • 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();     
  •                
  • }  


[cpp] view plain copy


  • 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函数修改如下

[cpp] view plain copy


  • 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>  

[cpp] view plain copy


  •     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();     
  •                
  • }  



世界终于清静了!
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

51

主题

84

帖子

1

粉丝