cancel
Showing results for 
Search instead for 
Did you mean: 

4GB write, read and erase EMMC with 4-bit DDR on STM32H7B0 using STM32Cube FW_H7 V1.9.0

indesaf43
Associate II

Hi,

I am trying to write, read and erase properly on a 4 GB Insignis EMMC (NSEC53K004-IT/-AT) with up to 250 MB/s read and 14 MB/s write.

I currently use the STM32Cube FW_H7 V1.9.0 and am unsure regarding the adjustments that need to be done to the generated code, as there have been fixes to described issues that I found here in the forums in other threads.

e.g. https://community.st.com/s/question/0D50X00009sVjaySAC/stm32h753-sdmmc-driver-not-working-properly-sdk-v130

(where a DTMODE adjustment is described for DDR)

Would that still be necessary? The mode 3 still is not officially defined.

// in stm32h753xx.h
    #define SDMMC_DCTRL_DTMODE_2             (0x3U << SDMMC_DCTRL_DTMODE_Pos)  
     
    //in stm32h7xx_ll_sdmmc.h
    #define SDMMC_TRANSFER_MODE_BLOCK_STOP		  SDMMC_DCTRL_DTMODE_2
     
    // in stm32h7xx_hal_mmc.c
    // in read/write dma function set transfermode to:
        config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK_STOP;

I am also unaware what is the current situation with this remark from the thread, as I don't see the call in with the current V1.9.0

Same as you, I noticed that the  cmd16(SDMMC_CmdBlockLength()) in the write/read function must be put in an IF statement to be ignored if we are in DDR mode.

The 4 data pins in Cube IDE are configured for alternative push-pull and the global interrupt is enabled as well as hardware flow control. Rising transition and not power save for the CLK.

The only adjustment I made was this one in the MCC_InitCard() function, as the HAL_MMC_Init() call from the main now includes the HAL_MMC_ConfigWideBusOperation() call and it would not configure for DDR without these set bit calls.

/* Configure the SDMMC peripheral */
  Init = hmmc->Init;
  Init.BusWide = SDMMC_BUS_WIDE_1B;
  (void)SDMMC_Init(hmmc->Instance, Init);
  SET_BIT((hmmc)->Instance->CLKCR, SDMMC_CLKCR_DDR);
  SET_BIT((hmmc)->Instance->CLKCR, SDMMC_CLKCR_BUSSPEED);
  /* All cards are initialized */
  return HAL_MMC_ERROR_NONE;

Writing seems to work, but is not faster than using 1-bit and default speed, I am very far away from 14 MB/s and therefore assume that DDR is not working at all. The CLK is set to 50 MHz, but I also tried 25 MHz using the EMMC CLK divider or setting it to 0.

Reading does not work, as even with single block reading, I get a busy response from the DMA Read function. My test code is as follows:

Interations refer to the block intertions to be written. I tested for 1 block writes and 8 block writes (4kB). MX_SDMMC2_MMC_Init() has been called.

for (int iteration = 0; iteration < iterations; iteration++) {
        errorState = HAL_MMC_WriteBlocks_DMA(&hmmc2, wData, blockCount, blocksPerWrite);
        while (HAL_MMC_GetCardState(&hmmc2) != HAL_MMC_CARD_TRANSFER) {
            HAL_Delay(1);
        }
        if(errorState != 0){
            HAL_Delay(50);
        }
        errorState = HAL_MMC_ReadBlocks_DMA(&hmmc2, rData, blockCount, blocksPerWrite);
        while (HAL_MMC_GetCardState(&hmmc2) != HAL_MMC_CARD_TRANSFER) {
            HAL_Delay(1);
        }
        if (memcmp(wData, rData, bytesPerWrite) == 0) {
      	  status = 0;
        }
        else {
            status = 1;
        }
        blockCount += blocksPerWrite;
    }

I reckon that I need to implement HAL_MMC_RxCpltCallback to avoid timeout, but would this help with the DMA being busy?

Can somebody tell me what might be the issue here and which adjustments would be necessary to get the DDR up and running using DMA or even without it?

Best regards

9 REPLIES 9
TDK
Guru

Regarding the last block of code you wrote:

HAL_MMC_GetCardState sends a command, which it can't do if the operation is ongoing. There doesn't appear to be a mechanism in HAL preventing this, at least in the version of the library I'm checking.

You should instead monitor the state of hmmc2.State and wait until it's HAL_MMC_STATE_READY, then call HAL_MMC_GetCardState to check for errors.

The HAL_Delay calls here are not necessary and will only slow down the operation. (But you should only be calling HAL_MMC_GetCardState once anyway.)

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

Hi TDK, thank your support! Do know of a best practice example for using these Write and Read functions in combination with EMMC?

indesaf43
Associate II

Without the GetCardState call, I get an error for the Write.

Best practice? Not really, other than understanding how HAL expects you to call functions. It is laid out relatively well at the top of the relevant source file.
Developing eMMC functionality is complicated, especially at higher data speeds. I would be extremely surprised if HAL could do this out of the box. It requires a low-level understanding of what is going on at the card level, and if you're using HAL, how those functions translate into MMC commands. For higher data rates, it requires an understanding of how to minimize the time spent not transferring data while still remaining responsive to user input, if applicable.
All of those add up to requiring a relatively specialized skillset and time investment.
If you feel a post has answered your question, please click "Accept as Solution".

To get any kind of speed you're going to have to write dozens of sectors at once, the erase block size is probably of the order of 128KB, and it's going to be juggling those behind the scenes. You'd likely need to write a stream of 32MB to get any appreciation of the sustained performance.

Not going to get anywhere need 250 MB/s on this platform.

Custom board presumably? Do you have a debug UART? Which UART, which pins?

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

Yes, it's a custom board, it's just about proof of concept and that everything is connected correctly. Also, a bit of a load and function test. Those speeds are not required, but it should be faster than the extrapolated 2h.

I have several UARTS as option, one is specifically thought for log output and only offers one pin as Tx for the STM32H7, PB6,14,15 and PD 0/1 would be options - no flow control available. Can you tell me how I can confirm that it actually uses the configured 4 lines?

>>Can you tell me how I can confirm that it actually uses the configured 4 lines?

I typically unpack the SDMMC and RCC/PLL clock registers to report the actual settings the HW is using.

Do you have USART1 wired to a terminal currently, or are you using the SWO pin from the SWD interface for diagnostic output?

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

I currently use a j-link plus JTAG to flash and debug and a toggling LED to signal activity while writing. What would you suggest to log at this point?

indesaf43
Associate II

When calling HAL_MMC_ConfigSpeedBusOperation with SDMMC_SPEED_MODE_DDR, it wants to set the device to HS mode and calls another MMC_PwrClassUpdate() after the MMC_PwrClassUpdate call that is in the implicitly called in HAL_MMC_ConfigWideBusOperation(). However, reading the POWER_CLASS register in this call, it hangs up in the posted polling. Can somebody tell me why?

I see that HAL_MMC_ConfigWideBusOperation() sets the bus width to 0x01, whereas only in the HAL_MMC_ConfigSpeedBusOperation() it is set to 0x05 as referenced in the JEDEC 5.0 standard. Also, it only does so if I set the bits as described earlier. As those bits supposed to be set in the HAL_MMC_ConfigSpeedBusOperation() I removed them again, but it does not succeed at the mentioned POWER_CLASS register read, which has worked in the first call.