Skip to main content
Associate
August 11, 2025
Question

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

  • August 11, 2025
  • 5 replies
  • 468 views

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

5 replies

Technical Moderator
August 12, 2025

Hello @KumarMayank99 

Please refer to the example below:

Projects/STM32H743I-EVAL/Applications/FatFs/FatFs_uSD_Standalone

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Saket_Om"
Associate
August 12, 2025

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

 

Technical Moderator
August 12, 2025
"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Saket_Om"
Associate
August 13, 2025

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
August 14, 2025

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
August 14, 2025

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 VenmoUp vote any posts that you find helpful, it shows what's working..
Associate
August 14, 2025

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