DKENNY 发表于 2023-12-24 17:28

IAP固件升级跳转方式及比较(下)

本帖最后由 DKENNY 于 2023-12-24 17:32 编辑

       承接上文,这篇主要对比一下APM32系列中实现IAP固件升级的3种方式。

       上节阐述了VTOR寄存器的作用,IAP固件升级也是与VTOR寄存器有关的,下面具体介绍一下这3种方式,主要是当APP产生中断时,其对应的中断向量表的查找方式。
1. 有VTOR寄存器
   在有VTOR寄存器的情况下,我们直接设置VTOR的值,直接指向APP的中断向量表的入口地址。
       在APM32F1(CORTEX-M3) 中就支持中断向量重定向,因为它有VTOR寄存器,可以重新设置中断向量在FLASH中的地址,这个功能使IAP实现变得非常完美。
       如下APP的main.c代码。int main(void)
{
    SCB->VTOR = FMC_BASE | 0x4000;

    SysTick_Config(SystemCoreClock / 1000);
    APM_MINI_LEDInit(LED2);
   
    while (1)
    {
      Delay();
      APM_MINI_LEDToggle(LED2);
    }
}       如下的System_Init()函数,也成功设置了中断向量表的偏移量,如果没有VTOR寄存器,下面的代码是不起作用的。#ifdef VECT_TAB_SRAM
    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
    SCB->VTOR = FMC_BASE | VECT_TAB_OFFSET;
#endif              若APP产生了中断,其对应的中断执行流程如下。      
       因为APP有自己的中断向量表,所以当APP产生中断时,会直接从VTOR所设置的地址查找中断向量表,执行对应的中断服务函数。
       如下是KEIL的配置,只需设置APP的FLASH的起始地址即可。

2. 无VTOR寄存器       有些芯片内核没有VTOR寄存器,即使这样,仍然有两种方式可以进行中断的相关处理,一种是中断向量表重映射,另一种是中断服务函数重定位。
2.1 中断向量表重映射       由于没有VTOR寄存器,所以我们可以在APP代码中,先将APP的中断向量表从FLASH中复制到RAM里,再将RAM区映射到vector table区域。
       以下是中断向量表重映射的相关寄存器。       (1)当MEM_MODE=00/10时,MainFlash映射到地址0x00000000,即地址0x08000000映射到0x00000000.       (2)当MEM_MODE=01时,SystemFlash映射到地址0x00000000,也就是芯片自带的Bootloader代码部分会映射到地址0x00000000,即0x1FFFC800映射到地址0x00000000.       (3)当MEM_MODE=11时,SRAM映射到地址0x00000000,也就是内存地址0x20000000映射到地址0x00000000.
       那么,中断向量表的固定地址是多少呢?在ARM官网上我们找到如下信息:
       也就是说,在没有VTOR寄存器时,中断向量表的地址固定在地址0x00000000上。       在这个过程中,中断的调用过程如下:            ->产生中断            ->CPU固定到地址0x00000000上找中断入口函数,由于映射关系,实际上是在从映射地址上寻找,即0x20000000。            ->找到并执行中断例程
       若使用这种方式进行IAP的固件升级,则必须在APP中将中断向量表拷贝到SRAM,并将系统重映射到SRAM,这样才能使中断恢复正常工作。       如下为实现IAP跳转的代码:/*!
* @brief       Jump to user application
*
* @param       Application : APP1 or APP2
*
* @retval      None
*
* @note
*/
void Jump_to_App(uint8_t Application)
{
    uint32_t address;

    /* Lock the Program memory */
    FMC_Lock();


    if(Application == APP1)
    {
      address = USER_APP1_START_ADDRESS;
    }
    else
    {
      address = USER_APP2_START_ADDRESS;
    }

    /* Jump to user application */
    JumpAddress = *(__IO uint32_t *) (address + 4);
    Jump_To_Application = (pFunction) JumpAddress;

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t *) address);

    /* Jump to application */
    Jump_To_Application();
}
       其具体的中断服务函数的实现流程如下图所示:
       当APP产生中断时,系统会选择根据MEM的映射方式,去0x00000000查找中断向量表,执行其对应的中断服务函数。
       如下为KEIL的相关配置:
       为什么设置IRAM1的Start地址为0x200000C0?       RAM区是用来存放程序运行时的一些变量,设置RAM区地址从0x200000C0,是因为0x20000000处存放了中断向量表,这是为了防止中断向量表被变量重新覆写。
2.2中断服务函数重定位       这种方式下,它并没有将中断向量表重映射,而是将中断服务函数进行了重定位,直接跳转到对应的中断服务函数。       在IAP程序中定义APP_interrupt_vector_addr(存储在0x20000000)变量,用于处理IAP中断函数,以响应正确的中断,该变量是一个标志位。       各个工程均需初始化变量FLASH_interrupt_vector(存储在0x20000004)变量,用于指向当前系统所需的中断服务函数,该变量是一个标志位。
       如下为IAP的中断服务函数,目的是为了判断当前是哪个APP发生了中断,跳转到对应APP的中断服务函数.
       同时在APP1中,更改FLASH_interrupt_vector,设置为APP1_INTERRUPT_VECTOR,代表指向APP1的中断向量表。
       具体的执行流程图如下:
       当APP产生中断时,其具体的执行流程如下:
   在这种情况下,当APP产生中断时,会去查找IAP的中断向量表,在IAP的中断服务函数里直接跳转到APP的中断服务函数。

       如下为KEIL的相关配置。


       为什么设置IRAM1的start值为0x20000008 ?       因为在0x20000000处存放了两个常量,常量类型为uint32_t,故一个变量占4个字节,两个常量占8个字节,这两个常量在程序运行时是不能被轻易修改的。程序运行时,会在RAM区生成一些数据,为了防止这两个常量被这些数据覆盖,从而影响后续的中断响应及中断服务函数的跳转。
3. 相关例程       附件中含上述3种情况的例程,有需要的可查看。
       以上,就是本次分享的内容了,如有问题,欢迎讨论。

   



风暴之眸 发表于 2025-4-22 19:25

直接跳转修改PC指针的方式 不就行了吗?
怎么感觉这活干复杂了呢?
还是我没有充分理解的楼主的项目需求?
页: [1]
查看完整版本: IAP固件升级跳转方式及比较(下)