ESP32 Master SPI bug in half-duplex mode ?

nleday
Posts: 1
Joined: Fri Aug 12, 2022 8:21 am

ESP32 Master SPI bug in half-duplex mode ?

Postby nleday » Fri Aug 12, 2022 9:07 am

Hello,

I am new to the forum but working with ESP32 chips for quite some time now, and I am running into the following issue.

For development of a product, I am integrating a W5500 SPI ethernet chipset with an ESP32-PICO-V3-02 in esp-idf v3.3.6

The driver (written using code extracted from esp-idf 4.4) is running reliably with SPI Master configured in Full-Duplex mode with DMA. However I would like to increase bus speed (currently 20MHz) and need to use Half-Duplex mode in order to raise bus speed to 40MHz, see details at the end of the post.

When trying to switch to Half-Duplex configuration with DMA, whatever the bus speed (I went down to 500KHz in order to capture transactions with a logic analyzer), some bytes get lost on multi-byte reads (single-byte reads seems to work fine). This problem happens at least on 2 bytes long reads, and not all the time. It is generally reading fine for a few transactions at startup before it starts to loose bytes (which reads as all zeros) on ALL following 2-bytes reads.

I am using SPI Master Address phase to send 24 bits header (Read address, bank etc.) followed by MISO phase only, as required by esp-idf driver, please see below.

SPI bus configuration:
  1. spi_bus_config_t buscfg = {
  2.     .mosi_io_num = 25,
  3.     .miso_io_num = 35,
  4.     .sclk_io_num = 4,
  5.     .quadwp_io_num = -1,
  6.     .quadhd_io_num = -1,
  7.     .max_transfer_sz = 0,
  8.     .flags = SPICOMMON_BUSFLAG_MASTER,
  9.     .intr_flags = 0
  10. };
  11. if (spi_bus_initialize(HSPI_HOST, &buscfg, 2) != ESP_OK)
  12. {
  13.     PRINT_FAIL();
  14.     return false;
  15. }
Spi device configuration:
  1. spi_device_interface_config_t devcfg = {
  2.     .command_bits = 0,
  3.     .address_bits = 24, // Address and Control phases in W5500 SPI frame
  4.     .mode = 0,
  5.     .duty_cycle_pos = 0,
  6.     .cs_ena_pretrans = 0,
  7.     .cs_ena_posttrans = 0,
  8.     .clock_speed_hz = 500000,
  9.     .input_delay_ns = 0,
  10.     .spics_io_num = 12,
  11.     .flags = SPI_DEVICE_HALFDUPLEX,
  12.     .queue_size = 20,
  13.     .pre_cb = NULL,
  14.     .post_cb = NULL
  15. };
Spi transaction setup:
  1. esp_err_t W5500_read(W5500NetIface_t emac, uint32_t address, void *value, uint32_t len)
  2. {
  3.     esp_err_t ret = ESP_OK;
  4.  
  5.     spi_transaction_t trans = {
  6.         .flags = len <= 4 ? SPI_TRANS_USE_RXDATA : 0,
  7.         .cmd = 0,
  8.         .addr = ((address & 0xFFFFFF) | (W5500_ACCESS_MODE_READ << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM),
  9.         .length = 0,
  10.         .rxlength = 8 * len,
  11.         .tx_buffer = NULL,
  12.         .rx_buffer = value
  13.     };
  14.  
  15.     if (W5500_lock(emac)) {
  16.         printf("Read @ %06X | len = %d - ", (uint32_t)trans.addr, len);
  17.         if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
  18.             ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
  19.             ret = ESP_FAIL;
  20.         }
  21.     } else {
  22.         ret = ESP_ERR_TIMEOUT;
  23.     }
  24.     if (len <= 4) {
  25.         printf("RXDATA : %02X %02X %02X %02X\r\n", (int)trans.rx_data[0], (int)trans.rx_data[1], (int)trans.rx_data[2], (int)trans.rx_data[3]);
  26.         memcpy(value, trans.rx_data, len);  // copy register values to output
  27.     }
  28.     else
  29.     {
  30.         printf("Buffer Read\r\n");
  31.     }
  32.     W5500_unlock(emac);
  33.     return ret;
  34. }
  • I make all tests @ 500KHz, showing the exact same behavior that I get at 20MHz or 40MHz
  • I tried using a DMA-capable allocated buffer even for small (< 4 bytes) read operations instead of rx_data with no success
  • I tried forcing 4-bytes read transactions with no success (in this case all 3 last bytes reads 0 even if the device is sending non-zero data)
  • I tried with option SPI_DEVICE_NO_DUMMY which does not work better even at 500KHz. In this case it is sometimes the first byte that get lost instead of the second
Below is a capture from my logic analyzer:
logic_1.JPG
logic_1.JPG (68.28 KiB) Viewed 1738 times
And matching console output from the W5500_read function:
  1. Read @ 002608 | len = 2 - RXDATA : 29 00 00 00

> ESP32 reads 29 00 instead of 29 28

Questions:
  • Is it a known issue ?
  • Is it corrected in more recent esp-idf version ? In which case I may be able to patch v3.3.6
Precisions:
  • The Write operations works fine in both Full-Duplex and Half-duplex modes
  • I already have a large codebase based on esp-idf 3.3.6 and in a hurry, so updating to esp-idf 4.4 for this product is not an option right now.
  • I am forced to use GPIO_MUX instead of IO_MUX because only HSPI IO_MUX pins are all available on ESP32-PICO-V3-02 module, but HSPI CLK (GPIO 14) is already used for an SD card wired in SDMMC mode (HSPI CLK is the same pin as SDMMC Master clock). Rewiring the SD card in SPI is not an option as I also need a second (dedicated) SPI port for a measurement chipset (must be real-time so no bus sharing), and only 2 SPI bus are freely available on the ESP. I also do not want to share an SPI bus between W5500 and SD card for performance reasons.
Thanks in advance for your help,
Best regards

ESP_ondrej
Posts: 166
Joined: Fri May 07, 2021 10:35 am

Re: ESP32 Master SPI bug in half-duplex mode ?

Postby ESP_ondrej » Tue Aug 16, 2022 1:32 pm

Hi nleday,

unfortunately, ESP-IDF version 3.3.6 is no longer supported. Please also check SPI documentation at https://docs.espressif.com/projects/esp ... own-issues if it helps you to resolve the issue.

Who is online

Users browsing this forum: No registered users and 103 guests