您当前的位置: 首页 > 

不脱发的程序猿

暂无认证

  • 0浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

电子产品如何使用IAP方式升级程序

不脱发的程序猿 发布时间:2020-11-29 23:13:55 ,浏览量:0

目录

1、ICP、ISP和IAP的概念

2、IAP升级程序的原理

3、IAP升级程序的流程

4、IAR环境下IAP的实现

4.1、BootLoader程序设计

4.2、User Application程序设计

4.3、IAR地址配置及文件输出

5、拓展:解析HEX文件

1、ICP、ISP和IAP的概念

在项目开发过程中通常使用SWD、JTAG等工具进行程序烧录和仿真,若产品节点较少还是比较方便,但是当设备节点量产时,就需要使用IAP的方式进行程序烧录。

简单说明几个概念ICP、ISP和IAP。

ICP In-circuit programmer

ICP:在电路编程,MCU内部不需要有程序,上电就能够对程序存储区域进行编程,例如平时使用JTAG、SWD等方式。

ISP In-system programer

ISP:在系统编程,通过MCU专用的串行编程接口进行编程,MCU需要具有运行的外部条件,例如有晶振等。

例如STM32通过设置BOOT引脚设置对应启动模式,然后通过串口等对内部Flash进行升级,可以说这种方式就是厂家在芯片内部固化了一个BootLoader程序。

IAP In-application programer 

IAP:在应用编程,开发者设计BootLoader程序,通过串口、CAN、以太网等通信方式实现程序升级。

2、IAP升级程序的原理

通常一块MCU芯片的Code(代码)区内只有一个用户程序,而IAP方案则是将代码区划分为两部分,两部分区域各存放一个程序,一个为BootLoader(引导加载程序),另一个为User Application(用户应用程序)。

BootLoader在出厂时就固定下来了,在需要变更User Application时只需要通过触发BootLoader对User Application的擦除和重新写入即可完成用户应用的更换。

程序执行初始化后首先会进入BootLoader,在BootLoader里面检测条件是否被触发(可通过按键是否被按下、串口是否接收到特定的数据、U盘是否插入等),如果有则进行对User Application进行擦除和重新写入操作新程序,如果没有则直接跳转到BootLoader执行User Application。

3、IAP升级程序的流程

假设设备仅有User Application,以STM32F103ZET6为例,其启动方式有三种:内置FLASH启动、内置SRAM启动、系统存储器ROM启动。通过BOOT0和BOOT1引脚的设置可以选择从哪中方式启动,这里选择内置的FLASH启动,STM32F103ZET6 FLASH的地址为0x08000000—0x0807FFFF,共512KB。

通常STM32发生中断的过程为以下五步:

1、发生中断(中断请求);

2、到中断向量表查找中断函数入口地址;

3、跳转到中断函数;

4、执行中断函数;

5、中断返回。

也就是说,STM32的内置的Flash中有一个中断向量表来存放各个中断服务函数的入口地址,内置Flash的分配情况如下图所示:

所以当只有一个程序的情况下(仅有User Applicatio时),程序执行的走向如下所示:

解析上图:

STM32F103ZET6有一个中断向量表,这个中断向量表存放在代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是堆栈栈顶的地址,当发生中断后程序通过查找该表得到相应的中断服务程序入口地址,然后再跳到相应的中断服务程序中执行。

设备上电后从0x08000004处取出复位中断向量的地址,然后跳转到复位中断程序的入口(标号①所示),执行结束后跳转到main函数中(标号②所示)。在执行main函数的过程中发生中断,则STM32强制将PC指针指回中断向量表处(标号③所示),从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数(标号④所示),执行完中断函数后再返回到main函数中来(标号⑤所示)。

下面要讲正题了。

若将STM32F103ZET6在内置的Flash里面添加User Application和BootLoader程序,则Flash分配情况大致如下图所示:

此时,User Application和BootLoader程序各有一个中断向量表,假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如下图所示:

解析上图:

设备上电初始程序依然从0x08000004处取出复位中断向量地址,执行复位中断函数后跳转到IAP的main(标号①所示),在IAP的main函数执行完成后(在BootLoader里面检测条件是否被触发(可通过按键是否被按下、串口是否接收到特定的数据、U盘是否插入等),如果有则进行对User Application进行擦除和重新写入操作新程序,如果没有则直接跳转到BootLoader执行User Application)强制跳转到0x08000004+N+M处(标号②所示),最后跳转到新的main函数中来(标号③所示),当发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,再跳转到新的中断服务函数中执行(标号④⑤所示),执行完中断函数后再返回到main函数中来(标号⑥所示)。

4、IAR环境下IAP的实现

以IAR环境为例,简单讲述IAP的实现步骤。这里MCU以华大HC32L130为例,因为使用的MCU不同,所以实现的细节也不一致,但是基本上官方都会提供Demo例程。

本示例Flash分配情况为:BootLoader地址:0x00000000~0x00000DFF,User Application地址:0x00001000~0x0000FFFF。

4.1、BootLoader程序设计

第1步:设计总体架构,包含三个功能函数:检测BootLoader标志程序、IAP配置程序和IAP烧录功能程序。

/**
 *******************************************************************************
 ** \brief  IAP 主函数
 **
 ** \param  None
 **
 ** \retval int32_t Return value, if needed
 **
 ******************************************************************************/
int32_t main(void)
{
    IAP_UpdateCheck();
    IAP_Init();
    IAP_Main();
}

第2步:检查BootPara标记区数据值,判断是否需要升级APP程序,若需要升级则才会执行IAP_Init()和IAP_Main()函数,否则会直接跳转到User Application程序。

/**
 *******************************************************************************
 ** \brief  检查BootPara标记区数据值,判断是否需要升级APP程序.
 **
 ** \param  None
 **
 ** \retval None
 **
 ******************************************************************************/
void IAP_UpdateCheck(void)
{
    uint32_t u32AppFlag;
    
    u32AppFlag = *(__IO uint32_t *)BOOT_PARA_ADDRESS; //读出BootLoader para区标记值
    if (APP_FLAG != u32AppFlag)                       //如果标记值不等于APP_FLAG,表示不需要升级APP程序
    {
        IAP_JumpToApp(APP_ADDRESS);                   //则直接跳转至APP
    }    
}

第3步:IAP_Init()函数的实现,主要包括外围模块初始化和IAP通信协议标志初始化。

/**
 *******************************************************************************
 ** \brief  IAP 初始化
 **
 ** \param  [in] None
 **
 ** \retval None
 **
 ******************************************************************************/
void IAP_Init(void)
{
    PreiModule_Init();
    Modem_RamInit();
}

/**
 *******************************************************************************
 ** \brief CPU外围模块初始化
 **
 ** \param [in] None
 **
 ** \retval None
 **
 ******************************************************************************/
void PreiModule_Init(void)
{
    HC32_SetSystemClockToRCH22_12MHz();
    HC32_InitUart();
    HC32_InitCRC();
    HC32_InitTIM();
    HC32_InitFlash(FLASH_CONFIG_FREQ_22_12MHZ);
}

/**
 *******************************************************************************
 ** \brief modem文件中相关变量参数初始化
 **
 ** \param [out] None
 ** \param [in]  None
 **
 ** \retval None
 **
 ******************************************************************************/
void Modem_RamInit(void)
{    
    uint32_t i;
    
    enFrameRecvStatus = FRAME_RECV_IDLE_STATUS;                         //帧状态初始化为空闲状态
    
    for (i=0; i            
关注
打赏
1664101891
查看更多评论
0.0359s