STM32
直播中

回头太晚

9年用户 811经验值
擅长:可编程逻辑 电源/新能源
私信 关注
[问答]

MCU bootload IAP程序是如何跳转的

MCU bootload  IAP程序是如何跳转的?需要注意哪些事项呢?

回帖(1)

庄雪昕

2021-11-29 09:06:51
这里是引用

                 https://www.jianshu.com/p/2eef44b1cfd3        <>
                 https://blog.csdn.net/tq384998430/article/details/81010002<<设计一款STM32的BootLoader>>
                 https://blog.csdn.net/baideweidao/article/details/82774808<>
                 http://news.eeworld.com.cn/mcu/2018/ic-news081940854.html<>
                 https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/<>
                 https://blog.csdn.net/yangzhao0001/article/details/73293379<>                 
                 ...
由于我写的GD的32E230 ARM® Cortex®-M23核,与STM32有些库不太一样,根据参考文献自己写了段代码测试发现可以跳转,单独使用boot和app都没有问题,但一组合app就频繁重启,经过同事帮助下才找到问题根本.
MCU启动是从FLASH起始地址开始的;ARM® Cortex®-Mxx常见的FALSH起始地址0x08000000.
我们现在把bootload代码区放在0x08000000,根据需要划分4K~16K的空间,空间必须FLASH最小块的整倍数;剩下的用来放应用程序(APP)代码.
代码划分参考"百度"<<分散加载>>.
bootload跳转代码及注意:

#define APP_ADDRESS             (uint32_t)0x08004000
/* Private typedef -----------------------------------------------------------*/
typedef void (*pFunction)(void);            /*!< Function pointer definition */


void vJumpToApplication(void)
{
    uint32_t  JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
    pFunction Jump_To_Application;
       
        if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000)  //ApplicationAddress为新程序的起始地址,检查栈顶地址是否合法,即栈顶地址是否为0x2000xxxx(内置SRAM)
        {
                usart_disable(USART0);        //这里是在跳转前关闭已经初始化的外设
                usart_disable(USART1);               
                rcu_deinit();               
                __set_MSP(*(__IO uint32_t*) APP_ADDRESS);                    //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
                SCB->VTOR = APP_ADDRESS;                                                                //重定向中断向量表
                       
                JumpAddress = *(__IO uint32_t*) (APP_ADDRESS + 4);           //用户代码区第二个字存储为新程序起始地址(新程序复位向量指针)
                Jump_To_Application = (pFunction) JumpAddress;            
                Jump_To_Application();                                        //设置PC指针为新程序复位中断函数的地址
        }       
        else
        {
                printf("!!!!!!ERROR:APP_ADDRESS ERR!!!!!!!!!n");
        }
}
注意:无意中参考到部分资料中说跳转前要屏蔽中断调用__set_PRIMASK(1),我就在这句话中上当.
在跳转前调用用屏蔽了中断,跳转后如果不及时恢复(正常情况不会有人去恢复)那么代码就会进不了中断造成异常.
正常情况下在跳转前需要关闭在bootload中打开的外设,初始化APP堆栈指针;中断向量表可选择是否重定向.
用户程序(APP)需要修改内容:
在main()第一行加入以下代码
SCB->VTOR = 0x08004000;
如果boolload和APP是分开烧写,就参考普通<<分散加载>>处理就可以了;现在我希望把bootload的代码以库或者镜像的方式直接加载在APP程序中,这样就不用合并两份代码:
链接文件

APP 0x08004000 0x0000C000  {    ; load region size_region
  app_update.bin 0x08004000 0x0000C000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00002000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
//这个区域用来加载bootload镜像
UBOOT 0x08000000 0x00004000  {    ; load region size_region
  boot.bin 0x08000000 0x00004000  {  ; load address = execution address
   *(.boot)
  }
}


新建一个.S文件

        AREA         |.boot|, DATA, READONLY
        ALIGN   4
                       
        EXPORT  __uboot_start_addr
__uboot_start_addr          ;Must set the top


        INCBIN ../BootLoad/HJ-GD32E230-boot.img        ;这里就是引用我们的bootload的镜像
               
        END


这里说明一下"__uboot_start_addr",这是用汇编声明的一变量,在这里本来是任何作用,那为什么还要声明呢?是因为如果只是这样将bootload加载到app程序中,bootload并不能被编译到应用程序中,这里就需要在app中调用一下这个变量,这样bootload镜像就能被正常加载,如:printf("%x",__uboot_start_addr);
如果各位大佬就更好的方法请不吝赐教.
bootload代码如果输出.bin或.img文件,使用以下.
C:Keil_v5ARMARMCCbinfromelf.exe --bin --output “                              L                      @                      L                      .                      i                      m                      g                      "                      "                          L@L.img" "               L@L.img""L@L.axf”


举报

更多回帖

发帖
×
20
完善资料,
赚取积分