STM32F407ZGT6 USB MSC SD读卡器 完整图文配置教程
目录
5.1 usbd_storage_if.c USB与SDIO扇区对接函数(核心文件,必须修改
5.2 main.c 初始化顺序(顺序错误会导致USB/SD卡死)
文档概述
本教程基于STM32CubeMX配置工具,详细讲解STM32F407ZGT6芯片实现USB MSC大容量存储读卡器的完整配置流程,包含全部配置界面截图与参数说明。
项目信息
- 主控芯片:STM32F407ZGT6 LQFP144
- 实现功能:USB OTG FS Device MSC(虚拟读卡器U盘)+ SDIO 4线TF卡存储 + FATFS文件系统
- 开发环境:STM32CubeMX + MDK-ARM Keil5
第一章 系统内核外设配置(基础硬件层)
1.1 DMA SDIO收发通道配置
DMA配置界面 - SDIO专用DMA2通道
配置说明
- 仅使用DMA2(F4硬件规定SDIO只能挂载DMA2,不可选用DMA1)
- SDIO_RX:DMA2 Stream3,传输方向Peripheral To Memory,优先级Low
- SDIO_TX:DMA2 Stream6,传输方向Memory To Peripheral,优先级Low
- 勾选MemToMem总开关,无DMA1外设占用
|
关键注意:SDIO不可选用DMA1,硬件总线绑定DMA2,选错会直接导致SD卡读写卡死。 |
1.2 GPIO复用全局参数配置
GPIO配置界面 - 全部外设引脚复用参数
统一复用规则(所有外设引脚通用)
- GPIO mode:Alternate Function 复用功能
- 上下拉:No pull-up/pull-down 无上下拉
- 输出速度:Very High 高速(USB/SDIO高频通信强制要求)
当前分组外设:FSMC、RCC、SDIO、SYS、USART、USB,全部引脚无冲突。
1.3 NVIC中断优先级分配配置
NVIC配置界面 - 中断优先级分配表
核心中断优先级表
|
中断源 |
抢占优先级 |
子优先级 |
作用 |
|
USB On The Go FS global interrupt |
1 |
0 |
USB通信最高优先级,防止传输中断 |
|
SDIO global interrupt |
2 |
0 |
SD卡硬件读写中断 |
|
DMA2 stream3/6 global interrupt |
3 |
0 |
SDIO DMA收发中断 |
|
USART2 global interrupt |
4 |
0 |
调试串口打印中断 |
附加配置
勾选Force DMA channels name,生成代码DMA命名标准化,便于调试。
1.4 RCC外部高速晶振时钟配置
RCC配置界面 - 外部晶振选择
参数说明
- HSE:Crystal/Ceramic Resonator(外部8M晶振,F4标准)
- LSE:Crystal/Ceramic Resonator(32.768K外部晶振)
- 关闭MCO2、I2S时钟输出,不占用额外引脚。
1.5 SYS调试与时基配置
SYS配置界面 - 调试与系统时基
配置项
- Debug:Serial Wire(SWD两线下载,节省引脚)
- Timebase Source:SysTick(系统毫秒时基)
- 无系统唤醒、额外时钟输出配置。
第二章 硬件外设专项配置
2.1 FSMC外部SRAM备用配置
FSMC配置界面 - 外部SRAM备用配置
说明
本项目读卡器功能不依赖FSMC,仅作为外部缓存备用:
- Bank3 NE3配置为16位SRAM,19位地址总线
- 时序参数适配通用外部SRAM
- 无SRAM硬件可直接取消FSMC勾选释放PD0~PD15引脚资源
2.2 SDIO 4线SD卡硬件配置
SDIO配置界面 - 4线高速SD卡模式
核心参数
- Mode:SD 4 bits Wide bus 4线高速SD卡模式
- SDIOCLK clock divide factor = 4,输出42MHz SD卡时钟
- 上升沿采样、关闭硬件流控、关闭时钟省电模式
|
性能提示:4线模式读写速度远优于1线模式,是SD卡高速读写的标准配置。 |
2.3 USART2调试串口配置
USART2配置界面 - 调试串口参数
标准调试参数
- 模式:Asynchronous异步,无硬件流控
- 波特率:115200
- 数据位:8 Bits
- 校验:None 无校验
- 停止位:1
- 过采样:16 Samples,提升串口抗干扰能力
2.4 USB_OTG_FS全速USB设备模式配置
USB_OTG_FS配置界面 - 设备模式
配置规则
- Mode:Device_Only 纯设备模式(仅做读卡器从设备)
- 取消Activate_SOF、Activate_VBUS(开发板自供电,无需VBUS检测)
- 自动分配PA11(USB_DM)、PA12(USB_DP)复用高速引脚
|
硬件注意:USB差分数据线D+/D-必须串联22Ω限流电阻,否则电脑无法识别设备。 |
第三章 Middleware中间件完整配置
3.1 USB_DEVICE MSC大容量存储基础参数
USB_DEVICE配置界面 - MSC基础参数
核心配置
- Class For FS IP:Mass Storage Class 大容量存储读卡器协议
- Class For HS IP:Disable(仅使用全速OTG FS)
- MSC_MEDIA_PACKET:512 bytes,必须与SD卡扇区大小匹配
- USBD_SELF_POWERED:Enabled 设备自供电(开发板独立5V供电,不从USB取电)
- USBD_DEBUG_LEVEL:0,关闭USB调试日志,减小代码体积
3.2 USB_DEVICE 设备描述符VID/PID配置
USB_DEVICE配置界面 - 设备描述符
固定标准参数(Windows免驱动)
|
参数 |
配置值 |
作用 |
|
VID(Vendor ID) |
1155 |
ST官方厂商ID,Windows自带驱动,无需手动安装 |
|
PID(Product ID) |
22314 |
ST MSC标准产品ID,电脑识别为U盘 |
|
MANUFACTURER_STRING |
STMicroelectronics |
设备管理器厂商名称 |
|
PRODUCT_STRING |
STM32 Mass Storage |
电脑显示设备名称 |
|
LANGID_STRING |
English(United States) |
USB字符串语言编码 |
3.3 USB_DEVICE 用户常量标签页
USB_DEVICE配置界面 - 用户常量
说明
无自定义USB常量,保持空白,无需新增参数。
3.4 FATFS 文件系统功能宏定义配置
FATFS配置界面 - 功能宏定义
启用功能
- USE_MKFS:Enabled(支持SD卡格式化,调试必备)
- USE_FASTSEEK:Enabled(加速文件寻址)
- USE_LFN:Enabled with dynamic buffer(长文件名支持,最大255字符)
- STRF_ENCODE:UTF-8(中文文件名兼容)
关闭功能
关闭只读模式、文件属性、卷标等冗余API,精简固件体积。
3.5 FATFS 物理磁盘扇区参数配置
FATFS配置界面 - 物理磁盘参数
关键参数
- VOLUMES = 1:仅挂载1张SD卡,单分区
- MAX_SS / MIN_SS = 512:扇区512字节,与USB MSC匹配
- FS_LOCK = 2:同时打开最大2个文件
- FS_EXFAT / FS_REENTRANT:关闭,无RTOS场景节省内存
3.6 FATFS SDIO硬件DMA绑定配置
FATFS配置界面 - 高级设置与DMA绑定
硬件对接
- SDIO instance:SDIO,绑定外设SDIO1
- Use dma template:Enabled,开启DMA2加速SD读写
- BSP code for SD:Generic,通用SD卡底层驱动,兼容TF/SD卡
3.7 FATFS 平台SD卡检测引脚配置

说明
Detect_SDIO配置为GPIO Input,无硬件CD检测引脚,Found Solutions=No solution。
|
本硬件未焊接SD卡CD卡检测引脚,无需分配IO,代码内轮询SD卡状态即可,不影响读卡器核心功能。 |
第四章 时钟树校验规则
|
生成代码前必做:时钟配置错误是USB识别失败的最主要原因(占90%以上),必须严格核对以下参数。 |

时钟树强制校验项
- HSE = 8MHz,PLLM = 8,PLLN = 336,PLLP = 2 → SYSCLK = 168MHz
- PLLQ = 7 → USB48CK = 48MHz(USB标准时钟,偏差±0.5M即无法枚举设备)
- APB1预分频 = 4(APB1最大42M,SDIO挂载APB1总线)
- APB2预分频 = 2
校验无误后点击右上角GENERATE CODE生成MDK工程。
第五章 代码生成后工程修改要点
5.1 usbd_storage_if.c USB与SDIO扇区对接函数(核心文件,必须修改
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usbd_storage_if.c
* @version : v1.0_Cube
* @brief : Memory management layer.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
/* USER CODE BEGIN INCLUDE */
#include "diskio.h"
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @brief Usb device.
* @{
*/
/** @defgroup USBD_STORAGE
* @brief Usb mass storage device module
* @{
*/
/** @defgroup USBD_STORAGE_Private_TypesDefinitions
* @brief Private types.
* @{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_Defines
* @brief Private defines.
* @{
*/
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200
/* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_Macros
* @brief Private macros.
* @{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_Variables
* @brief Private variables.
* @{
*/
/* USER CODE BEGIN INQUIRY_DATA_FS */
/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {/* 36 */
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0' ,'1' /* Version : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */
/* USER CODE BEGIN PRIVATE_VARIABLES */
/* USER CODE END PRIVATE_VARIABLES */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Exported_Variables
* @brief Public variables.
* @{
*/
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE BEGIN EXPORTED_VARIABLES */
/* USER CODE END EXPORTED_VARIABLES */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_FunctionPrototypes
* @brief Private functions declaration.
* @{
*/
static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
/**
* @}
*/
USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
STORAGE_Init_FS,
STORAGE_GetCapacity_FS,
STORAGE_IsReady_FS,
STORAGE_IsWriteProtected_FS,
STORAGE_Read_FS,
STORAGE_Write_FS,
STORAGE_GetMaxLun_FS,
(int8_t *)STORAGE_Inquirydata_FS
};
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes the storage unit (medium) over USB FS IP
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Init_FS(uint8_t lun)
{
/* USER CODE BEGIN 2 */
// UNUSED(lun);
DRESULT res = disk_initialize(lun);
if(res == RES_OK)
{
// if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
// {
//// UART_Printf("SDIO Set 4B Err\r\n");
// }
UART_Printf("USBD_OK");
return USBD_OK;
}else
{
UART_Printf("disk_initialize Err\r\n");
}
return USBD_FAIL;
// return (USBD_OK);
/* USER CODE END 2 */
}
/**
* @brief Returns the medium capacity.
* @param lun: Logical unit number.
* @param block_num: Number of total block number.
* @param block_size: Block size.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
/* USER CODE BEGIN 3 */
// UNUSED(lun);
uint32_t total_sectors = 0;
HAL_SD_CardInfoTypeDef sdCardInfo;
// 读取SD卡真实总扇区
HAL_SD_GetCardInfo(&hsd, &sdCardInfo);
total_sectors = sdCardInfo.LogBlockNbr;
// UART_Printf("STORAGE_Read_FS LogBlockNbr=%d\r\n", total_sectors);
*block_num = total_sectors;
*block_size = 512; // MSC强制512字节扇区
return (USBD_OK);
/* USER CODE END 3 */
}
/**
* @brief Checks whether the medium is ready.
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
/* USER CODE BEGIN 4 */
// UNUSED(lun);
uint8_t state = 0;
state = HAL_SD_GetState(&hsd) ;
if(HAL_SD_STATE_READY != state)
{
return USBD_FAIL ;
}
return (USBD_OK);
/* USER CODE END 4 */
}
/**
* @brief Checks whether the medium is write protected.
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
/* USER CODE BEGIN 5 */
UNUSED(lun);
return (USBD_OK);
/* USER CODE END 5 */
}
/**
* @brief Reads data from the medium.
* @param lun: Logical unit number.
* @param buf: data buffer.
* @param blk_addr: Logical block address.
* @param blk_len: Blocks number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
// UNUSED(lun);
// UNUSED(buf);
// UNUSED(blk_addr);
// UNUSED(blk_len);
if(HAL_OK != HAL_SD_ReadBlocks(&hsd,(uint8_t *)buf, blk_addr , blk_len, 1000))
{
// UART_Printf("STORAGE_Read_FS USBD_FAIL blk_addr=%1u\r\n", blk_addr);
return USBD_FAIL ;
}
// UART_Printf("STORAGE_Read_FS HAL_OK blk_addr=%1u\r\n", blk_addr);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* @brief Writes data into the medium.
* @param lun: Logical unit number.
* @param buf: data buffer.
* @param blk_addr: Logical block address.
* @param blk_len: Blocks number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
// UNUSED(lun);
// UNUSED(buf);
// UNUSED(blk_addr);
// UNUSED(blk_len);
if(HAL_OK != HAL_SD_WriteBlocks(&hsd, (uint8_t *)buf, blk_addr , blk_len, 1000))
{
return USBD_FAIL ;
}
// 循环等待SD卡写入完成,卡内部缓存落地
while(HAL_SD_GetState(&hsd) != HAL_SD_STATE_READY)
{
// 等待写入空闲
}
return (USBD_OK);
/* USER CODE END 7 */
}
/**
* @brief Returns the Max Supported LUNs.
* @param None
* @retval Lun(s) number.
*/
int8_t STORAGE_GetMaxLun_FS(void)
{
/* USER CODE BEGIN 8 */
return (STORAGE_LUN_NBR - 1);
/* USER CODE END 8 */
}
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
/**
* @}
*/
/**
* @}
*/
5.2 main.c 初始化顺序(顺序错误会导致USB/SD卡死)
必须先初始化SDIO,再初始化USB Device。如果顺序颠倒,会出现USB枚举失败或SD卡读写异常。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_SDIO_SD_Init();
MX_FATFS_Init();
MX_FSMC_Init();
MX_USART2_UART_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
SD卡硬件初始化时先初始化为1线,SD初始化指令仅支持 1-bit 单线通信。
static void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 4;
/* USER CODE BEGIN SDIO_Init 2 */
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
/* USER CODE END SDIO_Init 2 */
}
第六章 硬件接线参考
|
功能模块 |
引脚 |
说明 |
|
USB OTG FS |
PA11(DM)、PA12(DP) |
差分线串联22Ω限流电阻,开发板5V自供电 |
|
SDIO 4线TF卡 |
PC8(D0)、PC9(D1)、PC10(D2)、PC11(D3)、PC12(CLK)、PD2(CMD) |
4线高速SD卡模式 |
|
SWD下载 |
PA13(SWDIO)、PA14(SWCLK) |
两线调试下载接口 |
|
调试串口USART2 |
PA2(TX)、PA3(RX) |
接USB转TTL模块,波特率115200 |
第七章 故障排查清单
故障1:电脑插入USB无任何设备弹出
- 核对时钟树PLLQ输出是否精准48MHz
- USB_OTG_FS模式是否为Device_Only,不要开启VBUS检测
- PA11/PA12引脚复用是否正确,D+/D- 22Ω电阻焊接正常
- USB_DEVICE中间件Class是否选择Mass Storage Class,VID=1155 PID=22314
故障2:识别U盘但拷贝报错、提示格式化
- USB MSC参数MSC_MEDIA_PACKET=512,FATFS扇区MAX_SS=512,二者必须完全一致
- SDIO DMA2 Stream3/6是否正常分配,读写函数是否添加阻塞等待完成逻辑
- SD卡硬件接触是否良好,4bit总线模式,SDIO时钟分频系数需要根据SD卡读写速度调整
故障3:USB设备枚举不稳定、频繁断开
- NVIC中断优先级:USB FS中断是否高于SDIO/DMA中断
- 开发板5V电源是否增加1000uF滤波电容,降低供电纹波
- USB数据线是否选用带屏蔽短线,减少干扰
更多推荐

所有评论(0)