基于STM32f103芯片的应用程序在线升级功能框架的实现

本文详细介绍了如何在STM32f103芯片中实现应用程序的在线升级功能,包括Bootloader的设计、KEIL软件配置、固件版本控制和升级过程中的通信与擦除操作。
摘要由CSDN通过智能技术生成

目录

基于STM32f103芯片的应用程序在线升级功能框架的实现

一、原理简介

二、KEIL软件主要设置

三、应用程序app部分

四、Bootloader部分

五、补充部分


基于STM32f103芯片的应用程序在线升级功能框架的实现

一、原理简介

我们在使用stm32的过程中,如果需要对芯片的软件程序进行在线升级,一般会将软件程序分为bootloader程序以及应用程序app。
在bootloader程序中,系统上电后,通过进行条件判断确定是否需要对硬件板卡进行软件升级,如果不需要进行升级就直接跳转到app程序进行执行。如果需要进行软件升级,那么就在bootloader中完成对软件的升级操作。这里以stm32f103ze系列进行说明。    

二、KEIL软件主要设置

这里将软件程序分为bootloader和app两部分。
其中bootloader代码部分的起始地址为:0x08000000,大小为0x4000(16KB);
app部分的代码起始地址为:0x08004000,大小为0x7C000(512KB-16KB)。    //芯片flash总大小为512KB
在keil软件的魔术棒下的Target设置框下,按照以上信息在IROM1中分别设置好软件程序对应的起始地址和大小即可。

三、应用程序app部分

1、固定版本号信息
在应用程序app中,可以通过固化app程序版本号的位置作为后续判断硬件板卡是否需要升级的条件。具体代码如下:  
//在app中固定硬件板卡版本号V1.00的存储位置为0x0800F800。
const unsigned char Ver[6] __attribute__ ((at(0x0800F800)))= {'V','1','.','0','0'};
固定好硬件板卡的版本号信息后,我们后续在bootloader中通过读取该位置的版本号信息进行判断是否需要进行升级操作。
2、升级前擦除版本号所在的flash页内容。
关于对stm32的flash进行擦除的操作,不同的芯片操作方式可能有所不同。有的芯片是按页进行擦除有的芯片是按照扇区进行擦除。这里使用的stm32f103是采用页擦除的方式。具体代码如下:
    
void RunUpdateCommand()
{
    uint8_t *p;
    p = (uint8_t *)((uint32_t)0x0800F800);
    printf("擦除前FLASH地址0x0800F800存放的字符为:%c\n",*p);
    
    FLASH_Unlock();
    if(FLASH_ErasePage(0x0800F800) == FLASH_COMPLETE)
    {
        FLASH_Lock();
        printf("擦除后FLASH地址0x0800F800存放的字符为:%c\n",*p);  
    }
    printf("================进入bootloader程序===============\n");
    NVIC_SystemReset();
    while(1);
}
​
这里在app程序中,进入bootloader程序执行升级操作前首先会擦除原来的版本号所在的flash页内容。然后使用函数NVIC_SystemReset()进行复位操作从而进入到bootloader程序中。
3、app的主函数部分代码
应用程序app主函数main的主要代码如下:
    
void main()
{
    SystemInit();   //系统初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组
    NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000);     //设置app程序的向量表偏移位置
    
    __disable_irq();
    /* 在这里进行硬件外设的初始化操作*/
    
    __enable_irq();
    
    while(1)
    {
       //应用程序的代码部分    
    }
}

四、Bootloader部分

bootloader部分的核心代码如下:
​
typedef void (*pFunction)(void);    //定义函数指针pFunction,用于实现函数的跳转
​
//定义APP版本号地址,需要和app中的存储地址对应
#define APP_VERSION_ADDR    ((uint32_t)0x0800F800)  
​
//定义APP的起始地址,需要和keil软件中的设置对应并且和app主函数中的向量表的偏移地址对应。
//这里可知偏移地址为0x08004000 - 0x08000000 = 0x4000。
#define Application_Address ((uint32_t)0x08004000)
​
uint32_t JumpAddress;
​
pFunction Jump_To_Application;
​
void main()
{
    uint8_t ch1;
    
    SystemInit();   //系统初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组
    
    __disable_irq();
    /* 在这里进行硬件外设的初始化操作*/
    /*对于仅仅用于升级流程的初始化操作也可以放到while(1)前进行初始化*/
    //通讯串口初始化
    //调试串口初始化等等
    __enable_irq();
    
    //================================================================================
    ch1 = *(uint8_t *)(APP_VERSION_ADDR)
    if(ch1 == 'V')  
    {
        JumpAddress = *(__IO uint32_t *)(Application_Address + 4);  //app程序复位的地址
        Jump_To_Application = (pFunction)JumpAddress;
        __set_MSP(*(__IO uint32_t *)Application_Address);           //初始化app的栈指针
        printf("================进入应用程序APP===============\n");
        Jump_To_Application();  //跳转到app程序
        while(1);
    }
    //备注:双线之间的程序是通过读取应用程序存储在0x0800F800地址的版本号V1.00中的字符'V'
    //是否存在来判断是否需要执行程序升级的。
    //如果字符'V'依旧存在那就不需要升级直接跳转进入app程序即可。
    //如果字符'V'不存在(因为在进入boorloader升级之前在app中已经把对应页擦除掉了),
    //表示app程序需要进行升级操作,那么就不再跳转进入app程序,而是接着执行升级程序的操作。
    //================================================================================
    
    //这里可以初始化那些仅仅用于升级流程的初始化操作,比如初始化队列,或者初始化系统指示灯等。
    while(1)
    {
       /*升级程序的代码实现操作*/ 
        
       //注意在升级完成后,同样可以使用函数NVIC_SystemReset()进行复位操作
       //使得系统重新由bootloader跳转到app中。 
    }    
}

五、补充部分

补充一:
    对于bootloader中升级程序的代码实现思路,我这边是通过串口与上位机通讯进行操作的,
    在串口接收中断中将上位机发来的数据存放到队列中,然后根据升级流程从队列中读取相关内容。
    整个升级流程大致分为:
    1、握手(联机)
    2、擦除app的FLASH空间内容
    3、对之前擦除的FLASH写入新的升级程序数据,该步骤又可以细分为:
        ①接收每次写入flash的起始地址
        ②接收每次写入flash的数据长度
        ③接收每次写入的具体数据并进行数据校验
        ④调用接口将升级数据写入flash
    4、升级成功,调用函数接口NVIC_SystemReset()重启系统由bootloader进入app程序。
    以上的各步骤都可以和上位机之间添加应答机制。进一步保证通讯的可靠性。
    
补充二:
    如果在bootloader程序跳转进入到app程序后发现在app中无法进入中断,
    可能是因为app主函数中的以下代码的顺序有问题:
    SystemInit();   //系统初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组
    NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000);     //设置app程序的向量表偏移位置
​
    在app的main函数中要确保SystemInit()系统初始化函数放在
    NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000)设置向量表偏移位置函数之前。
完结。。。
  • 36
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牧以南歌〆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值