STM32CubeMX系列09——SDIO(SD卡读写、SD卡移植FATFS文件系统)

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

====>>> 文章汇总(有代码汇总) <<<====

1. 准备工作

1.1. 简单扫盲

准备看看这方面的知识,一时间还没不清有什么区别,先补补课,不需要的跳过。
参考文章(内容来源):http://www.360doc.com/content/21/1125/22/59057945_1005908465.shtml

主要写这两个:SD卡、TF卡

共同点:SD、TF、MMC都是在MMC基础上演化发展不同的规范,比如物理尺寸,封装,电压,管脚,位宽,时钟信号等不同,但都使用相同的总线规范。

1.1.1. SD卡

SD卡(Secure Digital Card,安全数字卡)图片如下:
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
SD卡是(secure digital memory card)安全数码卡,是在MMC基础上发展起来的。
增加特色:

  1. 可以设置所存储的使用权限,防止数据被他人复制;
  2. 传输速度比2.11版mmc卡快。

特性:

  1. 可选通信协议:SD模式 和 SPI模式
  2. 可变时钟频率:0~25Mhz
  3. 通信电压范围:2.0~3.6V
  4. 数据寿命:10万次编程/擦除
  5. 正向兼容MMC卡
  6. 运行在25M的频率上,数据带宽是4位,因此最大传输速率是12.5MHz(12.5兆字节每秒)。

引脚定义:
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

1.1.2. TF卡

Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro SD Card。

特点:

  1. SD卡 比 TF卡 的尺寸要大。
  2. 应用于不同产品,SD卡一般都用在大一些的电子设备:如电脑,相机,AV等器材,而TF一般用在手机上。TF卡我们见的比较多,图片如下:
  3. SD 卡上有一个(lock)开关(上图中右边的图,卡左边有个波动的开关),即写保护开关,TF卡没有。

除此之外,其实没什么区别。另外:TF卡插入适配器(adapter)可以转换成SD卡,但SD卡一般无法转换成TF卡。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
引脚定义:
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

1.1.3. SDIO接口

SDIO接口是在SD内存卡接口的基础上发展起来的接口,SDIO接口兼容以前的SD内存卡,并且可以连接SDIO接口的设备。

SDIO接口的信号传输模式有SPI、1-bit、4-bit三种。

  • 在SPI模式中,第8脚位被当成中断信号。其它脚位的功能和通信协定与SD记忆卡的标准规范一样。
  • 在SDIO总线定义中,DAT1信号线复用为中断线。
  • 在SDIO的 1BIT 模式下 DAT0 用来传输数据,DAT1用作中断线。
  • 在SDIO的 4BIT 模式下 DAT0-DAT3 用来传输数据,其中DAT1复用作中断线。

stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

1.2. 所用硬件及原理图

此处硬件上不同的开发板可能略有差异,但是实际开发的过程中都是一样的。

STM32F103 普中-准端-Z100,主控 STM32F103ZET6。这个是直接用SD卡插上去就可以了。这里我们用这个开发板进行实验
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
正点原子Mini板,主控 STM32F103RCT6。这个是用了一个比较大的SD卡的卡槽,如果有SD卡可以直接插上去,如果是用的Micro SD Card卡,需要一个适配器才能连。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

2. 创建工程

2.1. 选择主控

stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

2.2. 系统配置

配置时钟源
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
配置debug模式(如果需要ST-Link下载及调试可以勾选)
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
配置时钟树(可以直接在HCLK那里输入72,然后敲回车会自动配置)
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

2.3. 配置工程目录

stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

3. SD卡读写实验

3.1. 原理图

stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

3.2. 代码实现(轮询模式)

先把串口重定向配置一下,方便观察–>串口重定向配置<–

SDIO配置
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

SDIO分为两个部分:AHB interface和SDIO adapter。

  • AHB interface采用的时钟是HCLK/2=36MHz, 是用来访问STM32 SDIO本身的寄存器的。
  • SDIO adapter采用的时钟是SDIOCLK=HCLK=72MHz,SDIO_CK时钟线(PC12脚,单片机给SD卡提供的时钟)输出的时钟就是从这个上面分频得到的,分频公式为SDIOCLK/(CLKDIV+2)。CLKDIV就是hsd.Init.ClockDiv的值。(就是我们上面设定的值)
    • 当CLKDIV=70时,SDIO_CK输出的频率为72MHz/(70+2)=1MHz。在这个频率下可以不使用DMA收发数据。
    • 当CLKDIV=1时,SDIO_CK输出的频率为72MHz/(1+2)=24MHz。在这个频率下必须使用DMA收发数据。

前面第一章说了 SDIO的时钟频率为0~25Mhz(不同的卡不太一样),此处设置分频系数为34,而我们开发板的时钟频率为72Mhz,这里分频系数为34,也就是72/(34+2) = 2Mhz。(其他数也行,如果测试发现读写失败,就增大分频系数就好了)

然后生成工程。

main.c中,while(1)之前。

   /* USER CODE BEGIN 2 */
		printf("Micro SD Card Test... \r\n");
		
		uint8_t read_buf[512];		// 读数据缓存
		uint8_t write_buf[512];		// 写数据缓存

		/* SD卡状态 */
		int sdcard_status = 0;
		
		HAL_SD_CardCIDTypeDef sdcard_cid;

		/* 获取SD卡状态 */
		sdcard_status = HAL_SD_GetCardState(&hsd);
		// 处于数据传输模式的传输状态
		if(sdcard_status == HAL_SD_CARD_TRANSFER)
		{
			printf("SD card init ok!\r\n\r\n");

			// 打印SD卡基本信息
			printf("SD card information! \r\n");
			// 容量信息
			printf("CardCapacity(Byte): %llu \r\n",((unsigned long long)hsd.SdCard.BlockSize * hsd.SdCard.BlockNbr));
			// 块大小 默认都是512个字节
			printf("CardBlockSize(Byte): %d \r\n", hsd.SdCard.BlockSize);
			// 有多少个块
			printf("CardBlockNumber: %d \r\n", hsd.SdCard.BlockNbr);
			
			printf("RCA: %d \r\n", hsd.SdCard.RelCardAdd);
			
			printf("CardType: %d \r\n", hsd.SdCard.CardType);

			// 读取并打印SD卡的CID信息
			HAL_SD_GetCardCID(&hsd, &sdcard_cid);
			// 制造商
			printf("ManufacturerID: %d \r\n",sdcard_cid.ManufacturerID);
		}
		else
		{
			printf("SD card init fail! \r\n" );
			return 0;
		}
		
		/* 读取未操作之前的数据 */
		printf("------------------- Read SD card block data Test ------------------\r\n");
		/*
			读一个扇区的数据:
			0: 从第0个扇区开始。
			1:读一个扇区的数据。
			0xffff:等待时间。
			note:也就是只读了第0个扇区。
		*/
		sdcard_status = HAL_SD_ReadBlocks(&hsd, (uint8_t *)read_buf, 0, 1, 0xffff);
		if(sdcard_status == HAL_OK)
		{ 
			printf("Read block data ok! \r\n");
			for(int i = 0; i < 512; i++)
			{
				printf("0x%02x ", read_buf[i]);
				if((i+1)%16 == 0)
				{
					printf("\r\n");
				}
			}
		}
		else
		{
			printf("Read block data fail! status = %d \r\n", sdcard_status);
		}
		

		/* 向SD卡块写入数据 */
		printf("------------------- Write SD card block data Test ------------------\r\n");
		/* 填充缓冲区数据 */
		for(int i = 0; i < 512; i++)
		{
			write_buf[i] = i % 256;
		}
		// 开始写入数据
		/*
			写一个扇区的数据:
			0: 从第0个扇区开始。
			1:写一个扇区的数据。
			0xffff:等待时间。
			note:也就是只写了第0个扇区。
		*/
		sdcard_status = HAL_SD_WriteBlocks(&hsd, (uint8_t *)write_buf, 0, 1, 0xffff);
		if(sdcard_status == HAL_OK)
		{ 
			/* 传输完成不代表写入完成,因此要等待SD卡状态变为可传输状态。擦除操作也是一样。 */
			printf("Writing block data. state = %d \r\n", HAL_SD_GetCardState(&hsd));
			while (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING);
			printf("Write block data ok,state = %d \r\n", HAL_SD_GetCardState(&hsd));
		}
		else
		{
			printf("Write block data fail! status = %d \r\n", sdcard_status);
		}
		
		/* 读取写入之后的数据 */
		printf("------------------- Read SD card block data after Write ------------------\r\n");
		sdcard_status = HAL_SD_ReadBlocks(&hsd, (uint8_t *)read_buf, 0, 1, 0xffff);
		if(sdcard_status == HAL_OK)
		{ 
			printf("Read block data ok! \r\n");
			for(int i = 0; i < 512; i++)
			{
				printf("0x%02x ", read_buf[i]);
				if((i+1)%16 == 0)
				{
					printf("\r\n");
				}
			}
		}
		else
		{
			printf("Read block data fail! status = %d \r\n", sdcard_status);
		}
		
		/* 擦除SD卡块 */
		printf("------------------- Block Erase -------------------------------\r\n");
		/*
			擦除512个扇区的数据:
			0: 从第0个扇区开始。
			1:一直擦除到512扇区。
			note:擦除第0到第512个扇区数据,也包括0和512,也就是一共512个。
		*/
		sdcard_status = HAL_SD_Erase(&hsd, 0, 512);
		// 等待擦除完毕
		if (sdcard_status == HAL_OK)
		{	
			printf("Erasing block. state = %d \r\n", HAL_SD_GetCardState(&hsd));
			while (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING);
			printf("Erase block ok state = %d \r\n", HAL_SD_GetCardState(&hsd));
		}
		else
		{
			printf("Erase block fail! status = %d \r\n", sdcard_status);
		}
		
		/* 读取擦除之后的数据 */
		printf("------------------- Read SD card block data after Erase ------------------\r\n");
		sdcard_status = HAL_SD_ReadBlocks(&hsd, (uint8_t *)read_buf, 0, 1, 0xffff);
		if(sdcard_status == HAL_OK)
		{ 
			printf("Read block data ok \r\n" );
			for(int i = 0; i < 512; i++)
			{
				printf("0x%02x ", read_buf[i]);
				if((i+1)%16 == 0)
				{
					printf("\r\n");
				}
			}
		}
		else
		{
			printf("Read block data fail! status = %d \r\n", sdcard_status);
		}

		printf("------------------- Over ------------------\r\n");
		
  /* USER CODE END 2 */

实验效果
编译、烧录、串口下载。

Micro SD Card Test... 
SD card init ok!

SD card information! 
CardCapacity(Byte): 3965190144 
CardBlockSize(Byte): 512 
CardBlockNumber: 7744512 
RCA: 58916 
CardType: 1 
ManufacturerID: 3 
------------------- Read SD card block data Test ------------------
Read block data ok! 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
------------------- Write SD card block data Test ------------------
Writing block data. state = 7 
Write block data ok,state = 4 
------------------- Read SD card block data after Write ------------------
Read block data ok! 
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 
0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 
0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 
0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 
0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 
0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 
0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 
0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7b 0x7c 0x7d 0x7e 0x7f 
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 
0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 
0xa0 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 0xa9 0xaa 0xab 0xac 0xad 0xae 0xaf 
0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf 
0xc0 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7 0xc8 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 
0xd0 0xd1 0xd2 0xd3 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 
0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 
0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 
0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 
0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 
0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 
0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 
0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 
0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 
0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7b 0x7c 0x7d 0x7e 0x7f 
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 
0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 
0xa0 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 0xa9 0xaa 0xab 0xac 0xad 0xae 0xaf 
0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf 
0xc0 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7 0xc8 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 
0xd0 0xd1 0xd2 0xd3 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 
0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 
0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 
------------------- Block Erase -------------------------------
Erasing block. state = 7 
Erase block ok state = 4 
------------------- Read SD card block data after Erase ------------------
Read block data ok 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
------------------- Over ------------------

3.4. 程序中设置参数

因为用了CubeMX之后,很多东西虽然会用了,但是到最后都没明白很多东西到底怎么设置的,因此这里还是要说明一下的。

  1. main.c的头文件中打开sdio.h
  2. sdio.h中有函数void MX_SDIO_SD_Init(void);
  3. 查看这个函数的定义,可以看到所有设置的参数 都在 SD_HandleTypeDef hsd;中设置
SD_HandleTypeDef hsd;

void MX_SDIO_SD_Init(void)
{
  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 = 34;
  if (HAL_SD_Init(&hsd) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
  {
    Error_Handler();
  }
}

问题:上面的函数中有一个 hsd.Init.BusWide = SDIO_BUS_WIDE_1B;,但是我们配置的不是四线的吗。

答案:(其实也不太明白为什么,但是先这样吧):
SD卡可以采用1位数据线模式,也可以采用4位数据线模式。但是必须确保STM32单片机的SDIO设置的数据线位宽,和SD卡上设置的数据线位宽是一致的。
如果将 hsd.Init.BusWide 设为 SDIO_BUS_WIDE_4B,然后执行HAL_SD_Init 函数,只能把STM32单片机的SDIO设置为4位位宽,SD卡上还是用的1位位宽。
所以通常的做法是 hsd.Init.BusWide 设为 SDIO_BUS_WIDE_1B,HAL_SD_Init 执行完成后,再调用 HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B),这个函数可以将STM32和SD卡同时设为4位模式。

发现在有的固件包中,使用cubemx生成工程后,默认的就是 hsd.Init.BusWide = SDIO_BUS_WIDE_4B; 但是程序生成后发现初始化无法通过,还是需要手动改回来,改成1B。

3.3. 代码实现(DMA模式)

应用中一般都使用DMA传输模式

我们把原有的配置的频率提高一点(非必须)
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
然后需要添DMA的配置
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
可以看到,作为一个传输数据的东西,SDIO是有两个方向的。但是只能添加一个DMA Handle,要么选择收,要么选择发。实际上SDIO收发数据是可以用同一个DMA Handle的。

在生成的代码中:
sdio.c文件中有个void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)函数。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
设置完 hdma.Init 的其他成员后,调用了HAL_DMA_Init(&hdma_sdio)初始化DMA2_Channel4,之后,调用了两次__HAL_LINKDMA();函数,宏将hdma同时绑定到 hsd 的 hdmarx 和 hdmatx上。

中断优先级配置,一般用到DMA的地方,都需要把DMA的优先级比其他的优先级要低
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

编写一个DMA读写函数(主要是为了在传输前更改DMA传输方向):

/**
 * @brief   SD卡DMA读数据(开始前重新初始化DMA,更改传输方向)
 *
 * @param   hsd
 * @param   pData
 * @param   BlockAdd
 * @param   NumberOfBlocks
 *
 * @return  none
 */
HAL_StatusTypeDef SDIO_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
    HAL_StatusTypeDef Return_Status;
    HAL_SD_CardStateTypeDef SD_Card_Status;

    do
    {
        SD_Card_Status = HAL_SD_GetCardState(hsd);
    } while(SD_Card_Status != HAL_SD_CARD_TRANSFER);

    /* SDIO DMA DeInit */
    /* SDIO DeInit */
    HAL_DMA_DeInit(&hdma_sdio);
    /* SDIO DMA Init */
    /* SDIO Init */
    hdma_sdio.Instance = DMA2_Channel4;
    hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio.Init.Mode = DMA_NORMAL;
    hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
    if(HAL_DMA_Init(&hdma_sdio) != HAL_OK)
    {
        Error_Handler();
    }

    __HAL_LINKDMA(hsd, hdmarx, hdma_sdio);

    Return_Status = HAL_SD_ReadBlocks_DMA(hsd, pData, BlockAdd, NumberOfBlocks);

    return Return_Status;
}

/**
 * @brief   SD卡DMA写数据(开始前重新初始化DMA,更改传输方向)
 *
 * @param   hsd
 * @param   pData
 * @param   BlockAdd
 * @param   NumberOfBlocks
 *
 * @return  none
 */
HAL_StatusTypeDef SDIO_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
    HAL_StatusTypeDef Return_Status;
    HAL_SD_CardStateTypeDef SD_Card_Status;

    do
    {
        SD_Card_Status = HAL_SD_GetCardState(hsd);
    } while(SD_Card_Status != HAL_SD_CARD_TRANSFER);

    /* SDIO DMA DeInit */
    /* SDIO DeInit */
    HAL_DMA_DeInit(&hdma_sdio);
    /* SDIO DMA Init */
    /* SDIO Init */
    hdma_sdio.Instance = DMA2_Channel4;
    hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio.Init.Mode = DMA_NORMAL;
    hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
    if(HAL_DMA_Init(&hdma_sdio) != HAL_OK)
    {
        Error_Handler();
    }

    __HAL_LINKDMA(hsd, hdmatx, hdma_sdio);

    Return_Status = HAL_SD_WriteBlocks_DMA(hsd, pData, BlockAdd, NumberOfBlocks);

    return Return_Status;
}

编写一个DMA传输测试函数,并在main.c中while(1)之前运行:

/**
 * @brief   SD卡DMA读写测试(会破坏建立的FATFS系统)
 *
 * @param   none
 *
 * @return  none
 */
void SD_read_writer_dma_test(void)
{
    /* SD卡状态 */
    int sdcard_status = 0;

    HAL_SD_CardCIDTypeDef sdcard_cid;

    uint8_t read_buf[512];      // 读数据缓存
    uint8_t write_buf[512];     // 写数据缓存

    /* 读取未操作之前的数据 */
    printf("------------------- Read SD card block data Test ------------------\r\n");
	/*
        读一个扇区的数据:
        0: 从第0个扇区开始。
        1:读一个扇区的数据。
        note:也就是只读了第0个扇区。
    */
	sdcard_status = SDIO_ReadBlocks_DMA(&hsd, (uint8_t *)read_buf, 0, 1);
    
    if(sdcard_status == HAL_OK)
    {
        printf("Read block data ok! \r\n");
        for(int i = 0; i < 512; i++)
        {
            printf("0x%02x ", read_buf[i]);
            if((i + 1) % 16 == 0)
            {
                printf("\r\n");
            }
        }
    }
    else
    {
        printf("Read block data fail! status = %d \r\n", sdcard_status);
    }

    /* 向SD卡块写入数据 */
    printf("------------------- Write SD card block data Test ------------------\r\n");
    /* 填充缓冲区数据 */
    for(int i = 0; i < 512; i++)
    {
        write_buf[i] = i % 256;
    }
    // 开始写入数据
    /*
        写一个扇区的数据:
        0: 从第0个扇区开始。
        1:写一个扇区的数据。
        note:也就是只写了第0个扇区。
    */
	sdcard_status = SDIO_WriteBlocks_DMA(&hsd, (uint8_t *)write_buf, 0, 1);
	
    if(sdcard_status == HAL_OK)
    {
        /* 传输完成不代表写入完成,因此要等待SD卡状态变为可传输状态。擦除操作也是一样。 */
        printf("Writing block data. state = %d \r\n", HAL_SD_GetCardState(&hsd));
        while(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING);
        printf("Write block data ok,state = %d \r\n", HAL_SD_GetCardState(&hsd));
    }
    else
    {
        printf("Write block data fail! status = %d \r\n", sdcard_status);
    }

    /* 读取写入之后的数据 */
    printf("------------------- Read SD card block data after Write ------------------\r\n");
    
	sdcard_status = SDIO_ReadBlocks_DMA(&hsd, (uint8_t *)read_buf, 0, 1);
    
	if(sdcard_status == HAL_OK)
    {
        printf("Read block data ok! \r\n");
        for(int i = 0; i < 512; i++)
        {
            printf("0x%02x ", read_buf[i]);
            if((i + 1) % 16 == 0)
            {
                printf("\r\n");
            }
        }
    }
    else
    {
        printf("Read block data fail! status = %d \r\n", sdcard_status);
    }
}

程序运行结果同上。

4. SD卡移植FATFS文件系统

4.1. FATFS配置

CubeMX配置还是很方便的。

保留上一节轮询模式的配置不变,添加FATFS系统的配置。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
其他参数保持默认即可。

中文文件名,其实也可以选,但是没必要,因为占用的内存比较大。
文件名最大长度256(默认),这里设置64,如果使用的超过64,f_open可能会失败。

还需要配置一个SD卡插入引脚,如果不配置 生成文件时会报错,所以这里即使没有硬件连接,也可以任意设置一引脚,生成工程后不需要的话直接注释掉。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
把栈空间大小设置大一点
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
生成工程后,目录如下。可以发现和以往的工程相比多了两个文件夹。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

4.2. 修改SD卡插入检测代码

生成工程后,首先修改SD卡插入检测代码。

bsp_driver.sd.c文件中,可以看到__weak uint8_t BSP_SD_Init(void),该部分代码是检测SD卡是否正常工作。其中红框中的函数BSP_SD_IsDetected()是用于检测SD卡是否插入(或者写保护开关是否拨动,在前文SD卡介绍中有写)。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
函数BSP_SD_IsDetected()定义如下,可以看到,如果监测到SD卡未插入(写保护)就无法正常初始化。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
其中,这部分也就是检测我们配置时任意配置的那个引脚的高低电平。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
明白原理后,我们可以直接不管这部分的,因此需要进行修改。

  1. 可以选择直接把这个引脚在硬件上拉低
  2. 软件上在这行之前把引脚电平拉低(设置为下拉)
  3. 修改代码跳过这行。

这里我采用第三种,直接把BSP_SD_IsDetected()函数中的这部分屏蔽掉。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

这样要小心,你重新生成工程的话,这部分还要改。

4.3. 代码实现

main.c中的while(1)之前添加如下代码:

	FATFS fs;                       /* FatFs 文件系统对象 */
	FIL file;                       /* 文件对象 */
	FRESULT f_res;                  /* 文件操作结果 */
	UINT fnum;                      /* 文件成功读写数量 */
	BYTE ReadBuffer[1024] = {0};    /* 读缓冲区 */
	BYTE WriteBuffer[] =            /* 写缓冲区 */
						"This is STM32 working with FatFs \r\n";
  
	printf("\r\n ****** FatFs Example ****** \r\n \r\n");
    
    // 在外部 SD 卡挂载文件系统,文件系统挂载时会对 SD 卡初始化
	// note:必须先要保证SD卡正常拥有FAT文件系统,如果没有会失败。
    f_res = f_mount(&fs, "0:", 1);
    
    /*----------------------- 格式化测试 ---------------------------*/
    printf("\r\n ****** Register the file system object to the FatFs module ****** \r\n");
		
    /* 如果没有文件系统就格式化创建创建文件系统 */
    if(f_res == FR_NO_FILESYSTEM)
    {
        printf("The SD card does not yet have a file system and is about to be formatted... \r\n");
        /* 格式化 */
        f_res = f_mkfs("0:", 0, 0);
        if(f_res == FR_OK)
        {
            printf("The SD card successfully formatted the file system\r\n");
            /* 格式化后,先取消挂载 */
            f_res = f_mount(NULL, "0:", 1);
            /* 重新挂载 */
            f_res = f_mount(&fs, "0:", 1);
        }
        else
        {
            printf("The format failed\r\n");
            while(1);
        }
    }
    else if(f_res != FR_OK)
    {
        printf(" mount error : %d \r\n", f_res);
        while(1);
    }
    else
    {
        printf(" mount sucess!!! \r\n");
    }
    
    /*----------------------- 文件系统测试:写测试 -----------------------------*/
    /* 打开文件,如果文件不存在则创建它 */
    printf("\r\n ****** Create and Open new text file objects with write access ****** \r\n");
    
	f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_CREATE_ALWAYS | FA_WRITE);
    if(f_res == FR_OK)
    {
        printf(" open file sucess!!! \r\n");
        /* 将指定存储区内容写入到文件内 */
        printf("\r\n****** Write data to the text files ******\r\n");
        f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &fnum);
        if(f_res == FR_OK)
        {
            printf(" write file sucess!!! (%d)\n", fnum);
            printf(" write Data : %s\r\n", WriteBuffer);
        }
        else
        {
            printf(" write file error : %d\r\n", f_res);
        }
        /* 不再读写,关闭文件 */
        f_close(&file);
    }
    else
    {
        printf(" open file error : %d\r\n", f_res);
    }
    
    /*------------------- 文件系统测试:读测试 ------------------------------------*/
    printf("\r\n****** Read data from the text files ******\r\n");
    f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_OPEN_EXISTING | FA_READ);
    if(f_res == FR_OK)
    {
        printf(" open file sucess!!! \r\n");
        f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);
        if(f_res == FR_OK)
        {
            printf("read sucess!!! (%d)\n", fnum);
            printf("read Data : %s\r\n", ReadBuffer);
        }
        else
        {
            printf(" read error!!! %d\r\n", f_res);
        }
    }
    else
    {
        printf(" open file error : %d\r\n", f_res);
    }
    /* 不再读写,关闭文件 */
    f_close(&file);
    /* 不再使用文件系统,取消挂载文件系统 */
    f_mount(NULL, "0:", 1);
    /* 操作完成,停机 */

效果测试
编译、烧录、用串口查看效果。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm
拔下SD卡,插入电脑,也可以看到这个文件。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

4.4. 注意事项

f_open、f_write、f_read如果偶尔有问题;f_mkfs报错 FS_DISK_ERR,可以加上了SDIO硬件流使能试试。
stm32 sd卡带文件系统,CubeMX,stm32,单片机,arm

别人的文章里看到的,实际上我测试没有出现这个问题,先放这吧。文章来源地址https://www.toymoban.com/news/detail-703745.html

到了这里,关于STM32CubeMX系列09——SDIO(SD卡读写、SD卡移植FATFS文件系统)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 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日
    浏览(44)
  • stm32读写SD卡(SDIO模式)

    目录 一、SD卡简介 二、源码下载 三、移植条件 1、芯片参数 2、硬件连接 四、驱动代码 1、依赖宏如下 2、驱动代码实现 3、测试代码 4、运行截图 五、总结 SD卡有SDIO驱动模式和SPI驱动模式,本例中使用SDIO模式驱动SD卡。 https://download.csdn.net/download/qq_30095023/88702705 https://downl

    2024年01月24日
    浏览(49)
  • STM32CubeMX+FATFS+FREERTOS读写U盘

    软件:STM32CubeMX V6.6.1 、 KEIL5 V5.29 硬件:STM32F429ZET6 USB_OTG_FS:PA11/PA12引脚 USART1:PA9/PA10,方便输出调试信息 1)SYS下载方式选择SW方式,因为要使用FREERTOS,提前将时钟源修改为TIM7(其他定时器也可以) 2) RCC设置,选择高速外部晶振HSE(根据具体硬件选择) 3)USART1设置,方便输出调

    2024年01月18日
    浏览(51)
  • STM32FATFS文件系统移植

    FATFS文件系统是一个用于在微控制器上运行的开源文件系统,支持FAT/FATFS、NTFS、exFAT等主流文件系统,且一直保持更新。在此以FatFs官网最新版本v0.15进行移植。 FATFS源码在其官网就有下载链接,下载后解压即可,官网页面如图1所示: 图1.FATFS官网页面 将其翻至最下面,就可以

    2024年03月09日
    浏览(45)
  • STM32挂载SD卡基于Fatfs文件系统读取文件信息

    🔖本例程基于正点原子标准库修改而来。 📍FatFs 相关API函数网站: http://elm-chan.org/fsw/ff/00index_e.html 🌴分别测试了SD卡模块以及Mini SD卡模块。 🌿STM32f1单片机和TF卡、SD卡连接采用SPI通讯方式。 SD模块: Mini SD卡模块: 👉🏻如果需要采用SDIO驱动方式,那么需要采用下面这种

    2024年02月10日
    浏览(41)
  • STM32-基本知识梳理8-FATFS文件系统移植

    一、基本概念 1,为什么需要文件系统? 在没有文件系统的存储器中,一般通过手工记录,那些变量存放在那些位置,很难有系统的管理 难以记录有效数据的位置 、难以确定存储介质的剩余空间、 不明确应以何种格式来解读数据 加入文件系统后,就可以引导区、目录等对内

    2024年02月03日
    浏览(42)
  • STM32F429 Discovery开发板应用:实现SPI-SD Card文件写入(搭载FatFS文件系统)

    MCU:STM32F429ZIT6 开发环境:STM32CubeMX+MDK5   外购了一个SPI接口的SD Card模块,想要实现SD卡存储数据的功能。 首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找到开发板对应封装的MCU型号,双击打开(图中第三)。   此时,双击完后会关闭此界面,然后打开一个新界面。

    2024年02月08日
    浏览(58)
  • 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日
    浏览(49)
  • STM32——SDIO的学习(驱动SD卡)(实战篇)

    目录 一、SDIO寄存器 1.1 SDIO电源控制寄存器(SDIO_POWER) 1.2 SDIO时钟控制寄存器(SDIO_CLKCR) 1.3 SDIO参数寄存器(SDIO_ARG) 1.4 SDIO命令寄存器(SDIO_CMD) 1.5 SDIO命令响应寄存器(SDIO_RESPCMD) 1.6 SDIO响应 1..4 寄存器(SDIO_RESPx) 1.7 SDIO数据定时器寄存器(SDIO_DTIMER) 1.8 SDIO数据长度寄存器(SDIO_DLEN) 1.9 SDI

    2024年02月16日
    浏览(66)
  • 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日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包