STMicroelectronics / STM32CubeH7

STM32Cube MCU Full Package for the STM32H7 series - (HAL + LL Drivers, CMSIS Core, CMSIS Device, MW libraries plus a set of Projects running on all boards provided by ST (Nucleo, Evaluation and Discovery Kits))
https://www.st.com/en/embedded-software/stm32cubeh7.html
Other
495 stars 303 forks source link

Missing eMMC states on HAL_MMC_CardStateTypeDef and eMMC not going into sleep state #156

Closed C47D closed 2 years ago

C47D commented 3 years ago

Caution The Issues are strictly limited for the reporting of problem encountered with the software provided in this project. For any other problem related to the STM32 product, the performance, the hardware characteristics and boards, the tools the environment in general, please post a topic in the ST Community/STM32 MCUs forum

Describe the set-up

Describe the bug There's three states missing in HAL_MMC_CardStateTypeDef according to JEDEC Standard No. 84-B50 section 6.13 Device Status

imagen

The missing states are: Idle (0), Btst (9) and Slp (10).

This is the current set of states:

/** @defgroup MMC_Exported_Types_Group2 MMC Card State enumeration structure
  * @{
  */
typedef uint32_t HAL_MMC_CardStateTypeDef;

#define HAL_MMC_CARD_READY          0x00000001U  /*!< Card state is ready                     */
#define HAL_MMC_CARD_IDENTIFICATION 0x00000002U  /*!< Card is in identification state         */
#define HAL_MMC_CARD_STANDBY        0x00000003U  /*!< Card is in standby state                */
#define HAL_MMC_CARD_TRANSFER       0x00000004U  /*!< Card is in transfer state               */
#define HAL_MMC_CARD_SENDING        0x00000005U  /*!< Card is sending an operation            */
#define HAL_MMC_CARD_RECEIVING      0x00000006U  /*!< Card is receiving operation information */
#define HAL_MMC_CARD_PROGRAMMING    0x00000007U  /*!< Card is in programming state            */
#define HAL_MMC_CARD_DISCONNECTED   0x00000008U  /*!< Card is disconnected                    */
#define HAL_MMC_CARD_ERROR          0x000000FFU  /*!< Card response Error                     */

How To Reproduce

  1. I'm trying to set my MMC into sleep state when not using it. After setting it into standby mode and sending the CMD5 with the 15bit set to 1, the card goes into idle state and it's missing from the HAL_MMC_CardStateTypeDef values, it would be nice to have it declared there.

  2. The modules that you suspect to be the cause of the problem (Driver, BSP, MW ...)

  3. The use case that generates the problem

  4. Let me know if you have any board with eMMC on board.

Additional context If you have a first analysis or patch correction, thank you to share your proposal.

Screenshots If applicable, add screenshots to help explain your problem.

C47D commented 3 years ago

Second part of the issue:

We need to put the eMMC into sleep state in order to save some current consumption, but the card doesn't deselects without errors, and if I send the CMD5 command and get the card state afterwards I get state 0 or IDLE.

  1. In order to enter sleep state I need to be in standby state first, which is achieved from staying in transferring state and sending the CM7 command with the RCA of the card as argument (1).

  2. Then when the card is in standby state we can enter sleep state by sending the CMD5 command with the RCA of the card as argument and the 15th bit set to 1.

  3. Then in order to leave the sleep state we need to send the CMD5 command with the RCA of the card as argument and the 15th bit set to 0,

  4. Then to go into transfer state we need to send the CMD7 command with the RCA of the card as argument.

imagen

The CMD5 response type is R1b, which is depicted in the reference manual to be handled as follows:

imagen

imagen

This are the functions I've done in order to send the CMD5 commands:

/* See Reference manual 55.6.3 */
void mmcSleep(MMC_HandleTypeDef * mmc)
{
    uint32_t rca = (uint32_t) cardInfo.RelCardAdd << 16U;

    uint32_t error = 0;
    uint32_t arg = rca;
    arg |= (1 << 15);

    __HAL_MMC_ENABLE_IT(mmc, SDMMC_IT_BUSYD0END);

    SDMMC_CmdInitTypeDef cmd = {
        .CmdIndex = SDMMC_CMD_SDMMC_SEN_OP_COND,
        .Argument = arg,

        .Response = SDMMC_RESPONSE_SHORT,
        .WaitForInterrupt = SDMMC_WAIT_IT,
        .CPSM = SDMMC_CPSM_ENABLE
    };

    /* Always returns HAL_OK */
    (void) SDMMC_SendCommand(mmc->Instance, &cmd);

    /* Check for error conditions */
    error = SDMMC_GetCmdResp1(mmc->Instance, SDMMC_CMD_SDMMC_SEN_OP_COND, SDMMC_CMDTIMEOUT);

    /* We're getting a timeout SDMMC_ERROR_TIMEOUT */
    if (error) {
        MY_ASSERT(0);
    }

    while (0 == mmc_state_changed) {

    }

    mmc_state_changed = 0;
}

void mmcWakeup(MMC_HandleTypeDef *mmc)
{
    uint32_t rca = (uint32_t) cardInfo.RelCardAdd << 16U;

    uint32_t arg = rca;

    __HAL_MMC_ENABLE_IT(mmc, SDMMC_IT_BUSYD0END);

    SDMMC_CmdInitTypeDef cmd = {
        .CmdIndex = SDMMC_CMD_SDMMC_SEN_OP_COND,
        .Argument = arg,

        .Response = SDMMC_RESPONSE_SHORT,
        .WaitForInterrupt = SDMMC_WAIT_IT,
        .CPSM = SDMMC_CPSM_ENABLE
    };

    (void) SDMMC_SendCommand(mmc->Instance, &cmd);

    /* Check for error conditions */
    SDMMC_GetCmdResp1(mmc->Instance, SDMMC_CMD_SDMMC_SEN_OP_COND, SDMMC_CMDTIMEOUT);

    while (0 == mmc_state_changed) {

    }

    mmc_state_changed = 0;
}

mmc_state_changed is a boolean variable (qualified as volatile) set on the MMC interrupt handler like so:

/**
  * @brief This function handles SDMMC1 global interrupt.
  */
void SDMMC1_IRQHandler(void)
{
  /* USER CODE BEGIN SDMMC1_IRQn 0 */

    if (__HAL_MMC_GET_FLAG(&hmmc1, SDMMC_FLAG_BUSYD0END)) {
        /* Disable interrupt */
        __HAL_MMC_DISABLE_IT(&hmmc1, SDMMC_IT_BUSYD0END);

        mmc_state_changed = 1;
    }

  /* USER CODE END SDMMC1_IRQn 0 */
  HAL_MMC_IRQHandler(&hmmc1);
  /* USER CODE BEGIN SDMMC1_IRQn 1 */

  /* USER CODE END SDMMC1_IRQn 1 */
}

For sending the CMD7 command I'm using the SDMMC_CmdSelDesel function, to select the card (or go from standby to transferring state):

uint32_t rca = (uint32_t) cardInfo.RelCardAdd << 16U;
error = SDMMC_CmdSelDesel(hmmc1.Instance, rca);

To go from transferring into standby state:

uint32_t rca = (uint32_t) 1U << 16U;
error = SDMMC_CmdSelDesel(hmmc1.Instance, rca);

This is how I'm trying to wakeup the card when I'm about to use it:

        state = HAL_MMC_GetCardState(&hmmc1);

        if (HAL_MMC_CARD_TRANSFER != state) {

            if (10 /* sleep state */ == state) {
            /* Wake the MMC up */
                mmcWakeup(&hmmc1);
            }

                        /* We should be in standby state now */

            /* Select the card in order to perform FS operations in it */
            uint32_t rca = (uint32_t) cardInfo.RelCardAdd << 16U;
            error = SDMMC_CmdSelDesel(hmmc1.Instance, rca);
            ASSERT(HAL_MMC_ERROR_NONE == error);

            /* Assert the card is in HAL_MMC_CARD_TRANSFER state */
            state = HAL_MMC_GetCardState(&hmmc1);
            ASSERT(HAL_MMC_CARD_TRANSFER == state);
        }

And this is how I'm sending it to sleep when I'm not going to use it (I'm getting back error SDMMC_ERROR_CMD_RSP_TIMEOUT when calling SDMMC_CmdSelDesel):

        state = HAL_MMC_GetCardState(&hmmc1);

        if (HAL_MMC_CARD_TRANSFER == state) {
            uint32_t rca = (uint32_t) 1U << 16U;
            error = SDMMC_CmdSelDesel(hmmc1.Instance, rca);

                        /* We should be in standby state now */

            state = HAL_MMC_GetCardState(&hmmc1);
            if (SDMMC_ERROR_NONE == error || HAL_MMC_CARD_STANDBY == state) {
                mmcSleep(&hmmc1);
                state = HAL_MMC_GetCardState(&hmmc1);
                                /* We should be in sleep state now */
            }
        }

Do you have any pointers or something missing on the code in order to send the card to sleep state?

Regards

ASELSTM commented 3 years ago

Hi @C47D,

Thank you for this report. The issue you pointed out has been confirmed, a fix will be implemented and made available in future release. Thank you once again for your contribution.

With regards,

ASELSTM commented 3 years ago

ST Internal Reference: 110154

ALABSTM commented 2 years ago

Hi @C47D,

I hope you are fine. The issue you reported has been fixed in the frame of version v1.9.1 of the STM32CubeH7 published recently on GitHub as you can see from the code extracts below. Thank you again for having reported.

With regards,

https://github.com/STMicroelectronics/STM32CubeH7/blob/e9472e471cc8974c4a2596fc86e565241871c20e/Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_mmc.h#L64-L77

https://github.com/STMicroelectronics/STM32CubeH7/blob/e9472e471cc8974c4a2596fc86e565241871c20e/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mmc.c#L3157-L3161

https://github.com/STMicroelectronics/STM32CubeH7/blob/e9472e471cc8974c4a2596fc86e565241871c20e/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mmc.c#L3355-L3359