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

最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255

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

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

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

目录

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

29.1 初学者重要提示

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

29.3 STM32CubeProg的安装说明

29.4 STM32CubeProg的程序下载说明

29.4.1 设置boot引脚跳转到系统bootLoader

29.4.2 应用程序跳转到系统bootloader

29.4.3 STM32CubeProg下载程序设置

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

29.6 实验例程设计框架

29.7 实验例程说明(MDK)

29.8 实验例程说明(IAR)

29.9 总结


29.1 初学者重要提示

  1.   学习本章节前,务必优先学习第28章。
  2.   本章用到的相关软件和文档下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=96573
  3.   软件STM32CubeProg和DfuSe都支持USB DFU,但是两个软件不能都安装使用,因为这两个软件的USB驱动不同,导致工作在系统bootloader模式的板子通过USB线接到电脑端时,只有一个软件的驱动被识别。
  4.   DfuSe是老版的USB DFU软件,不推荐大家使用了。建议使用STM32CubeProg,此软件实现了之前的DfuSe,STLINK小软件和Flashloader三合一,并且支持外部EEPROM,NOR Flash,SPI Flash,NAND Flash等烧写,也支持OTA编程。
  5.   本章节的USB DFU的下载软件采用STM32CubeProg,如果想使用DfuSe的话,此贴有详细说明:http://www.armbbs.cn/forum.php?mod=viewthread&tid=11185
  6.   当芯片工作在系统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组。

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

  •   第49行,跳转到系统bootLoader。

29.3 STM32CubeProg的安装说明

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

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

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

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

29.4 STM32CubeProg的程序下载说明

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

29.4.1 设置boot引脚跳转到系统bootLoader

  •   第1步:此接口插上USB线:

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

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

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

29.4.2 应用程序跳转到系统bootloader

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

29.4.3 STM32CubeProg下载程序设置

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

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

识别成功后的效果如下:

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

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

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

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

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

 

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

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

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

/* 开关全局中断的宏 */
#define ENABLE_INT()    __set_PRIMASK(0)    /* 使能全局中断 */
#define DISABLE_INT()    __set_PRIMASK(1)    /* 禁止全局中断 */

29.6 实验例程设计框架

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

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

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

  第2阶段,进入main函数:

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

29.7 实验例程说明(MDK)

配套例子:

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

实验目的:

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

实验内容:

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

实验操作:

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

上电后串口打印的信息:

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

程序设计:

  系统栈大小分配:

  硬件外设初始化

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

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无0
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32H429 HAL 库初始化,此时系统用的还是F429自带的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)

配套例子:

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

实验目的:

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

实验内容:

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

实验操作:

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

上电后串口打印的信息:

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

程序设计:

  系统栈大小分配:

  硬件外设初始化

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

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无0
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32H429 HAL 库初始化,此时系统用的还是F429自带的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引脚时。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值