【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第68章       STM32H7的系统bootloader之USB DFU方式固件升级

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

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

目录

第68章       STM32H7的系统bootloader之USB DFU方式固件升级

68.1 初学者重要提示

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

68.3 STM32CubeProg的安装说明

68.4 STM32CubeProg的程序下载说明

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

68.4.2 应用程序跳转到系统bootloader

68.4.3 STM32CubeProg下载程序设置

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

68.6 实验例程设计框架

68.7 实验例程说明(MDK)

68.8 实验例程说明(IAR)

68.9 总结


 

 

68.1 初学者重要提示

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

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

程序设计如下,基本是按照第67章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 = 0x1FF09800; /* STM32H7的系统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.        /* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断服务程序地址 */
37.        SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));
38.    
39.        /* 设置主堆栈指针 */
40.        __set_MSP(*(uint32_t *)BootAddr);
41.        
42.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
43.        __set_CONTROL(0);
44.    
45.        /* 跳转到系统BootLoader */
46.        SysMemBootJump(); 
47.    
48.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
49.        while (1)
50.        {
51.    
52.        }
53.    }

 

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

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第1张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第2张图片

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

68.3 STM32CubeProg的安装说明

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

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第3张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第4张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第5张图片

68.4 STM32CubeProg的程序下载说明

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

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

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第6张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第7张图片

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

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第8张图片

68.4.2 应用程序跳转到系统bootloader

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第9张图片

68.4.3 STM32CubeProg下载程序设置

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

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第10张图片

识别成功后的效果如下:

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第11张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第12张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第13张图片

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

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第14张图片

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

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

 【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第15张图片

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

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

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

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

 

68.6 实验例程设计框架

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

 【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第16张图片

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

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

  第2阶段,进入main函数:

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

68.7 实验例程说明(MDK)

配套例子:

V7-047_基于系统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。

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第17张图片

程序设计:

  系统栈大小分配:

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第18张图片

  RAM空间用的DTCM:

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第19张图片

  硬件外设初始化

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

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 配置MPU */
    MPU_Config();
    
    /* 使能L1 Cache */
    CPU_CACHE_Enable();

    /* 
       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

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

    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
    bsp_InitLed();        /* 初始化LED */    
    bsp_InitExtSDRAM(); /* 初始化SDRAM */
}

 

  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

/*
*********************************************************************************************************
*    函 数 名: MPU_Config
*    功能说明: 配置MPU
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    /* 禁止 MPU */
    HAL_MPU_Disable();

    /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
    
    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x60000000;
    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/*
*********************************************************************************************************
*    函 数 名: CPU_CACHE_Enable
*    功能说明: 使能L1 Cache
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
    /* 使能 I-Cache */
    SCB_EnableICache();

    /* 使能 D-Cache */
    SCB_EnableDCache();
}

 

  每10ms调用一次蜂鸣器处理:

蜂鸣器处理是在滴答定时器中断里面实现,每10ms执行一次检测。

/*
*********************************************************************************************************
*    函 数 名: bsp_RunPer10ms
*    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
*              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)
{
    bsp_KeyScan10ms();
}

 

  主功能:

主程序实现如下操作:

  •   启动一个自动重装软件定时器,每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;
            }
        }
    }
}

 

68.8 实验例程说明(IAR)

配套例子:

V7-047_基于系统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。

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第20张图片

程序设计:

  系统栈大小分配:

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第21张图片

  RAM空间用的DTCM:

【STM32H7教程】第68章 STM32H7的系统bootloader之USB DFU方式固件升级_第22张图片

  硬件外设初始化

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

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 配置MPU */
    MPU_Config();
    
    /* 使能L1 Cache */
    CPU_CACHE_Enable();

    /* 
       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

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

    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
    bsp_InitLed();        /* 初始化LED */    
    bsp_InitExtSDRAM(); /* 初始化SDRAM */
}

 

  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

/*
*********************************************************************************************************
*    函 数 名: MPU_Config
*    功能说明: 配置MPU
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    /* 禁止 MPU */
    HAL_MPU_Disable();

    /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
    
    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x60000000;
    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/*
*********************************************************************************************************
*    函 数 名: CPU_CACHE_Enable
*    功能说明: 使能L1 Cache
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
    /* 使能 I-Cache */
    SCB_EnableICache();

    /* 使能 D-Cache */
    SCB_EnableDCache();
}

 

  每10ms调用一次蜂鸣器处理:

蜂鸣器处理是在滴答定时器中断里面实现,每10ms执行一次检测。

/*
*********************************************************************************************************
*    函 数 名: bsp_RunPer10ms
*    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
*              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)
{
    bsp_KeyScan10ms();
}

 

  主功能:

主程序实现如下操作:

  •   启动一个自动重装软件定时器,每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;
            }
        }
    }
}

 

68.9 总结

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

 

你可能感兴趣的:(STM32H7教程)