{"id":12637,"date":"2024-04-06T03:32:10","date_gmt":"2024-04-06T01:32:10","guid":{"rendered":"https:\/\/deepbluembedded.com\/?p=12637"},"modified":"2024-04-06T11:55:54","modified_gmt":"2024-04-06T09:55:54","slug":"stm32-sdio-dma-example","status":"publish","type":"post","link":"https:\/\/deepbluembedded.com\/stm32-sdio-dma-example\/","title":{"rendered":"STM32 SDIO DMA Example"},"content":{"rendered":"\n
In this tutorial, we’ll learn how to use STM32 SDIO + DMA With FatFS Library For SD Card Interfacing<\/strong>. You’ll learn how to configure the STM32 SDIO With DMA enabled for faster data read\/write operations with less CPU intervention. Without further ado, let’s get right into it!<\/p>\n\n\n In this previous tutorial, we discussed the STM32 SDIO interface in detail and created an example project for STM32 SD card interfacing using the SDIO interface with CPU-blocking read\/write operations. Therefore, in this tutorial, we’ll expand more on the topic by adding DMA Rx\/Tx channels for both read\/write operations of the SDIO to accelerate the performance and also save as much CPU time as possible.<\/p>\n\n\n\n It’s highly recommended to check out the previous STM32 SDIO Tutorial as a starting point (if you’ve not already completed it).<\/p>\n\n\n This tutorial will give you more in-depth information about the STM32 SDIO interface and how to use it with FatFS for SD Card interfacing with a handful of test examples.<\/p>\n\n<\/div><\/div><\/div>\n<\/div>\n<\/div><\/div>\n\n\n In this example project, we’ll test the STM32 SDIO + DMA<\/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 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 SDIO Module To Be Used For SD Card Interfacing<\/strong><\/p>\n\n\n\n Here, I’m using the SDIO 1-Bit mode while the rest of the settings are left as default.<\/p>\n\n\n\n <\/p>\n\n\n\n Make sure that all SDIO GPIO pins are internally, or externally, pulled-up except for the CLK line.<\/p>\n\n\n\n <\/p>\n\n\n\n In the SDIO DMA settings tab, add 2x DMA channels for (Rx & Tx) as shown below.<\/p>\n\n\n\n <\/p>\n\n\n\n In the SDIO NVIC tab, enable the SDIO global interrupt as shown below.<\/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 In the FatFS advanced settings tab, enable the DMA template.<\/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’m using a 2GB 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 bottom of my STM32F405 Development Board<\/a><\/strong> as stated earlier according to the schematic design figure that I did also show earlier in this tutorial. That’s 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 It may not be very obvious that this example project is handling the SDIO (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’ll find the FATFS\/Target\/bsp_driver_sd.c<\/strong><\/p>\n\n<\/div><\/div>\n\n The advantage of using DMA over the polling version of SD read\/write operations will be obviously visible when you’re attempting to read\/write big chunks of data into large files. This is when you can notice major CPU time savings and CPU load reduction overall.<\/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 SDIO (Secure Digital IO)<\/strong><\/h2>\n\n\n
\n\n\nSTM32 SDIO DMA Example<\/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 SDIO DMA Example Code<\/strong><\/h3>\n\n\n
\/*\n * LAB Name: STM32 SDIO + DMA 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 hsd;\nDMA_HandleTypeDef hdma_sdio_rx;\nDMA_HandleTypeDef hdma_sdio_tx;\nchar TxBuffer[250];\n\nvoid SystemClock_Config(void);\nstatic void MX_GPIO_Init(void);\nstatic void MX_DMA_Init(void);\nstatic void MX_SDIO_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\n HAL_Init();\n SystemClock_Config();\n MX_GPIO_Init();\n MX_DMA_Init();\n MX_SDIO_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\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 SDIO + DMA, 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 SDIO + DMA, 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
SD_read()<\/code> &
SD_write()<\/code> functions are using the DMA versions of the BSP_SD_ReadBlocks_DMA() & BSP_SD_WriteBlocks_DMA() functions. You can also find their implementations in the source file below.<\/p>\n\n\n\n
\n\n\n\n