要使用 M032 系列微控制器 实现 USB 磁盘和 FatFs 功能,需结合 USB Mass Storage Class (MSC) 协议和 FatFs 文件系统库。以下是详细步骤和代码框架:
1. 硬件准备
- 开发板:如 NuMaker-M032SE/M032KI。
- 存储介质:SPI Flash 或 SD 卡(通过 SPI/SDIO 接口连接)。
- USB 接口:确保 USB DP/DM 引脚正确连接。
2. 软件环境
- IDE:Keil MDK 或 IAR Embedded Workbench。
- BSP:安装 NuMicro M032 BSP。
- 库依赖:
- USB Device Library:提供 MSC 协议栈。
- FatFs R0.14+:文件系统库(下载地址)。
3. 步骤概述
- 初始化存储介质(如 SPI Flash)。
- 集成 FatFs 并实现磁盘访问接口。
- 配置 USB MSC 并链接到 FatFs。
- 处理 USB 事件 和存储访问同步。
4. 代码实现
(1) 初始化存储介质(以 SPI Flash 为例)
#include "NuMicro.h"
void SPI_FLASH_Init(void) {
// 启用 SPI0 时钟
CLK_EnableModuleClock(SPI0_MODULE);
// 配置 SPI0 引脚 (CLK0: PB2, MISO0: PB3, MOSI0: PB4)
SYS->GPB_MFP0 = (SYS->GPB_MFP0 & ~(SYS_MFP_PB2_Msk | SYS_MFP_PB3_Msk | SYS_MFP_PB4_Msk))
| (SYS_MFP_PB2_SPI0_CLK | SYS_MFP_PB3_SPI0_MISO | SYS_MFP_PB4_SPI0_MOSI);
// SPI 配置:主机模式, 模式 0, 1 MHz
SPI_Open(SPI0, SPI_MASTER, SPI_MODE_0, 8, 1000000);
}
(2) 集成 FatFs 并实现磁盘 I/O
diskio.c(实现 FatFs 的底层接口):
#include "ff.h"
#include "diskio.h"
DSTATUS disk_status(BYTE pdrv) {
return RES_OK; // 假设磁盘始终就绪
}
DSTATUS disk_initialize(BYTE pdrv) {
SPI_FLASH_Init(); // 初始化 SPI Flash
return RES_OK;
}
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
for (UINT i = 0; i < count; i++) {
SPI_FLASH_Read(sector + i, buff + i * FF_MAX_SS); // 假设扇区大小=512字节
}
return RES_OK;
}
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) {
for (UINT i = 0; i < count; i++) {
SPI_FLASH_Write(sector + i, buff + i * FF_MAX_SS);
}
return RES_OK;
}
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) {
switch (cmd) {
case GET_SECTOR_COUNT: // 总扇区数
*(LBA_t*)buff = SPI_FLASH_SIZE / FF_MAX_SS;
break;
case GET_SECTOR_SIZE: // 扇区大小
*(WORD*)buff = FF_MAX_SS;
break;
case CTRL_SYNC: // 同步缓存
SPI_FLASH_Sync();
break;
default: return RES_PARERR;
}
return RES_OK;
}
(3) 配置 USB MSC 设备
main.c(关键部分):
#include "NuMicro.h"
#include "ff.h"
#include "diskio.h"
#include "usbd.h"
#include "msc.h"
FATFS g_fs; // FatFs 工作区
BYTE g_usbd_buff[FF_MAX_SS]; // 读写缓冲区
// USB MSC 回调函数
int32_t MSC_Read(uint32_t lba, uint8_t *buf, uint32_t buf_len) {
UINT br;
// 使用 FatFs 读取扇区
f_read(&g_fs.drv[0], buf, buf_len / FF_MAX_SS, &br);
return 0;
}
int32_t MSC_Write(uint32_t lba, uint8_t *buf, uint32_t buf_len) {
UINT bw;
// 使用 FatFs 写入扇区
f_write(&g_fs.drv[0], buf, buf_len / FF_MAX_SS, &bw);
return 0;
}
void MSC_OtherRequest(void) {
// 处理 SCSI 命令(如获取容量)
switch (g_usbd_scsi_cmd[0]) {
case SCSI_READ_CAPACITY:
// 填充磁盘容量信息
break;
// 其他命令...
}
}
int main() {
// 初始化 SPI Flash
SPI_FLASH_Init();
// 挂载文件系统
f_mount(&g_fs, "0:", 1); // "0:" 表示物理磁盘0
// 初始化 USB MSC 设备
USBD_Open(&gsInfo, MSC_ClassRequest, NULL);
MSC_SetCallbacks(MSC_Read, MSC_Write, MSC_OtherRequest);
USBD_Start();
while (1) {
// 处理 USB 事件和文件系统任务
USBD_ProcessSetupPacket();
}
}
5. 关键配置
USB 时钟设置:
USB 引脚配置:
SYS->GPA_MFP0 |= SYS_MFP_PA12_USB_DP | SYS_MFP_PA13_USB_DM;
SCSI 命令处理:
- 在
MSC_OtherRequest() 中实现 SCSI_READ_CAPACITY、SCSI_INQUIRY 等标准命令。
6. 调试技巧
格式化存储介质:
首次使用时,在 PC 端格式化磁盘(FAT32)或调用 f_mkfs("0:", FM_FAT32, 0, g_usbd_buff, sizeof(g_usbd_buff))。
日志输出:
通过 UART 打印调试信息(如 printf("Read LBA: %dn", lba);)。
USB 枚举检查:
- 使用 USBlyzer 或 Wireshark 监控 USB 枚举过程。
7. 常见问题
示例工程
参考 NuMicro BSP 中的示例代码:
SampleCodeStdDriverUSBD_MSC_Flash
SampleCodeStdDriverUSBD_MSC_SD
将 FatFs 集成到现有 USB MSC 工程中,替换存储访问函数即可。
通过以上步骤,M032 MCU 即可实现 USB 磁盘和 FatFs 功能。