Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharing SPI bus between TFT and sdcard results in error (IDFGH-4699) #6510

Closed
jkent opened this issue Feb 6, 2021 · 5 comments
Closed

Sharing SPI bus between TFT and sdcard results in error (IDFGH-4699) #6510

jkent opened this issue Feb 6, 2021 · 5 comments
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally

Comments

@jkent
Copy link
Contributor

jkent commented Feb 6, 2021

Environment

  • Development Kit: none
  • Module or chip used: ESP32-WROVER
  • IDF version (run git describe --tags to find it):
    v4.3-dev-2940-g6e776946d
  • Build System: idf.py
  • Compiler version
    xtensa-esp32-elf-gcc (crosstool-NG esp-2020r3) 8.4.0
  • Operating System: Linux
  • Using an IDE?: Yes: vscode
  • Power Supply: USB / Battery

Problem Description

Hardware is an ODROID-GO. Sdcard is connected via SPI. Sdcard initializes fine, able to read some files off the card. After user event, reading same files again results in an error.

Expected Behavior

No error. Files read again as expected.

Actual Behavior

E (65453) sdmmc_cmd: sdmmc_read_sectors_dma: sdmmc_send_cmd returned 0x107
E (65453) diskio_sdmmc: sdmmc_read_blocks failed (263)

Code to reproduce this issue

Source can be found here, in the wip branch: https://gitlab.jkent.net/odroid-go/golauncher

const gpio_num_t GPIO_NUM_MISO          = GPIO_NUM_19;
const gpio_num_t GPIO_NUM_MOSI          = GPIO_NUM_23;
const gpio_num_t GPIO_NUM_SCLK          = GPIO_NUM_18;
const gpio_num_t GPIO_NUM_DISPLAY_CS    = GPIO_NUM_5;
const gpio_num_t GPIO_NUM_DISPLAY_DC    = GPIO_NUM_21;
const gpio_num_t GPIO_NUM_DISPLAY_BL    = GPIO_NUM_14;
const gpio_num_t GPIO_NUM_SDCARD_CS     = GPIO_NUM_22;
    spi_bus_config_t bus_config = { };
    bus_config.miso_io_num = GPIO_NUM_MISO;
    bus_config.mosi_io_num = GPIO_NUM_MOSI;
    bus_config.sclk_io_num = GPIO_NUM_SCLK;
    bus_config.quadwp_io_num = GPIO_NUM_NC;
    bus_config.quadhd_io_num = GPIO_NUM_NC;
    bus_config.max_transfer_sz = sizeof(lv_color_t) * LV_HOR_RES_MAX * 10;
    ret = spi_bus_initialize(VSPI_HOST, &bus_config, 1);
    assert(ret == ESP_OK);

    spi_device_interface_config_t device_interface_config = { };
    device_interface_config.clock_speed_hz = SPI_MASTER_FREQ_40M;
    device_interface_config.mode = 0;
    device_interface_config.spics_io_num = GPIO_NUM_DISPLAY_CS;
    device_interface_config.queue_size = 2;
    device_interface_config.pre_cb = PreTransfer;
    device_interface_config.post_cb = PostTransfer;
    device_interface_config.flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_HALFDUPLEX;
    ret = spi_bus_add_device(VSPI_HOST, &device_interface_config,
            &s_spi_device_handle);
    sdmmc_host_t host = SDSPI_HOST_DEFAULT();
    host.slot = VSPI_HOST;
    host.max_freq_khz = SDMMC_FREQ_PROBING;

    sdspi_dev_handle_t sdspi_dev_handle;
    sdspi_device_config_t device_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    device_config.gpio_cs = GPIO_NUM_SDCARD_CS;
    device_config.host_id = VSPI_HOST;
    sdspi_host_init_device(&device_config, &sdspi_dev_handle);

    esp_vfs_fat_sdmmc_mount_config_t mount_config = {};
    mount_config.format_if_mount_failed = false;
    mount_config.max_files = 5;

    return esp_vfs_fat_sdspi_mount(mount_path, &host, &device_config,
            &mount_config, &SdcardHandle);

sdkconfig.txt

@github-actions github-actions bot changed the title Sharing SPI bus between TFT and sdcard results in error Sharing SPI bus between TFT and sdcard results in error (IDFGH-4699) Feb 6, 2021
@jkent
Copy link
Contributor Author

jkent commented Feb 6, 2021

Oh another note. The sdcard esp-idf example runs correctly (with modified pin configuration).

@nopnop2002
Copy link

device_interface_config.clock_speed_hz = SPI_MASTER_FREQ_40M;

ESP-IDF SDSPI driver uses a 20MHz bus clock.

Try SPI Clock at 20Mhz.

@jkent
Copy link
Contributor Author

jkent commented Sep 5, 2021

I will make time to try this. However, this is an unacceptable solution, as the LCD needs to run at 40MHz -- I'm pretty sure it was working in an earlier version of IDF for the ODROID-GO.

@ginkgm
Copy link
Collaborator

ginkgm commented Sep 6, 2021

@jkent @nopnop2002 ,

Sorry for late reply. We have did some tests and found the issue is not very simple and straight. We plan to update some documentation about sharing the same SPI bus among SD card and other devices. Here's the docs for you to preview

Sharing the SPI bus among SD card and other SPI devices
=======================================================

The SD card has a SPI mode, which allows it being communicated to as a SPI device. But there are some restrictions that we need to pay attention to.

Pin loading of other devices
----------------------------

When adding more devices onto the same bus, the overall pin loading increase. The loading consists of AC loading (pin capacitor) and DC loading (pull-ups).

AC loading
^^^^^^^^^^

SD cards, which are designed for high-speed communications, have small pin capacitors (AC loading) to work until 50MHz. However, the other attached devices will make the AC loading of the pins larger.

The heavy AC loading of the pin may prevent it from being toggled quickly, and you will see the edges of the pin become smoother and not ideal any more. This may violate the setup timing requirements of SD card. Even worse, the clock from the host may not be recognized by the SD card and other SPI devices.

This issue may be move obvious, if other attached devices are not designed to work under the same frequency as the SD card, because they may have larger pin capacitors.

To see if your pin AC loading is too heavy, you can try the following tests:

1. Use an oscilloscope to see the clock, and comparing the data line with the clock. 
   - If you see the clock is not fast enough (for example, the rising/falling edge is longer than 1/4 of the clock cycle), it means the clock is skewed too much.
   - If you see the data line cannot be stable before the latch edge (rising edge) of the clock, it means the load of the data line is too large.

   You may also observed the corresponding phenomenon (data delayed largely from launching edge of clock) with logic analyzers. But it's not as obvious as an oscilloscope.

2. Try to use slower clock frequency to see if it works.

   It's an indication that the AC loading on the pins is too large, if lower frequency can work while higher frequency can't. 

If the AC loading of the pins is too large, you have no other choices but to use other faster devices (with lower pin load), or slow down the clock speed.

DC loading
^^^^^^^^^^

The pull-ups required by SD cards are usually around 10 kOhm to 50 kOhm, which may be too large for some other SPI devices. 

Check the specification about the DC output current of your device, it should be larger than 500uA. For example, the LCD on Espressif official Wrover devkit has only 1uA drive strength, whic is not sufficient to drive such pull-ups. When using SD card with such devices, the output of these devices cannot be read correctly by the host.

Initialization sequence
-----------------------

.. note::

  To avoid the influence of pin loading (see above section), please make sure the timing is correct, or set the clock speed of slower (SDMMC_FREQ_PROBING = 400KH for SD card) before continuing.

When using the SD card with other SPI devices on the same SPI bus, due to the restrictions of SD card startup flow, the following initialization sequence must be followed: (See also :example:`storage/sd_card`)

1. Initialize the SPI bus properly by `spi_bus_initialize`.
2. Tie the CS lines of all other devices to high. This is to avoid conflicts to the SD card in the following step.

   You can do this by either:
   1. Attach devices to the SPI bus by calling `spi_bus_add_device`. This function will initialize the GPIO that is used as CS to the idle level: high.
   2. Initialize GPIO on the CS pin that needs to be tied up before actually adding a new device.
   3. Rely on the internal/external pull-up (not recommended). You need to check carefull the pull-up is strong enough and there are no other pull-down that will influence the pull-up (For example, internal pull-down is not enabled).

3. Mount the card to the filesystem by calling `esp_vfs_fat_sdspi_mount`. 
   This step will put the SD card into the SPI mode, which MUST be done before all other SPI communications on the same bus. Otherwise the card will stay in the SD mode, in which it may randomly respond to any SPI communications on the bus, even when its CS line is not addressed. 

   If you want to test this behavior, please also note that, once the card is put into SPI mode, it will not return to SD mode before next power cycle, i.e. powered down and powered up again.

4. Now you can talk to other SPI devices freely!

@espressif-bot espressif-bot added Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Resolution: Done Issue is done internally and removed Resolution: NA Issue resolution is unavailable labels Dec 27, 2021
@Alvin1Zhang
Copy link
Collaborator

Thanks for reporting, sorry for late reply, the fix is available 5cc4bce, feel free to reopen if the issue still happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

5 participants