STM32CubeMX之SD卡+FatFs


参考资料:

  1. 《零死角玩转STM32—F103霸道》
  2. 《STM32F1开发指南(精英版)-HAL库版本_V1.0》

1 STM32CubeMX配置SDIO

在这里插入图片描述
这里参数描述建议将SDIOCLK clock divede factor 参数使用默认值为0,SDIOCLK为48MHz,可以得到最大频率24MHz,但请注意,有些型号的SD卡可能不支持24MHz这么高的频率,所以还是要以实际情况而定。

1.1 SDIO的时钟

SDIO框图在这里插入图片描述从上图中可以看到 SDIO 总共有 3 个时钟,分别是:

  1. 卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输 1 位命令或数据。对于 SD 或 SD I/O 卡,时钟频率可以在 0MHz 至 25MHz间变化。
  2. SDIO 适配器时钟(SDIOCLK):该时钟用于驱动 SDIO 适配器,其频率等于 AHB 总线频率(HCLK),并用于产生 SDIO_CK 时钟。
  3. AHB 总线接口时钟(HCLK/2) :该时钟用于驱动SDIO的AHB总线接口,其频率为HCLK/2。

SD 卡时钟(SDIO_CK),根据卡的不同,可能有好几个区间,这就涉及到时钟频率的设置,SDIO_CK 与 SDIOCLK 的关系为:SDIO_CK=SDIOCLK/(2+CLKDIV)
其中,SDIOCLK 一般是48Mhz(疑问:到底是72MHz还是48MHz,看时钟树是72MHz,但是 SDIOCLK clock divede factor 参数的描述中又是48MHz),而 CLKDIV 则是分频系数,可以通过 SDIO的 SDIO_CLKCR 寄存器进行设置(确保 SDIO_CK 不超过卡的最大操作频率)。
SD 卡初始化的时候,其时钟频率(SDIO_CK)是不能超过 400Khz的,否则可能无法完成初始化。在初始化以后,就可以设置时钟频率到最大了(但不可超过 SD卡的最大操作时钟频率)。这步操作在STM32CubeMX生成的工程中已经做好了,函数SD_Driver.disk_initialize(0) —>BSP_SD_Init —> HAL_SD_Init —> HAL_SD_InitCard
在这里插入图片描述在这里插入图片描述使用400KHz频率初始化完成之后,会重新根据自定义的分频系数重新初始化SDIO,如下函数 BSP_SD_Init —>HAL_SD_ConfigWideBusOperation

HAL_StatusTypeDef HAL_SD_ConfigWideBusOperation(SD_HandleTypeDef *hsd, uint32_t WideMode)
{
    /*省略了很多代码*/
    /* Configure the SDIO peripheral */
    Init.ClockEdge           = hsd->Init.ClockEdge;
    Init.ClockBypass         = hsd->Init.ClockBypass;
    Init.ClockPowerSave      = hsd->Init.ClockPowerSave;
    Init.BusWide             = WideMode;
    Init.HardwareFlowControl = hsd->Init.HardwareFlowControl;
    Init.ClockDiv            = hsd->Init.ClockDiv;  /*这里是自定义的分频系数*/
    (void)SDIO_Init(hsd->Instance, Init);
}

2 STM32CubeMX配置FATFS

在这里插入图片描述
在这里插入图片描述

3 STM32CubeMX配置SD卡检测引脚

  1. 先配置PE4引脚为输入模式(当然选择其他引脚也可以)
    在这里插入图片描述
  2. 选中PE4引脚为检测引脚
    在这里插入图片描述

4 代码分析

4.1 MX_SDIO_SD_Init 函数

main() 函数中找到MX_SDIO_SD_Init(),该函数下
在这里插入图片描述

参数含义如下:

  1. SDIO_ClockEdge:主时钟 SDIOCLK产生 CLK引脚时钟有效沿选择,可选上升沿或下降沿,它设定 SDIO 时钟控制寄存器(SDIO_CLKCR)的 NEGEDGE 位的值,一般选择设置为上升沿。
  2. SDIO_ClockBypass:时钟分频旁路使用,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 BYPASS位。如果使能旁路,SDIOCLK直接驱动 CLK线输出时钟;如果禁用,使用 SDIO_CLKCR 寄存器的 CLKDIV 位值分频 SDIOCLK,然后输出到 CLK线。一般选择禁用时钟分频旁路。
  3. SDIO_ClockPowerSave:节能模式选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 PWRSAV 位的值。如果使能节能模式,CLK线只有在总线激活时才有时钟输出;如果禁用节能模式,始终使能 CLK线输出时钟。
  4. SDIO_BusWide:数据线宽度选择,可选 1 位数据总线、4 位数据总线或 8为数据总线。初始化时系统默认使用 1 位数据总线,初始化SD卡完成之后,会改为 4 位数据总线,操作 SD卡时在数据传输模式下一般选择 4 位数据总线。 它设定 SDIO_CLKCR 寄存器的 WIDBUS位的值。
  5. SDIO_HardwareFlowControl:硬件流控制选择,可选使能或禁用,它设定SDIO_CLKCR 寄存器的 HWFC_EN 位的值。硬件流控制功能可以避免 FIFO 发送上溢和下溢错误。
  6. SDIO_ClockDiv:时钟分频系数,它设定 SDIO_CLKCR 寄存器的 CLKDIV 位的值,设置 SDIOCLK与 CLK线输出时钟分频系数:CLK线时钟频率=SDIOCLK/([CLKDIV+2])。

该函数配置参数后没有给出具体的初始化函数,因为初始化函数其放在了 sd_diskio.c 文件的 DSTATUS SD_initialize(BYTE lun)函数中。在 sd_diskio.c 文件下找到 DSTATUS SD_initialize(BYTE lun) 函数:
在这里插入图片描述
打开 BSP_SD_Init() 函数,工程跳转到 bsp_driver_sd.c 文件,并找到 BSP_SD_Init() 函数,在该函数下初始化SDIO,并将改为4位数据总线。
在这里插入图片描述

4.2 MX_FATFS_Init函数

该函数功能即将SD驱动程序挂载到FATFS
在这里插入图片描述

4.3 SD卡驱动初始化

初始化需要手动在main()函数中添加,如下所示:

int main(void)
{
SD_Driver.disk_initialize(0);
while(1){}
}

进入 SD_Driver.disk_initialize(0);函数,如下:

/**
  * @brief  Initializes a Drive
  * @param  lun : not used 
  * @retval DSTATUS: Operation status
  */
DSTATUS SD_initialize(BYTE lun)
{
  Stat = STA_NOINIT;
  /* Configure the uSD device */
  if(BSP_SD_Init() == MSD_OK)
  {
    Stat &= ~STA_NOINIT;
  }
  return Stat;
}

具体分析SD_initialize函数 中的 BSP_SD_Init()函数分析:
1、检查是否将SD卡插入卡槽,这里使用了PE4引脚作为检测引脚,引脚为低电平表示SD卡已插入
2、SD卡初始化;
3、SD卡初始化成功后,将 1 位数据总线切换成 4 位数据总线;

/**
  * @brief  Initializes the SD card device.
  * @retval SD status
  */
__weak uint8_t BSP_SD_Init(void)
{
  uint8_t sd_state = MSD_OK;
  /* Check if the SD card is plugged in the slot */
  if (BSP_SD_IsDetected() != SD_PRESENT)
  {
    return MSD_ERROR;
  }
  /* HAL SD initialization */
  sd_state = HAL_SD_Init(&hsd);
  /* Configure SD Bus width (4 bits mode selected) */
  if (sd_state == MSD_OK)
  {
    /* Enable wide operation */
    /*初始化时系统默认使用 1 位数据总线,在此切换成 4 位总线*/
    if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
    {
      sd_state = MSD_ERROR;
    }
  }
  return sd_state;
}

具体分析 BSP_SD_Init 函数 中的SD 卡初始化函数HAL_SD_Init(&hsd),如下:
1、初始化GPIO、时钟等;
2、初始化SD卡参数;

/**
  * @brief  Initializes the SD according to the specified parameters in the
            SD_HandleTypeDef and create the associated handle.
  * @param  hsd: Pointer to the SD handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd)
{
  ...
  if(hsd->State == HAL_SD_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hsd->Lock = HAL_UNLOCKED;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)/*需要用户自定义,暂不用该*/
    /* Reset Callback pointers in HAL_SD_STATE_RESET only */
   ...
#else
    /* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
    HAL_SD_MspInit(hsd);   /*先初始化默认值,目的是有些参数没有修改,则使用默认值*/
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
  }
  hsd->State = HAL_SD_STATE_BUSY;  /*将SD卡状态设置为忙*/
  /* Initialize the Card parameters */
  if (HAL_SD_InitCard(hsd) != HAL_OK)
  {
    return HAL_ERROR;
  }
  ...
  return HAL_OK;
}

具体分析HAL_SD_Init函数 中的SD卡初始化参数HAL_SD_InitCard(hsd),如下:
1、使用SDIO外设默认参数初始化SD卡;
重点是参数Init.ClockDiv = SDIO_INIT_CLK_DIV; ,SDIO_CK 引脚的时钟信号在卡识别模式时要求不超过400KHz,

/* SDIO Initialization Frequency (400KHz max) */
#define SDIO_INIT_CLK_DIV     ((uint8_t)0x76)    /* 48MHz / (SDMMC_INIT_CLK_DIV + 2) < 400KHz */

2、使用默认参数初始化SDIO外设接口;
3、给SDIO外设上电,SDIO上电前需要关闭SDIO时钟,SDIO上电后再开启SDIO时钟。
4、SD卡识别和相关 SD 卡状态获取,函数SD_PowerON(hsd)
5、在下面分析

/**
  * @brief  Initializes the SD Card.
  * @param  hsd: Pointer to SD handle
  * @note   This function initializes the SD card. It could be used when a card
            re-initialization is needed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SD_InitCard(SD_HandleTypeDef *hsd)
{
  uint32_t errorstate;
  HAL_StatusTypeDef status;
  SD_InitTypeDef Init;
  
  /* Default SDIO peripheral configuration for SD card initialization */
  Init.ClockEdge           = SDIO_CLOCK_EDGE_RISING;
  Init.ClockBypass         = SDIO_CLOCK_BYPASS_DISABLE;
  Init.ClockPowerSave      = SDIO_CLOCK_POWER_SAVE_DISABLE;
  Init.BusWide             = SDIO_BUS_WIDE_1B;
  Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  Init.ClockDiv            = SDIO_INIT_CLK_DIV;

  /* Initialize SDIO peripheral interface with default configuration */
  status = SDIO_Init(hsd->Instance, Init);
  if(status != HAL_OK)
  {
    return HAL_ERROR;
  }

  /* Disable SDIO Clock */
  __HAL_SD_DISABLE(hsd);

  /* Set Power State to ON */
  (void)SDIO_PowerState_ON(hsd->Instance);

  /* Enable SDIO Clock */
  __HAL_SD_ENABLE(hsd);

  /* Identify card operating voltage */
  errorstate = SD_PowerON(hsd);
  if(errorstate != HAL_SD_ERROR_NONE)
  {
    hsd->State = HAL_SD_STATE_READY;
    hsd->ErrorCode |= errorstate;
    return HAL_ERROR;
  }

  /* Card initialization */
  errorstate = SD_InitCard(hsd);
  if(errorstate != HAL_SD_ERROR_NONE)
  {
    hsd->State = HAL_SD_STATE_READY;
    hsd->ErrorCode |= errorstate;
    return HAL_ERROR;
  }

  return HAL_OK;
}

具体分析HAL_SD_InitCard函数中的 SD_PowerON(hsd)函数:
注意:ACMD41是应用特定命令,发送该命令之前必须先发 CMD55
根据下图进行初始化
在这里插入图片描述

/**
  * @brief  Enquires cards about their operating voltage and configures clock
  *         controls and stores SD information that will be needed in future
  *         in the SD handle.
  * @param  hsd: Pointer to SD handle
  * @retval error state
  */
static uint32_t SD_PowerON(SD_HandleTypeDef *hsd)
{
  __IO uint32_t count = 0U;
  uint32_t response = 0U, validvoltage = 0U;
  uint32_t errorstate;

  /* CMD0: GO_IDLE_STATE */
  errorstate = SDMMC_CmdGoIdleState(hsd->Instance);
  if(errorstate != HAL_SD_ERROR_NONE)
  {
    return errorstate;
  }

  /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
  errorstate = SDMMC_CmdOperCond(hsd->Instance);
  if(errorstate != HAL_SD_ERROR_NONE)
  {
    hsd->SdCard.CardVersion = CARD_V1_X;
    /* CMD0: GO_IDLE_STATE */
    errorstate = SDMMC_CmdGoIdleState(hsd->Instance);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return errorstate;
    }
  }
  else
  {
    hsd->SdCard.CardVersion = CARD_V2_X;
  }

  if( hsd->SdCard.CardVersion == CARD_V2_X)
  {
    /* SEND CMD55 APP_CMD with RCA as 0 */
    errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
    }
  }
  /* SD CARD */
  /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
  while((count < SDMMC_MAX_VOLT_TRIAL) && (validvoltage == 0U))
  {
    /* SEND CMD55 APP_CMD with RCA as 0 */
    errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return errorstate;
    }

    /* Send CMD41 */
    errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
    }

    /* Get command response */
    response = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);

    /* Get operating voltage*/
    validvoltage = (((response >> 31U) == 1U) ? 1U : 0U);

    count++;
  }

  if(count >= SDMMC_MAX_VOLT_TRIAL)
  {
    return HAL_SD_ERROR_INVALID_VOLTRANGE;
  }

  if((response & SDMMC_HIGH_CAPACITY) == SDMMC_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */
  {
    hsd->SdCard.CardType = CARD_SDHC_SDXC;
  }
  else
  {
    hsd->SdCard.CardType = CARD_SDSC;
  }
  return HAL_SD_ERROR_NONE;
}

具体分析HAL_SD_InitCard函数 中的SD_InitCard(hsd),获取SD卡寄存器相关信息,具体如下:
1、检测SDIO上电状态;
2、发送CMD2指令,获取SD卡CID信息;
3、设置RCA;
4、发送CMD3指令,获取SD卡CSD信息;
5、配置卡其他信息;
6、重新初始化SDIO;
SD卡相关寄存器:
在这里插入图片描述

/**
  * @brief  Initializes the sd card.
  * @param  hsd: Pointer to SD handle
  * @retval SD Card error state
  */
static uint32_t SD_InitCard(SD_HandleTypeDef *hsd)
{
  HAL_SD_CardCSDTypeDef CSD;
  uint32_t errorstate;
  uint16_t sd_rca = 1U;

  /* Check the power State */
  if(SDIO_GetPowerState(hsd->Instance) == 0U)
  {
    /* Power off */
    return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
  }

  if(hsd->SdCard.CardType != CARD_SECURED)
  {
    /* Send CMD2 ALL_SEND_CID */
    errorstate = SDMMC_CmdSendCID(hsd->Instance);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return errorstate;
    }
    else
    {
      /* Get Card identification number data */
      hsd->CID[0U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
      hsd->CID[1U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2);
      hsd->CID[2U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3);
      hsd->CID[3U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4);
    }
  }

  if(hsd->SdCard.CardType != CARD_SECURED)
  {
    /* Send CMD3 SET_REL_ADDR with argument 0 */
    /* SD Card publishes its RCA. */
    errorstate = SDMMC_CmdSetRelAdd(hsd->Instance, &sd_rca);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return errorstate;
    }
  }
  if(hsd->SdCard.CardType != CARD_SECURED)
  {
    /* Get the SD card RCA */
    hsd->SdCard.RelCardAdd = sd_rca;

    /* Send CMD9 SEND_CSD with argument as card's RCA */
    errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      return errorstate;
    }
    else
    {
      /* Get Card Specific Data */
      hsd->CSD[0U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
      hsd->CSD[1U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2);
      hsd->CSD[2U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3);
      hsd->CSD[3U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4);
    }
  }

  /* Get the Card Class */
  hsd->SdCard.Class = (SDIO_GetResponse(hsd->Instance, SDIO_RESP2) >> 20U);

  /* Get CSD parameters */
  if (HAL_SD_GetCardCSD(hsd, &CSD) != HAL_OK)
  {
    return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
  }

  /* Select the Card */
  errorstate = SDMMC_CmdSelDesel(hsd->Instance, (uint32_t)(((uint32_t)hsd->SdCard.RelCardAdd) << 16U));
  if(errorstate != HAL_SD_ERROR_NONE)
  {
    return errorstate;
  }

  /* Configure SDIO peripheral interface */
  (void)SDIO_Init(hsd->Instance, hsd->Init);

  /* All cards are initialized */
  return HAL_SD_ERROR_NONE;
}

至此,SD卡初始化完成。

5 打印SD卡初始化信息

开发板上PE4引脚需要拉低
初始化并打印SD卡信息:

HAL_SD_CardInfoTypeDef  SDCardInfo;           
SD_HandleTypeDef hsd;
static void printf_sdcard_info(void);

int main(void)
{
  MX_SDIO_SD_Init();
  MX_FATFS_Init();
  SD_Driver.disk_initialize(0);
  printf_sdcard_info();
  while(1);
}
void printf_sdcard_info(void)
{
	uint64_t CardCap;      	//SD卡容量
	HAL_SD_CardCIDTypeDef SDCard_CID; 

	HAL_SD_GetCardCID(&hsd,&SDCard_CID);	//获取CID
	HAL_SD_GetCardInfo(&hsd,&SDCardInfo);                    //获取SD卡信息
	CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize);	//计算SD卡容量
	switch(SDCardInfo.CardType)
	{
		case CARD_SDSC:
		{
			if(SDCardInfo.CardVersion == CARD_V1_X)
				printf("Card Type:SDSC V1\r\n");
			else if(SDCardInfo.CardVersion == CARD_V2_X)
				printf("Card Type:SDSC V2\r\n");
		}
		break;
		case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
		default:break;
	}	
		
    printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID);				//制造商ID	
 	printf("CardVersion:         %d \r\n",(uint32_t)(SDCardInfo.CardVersion));		//卡版本号
	printf("Class:               %d \r\n",(uint32_t)(SDCardInfo.Class));		    //
 	printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd);					//卡相对地址
	printf("Card BlockNbr:       %d \r\n",SDCardInfo.BlockNbr);						//块数量
 	printf("Card BlockSize:      %d \r\n",SDCardInfo.BlockSize);					//块大小
	printf("LogBlockNbr:         %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr));		//逻辑块数量
	printf("LogBlockSize:        %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize));		//逻辑块大小
	printf("Card Capacity:       %d MB\r\n",(uint32_t)(CardCap>>20));				//卡容量
}

串口打印的SD卡信息:
在这里插入图片描述从上图中可以得到如下信息:

  1. 该SD卡总容量为7616MB;
  2. 一共15597568个扇区,每个扇区大小为512个字节,注意每次读写最小单位都是一个扇区;

6 SD卡读写测试

要实现内容:向扇区地址为20的地方写入超过512个字节但小于1024个字节的数据,所以该内容占用了2个扇区,并将该数据读出来

	sd_datus = SD_Driver.disk_write(0,"President will take part in the Global Health Summit on Friday via video link from Beijing,\
 joining leaders of the Group of 20 members and heads of international and regional organizations in efforts to boost global cooperation in\
 the fight against the COVID-19 pandemic.Xi will deliver a speech at the event, which will take place at Villa Pamphilj in Rome. The summit\
 was organized by Italy,the holder of the G20 presidency, in partnership with the European Commission.Speaking at a news conference on Thursday,\
 Foreign Ministry spokesman Zhao Lijian said China expects the summit to send a strong message to uphold multilateralism and enhance solidarity\
 and cooperation in the global fight against the pandemic.As COVID-19 is making a resurgence and spreading globally, Zhao said international\
 cooperation in combating the virus is at a critical juncture.",20,2);
 
	printf("sd write result:%d\r\n",sd_datus);
	sd_datus = SD_Driver.disk_read(0,sd_buf,20,2);
	printf("sd reak result:%d\r\n",sd_datus);
	printf("sd read content:\r\n%s\r\n",sd_buf);

串口调试助手输出信息如下:
在这里插入图片描述

7 工程链接

gitee平台: STM32F10xxx Learn

  • 22
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
STM32CubeMX是一个用于配置STM32微控制器的图形化工具。它可以帮助我们快速配置SD卡、DMA和FATFS文件系统。 在开始配置之前,我们需要先连接SD卡STM32微控制器,并确保正确配置了SD卡的GPIO引脚,使其与STM32SDIO接口连接。 首先,打开STM32CubeMX并选择相应的微控制器型号。然后,点击"Pinout & Configuration"选项卡,在左侧的"Peripherals"下选择SDIO,然后在右侧选择SDIO的引脚和模式。确保使能SDIO的时钟和数据信号引脚,并选择正确的模式,如4线模式。 接下来,点击"Middleware"选项卡,在右侧的"STemWin"下选择"FATFS"。然后,在"FATFs 1"下选择"SDIO"作为SD卡的字节访问连接器,并在"Volume1 size"中指定SD卡的容量。 再次点击"Middleware"选项卡,在右侧的"FATFS"下选择"DMA",以启用DMA传输。在"Mode"中选择"POLLING" 或"DMA"作为传输模式,并选择一个可用的DMA通道,例如DMA2-Stream3。 最后,点击"Project"选项卡,在右侧的"Project Name"下输入项目名称,然后点击"Save"按钮保存配置。 现在,我们已经完成了STM32CubeMX的配置。生成代码并导入到我们的IDE中,例如Keil或者STM32CubeIDE。 在代码中,我们需要初始化SDIO和DMA,并创建FATFS实例,在主循环中使用FATFS函数完成SD卡的读写操作。我们可以使用FATFS提供的函数来打开、写入、读取和关闭文件,以及创建、删除和重命名目录。 这就是使用STM32CubeMX配置SD卡、DMA和FATFS的步骤。通过使用STM32CubeMX,我们可以快速而方便地配置SD卡、DMA和FATFS,从而实现SD卡的读写操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值