cancel
Showing results for 
Search instead for 
Did you mean: 

SD Init Failure on STM32H743I-EVAL2 with Example Code

stephenhopkins
Associate

I am using the STM32H743I-EVAL2 and have been trying to get the SD card initialization working. During the execution of HAL_SD_Init() --> HAL_SD_InitCard() --> SD_PowerON(), HAL_SD_ERROR_CMD_RSP_TIMEOUT is returned.

I was originally using code generated by CubeMX, but when I couldn't get this issue resolved, I loaded in one of the example projects for this Eval board (FatFs_uSD_Standalone), and it worked for about an hour. But then when I switched the SD card for a different card, it started failing in the same way as before. And when I put the other SD card back in, it continued to fail. One of these cards is the one that shipped with the Eval board. The other is a 16GB SDHC I speed class 10 card.

One more thing to mention: I probed the CMD and clock lines going to the SD card and noticed that when the Eval board is sending commands, transitions on the CMD line occur on the rising edge of the clock, but when the SD card is responding, transitions occur on the falling edge of the clock. I don't know if this is an effect of the IP4856CX25 voltage level translator and is to be expected, or if this indicates something is wrong, but this could possibly be connected to the problem I am seeing.

7 REPLIES 7
Paul Madle
Associate II

Hi Stephen,

I don't suppose you managed to fix this problem did you?... I am currently experiencing exactly the same problem with the same HAL_SD_ERROR_CMD_RSP_TIMEOUT error in the same function??

Paul Madle
Associate II

Right, so my problem is very similar to Stephens and I think I *might* be getting somewhere....

My Configuration

I have an STM32H753-EVAL2 board, I have installed STM32CubeIDE and have used the graphical tools to generate code (including FreeRTOS) that includes a main function that initialises the SDIO1 interface.

The Problem

During the initialisation of the SDIO1 peripheral, the code attempts to send the CMD55 to the SD card... This fails with a timeout (STAR register holds STA=4, timeout). The stack looks like this

main()

MX_SDMMC1_SD_Init()

HAL_SD_Init()

HAL_SD_InitCard()

SD_PowerON()

SDMMC_CmdAppCommand()

SDMMC_GetCmdResp1()

I have then added scope probes to the SD card socket on CLK and CMD lines... I can see the clock fine but no data (on the CMD line) when the code is attempting to send the command.

Possible Cause

I have then placed the probe on the CMD line input to the M1 module card (that has a IP4856CX25 isolation type chip)... Now I can see CMD data travelling to the IP4856CX25 but not onward to the SD Card..... Aha!... The signal also does not look nice (looks like bus contention). It looks like maybe the code from the STM32Cube wizard has no awareness of the IP4856CX35 isolation chip? That said... The code has provision for I/O pins CKIN, D0DIR, CDIR, D123DIR and D0DIR in HAL_SD_MspInit()... All of these are pins specific to the IP4856CX35.... But what is setting the SEL and ENABLE lines on the IP4856CX35...

I have isolated the problem to the transmission of data through the IP4856CX35... The CMD data is not getting through and there looks to be contention on the CMD line.... Any wisdom is greatfully accepted!

Here is a scope grab, showing CLK (at the SD card connector - blue) and CMD (at the input to the IP4856CX35 - red)....

0693W000001pvmDQAQ.png

Paul Madle
Associate II

Ok, getting further....

It looks like the ST generated code does not set the hsd1 structure quite right for the board... The board has an SD tranceiver, so I have changed the code in MX_SDMMC1_SD_Init() as follows:

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_PRESENT; // ALTERED THIS LINE
  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDMMC1_Init 2 */
 
  /* USER CODE END SDMMC1_Init 2 */
 
}

Now I can see the CMD data getting across to the SD card itself.... Still getting timeouts following CMD55 transmission. Again, wisdom would be appreciated.

Paul Madle
Associate II

Right.... the saga continues!

It seems that the problem related to the transceiver and code that switches from operating at 3V3 to 1V8... The code supports this switch of operating voltage BUT... the board has no fit resistors R97, R98, R110, R112, R115... These are required (I think) for the SD card to operate at 1V8.

The upshot of this appears to be that from power up, the SD card gets initialised correctly UNTIL the switch to 1V8 (which fails because of the lack of said resistors)... From this point forward, the SD card is in an inoperable state.... Even following a board reset, CMD0 does not reset the state of the chip (I can only assume because the voltage is 3V3 and the chip is expecting 1V8)... The only way out of it is a power cycle (or take the SD card out and pop it back in again).

But, I have found that the following hack (in function SD_PowerOn()) as well as the other hack (above) prevents the code from switching to 1V8 and then the card behaves itself and initialises correctly....

#ifdef NOT_DEFINED // PAUL HACK HERE... REMOVES CODE TO SWITCH TO 1.8V
//#if (USE_SD_TRANSCEIVER != 0U) // original code.
    if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)
    {
      if((response & SD_SWITCH_1_8V_CAPACITY) == SD_SWITCH_1_8V_CAPACITY)
      {
        hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED;
 
        /* Start switching procedue */
        hsd->Instance->POWER |= SDMMC_POWER_VSWITCHEN;
 
        /* Send CMD11 to switch 1.8V mode */
        errorstate = SDMMC_CmdVoltageSwitch(hsd->Instance);
        if(errorstate != HAL_SD_ERROR_NONE)
        {
          return errorstate;
        }
 
        /* Check to CKSTOP */
        while(( hsd->Instance->STA & SDMMC_FLAG_CKSTOP) != SDMMC_FLAG_CKSTOP)
        {
          if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
          {
            return HAL_SD_ERROR_TIMEOUT;
          }
        }
 
        /* Clear CKSTOP Flag */
        hsd->Instance->ICR = SDMMC_FLAG_CKSTOP;
 
        /* Check to BusyD0 */
        if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) != SDMMC_FLAG_BUSYD0)
        {
          /* Error when activate Voltage Switch in SDMMC Peripheral */
          return SDMMC_ERROR_UNSUPPORTED_FEATURE;
        }
        else
        {
          /* Enable Transceiver Switch PIN */
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
          hsd->DriveTransceiver_1_8V_Callback(SET);
#else
          HAL_SD_DriveTransceiver_1_8V_Callback(SET);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
 
          /* Switch ready */
          hsd->Instance->POWER |= SDMMC_POWER_VSWITCH;
 
          /* Check VSWEND Flag */
          while(( hsd->Instance->STA & SDMMC_FLAG_VSWEND) != SDMMC_FLAG_VSWEND)
          {
            if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
            {
              return HAL_SD_ERROR_TIMEOUT;
            }
          }
 
          /* Clear VSWEND Flag */
          hsd->Instance->ICR = SDMMC_FLAG_VSWEND;
 
          /* Check BusyD0 status */
          if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) == SDMMC_FLAG_BUSYD0)
          {
            /* Error when enabling 1.8V mode */
            return HAL_SD_ERROR_INVALID_VOLTRANGE;
          }
          /* Switch to 1.8V OK */
 
          /* Disable VSWITCH FLAG from SDMMC Peripheral */
          hsd->Instance->POWER = 0x13U;
 
          /* Clean Status flags */
          hsd->Instance->ICR = 0xFFFFFFFFU;
        }
      }
    }
#endif /* USE_SD_TRANSCEIVER  */

You could also undefine USE_SD_TRANSCEIVER but this define is also used to switch the polarity of the CMD_DIR line (which is needed).

Well that was 2 days of my life I will not get back! 😉

>>STM32H743I-EVAL2 

>>... the board has no fit resistors R97, R98, R110, R112, R115...

I have a much earlier version of the board, will check what's on that BOM, as I'm pretty sure it worked.

On the NUCLEO I completely skipped the transceiver, and didn't use the DDR or other modes requiring the voltage drop.

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

Hi clive1,

That is interesting... The code that now gets generated by STMCube performs a transition so that the SD card goes from 3V3 to 1V8. This would be fine if the board could support it,,, I think without the resistors fitted, it will not work.

Hopefully others will find the above investigation helpful when getting the board to work well with SD cards and STMCube generated code.... The initialisation routine is now running to completion without failure... Sadly I still have issues with the first write operation... If I don't fix quickly, I will start another forum conversation.

Paul Madle
Associate II

Ok, I have now managed to get writes and reads working to/from an SD card....

The extra "special source" required was:

  1. Reduce the clock rate... the default clock rate was producing CRC errors.... I guess it was a bit too fast for the board routing?
  2. Turned on hardware flow control... I was getting TXUNDER error and RXOVERFLOW errors I guess because I am using the polling drivers and the software wasn't keeping up with the interface... So the following tweaks to the main.c file function "MX_SDMMC1_SD_Init()" seem to have finally got it to kick into life:

/**
  * @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_ENABLE; // PRM hack.... this was DISABLED, causing FIFO overflow/underflow on read/writes during block transfer.... I am using a polling driver (no DMA or ISR)
  hsd1.Init.ClockDiv = 0xFA; // PRM hack turn down the data rate to 400kHz... I was seeing CRC errors at very high rate, by default this was "0"
  hsd1.Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT; // PRM hack, this configures the polarity of the CMD_DIR signal correctly for the SD card transceiver.
  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDMMC1_Init 2 */
 
  /* USER CODE END SDMMC1_Init 2 */
 
}