一、简介
1.1、开发环境
STM32CubeIDE软件版本:V1.9.0。
单片机型号:STM32F103ZETx。
1.2、主要内容
使用STM32CubeIDE实现Bootloader跳转到APP程序。需分别建立Bootloader和APP两个工程。
二、Bootloader工程
Bootloader的CubeMX无需设置,直接生成程序。
2.1、Bootloader跳转程序
Bootloader跳转程序,主要是利用函数指针,让程序跳转到指定的应用程序地址。以下3种方案殊途同归,选择其一即可。
方案1:用typedef定义跳转函数指针的别名。
typedef void (*p_APP)(void);
/*
* 功能:运行应用程程序
* 输入:app_address:应用程序起始地址
* 输出:
* 备注:
*/
void StartApplication(uint32_t app_address)
{
p_APP application;
uint32_t jump_address;
if (((*(__IO uint32_t*)app_address) & 0x2FFE0000 ) == 0x20000000)
{
jump_address = *(__IO uint32_t*) (app_address + 4);
application = (p_APP) jump_address;
__set_MSP(*(__IO uint32_t*) app_address);
application();
}
}
方案2:直接定义函数指针。
/*
* 功能:运行应用程程序
* 输入:app_address:应用程序起始地址
* 输出:
* 备注:
*/
void StartApplication(uint32_t app_address)
{
void (*p_APP)(void);
uint32_t jump_address;
if (((*(__IO uint32_t*)app_address) & 0x2FFE0000 ) == 0x20000000)
{
jump_address = *(__IO uint32_t*) (app_address + 4);
p_APP = (void(*)(void))jump_address;
__set_MSP(*(__IO uint32_t*) app_address);
(*p_APP)();
}
}
方案3:跳转时,强制类型转换为函数指针。
/*
* 功能:运行应用程程序
* 输入:app_address:应用程序起始地址
* 输出:
* 备注:
*/
void StartApplication(uint32_t app_address)
{
uint32_t jump_address;
if (((*(__IO uint32_t*)app_address) & 0x2FFE0000 ) == 0x20000000)
{
jump_address = *(__IO uint32_t*) (app_address + 4);
__set_MSP(*(__IO uint32_t*) app_address);
(*(void(*)(void))jump_address)();
}
}
2.2、设置Flash大小
打开Bootloader工程下的文件STM32F103ZETX_FLASH.ld。
本文分配给Bootloader的程序空间为8K,因此将Flash的大小改为8K,具体如下:
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 8K
}
注:用编译器烧录程序时,只会根据当前程序大小,以Flash页或扇区为最小单位,擦除需要用到的Flash页或扇区。因此只要Flash分区合理,用编译器烧写Bootloader程序时,也不会擦除已经烧录的APP程序。修改的目的,只是为了在Bootloader的程序大小超过8K后,编译时,软件会报错提醒。
2.3、跳转示例
#define ApplicationFlashAddress 0x08002000 //定义应用程序地址
int main(void)
{
StartApplication(uint32_t app_address);
while();
}
注:此处的应用程序地址,要和“3.2修改应用程序Flash首地址和大小”设置的APP程序Flash起始地址一致。
三、APP部分
APP根据需求,配置完CubeMX,再生成程序。
3.1、设置中断向量表偏移量
打开文件system_stm32f1xx.c。
找到如下位置:
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
in Sram else user remap will be done in Flash. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
主要修改内容:
(1)在语句“#if defined(USER_VECT_TAB_ADDRESS)”前面增加“#define USER_VECT_TAB_ADDRESS”;
(2)将“#define VECT_TAB_OFFSET 0x00000000U”改为“#define VECT_TAB_OFFSET 0x00002000”。
中断向量表偏移地址(0x00002000) = APP起始地址(0x08002000) - Flash起始地址(0x08000000)。
改后程序如下:
#define USER_VECT_TAB_ADDRESS //增加处1
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
in Sram else user remap will be done in Flash. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00002000 //修改处1,0x00002000 = 应用程序地址 - 0x08000000
/*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
注:若找不到以上程序段,可全局搜索“VECT_TAB_OFFSET”。
3.2、修改应用程序Flash首地址和大小
打开APP工程下的文件STM32F103ZETX_FLASH.ld。
APP程序Flash起始地址(ORIGIN)改为0x08002000。注意与Bootloader设置的跳转地址一致。
APP程序Flash空间大小(LENGTH)改为32K。
具体如下:
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8002000, LENGTH = 32K
}