SPI Master fails to read MISO correctly on Mode 3
-
- Posts: 6
- Joined: Fri Jul 14, 2023 7:15 am
SPI Master fails to read MISO correctly on Mode 3
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: 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.
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?
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: 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.
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?
Re: SPI Master fails to read MISO correctly on Mode 3
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:
On the ESP32 it showed me a correct result (0x80) when i inject a pulse on the MISO line during rising edge of SCLK:
However on the ESP32-S3, running the exact same code (SPI-Mode 3) I get a 0x00!
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);
}
Re: SPI Master fails to read MISO correctly on Mode 3
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: 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?
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: 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?
-
- Posts: 6
- Joined: Fri Jul 14, 2023 7:15 am
Re: SPI Master fails to read MISO correctly on Mode 3
Any reaction here from Espressif team?
Re: SPI Master fails to read MISO correctly on Mode 3
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.
Re: SPI Master fails to read MISO correctly on Mode 3
Hi
try it
try it
Code: Select all
spi_device_interface_config_t
.flag = SPI_DEVICE_NO_DUMMY
Re: SPI Master fails to read MISO correctly on Mode 3
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.
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.
Re: SPI Master fails to read MISO correctly on Mode 3
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
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;
}
}
Re: SPI Master fails to read MISO correctly on Mode 3
Thank you for that hint.ok-home wrote: ↑Wed Nov 15, 2023 3:43 amHi
try itCode: Select all
spi_device_interface_config_t .flag = SPI_DEVICE_NO_DUMMY
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);
}
Re: SPI Master fails to read MISO correctly on Mode 3
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.ok-home wrote: ↑Wed Nov 15, 2023 2:52 pmI 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
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: Majestic-12 [Bot] and 285 guests