USB的MSD模式和FatFS在操作SD卡,让他们互斥就好了
一、总原则
MSD 模式下,MCU 的角色是"块级透明桥",不是文件系统代理。
- 它不解析 FAT、不认文件名、不知道什么是"文件"
- 它只做一件事:把 PC 的"读/写第 N 个扇区"翻译成 SD 卡的
CMD17/CMD18/CMD24 - 文件系统的事全在 PC 那边(Windows 的 FAT 驱动)
所以"U 盘"= 把 SD 卡的扇区原样透传给电脑。
二、USB 插入 → 是否进入 MSD 模式
USB 插入
│
┌──────────┴──────────┐
│ │
VBUS 存在 PC 发起枚举
(PB5 变高) GET_DESCRIPTOR → SET_ADDRESS
│ → GET_DESCRIPTOR(配置)
│ │
只说明"有电" SET_CONFIGURATION ← 握手成功的唯一标志
充电头也满足 │
→ 不能作判据 ┌─────┴─────┐
│ 是 不是
│ │ │
└──► ✗ 进入 MSD ✗ 不进 MSD
模式 本机照常拍照
关键:判据是"协议握手",不是"有没有电"。
充电头只会给 VBUS,永远不会发 SET_CONFIGURATION,所以插充电器时本机照常工作,不进 MSD。
三、进入 MSD 模式(握手成功的那一刻)
这一步必须在中断里、几毫秒内完成,因为主机的第一条 SCSI 命令随后就到:
① 置模式标志 → "本机禁访"立即生效
② 让 MSC 能报"有介质" → 用开机时就已缓存的容量
③ 不动本机 FatFs → 卸载是 I/O,太慢,会错过主机第一条命令
四、PC 读 SD 卡的完整流程
PC(Windows FAT 驱动)
│ ① READ CAPACITY(10)
▼
USB1 控制器 ──中断──► USB-ESL 协议栈 ──► InterfaceMSD (BOT/SCSI)
│ │
│ ├─ ② 用缓存的 BlockCount 回答
│ ③ READ(10) LBA=N, count=M │
▼ ▼
usbMSDDiskRead()
│ ④ 打上"USB 正在用总线"标记
▼
disk_read(0, buf, N, M)
▼
SD_SPI_ReadSectors()
│ ⑤ CMD17/CMD18 → SPI4
▼
SD 卡
要点:
| 点 | 说明 |
|---|---|
| 全程同步发生在 USB 中断里 | MCU 就是个搬运工,没有任务调度参与 |
| 中断可能很长 | 一次 READ10 能读几十个块 → 所以 USB 中断优先级要低于图像采集 |
| 数据不经过文件系统 | buf 与扇区直接对拷,MCU 完全不知道这是 FAT 还是目录还是照片 |
五、PC 写 SD 卡的流程
同一条链,只是命令换成写:
WRITE(10) → usbMSDDiskWrite() → disk_write() → CMD24/CMD25 → SD 卡
六、MSD 模式下本机能做什么
| 操作 | 允许 | 原因 |
|---|---|---|
| 拍照(写文件) | ✗ | 两边 FAT 缓存会互相覆盖 |
| 格式化 | ✗ | 同上 |
| 读文件 / 刷新图库 | ✗ | 只读也会拿到过期目录,会看到不存在的文件 |
| 显示卡的总容量 | ✅ | 来自 CSD 缓存,不读 FAT |
| 显示剩余容量 | ⚠️ 只能显示进入前的旧值 | 算剩余要挂载 FAT |
禁的是"本机挂载文件系统",不是"本机不能碰卡"。 物理上 MCU 随时能读扇区;不让它读,是因为它的 FAT 缓存已经和 PC 改过的实际内容不一致了。
七、退出 MSD 模式
判据:PB5 物理拔出(去抖后)。 为什么不看协议事件:
- 本机是自供电设备,拔线时 PC 侧不一定发任何事件(reset / deconfig 都可能没有)
- PC 上点"弹出" ≠ 拔线,不应该退出
退出动作(顺序不能反):
① 清模式标志 ← 先退出模式,USB 侧立刻拒绝新访问
② f_mount(NULL) ← 丢弃被 PC 改过的陈旧 FAT/目录缓存
③ disk_initialize() ← 卡可能被 PC 动过,重跑 SD 协议初始化
④ 用本机唯一的 FATFS 对象重挂 + 刷新图库
②③④ 顺序的原因:必须先退出模式再挂载。反过来(还在模式内就挂载)挂载过程中的磁盘读会被自己的互斥层拒绝,永远挂不上。
八、互斥的两层(概念)
| 层 | 粒度 | 解决什么 |
|---|---|---|
| 模式层 | 整卷 | 决定"这一段时间归谁"——本机所有磁盘调用一律拒绝 |
| 事务层 | 单次 SPI 事务 | 防止一次 CMD17/CMD24 被另一端插进来打断 |
模式层保证不会两个主人同时挂同一个 FAT;事务层保证单条 SD 命令不被切碎。
九、完整状态图
┌──────────────────────────────────────────────┐
│ 本机模式(LOCAL) │
│ FatFs 挂载中 · 可拍照 · 可格式化 · 可看图库 │
└──────────────────────────────────────────────┘
│ ▲
USB 插入并用真主机 PB5 物理拔出
完成 SET_CONFIGURATION (去抖 ~300ms)
│ │
▼ │
┌──────────────────────────────────────────────┐
│ MSD 模式(USB) │
│ PC 全权限读写扇区 · 本机禁止读写 SD │
│ 容量显示停在进入前的旧值 │
└──────────────────────────────────────────────┘
插充电器:只有 VBUS,永远不握手 → 留在"本机模式"
PC 上点"弹出":不退出 → 要物理拔线