cancel
Showing results for 
Search instead for 
Did you mean: 

SDMMC fixed

Jack3
Senior II

I already reported this bug up at previous versions of the STM32H7 firmware.

Now I'm using

  • STM32CubeMX 5.6.1
  • STM32CubeIDE 1.3.1 (arm-none-eabi-gcc 7.3.1)
  • STM32Cube FW_H7 V1.7.0

For those who find SDMMC not working, there still is an obvious bug , the way the code is generated by STM32CubeMX. If we look at the below code:

void MX_SDMMC1_SD_Init(void)
{
 
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 2;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
 
}

We seem to be missing a few lines in there.

EDIT: DTK mentioned this, because the Init code was missing the initialization functions, I also changed the bits to 8 because of thinking of eMMC I also use. But this was for SD-cards, where I use 4-bit sofar, a slip of the pen. Now Clive just did show that 8-bit SD-Cards also exist, so it still would be valid. In my working code, I did correct fine though, and it works, because after generation I always add and change things and don't let STM32CubeMX modify it anymore. Because not everywhere always are comment lines where I need to change things.

This is just about wondering why the generated code is missing the init function after filling the structure. The ioc file is below, maybe there is an error in there.

Now I need to test if STM32CubeMX always leaves the init function out, both for SD and MMC.

So now I added SD and MMC parts.

SD:

void MX_SDMMC1_SD_Init(void)
{
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 2;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
  
  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }
}

MMC:

void MX_SDMMC1_MMC_Init(void)
{
  hmmc1.Instance = SDMMC1;
  hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hmmc1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE;
  hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
  hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
  hmmc1.Init.ClockDiv = 0;
  if (HAL_MMC_Init(&hmmc1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

I hope this helps somebody.

It brought his to ST attention, and it is still like this, maybe I do something wrong?

I'm mainly using HAL.

I'm also not sure why they removed __FILE__, __LINE__ from the Error_Handler. How would that benefit?

I hope the suggestions will finally make it o the ST developers in charge. But...

The complete sdmmc.c file, unmodified looks like:

/**
  ******************************************************************************
  * File Name          : SDMMC.c
  * Description        : This file provides code for the configuration
  *                      of the SDMMC instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
 
/* Includes ------------------------------------------------------------------*/
#include "sdmmc.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
SD_HandleTypeDef hsd1;
 
/* SDMMC1 init function */
 
void MX_SDMMC1_SD_Init(void)
{
 
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_8B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 2;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
 
}
 
void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspInit 0 */
 
  /* USER CODE END SDMMC1_MspInit 0 */
    /* SDMMC1 clock enable */
    __HAL_RCC_SDMMC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**SDMMC1 GPIO Configuration    
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 
                          |GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
    /* SDMMC1 interrupt Init */
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspInit 1 */
 
  /* USER CODE END SDMMC1_MspInit 1 */
  }
}
 
void HAL_SD_MspDeInit(SD_HandleTypeDef* sdHandle)
{
 
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspDeInit 0 */
 
  /* USER CODE END SDMMC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SDMMC1_CLK_DISABLE();
  
    /**SDMMC1 GPIO Configuration    
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD 
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 
                          |GPIO_PIN_12);
 
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
 
    /* SDMMC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspDeInit 1 */
 
  /* USER CODE END SDMMC1_MspDeInit 1 */
  }
} 
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

10 REPLIES 10
TDK
Guru

There is no 8-bit mode for SD cards. Your code also doesn't have the user code block comments. Are you sure that was generated by CubeMX and not something that you modified?

I just generated a new STM32H743 project with the same versions you call out and could not reproduce. Both 8-bit MMC and 4-bit SD initialization code works fine.

/**
  * @brief SDMMC1 Initialization Function
  * @param None
  * @retval None
  */
static 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_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 0;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDMMC1_Init 2 */
 
  /* USER CODE END SDMMC1_Init 2 */
 
}

/**
  * @brief SDMMC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SDMMC1_MMC_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 */
  hmmc1.Instance = SDMMC1;
  hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
  hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hmmc1.Init.ClockDiv = 0;
  hmmc1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
  if (HAL_MMC_Init(&hmmc1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDMMC1_Init 2 */
 
  /* USER CODE END SDMMC1_Init 2 */
 
}

If you feel a post has answered your question, please click "Accept as Solution".
Jack3
Senior II

Yes, I think so. I checked: STM32CubeMX 5.6.1

sdmmc.c:

/**
  ******************************************************************************
  * File Name          : SDMMC.c
  * Description        : This file provides code for the configuration
  *                      of the SDMMC instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
 
/* Includes ------------------------------------------------------------------*/
#include "sdmmc.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
SD_HandleTypeDef hsd1;
 
/* SDMMC1 init function */
 
void MX_SDMMC1_SD_Init(void)
{
 
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_8B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 2;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
 
}
 
void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspInit 0 */
 
  /* USER CODE END SDMMC1_MspInit 0 */
    /* SDMMC1 clock enable */
    __HAL_RCC_SDMMC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**SDMMC1 GPIO Configuration    
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 
                          |GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
    /* SDMMC1 interrupt Init */
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspInit 1 */
 
  /* USER CODE END SDMMC1_MspInit 1 */
  }
}
 
void HAL_SD_MspDeInit(SD_HandleTypeDef* sdHandle)
{
 
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspDeInit 0 */
 
  /* USER CODE END SDMMC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SDMMC1_CLK_DISABLE();
  
    /**SDMMC1 GPIO Configuration    
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD 
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 
                          |GPIO_PIN_12);
 
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
 
    /* SDMMC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspDeInit 1 */
 
  /* USER CODE END SDMMC1_MspDeInit 1 */
  }
} 
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

I did not modify this.

Please find the ioc file below.

Jack3
Senior II

ioc file

Hi TDK, thanks for trying that. I confirm it is an inconsistent result.

  

I use the SDMMC peripheral in 8-bits mode with 8-bit eMMC memory cards (16GB) or in 4-bits mode with SD-Cards.

I noticed the incomplete init function in the generated files, with no warning.

This one was for SD.

eMMC 8-Bit and DDR on both H7 and L4+ platforms, works quite well, 64 GB and 128 GB, good for automotive temps and high vibration environments.

MMCPlus (MMC+) cards had an 8-bit flavour, have a couple, but the sockets are impossible to find now.

0693W000001cdWuQAI.jpg

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

> And I didn't mention an SD-card, did I?

The code you proposed in the OP has SD initialization code (not MMC), as shown in the function name and the HAL_SD_Init() call, and it sets the bus to 8-bit. That is not a supported configuration. Flip over an SD card and you will not find enough pins for 8 data lines.

This is the code you proposed:

void MX_SDMMC1_SD_Init(void)
{
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_8B; // <--- 8 bits
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 2;
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_NOT_PRESENT;
  
  if (HAL_SD_Init(&hsd1) != HAL_OK) // <--- SD, not MMC
  {
    Error_Handler();
  }
}

If you feel a post has answered your question, please click "Accept as Solution".

Hi Clive thanks!

It also works well on the F7.

In the past I modified the ST library for the F7 to support greater capacities than 2GB of eMMC. Maybe the newer firmware for F7 has been fixed.

I use it in high vibration environments, on ships, environmental humidity counts too, so no SD-cards slots there.

Good catch TDK! I added a different number of bits thinking of my eMMC but this was not for that. But Clive now did show 8-bit SD-Cards, which I didn't discover yet, interesting. So it still seemed valid.

In the initial post added the eMMC stuff too now.

But I just need to figure why STM32CubeMX didn't insert the init function lines. I should both try SD and MMC, and see what happens.

Normally what got generated isn't an issue, as I manually add and adjust things to my needs after generation, and don't let CubeMX touch my code a second time.

There were occasions where I modified libraries, for example for F7 to support greater than 2GB eMMC chips. I don't now if it is now supported out of the box with the latest F7 firmware. Once everything works fine, I do not often update firmware because there is newer. There must be a good reason for it.

I had merged my eMMC support into the SDIO/SDMMC forks, it didn't make sense to have two near identical​ pieces of code and allowed me to get it running on F4 and other platforms. Also added in EXTCSD support early on as all the test parts (ODRIOD) where relatively large, 8GB and above.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..