You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

最新版CubeIDE下STM32F407 SDIO接口SD卡挂载失败问题

STM32F407VG Discovery SDIO接SD卡挂载失败问题

问题背景

  • 硬件平台:STM32F407VG Discovery开发板
  • 实现目标:通过板载SDIO接口外接SD卡,移植FatFs文件系统实现数据存储
  • 故障现象:参考公开开发教程严格按步骤操作后功能异常,代码烧录后红色LED常亮,调试确认f_mount函数返回值不等于FR_OK,SD卡挂载失败,已逐一排查硬件接线确认连接无误。

故障代码

#include "main.h"
#include "fatfs.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SD_HandleTypeDef hsd;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SDIO_SD_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
FATFS myFatFS;
FIL myFile;
UINT myBytes;
/* USER CODE END 0 */

/**
  * @brief  应用入口函数
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU配置--------------------------------------------------------*/

  /* 复位所有外设,初始化Flash接口和Systick */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* 配置系统时钟 */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* 初始化所有已配置外设 */
  MX_GPIO_Init();
  MX_SDIO_SD_Init();
  MX_FATFS_Init();
  /* USER CODE BEGIN 2 */
  if(f_mount(&myFatFS,SDPath,1) == FR_OK)
   {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);//绿色LED
        char myFileName[] = "TEST1.txt";
        if (f_open(&myFile, myFileName, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK)
            {
                HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);//橙色LED
                char myData[] = "Hello from STM32F4 Disco, SDIO in 4 bits mode";
                if (f_write(&myFile, myData, sizeof(myData), &myBytes))
                    {
                                HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);//蓝色LED

                    }
                    f_close(&myFile);
            }
   }
   else
  {
                                HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);//红色LED

  }
  /* USER CODE END 2 */

  /* 无限循环 */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief 系统时钟配置函数
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 配置主内部稳压器输出电压
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** 按照RCC_OscInitTypeDef结构体指定参数初始化RCC振荡器
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 192;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** 初始化CPU、AHB和APB总线时钟
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SDIO初始化函数
  * @param None
  * @retval None
  */
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_1B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0;
  /* USER CODE BEGIN SDIO_Init 2 */

  /* USER CODE END SDIO_Init 2 */

}

/**
  * @brief GPIO初始化函数
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* 使能GPIO端口时钟 */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* 配置GPIO引脚输出电平 */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /* 配置GPIO引脚 : PD12 */
  GPIO_InitStruct.Pin = GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* 配置GPIO引脚 : PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  错误发生时执行的函数
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* 用户可自行添加实现以上报HAL错误返回状态 */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  上报参数断言错误所在的源文件名和行号
  * @param  file: 指向源文件名的指针
  * @param  line: 断言错误所在的行号
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* 用户可自行添加上报文件名和行号的实现,
     例: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

根因定位

代码存在6处直接导致挂载失败的问题:

  1. SDIO初始化流程缺失:MX_SDIO_SD_Init仅给SDIO句柄结构体赋值,未调用HAL_SD_Init(&hsd)完成SDIO外设使能、SD卡上电识别流程,FatFs底层驱动无法访问SD卡硬件,挂载必然失败。
  2. 系统时钟配置错误:PLL参数配置完成后,系统时钟源仍选择内部16MHz HSI,未切换到PLL输出,SDIO所在的APB2总线时钟不符合SD卡通信要求;SDIO初始化分频值设为0,初始通信速率远超过SD卡识别阶段要求的400kHz上限,卡识别流程直接失败。
  3. SDIO引脚未初始化:GPIO初始化函数仅配置了4个LED引脚,SDIO通信必需的PC8(D0)、PC9(D1)、PC10(D2)、PC11(D3)、PC12(CLK)、PD2(CMD)引脚未配置为SDIO复用功能模式,SDIO外设无法连接到物理引脚。
  4. LED引脚配置错误:绿色LED对应的PD12引脚被配置为模拟输入模式,即使挂载成功也无法点亮。
  5. 逻辑判断写反:f_write函数返回FR_OK(值为0)才代表写入成功,现有逻辑在写入失败(返回非0值)时点亮蓝色LED,状态指示完全错误。
  6. 总线宽度配置不匹配:代码注释标注使用4位SDIO模式,但初始化时仅配置为1位模式,且未在卡识别完成后调用总线宽度切换接口,后续4位模式通信会直接失败。

修复方案

按以下顺序修改代码即可解决挂载问题:

  • 补全SDIO初始化逻辑:在MX_SDIO_SD_Init末尾调用HAL_SD_Init(&hsd),确认工程已加入适配STM32F4的SDIO底层驱动文件,实现FatFs要求的块设备读写、控制接口。
  • 修正时钟配置:将系统时钟源切换为PLL输出,配置主频为168MHz,APB2分频系数设为2得到84MHz总线时钟;SDIO初始化阶段将分频值设为255以上,保证初始通信速率低于400kHz,卡识别完成后再提高时钟速率;按主频要求配置Flash等待周期为5WS。
  • 补全SDIO引脚配置:将PC8~PC12、PD2引脚配置为复用推挽输出模式,复用功能选择AF12(SDIO),引脚速度设为高速,配置上拉电阻。
  • 修正LED配置:将PD12引脚改为通用推挽输出模式,和其余三个LED引脚配置一致。
  • 修正状态判断逻辑:所有FatFs接口调用后,仅当返回值等于FR_OK时才点亮对应成功状态的LED。
  • 若需使用4位SDIO模式,在SD卡初始化完成后调用HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)切换总线宽度,再执行文件系统挂载操作。

内容的提问来源于stack exchange,提问作者Arseniy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:39:09