TeenyUSB MSC U盘开发指南:用FatFs打造你自己的闪存U盘设备
【免费下载链接】TeenyUSBLightweight USB device and host stack for STM32 and other MCUs. Ready for USB 3.0 device.项目地址: https://gitcode.com/gh_mirrors/te/TeenyUSB
TeenyUSB 是一个轻量级单片机 USB 协议栈,支持 STM32、CH565W 等主流 MCU 的 USB 设备与主机模式。本指南带你用 TeenyUSB 的 MSC(大容量存储类)功能,把 MCU 做成一台电脑即插即用的 U 盘,并配合项目内置的 FatFs 文件系统,直接在 U 盘上读写文件——无需任何驱动,Windows/macOS/Linux 全平台免驱识别。
1. 三分钟了解 MSC 设备架构 🧩
把 MCU 变成 U 盘,本质上就是让单片机应答标准的 SCSI 命令。TeenyUSB 在class/msc/目录下提供了完整的 MSC BOT(Bulk-Only Transport)协议实现:
| 模块 | 路径 | 作用 |
|---|---|---|
| MSC 设备类 | tusbd_msc.c | BOT 协议状态机、SCSI 命令解析 |
| MSC 设备接口 | tusbd_msc.h | tusb_msc_device_t结构与回调定义 |
| BOT 协议定义 | tusb_msc.h | CBW/CSW 包格式 |
| SCSI 命令定义 | tusb_scsi.h | INQUIRY、READ(10)、WRITE(10) 等命令 |
| 复合设备示例 | composite_device.c | 含 MSC U 盘的完整可编译例程 |
USB 传输由底层 API 与中断回调完成,而应用层只需要关心三件事:
- 写三个块级回调函数:
get_cap(容量)、block_read(读块)、block_write(写块); - 填一个结构体,把回调挂到
tusb_msc_device_t上; - 在主循环里调用
tusb_msc_device_loop()处理命令。
这就是 TeenyUSB "teeny"(迷你)的精髓——MSC 设备类代码只有几百行,却能让电脑把你的 MCU 识别成标准可移动磁盘。
2. 用 TeenyDT 生成带 MSC 接口的描述符
USB 描述符不需要手写,项目自带基于 Lua 的描述符生成工具TeenyDT(源码见 TeenyDT/)。在 composite_desc.lua 中,MSC 接口只需 6 行配置:
Interface{ bInterfaceClass = 0x08, -- MSC bInterfaceSubClass = 0x06, -- SCSI bInterfaceProtocol = 0x50, -- BOT EndPoint(IN(4), BulkDouble, 64), EndPoint(OUT(4), BulkDouble, 64), }生成后的teeny_usb_desc.c/h由脚本自动产出,其中BulkDouble表示按高速/全速自动调整端点包长。三个值0x08 / 0x06 / 0x50是 U 盘识别的"身份证",操作系统看到它们就会加载大容量存储驱动。
3. 实现块设备回调:告诉协议栈数据存哪里
MSC 层只操作 512 字节的"块",存储介质可以是 RAM、NOR Flash、SD 卡甚至 NAND。以 composite_device.c 中的 RAM 盘为例:
tusb_msc_device_t msc_dev = { .backend = &msc_device_backend, .ep_in = 4, .ep_out = 4, .max_lun = 0, // 1个逻辑单元 .get_cap = msc_get_cap, // 返回块数/块大小 .block_read = msc_block_read, .block_write = msc_block_write, };- RAM 盘(示例代码 L233-L272):
START_ADDR指向 RAM 尾部的空闲区域,BLOCK_COUNT按芯片 RAM 计算,读写就是memcpy,速度最快,适合功能演示; - Flash 盘(示例代码 L275-L297):
START_ADDR从 Flash 偏移 20KB 处开始,块大小取 Flash 扇区大小,写入调用flash_write(),适合做真正的"闪存 U 盘",但注意 Flash 擦写寿命有限。
两个回调的返回值约定很清晰:返回实际读写的字节数,出错返回 -1,协议栈会自动填充相应的 SCSI Sense 错误码(如MEDIUM_ERROR、WRITE_FAULT),宿主机就能看到"读写失败"提示。
⚠️常见坑:MSC_DATA_PACKET_LENGTH数据缓冲区必须 ≥ 512,否则 composite_device.c 末尾的编译期检查会直接报错。
配置好结构体后,只需在主循环中周期性调用tusb_msc_device_loop(&msc_dev);(示例代码 L229),电脑即可看到一块可移动磁盘。
4. 用 FatFs 让 U 盘支持文件读写 📁
裸盘只是一堆块数据,接上 FatFs 后电脑才能看到.txt、.jpg这样的文件。项目已在 third_part/fatfs/ 内置完整的 FatFs 源码:
- ff.c / ff.h:文件系统核心(FAT12/16/32 读写)
- ffconf.h:功能裁剪配置
- diskio.c:底层磁盘适配"胶水层"
FatFs 通过diskio.c与具体存储解耦,其中预留了 RAM/MMC/USB 三种物理盘的定义。接入自己的存储只需实现四个胶水函数(以 RAM 盘为例):
DRESULT RAM_disk_read(BYTE *buff, LBA_t sector, UINT count) { memcpy(buff, (void*)START_ADDR + sector*512, count*512); return RES_OK; }然后挂载并验证:
f_mount(&fs, "", 1); // 挂载盘0 FRESULT res = f_open(&file, "hello.txt", FA_READ); f_read(&file, buf, sizeof(buf), &bytes); // 读出U盘里的文件由于 TeenyUSB 的block_read/block_write回调与disk_read/disk_write参数几乎一致(起始块地址 + 块数 + 缓冲区),FatFs 层可以零拷贝地直接调用 MSC 的同一套存储函数,一套介质驱动同时服务于"USB 对外服务"和"自己读自己的盘"两个方向。
💡提示:FAT 的根目录表、FAT 表会频繁改写。若介质是 Flash,建议在diskio.c中加一层块缓存,或把 FAT 表映射到 RAM,可显著延长 Flash 寿命。
5. 一键编译验证
项目使用arm-none-eabi-gcc工具链编译,MSC 已集成在 composite 复合设备示例中(HID + CDC + WinUSB + MSC 四合一):
git clone https://gitcode.com/gh_mirrors/te/TeenyUSB cd TeenyUSB git submodule update --init # 拉取mcu_lib的STM32库 cd sample make comp支持的验证板卡包括 STM32F072/F103/F107/F303/F407/F723/F767/H743 及 CH565W(USB 3.0 设备),各板卡配置见 sample/boards/。烧录后插线到电脑,设备管理器中应看到 "TeenyUSB" 厂商名的可移动磁盘(SCSI INQUIRY 回复默认是TeenyUSB / MSC BOT DEMO,可在 tusbd_msc.c 的msc_scsi_inquiry()中改成你自己的品牌名)。
6. 常见问题排查清单 ✅
| 现象 | 原因与对策 |
|---|---|
| 电脑识别为未知设备 | 描述符 MSC 三字节不对,确认0x08/0x06/0x50,并用 TeenyDT 重新生成 |
| 磁盘容量为 0 或异常 | get_cap返回的block_num计算错误,注意减去程序与栈占用的空间 |
| 读写偶发失败 | block_read/block_write返回了 -1,检查地址越界与 Flash 扇区对齐 |
| FatFs 挂载失败(FR_NO_FILESYSTEM) | 裸盘无 FAT 表,先用电脑格式化一次或调用f_mkfs()初始化 |
| 编译报错 buffer 太小 | 把MSC_DATA_PACKET_LENGTH提到 ≥ 512 |
进阶方向:tusb_msc_device_t支持max_lun多逻辑单元和可选的scsi_ops(is_ready、loadEject、inquiry),可以实现"可弹出"语义和自定义 INQUIRY 品牌信息;主机侧的 tusbh.c 同样实现了 MSC Host 类,同一块板还能反过来读取插入的 U 盘——设备与主机双角色,这正是 TeenyUSB 相比同类轻量栈的优势所在。
祝你的第一块"MCU 自制 U 盘"点亮成功!🚀
【免费下载链接】TeenyUSBLightweight USB device and host stack for STM32 and other MCUs. Ready for USB 3.0 device.项目地址: https://gitcode.com/gh_mirrors/te/TeenyUSB
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考