文章目录
- 一、前言
- 二、硬件部分
-
- 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。
文章图片
使用硬件的boot电路方法需要设计对应的硬件电路,而且还有对应的操作时序,相当麻烦。
2、使用本次从安富莱教程学习的方法:在应用程序里灵活地让mcu进入bootloader,进入bootloader后就可以使用stm32Cubeprogrammer方便地烧录新的代码到芯片内部的flash里。参考硬汉的牛叉实战教程:
实战技能分享,一劳永逸的解决BOOT跳转APP失败问题,含MDK AC5,AC6和IAR,同时制作了一个视频操作说
为了实验通过应用程序进入bootloader,然后通过usb,uart等外设升级mcu的升级,我准备了两份工程代码:
文章图片
百度网盘地址:
链接: 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引脚,如上图所示。
文章图片
根据stm32f4的参考手册看到,bootloader支持很多外设,这一次学习的是DFU(PA11/12)。
文章图片
三、KEIL 3.1、Device Target 根据安富莱的教程,如果使用AC6编译器的话,另外还需要在keil上设置一些配置。
文章图片
3.2、Linker AC6编译器的话,需要修改.sct文件。
文章图片
;
*************************************************************
;
*** 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)
}
}
接着,重新编译整个工程!!一定要重新编译!!!
文章图片
为什么这样去修改.sct文件?因为需要将一个全局变量(g_JumpInit)分配到RAM2内存里。当程序调用NVIC_SystemReset()去复位程序时,全局变量g_JumpInit不会被重置。只有开发板掉电之后,变量g_JumpInit才会被重置。
四、代码 4.1、main.c
文章图片
这段代码所放置的位置很有讲究,必须在其他外设还没有初始化之前就进入bootloader程序,以免干涉到bootloader程序的运行(干净的环境)。
它是硬汉哥这一次优化bootloader代码的关键点。
文章图片
为了方便测试,使用按钮KEY1来触发。后续大家可以根据自己的情况来调用124行与125行的代码,让CPU复位后马上进入bootloader程序。
文章图片
最后就是最重要的函数JumpToApp( )的实现了。
文章图片
stm32f407为什么是0x1FFF0000,通过stm32f4xx的中文参考手册的第57页,可以看到系统存储器(bootloader)的地址范围是0x1FFF0000 - 0x1FFF77FF。
文章图片
五、实验开始 5.1、烧录boot文件夹的工程代码 烧录代码成功后,LD1开始以100ms的间隔闪烁。
从代码可以看到,当按下K1按钮后,LD2将不再闪烁。因为程序跳转到bootloader程序那里去了。
5.2、stm32CubeProgrammer 打开软件之后,选择USB方式,再点击Connect。
文章图片
连接成功后,在Target information能找到mcu的信息,还有左侧的Log栏目能看到Data read successfully!
文章图片
接着,就是需要找到将要烧录的固件程序,它的格式是hex。
文章图片
找到需要通过bootloader程序来更新程序的新固件,格式hex。
下载新的固件代码成功后,按下stm32-v5开发板的reset按钮,让mcu复位。如下图所示,LD1以更加高的频率进行闪烁了。通过USB的方式更新代码成功!!
六、细节补充 6.1、变量g_JumpInit究竟被存放在哪里? 通过修改.sct文件与按照以下的方式定义变量g_JumpInit后,它真的被存放在RAM2里边了吗?为此我通过.map文件来确认。
文章图片
从.map文件看到,变量g_JumpInit被存放到内存0x2001c000里,而且大小是4个byte(字节),0x2001c000其实就是RAM2内存的起始地址。
6.2、进入bootloader程序后,MCU真的运行在内存0x1FFF0000~0x1FFF77FF吗? 通过debug模式,当按下按钮KEY1后,通过PC寄存器可以看到,程序运行在内存地址0x1FFF149F,这个内存地址就是在0x1FFF0000 ~ 0x1FFF77FF之间。
文章图片
6.3、变量g_JumpInit一定要存放在RAM2里面吗? 【STM32|bootloader | 基于STM32F407 - 使用STM32Cubeprogrammer的USB DFU进行固件烧写】变量g_JumpInit并不一定要放在RAM2里面,在实际项目中,有的人会把它放在外部flash里,或者内部flash。目的是避免复位cpu时,变量g_JumpInit也跟着复位。
推荐阅读
- 物联网学习|基于iOS快捷指令和Siri控制连接OneNET物联网平台的STM32的智能安防家居系统
- 笔记|使用Python自动调节EFR32的高频晶振(HFXO)电容器组-CTune
- 硬件经验|Lightning 转 USB Type-A/Type-C 思路
- fpga开发|TDC进位链
- DDR3|FPGA-DDR总线电源硬件设计技巧-Fly-by走线阻抗
- RT-Thread|RT-Thread记录(十七、AT组件 — ESP8266使用 at_device 软件包联网)
- RT-Thread和STM32|RT-Thread IIC总线官方实例实现
- RT-Thread|RT-Thread记录(十四、I/O 设备模型之ADC设备)
- RT-Thread|RT-Thread记录(十六、SFUD组件 — SPI Flash的读写)