news 2026/8/27 15:12:24

TeenyUSB MSC U盘开发指南:用FatFs打造你自己的闪存U盘设备

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TeenyUSB MSC U盘开发指南:用FatFs打造你自己的闪存U盘设备

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.cBOT 协议状态机、SCSI 命令解析
MSC 设备接口tusbd_msc.htusb_msc_device_t结构与回调定义
BOT 协议定义tusb_msc.hCBW/CSW 包格式
SCSI 命令定义tusb_scsi.hINQUIRY、READ(10)、WRITE(10) 等命令
复合设备示例composite_device.c含 MSC U 盘的完整可编译例程

USB 传输由底层 API 与中断回调完成,而应用层只需要关心三件事:

  1. 写三个块级回调函数get_cap(容量)、block_read(读块)、block_write(写块);
  2. 填一个结构体,把回调挂到tusb_msc_device_t上;
  3. 在主循环里调用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_ERRORWRITE_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_opsis_readyloadEjectinquiry),可以实现"可弹出"语义和自定义 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 15:10:59

KKCE: 网站测速,ping检测,IP查询,路由追踪-快快测

一、引言:为什么 Chrome DevTools 显示完美,网站测速却显示移动端布局错乱? 在响应式网页设计中,我们常以为只要在 Chrome DevTools 的设备模拟器中切换为“iPhone 12”视图,页面能正常排列,移动端适配就“…

作者头像 李华
网站建设 2026/8/27 15:08:37

AI情感陪伴的隐私风险:从上下文窗口到数据脱敏的技术拆解

这两天“AI 情感陪伴”的话题热度又上来了。聊天机器人能陪你聊心事、模拟朋友口吻、在你深夜失眠时给出“温柔回应”,但斯坦福相关研究引发的讨论,给这个热闹场面泼了一盆冷水:你跟 AI 说的私密话,可能并不只是你们俩知道。问题不…

作者头像 李华
网站建设 2026/8/27 15:05:23

Hotfix API 参考:HotFix.patch() 方法完整用法与参数说明

Hotfix API 参考:HotFix.patch() 方法完整用法与参数说明 【免费下载链接】Hotfix The Hotfix tool can dynamically fix online bugs for Android without republishing an app. 项目地址: https://gitcode.com/gh_mirrors/hot/Hotfix Hotfix 是一款免费开源…

作者头像 李华
网站建设 2026/8/27 15:01:51

实时上报停留时长数据:TimeMe.js内置WebSocket通道3步集成教程

实时上报停留时长数据:TimeMe.js内置WebSocket通道3步集成教程 【免费下载链接】TimeMe.js A JavaScript library to accurately time how long a user views a web page, disregarding idle time and time when the tab or window is minimized. 项目地址: https…

作者头像 李华