Beware! Not all STM32 devices and drivers are created equal, especially when it comes to interfacing with eMMC memory.
Designing a deeply embedded system with eMMC has its rewards as well as its challenges. One of those challenges shouldn't be fixing released vendor driver bugs, but that is what we had to do to verify the eMMC hardware implementation for a client. Read below to find out what needed to be fixed and what might be blocking your eMMC project.
eMMC - or embedded Multi Media Card memory - is a great choice for your STM32-based device when you need GB of non-volatile, on-board and non-removable storage in a cost-effective format.
eMMC memory, based on NAND technology, offers higher capacities along with built-in flash management that you won't find in smaller capacity NOR-based SPI-Flash memories typically found in deeply embedded systems.
However, eMMC requires a new interface with more sophistication than SPI. eMMC memories use a host driven clock, a single dedicated bi-directional command line and from 1 to 8 bi-directional data lines. ST provides hardware-level support in the form of the SDMMC1 peripheral found in many device families including the STM32L4 series.
Commands are 48-bit structures that are delivered to the eMMC module through the data line. The eMMC module can respond with up to 6 different types of responses. These responses are sent back to the STM32 host via the same data line. Commands are used to poll for eMMC capabilities, configure the eMMC or initiate data transactions on the data lines.
The processing of commands, that is, the serialization of command messages and capturing of command responses, is automatically handled by the STM32 SDMMC1 hardware peripheral.
Now, the task of deciding which commands to send and their content is up to the firmware driver. It is the driver that implements the eMMC protocol defined by the JEDEC standard. ST offers a HAL-based driver - comprising stm32l4xx_hal_mmc.c and stm32l4xx_ll_sdmmc.c - as part of their standard Cube offering.
Firing up this driver underneath a FatFS test application on a client's new board yielded an initialization error. What was wrong? The clock was operating. The command bus had traffic, but the driver was reporting an error. Digging deep - very deep - we found two key problems.
The first problem in the STM32L4 HAL MMC driver was found during the initialization sequence:
1. CMD1 (get Operational Capabilities Register - OCR)
2. CMD2 (get the Card ID - CID)
3. CMD3 (Set the Relative Card Address - RCA)
In the STM32L4 HAL driver, CMD3 was attempting to set address 0x1 - correct - but incorrectly attempting to confirm it in the CMD3 response and hence returning 0x0 to be assigned as the RCA in the driver for subsequent commands. Therefore, subsequent commands that require a card address, like CMD7 (Select Card), didn't work.
The second problem was in the sequence of commands that come next, after the initialization sequence. Even if the RCA was correct and CMD7 worked, the driver (note: this error applies to L4 devices only and NOT L4+ devices) was doing this:
4. CMD8 (Get Extended CSD)
5. CMD7 (Select Card)
The card has to be selected before it can return the extended CSD. Swapping the order of commands to CMD7 then CMD8 allows the driver initialization to complete. Note that the order is correct for the newer L4+ device series, for which special handling is differentiated with a #define statement. Both L4 and L4+ devices shared a common path with the incorrect RCA handling, however.
Hopefully resolutions to these issues get baked into CubeL4 firmware for aspiring eMMC users. If you're facing a problem with your project, we suggest looking into your HAL driver and ensuring the resolutions to the issues presented in this blog post are applied.