需求:对STM32F103进行Firmware升级。可能有人会问,STM官网会提供DFU接口并且有专门的ST LINK可以给芯片下载Firwmare。
事实上,真实的需求是,我需要做一个Debug工具,下位机是STM32F103,上位机会用C#实现。这个Debug工具会进行更新,比如这次的测试需求满足,过了一段时间,另外的测试需求出现了,那么我的下位机需要具备Firmware在线更新的能力。这个Debug工具的使用者是多种多样的人甚至包括我这边的客户。所以,这个在线升级Firmware的工具最好和上位机是做到一起的,并且要简单易用,不需要复杂的配置。
因此,Bootloader将是必不可少的。
基本的设计思路:下位机分为两个区域,一个为Bootloader区域,另一个为Application区域,Bootloader区域不需要升级,每次对Application进行升级。另外,Bootloader里面的代码需要对Application区域的Firmware进行CRC校验,如果Application里面的CRC值与STM32 Bootloader算出来的CRC值不一致,那么Firmware将停留在Bootloader区域,保证芯片处在已知的工作范围,如果校验一致,那么Firmware将跳转至Application区域。
STM32F103的Firmware默认执行地址为0x8000000,Bootloader的Main函数需要放在初始默认位置,需要对Application区域的Code进行重新定位。Bootloader预留32K的Flash。剩下的Application区域,然后需要预留1K Bytes保存配置信息,如Application的CRC值,Applicaion Firmware 版本信息等等。因此Application代码的地址为0x8008400(32K(bootloader)+1K(configuration Code)),如下所示:
#define APP_RUN_BASEADDR 0x8008400 //32K for Bootloader, and another space for APP
那么,Bootloader里面的主要代码如下:
SysTick->CTRL =0;//关闭滴答定时器
HAL_DeInit();//关闭滴答定时器
HAL_NVIC_DisableIRQ(SysTick_IRQn);//关闭滴答定时器中断
HAL_NVIC_ClearPendingIRQ(SysTick_IRQn);//清除滴答定时器中断标志位,
//这几步的目的是避免滴答定时器产生的中断影响Firmware的跳转
__disable_irq();//关闭其他中断。
//上述步骤为关闭中断,防止中断影响Firmware跳转,之所以对滴答定时器操作很多,是因为我Firmware中滴答定时器是默认开启的。因此,对滴答定时器特殊照顾
JumpAddress =*(__IO uint32_t*)(APP_RUN_BASEADDR+4);
JumpToApplication = (pFunction)JumpAddress; //Firmware 复位地址,为初始地址+4
__set_MSP(*(__IO uint32_t*)APP_RUN_BASEADDR);//设置堆栈指针
JumpToApplication();//跳转到Application
Application区域的代码需要对中断向量表重新定位。如下所示,将HAL库中的VECT_TAB_OFFSET宏定义改掉为0x00008400.
#define FLASH_BASE 0x08000000UL /*!< FLASH base address in the alias region */
#define VECT_TAB_OFFSET 0x00008400U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#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
然后Application的代码就可以正常写了,代码编译的时候会自动从0x8008400开始放。注意:有一些库可能会在代码中对中断向量表重新定位,我目前使用的库中只有上面一处对中断向量地址进行了定义。
另外需要说明的一点,就是要在链接文件STM32F103XX_Flash.ld文件修改为:
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K//RAM的空间分配
FLASH (rx) : ORIGIN = 0x8008400, LENGTH = 470K//Flash的空间分配
}
代码的烧录:初次代码烧录使用ST-LINK,以及官网上提供的STM32CubeProgrammer,利用SWD进行烧录,注意选择文件的时候,需要选择HEX文件,HEX文件才会有地址信息,不要选择BIN文件,不要选择BIN文件,不要选择BIN文件。
另外在烧录之前,可以判断一下,Application初始地址是否设置成功,可以用STM32CubeProgrammer打开Application的HEX文件,将会显示,0x8008400上的值一定是0x2001000,否则就是设置失败。设置成功之后,将Bootloader的HEX和Application的HEX分别下载进入STM32,就实现了一个基本的Bootloader功能。
我上面写的关于对Application代码检测的CRC检验,将在后面的文章介绍。
本文暂时没有评论,来添加一个吧(●'◡'●)