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

