STM32CubeMX教程27 SDIO - 读写SD卡

这篇具有很好参考价值的文章主要介绍了STM32CubeMX教程27 SDIO - 读写SD卡。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、准备材料

正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0)

keil µVision5 IDE(MDK-Arm)

ST-LINK/V2驱动

逻辑分析仪nanoDLA

野火DAP仿真器

XCOM V2.6串口助手

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板SDIO读写4线SD卡,实现轮询方式读写SD卡、以中断方式读取SD卡和以DMA方式读取SD卡

3、轮询方式读取SD卡流程

3.0、前提知识

安全数码卡(Secure Digital Memory Card),简称SD卡,是嵌入式设备上常用的一种存储介质,通常可以将SD卡分为标准SD卡、miniSD卡和microSD卡(TF卡)三种类型,每种卡形状大小不一,除标准SD卡卡身上拥有一个写保护开关外,其他的功能三张卡一致,如今miniSD卡正逐渐被microSD卡所取代,如下图所示为三种不同类型SD卡形状 (注释1)

按照SD卡容量大小的不同可以将其分为SD、SDHC、SDXC等型号,按照SD卡读写机制速度的不同又可以将其分为Standard、High-speed、UHS-I等型号,具体如下表所示

STM32F407提供了一个SDIO接口可以直接通过HAL库来驱动1/4位总线宽度的SD卡或1/4/8位总线宽度的多媒体卡,其完全兼容SD卡规范版本2.0,但只支持高速SD卡,也即与SD卡进行数据传输最大速度为25MHz

SDIO由APB2接口和SDIO适配器两部分组成,SDIO适配器提供了驱动SD/MMC卡的全部功能,APB2接口则可以访问SDIO适配器寄存器在适当时候向内核发起中断/DMA请求

SDIO适配器由48MHz的SDIOCLK驱动,根据SDIOCLK时钟频率、 SDIO Clock divider bypass 参数和 SDIOCLK clock divide factor 参数就可以确定与SD卡通信时SDIO_CLK的时钟频率,当时钟分频器旁路使能时,SDIO_CLK=SDIOCLK;当时钟分频器旁路不使能时,SDIO_CLK=SDIOCLK / (2+时钟分频因子);

根据上面的描述,由于STM32F407的SDIO只支持高速SD卡,因此时钟分频器旁路常常不使能,这样当时钟分频因子为0时,SDIO_CLK则达到最大速度48MHz / 2 = 24Mhz,但在实际的使用中往往稍微降低该时钟频率,否则可能会出现读写SD卡失败的现象

另外值得提醒的是SD卡初始化的时候应该以不超过400KHz的速率,1位总线宽度进行初始化,否则将初始化失败

如下图所示为STM32F407内部的SDIO接口结构框图 (注释2)

笔者使用的开发板上SD卡槽设计为了4位总线宽度,在硬件设计时需要注意MCU与SD卡通信的1/4根数据线SDIO_D0/1/2/3和命令线SDIO_CMD均需外部上拉,硬件原理图如下图所示

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示

开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示

详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立”

3.1.1、时钟树配置

当在STM32CubeMX中启用SDIO功能后,时钟树中48MHz时钟便可以进行调节,该时钟一般如其名字一样配置为48MHz即可,也即将Main PLL(主锁相环)的Q参数调节为7即可,其他HCLK、PCLK1和PCLK2时钟仍然设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

本实验需要初始化开发板上WK_UP、KEY2、KEY1和KEY0用户按键,具体配置步骤请阅读“STM32CubeMX教程3 GPIO输入 - 按键响应”

本实验需要初始化USART1作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信”

单击Pinout & Configuration页面左边功能分类栏目Connectivity/SDIO,将其模式选择为4位宽总线SD卡

Clock transition on which the bit capture is made (时钟跳变沿捕获数据配置):数据捕获边沿设置,可设置为上升沿/下降沿

SDIO Clock divider bypass (时钟分频器旁路使能):使能该参数时,SDIO_CLK=SDIOCLK;否则SDIO_CLK频率由时钟分频因子决定

SDIO Clock output enable when the bus is idle (空闲模式时钟输出使能):节能模式,此实验不使能

SDIO hardware flow control (硬件流控):设置是否使能SDIO的硬件流控,此处不使能

SDIOCLK clock divide factor (时钟分频因子):当不使能时钟分频器旁路时,SDIO_CLK=SDIOCLK / (2+时钟分频因子)

SDIO驱动4位宽总线SD卡的参数配置大多按照默认参数配置即可,但是要注意SD卡读写频率过高可能会导致读写失败,因此这里设置SD_CLK频率为8MHz,另外需要注意默认的SDIO复用引脚和开发板上的实际控制SD的引脚是否一致,具体配置如下图所示

3.1.3、外设中断配置

轮询方式读写SD卡无需配置中断

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示

详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、外设初始化调用流程

在main.c文件main()函数中调用MX_SDIO_SD_Init()对SDIO参数配置,并调用HAL_SD_Init()函数对SD卡初始化,最后将SD卡切换到4位宽总线模式

在stm32f4xx_hal_sd.c文件HAL_SD_Init()中调用HAL_SD_MspInit()函数对SDIO时钟使能和所使用到的引脚功能复用,如果配置了中断或DMA,该函数中还会相应的出现NVIC/DMA相关配置,最后在真正的SD卡初始化函数HAL_SD_InitCard()中对SD卡初始化完毕

具体外设初始化函数调用流程如下图所示

初始化配置中时钟分频因子为4,SD_CLK=8MHz,为什么SD卡还可以初始化成功?

这里读者需要搞清楚真正对SD卡初始化时使用的参数配置是不是我们设置的参数,上面提到真正的SD卡初始化函数为HAL_SD_InitCard(),进入该函数发现实际初始化SD卡时用到的并不是用户配置的参数,而是使用的默认初始化参数,这里时钟分频因子被设置为了0x76,也即118,根据上面提到的公式计算可知48MHz / (118 + 2) = 400KHz,满足SD卡的初始化频率,具体如下图所示

3.2.2、外设中断调用流程

轮询方式读写SD卡无配置中断

3.2.3、添加其他必要代码

笔者使用的STM32CubeMX版本为6.10.0,在生成的SDIO初始化函数MX_SDIO_SD_Init()中需要将参数配置中的SD卡数据总线宽度从默认的4位手动修改为1位(STM32CubeMX软件BUG?),在SD卡初始化时应该以不超过400KHz的速率,1位总线宽度进行初始化,如果不修改这里SD卡将无法成功初始化,如下图所示

在sdio.c中添加SD卡读、写、擦除和输出SD卡信息测试函数

/*显示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= %d\r\n", cardInfo.CardType);
	printf("Card Version= %d\r\n", cardInfo.CardVersion);
	printf("Card Class= %d\r\n", cardInfo.Class);
	printf("Relative Card Address= %d\r\n", cardInfo.RelCardAdd);
	printf("Block Count= %d\r\n", cardInfo.BlockNbr);
	printf("Block Size(Bytes)= %d\r\n", cardInfo.BlockSize);
	printf("LogiBlockCount= %d\r\n", cardInfo.LogBlockNbr);
	printf("LogiBlockSize(Bytes)= %d\r\n", cardInfo.LogBlockSize);
	printf("SD Card Capacity(MB)= %d\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);
}

/*SD卡擦除测试*/
void SDCard_EraseBlocks(void)
{
	uint32_t BlockAddrStart=0;
	uint32_t BlockAddrEnd=10;
	
	printf("\r\n*** Erasing blocks ***\r\n");

	if(HAL_SD_Erase(&hsd, BlockAddrStart, BlockAddrEnd)==HAL_OK)
		printf("Erasing blocks,OK\r\n");
	else
		printf("Erasing blocks,fail\r\n");

	HAL_SD_CardStateTypeDef cardState=HAL_SD_GetCardState(&hsd);
	printf("GetCardState()= %d\r\n", cardState);

	while(cardState != HAL_SD_CARD_TRANSFER)
	{
		HAL_Delay(1);
		cardState=HAL_SD_GetCardState(&hsd);
	}
	printf("Blocks 0-10 is erased.\r\n");
}

/*SD卡写入测试函数*/
void SDCard_TestWrite(void)
{
	printf("\r\n*** Writing blocks ***\r\n");
	
	// BLOCKSIZE为512,在stm32f4xx_hal_sd.h中被定义
	uint8_t pData[BLOCKSIZE]="Hello, welcome to UPC\0";  
	uint32_t BlockAddr=5; 	
	uint32_t BlockCount=1; 
	uint32_t TimeOut=1000;	

	if(HAL_SD_WriteBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK)
	{
		printf("Write to block 5, OK\r\n");
		printf("The string is: %s\r\n", pData);
	}
	else
	{
		printf("Write to block 5, fail ***\r\n");
		return;
	}

	for(uint16_t i=0;i<BLOCKSIZE; i++)
		pData[i]=i; 	

	BlockAddr=6;
	if(HAL_SD_WriteBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK) 
	{
		printf("Write block 6, OK\r\n");
		printf("Data in [10:15] is: ");
		for (uint16_t j=11; j<=15;j++)
		{
			printf("%d,", pData[j]);
		}
		printf("\r\n");
	}
	else
		printf("Write to block 6, fail ***\r\n");
}

/*SD卡读取测试函数*/
void SDCard_TestRead(void)	
{
	printf("\r\n*** Reading blocks ***\r\n");

	uint8_t pData[BLOCKSIZE];
	uint32_t BlockAddr=5;
	uint32_t BlockCount=1;
	uint32_t TimeOut=1000;

	if(HAL_SD_ReadBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK)
	//if(HAL_SD_ReadBlocks_IT(&hsd,pData,BlockAddr,BlockCount) == HAL_OK)
	{
		printf("Read block 5, OK\r\n");
		printf("The string is: %s\r\n", pData);
	}
	else
	{
		printf("Read block 5, fail ***\r\n");
		return;
	}

	BlockAddr=6;
	if(HAL_SD_ReadBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut)== HAL_OK)
	//if(HAL_SD_ReadBlocks_IT(&hsd,pData,BlockAddr,BlockCount) == HAL_OK)
	{
		printf("Read block 6, OK\r\n");
		printf("Data in [10:15] is: ");

		for (uint16_t j=11; j<=15;j++)
		{
			printf("%d,", pData[j]);
		}
		printf("\r\n");
	}
}

在sdio.h中声明定义的这些测试函数

/*在sdio.h中声明*/
void SDCard_TestRead(void);
void SDCard_TestWrite(void);
void SDCard_ShowInfo(void);
void SDCard_EraseBlocks(void);

在main.c文件主循环中添加按键逻辑控制程序,WK_UP按键按下输出SD卡信息,KEY2按键按下擦除SD卡块0-10,KEY1按键按下测试SD卡写功能,KEY0按键按下测试SD卡读功能

具体源代码如下所示

/*WK_UP按键按下*/
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
{
	HAL_Delay(50);
	if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
	{
		SDCard_ShowInfo();
		while(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin));
	}
}

/*KEY2按键按下*/
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
	HAL_Delay(50);
	if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
	{
		SDCard_EraseBlocks();
		while(!HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin));
	}
}

/*KEY1按键按下*/
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
	HAL_Delay(50);
	if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
	{
		SDCard_TestWrite();
		while(!HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin));
	}
}

/*KEY0按键按下*/
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
{
	HAL_Delay(50);
	if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
	{
		SDCard_TestRead();
		while(!HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin));
	}
}

4、烧录验证

烧录程序,开发板复位后按下WK_UP按键会输出SD卡信息,按下KEY2按键会擦除SD卡的块0-10数据,按下KEY0按键会读取SD卡块5和块6的数据,按下KEY1按键会写入一段字符串到SD卡块5,写入块6从1-256整形数字,具体串口输出信息如下图所示

5、中断方式读取SD卡流程简述

5.1、CubeMX相关配置

工程、时钟树、外设参数等配置与轮询方式读取SD卡一致,中断方式读取SD卡只需要在CubeMX软件中启动SDIO的全局中断

在Pinout & Configuration页面左边System Core/NVIC中勾选SDIO全局中断,然后选择合适的中断优先级即可,如下图所示

5.2、生成代码

修改STM32CubeMX工程重新生成工程代码后,读者应注意再次手动修改MX_SDIO_SD_Init()函数中SD卡数据总线宽度从默认的4位手动修改为1位

在sdio.c中增加以中断方式读写SD卡的测试函数,具体代码如下所示

/*SD卡中断写入测试函数*/
void SDCard_TestWrite_IT(void)
{
	printf("\r\n*** IT Writing blocks ***\r\n");
	uint32_t BlockCount=1; 
	uint16_t BlockAddr=5;
	
	HAL_SD_WriteBlocks_IT(&hsd, TX, BlockAddr, BlockCount);
}

/*SD卡中断读取测试函数*/
void SDCard_TestRead_IT(void)	
{
	printf("\r\n*** IT Reading blocks ***\r\n");
	uint32_t BlockCount=1;
	uint16_t BlockAddr=5;
	
	HAL_SD_ReadBlocks_IT(&hsd, RX, BlockAddr, BlockCount);
}

在sdio.c中新增加SD卡Tx/Rx传输完成回调函数HAL_SD_TxCpltCallback()和HAL_SD_RxCpltCallback(),具体代码如下所示

/*SD Tx传输完成回调*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
	printf("IT Write to block 5, OK\r\n");
	printf("The string is: %s\r\n", TX);
}

/*SD Rx传输完成回调*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
	printf("IT Read block 5, OK\r\n");
	printf("The string is: %s\r\n", RX);
}

在sdio.c中定义全部变量发送缓存数组TX和接收缓存数组RX,并在sdio.h中声明修改后的中断方式的SD卡写入测试函数和SD卡读取测试函数,源代码如下

/*sdio.c中定义的发送、接收缓存数组*/
uint8_t TX[BLOCKSIZE] = "Hello, welcome to UPC\0";  
uint8_t RX[BLOCKSIZE];  

/*sdio.h中对函数声明*/
void SDCard_TestRead_IT(void);
void SDCard_TestWrite_IT(void);

最后在main.c文件主循环中实现与轮询读写SD时一致的按键逻辑程序,并用修改后的以中断方式读写SD卡的函数替换以轮询方式读写SD卡的函数即可

5.3、烧录验证

烧录程序,开发板复位后按下WK_UP按键会输出SD卡信息,按下KEY2按键会擦除SD卡的块0-10数据,与轮询方式读写SD卡时现象一致

按下KEY0按键以中断方式读取SD卡的块5数据,读取完成后会进入Rx传输完成回调中,在该回调函数中会从串口输出读取到的SD卡块5的数据

按下KEY1按键会以中断方式写入一段字符串到SD卡块5,写入完成后会进入Tx传输完成回调中,在该回调函数中会从串口输出写入到SD卡块5中的数据

具体串口输出信息如下图所示

6、DMA方式读取SD卡流程简述

6.1、CubeMX相关配置

工程、时钟树、外设参数等配置与轮询方式读取SD卡一致,以DMA方式读取SD卡只需要在CubeMX软件中增加SDIO的DMA请求即可

在Pinout & Configuration页面单击Connectivity/SDIO页面,在Configuration配置页面中点击DMA Settings选项卡对SDIO的DMA进行配置,单击ADD增加SDIO的RX/TX两个DMA请求,SDIO的两个DMA请求除了内存地址递增可以设置外,其他的包括Mode、Use Fifo、Data Width和Burst Size等参数都不可以设置

对DMA参数不理解的可以阅读”STM32CubeMX教程12 DMA 直接内存读取“实验,SDIO的具体DMA配置参数如下图所示

在System Core/NVIC中勾选SDIO全局中断、DMA2 stream3 全局中断和 DMA2 stream6 全局中断,然后选择合适的中断优先级即可,如下图所示

6.2、生成代码

修改STM32CubeMX工程重新生成工程代码后,读者应注意再次手动修改MX_SDIO_SD_Init()函数中SD卡数据总线宽度从默认的4位手动修改为1位

在sdio.c中增加以DMA方式读写SD卡的测试函数,具体代码如下所示

/*SD卡DMA写入测试函数*/
void SDCard_TestWrite_DMA(void)
{
	printf("\r\n*** DMA Writing blocks ***\r\n");
	uint32_t BlockCount=1; 
	uint16_t BlockAddr=6;
	
	for(uint16_t i=0;i<BLOCKSIZE; i++)
		TX[i]=i; 
	
	HAL_SD_WriteBlocks_DMA(&hsd, TX, BlockAddr, BlockCount);
}

/*SD卡DMA读取测试函数*/
void SDCard_TestRead_DMA(void)	
{
	printf("\r\n*** DMA Reading blocks ***\r\n");
	uint32_t BlockCount=1;
	uint16_t BlockAddr=6;
	
	HAL_SD_ReadBlocks_DMA(&hsd, RX, BlockAddr, BlockCount);
}

在sdio.h中对增加的函数声明

/*sdio.h中对函数声明*/
void SDCard_TestWrite_DMA(void);
void SDCard_TestRead_DMA(void);

DMA的回调函数使用的是外设的中断回调函数

当启用了SDIO TX DMA请求和SDIO全局中断,并以 HAL_SD_WriteBlocks_DMA() 写入SD卡块数据完成之后,会调用传输完成回调 HAL_SD_TxCpltCallback()

当启用了SDIO RX DMA请求和SDIO全局中断,并以 HAL_SD_ReadBlocks_DMA() 从SD卡块读取数据完毕之后,会调用读取完成回调函数 HAL_SD_RxCpltCallback()

故直接重新实现HAL_SD_RxCpltCallback/HAL_SD_TxCpltCallback两个函数即可,源代码如下所示

/*DMA Tx传输完成回调*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
		printf("DMA Write to block 6, OK\r\n");
		printf("Data in [10:15] is: ");

		for (uint16_t j=10; j<=15;j++)
		{
			printf("%d,", TX[j]);
		}
		printf("\r\n");
}

/*DMA Rx传输完成回调*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
		printf("DMA Read block 6, OK\r\n");
		printf("Data in [10:15] is: ");

		for (uint16_t j=10; j<=15;j++)
		{
			printf("%d,", RX[j]);
		}
		printf("\r\n");
}

最后在main.c文件主循环中实现与轮询读写SD时一致的按键逻辑程序,并用修改后的以DMA方式读写SD卡的函数替换以中断方式读写SD卡的函数即可

6.3、实验现象

烧录程序,开发板复位后按下WK_UP按键会输出SD卡信息,按下KEY2按键会擦除SD卡的块0-10数据,与轮询方式读写SD卡时现象一致

按下KEY0按键以DMA的方式读取SD卡块6数据,读取完成后会进入Rx传输完成回调中,在该回调函数中会从串口输出读取到的SD卡块6的数据

按下KEY1按键会以DMA的方式写入1-256的数字到SD卡块6(一个字节写入一个数字),写入完成后会进入Tx传输完成回调中,在该回调函数中会从串口输出写入到SD卡块6中的数据

具体串口输出信息如下图所示

7、常用函数

/*读块*/
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)

/*写块*/
HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)

/*擦除块*/
HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd)

/*获取SD卡信息*/
HAL_StatusTypeDef HAL_SD_GetCardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypeDef *pCardInfo)

/*获取SD卡状态*/
HAL_StatusTypeDef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypeDef *pStatus)

/*以中断方式读块*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)

/*以中断方式写块*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)

/*以DMA方式读块*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)

/*以DMA方式写块*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)

/*SD卡Tx传输完成回调*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)

/*SD卡Rx传输完成回调*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)

8、注释详解

注释1:图片来源自 维基百科-SD卡

注释2:图片来源自 STM32F407中文参考手册 RM009

参考资料

STM32Cube高效开发教程(高级篇)文章来源地址https://www.toymoban.com/news/detail-825225.html

到了这里,关于STM32CubeMX教程27 SDIO - 读写SD卡的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32——SDIO的学习(驱动SD卡)(理论篇)

    目录 一、SD卡简介 1.1历史 1.2 tf卡和SD卡的区别 1.3 mmc,emmc,nand,flash的关系 1.4 SD卡的规格等级 1.4.1按容量分 1.4.2 class等级 1.4.3 UHS总线模式 1.4.4 UHS速度等级 1.4.5 VSC视频速度等级 二、SD卡的内部结构 三、SDIO的学习 3.1 SDIO的主要功能 3.2 SDIO总线拓扑 ​3.3 SDIO功能描述  3.3.1 SD

    2024年02月16日
    浏览(47)
  • stm32在SDIO模式下SD写入错误的问题

    1、问题描述 使用FAT32 f_write 多次执行写操作时,会报FR_DISK_ERR错误,而且是刚开始写不报错,写几次后会一直报错。 设断点跟踪到HAL_SD_WriteBlocks中,在调用SDMMC_CmdWriteMultiBlock时,会报SDMMC_ERROR_TX_UNDERRUN,意思 是Transmit FIFO underrun 2、原因分析 如下图所示,SDMMC开始写操作时,首

    2023年04月24日
    浏览(43)
  • STM32用一线式驱动SD NAND,SDIO的一线式驱动

    SDIO的一线式和四线式 SDIO(Secure Digital Input/Output)是一种用于在嵌入式系统中连接外部设备的标准接口。在SDIO标准中,一线式和四线式是指SDIO接口的不同工作模式。 一线式(Single-Line Mode): 工作原理: 在一线式模式下,SDIO接口仅使用单个数据线进行通信。这个模式通常用

    2024年01月17日
    浏览(40)
  • STM32对SD卡的读、写、擦除操作(SDIO模式)(DMA)

    对于STM32操作SD卡来说,最重要的就算 初始化 、 写操作 、 读操作 、 擦除 这几个操作了。 对于初始化部分上一篇文章已经分析,本篇就主要分析写、读、擦除操作。 本篇函数来自于 STM32提供的例程 。参考野火的程序进行了解释,与野火函数有些不同。 这几种函数完成之后

    2023年04月08日
    浏览(46)
  • STM32F4X SDIO(七) 例程讲解-SD_InitializeCards & SD_GetCardInfo

    本节例程基于 野火电子的STM32F407的SD卡读写例程 进行讲解。上一节中讲解了SD卡上电过程,这节将会讲解一下SD卡的初始化过程,包括 获取SD卡的CID、CSD和SD卡RCA地址 。 CMD2的作用是 通知所有卡通过CMD线返回CID值 ,CID值包括 SD卡的识别号、制造商ID、OEMID、产品名称、版本号、

    2024年02月05日
    浏览(45)
  • STM32使用STM32CUBEMX配置FreeRTOS+SDIO4bit+FATFS注意事项

    以STM32F429为例: 1、SDIO配置 配置为4bit模式,此配置不是最终配置,后面会在代码进行修改。 2、Fatfs配置 Set Defines 选项中的配置可以默认,最重要注意Advanced Setting 选择中的配置,如下 该界面配置默认Use dma template是默认使能的 ,并且不可以选择,只能选择使能,所以需要使

    2024年02月11日
    浏览(58)
  • STM32CubeMX教程26 FatFs 文件系统 - W25Q128读写

    正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 使用FatFs中间件通过SPI通信协议对W25Q128芯片进行读写等操作 关于STM32F407使用SPI通信协议对W25Q128 FLASH芯片读写

    2024年02月19日
    浏览(52)
  • STM32CubeMX教程29 USB_HOST - 使用FatFs文件系统读写U盘

    正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 USB_OTG_FS为工作在Mass Storage Host Class(大容量存储主机类)模式下的USB_HOST(USB主机),并使用FatFs文件系统对

    2024年02月19日
    浏览(43)
  • SDIO读写SD卡速度有多快?

    前两天测试了SPI方式读写SD卡的速度《SPI方式读写SD卡速度测试》,今天来测试一下SDIO方式的读写速度。 测试条件: 单片机:STM32F407VET6 编译环境:MDK 5.30+HAL库 SD卡:闪迪32GB/64GB TF卡 文件系统:FatFS R0.12c 之前测试中说过了,非DMA方式速度和资源利用率都不如DMA方式,所以今

    2024年02月02日
    浏览(43)
  • 【正点原子STM32连载】 第十章 STM32CubeMX简介 摘自【正点原子】STM32F103 战舰开发指南V1.2

    1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html STM32CubeMX是由ST公司开发的图形化代码自动生成工具,能够快速生成初始化代码,如配置GPIO,时钟树

    2024年01月15日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包