STM32分区跳转问题

项目场景:

在OTA中,FLASH通常被划分为以下几种类型

  • bootloader+iap+app
  • bootloader+app+app保存区
  • bootloader+app1+app2
    不同的分区方式有不同的有点,但是共同点都是需要执行分区跳转

问题1描述

但在分区跳转过程中遇到过使用不同的编译器不能跳转的情况,例如在keil中使用v5编译器可以正常跳转,但是使用v6编译器就无法跳转了。

void JumpToCode(uint32_t addr) {
    uint32_t *inputAddr = (uint32_t *)addr;
    uint32_t jumpAddr  = *(uint32_t *)(addr + 4);
    if ((*inputAddr & 0x2FFE0000) == 0x20000000) {
        __set_MSP(*inputAddr);
        ((void (*)(void))jumpAddr)();
    }
}

问题1原因分析:

发现v6和v5的编译优化不一样,v6编译执行__set_MSP后,跳转地址变量jumpAddr被释放,就不能正确跳转了。把地址相关的变量声明为全局变量就可以正常跳转了

uint32_t *inputAddr;  // !声明为全局变量,防止执行__set_MSP后,变量被释放
uint32_t jumpAddr;    // !设置MSP后改变了栈底地址,导致原来的局部变量范围出了新栈的空间,被系统释放

void JumpToCode(uint32_t addr) {
    inputAddr = (uint32_t *)addr;
    jumpAddr  = *(uint32_t *)(addr + 4);
    if ((*inputAddr & 0x2FFE0000) == 0x20000000) {
        __set_MSP(*inputAddr);
        ((void (*)(void))jumpAddr)();
    }
}

问题2描述

裸机时可以正常跳转,但是开启freertos后分区无法相互跳转,度娘说要跳转前需要关闭全局中断、关闭外设。我采用的分区方式是bootloader+iap+app,boot跳转前关闭中断和外设后,跳转freertos的app分区没有问题,而跳转裸机的iap分区时无法运行,发现卡在初始化中。为什么跳freertos就ok呢?最后发现MX_FREERTOS_Init的时候自动把中断打开了,原来跳转后在main函数中需要重新开启中断,在其他所有裸机的main函数的while前添加__set_FAULTMASK(0)开启中断即可,freertos不需要。修改后的跳转代码如下:

uint32_t *inputAddr;  // !声明为全局变量,防止执行__set_MSP后,变量被释放
uint32_t jumpAddr;    // !设置MSP后改变了栈底地址,导致原来的局部变量范围出了新栈的空间,被系统释放

void JumpToCode(uint32_t addr) {
    inputAddr = (uint32_t *)addr;
    jumpAddr  = *(uint32_t *)(addr + 4);
    if ((*inputAddr & 0x2FFE0000) == 0x20000000) {
        HAL_RCC_DeInit();
        HAL_DeInit();
        __set_FAULTMASK(1);

        __set_MSP(*inputAddr);
        ((void (*)(void))jumpAddr)();
    }
}

问题3描述

boot可以跳iap和app了,但是!但是app无法跳iap,最后发现FREERTOS运行在PSP模式,而裸机运行在MSP模式,尝试跳转前设定MSP就正常了,添加__set_CONTROL(0),最终的跳转如下:

uint32_t *inputAddr;  // !声明为全局变量,防止执行__set_MSP后,变量被释放
uint32_t jumpAddr;    // !设置MSP后改变了栈底地址,导致原来的局部变量范围出了新栈的空间,被系统释放

void JumpToCode(uint32_t addr) {
    inputAddr = (uint32_t *)addr;
    jumpAddr  = *(uint32_t *)(addr + 4);
    if ((*inputAddr & 0x2FFE0000) == 0x20000000) {
        HAL_RCC_DeInit();
        HAL_DeInit();
        __set_FAULTMASK(1);
        __set_CONTROL(0);

        __set_MSP(*inputAddr);
        ((void (*)(void))jumpAddr)();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32分区固件开发指的是在STM32单片机上使用分区概念来进行固件开发的一种方法。分区是将存储器划分为不同的区域,每个区域具有不同的属性和功能。在STM32分区固件开发中,常用的分区有代码区、数据区、堆栈区和外设寄存器区。 在代码区,存放着程序的指令,包括正文段和初始化段。正文段包含了程序的主要逻辑代码,而初始化段包含了程序的初始化代码。 数据区主要用于存放程序的数据,包括全局变量、静态变量和常量。这些数据在程序运行过程中可能会被修改。 堆栈区用于存放函数的参数和局部变量。每当函数被调用时,相关的参数值和局部变量都会被压入堆栈中,函数执行完成后再从堆栈中弹出。 外设寄存器区用于存放与外部设备交互的寄存器值。通过读写这些寄存器,可以实现与外部设备的通信和控制。 使用分区的好处是可以更好地组织代码和数据,提高程序的可读性和可维护性。同时,分区可以让我们更精确地控制程序的运行和存储资源的分配,充分发挥STM32单片机的性能。 在STM32分区固件开发中,开发者可以根据程序的需求和资源的分配情况,对不同的分区进行灵活的配置和优化。这需要开发者对STM32单片机的特性和存储器的结构有一定的了解和掌握。可以通过使用相关的开发工具和软件库,来简化分区的配置和使用过程。 总之,STM32分区固件开发是一种灵活而高效的开发方法,可以使程序在STM32单片机上得以高效运行,并充分利用其性能和资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值