【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级

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

第69章       STM32H7的系统bootloader之串口IAP固件升级

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

IAP的全称是In Application Programming,即在线应用编程。

目录

第69章       STM32H7的系统bootloader之串口IAP固件升级

69.1 初学者重要提示

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

69.3 STM32CubeProg的安装说明

69.4 STM32CubeProg的程序下载说明

69.4.1 选择好用的串口线

69.4.2 设置boot引脚跳转到系统botLoader

69.4.3 应用程序跳转到系统bootloader

69.4.4 STM32CubeProg下载程序设置

69.5 串口方式系统Bootloader驱动移植和使用

69.6 实验例程设计框架

69.7 实验例程说明(MDK)

69.8 实验例程说明(IAR)

69.9 总结

 

69.1 初学者重要提示

  1.   学习本章节前,务必优先学习第67章。
  2.   特别注意STM32H7的系统BootLoader地址并不是0x1FFF 0000。
  3.   本章用到的相关软件和文档下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=96573 。
  4.   本章节的串口IAP下载软件使用STM32CubeProg,此软件实现了之前的DfuSe,STLINK小软件和Flashloader三合一,并且支持外部EEPROM,NOR Flash,SPI Flash,NAND Flash等烧写,也支持OTA编程。
  5.   使用系统bootloader做串口IAP升级时,MicroUSB接口不要接线到电脑端,因为这会导致系统bootloader工作在USB DFU模式,无法再使用串口IAP。

69.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教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第1张图片

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第2张图片

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

69.3 STM32CubeProg的安装说明

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

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第3张图片

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第4张图片

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第5张图片

69.4 STM32CubeProg的程序下载说明

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

69.4.1 选择好用的串口线

(注:MicroUSB接口不要接线到电脑端,因为这会导致系统bootloader工作在USB DFU模式,无法再使用串口IAP)

选择好用的USB线很重要,比如我们开发板赠送的那根USB转RS232串口线是不可以用在这里做串口IAP的,这根线只能用于一般的串口通信和串口打印功能。

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第6张图片

当前我这里是用的我们H7-TOOL的USB转TTL输出,注意交叉方式连接,即RX接TX,TX接RX。GNG接GND。

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第7张图片

注,我这里没有接共地线,推荐大家接上,3.3V可以不接。

69.4.2 设置boot引脚跳转到系统botLoader

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第8张图片

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

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第9张图片

69.4.3 应用程序跳转到系统bootloader

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第10张图片

69.4.4 STM32CubeProg下载程序设置

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

  第1步,选择UART方式,配置使用的串口号,串口波特率115200和偶校验,点击Connect按钮。

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第11张图片

识别成功后的效果如下:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第12张图片

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第13张图片

  •   Start address选项不填的话,默认会下载到内部Flash的首地址,保险起见,大家也可以填上首地址0x0800 0000,或者其它要下载的地址。
  •   Run after programming选项可以根据需要勾上,如果勾上此选项后,下载完毕程序后,会自动断开连接,并弹出一些列窗口,最终弹出下面这个窗口:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第14张图片

弹出这个窗口并不是表示下载失败了,而是下载完成后退出了系统bootloader,启动用刚刚下载的程序了。

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

 【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第15张图片

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

69.5 串口方式系统Bootloader驱动移植和使用

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

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

 

69.6 实验例程设计框架

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

 【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第16张图片

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

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

  第2阶段,进入main函数:

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

69.7 实验例程说明(MDK)

配套例子:

V7-048_基于系统bootloader的串口IAP方式固件升级

实验目的:

  1. 学习基于系统bootloader的串口IAP方式固件升级。

实验内容:

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

实验操作:

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

上电后串口打印的信息:

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第17张图片
 

程序设计:

  系统栈大小分配:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第18张图片

  RAM空间用的DTCM:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第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;
            }
        }
    }
}

 

69.8 实验例程说明(IAR)

配套例子:

V7-048_基于系统bootloader的串口IAP方式固件升级

实验目的:

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

实验内容:

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

实验操作:

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

上电后串口打印的信息:

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

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第20张图片

程序设计:

  系统栈大小分配:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第21张图片

  RAM空间用的DTCM:

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级_第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;
            }
        }
    }
}

 

69.9 总结

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

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