Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Bootloader
灵动微_MM32
USB
提供一种固件在线调试的USB Bootloader
5.00
发布于 2022-08-24 21:08:43 浏览:1066
订阅该版
[tocm] ## 用途与背景 在MCU开发中,固件的调试离不开烧录工具,烧录工具的种类有很多,常见的比如有ST-Link、J-Link、DAP等等。这些烧录工具的接口都不是统一的,并且它们的引脚接线往往需要非常仔细、慎重,才能保证正确烧录程序并调试。为了解决这个问题,本文提供了一种使用USB线即可完成程序在线调试的方法。USB已经是生活中常见的接口,并且它是以“盲插”的方式接入电脑的,也就是说,不会出现接错的情况。 另外,在SRAM上调试的速度可比flash快很多,并且不用担心flash的寿命问题,但相应的,也就有掉电无法保存的缺陷。 ## 效果演示 当试用板的USB接口接入计算机时,计算机会弹出“U盘”的弹窗,此时,可将MCU的bin固件放入此U盘中(注意:目前Bootloader只检测“project”名称的bin固件),在传输完成后,按下试用板的“D7”按键,实现将“project.bin”固件的内容拷贝到外部sram。之后,MCU跳转到外部sram执行程序。这样就实现了在线调试程序的效果。 想观看效果演示的话,可以查看以下链接: https://www.bilibili.com/video/BV15B4y1V7Tt/?aid=602151098&cid=810080747&page=1 ## 整体原理介绍 ### 存储分布 USB Bootloader主要涉及到2个存储区域,一是USB MSC设备的存储区,二是用户app的存储区。这两者目前都存放在SRAM中,其内存分布如下: ![存储分布.png](https://oss-club.rt-thread.org/uploads/20220824/024ee162749593fef5471c0d94b5aba6.png "存储分布.png") ### USB USB是一种通用的串行通信方式,其硬件底层使用NAZI编码,并采用差分方式传输,进行了位填充、串行化、反串行化、CRC校验等处理,这些底层的处理都是由芯片硬件完成的,作为开发者无需关注更多。在经历这些底层的传输后,我们真正可以拿到的数据都是从端点取到的,当然,也可以通过端点发送数据。端点是通过端点号来标识的,端点0永远是控制端点,可以双向传输,其余端点只能标志为单向传输。基于端点之上,USB协议栈抽象了接口、配置和设备等概念,对应的,也就有端点描述符、接口描述符、配置描述符和设备描述符等。接口描述符包含了USB设备的功能信息,例如本文涉及到的U盘其实就是在接口描述符中添加MSC接口。更多USB基础知识可以直接上USB官网下载相关文档学习。 ### FATFS 我们知道,每个U盘在使用之前(如果还没有格式化),需要先格式化操作。在格式化过程中会选择格式化的文件系统。文件系统本质上是一种数据结构,完成数据的索引和存取。在windows的格式化选项中,一般会有fatfs文件系统,fatfs文件系统也是嵌入式领域常用的开源文件系统,因此,需要移植一个fatfs文件系统,实现对存储空间的文件系统制作以及文件数据的存取(也可以自己实现文件系统制作和数据存取,这需要了解文件系统构成,并且会降低程序可读性)。 ## 关键实现 ### USB MSC存储空间操作 根据USB MSC的相关规范,USB主机会发送以下命令: 1. READ FORMAT CAPACITIES 和 READ CAPACITY "READ FORMAT CAPACITIES"用于获取可格式化的最大容量,"READ CAPACITY"用于获取实际设备存储媒介的容量。在MindMotion的MSC例程中,这两者都回调同一个函数,也即两者返回容量一致,本文在此处将返回的容量改为256k的空间大小。如下: ``` enum { DISK_BLOCK_NUM = 2 * 256, // 256k DISK_BLOCK_SIZE = 512 }; ``` 2. READ USB主机通过该命令读取U盘数据。在TinyUSB协议栈中,设备在接收到该命令时,回调“tud_msc_read10_cb”函数,在该函数添加SRAM读取处理即可。如下: ``` int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; if ( lba >= DISK_BLOCK_NUM ) return -1; udisk_sram_read(lba * DISK_BLOCK_SIZE + offset, (uint8_t *)buffer, bufsize); return bufsize; } ``` 3. WRITE 与READ类似,设备在接收到该命令时,回调“tud_msc_write10_cb”函数,在该函数添加SRAM写入处理即可。如下: ``` int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { (void) lun; // out of ramdisk if ( lba >= DISK_BLOCK_NUM ) return -1; udisk_sram_write(lba * DISK_BLOCK_SIZE + offset, buffer, bufsize); return bufsize; } ``` ### FATFS移植 进入[fatfs官网](http://elm-chan.org/fsw/ff/00index_e.html)下载源码,fatfs本质上是实现对数据的组织,其移植十分简单,主要在“diskio.c”文件中,在该文件中,实现对设备实际上存储媒介的状态查询、初始化、读写、和信息查询等接口即可。以下给出读写的代码参考: ``` DRESULT disk_read ( BYTE pdrv, BYTE *buff, LBA_t sector, UINT count ) { switch (pdrv) { case DEV_RAM : FATFS_SRAM_READ(sector * FF_MIN_SS, buff, count * FF_MIN_SS); return RES_OK; //case DEV_FLASH : } return RES_PARERR; } DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { switch (pdrv) { case DEV_RAM : FATFS_SRAM_WRITE(sector * FF_MIN_SS, (uint8_t *)buff, count * FF_MIN_SS); return RES_OK; //case DEV_FLASH : //return res; } return RES_PARERR; } ``` ### 程序跳转 程序跳转主要包括以下步骤: 1. 外设解初始化; 2. 中断向量重定向; 3. 堆栈指针重定位; 4. 跳转到指定地址运行。 可参考如下: ``` void jump_to_app() { printf("jump to app\r\n"); dcd_int_disable(0); USB_Enable(BOARD_USB_PORT, false); UART_Enable(BOARD_DEBUG_UART_PORT, false); SCB->VTOR = APP_START_ADDR; Jump_To_App(); } ``` Jump_To_App的实现如下: ``` Jump_To_App: ldr r0, = 0x68050000 ldr r0, [r0] mov sp, r0 ldr r0, = 0x68050000 + 4 ldr r0, [r0] bx r0 ``` ## 注意事项 由于用户app是运行在sram上的,此时用户程序最好不要有sram的其它相关操作。并且由于bootloader已经使能了fsmc接口的相关引脚时钟,包括GPIOD、GPIOE、GPIOF、GPIOG,为了保证sram能够持续工作,**用户app如若需要使用到“GPIOD、GPIOE、GPIOF、GPIOG”端口的相关引脚,不能再去打开这些端口的时钟,否则,sram会被中断导致用户app无法执行,出现“卡死”现象。** 更新的用户程序需要做一些修改,主要在于分散加载文件,由于固件在sram上跑,因此程序的加载和运行位置都需要修改,以“plus-f5270_mdk\driver_examples\uart\uart_basic”例程为例,在默认的分散加载文件“mm32f5277e_flash.scf”中修改,具体如下: ``` #define __ROM_BASE 0x68050000 #define __ROM_SIZE 0x00040000 ``` 栈的起始位置可以覆盖之前的位置。 在Keil中默认生成的固件为hex固件,可在设置中配置使其生成bin固件,如下: ![bin生成.png](https://oss-club.rt-thread.org/uploads/20220824/611bbb5cc5c7baea5f991770100d0b37.png.webp "bin生成.png") ## 拓展与升级 目前,该Bootloader仅仅实现在SRAM中跑程序,可进一步实现将固件数据拷贝到flash,实现程序升级。MM32F5270支持XIP,因此也可实现程序放置在外部flash上运行,从而支持大规模的应用。 ## 代码链接 https://gitee.com/bigbear2021/mm32_usb_bootloader.git
6
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
大目熊
业余开发者
文章
3
回答
13
被采纳
3
关注TA
发私信
相关文章
1
请教USB Host
2
STM32F4调试USB 读卡器(Slave)提示格式化
3
急求 STM32F4 USB Device MSC+SD 的相关问题
4
USB 框架问题
5
USB键盘
6
LPC17xx 如何添加USB HOST设备
7
RT-Thread目前支持USB HOST了吗?
8
USB HOST的支持问题
9
RTT 2.0.1 USB存储设备问题,枚举到USBREQ_GET_MAX_LUN后复位
10
USB库已经很久没更新了
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
线程
RT-Thread Nano
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
807
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部