{"id":12655,"date":"2024-04-06T11:48:01","date_gmt":"2024-04-06T09:48:01","guid":{"rendered":"https:\/\/deepbluembedded.com\/?p=12655"},"modified":"2024-04-06T11:48:03","modified_gmt":"2024-04-06T09:48:03","slug":"stm32-sdmmc-tutorial-examples-dma","status":"publish","type":"post","link":"https:\/\/deepbluembedded.com\/stm32-sdmmc-tutorial-examples-dma\/","title":{"rendered":"STM32 SDMMC Tutorial With Examples + DMA"},"content":{"rendered":"\n
This is a comprehensive guide for STM32 SDMMC SD Card Interfacing With FatFS Library<\/strong>. You’ll learn how to use SD Cards with STM32 microcontrollers using the SDMMC interface. We’ll create some STM32 SD Card Example Test Projects to verify what we’ll learn in this tutorial.<\/p>\n\n\n Some STM32 microcontroller series have an integrated SDMMC hardware peripheral that’s designed specifically to interface SD cards at the maximum operating speed. The SDMMC interface provides an interface between the AHB bus and (SD memory cards, SDIO cards, and eMMC devices).<\/p>\n\n\n\n However, SD cards can still be used over SPI communication which is available in all STM32 microcontrollers and pretty much every single microcontroller in the market. We’ve already focused on STM32 SD Card SPI interfacing<\/a><\/strong> in this previous tutorial, and STM32 SDIO Interface<\/a><\/strong> in this other previous tutorial. Therefore, in today’s tutorial, we’ll shift the attention to using the STM32 SDMMC interface for SD Card handling.<\/p>\n\n\n SPI<\/strong> is a generic serial peripheral interface and can still be used to interface SD cards with low-end microcontrollers at a relatively lower speed of communication and a much simpler software stack. That’s why SPI is the most commonly used interface for SD cards in a lot of projects.<\/p>\n\n\n\n SDIO<\/strong> is a hardware peripheral designed specifically for interfacing (SD Cards, SDIO Cards, and MultiMedia Cards “MMC”) with the APB2 peripheral bus in “some” of the STM32 microcontrollers. Given that it’s dedicated to SD card interfacing, it’s going to be a much faster way of communicating with SD cards (4x the speed you can get with an SPI interface).<\/p>\n\n\n\n SDMMC<\/strong> is a hardware peripheral designed specifically for interfacing (SD memory cards, SDIO cards, and eMMC devices) with the APB2 peripheral bus in “some” of the STM32 microcontrollers. It’s almost identical to the SDIO interface but it supports eMMC devices additionally and can go up to way higher transfer speeds (in 8-Bit mode).<\/p>\n\n\n The SDMMC does not have an SPI-compatible communication mode. And it only supports one (SD\/SDIO\/eMMC) card at a time.<\/p>\n\n<\/div><\/div>\n\n\n In this section, we’ll discuss how to interface STM32 microcontrollers with SD Cards using the SDMMC interface.<\/p>\n\n\n\n <\/p>\n\n\n Use an SD Card Reader<\/a><\/strong> for this step.<\/p>\n\n\n\n Before using your SD card, make sure you’ve Formatted<\/strong> it to the FAT<\/strong> (FAT32\/FAT) file system (in your operating system of choice).<\/p>\n\n\n If you’re designing your own STM32-based PCB board project that requires having an SD card memory slot onboard, you’ll need to connect your STM32 SDMMC pins to the SD Card slot as shown below.<\/p>\n\n\n\n <\/p>\n\n\n\n The MicroSD_SW pin in the schematic design shown above is used for “SD Card Presence Detection”, and you can read its state in software if needed.<\/p>\n\n\n\n Also keep in mind that all SDMMC pins, except the CLK, need to be pulled up either in hardware or in software configurations of the STM32 GPIO pins. While routing the DATA lines during the PCB design, make sure the lines are matched to maximize signal integrity for high-speed communication.<\/p>\n\n\n For quick prototyping and project idea testing, you can use any STM32 development board that has a target microcontroller with an internal SDMMC interface as well as the hardware SD Card socket onboard. For me, I’ve used This STM32H750 Development Board<\/a><\/strong> from WeAct<\/a><\/strong>. But you can use any other STM32 development board that satisfies those two conditions.<\/p>\n\n\n\n However, if you’ve got an STM32 development board that doesn’t have an SD card slot but its target microcontroller still has an SDMMC interface, you can use an SD Card breakout board like this and wire them up together as shown in the schematic diagram shown earlier.<\/p>\n\n\n\n Buy an SD Card SDMMC Breakout Board<\/strong> (on Amazon)<\/a><\/p>\n\n\n\n In this example project, our ultimate goal is to test the STM32 SDMMC<\/strong> interface with an SD Card and also test the functionalities provided by the FatFS<\/strong> library and use it to create a text file, write to it, read the file, modify the existing file, and delete the file. We’ll monitor the progress of this test sequence using USB CDC (VCP)<\/a><\/strong> messages printed to the serial monitor on the PC.<\/p>\n\n\n\n SD Card Tests Included in This Project:<\/strong><\/p>\n\n\n\n Please, follow The step-by-step guide below to create the project, configure the needed hardware peripherals in CubeMX, and run the test project on your STM32 dev board.<\/p>\n\n\n Step #1<\/strong><\/p>\n\n<\/div>\n\n\n Create a New Project in STM32CubeMX<\/strong><\/p>\n\n\n\n The first step is to head over to STM32CubeMX, create a new project, enable the SWD (serial wire debug), enable the external HSE oscillator, and configure the RCC clock.<\/p>\n\n\n\n Make sure that the USB clock & SDMMC clock are both 48MHz<\/strong>.<\/p>\n\n\n Step #2<\/strong><\/p>\n\n<\/div>\n\n\n Configure 1x USB CDC Device<\/strong><\/p>\n\n\n\n Enable a USB CDC device to be used as a serial communication with the PC through a Windows virtual COM port (VCP). Leave the default settings as is, no need to change them.<\/p>\n\n\n Step #3<\/strong><\/p>\n\n<\/div>\n\n\n Configure The SDMMC Module To Be Used For SD Card Interfacing<\/strong><\/p>\n\n\n\n Here, I’m using the SDMMC 4-Bit mode, and increase the SDMMC clock divider factor a bit to stay below the speed limit of your SD card’s slass.<\/p>\n\n\n\n <\/p>\n\n\n Step #4<\/strong><\/p>\n\n<\/div>\n\n\n Enable The FatFS Library<\/strong><\/p>\n\n\n\n Edit the library configurations as shown below.<\/p>\n\n\n\n <\/p>\n\n\n\n Once you’re done with CubeMX configurations, generate the project code and head over to STM32CubeIDE.<\/p>\n\n\n Step #5<\/strong><\/p>\n\n<\/div>\n\n\n Copy The Project’s Code Below into Your Main.c File<\/strong><\/p>\n\n\n\n Build The Project, Flash The Code To The STM32 Board, and Start Testing!<\/strong><\/p>\n\n\n\n <\/p>\n\n\n The Application Code For This Example (main.c)<\/strong><\/span><\/p>\n\n\n <\/p>\n\n\n This is my test setup for this example project. I\u2019m using a 16GB SD card as well as a USB cable to connect the STM32 USB CDC to my PC as a virtual COM port. The SD card socket is already soldered to the top side of my\u00a0STM32H750 Development Board<\/a><\/strong>\u00a0as stated earlier according to the schematic design figure that I did also show earlier in this tutorial. That\u2019s all about it!<\/p>\n\n\n\n <\/p>\n\n\n Here is the test result that’s printed on the serial monitor.<\/p>\n\n\n\n <\/p>\n\n\n\n And this is the content of the SD card after running this example project as shown on my PC file manager.<\/p>\n\n\n\n <\/p>\n\n\n\n Setting up the STM32 SDMMC DMA is very similar to what we’ve done in the STM32 SDIO DMA Tutorial<\/a><\/strong> previously. You can refer to the SDIO + DMA tutorial to see how it’s configured and use the exact same code provided in the example of this tutorial and it should work just as fine.<\/p>\n\n\n This article will give more in-depth information about configuring an STM32 SDIO interface with DMA channels for Rx\/Tx operations and test its functionality in an example project.<\/p>\n\n<\/div><\/div><\/div>\n<\/div>\n<\/div><\/div>\n\n It may not be very obvious that your final project will be handling the SDMMC (read\/write) operations using DMA. However, you can check the following files to make sure that the application-level drivers are using the DMA channels under the hood.<\/p>\n\n\n\n FATFS\/Target\/sd_diskio.c<\/strong><\/p>\n\n\n\n You\u2019ll find the\u00a0 FATFS\/Target\/bsp_driver_sd.c<\/strong><\/p>\n\n<\/div><\/div>\n\n\n Required Parts For STM32 Examples<\/strong><\/p>\n\n\n\n All the example Code\/LABs\/Projects in this STM32 Series of Tutorials are done using the Dev boards & Electronic Parts Below:<\/p>\n\n\n\nTable of Contents<\/h2>\n
\n
\n\n\nSTM32 SDMMC<\/strong><\/h2>\n\n\n
STM32 SPI Vs SDIO Vs SDMMC<\/strong><\/h3>\n\n\n
STM32 SDMMC Features<\/strong><\/h3>\n\n\n
\n
\n\n\nSTM32 SDMMC SD Card Interfacing<\/strong><\/strong><\/h2>\n\n\n
Preparing The SD Card<\/strong><\/h3>\n\n\n
STM32 SDMMC SD Card Hardware Design<\/strong><\/h3>\n\n\n
Development Board<\/strong><\/h3>\n\n\n
\n\n\nSTM32 SDMMC (4-Bit Mode) FatFS Example Project<\/strong><\/h2>\n\n\n
\n
f_puts()<\/code> function<\/li>\n\n\n\n
f_write()<\/code> function<\/li>\n\n\n\n
f_gets()<\/code> function<\/li>\n\n\n\n
f_read()<\/code> function<\/li>\n\n\n\n
STM32 SDMMC SD Card FatFS Example Code<\/strong><\/h3>\n\n\n
\/*\n * LAB Name: STM32 SDMMC SD Card Interfacing Example\n * Author: Khaled Magdy\n * For More Info Visit: www.DeepBlueMbedded.com\n*\/\n#include \"main.h\"\n#include \"fatfs.h\"\n#include \"usb_device.h\"\n#include \"usbd_cdc_if.h\"\n#include <stdio.h>\n#include <string.h>\n\nSD_HandleTypeDef hsd1;\nchar TxBuffer[250];\n\nvoid SystemClock_Config(void);\nstatic void MPU_Config(void);\nstatic void MX_GPIO_Init(void);\nstatic void MX_SDMMC1_SD_Init(void);\nstatic void SDIO_SDCard_Test(void);\n\nstatic void USB_CDC_Print(char* TxStr)\n{\n while(CDC_Transmit_FS((uint8_t*)TxStr, strlen(TxStr)) == USBD_BUSY);\n}\n\nint main(void)\n{\n MPU_Config();\n HAL_Init();\n SystemClock_Config();\n MX_GPIO_Init();\n MX_SDMMC1_SD_Init();\n MX_FATFS_Init();\n MX_USB_DEVICE_Init();\n \/\/ Test The SDIO SD Card Interface\n HAL_Delay(5000); \/\/ This delay is not mandatory but it gives me some time to connect the USB cable and open the terminal\n SDIO_SDCard_Test();\n\n while (1)\n {\n\t \/\/ Nothing To Do Here!\n }\n}\n\nstatic void SDIO_SDCard_Test(void)\n{\n FATFS FatFs;\n FIL Fil;\n FRESULT FR_Status;\n FATFS *FS_Ptr;\n UINT RWC, WWC; \/\/ Read\/Write Word Counter\n DWORD FreeClusters;\n uint32_t TotalSize, FreeSpace;\n char RW_Buffer[200];\n do\n {\n \/\/------------------[ Mount The SD Card ]--------------------\n FR_Status = f_mount(&FatFs, SDPath, 1);\n if (FR_Status != FR_OK)\n {\n sprintf(TxBuffer, \"Error! While Mounting SD Card, Error Code: (%i)\\r\\n\", FR_Status);\n USB_CDC_Print(TxBuffer);\n break;\n }\n sprintf(TxBuffer, \"SD Card Mounted Successfully! \\r\\n\\n\");\n USB_CDC_Print(TxBuffer);\n \/\/------------------[ Get & Print The SD Card Size & Free Space ]--------------------\n f_getfree(\"\", &FreeClusters, &FS_Ptr);\n TotalSize = (uint32_t)((FS_Ptr->n_fatent - 2) * FS_Ptr->csize * 0.5);\n FreeSpace = (uint32_t)(FreeClusters * FS_Ptr->csize * 0.5);\n sprintf(TxBuffer, \"Total SD Card Size: %lu Bytes\\r\\n\", TotalSize);\n USB_CDC_Print(TxBuffer);\n sprintf(TxBuffer, \"Free SD Card Space: %lu Bytes\\r\\n\\n\", FreeSpace);\n USB_CDC_Print(TxBuffer);\n \/\/------------------[ Open A Text File For Write & Write Data ]--------------------\n \/\/Open the file\n FR_Status = f_open(&Fil, \"MyTextFile.txt\", FA_WRITE | FA_READ | FA_CREATE_ALWAYS);\n if(FR_Status != FR_OK)\n {\n sprintf(TxBuffer, \"Error! While Creating\/Opening A New Text File, Error Code: (%i)\\r\\n\", FR_Status);\n USB_CDC_Print(TxBuffer);\n break;\n }\n sprintf(TxBuffer, \"Text File Created & Opened! Writing Data To The Text File..\\r\\n\\n\");\n USB_CDC_Print(TxBuffer);\n \/\/ (1) Write Data To The Text File [ Using f_puts() Function ]\n f_puts(\"Hello! From STM32 To SD Card Over SDMMC, Using f_puts()\\n\", &Fil);\n \/\/ (2) Write Data To The Text File [ Using f_write() Function ]\n strcpy(RW_Buffer, \"Hello! From STM32 To SD Card Over SDMMC, Using f_write()\\r\\n\");\n f_write(&Fil, RW_Buffer, strlen(RW_Buffer), &WWC);\n \/\/ Close The File\n f_close(&Fil);\n \/\/------------------[ Open A Text File For Read & Read Its Data ]--------------------\n \/\/ Open The File\n FR_Status = f_open(&Fil, \"MyTextFile.txt\", FA_READ);\n if(FR_Status != FR_OK)\n {\n sprintf(TxBuffer, \"Error! While Opening (MyTextFile.txt) File For Read.. \\r\\n\");\n USB_CDC_Print(TxBuffer);\n break;\n }\n \/\/ (1) Read The Text File's Data [ Using f_gets() Function ]\n f_gets(RW_Buffer, sizeof(RW_Buffer), &Fil);\n sprintf(TxBuffer, \"Data Read From (MyTextFile.txt) Using f_gets():%s\", RW_Buffer);\n USB_CDC_Print(TxBuffer);\n \/\/ (2) Read The Text File's Data [ Using f_read() Function ]\n f_read(&Fil, RW_Buffer, f_size(&Fil), &RWC);\n sprintf(TxBuffer, \"Data Read From (MyTextFile.txt) Using f_read():%s\", RW_Buffer);\n USB_CDC_Print(TxBuffer);\n \/\/ Close The File\n f_close(&Fil);\n sprintf(TxBuffer, \"File Closed! \\r\\n\\n\");\n USB_CDC_Print(TxBuffer);\n \/\/------------------[ Open An Existing Text File, Update Its Content, Read It Back ]--------------------\n \/\/ (1) Open The Existing File For Write (Update)\n FR_Status = f_open(&Fil, \"MyTextFile.txt\", FA_OPEN_EXISTING | FA_WRITE);\n FR_Status = f_lseek(&Fil, f_size(&Fil)); \/\/ Move The File Pointer To The EOF (End-Of-File)\n if(FR_Status != FR_OK)\n {\n sprintf(TxBuffer, \"Error! While Opening (MyTextFile.txt) File For Update.. \\r\\n\");\n USB_CDC_Print(TxBuffer);\n break;\n }\n \/\/ (2) Write New Line of Text Data To The File\n FR_Status = f_puts(\"This New Line Was Added During File Update!\\r\\n\", &Fil);\n f_close(&Fil);\n memset(RW_Buffer,'\\0',sizeof(RW_Buffer)); \/\/ Clear The Buffer\n \/\/ (3) Read The Contents of The Text File After The Update\n FR_Status = f_open(&Fil, \"MyTextFile.txt\", FA_READ); \/\/ Open The File For Read\n f_read(&Fil, RW_Buffer, f_size(&Fil), &RWC);\n sprintf(TxBuffer, \"Data Read From (MyTextFile.txt) After Update:\\r\\n%s\", RW_Buffer);\n USB_CDC_Print(TxBuffer);\n f_close(&Fil);\n \/\/------------------[ Delete The Text File ]--------------------\n \/\/ Delete The File\n \/*\n FR_Status = f_unlink(MyTextFile.txt);\n if (FR_Status != FR_OK){\n sprintf(TxBuffer, \"Error! While Deleting The (MyTextFile.txt) File.. \\r\\n\");\n USC_CDC_Print(TxBuffer);\n }\n *\/\n } while(0);\n \/\/------------------[ Test Complete! Unmount The SD Card ]--------------------\n FR_Status = f_mount(NULL, \"\", 0);\n if (FR_Status != FR_OK)\n {\n sprintf(TxBuffer, \"\\r\\nError! While Un-mounting SD Card, Error Code: (%i)\\r\\n\", FR_Status);\n USB_CDC_Print(TxBuffer);\n } else{\n sprintf(TxBuffer, \"\\r\\nSD Card Un-mounted Successfully! \\r\\n\");\n USB_CDC_Print(TxBuffer);\n }\n}<\/pre>\n\n\n
Test Setup<\/strong><\/h4>\n\n\n
Testing Result<\/strong><\/h4>\n\n\n
\n\n\nSTM32 SDMMC DMA Example<\/strong><\/h2>\n\n\n
SD_read()<\/code>\u00a0&\u00a0
SD_write()<\/code>\u00a0functions are using the DMA versions of the
BSP_SD_ReadBlocks_DMA()<\/code> &
BSP_SD_WriteBlocks_DMA()<\/code> functions. You can also find their implementations in the source file below.<\/p>\n\n\n\n
\n\n\n\n