Skip to main content
Associate
Aug 11, 2025 1:06 PM UTC
Question

Need Disk i/o.c for mmc flash for FATFS

Hi all,

I am using the MTFC8GAMALNA-AAT 8GB flash memory via SDMMC1, operating in MMC 4-bit wide bus mode, along with FATFS (M7). I now require the diskio.c file. Kindly provide it, or if you have any related example code, please share that as well. Please note that I do not want to use DMA or an RTOS for this implementation.

Thanks

This topic has been closed for replies.

7 replies

ST Technical Moderator
Aug 12, 2025 10:32 AM UTC

Hello @KumarMayank99 

Please refer to the example below:

Projects/STM32H743I-EVAL/Applications/FatFs/FatFs_uSD_Standalone

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Associate
Aug 12, 2025 11:55 AM UTC

Hi @Saket_Om ,

Thank you for your response.

I would like to ask if you have a ready-made diskio.c  implementation that supports MMC in 4-bit mode. If available, I would greatly appreciate it if you could share the file or point me in the right direction.

Best regards,

Mayank

 

ST Technical Moderator
Aug 12, 2025 1:15 PM UTC
In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Associate
Aug 13, 2025 5:29 AM UTC

Hi @Saket_Om,

Thank you for your response.

I checked and i found that this is  for SD 4 bits mode bus but  i want mmc 4 bits wide bus.

KumarMayank99_0-1755062932684.png

 

Best regards,

Mayank

Associate
Aug 14, 2025 9:02 AM UTC

Hi @Saket_Om

Below is my user_diskio.c file please chcek ones is it correct or need to modify .

 

 

 

/* Includes ------------------------------------------------------------------*/

#include <string.h>

#include "ff_gen_drv.h"

 

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

 

/* Private variables ---------------------------------------------------------*/

/* Disk status */

static volatile DSTATUS Stat = STA_NOINIT;

extern MMC_HandleTypeDef hmmc1;

/* USER CODE END DECL */

 

/* Private function prototypes -----------------------------------------------*/

DSTATUS USER_initialize (BYTE pdrv);

DSTATUS USER_status (BYTE pdrv);

DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);

#if _USE_WRITE == 1

DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);

#endif /* _USE_WRITE == 1 */

#if _USE_IOCTL == 1

DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);

#endif /* _USE_IOCTL == 1 */

 

Diskio_drvTypeDef USER_Driver =

{

USER_initialize,

USER_status,

USER_read,

#if _USE_WRITE

USER_write,

#endif /* _USE_WRITE == 1 */

#if _USE_IOCTL == 1

USER_ioctl,

#endif /* _USE_IOCTL == 1 */

};

 

/* Private functions ---------------------------------------------------------*/

 

/**

* @brief Initializes a Drive

* @param pdrv: Physical drive number (0..)

* @retval DSTATUS: Operation status

*/

DSTATUS USER_initialize(BYTE pdrv)

{

Stat = STA_NOINIT;

 

if (pdrv != 0)

return Stat;

 

if (HAL_MMC_InitCard(&hmmc1) == HAL_OK)

{

// Configure 4-bit bus width

if (HAL_MMC_ConfigWideBusOperation(&hmmc1, SDMMC_BUS_WIDE_4B) == HAL_OK)

{

Stat &= ~STA_NOINIT; // Clear NOINIT flag

}

}

 

return Stat;

}

 

 

/**

* @brief Gets Disk Status

* @param pdrv: Physical drive number (0..)

* @retval DSTATUS: Operation status

*/

DSTATUS USER_status(BYTE pdrv)

{

if (pdrv != 0)

return STA_NOINIT;

if (HAL_MMC_GetCardState(&hmmc1)==HAL_MMC_CARD_TRANSFER)

return RES_OK;

return STA_NOINIT;

}

 

 

/**

* @brief Reads Sector(s)

* @param pdrv: Physical drive number (0..)

* @param *buff: Data buffer to store read data

* @param sector: Sector address (LBA)

* @param count: Number of sectors to read (1..128)

* @retval DRESULT: Operation result

*/

DRESULT USER_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)

{

if (pdrv != 0 || !count)

return RES_PARERR;

if (Stat & STA_NOINIT)

return RES_NOTRDY;

if (HAL_MMC_ReadBlocks(&hmmc1, buff, sector, count, HAL_MAX_DELAY) == HAL_OK)

{

// Wait until card is in transfer state

while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER);

return RES_OK;

}

return RES_ERROR;

}

 

 

/**

* @brief Writes Sector(s)

* @param pdrv: Physical drive number (0..)

* @param *buff: Data to be written

* @param sector: Sector address (LBA)

* @param count: Number of sectors to write (1..128)

* @retval DRESULT: Operation result

*/

#if _USE_WRITE == 1

DRESULT USER_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)

{

if (pdrv != 0 || !count)

return RES_PARERR;

if (Stat & STA_NOINIT)

return RES_NOTRDY;

if (HAL_MMC_WriteBlocks(&hmmc1, (uint8_t*)buff, sector, count, HAL_MAX_DELAY) == HAL_OK)

{

while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER);

return RES_OK;

}

return RES_ERROR;

}

 

#endif /* _USE_WRITE == 1 */

 

/**

* @brief I/O control operation

* @param pdrv: Physical drive number (0..)

* @param cmd: Control code

* @param *buff: Buffer to send/receive control data

* @retval DRESULT: Operation result

*/

#if _USE_IOCTL == 1

DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void *buff)

{

DRESULT res = RES_ERROR;

HAL_MMC_CardInfoTypeDef CardInfo;

if (Stat & STA_NOINIT)

return RES_NOTRDY;

if (pdrv != 0)

return RES_PARERR;

switch (cmd)

{

case CTRL_SYNC:

res = RES_OK;

break;

case GET_SECTOR_COUNT:

HAL_MMC_GetCardInfo(&hmmc1, &CardInfo);

*(DWORD*)buff = CardInfo.LogBlockNbr;

res = RES_OK;

break;

case GET_SECTOR_SIZE:

HAL_MMC_GetCardInfo(&hmmc1, &CardInfo);

*(WORD*)buff = CardInfo.LogBlockSize;

res = RES_OK;

break;

case GET_BLOCK_SIZE:

*(DWORD*)buff = 1; // Usually 1 for MMC unless otherwise specified

res = RES_OK;

break;

default:

res = RES_PARERR;

}

return res;

}

 

#endif /* _USE_IOCTL == 1 */

 

 

 

Tesla DeLorean
Guru
Aug 14, 2025 10:12 AM UTC

Use the code pasting tool via </> icon rather than inline unformatted wall of text.

Should be an MMC example within some releases of H745I-DISCO board.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Associate
Aug 14, 2025 11:04 AM UTC

Hi @Tesla DeLorean @Saket_Om 

Thank you for your response.

I am currently using the STM32H755BIT3 microcontroller.

Could you please review my user_diskio.c file to ensure it is correctly implemented for this MCU? Let me know if any modifications are needed.

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file user_diskio.c
 * @brief This file includes a diskio driver aligned with STM reference logic.
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"
#include "main.h" // In case needed for definitions like HAL_MAX_DELAY

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define MMC_DEFAULT_BLOCK_SIZE 512
#define MMC_TIMEOUT HAL_MAX_DELAY

/* Private variables ---------------------------------------------------------*/
static volatile DSTATUS Stat = STA_NOINIT;
extern MMC_HandleTypeDef hmmc1;

/* Private function prototypes -----------------------------------------------*/
static DSTATUS USER_CheckStatus(BYTE pdrv);
DSTATUS USER_initialize(BYTE pdrv);
DSTATUS USER_status(BYTE pdrv);
DRESULT USER_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
DRESULT USER_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif
#if _USE_IOCTL == 1
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void *buff);
#endif

/* Diskio driver structure ---------------------------------------------------*/
Diskio_drvTypeDef USER_Driver =
{
 USER_initialize,
 USER_status,
 USER_read,
#if _USE_WRITE == 1
 USER_write,
#endif
#if _USE_IOCTL == 1
 USER_ioctl,
#endif
};

/* Private functions ---------------------------------------------------------*/

static DSTATUS USER_CheckStatus(BYTE pdrv)
{
 Stat = STA_NOINIT;

 if (pdrv != 0)
 return Stat;

 if (HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
 Stat &= ~STA_NOINIT;

 return Stat;
}

/**
 * @brief Initializes a Drive
 * @param pdrv: Physical drive number (0..)
 * @retval DSTATUS: Operation status
 */
DSTATUS USER_initialize(BYTE pdrv)
{
 Stat = STA_NOINIT;

 if (pdrv != 0)
 return Stat;

 if (HAL_MMC_InitCard(&hmmc1) == HAL_OK)
 {
 if (HAL_MMC_ConfigWideBusOperation(&hmmc1, SDMMC_BUS_WIDE_4B) == HAL_OK)
 {
 Stat = USER_CheckStatus(pdrv);
 }
 }

 return Stat;
}

/**
 * @brief Gets Disk Status
 * @param pdrv: Physical drive number (0..)
 * @retval DSTATUS: Operation status
 */
DSTATUS USER_status(BYTE pdrv)
{
 return USER_CheckStatus(pdrv);
}

/**
 * @brief Reads Sector(s)
 * @param pdrv: Physical drive number (0..)
 * @param *buff: Data buffer to store read data
 * @param sector: Sector address (LBA)
 * @param count: Number of sectors to read (1..128)
 * @retval DRESULT: Operation result
 */
DRESULT USER_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
 if ((pdrv != 0) || !count)
 return RES_PARERR;

 if (Stat & STA_NOINIT)
 return RES_NOTRDY;

 if (HAL_MMC_ReadBlocks(&hmmc1, buff, sector, count, MMC_TIMEOUT) == HAL_OK)
 {
 while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER);
 return RES_OK;
 }

 return RES_ERROR;
}

/**
 * @brief Writes Sector(s)
 * @param pdrv: Physical drive number (0..)
 * @param *buff: Data to be written
 * @param sector: Sector address (LBA)
 * @param count: Number of sectors to write (1..128)
 * @retval DRESULT: Operation result
 */
#if _USE_WRITE == 1
DRESULT USER_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
 if ((pdrv != 0) || !count)
 return RES_PARERR;

 if (Stat & STA_NOINIT)
 return RES_NOTRDY;

 if (HAL_MMC_WriteBlocks(&hmmc1, (uint8_t *)buff, sector, count, MMC_TIMEOUT) == HAL_OK)
 {
 while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER);
 return RES_OK;
 }

 return RES_ERROR;
}
#endif /* _USE_WRITE == 1 */

/**
 * @brief I/O control operation
 * @param pdrv: Physical drive number (0..)
 * @param cmd: Control code
 * @param *buff: Buffer to send/receive control data
 * @retval DRESULT: Operation result
 */
#if _USE_IOCTL == 1
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
 DRESULT res = RES_ERROR;
 HAL_MMC_CardInfoTypeDef CardInfo;

 if (Stat & STA_NOINIT)
 return RES_NOTRDY;

 if (pdrv != 0)
 return RES_PARERR;

 switch (cmd)
 {
 case CTRL_SYNC:
 res = RES_OK;
 break;

 case GET_SECTOR_COUNT:
 HAL_MMC_GetCardInfo(&hmmc1, &CardInfo);
 *(DWORD *)buff = CardInfo.LogBlockNbr;
 res = RES_OK;
 break;

 case GET_SECTOR_SIZE:
 HAL_MMC_GetCardInfo(&hmmc1, &CardInfo);
 *(WORD *)buff = CardInfo.LogBlockSize;
 res = RES_OK;
 break;

 case GET_BLOCK_SIZE:
 HAL_MMC_GetCardInfo(&hmmc1, &CardInfo);
 *(DWORD *)buff = CardInfo.LogBlockSize / MMC_DEFAULT_BLOCK_SIZE;
 res = RES_OK;
 break;

 default:
 res = RES_PARERR;
 break;
 }

 while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER);

 return res;
}
#endif /* _USE_IOCTL == 1 */

Regard,

Mayank