[MM32生态]

MM32F103 串口 BootLoader 升级(一)

[复制链接]
417|0
手机看帖
扫描二维码
随时随地手机跟帖
Zhiniaocun|  楼主 | 2025-6-10 17:39 | 显示全部楼层 |阅读模式
前言
最近在研究通过串口进行代码程序的升级,参考网上教程进行移植bootloader和app,总结心得,只涉及简单的bootloader启动,具体使用时根据自身项目修改。可参考st官方链接官方链接:https://www.st.com/zh/embedded-software/stsw-stm32116.html#overview

一、使用的平台和工具
1、硬件:单片机为mm32F103

2、软件:Keil,SecureCRT8.3。

二、软件工具的下载
可参考网上下载**。

三、操作
1、bootloader生成
1.1 程序跳转
bootloader一个主要的功能就是首先程序的跳转。在芯片中只要将要跳转的地址直接写入到PC寄存器,就可以跳转到对应的地址中去。

当我们实现一个函数的时候,这个函数最终会占用一段内存,而它的函数名代表的就是这段内存的起始地址。当我们调用这个函数的时候,单片机会将这段

内存的首地址(函数名对应的地址)加载到PC寄存器中,从而跳转到这段代码来执行。那么我们也可以利用这个原理,定义一个函数指针,将这个指针指向我们想要跳转的地址,然后调用这个函数,就可以实现程序的跳转了

代码如下:

#define  APP_ADDR  0x08002000   //应用程序首地址定义
typedef void (*Jump_Fun)(); //函数指针类型定义

Jump_Fun jump2app; //定义一个函数指针

jump2app = ( Jump_Fun )(APP_ADDR + 4); //给函数指针赋值
jump2app(); //调用函数指针,实现程序跳转


上面的代码实现了我们要的跳转功能,但是为什么要跳转到(APP_ADDR + 4) 这个地址,而不是APP_ADDR 呢?

  首先我们要了解主控芯片的启动过程。在mm32中,在芯片上电的时候,首先会从内存地址位0x0800 0000(由启动模式决定)的地方加载栈顶地址(4字节),从0x0800 0004的地方加载程序复位地址(4字节),然后跳转到对应的复位地址去执行。

  所以上面的程序会中,jump2app这个函数指针的地址为(APP_ADDR + 4),调用这个函数指针的时候,芯片内核会自动跳转到这个指针指向的内存地址,也即是应用程序的复位地址。

1.2加载栈地址
  实际运行会发现,上面的程序可能会出现问题。因为我们还缺少了一个栈地址的加载过程,也就是芯片上电的第一个动作。这里要用到一点汇编的知识:

__asm void MSR_MSP(uint32_t addr)
{
    MSR MSP, r0
    BX r14;
}


__asm void MSR_MSP(uint32_t addr) 是MDK嵌入式汇编形式。

BX r14 跳转到连接寄存器保存的地址中,即退出函数,跳转到函数调用地址

完整的程序如下:

/* 采用汇编设置栈的值 */
__asm void MSR_MSP (uint32_t ulAddr)
{
    MSR MSP, r0                                //set Main Stack value
    BX r14
}
/* 程序跳转函数 */
typedef void (*Jump_Fun)(void);
void IAP_ExecuteApp (uint32_t App_Addr)
{
    Jump_Fun JumpToApp;
    if ( ( ( * ( __IO uint32_t * ) App_Addr ) & 0x2FFE0000 ) == 0x20000000 )    //检查栈顶地址是否合法.
    {
        JumpToApp = (Jump_Fun) * ( __IO uint32_t *)(App_Addr + 4);              //用户代码区第二个字为程序开始地址(复位地址)        
        MSR_MSP( * ( __IO uint32_t * ) App_Addr );                              //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
        JumpToApp();                                                            //跳转到APP.
    }
}



1.3编译设置

438226847dcf9bbc74.png

二,app工程的设定
1.设定启动地址

493736847dcf14f4e3.png

2.中断向量表重映射
  完成了上面的工作,实际测试发现程序还是无法正确运行。原因是我们没有进行中断向量表的重映射。向量表映射?什么时候有做过这个工作,我们来看一下:

.s文件里有如下代码:



; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler                 [WEAK]
        IMPORT  __main
        IMPORT  SystemInit  
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP
这段代码表示,程序在执行main函数之前,会先执行SystemInit这个函数。下面看看这个函数到底做了什么东西:



/**
  * @brief  Setup the microcontroller system.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
/*!< Set MSION bit */
  RCC->CR |= (uint32_t)0x00000100U;

  /*!< Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], MCOSEL[2:0] and MCOPRE[2:0] bits */
  RCC->CFGR &= (uint32_t) 0x88FF400CU;

  /*!< Reset HSION, HSIDIVEN, HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFF6U;

  /*!< Reset HSI48ON  bit */
  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;

  /*!< Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFFU;

  /*!< Reset PLLSRC, PLLMUL[3:0] and PLLDIV[1:0] bits */
  RCC->CFGR &= (uint32_t)0xFF02FFFFU;

  /*!< Disable all interrupts */
  RCC->CIER = 0x00000000U;

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}


  从上面的代码可以看到,这个函数主要是做了时钟的初始化和中断初始化,还有就是中断向量表的映射,就是最后那一段代码


215256847dcc960c98.png


  再看看FLASH_BASE 和 VECT_TAB_OFFSET的定义:



924426847dcc1e172e.png



434476847dcbd0b0d1.png

这里默认映射的地址就是FLASH的初始地址,所以只要将其改成我们程序的起始地址 0x08004000,而我们只需要将VECT_TAB_OFFSET修改为0x4000就可以了。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_45234526/article/details/145227343

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

170

帖子

1

粉丝