GD32 IAP固件升级:Bootloader到APP的踩坑指南

GD32_IAP升级跳转踩坑解答

  • GD32升级进入HardFaultHandler()原因分析
  • 第一个坑
  • 第二个坑
  • 函数指针跳转 和 系统复位 的区别
  • 函数指针跳转
  • 系统复位
  • GD32升级进入HardFaultHandler()原因分析

    大家好!随着全球芯片紧缺,许多企业纷纷选择了国产芯片。今天我就GD32(兆易创新)MCU的固件升级所遇到的问题给大家说说我的看法。相信使用GD芯片的工程师,都看过GD给出的Demo例程,关于IAP的,有一个BOOT(LED慢闪),按下按键跳转至APP(LED快闪)的例程。 这里看似没啥问题,大家注意其中有2个坑

    第一个坑

    BOOT程序(或者叫IAP程序) 和 APP FLASH划分

    1. BOOT通常来说比较小 最多也就10K多,大家看看我的配置

      BOOT程序起始地址:0x8000000
      SIZE我分配了0x2000 ,也就是8k字节 , BOOT程序编译下来需要比8k小

    2. app程序起始地址:0x8010000

      SIZE我分配了0x80000(最大) , 实际上APP程序不会有这么大,没关系就写这个。

    第二个坑

    跳转问题:
    1.BOOT跳转至APP时,调用这个代码即可
    __disable_irq(); // 可以使用这个函数 关闭总中断

    JumpAddress = *( __IO uint32_t* )( ApplicationAddress + 4 );            //用户代码区第二个字存储为新程序起始地址(新程序复位向量指针)
    Jump_To_Application = ( pFunction ) JumpAddress;
    __set_MSP( *( __IO uint32_t* ) ApplicationAddress );                    //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
    
    
    Jump_To_Application();                                                  //设置PC指针为新程序复位中断函数的地址
    

    这一步都没啥问题,把跳转地址填对(就是APP程序的起始地址)

    2.APP跳转至BOOT
    这里问题就大了,用BOOT的方法,将地址替换成BOOT的起始地址0x8000000,你会发现,也可以成功,但是,再从BOOT跳转至APP的时候 就有问题了, 进入APP程序后,初始化外设时,会进入HardFaultHandler();硬件错误中断函数,一直停留在while(1); 这是为啥???

    函数指针跳转 和 系统复位 的区别

    大家看到没有,BOOT跳转至APP的方法是,使用函数指针,调用时,使得PC指针指向APP所在位置,但是这个方法用在 APP跳向BOOT的时候,却不严谨。

    函数指针跳转

    函数指针跳转,仅仅是将PC指针 指向 目标地址,MCU是有堆栈的呀,光跳转过去,不清除堆栈.有可能出现RAM溢出(你的APP程序占用RAM比较大就会出现这个情况), 进入HardFault硬件错误中断的情况之一:堆栈溢出。 就会出现 BOOT第一次跳转至APP,都正常 ,APP跳转BOOT之后 , 第二次再从BOOT使用函数指针跳转APP,进入 HardFault硬件错误中断 , 因为第一次从BOOT跳转APP时,BOOT并没有占用太多的RAM, 所以哪怕不清除堆栈, 依然够用, 那么第二次再跳转APP的时候,. 之前在APP时已经初始化太多变量和函数,消耗了太多的RAM,这时不清除堆栈,再次进入APP, MCU就会因为堆栈不够,发生溢出,导致进入了硬件错误中断。

    系统复位

    前面我已经说了跳转导致进入硬件错误中断的原因, 知道了原因问题就已经解决了一半,怎么解决? 我清除堆栈不就行了麻。 怎么清除? 大家麻烦去百度一下 这个函数 NVIC_SystemReset(); 看名字就知道,是系统复位函数, 是的,这个函数会将相关标志位清除,具体是哪一行我不知道,但是这个函数确实能清除堆栈,使用这个函数,实现 APP跳转至 BOOT, 就能够避免因为堆栈溢出,而导致进入硬件错误中断。 上源码

    	__disable_irq();  // 可以使用这个函数 关闭总中断
    	__set_FAULTMASK(1);	//关闭中断,确保跳转过程中 不会进入中断,导致跳转失败
    	NVIC_SystemReset();	  //系统复位,复位后默认从MCU的起始地址开始, 也就是BOOT的起始地址开始, 这样程序就从APP回到了BOOT,再从BOOT跳转至APP的时候, 堆栈已经清除了,也就不会发生溢出
    
    
    
    
    
    
    
    
    
    	上面是我写给自己的, 避免以后再犯错, 在下能力有限 如有不对之处,恳请大佬指点,感激不尽!
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » GD32 IAP固件升级:Bootloader到APP的踩坑指南

    发表评论