STM32F103系列实现软件在线加载功能的几种方法

一.浅谈“BootLoader与APP”

APP就是平时写的单片机上的应用程序,而BootLoader本质上和APP一样,也是平时写的应用程序。BootLoader只不过是拥有从外部接收数据,更新Flash(也就是APP),跳转至APP功能的特殊APP罢了。

以STM32F103为例,如果没有BootLoader,flash分布就如下图左半部分。如果有BootLoader,就如下图右半部分,将flash分为两部分(这里举例用0x8010000做分界线,0x8010000 =0x8000000+BootLoader代码的长度,根据实际情况划分区域BOOT和APP区域大小),存储了两个应用程序(BootLoader和APP)

 

 

二. 如何从BootLoader跳转到APP

从外部接收数据,更新Flash,普通的APP也会有这样的需求。不常见的也就是从BootLoader跳转到APP这个功能了。STM32 单片机启动流程中介绍了单片机上电后的启动流程,其实也就主要干了两件事:

①将栈顶位置加载到MSP寄存器中
②将复位中断服务函数的入口地址给PC寄存器

  然后单片机执行复位中断服务函数,在复位中断服务函数中设置中断向量表的偏移地址,准备C环境,最后跳转到main()函数。同理,从Bootloader跳到APP也需要干这两件事情,只不过上电时是单片机自动加载的MSP和PC,而从Bootloader跳到APP则需要我们编写函数进行跳转。

下面是STM32 跳转到APP的具体函数,在BootLoader函数中调用即可跳转到APP_ADDR,如果该地址存放了APP的bin文件则会运行APP的复位中断服务函数(一定要记得在APP中修改中断向量表偏移地址,如APP中不修改则默认使用BootLoader的中断向量表,APP中发生中断时就会去查BootLoader的中断向量表,从而调用BootLoader的中断服务函数),进而运行APP的main()函数。同理,APP跳转到BootLoader,修改跳转地址 APP_ADDR 为BootLoader地址(这里为0x8000000)即可实现(也可选择只在上电跳转一次APP,正常工作后不允许加载,则删除该处回跳至BOOT启动地址0x8000000的操作).

/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0)  /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#define APP_ADDR    0x8010000          /* APP地址 */
/*
*********************************************************************************************************
* 函 数 名: JumpToApp
* 功能说明: 跳转到APP
* 形    参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void JumpToApp(void)
{
  void (*SysMemBootJump)(void);        /* 声明一个函数指针 */
  __IO uint32_t AppAddr = APP_ADDR;    /* APP地址 */
    
  /* 如果初始化了外设,需要反向初始化外设 */
  
  /* 设置所有时钟到默认状态,使用HSI时钟 */
  HAL_RCC_DeInit();

  /* 关闭滴答定时器,复位到默认值 */
  SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;

  /* 关闭全局中断 */
  DISABLE_INT();
    
  /* 关闭所有中断,清除所有中断挂起标志 */
  for (uint32_t i = 0; i < 8; i++)
  {
    NVIC->ICER[i]=0xFFFFFFFF;
    NVIC->ICPR[i]=0xFFFFFFFF;
  } 

  /* 使能全局中断 */
  ENABLE_INT();

  /* 设置SysMemBootJump为中断服务函数入口地址,首地址是MSP,地址+4是复位中断服务程序地址 */
  SysMemBootJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));

  /* 设置主堆栈指针 */
  __set_MSP(*(uint32_t *)AppAddr);

  /* 在RTOS工程,这条语句很重要,设置为特权级模式,SP使用MSP指针 */
  __set_CONTROL(0);

  /* 进行跳转 也就是将SysMemBootJump 赋值给PC */
  SysMemBootJump(); 

  /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
  while (1)
  {

  }
}

三.在线加载功能设计

方法1:用户定义的应用程序(BootLoader+APP)

常用的BootLoader+APP框架

单片机升级的原理大致是:收到升级指令——>MCU复位或者跳转到Boot程序区——>擦除对应的Flash区域——>获取APP数据——>写入FLASH数据——>校验——>跳转到APP应用程序区

单APP单APP方案将Flash分成了三个部分,Boot+APP+Config,Boot负责更新APP;APP实现程序的主要功能;Config区域主要是存放APP是否完整的标志位,协助Boot判断是否要跳转到APP。单APP有个明显的缺点:开始升级时就将原来的APP擦除了,如果升级中断则会一直停留在BootLoader,直至APP升级完成。

方法2 :STM32系统自带BootLoader程序

1)STM32自举具体信息可以去官网查看手册AN2606
如果BOOT0为高电平,复位后将从系统存储器自举(系统存储区存放着系统bootLoader,出厂时,官方固化在单片机中的一段代码,用户无法修改的。在STM32中,常用的串口下载,DFU就是系统bootLoad中的功能)

 

2)使用系统bootLoader需要在复位时调整BOOT0管脚的电平,使用起来还是比较麻烦的。系统BootLoader也是FLash中的一段程序,只不过是官方烧录的不可修改的,我们可以利用前面说的跳转到APP的方法跳转到系统BootLoader,这样就可以不修改BOOT0管脚电平,直接进入系统BootLoader,利用系统BootLoader的下载功能下载更新程序。

 

在手册中的闪存章节,找到系统BootLoader的起始地址0x1FFF F000,将APP_ADDR宏定义改为系统BootLoader地址即可跳转到系统BootLoader

/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0)  /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#define APP_ADDR    0x1FFFF000         /* 系统bootloader地址 */
/*
*********************************************************************************************************
* 函 数 名: JumpToApp
* 功能说明: 跳转到APP
* 形    参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void JumpToApp(void)
{
  void (*SysMemBootJump)(void);        /* 声明一个函数指针 */
  __IO uint32_t AppAddr = APP_ADDR;    /* 跳转地址 */
    
  /* 如果初始化了外设,需要反向初始化外设 */
  
  /* 设置所有时钟到默认状态,使用HSI时钟 */
  HAL_RCC_DeInit();

  /* 关闭滴答定时器,复位到默认值 */
  SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;

  /* 关闭全局中断 */
  DISABLE_INT();
    
  /* 关闭所有中断,清除所有中断挂起标志 */
  for (uint32_t i = 0; i < 8; i++)
  {
    NVIC->ICER[i]=0xFFFFFFFF;
    NVIC->ICPR[i]=0xFFFFFFFF;
  } 

  /* 使能全局中断 */
  ENABLE_INT();

  /* 设置SysMemBootJump为中断服务函数入口地址,首地址是MSP,地址+4是复位中断服务程序地址 */
  SysMemBootJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));

  /* 设置主堆栈指针 */
  __set_MSP(*(uint32_t *)AppAddr);

  /* 在RTOS工程,这条语句很重要,设置为特权级模式,SP使用MSP指针 */
  __set_CONTROL(0);

  /* 进行跳转 也就是将SysMemBootJump 赋值给PC */
  SysMemBootJump(); 

  /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
  while (1)
  {

  }
}


3)从APP跳转到系统BootLoader后,利用STM32CubeProgrammer工具更新程序

 

 

STM32F103写入Flash:http://t.csdn.cn/JDMr6

原文引入文章:http://t.csdn.cn/GwKKq

————————————————
版权声明:本文为CSDN博主「不咸不要钱」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42378319/article/details/javascript:;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值