cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5 SDMMC1 FATFS integration

Julian_
Associate III

Hi guys,

 

I'm trying to implement a sd card interface for the STM32U5 series using SDMMC1 interface. Since there is no native FATFS support over CubeMX, I guess, I started to use the generic fat file module from elm-chan.

Basic configuration:

1. SDMMC1 in SD 4 bits wide bus mode, clock divider 4, power safe for clock enabled, no hardware control, no external transceiver, SDMMC1 global interrupt enabled, gpios pullup all enabled despite of clk

2. Modified diskio.c see code example

The interface works and I can also kind of work with fatFS, f_mount, f_open works basiclly, but sometimes I got a FR_DISK_ERR. On my scope I can see that the SD clock is always on when the error occures. So I think there is an issue with the low level driver level or better say somethimg is going on with the diskio layer. Please see the attached pictures of working f_mount and f_open and the f_open where the clock doesn't stop.

I'm using FreeRTOS and I have a dedicated SD_Card Task.

Julian__0-1746000981422.png

My modified diskio.c:

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "stm32u5xx_hal.h"
#include "sdmmc.h"

/* Definitions of physical drive number for each drive */
#define DEV_RAM		0	/* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC		1	/* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB		2	/* Example: Map USB MSD to physical drive 2 */

extern SD_HandleTypeDef hsd1;
DSTATUS Stat = STA_NOINIT;


/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
    if (pdrv == 0) {
        HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(&hsd1);

        if (state == HAL_SD_CARD_TRANSFER || state == HAL_SD_CARD_READY) {
            return RES_OK;       // Card is ready
        } else {
            return STA_NOINIT;   // Card is not ready
        }
    }
    return STA_NOINIT;           // Only drive 0 supported
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
    if (pdrv != 0) return STA_NOINIT; // Only support drive 0 for SD

    if (!(Stat & STA_NOINIT)) // If already initialized
    {
        return RES_OK; // No need to reinitialize
    }

    // Otherwise, maybe check card presence etc if needed
    if (HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER) // Already ready
    {
        Stat &= ~STA_NOINIT; // Clear the NOINIT bit
        return RES_OK;
    }

    // (Optional) If you really need HAL_SD_Init() again, only under safe conditions

    return STA_NOINIT; // Fail if not ready
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
    if (pdrv != 0) return RES_PARERR;

    if (Stat & STA_NOINIT) return RES_NOTRDY;

    HAL_StatusTypeDef hal_res = HAL_SD_ReadBlocks(&hsd1, buff, sector, count, HAL_MAX_DELAY);

    if (hal_res == HAL_OK)
    {
        /* Wait until SD card is ready */
        uint32_t timeout = HAL_GetTick() + 500; // 500ms timeout
        while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER)
        {
            if (HAL_GetTick() > timeout)
            {
                return RES_ERROR; // Timeout, SD busy too long
            }
            osDelay(1); // yield to other FreeRTOS tasks
        }
        return RES_OK;
    }

    return RES_ERROR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{

	if (pdrv != 0) return RES_PARERR;

	if (Stat & STA_NOINIT) return RES_NOTRDY;

	HAL_StatusTypeDef hal_res = HAL_SD_WriteBlocks(&hsd1, (uint8_t*)buff, sector, count, HAL_MAX_DELAY);

	if (hal_res == HAL_OK)
	{
		/* Wait until SD card is ready */
		uint32_t timeout = HAL_GetTick() + 500; // 500ms timeout
		while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER)
		{
			if (HAL_GetTick() > timeout)
			{
				return RES_ERROR; // Timeout
			}
			osDelay(1); // yield in FreeRTOS
		}
		return RES_OK;
	}

	return RES_ERROR;
}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
    if (pdrv != 0) return RES_PARERR;

    HAL_SD_CardInfoTypeDef info;
    HAL_SD_GetCardInfo(&hsd1, &info);

    switch (cmd) {
        case GET_SECTOR_COUNT:
            *(DWORD*)buff = info.LogBlockNbr;
            return RES_OK;
        case GET_SECTOR_SIZE:
            *(WORD*)buff = 512;
            return RES_OK;
        case GET_BLOCK_SIZE:
            *(DWORD*)buff = info.LogBlockSize / 512;
            return RES_OK;
    }
    return RES_PARERR;
}

Initalize SDMMC and HAL_SD:

void MX_SDMMC1_SD_Init(void)
{

  /* USER CODE BEGIN SDMMC1_Init 0 */

  /* USER CODE END SDMMC1_Init 0 */

  /* USER CODE BEGIN SDMMC1_Init 1 */

  /* USER CODE END SDMMC1_Init 1 */
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 4;
  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDMMC1_Init 2 */

  /* USER CODE END SDMMC1_Init 2 */

}

 Would be great if I get some input from you guys - how I can fix this.

 

Thanks,

Julian

19 REPLIES 19

Hello @Julian_ 

what is the time base timer you are using? 

Could you re-enable interrupt before HAL_Delay. 

__enable_irq();

Could you please set the priorities of Systick interrupts higher (Lower numerically) than SDMMC.  Also try to remove the initialisation of all other peripheral. 

 

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
Saket_Om
ST Employee

@Julian_ 

Any update concerning this issue?

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

@Saket_Om 

unfortunally no positive update...

The interrupt priority for sysTick is the highest see .ioc config: 

Julian__0-1747229362929.png

Enabling the interrupts before HAL-Delay has also no influence to the issue:

  HAL_Delay(50); //this delay works

  while (1){

	  // Mount SD card
	  fres = f_mount(&fs, "0", 1);
	  if (fres != FR_OK) {
		  printf("Mount failed: %d\n", fres);
		  //return;
	  }
	  printf("Mount successful.\n");

	  __enable_irq(); //no influence on issue
	  HAL_Delay(20); //<-- delay doesnt work

 

I also disabled UART DMA initalization before the FATfs Test. 

In my opinion anything during f_mount is responsible for this behaviour but I don't know what.

 

Systick source is: systick_source = SYSTICK_CLKSOURCE_HCLK;

Do you have some input how to move on?

Thanks,

Julian

 

Hello @Julian_ 

You did check with priorities of Timer (Timer used as time base) interrupts higher (Lower numerically) than SDMMC.  

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

@Saket_Omwhen Time base: TIM2 global interurrupt priority is set to 4 and SDMMC1 global interrupt to 5 the test code finally works:

Julian__0-1747237849698.png

Runs in a while true loop and I checked the scope, seems to work:

Julian__1-1747237982281.png

maybe this sequence is a little bit suspicious, but all in all there is not the "never-ending-clock-issue":

Julian__2-1747238005615.png

When running or accesing the sd card over fatfs in a rtos task the issue still appears:

Julian__3-1747238111074.png

So I guess we can say that HAL Layer works, fatfs layer works but with the rtos it doesn't work. Please note that you can read files over fatfs in rtos to but sometimes there is that issue - seems like that maybe the hal driver for sdmmc is interrupted by the rtos sheduler or similar...

 

Any hints how to move on?

 

Best,

Julian

 

 

 

Hello @Julian_ 

When using FreeRTOS, ensure that interrupt priorities are not set higher (i.e., lower numerical values) than the default priority level of FreeRTOS, which is 5.

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY  5
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

@Julian_ 

Any update on this thread?

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

@Saket_Omunfortunally no. I tried to change the interrupt priorities according to the

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY  5

but this doesn't work well. In addition to this I also disabled the SDMMC1 interface interrupt, because we're using the interface in pulling mode, see fatfs diskio.c I already shared in this thread.

Maybe a general questions regarding this issue:

1) Is it possible/recommended to use sdmmc in polling mode with RTOS? I think that should be possible, because in the STM32CubeH7 package there is also one integration in polling mode (with HAL_SD_ReadBlocks, HAL_SD_WriteBlocks) and another with DMA.

 

Thanks for your support.

 

Best,

Julian


@Julian_ wrote:

1) Is it possible/recommended to use sdmmc in polling mode with RTOS? I think that should be possible, because in the STM32CubeH7 package there is also one integration in polling mode (with HAL_SD_ReadBlocks, HAL_SD_WriteBlocks) and another with DMA.


While it is possible, it is not advisable. For transferring a small amount of data, polling mode is recommended.

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

@Saket_Om 

Another long debug session past by without finding a solution for this issue. Do you have any input how to move on with this?

Are there some example projects/resources available for the STM32U5A9 using FatFS and RTOS?

I'm stuck right now. Thanks.