你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的系统bootloader之USB DFU方式固件升级

[复制链接]
STMCU小助手 发布时间:2021-11-2 23:47
68.1 初学者重要提示
  学习本章节前,务必优先学习第67章。
  特别注意STM32H7的系统bootLoader地址并不是0x1FFF 0000。
  软件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
  当芯片工作在系统bootLoader的USB DFU模式,更新完毕程序后,不会自动退出USB DFU,需要重新复位芯片后才会退出。由于DFU模式会用到USB线,插拔USB线是难以避免的,所以是否支持自动退出,并不影响。
68.2 跳转到系统bootLoader的程序设计
程序设计如下,基本是按照第67章3.2小节的方法进行设计

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



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

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  第46行,跳转到系统bootLoader。
68.3 STM32CubeProg的安装说明
STM32CubeProg的安装比较简单,如果大家的电脑中缺少JAVA环境,会提示安装,按照提示操作即可。

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  第3步:板子上电3秒左右,松手。
在电脑端设备管理器就可以看到已经识别出来:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


68.4.3 STM32CubeProg下载程序设置
识别成功后就可以下载程序了。

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


识别成功后的效果如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

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

  1. /* 开关全局中断的宏 */
  2. #define ENABLE_INT()    __set_PRIMASK(0)    /* 使能全局中断 */
  3. #define DISABLE_INT()    __set_PRIMASK(1)    /* 禁止全局中断 */
复制代码

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


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

这部分在第14章进行了详细说明。
  第2阶段,进入main函数:

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

68.7 实验例程说明(MDK)
配套例子:

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

实验目的:

学习基于系统bootloader的USB接口方式IAP升级。
实验内容:

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

K1键按下,跳转到系统bootLoader。
上电后串口打印的信息:

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  硬件外设初始化

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

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

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

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

  37. bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
  38.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  39.     bsp_InitTimer();      /* 初始化滴答定时器 */
  40.     bsp_InitUart();    /* 初始化串口 */
  41.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  42.     bsp_InitLed();        /* 初始化LED */   
  43.     bsp_InitExtSDRAM(); /* 初始化SDRAM */
  44. }
复制代码


  MPU配置和Cache配置:

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /*使能 MPU */
  41.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  42. }

  43. /*
  44. *********************************************************************************************************
  45. *    函 数 名: CPU_CACHE_Enable
  46. *    功能说明: 使能L1 Cache
  47. *    形    参: 无
  48. *    返 回 值: 无
  49. *********************************************************************************************************
  50. */
  51. static void CPU_CACHE_Enable(void)
  52. {
  53.     /* 使能 I-Cache */
  54.     SCB_EnableICache();

  55.     /* 使能 D-Cache */
  56.     SCB_EnableDCache();
  57. }
复制代码



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

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

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

复制代码

  主功能:

主程序实现如下操作:

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


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

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

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

  19.         /* 判断定时器超时时间 */
  20.         if (bsp_CheckTimer(0))   
  21.         {
  22.             /* 每隔100ms 进来一次 */  
  23.             bsp_LedToggle(2);
  24.         }

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

  34.                 default:
  35.                     /* 其它的键值不处理 */
  36.                     break;
  37.             }
  38.         }
  39.     }
  40. }
复制代码

68.8 实验例程说明(IAR)
配套例子:

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

实验目的:

学习基于系统bootloader的USB接口方式IAP升级。
实验内容:

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

K1键按下,跳转到系统bootLoader。
上电后串口打印的信息:

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

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png


  硬件外设初始化

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

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

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

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

  37. bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
  38.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  39.     bsp_InitTimer();      /* 初始化滴答定时器 */
  40.     bsp_InitUart();    /* 初始化串口 */
  41.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  42.     bsp_InitLed();        /* 初始化LED */   
  43.     bsp_InitExtSDRAM(); /* 初始化SDRAM */
  44. }
复制代码



  MPU配置和Cache配置:

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /*使能 MPU */
  41.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  42. }

  43. /*
  44. *********************************************************************************************************
  45. *    函 数 名: CPU_CACHE_Enable
  46. *    功能说明: 使能L1 Cache
  47. *    形    参: 无
  48. *    返 回 值: 无
  49. *********************************************************************************************************
  50. */
  51. static void CPU_CACHE_Enable(void)
  52. {
  53.     /* 使能 I-Cache */
  54.     SCB_EnableICache();

  55.     /* 使能 D-Cache */
  56.     SCB_EnableDCache();
  57. }

复制代码

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

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

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

  主功能:

主程序实现如下操作:

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


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

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

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

  19.         /* 判断定时器超时时间 */
  20.         if (bsp_CheckTimer(0))   
  21.         {
  22.             /* 每隔100ms 进来一次 */  
  23.             bsp_LedToggle(2);
  24.         }

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

  34.                 default:
  35.                     /* 其它的键值不处理 */
  36.                     break;
  37.             }
  38.         }
  39.     }
  40. }
复制代码


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



收藏 1 评论0 发布时间:2021-11-2 23:47

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版