STM32与FATFS在SDIO接口SD卡上的协同运行指南

参考文章

STM32CubeMX | SD Card FATFS – 知乎

[STM32F4]基于F407的硬件移植Free RTOS+FATFS(SDIO)_freertos+fatfs-CSDN博客

例程地址:STM32FatFS: 基于stm32的fatfs例程,配合博客文章

基于梁山派天空星开发板,STM32F407VET6

开发板引脚

STM32配置

系统模式配置

输出串口配置

系统时钟配置

这里有个48M的时钟,需要把这里配置成48M,SDIO使用的是系统时钟HCLK,也就是96M,这个需要记住,后面配置SDIO的时候会用到。

SDIO配置

选择4位总线,分频选择4分频,原因点击选项会看到。

SDIO_CK = SDIOCLK / [CLKDIV + 2]. The output clock frequency can vary between 187 KHz and 24 MHz. It is advised to keep the default ClockDiv value (0) to have a maximum SDIO_CK frequency of 24 MHz.

要求SDIO_CK在187 KHz 和 24 MHz之间,我们的系统时钟是96M,分频4,SDIO_CK计算后16M,符合要求。如果有的卡不能识别可以尝试降低频率。

需要开启DMA,因为在FATFS下的SDIO设置中,由于使用了Free RTOS,所以只能选择DMA的方式进行数据处理,且DMA的中断等级要低于SDIO的中断等级,但是在中断系统中0-4的优先级被RTOS占用。

打开SDIO中断

中断优先级调整,将DMA中断调整为7.

配置检测引脚

配置FATFS

使能SD卡,配置简体中文编码,因为资源足够多,可以选择长文件名支持,最大扇区尺寸选择4k。

配置检测引脚

这个引脚会在mount的时候进行判断,如果没有插卡会直接返回错误。

FREERTOS配置

选择V2版本,STM32F103可能需要选择V1版本,任务堆栈使用2048,避免栈溢出导致程序运行错误

长文件名支持,需要增大堆

配置独立c和h文件

代码

CUBEIDE自动生成的代码基本把驱动都实现了,只需要修改一部分内容,我是参考了

[STM32F4]基于F407的硬件移植Free RTOS+FATFS(SDIO)_freertos+fatfs-CSDN博客

文章修改的生成代码

在main.c中添加printf实现的支持函数

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

int __io_putchar(int ch)
{
    /* Implementation of __io_putchar */
	/* e.g. write a character to the UART1 and Loop until the end of transmission */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFFFFFF);

    return ch;
}
int __io_getchar(void)
{
  /* Implementation of __io_getchar */
    char rxChar;

    // This loops in case of HAL timeout, but if an ok or error occurs, we continue
    while (HAL_UART_Receive(&huart1, (uint8_t *)&rxChar, 1, 0xFFFFFFFF) == HAL_TIMEOUT);

    return rxChar;
}
/* USER CODE END 0 */

还需要修改sdio.c源码,当我们挂载磁盘时,一次进入:

f_mount

—–>find_volume

—–>disk_initialize

—–>disk.drv[pdrv]->disk_initialize(disk.lun[pdrv])

—–>BSP_SD_Init;

SD卡在刚上电寻卡获取卡参数等一系列的初始化过程中,是采用单总线模式(SDIO_BUS_WIDE_1B)且时钟频率不超过400K的模式下进行的;但是问题在于初始化完成之后,要调用 HAL_SD_ConfigWideBusOperation 设置为4总线,在这个过程中要获取 SD卡 scr下的内容,此时采用4总线的方式获取不到数据,所以会导致最终的初始化失败!!!

解决方法:所以我们要将初始化配置里的总线模式从 SDIO_BUS_WIDE_4B 改为 SDIO_BUS_WIDE_1B,然后后面在使用 HAL_SD_ConfigWideBusOperation 使能设置为4总线时就没有问题了;

代码修改如下

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 */

}

增加了 hsd.Init.BusWide = SDIO_BUS_WIDE_1B;,也就是在初始化之后将SDIO_BUS_WIDE_4B改为了SDIO_BUS_WIDE_1B

下面是编写freertos的逻辑部分

在freertos.c文件中

添加头文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "fatfs.h"
#include "sdio.h"
#include <stdio.h>
/* USER CODE END Includes */

在默认任务中实现挂载、写入的实现。

/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /*测试SD card FATFS */
  // printf("》SD card FATFS BSP_SD_Init %ld.\r\n", BSP_SD_Init());
  
  // printf("》SD card FATFS HAL_SD_GetCardState %ld.\r\n", HAL_SD_GetCardState(&hsd));

  printf("Compilation Date: %s %s\n", __DATE__, __TIME__);
  // mount SD card
  int retSD = f_mount(&SDFatFS, (TCHAR const *)SDPath, 1);
  if (retSD == FR_OK) {
      printf("》Filesystem mount ok, now you can read/write files.\r\n");
      // 创建或者打开文件 SD_Card_test.txt
      retSD = f_open(&SDFile, "SD_Card_test.txt", FA_OPEN_ALWAYS | FA_WRITE);
      if (retSD == FR_OK) {
          printf("》open/create SD_Card_test.txt OK, write data to it.\r\n");

          // Move to end of the file to append data
          retSD = f_lseek(&SDFile, f_size(&SDFile));
          if (retSD == FR_OK) {
              f_printf(&SDFile, "SD card FATFS test.\r\n");
              printf("》write data to file OK, write bytes: SD card FATFS test.\r\n");
          } else {
              printf("!! File Write error: (%d)\n", retSD);
          }
          /* close file */
          f_close(&SDFile);
      } else {
          printf("!! open/Create file SD_Card_test.txt Fail (%d).\r\n", retSD);
      }
  } else {
      printf("!! SDcard mount filesystem error。(%d)\r\n", retSD);
  }
  // 不带fatfs调试函数
  SDCard_ShowInfo();
  // SDCard_ShowStatus();
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

两个SDIO的测试函数

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/*显示SD卡的信息*/
void SDCard_ShowInfo(void)
{
    // SD卡信息结构体变量
    HAL_SD_CardInfoTypeDef cardInfo;
    HAL_StatusTypeDef res = HAL_SD_GetCardInfo(&hsd, &cardInfo);
    if (res != HAL_OK) {
        printf("HAL_SD_GetCardInfo() error\r\n");
        return;
    }
    printf("\r\n*** HAL_SD_GetCardInfo() info ***\r\n");
    printf("Card Type= %ld\r\n", cardInfo.CardType);
    printf("Card Version= %ld\r\n", cardInfo.CardVersion);
    printf("Card Class= %ld\r\n", cardInfo.Class);
    printf("Relative Card Address= %ld\r\n", cardInfo.RelCardAdd);
    printf("Block Count= %ld\r\n", cardInfo.BlockNbr);
    printf("Block Size(Bytes)= %ld\r\n", cardInfo.BlockSize);
    printf("LogiBlockCount= %ld\r\n", cardInfo.LogBlockNbr);
    printf("LogiBlockSize(Bytes)= %ld\r\n", cardInfo.LogBlockSize);
    printf("SD Card Capacity(MB)= %ld\r\n", cardInfo.BlockNbr >> 1 >> 10);
}
// 获取SD卡当前状态
void SDCard_ShowStatus(void)
{
    // SD卡状态结构体变量
    HAL_SD_CardStatusTypeDef cardStatus;
    HAL_StatusTypeDef res = HAL_SD_GetCardStatus(&hsd, &cardStatus);
    if (res != HAL_OK) {
        printf("HAL_SD_GetCardStatus() error\r\n");
        return;
    }
    printf("\r\n*** HAL_SD_GetCardStatus() info ***\r\n");
    printf("DataBusWidth= %d\r\n", cardStatus.DataBusWidth);
    printf("CardType= %d\r\n", cardStatus.CardType);
    printf("SpeedClass= %d\r\n", cardStatus.SpeedClass);
    printf("AllocationUnitSize= %d\r\n", cardStatus.AllocationUnitSize);
    printf("EraseSize= %d\r\n", cardStatus.EraseSize);
    printf("EraseTimeout= %d\r\n", cardStatus.EraseTimeout);
}
/* USER CODE END Application */

需要自行添加函数文件声明。

运行效果

作者:andylauren

物联沃分享整理
物联沃-IOTWORD物联网 » STM32与FATFS在SDIO接口SD卡上的协同运行指南

发表回复