STM32CubeMX series 09 - SDIO (SD card read and write, SD card transplant FATFS file system)

====>>> Article summary (with code summary) <<<====

1. Preparations

1.1. Simple literacy

I am going to take a look at the knowledge in this area. I don’t know the difference for a while, so I will make up the lessons first, and skip the unnecessary ones.
Reference article (content source): http://www.360doc.com/content/21/1125/22/59057945_1005908465.shtml

Mainly write these two: SD card, TF card

Common point: SD, TF, and MMC all evolve and develop different specifications on the basis of MMC, such as physical size, package, voltage, pin, bit width, clock signal, etc., but all use the same bus specification.

1.1.1. SD card

SD card (Secure Digital Card, secure digital card) pictures are as follows:
insert image description here
SD card is (secure digital memory card) secure digital card, which is developed on the basis of MMC.
Add features:

  1. You can set the stored usage permissions to prevent the data from being copied by others;
  2. The transmission speed is faster than the 2.11 mmc card.

characteristic:

  1. Optional communication protocol: SD mode and SPI mode
  2. Variable clock frequency: 0~25Mhz
  3. Communication voltage range: 2.0~3.6V
  4. Data life: 100,000 programming/erasing cycles
  5. Forward compatible with MMC card
  6. Running at a frequency of 25M, the data bandwidth is 4 bits, so the maximum transfer rate is 12.5MHz (12.5 megabytes per second).

Pin definition:
insert image description here

1.1.2. TF card

Micro SD Card, formerly known as Trans-flash Card (TF card), officially changed its name to Micro SD Card in 2004.

Features:

  1. SD cards are larger than TF cards.
  2. Applied to different products, SD cards are generally used in larger electronic equipment: such as computers, cameras, AV and other equipment, while TF cards are generally used in mobile phones. We have seen a lot of TF cards, the pictures are as follows:
  3. There is a (lock) switch on the SD card (the picture on the right in the above picture, there is a fluctuating switch on the left of the card), that is, the write protection switch, and the TF card does not have it.

Other than that, there's really no difference. In addition: TF card can be converted into SD card by inserting the adapter (adapter), but generally SD card cannot be converted into TF card.
insert image description here
Pin definition:
insert image description here

1.1.3. SDIO interface

The SDIO interface is an interface developed on the basis of the SD memory card interface. The SDIO interface is compatible with the previous SD memory card and can be connected to SDIO interface devices.

There are three signal transmission modes of SDIO interface: SPI, 1-bit, and 4-bit.

  • In SPI mode, pin 8 is used as an interrupt signal. The functions and communication protocols of other pins are the same as the SD memory card standard specification.
  • In the SDIO bus definition, the DAT1 signal line is multiplexed as an interrupt line.
  • In the 1BIT mode of SDIO, DAT0 is used to transmit data, and DAT1 is used as an interrupt line.
  • In the 4BIT mode of SDIO, DAT0-DAT3 is used to transmit data, and DAT1 is multiplexed as an interrupt line.

insert image description here

1.2. The hardware and schematic diagram used

Different development boards on the hardware here may have slight differences, but the actual development process is the same.

STM32F103 Puzhong-Junend-Z100, master STM32F103ZET6. This can be directly inserted into the SD card. Here we use this development board for experiments.
insert image description here
The punctual atom Mini board, the main control is STM32F103RCT6. This one uses a relatively large SD card slot. If you have an SD card, you can plug it in directly. If you use a Micro SD Card, you need an adapter to connect it.
insert image description here

2. Create a project

2.1. Select master

insert image description here

2.2. System configuration

Configure the clock source
insert image description here
Configure the debug mode (you can check it if you need ST-Link download and debug)
insert image description here
Configure the clock tree (you can directly enter 72 in HCLK, and then press Enter to automatically configure)
insert image description here

2.3. Configuration project directory

insert image description here
insert image description here

3. SD card reading and writing experiment

3.1. Schematic

insert image description here

3.2. Code implementation (polling mode)

First configure the serial port redirection for easy observation –>Serial port redirection configuration<–

SDIO configuration
insert image description here

SDIO is divided into two parts: AHB interface and SDIO adapter.

  • The clock used by the AHB interface is HCLK/2=36MHz, which is used to access the registers of the STM32 SDIO itself.
  • The clock used by the SDIO adapter is SDIOCLK=HCLK=72MHz, and the clock output by the SDIO_CK clock line (PC12 pin, the clock provided by the microcontroller to the SD card) is obtained from this frequency division. The frequency division formula is SDIOCLK/(CLKDIV+2) . CLKDIV is the value of hsd.Init.ClockDiv. (That is the value we set above)
    • When CLKDIV=70, the output frequency of SDIO_CK is 72MHz/(70+2)=1MHz. At this frequency, data can be sent and received without using DMA.
    • When CLKDIV=1, the output frequency of SDIO_CK is 72MHz/(1+2)=24MHz. DMA must be used to send and receive data at this frequency.

The previous chapter 1 said that the clock frequency of SDIO is 0~25Mhz (different cards are not the same). That is 72/(34+2) = 2Mhz. (Other numbers are also fine. If the test finds that reading and writing fails, just increase the frequency division factor)

Then generate the project.

In main.c, before 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 */

Experimental results
Compile, burn, and download via serial port.

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. Setting parameters in the program

Because after using CubeMX, although many things can be used, but in the end I didn't understand how to set up many things, so I still need to explain here.

  1. main.cOpen the header file ofsdio.h
  2. sdio.hThere are functions invoid MX_SDIO_SD_Init(void);
  3. Looking at the definition of this function, you can see that all the set parameters are SD_HandleTypeDef hsd;set in
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();
  }
}

Question : There is one of the above functions hsd.Init.BusWide = SDIO_BUS_WIDE_1B;, but isn't the four-wire configuration we configured?

Answer: (Actually, I don't really understand why, but let's do this first):
The SD card can use 1-bit data line mode or 4-bit data line mode. However, it must be ensured that the data line bit width set by the SDIO of the STM32 microcontroller is consistent with the data line bit width set on the SD card.
If you set hsd.Init.BusWide to SDIO_BUS_WIDE_4B, and then execute the HAL_SD_Init function, you can only set the SDIO of the STM32 microcontroller to a 4-bit width, and the SD card still uses a 1-bit width.
So the usual practice is to set hsd.Init.BusWide to SDIO_BUS_WIDE_1B. After HAL_SD_Init is executed, call HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B). This function can set STM32 and SD card to 4-bit mode at the same time.

It is found that in some firmware packages, after using cubemx to generate the project, the default is hsd.Init.BusWide = SDIO_BUS_WIDE_4B; but after the program is generated, it is found that the initialization cannot pass, and it still needs to be manually changed back to 1B.

3.3. Code implementation (DMA mode)

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

We increase the frequency of the original configuration a little (not necessary)
insert image description here
and then need to add DMA configuration
insert image description here
. It can be seen that, as a thing for transmitting data, SDIO has two directions. But only one DMA Handle can be added, either choose to receive or send. In fact, SDIO can use the same DMA Handle to send and receive data.

In the generated code:
sdio.cThere is a function in the file void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle).
insert image description here
After setting other members of hdma.Init, call to HAL_DMA_Init(&hdma_sdio)initialize DMA2_Channel4, after that, call __HAL_LINKDMA();the function twice, the macro binds hdma to hdmarx and hdmatx of hsd at the same time.

Interrupt priority configuration, generally where DMA is used, the priority of DMA needs to be lower than other priorities .
insert image description here

Write a DMA read and write function (mainly to change the DMA transfer direction before transfer):

/**
 * @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;
}

Write a DMA transfer test function and main.crun it before 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);
    }
}

The result of the program running is the same as above.

4. Transplant FATFS file system to SD card

4.1. FATFS configuration

CubeMX configuration is still very convenient.

Keep the configuration of the polling mode in the previous section unchanged, and add the configuration of the FATFS system.
insert image description here
Other parameters can be left as default.

The Chinese file name can actually be selected, but it is not necessary because it takes up a lot of memory.
The maximum length of the file name is 256 (default), and 64 is set here. If it exceeds 64, f_open may fail.

You also need to configure an SD card insertion pin. If you do not configure the generated file, an error will be reported, so even if there is no hardware connection here, you can set a pin arbitrarily, and comment it out if you don’t need it after generating the project.
insert image description here
Set the size of the stack space larger
insert image description here
. After generating the project, the directory is as follows. It can be found that there are two more folders compared with previous projects.
insert image description here

4.2. Modify SD card insertion detection code

After generating the project, first modify the SD card insertion detection code.

In bsp_driver.sd.cthe file, you can see __weak uint8_t BSP_SD_Init(void)that this part of the code is to detect whether the SD card is working normally. The function in the red box BSP_SD_IsDetected()is used to detect whether the SD card is inserted (or whether the write protection switch is toggled, which is written in the introduction of the SD card above).
insert image description here
The function BSP_SD_IsDetected()definition is as follows. It can be seen that if the SD card is not inserted (write-protected), it cannot be initialized normally.
insert image description here
Among them, this part is to detect the high and low levels of the pin that we arbitrarily configure during configuration.
insert image description here
After understanding the principle, we can ignore this part directly, so it needs to be modified.

  1. You can choose to directly pull this pin low on the hardware
  2. The software pulls the pin level low before this line (set to pull down)
  3. Modify the code to skip this line.

Here I use the third method, directly BSP_SD_IsDetected()shielding this part of the function.
insert image description here

Be careful with this, if you regenerate the project, this part will have to be changed.

4.3. Code implementation

main.cAdd the following code before while(1) in :

	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);
    /* 操作完成,停机 */

Effect test
Compile, burn, and view the effect through the serial port.
insert image description here
Unplug the SD card and insert it into the computer, you can also see this file.
insert image description here

4.4. Precautions

If there are occasional problems with f_open, f_write, and f_read; f_mkfs reports an error of FS_DISK_ERR, you can add SDIO hardware stream enable to try.
insert image description here

I saw it in other people's articles. In fact, this problem did not occur in my test, so let's put it here first.

Guess you like

Origin blog.csdn.net/weixin_46253745/article/details/127865071