SAM4, ASF and eMMC

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I just received a newly manufactured card based on a SAM4E16C, and with eMMC instead of the microSD we've been using for the last few years. Im trying to test if the eMMC is working properly, but running in to some troubles.

 

I'm using the sd_mmc driver from the ASF library. The power to the eMMC is turned on, and all the pins for communication with the eMMC is initialized as follows:

  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCCDA_GPIO, IOPORT_MODE_MUX_C);
  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCCK_GPIO, IOPORT_MODE_MUX_C);
  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCDA0_GPIO, IOPORT_MODE_MUX_C);
  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCDA1_GPIO, IOPORT_MODE_MUX_C);
  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCDA2_GPIO, IOPORT_MODE_MUX_C);
  ioport_set_pin_peripheral_mode(PIN_HSMCI_MCDA3_GPIO, IOPORT_MODE_MUX_C);

 

This has been working well with the eval board and a SD-card. From what I gather, pretty much the same should be able to be used with the eMMC, since the driver supports both MMC and SD.

 

However, when I try to init the card, a few strange things are happening, and I'm trying to figure out at which level things are going on. I would like to basically first issue a simple command and read the response just to see if the electrical stuff is working properly.

 

The first thing the driver does is to send a CMD0. The hsmci_send_cmd function returns true, which means success. But the odd thing is that it returns true even if the eMMC is powered off. The next command, mmc_mci_op_cond, fails with the debug output "hsmci_send_cmd_execute: CMD 0x00004501 sr 0x0c10c1e5 error".

 

I haven't really dived too deep into HSMCI and the MMC protocol, so I'm somewhat lost.

 

Any tips in where to start? Maybe I've missed some initialization or basic thing related to the driver.

 

 

Best regards,

zetter

 

 

Last Edited: Tue. Nov 6, 2018 - 08:18 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

..started focusing more on the hardware and noticed that the CLK is a nice square between 0 and 3.3V. The CMD signal is also square and nice, until the command is done where it slowly drifts from 3.3V down. The goal is to use the internal pull-ups in the MCU, so there are no pull-ups on the signal on the board. Maybe there's something wrong with the pin configuration. This is how it's done in more detail:

 

In board init:

1. Turn power to eMMC

2. Set all communication pins output and low with: pio_configure(SD_MMC_PIO, PIO_TYPE_PIO_OUTPUT_0, SD_MMC_COM_PINS_MASK, PIO_DEFAULT) (To make sure the eMMC isn't semi-powered via those pins).

 

In eMMC init:

1. Turn power on to eMMC

2. Set all communication pins in peripheral mode with the code from the previous post.

3. Init driver with sd_mmc_init() (from ASF).

4. Run sd_mmc_test_unit_ready(0) (from ASF)

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just checked the schematic for our custom PCB with a working eMMC chip.  There is a 10K external pullup on the MCCDA signal and 49.9K on the MCDAx lines.  These are all bidirectional signals.  But the MCCK line does not have any pullups.

 

I'm using a SAME70 processor with ASF4 (Start).  Your library calls are different, perhaps ASF3.X instead?

 

For reference on my board:

PA25 = MCCK

PA28 = MCCDA

PA30 = MCDA0

PA31 = MCDA1

PA26 = MCDA2

PA27 = MCDA3

 

The code below was generated via Atmel's Start web based program

 

/* Card Detect (CD) pin settings */
static sd_mmc_detect_t SDMMC_ACCESS_0_cd[CONF_SD_MMC_MEM_CNT] = {

    {-1, CONF_SD_MMC_0_CD_DETECT_VALUE},
};

/* Write Protect (WP) pin settings */
static sd_mmc_detect_t SDMMC_ACCESS_0_wp[CONF_SD_MMC_MEM_CNT] = {

    {-1, CONF_SD_MMC_0_WP_DETECT_VALUE},
};

static void IO_BUS_init(void)
{
    gpio_set_pin_direction(PA28,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA28,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA28,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA28,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA28C_HSMCI_MCCDA"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA28C_HSMCI_MCCDA);

    gpio_set_pin_direction(PA25,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA25,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA25,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA25,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA25D_HSMCI_MCCK"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA25D_HSMCI_MCCK);

    gpio_set_pin_direction(PA30,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA30,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA30,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA30,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA30C_HSMCI_MCDA0"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA30C_HSMCI_MCDA0);

    gpio_set_pin_direction(PA31,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA31,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA31,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA31,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA31C_HSMCI_MCDA1"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA31C_HSMCI_MCDA1);

    gpio_set_pin_direction(PA26,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA26,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA26,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA26,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA26C_HSMCI_MCDA2"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA26C_HSMCI_MCDA2);

    gpio_set_pin_direction(PA27,
                           // <y> Pin direction
                           // <id> pad_direction
                           // <GPIO_DIRECTION_OFF"> Off
                           // <GPIO_DIRECTION_IN"> In
                           // <GPIO_DIRECTION_OUT"> Out
                           GPIO_DIRECTION_OUT);

    gpio_set_pin_level(PA27,
                           // <y> Initial level
                           // <id> pad_initial_level
                           // <false"> Low
                           // <true"> High
                           false);

    gpio_set_pin_pull_mode(PA27,
                           // <y> Pull configuration
                           // <id> pad_pull_config
                           // <GPIO_PULL_OFF"> Off
                           // <GPIO_PULL_UP"> Pull-up
                           // <GPIO_PULL_DOWN"> Pull-down
                           GPIO_PULL_OFF);

    gpio_set_pin_function(PA27,
                           // <y> Pin function
                           // <id> pad_function
                           // <i> Auto : use driver pinmux if signal is imported by driver, else turn off function
                           // <MUX_PA27C_HSMCI_MCDA3"> Auto
                           // <GPIO_PIN_FUNCTION_OFF"> Off
                           // <GPIO_PIN_FUNCTION_A"> A
                           // <GPIO_PIN_FUNCTION_B"> B
                           // <GPIO_PIN_FUNCTION_C"> C
                           // <GPIO_PIN_FUNCTION_D"> D
                           MUX_PA27C_HSMCI_MCDA3);

    _pmc_enable_periph_clock(ID_HSMCI);

    mci_sync_init(&IO_BUS, HSMCI);

    sd_mmc_init(&IO_BUS, SDMMC_ACCESS_0_cd, SDMMC_ACCESS_0_wp);
}

 

Last Edited: Tue. Nov 6, 2018 - 03:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ScottMN, thank you. I will go through the code at the office first thing in the morning.

 

I tried to add a 68K pullup på CMD, it yields the exact same result as activating the internal pullup on the pin in the SAM, so I guess that would be a good idea. 

 

Will report back tomorrow.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I went though the init code from ScottMN, and it's pretty much identical to what we have. The only difference is that we use the internal pull-ups in the MCU.

 

Actually, the eMMC just jumped to life and everything is working now. I was about to do some more measurements on the CLK signal, and therefore moved one of the oscilloscope probes från the CMD signal. Then suddenly, everything worked. If I reconnect oscilliscope probe to the CDM signal, the init process fails. However, if I add the probe after init of the eMMC is done, it keeps working.

 

Analogue electronics isn't my strong suite, but a wild guess is that the pull-ups are to weak. We use the internal ones in the SAM, which are typically 100 kOhm according to the data sheet. The max recommended pullup for the eMMC component on CMD is 50 kOhm. Maybe the minuscule current draw from the oscilloscope means that the signal is not really draw high enough. And, maybe, the init process is extra sensitive due to the lower frequency used during the init process, which means the signal has to be held high/low for longer periods. A wild guess.

 

Anyway, thanks again for sharing ScottMN. It helped me switch focus from the init code, which I was pretty sure was the problem, to the electronics. Which turned out to be the problem.