目录

第一章 系统内核外设配置(基础硬件层)

1.1 DMA SDIO收发通道配置

1.2 GPIO复用全局参数配置

1.3 NVIC中断优先级分配配置

1.4 RCC外部高速晶振时钟配置

1.5 SYS调试与时基配置

第二章 硬件外设专项配置

2.1 FSMC外部SRAM备用配置

2.2 SDIO 4线SD卡硬件配置

2.3 USART2调试串口配置

2.4 USB_OTG_FS全速USB设备模式配置

第三章 Middleware中间件完整配置

3.1 USB_DEVICE MSC大容量存储基础参数

3.2 USB_DEVICE 设备描述符VID/PID配置

3.3 USB_DEVICE 用户常量标签页

3.4 FATFS 文件系统功能宏定义配置

3.5 FATFS 物理磁盘扇区参数配置

3.6 FATFS SDIO硬件DMA绑定配置

3.7 FATFS 平台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%以上),必须严格核对以下参数。

时钟树强制校验项

  1. HSE = 8MHz,PLLM = 8,PLLN = 336,PLLP = 2 → SYSCLK = 168MHz
  1. PLLQ = 7 → USB48CK = 48MHz(USB标准时钟,偏差±0.5M即无法枚举设备)
  1. APB1预分频 = 4(APB1最大42M,SDIO挂载APB1总线)
  1. 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数据线是否选用带屏蔽短线,减少干扰
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐