【stm32 IAP-APP跳转学习记录】代码少一“点“,调试大半天

首先直接上结果,正确代码:

#define IAP_ADDR   0x8000000
#define APP_ADDR   0x8002000    //测试代码,8K足够


void gotoAPP(void)
{
 uint32_t JumpAddress;
 void (*pFun)(void);      //定义一个函数指针.用于指向APP程序入口
 INTX_DISABLE();       //关闭所有中断
 MSR_MSP(APP_ADDR);      //设置SP 堆栈栈顶地址
 JumpAddress=*(__IO uint32_t*) (APP_ADDR+4);  
 pFun=(void(*)(void))JumpAddress;//生成跳转函数.将复位中断向量地址做为函数指针
 (*pFun)();        //跳转
}

void gotoIAP(void)
{
 uint32_t JumpAddress;
 void (*pFun)(void);      //定义一个函数指针.用于指向APP程序入口
 INTX_DISABLE();       //关闭所有中断
 MSR_MSP(IAP_ADDR);      //设置SP 堆栈栈顶地址
 JumpAddress=*(__IO uint32_t*) (IAP_ADDR+4);  //生成跳转函数.将复位中断向量地址做为函数指针
 pFun=(void(*)(void))JumpAddress;
 (*pFun)();        //跳转
}

IAP和APP的main()函数开头要加上:

 INTX_ENABLE(); //打开中断
 SCB->VTOR = 0x8002000;//配置APP中断向量表,IAP是0x8000000,APP你烧录在哪就写哪

用到了原子哥的三个函数:

//关闭所有中断
void INTX_DISABLE(void)
{    
 __ASM volatile("cpsid i");
}
//开启所有中断
void INTX_ENABLE(void)
{
 __ASM volatile("cpsie i");    
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
    MSR MSP, r0    //set Main Stack value
    BX r14
}

调试血泪史

随手拿了个板子,准备写个简单的代码尝试一下IAP-APP的跳转,感觉很高端,预期目标是这样的:

刚开机运行iap,蓝灯闪烁,通过按键中断跳转。
当按键1按下,跳转到app,绿灯闪烁。
当按键2按下,跳转回iap,蓝灯闪烁。

我第一次写的跳转函数是这样的:

void gotoAPP(void)
{
 void (*pFun)(void);      //定义一个函数指针.用于指向APP程序入口
 INTX_DISABLE();       //关闭所有中断
 MSR_MSP(APP_ADDR);      //设置SP 堆栈栈顶地址
 pFun=(void(*)(void))(APP_ADDR+4);  //生成跳转函数.将复位中断向量地址做为函数指针
 (*pFun)();        //跳转
}

然后得到的现象是这样的:

当按键1按下,程序进入硬件错误中断,蓝绿灯都不亮。
在调试界面跳转处加入断点,重新运行。
按下按键,运行到断点处停下。
点击继续,绿灯开始闪烁,可能跳转到了APP(为什么说可能,因为我也不知道他为什么能闪)。
在app处跳转回来也是这个现象。

出现了问题就要解决,首先我觉得断点继续就能行,那应该是需要个延时,然后我加了个延时,结果并没有什么卵用。

上百度,发现有的地址要加4,有的不要,我干脆全试了一遍,改跳转地址、栈顶地址、中断向量表地址,然后发现,还是毫无效果。

改开关中断位置,改配置中断向量表的位置,没有效果。

会不会是按键有问题呢,我后知后觉的想,这个本来应该刚开始就测试的。测试外部中断和按键,将两个按键中断分别对应一个灯,测试表明外部中断没问题,看来问题也不在这。

没辙了,直接复制一个网上的代码过来试试,代码如下:

void GotoApp(void){
 /* Test if user code is programmed starting from address "ApplicationAddress" */
 if (((*(__IO uint32_t*)FLASH_APP_ADDR) & 0x2FFE0000 ) == 0x20000000)
 {
  __set_FAULTMASK(1);      // 关闭所有中断
  /* Jump to user application */
  JumpAddress = *(__IO uint32_t*) (FLASH_APP_ADDR + 4);
  Jump_To_Application = (pFunction) JumpAddress;
  /* Initialize user application's Stack Pointer */
  __set_MSP(*(__IO uint32_t*) FLASH_APP_ADDR);
  Jump_To_Application();
 }
}

简单适配了一下,测试居然成功了,流畅的从蓝灯闪变成绿灯闪,我都快感动哭了。
擦擦眼泪逐条替换,我一定要找到错在哪,然后就找到了问题:

先将地址赋值给u32变量,然后变量赋值给函数指针,可以跳转,直接赋值给函数指针就跑死。

根据问题找根本原因:

在调制界面发现赋值给变量后,地址从0x8002004变成了0x800214d。
打开memory窗口,发现0x8002004的地址内数据是800214d。
再看代码,发现赋值给变量时通过星号取了地址内的数据,这就是根本原因。
验证:直接通过((void(*)())0x0800214D)();跳转成功。

终于成功了,内牛满面。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值