SPI Master fails to read MISO correctly on Mode 3

stefan.nagel
Posts: 6
Joined: Fri Jul 14, 2023 7:15 am

SPI Master fails to read MISO correctly on Mode 3

Postby stefan.nagel » Thu Nov 09, 2023 12:47 pm

Dear community,
We are facing major issues in the communication between a MODE 3 SPI slave and an ESP32-S3.

Please checkout here the following thread:
https://github.com/espressif/esp-idf/issues/7825
Here it is stated that the change on the MISO line must be AFTER the falling edge of the CLK. If the MISO line changes directly on the falling edge or before the falling edge, it cannot read data.

This is comparable with our measurement:
MISO_Working.png
MISO_Working.png (24.21 KiB) Viewed 10683 times
The change on the MISO line is here slightly after a falling edge. So the ESP reads here 0x55 and also our logic analyzer reads 0x55.
MISO_Not_Working.png
MISO_Not_Working.png (27.66 KiB) Viewed 10683 times
The MISO line is here changing exactly on the falling edge … from time to time, the MISO is also changing its line shortly before the falling edge. In this case the ESP cannot read the data and reads out 0x54, the logic analyzer still reads the correct data of 0xAA.


In my mind the ESP should not care about the transition of the MISO line, it should only check the actual state of the MISO line at the rising edge of the clock. Is there any idea how we can solve that problem?

chris6347
Posts: 4
Joined: Fri Nov 10, 2023 7:46 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby chris6347 » Fri Nov 10, 2023 9:23 am

I had a look into the Esp32-S3 Reference Manual and according to that MISO Line should be sampled on the rising edge of SCLK:
rm_mode3.PNG
rm_mode3.PNG (71 KiB) Viewed 10617 times
I wrote a quick program to check this:

Code: Select all

#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/spi_master.h>

// Define the SPI bus parameters
#  define PIN_NUM_MISO 12
#  define PIN_NUM_MOSI 13
#  define PIN_NUM_CLK  14
#  define PIN_NUM_CS   15
#  define SPI_HOST_NUM SPI2_HOST

void app_main()
{
    // Initialize the SPI bus
    spi_bus_config_t bus_config = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 0
    };
    
    esp_err_t ret = spi_bus_initialize(SPI_HOST_NUM, &bus_config, SPI_DMA_CH_AUTO);
    assert(ret == ESP_OK);

    // Attach the device to the SPI bus
    spi_device_interface_config_t dev_config = {
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .mode = 3,
        .duty_cycle_pos = 0,
        .cs_ena_pretrans = 1,
        .cs_ena_posttrans = 0,
        .clock_speed_hz = 1000000, // 1MHz clock speed
        .input_delay_ns = 0,
        .spics_io_num = PIN_NUM_CS,
        .flags = 0,
        .queue_size = 1
    };
    
    spi_device_handle_t spi;
    ret = spi_bus_add_device(SPI_HOST_NUM, &dev_config, &spi);
    assert(ret == ESP_OK);

    // Define the data to be transmitted (2 bytes)
    uint8_t tx_data[2] = {0x01, 0x02};

    // Define a buffer to receive the data
    uint8_t rx_data[2];

    // Prepare the SPI transaction
    spi_transaction_t trans = {
        .flags = 0,
        .cmd = 0,
        .addr = 0,
        .length = 8 * 2,  // 2 bytes
        .rxlength = 8 * 2,
        .tx_buffer = tx_data,
        .rx_buffer = rx_data
    };

    // Perform the SPI transaction
    while(1)
    {
        ret = spi_device_transmit(spi, &trans);
        assert(ret == ESP_OK);

        // Print the received data
        printf("Received: %02x %02x\n", rx_data[0], rx_data[1]);
        vTaskDelay(100);
    }

    // Clean up
    spi_bus_remove_device(spi);
    spi_bus_free(SPI_HOST_NUM);
}

On the ESP32 it showed me a correct result (0x80) when i inject a pulse on the MISO line during rising edge of SCLK:
wrover.png
wrover.png (79.86 KiB) Viewed 10617 times
However on the ESP32-S3, running the exact same code (SPI-Mode 3) I get a 0x00!
esp32s3_rising.png
esp32s3_rising.png (75.8 KiB) Viewed 10617 times

chris6347
Posts: 4
Joined: Fri Nov 10, 2023 7:46 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby chris6347 » Mon Nov 13, 2023 12:27 pm

One more info:

I have tried moving the high pulse over the falling edge, and suddenly the ESP32-S3 recognizes it, even though in it's SPI-Mode 3:
esp32s3_falling.png
esp32s3_falling.png (77.92 KiB) Viewed 10597 times
ESP IDF version is 5.1.1.
This seems to be like a major bug in either ESP IDF, or worse, the ESP32-S3 silicon, or not?

stefan.nagel
Posts: 6
Joined: Fri Jul 14, 2023 7:15 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby stefan.nagel » Tue Nov 14, 2023 9:28 am

Any reaction here from Espressif team?

martins
Posts: 51
Joined: Tue Aug 24, 2021 8:58 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby martins » Tue Nov 14, 2023 1:42 pm

I'm also having trouble setting correct timing with S3 and IDF v5.2-dev (only SPI Mode 2 seems correct) or IDFv4.4.6 (only SPI Mode 0 and 2 seems correct) while results on logic analyzer are correct for all modes. Something does not seem right.

User avatar
ok-home
Posts: 78
Joined: Sun May 02, 2021 7:23 pm
Location: Russia Novosibirsk
Contact:

Re: SPI Master fails to read MISO correctly on Mode 3

Postby ok-home » Wed Nov 15, 2023 3:43 am

Hi
try it

Code: Select all

spi_device_interface_config_t 
   .flag = SPI_DEVICE_NO_DUMMY

martins
Posts: 51
Joined: Tue Aug 24, 2021 8:58 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby martins » Wed Nov 15, 2023 1:50 pm

I see, so what I already did was to set both .command_bits and .address_bits to 0 as well as .spics_io_num to -1 and doing the write/read manually byte-by-byte, which allows me to have very safe delays between CS change as well as each byte transfer. This seems to have same effect as setting SPI_DEVICE_NO_DUMMY flag as there should be no addres phase, only the data phase (I can only see 8 clocks per byte as expected).

Currently even the mode 2 is broken for me. Judging by the data I read the ESP (master) just samples the RX data too late.

User avatar
ok-home
Posts: 78
Joined: Sun May 02, 2021 7:23 pm
Location: Russia Novosibirsk
Contact:

Re: SPI Master fails to read MISO correctly on Mode 3

Postby ok-home » Wed Nov 15, 2023 2:52 pm

SPI_DEVICE_NO_DUMMY
There are timing issue when reading at high frequency (the frequency is related to whether iomux pins are used, valid time after slave sees the clock).
In half-duplex mode, the driver automatically inserts dummy bits before reading phase to fix the timing issue. Set this flag to disable this feature.
In full-duplex mode, however, the hardware cannot use dummy bits, so there is no way to prevent data being read from getting corrupted. Set this flag to confirm that you’re going to work with output only, or read without dummy bits at your own risk.

in other words, it disables the driver logic, which itself determines which delays to set.

I didn’t look into it in detail, but there are probably answers to the questions here. And I think this is intentional and conscious.
https://github.com/espressif/esp-idf/bl ... hal.c#L133

Code: Select all

} else {
        //if the dummy is not required, maybe we should also delay half a SPI clock if the data comes too early
        if (delay_apb_n * 4 <= spiclk_apb_n) {
            miso_delay = -1;
        }
    }
 

chris6347
Posts: 4
Joined: Fri Nov 10, 2023 7:46 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby chris6347 » Wed Nov 15, 2023 3:18 pm

ok-home wrote:
Wed Nov 15, 2023 3:43 am
Hi
try it

Code: Select all

spi_device_interface_config_t 
   .flag = SPI_DEVICE_NO_DUMMY
Thank you for that hint.

However, I have tried this and it made no difference. I still see that the ESP32-S3 only reads MISO line on the falling edge of the SPI clock in SPI mode 3.

Here is the code i used with the proposed flag:

Code: Select all

#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/spi_master.h>

// Define the SPI bus parameters
#  define PIN_NUM_MISO 12
#  define PIN_NUM_MOSI 13
#  define PIN_NUM_CLK  14
#  define PIN_NUM_CS   15
#  define SPI_HOST_NUM SPI2_HOST

void app_main()
{
    // Initialize the SPI bus
    spi_bus_config_t bus_config = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 0
    };
    
    esp_err_t ret = spi_bus_initialize(SPI_HOST_NUM, &bus_config, SPI_DMA_CH_AUTO);
    assert(ret == ESP_OK);

    // Attach the device to the SPI bus
    spi_device_interface_config_t dev_config = {
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .mode = 3,
        .duty_cycle_pos = 0,
        .cs_ena_pretrans = 1,
        .cs_ena_posttrans = 0,
        .clock_speed_hz = 1000000, // 1MHz clock speed
        .input_delay_ns = 0,
        .spics_io_num = PIN_NUM_CS,
        .flags = SPI_DEVICE_NO_DUMMY,
        .queue_size = 1
    };
    
    spi_device_handle_t spi;
    ret = spi_bus_add_device(SPI_HOST_NUM, &dev_config, &spi);
    assert(ret == ESP_OK);

    // Define the data to be transmitted (2 bytes)
    uint8_t tx_data[2] = {0x01, 0x02};

    // Define a buffer to receive the data
    uint8_t rx_data[2];

    // Prepare the SPI transaction
    spi_transaction_t trans = {
        .flags = 0,
        .cmd = 0,
        .addr = 0,
        .length = 8 * 2,  // 2 bytes
        .rxlength = 8 * 2,
        .tx_buffer = tx_data,
        .rx_buffer = rx_data
    };

    // Perform the SPI transaction
    while(1)
    {
        ret = spi_device_transmit(spi, &trans);
        assert(ret == ESP_OK);

        // Print the received data
        printf("Received: %02x %02x\n", rx_data[0], rx_data[1]);
        vTaskDelay(100);
    }

    // Clean up
    spi_bus_remove_device(spi);
    spi_bus_free(SPI_HOST_NUM);
}


martins
Posts: 51
Joined: Tue Aug 24, 2021 8:58 am

Re: SPI Master fails to read MISO correctly on Mode 3

Postby martins » Thu Nov 16, 2023 12:17 pm

ok-home wrote:
Wed Nov 15, 2023 2:52 pm
I didn’t look into it in detail, but there are probably answers to the questions here. And I think this is intentional and conscious.
https://github.com/espressif/esp-idf/bl ... hal.c#L133
iiinteresting... So the debug output print of spi_hal_cal_timing() suggested that there is no MISO delay needed even without SPI_DEVICE_NO_DUMMY flag set and input_delay_ns = 0 at 3MHz SPI clock I was using. So I made local copy of driver and tried manually injecting the MISO delay value, but nothing changed.

Then I went back (reverted the manual MISO delay) and just set the SPI clock to 20MHz (SPI Slave's max in my case) and suddenly it started working IN ALL MODES. spi_hal_cal_timing() also returned -1 for delay, sugesting to compensate half a clock, so I've set input_delay_ns to something like (1000*1000*1000/SPI_CLK_FREQ)/2 - taken from the SPI EEPROM example.

EDIT: Apparently it works down to 15 MHz for me. Needless to say I need the SPI to work on lower frequencies too...

Who is online

Users browsing this forum: No registered users and 79 guests