意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

【STM32F407开发板用户手册】第29章STM32F407的系统bootloader之USBDFU方式固件升级

来源:恒创科技 编辑:恒创科技编辑部
2024-02-04 08:06:59

​​​​

第29章 STM32F407的系统bootloader之USB DFU方式固件升级

本章节为大家讲解使用系统bootloader做程序升级的方法,即使不依赖外部boot引脚也可以方便升级。

DFU的全称是Device Firmware Upgrade,即设备固件升级


【STM32F407开发板用户手册】第29章STM32F407的系统bootloader之USBDFU方式固件升级

29.1 初学者重要提示

29.2 跳转到系统bootloader的程序设计

29.3 STM32CubeProg的安装说明

29.3 STM32CubeProg的程序下载说明

29.4 USB DFU方式系统bootloader驱动移植和使用

29.6 实验例程设计框架

29.7 实验例程说明(MDK)

29.8 实验例程说明(IAR)

29.9 总结

29.1 初学者重要提示学习本章节前,务必优先学习第28章。本章用到的相关软件和文档下载:​​http://www.armbbs.cn/forum.php?mod=viewthread&tid=96573​​ 。软件STM32CubeProg和DfuSe都支持USB DFU,但是两个软件不能都安装使用,因为这两个软件的USB驱动不同,导致工作在系统bootloader模式的板子通过USB线接到电脑端时,只有一个软件的驱动被识别。DfuSe是老版的USB DFU软件,不推荐大家使用了。建议使用STM32CubeProg,此软件实现了之前的DfuSe,STLINK小软件和Flashloader三合一,并且支持外部EEPROM,NOR Flash,SPI Flash,NAND Flash等烧写,也支持OTA编程。本章节的USB DFU的下载软件采用STM32CubeProg,如果想使用DfuSe的话,此贴有详细说明:​​http://www.armbbs.cn/forum.php?mod=viewthread&tid=11185​​ 。当芯片工作在系统bootLoader的USB DFU模式,更新完毕程序后,不会自动退出USB DFU,需要重新复位芯片后才会退出。由于DFU模式会用到USB线,插拔USB线是难以避免的,所以是否支持自动退出,并不影响。29.2 跳转到系统bootLoader的程序设计

程序设计如下,基本是按照第28章3.2小节的方法进行设计

1.    /*
2. ******************************************************************************************************
3. * 函 数 名: JumpToBootloader
4. * 功能说明: 跳转到系统BootLoader
5. * 形 参: 无
6. * 返 回 值: 无
7. ******************************************************************************************************
8. */
9. static void JumpToBootloader(void)
10. {
11. uint32_t i=0;
12. void (*SysMemBootJump)(void); /* 声明一个函数指针 */
13. __IO uint32_t BootAddr = 0x1FFF0000; /* STM32F4的系统BootLoader地址 */
14.
15. /* 关闭全局中断 */
16. DISABLE_INT();
17.
18. /* 关闭滴答定时器,复位到默认值 */
19. SysTick->CTRL = 0;
20. SysTick->LOAD = 0;
21. SysTick->VAL = 0;
22.
23. /* 设置所有时钟到默认状态,使用HSI时钟 */
24. HAL_RCC_DeInit();
25.
26. /* 关闭所有中断,清除所有中断挂起标志 */
27. for (i = 0; i < 8; i++)
28. {
29. NVIC->ICER[i]=0xFFFFFFFF;
30. NVIC->ICPR[i]=0xFFFFFFFF;
31. }
32.
33. /* 使能全局中断 */
34. ENABLE_INT();
35.
36. /* 设置重映射到系统Flash */
37. __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
38.
39. /* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断服务程序地址 */
40. SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));
41.
42. /* 设置朱堆栈指针 */
43. __set_MSP(*(uint32_t *)BootAddr);
44.
45. /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
46. __set_CONTROL(0);
47.
48. /* 跳转到系统BootLoader */
49. SysMemBootJump();
50.
51. /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
52. while (1)
53. {
54.
55. }
56. }

这里把程序设计中的几个关键地方做个说明:

第12行,声明一个函数指针。第13行,这个要特别注意,F4的系统bootloader地址。第19到21行,设置滴答定时器到复位值。第24行,此函数比较省事,可以方便的设置F4所有时钟到复位值,内部时钟使用HSI。第27到31行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口


第37行,将系统bootloader的地址映射到0x0000 0000。这点非常重要,根本原因是F4的系统bootloader要从0x00000000地址读取中断向量。第40行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。第43行,设置主堆栈指针位置,即系统bootloader的首地址存储的就是栈地址。第46行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_02


第49行,跳转到系统bootLoader。29.3 STM32CubeProg的安装说明

STM32CubeProg的安装比较简单如果大家的电脑中缺少JAVA环境,会提示安装,按照提示操作即可。

这里特别注意USB DFU驱动的安装,如果大家的电脑上安装了DfuSe软件,那边板子工作在系统bootLoader模式时,电脑端的设备管理器识别出来的标识是这样的:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_03


如果用STM32CubeProg的话,务必要将此驱动删掉,鼠标右击此标识,选择卸载,弹出如下对话框:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_04


卸载完毕后,重启电脑,然后运行STM32CubeProg安装目录里面的STM32Bootloader.bat即可,最后插上设备就可以正常识别了。识别后的标识:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_初始化_05


29.4 STM32CubeProg的程序下载说明

这里把两种下载方式都做个说明,一种是设置外部boot引脚进行下载,另一种是设置程序跳转到系统bootloader进行下载。

29.4.1 设置boot引脚跳转到系统bootLoader第1步:此接口插上USB线:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_06


第2步:板子上电前按住右下角的BOOT引脚。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_07


第3步:板子上电3秒左右,松手。

在电脑端设备管理器就可以看到已经识别出来:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_08


29.4.2 应用程序跳转到系统bootloader

应用程序跳转到系统bootLoader比较方便,无需用户操作外置的boot引脚了,只需调用本章第2小节的程序就可以跳转。本章配套的例子是用户按下按键K1后执行跳转程序,大家可以根据需要实现各种触发跳转的方式。跳转成功后,在电脑端设备管理器里面也会看到bootloader标识:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_09


29.4.3 STM32CubeProg下载程序设置

识别成功后就可以下载程序了。

第1步,选择USB方式,点击Connect按钮。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_10


识别成功后的效果如下:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_11


这里要特别注意一点,如果用户没有关闭这个软件,多次插拔USB线时,记得点击这里的刷新按钮,因为有时候这个软件不会自动显示出来,点击刷新按钮才行。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_12


第2步,添加要下载的hex文件,勾选需要设置的选项,点击启动编程。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_13


Start address选项不填的话,默认会下载到内部Flash的首地址,保险起见,大家也可以填上首地址0x0800 0000,或者其它要下载的地址。Run after programming选项勾选或者不勾选均可,因为测试发现STM32CubeProg不支持USB DFU编程后运行。这样特别说一点,如果勾上此选项后,下载完毕程序后,会自动断开连接,并弹出一些列窗口,最终弹出下面这个窗口:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_初始化_14


弹出这个窗口并不是表示下载失败了,而是下载完成后退出了系统bootloader。

第3步,完成下载后的效果如下:


【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_15

下载完成后板子重新上电就可以看到程序已经成功下载了。

29.5 USB DFU方式系统Bootloader驱动移植和使用

系统bootloader的移植比较简单,仅需添加本章第2小节的程序到自己工程里面即可。里面有个开关中断API,是在bsp.h文件里面定义的:

/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define
29.6 实验例程设计框架

通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_16

第1阶段,上电启动阶段:

这部分在第14章进行了详细说明。

第2阶段,进入main函数:

第1部分,硬件初始化,主要是HAL库,系统时钟,滴答定时器和LED。第2部分,应用程序设计部分,K1按键按下后跳转到系统bootloader。。29.7 实验例程说明(MDK)

配套例子:

V5-009_基于系统bootloader的USB接口方式IAP升级(USB DFU)

实验目的:

学习基于系统bootloader的USB接口方式IAP升级。

实验内容:

STM32的系统存储区自带BootLoader,可以方便的实现串口,I2C,CAN,SPI,USB等接口方式的程序升级。如果使用系统BootLoader支持的接口升级方式,基本就不需要用户自己做BootLoader了。除了通过boot引脚控制启动地址,也可以直接从应用程序里面跳转到系统存储区。

实验操作:

K1键按下,跳转到系统BootLoader。

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_串口_17


程序设计:

系统栈大小分配:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_18


硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/*
STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
- 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
- 设置NVIV优先级分组为4。
*/
HAL_Init();

/*
配置系统时钟到168MHz
- 切换使用HSE。
- 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
*/
SystemClock_Config();

/*
Event Recorder:
- 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
- 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
*/
#if Enable_EventRecorder == 1
/* 初始化EventRecorder并开启 */
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
#endif

bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
bsp_InitTimer(); /* 初始化滴答定时器 */
bsp_InitUart(); /* 初始化串口 */
bsp_InitExtIO(); /* 初始化扩展IO */
bsp_InitLed(); /* 初始化LED */
BEEP_InitHard(); /* 初始化蜂鸣器 */
}

主功能:

主程序实现如下操作:

启动一个自动重装软件定时器,每100ms翻转一次LED2。K1键按下,跳转到系统BootLoader。
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参: 无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode; /* 按键代码 */


bsp_Init(); /* 硬件初始化 */
PrintfLogo(); /* 打印例程名称和版本等信息 */
PrintfHelp(); /* 打印操作提示 */

bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */

while (1)
{
bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

/* 判断定时器超时时间 */
if (bsp_CheckTimer(0))
{
/* 每隔100ms 进来一次 */
bsp_LedToggle(2);
}

/* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1键按下,K1键按下,跳转到系统BootLoader */
JumpToBootloader();
break;

default:
/* 其它的键值不处理 */
break;
}
}
}
}
29.8 实验例程说明(IAR)

配套例子:

V5-009_基于系统bootloader的USB接口方式IAP升级(USB DFU)

实验目的:

学习基于系统bootloader的USB接口方式IAP升级。

实验内容:

STM32的系统存储区自带bootLoader,可以方便的实现串口,I2C,CAN,SPI,USB等接口方式的程序升级。如果使用系统bootLoader支持的接口升级方式,基本就不需要用户自己做bootLoader了。除了通过boot引脚控制启动地址,也可以直接从应用程序里面跳转到系统存储区。

实验操作:

K1键按下,跳转到系统bootLoader。

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_引脚_19


程序设计:

系统栈大小分配:

【STM32F407开发板用户手册】第29章       STM32F407的系统bootloader之USB DFU方式固件升级_初始化_20


硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/*
STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
- 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
- 设置NVIV优先级分组为4。
*/
HAL_Init();

/*
配置系统时钟到168MHz
- 切换使用HSE。
- 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
*/
SystemClock_Config();

/*
Event Recorder:
- 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
- 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
*/
#if Enable_EventRecorder == 1
/* 初始化EventRecorder并开启 */
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
#endif

bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
bsp_InitTimer(); /* 初始化滴答定时器 */
bsp_InitUart(); /* 初始化串口 */
bsp_InitExtIO(); /* 初始化扩展IO */
bsp_InitLed(); /* 初始化LED */
BEEP_InitHard(); /* 初始化蜂鸣器 */
}

主功能:

主程序实现如下操作:

启动一个自动重装软件定时器,每100ms翻转一次LED2。K1键按下,跳转到系统BootLoader。
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参: 无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode; /* 按键代码 */


bsp_Init(); /* 硬件初始化 */
PrintfLogo(); /* 打印例程名称和版本等信息 */
PrintfHelp(); /* 打印操作提示 */

bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */

while (1)
{
bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

/* 判断定时器超时时间 */
if (bsp_CheckTimer(0))
{
/* 每隔100ms 进来一次 */
bsp_LedToggle(2);
}

/* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1键按下,K1键按下,跳转到系统BootLoader */
JumpToBootloader();
break;

default:
/* 其它的键值不处理 */
break;
}
}
}
}
29.9 总结

本章节为大家介绍的USB DFU方式还是非常实用的,特别是产品硬件不带boot引脚时。

微信公众号:armfly_com



上一篇: 【STM32F429开发板用户手册】第27章STM32F429的定时器应用之TIM1-TIM14的PWM实现 下一篇: 手机怎么远程登录云服务器?