打印
[APM32F1]

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

[复制链接]
532|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
DKENNY|  楼主 | 2023-12-24 17:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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跳转的代码:
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url]       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种情况的例程,有需要的可查看。
Example Project.zip (2.03 MB)

       以上,就是本次分享的内容了,如有问题,欢迎讨论。

   
  


  

使用特权

评论回复
评论
forgot 2023-12-27 08:48 回复TA
赞 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

39

主题

66

帖子

6

粉丝