bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写

文章目录

  • 一、前言
  • 二、硬件部分
    • 2.1、stm32-v5开发板
    • 2.2、stm32-v5原理图
  • 三、KEIL
    • 3.1、Device Target
    • 3.2、Linker
  • 四、代码
    • 4.1、main.c
  • 五、实验开始
    • 5.1、烧录boot文件夹的工程代码
    • 5.2、stm32CubeProgrammer
  • 六、细节补充
    • 6.1、变量g_JumpInit究竟被存放在哪里?
    • 6.2、进入bootloader程序后,MCU真的运行在内存0x1FFF0000~0x1FFF77FF吗?
    • 6.3、变量g_JumpInit一定要存放在RAM2里面吗?

一、前言


本次实验的目的是使用stm32Cubeprogrammer与USB线烧写新的固件到stm32f407的flash里。
STM32的bootloader学习我是参考安富莱的stm32-v5教程与使用安富莱的stm32-v5开发板。ST为STM32芯片都准备了bootloader程序,目的是让用户使用UART、USB、CAN等方式方便地刷写FLASH的程序。stm32芯片进入bootloader程序有两种方式:
1、通过硬件的boot电路,接着按照对应的时序让mcu进入bootloader。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第1张图片

使用硬件的boot电路方法需要设计对应的硬件电路,而且还有对应的操作时序,相当麻烦。

2、使用本次从安富莱教程学习的方法:在应用程序里灵活地让mcu进入bootloader,进入bootloader后就可以使用stm32Cubeprogrammer方便地烧录新的代码到芯片内部的flash里。参考硬汉的牛叉实战教程:

实战技能分享,一劳永逸的解决BOOT跳转APP失败问题,含MDK AC5,AC6和IAR,同时制作了一个视频操作说

为了实验通过应用程序进入bootloader,然后通过usb,uart等外设升级mcu的升级,我准备了两份工程代码:
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第2张图片
百度网盘地址:
链接: https://pan.baidu.com/s/1A3du82lGWUpcA8t0dUss8w?pwd=eamn 提取码: eamn

二、硬件部分


2.1、stm32-v5开发板


按照安富莱的教程使用USB线连接开发板的CN25接口(micro usb插座)。

2.2、stm32-v5原理图

这个micro usb插座实际连接到stm32f407IGT6的PA11与PA12引脚,如上图所示。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第3张图片
根据stm32f4的参考手册看到,bootloader支持很多外设,这一次学习的是DFU(PA11/12)。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第4张图片

三、KEIL


3.1、Device Target

根据安富莱的教程,如果使用AC6编译器的话,另外还需要在keil上设置一些配置。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第5张图片

3.2、Linker

AC6编译器的话,需要修改.sct文件。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第6张图片

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x0001C000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x2001C000 UNINIT 0x00000004  {  
   *(.bss.NoInit)
  }
}

接着,重新编译整个工程!!一定要重新编译!!!
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第7张图片
为什么这样去修改.sct文件?因为需要将一个全局变量(g_JumpInit)分配到RAM2内存里。当程序调用NVIC_SystemReset()去复位程序时,全局变量g_JumpInit不会被重置。只有开发板掉电之后,变量g_JumpInit才会被重置。

四、代码


4.1、main.c

bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第8张图片
这段代码所放置的位置很有讲究,必须在其他外设还没有初始化之前就进入bootloader程序,以免干涉到bootloader程序的运行(干净的环境)。
它是硬汉哥这一次优化bootloader代码的关键点。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第9张图片
为了方便测试,使用按钮KEY1来触发。后续大家可以根据自己的情况来调用124行与125行的代码,让CPU复位后马上进入bootloader程序。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第10张图片
最后就是最重要的函数JumpToApp( )的实现了。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第11张图片
stm32f407为什么是0x1FFF0000,通过stm32f4xx的中文参考手册的第57页,可以看到系统存储器(bootloader)的地址范围是0x1FFF0000 - 0x1FFF77FF。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第12张图片

五、实验开始


5.1、烧录boot文件夹的工程代码

烧录代码成功后,LD1开始以100ms的间隔闪烁。

从代码可以看到,当按下K1按钮后,LD2将不再闪烁。因为程序跳转到bootloader程序那里去了。

5.2、stm32CubeProgrammer

打开软件之后,选择USB方式,再点击Connect。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第13张图片
连接成功后,在Target information能找到mcu的信息,还有左侧的Log栏目能看到Data read successfully!
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第14张图片
接着,就是需要找到将要烧录的固件程序,它的格式是hex。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第15张图片
找到需要通过bootloader程序来更新程序的新固件,格式hex。

下载新的固件代码成功后,按下stm32-v5开发板的reset按钮,让mcu复位。如下图所示,LD1以更加高的频率进行闪烁了。通过USB的方式更新代码成功!!

六、细节补充


6.1、变量g_JumpInit究竟被存放在哪里?

通过修改.sct文件与按照以下的方式定义变量g_JumpInit后,它真的被存放在RAM2里边了吗?为此我通过.map文件来确认。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第16张图片
从.map文件看到,变量g_JumpInit被存放到内存0x2001c000里,而且大小是4个byte(字节),0x2001c000其实就是RAM2内存的起始地址。

6.2、进入bootloader程序后,MCU真的运行在内存0x1FFF0000~0x1FFF77FF吗?

通过debug模式,当按下按钮KEY1后,通过PC寄存器可以看到,程序运行在内存地址0x1FFF149F,这个内存地址就是在0x1FFF0000 ~ 0x1FFF77FF之间。
bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写_第17张图片

6.3、变量g_JumpInit一定要存放在RAM2里面吗?

变量g_JumpInit并不一定要放在RAM2里面,在实际项目中,有的人会把它放在外部flash里,或者内部flash。目的是避免复位cpu时,变量g_JumpInit也跟着复位。

你可能感兴趣的:(STM32,stm32,单片机,arm,bootloader)