Problem with ESDHC on K70

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with ESDHC on K70

2,383 Views
chrissolomon
Contributor III

Hi,

I am trying to get the ESDHC driver in MQX 4.1.0.1 going on my K70 based product.

I know the out of the box MQX doesn't support eMMC, but we have been using a Samsung 4GB eMMC device under MQX 4.0.1 - we were able to use this device with modification to the initialization sequence in sdcard_esdhc.

I'm not sure the device is relevant to our issue because we aren't able to get that far with MQX 4.1.0.1:

The basic initialization starts with car identification, which begins with CMD0 (which fails with CTOE and CCE), but succeeds on the second attempt, then the second command is a CMD8, which always fails with CTOE and CC.

Since the basic card identification should work with any device type it seems that there is a more fundamental problem.

I have done side-by-side debugging with GDB and confirmed that the port pins registers are configure as they were previously, that the system clock setup is the same (96MHz generated by PLL0 using OSC0), and aside from expected differences due to the use of interrupts and DMA the ESDHC registers look the same, but it still doesn't want to play ball.

Any suggestions?

Thanks

Chris

Tags (2)
10 Replies

1,051 Views
ricktseng
Contributor III

Hi Chris ,

Can you post the your modification to the initialization sequence on eMMC device under 4.0.1 ? We have the same issue on MQX 4.1 on K40 device. The eSDHC driver has time out on CMD55 and it cannot get the correct card type on eMMC. We use protocol analyzer with Code Warrior to debug the sequence and found out the driver only issue 4 commands on eMMC  : CMD00 , CMD08 , CMD05 and CMD55. Per Freescale data sheet , the eSDHC driver support SD card and MMC , but I think we need to modify the eSDHC driver to support eMMC device.

Thanks

Rick

0 Kudos

1,051 Views
chrissolomon
Contributor III

HI Rick,

I am still working on getting this to work under MQX 4.1 - I'm failing to get a reply to CMD08, how did you get past that point?

I'm working on it now, and I'll post my progress.

In any case the sdcard_esdhc.c which was the only file we needed to modify under 4.0.1.

I attached it for reference - there is some extraneous code in there to store card info that you don't need, but I't might be useful once we get past the current problem.

Chris

1,052 Views
ricktseng
Contributor III

HI Chris ,

Same here , the eMMC does not reply to CMD08 but SD card does reply CMD08.

Please see  Protocol Analyzer output in the file : SD card vs MMC command

on TWR-K40x256.doc

(See attached file: SD card vs MMC command on TWR-K40x256.doc)

Let me know if you cannot open the attached file or you did not receive it.

Please note that the CMD on the above file is hex No. For example , CMD 55

is 0x37.

Thanks

Rick

0 Kudos

1,052 Views
chrissolomon
Contributor III

Hi Rick,

I have made some progress by comparing the functional code in MQX 4.0.1 to 4.1.0 in the debugger.

The problem seems to come from the differences in the initialization sequence for eMMC cards and SD cards.

An eMMC will not respond to any command after a CMD0 until it has seen CMD1.

The correct sequence information is in JDEC 84-A44, section A.8.

In the MQX 4.0.1 ESDHC driver's card identification routine timeout failures didn't cause the sequence to abort, and eventually it did issue a CMD1 and then began to function.

In the new driver the timeout causes the sequence to abort with an error code.

I have made a minor modification (two extra terms in 2 if statements), and now it does succeed - I'm not able to confirm if this breaks functionality with SD cards.

This isn't a nice init sequence for the eMMC, which is why in the modified sdcard_esdhc.c I have restarted the init sequence once the card type has been determined.

It still fails at this point - this is a work-in-progress. It now fails when I do a CMD8 - I may not have the command parameters quite right - I will continue with this tomorrow and let you know how I get on.

In the meantime, I have attached a zip with the modified files in there current state.

(BTW, you only seem to be able to see the attachments if you go back to the discussion, they don't show up in the inbox for some reason. Let me know if you can't see this one.)

Chris

0 Kudos

1,052 Views
ricktseng
Contributor III

Hi Chris ,

The the EXT_CSD sector count is from byte 212 to 215. In your code , you

wrote :

sdcard_ptr-> NUM_BLOCKS

= ((uint32_t) &buffer[212]);

In Paul's code , he use :

sdcard_ptr->NUM_BLOCKS = iosdcard_emmc_ext_csd_capacity(ext_csd);

uint32_t _io_sdcard_emmc_ext_csd_capacity

sec_count = 0;

     sec_count = ext_csd[215] << 24;

     sec_count |= ext_csd[214] << 16;

     sec_count |= ext_csd[213] << 8;

     sec_count |= ext_csd[212];

         

     return sec_count;

Can you double check your code ?

The other thing is the CMD08's response. Many zero ? Please open the cs_cmd08_again.png.

After CMD08 , you code return FALSE on  this :

if ( IO_SDCARD_BLOCK_SIZE not EQ read ( sdcard_ptr ->COM_DEVICE , buffer, IO_CARD_BLOCK_SIZE))

{

return FALSE;

}

Do not  know the reason . I will continue to debug.

Many Thanks  for sharing your code.

Rick

0 Kudos

1,052 Views
chrissolomon
Contributor III

Hi Rick,

I think the code is equivalent - you copied my code slightly incorrectly, the line actually reads

sdcard_ptr->NUM_BLOCKS = *((uint32_t *)&buffer[212]);

So, I am casting the address of the byte at index 212 to a uint32_t pointer, then dereferencing that uint32_t pointer - I agree without the stars it wouldn't work.

I'm not sure but I think Paul's code may be more portable. (Certainly easier to follow.)

BTW, I figured out how to get CMD08 to complete - the command should have been

command.COMMAND = ESDHC_CREATE_CMD(8, ESDHC_COMMAND_TYPE_NORMAL, ESDHC_COMMAND_RESPONSE_R1, ESDHC_COMMAND_DATACMD_FLAG | ESDHC_COMMAND_DATA_READ_FLAG );

I am still not happy with the code.

I have spotted a significant bug:

Both _esdhc_read and _esdhc_write can fail and return IO_ERROR_TIMEOUT, which is 0x00000A10 or 2576. Note this is a POSITIVE error code, so indistinguishable from a the number of bytes read or written.

I am replacing the IO_ERROR_TIMEOUT error codes with IO_ERROR and setting esdhc_fd_ptr->ERROR = IO_ERROR_TIMEOUT.

I'll get back to you with some code later today.

0 Kudos

1,052 Views
ricktseng
Contributor III

Hi Chris ,

Thanks for pointing out my mistake. Both your code and Paul's code are

correct on sector count.

I follow your instruction on CMD08 and the TWR-K40x256 is working OK on

eMMC. I test 2 kinds of eMMC :

Kingston , EMMC04G-S100 , ( eMMC5.0) , 4GB

Kingston , KE4CN3H5A , (eMMC4.5) , 8GB

On Freescale's SD card demo program , we can create directories , write

files , read files and format the drive on eMMC.

Many thanks for you and Paul's contribution. I will post Protocol

Analyzer's data this week.

Rick

0 Kudos

1,052 Views
chrissolomon
Contributor III

Hi Rick and Paul,

I have made a few modifications and the attached code seems to work - I don't have a protocol analyzer to check if there is anything nasty happening under the hood, but it appears to work.

I reviewed Paul's code, and it is nicer in places - I think my changes are closer to the original code, which may make merging any updates easier, so I have chosen to stick with my approach.

Here is a brief list of the changes that were required to get things going:

1) Modified the card identification process so on timeout it falls through to a CMD1 (and then the MMC card identification succeeds)

2) Modified the _io_sdcard_esdhc_init check for MMC card type, and if it is an MMC to return the result of new function, _io_emmc_esdhc_init.

3) Modified the _esdhc_send_command function, setting BCEN on non-infinite rather than infinite transfers.

4) Changed the _esdhc_read and _esdhc_write so on lwsem timeout the function returns IO_ERROR (-1) and sets the file hand error to IO_ERROR_TIMEOUT, otherwise writes of 2576 bytes would be indistinguishable from the error code.

5) Added a wait for data lines to be available (thanks to Paul for that)

There are some other mods, not strictly required:

1) Changed to use read and write (and added divides on the results to put them back into sectors) rather the fread and fwrite - I get warnings since I am using EWL, so I changed it.

2) Added a structures and enums for storing info about the emmc, and an additional ioctl command to get it.

Additional note:

Unlike the previous driver you can only read and write a maximum of 127 blocks (65024 bytes).

I considered modifying the code so the read and write operations would chop up the requests, but it doesn't seem to cause a problem for MFS. We only hit the problem because we load a big firmware image into DDR from a raw partition (previously in one go), so I just modified our app code.

Chris

EDIT:

I have found 2 bugs in this code - the first is in the baud rate variable was not initialized prior to switching to high speed baud rate. to fix, insert the following at about line 296 of sdcard_esdhc.c

    ESDHC_DEVICE_STRUCT_PTR esdhc_device_ptr = sdcard_ptr->COM_DEVICE->DEV_PTR->DRIVER_INIT_PTR;

    baudrate = esdhc_device_ptr->INIT->MAX_BAUD_RATE;

The second is in esdhc.c, in _esdhc_init - the line that read

    _esdhc_set_baudrate_low(esdhc_ptr, esdhc_init_ptr->CLOCK_SPEED, ESDHC_INIT_BAUDRATE);

should have read

    _esdhc_set_baudrate_low(esdhc_ptr, _bsp_get_clock_freq( esdhc_init_ptr->CLOCK_SPEED ), ESDHC_INIT_BAUDRATE);

the _bsp_get_clock_freq function is a function of my own creation that returns the actual baud rate for a given clock, which is useful if you want the esdhc to function properly if it can be initialized in different clock modes.

This isn't the most robust bit of code, and if it isn't required that function can be removed from everywhere it is used.

If this was helpful, please give me a +1

1,052 Views
pbanta
Contributor IV

Hi Chris,

Thanks for sharing your work on this.  When I get some time I'm going to revisit.  I hope Freescale will update MQX in a future release to include these fixes.

Best regards,

Paul

0 Kudos

1,052 Views
pbanta
Contributor IV

Hi Chris,

I recently went through this for a project that I'm working on.  I got it working and here's what I did. (Disclaimer: it's not elegant.)

Background

I have a K70FX-based board and a Kingston KE4CN2H5C eMMC part.  The production boards will have 5.0 parts but I had 4.5 and 5.0 samples.  I used both in the development/debugging.

Problem

As you have correctly observed, the sdcard/esdhc driver in MQX 4.1 doesn't support eMMC parts.  Not even close.  Not only does it not follow the state machine in JEDEC 84-B45, it doesn't follow the Freescale SD/MMC Deep Dive from FTF2010 ( WBNR_FTF10_NET_F0598_PDF.pdf , page 17).

My Solution

After reviewing the driver code I decided that I didn't want to modify _esdhc_get_card_type().  Instead, I wrote _esdhc_get_mmc_type() and added it to esdh.c.  In addition I created sdcard_emmc in Peripheral_IO_Drivers/sdcard.  This way I can keep most of  the eMMC code in one place.  I control which driver is used (either sdcard/sdcard_esdhc or sdcard/sdcard_emmc) by a manifest constant in user_config.h near the bottom of the file:

user_config.h

/*

** include common settings

*/

#define MQX_USE_IO_OLD          1

#define BSPCFG_USE_EMMC         1

Then in BSP_Files/init_sdcard.c:

  init_sdcard.c

const SDCARD_INIT_STRUCT _bsp_sdcard0_init = {

#if BSPCFG_USE_EMMC

        _io_sdcard_emmc_init,

        _io_sdcard_emmc_read_block,

        _io_sdcard_emmc_write_block,

        ESDHC_BUS_WIDTH_4BIT 

#else

        _io_sdcard_esdhc_init,

        _io_sdcard_esdhc_read_block,

        _io_sdcard_esdhc_write_block,

        ESDHC_BUS_WIDTH_4BIT

#endif

};

Finally in Peripheral_IO_Drivers/esdhc.c:_esdhc_ioctl() in the code for IO_IOCTL_ESDHC_GET_CARD I did the following:

#if BSPCFG_USE_EMMC

                        /* Recognize inserted card */

                        val = _esdhc_get_mmc_type(esdhc_device_ptr);

#else

                        val = _esdhc_get_card_type(esdhc_device_ptr);

#endif

                        if (val != ESDHC_OK)

                        {

                            esdhc_device_ptr->CARD = ESDHC_CARD_UNKNOWN;

                        }

Final Comments

I set my eMMC devices to 4-bit mode and they work fine.  I have not tested the _set_sd_high_speed_mode() function in sdcard_emmc.c.  I don't need it and it's a copy from sdcard_esdhc.c.  My parts are 4GB parts.  That means that the sector count is stored in EXT_CSD.  I wrote code to read it.  If you have an eMMC part with capacity less than 2GB then I think the sector count is in the CSD.  I think that should be the same as SD cards.

When setting the relative address with CMD3 I wasn't sure what to do.  I knew address 0x1 was illegal, so I chose 0x2.  (Remember, I am not an expert!) Smiley Happy

For 5.0 parts I found that I had to add a delay in my application right before _io_part_mgr_install().  I don't like that solution and I need to go back and take a look at it again (but there are too many other pressing issues. Smiley Happy

Also, the CMD line is supposed to be in open drain mode in the beginning and later changed to push-pull.  So in init_gpio.c I have the following:

#if BSPCFG_USE_EMMC

            pctl->PCR[3] = value & (PORT_PCR_MUX(4) | PORT_PCR_ODE_MASK | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK);    /* ESDHC.CMD */

#else

            pctl->PCR[3] = value & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK);    /* ESDHC.CMD */

#endif

And then later in _io_sdcard_emmc_init() I change it to push-pull.

Good luck!

Paul