【嵌入式】stm32程序跳转实验

【嵌入式】stm32程序跳转实验

菜老越

于 2019-04-23 17:54:56 发布

2888
 收藏 22
分类专栏: 嵌入式 文章标签: keil stm32 程序跳转 IAP BootLoader
版权

嵌入式
专栏收录该内容
32 篇文章4 订阅
订阅专栏
近期想研究下stm32基于BootLoader的IAP功能,要想实现这个,必须先搞明白程序跳转,在真正开搞前折腾了一下午,完成了程序跳转的简单测试。共用了两个程序,一个放在0x8000000开始的位置,暂称为Load程序;另一个放在0x8004000的位置,暂称为APP程序。两个程序分别包含以下功能:
1.Load程序:进入程序后首先向串口打印一句"This means START!”,然后在while(1)里循环打印“In While”,间隔为1秒;设立一个按键外部中断,中断发生后跳转到0x8004000的位置以运行APP程序。
2.APP程序:跳转过来后直接进到while(1)里循环打印“This is APP”,间隔为1秒,5秒后跳回Load程序。
下面先以最终的成功案例来介绍Load和APP程序。当然出于实验,也可以用在Load、APP程序中分别以不同形式操作led的方法,来检测Load和APP之间的跳转。

一、成功实验过程
1.Load程序
stm32代码下载到0x8000000开始的地址,程序跳转的意思也就是在程序运行时,通过一个跳转函数使得PC指针指到制定位置继续运行。看上去很简单但是重点需要注意跳转前后的中断的处理。
while(1)附近的程序如下

printf("This means START!\n");
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        HAL_Delay(1000);
        printf("In While\n");

1
2
3
4
5
6
7
8
9
重点在于按键中断中的跳转函数Jump_test,程序如下

void Reset_test(void)
{
    typedef  void (*iapfun)(void);
    uint32_t JUMP_ADDR = 0x08004000;
    uint32_t STACK_ADDR = 0x20000000;
    uint32_t RESET_IRQ_ADDR = JUMP_ADDR + 4;
    iapfun jump2app;
    jump2app = (iapfun)*(volatile uint32_t *)RESET_IRQ_ADDR;
    __set_MSP(STACK_ADDR);
    __disable_irq();
    jump2app();
}
1
2
3
4
5
6
7
8
9
10
11
12
RESET_IRQ_ADDR 设置为JUMP_ADDR +4是因为stm32中断向量中,复位中断的相对地址为起始地址+4,如图所示;__set_MSP(STACK_ADDR)的作用为重新初始化堆栈;同时,在跳转前__disable_irq()是为了关闭所有中断,这似的在跳转过程中不会进入“很有缘分”的中断……

在这里插入图片描述
2.App程序
App程序在这里就更简单了,直接上代码

 

 int main(void)
{
  __enable_irq();
  SCB->VTOR = 0x8004000;
  
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  
  int count = 0;
  while (1)
  {
    HAL_Delay(1000);
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_7);
    printf("This is APP\n");
    if(count >= 5)
        HAL_NVIC_SystemReset();
    count++;
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
其中头两行的__enable_irq()和SCB->VTOR = 0x8004000要在进入main函数一开始就执行,这是为了打开跳转前关闭的中断,并且重定位向量表,否则APP程序里的与中断相关的程序会炸。重定位中断向量时,往VTOR寄存器中写入的值即为APP程序的起始地址,具体为什么要这样,请参考《ARM Cortex-M3与M4权威指南》。经过用stm32Cube自动生成的一些列初始化后,就到了APP程序的主体。可以看到当定义的count变量大于5时,直接运行HAL_NVIC_SystemReset()使系统软重启,程序又从0x8000000的位置开始执行,即为跳回了Load程序。
这里需要注意的是在APP跳回Load程序时,本以为可以类比于Load跳到APP,即用Jump_test函数,跳到0x8000000的位置,结果发现这样操作时,虽然能跳回去,但Load程序中跟中断相关的代码会出现异常。如定时器中断一直处于活跃状态,无论怎么清标志位都出不来;同时,外部按键中断也因为中断优先级的问题偶尔挂起,无论怎么清除中断挂起状态都不行。DeBug了半天,看寄存器值看的都眼花了,还是无果。干脆直接重启系统,反正重启系统也是从0x8000000开始运行……

3.程序下载
3.1.Load程序下载
Load程序就是下载在0x8000000开始的位置,这个和普通下载程序一样,直接用默认值下载就好了,打开keil的Options for Target,选择Target选型卡,可以看到下图,红框里就是默认位置,只不过我将Size设置成了0x4000,也就是16k,因为Load程序很小,16k足够了,同时APP下在0x8004000的位置,正好紧邻着Load程序。

在这里插入图片描述
在选择Utilities选项卡,点击Settings,在点击Flash Download选项卡,如下图所示,Start和Size同上,这样一来。设置好后就可以先下载Load程序到单片机了。

 在这里插入图片描述

 

3.2.APP程序下载
同理的,APP设置过程同上,只是记得把Start设置为0x8004000,size随便设置,只要放得下你的程序就好了。设置好后点击下载,程序就被下到了0x8004000开始的位置。下面就可以测试啦。

4.程序测试
链接好ttl转串口线,打开串口助手后,可以观察到Load程序的运行结果

在这里插入图片描述

 

按下外部中断对应的按键后,跳入APP程序,打印结果如下。可以观察到打印6次This is APP后系统复位,重新进入Load程序。测试成功。

在这里插入图片描述

 

二、总结
1.跳转函数里要重新初始化堆栈,并禁用中断;
2.APP程序一进main函数首先要开启中断,并重定位中断向量;
3.APP跳回Load时直接用软复位就好了。如果用Jump_test类似的函数,跳回Load后整个中断系统会出现异常,不如直接复位重启所有,古人云出了Bug先重启,是有一定道理的……

通过这次实验实现了Load与APP间的互跳,接下的任务就是打造一个自己的BootLoader以及IAP程序啦
————————————————
版权声明:本文为CSDN博主「菜老越」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/spiremoon/article/details/89460441

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值