ESP32-S3 freeze in spi_device_transmit() when transaction length is 1 bit (IDFGH-15396)
Answers checklist.
- [x] I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
- [x] I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
- [x] I have searched the issue tracker for a similar issue and not found a similar issue.
IDF version.
v5.4.1
Espressif SoC revision.
ESP32-S3
Operating System used.
Linux
How did you build your project?
Command line with idf.py
If you are using Windows, please specify command line type.
None
Development Kit.
ESP32-S3-DevKitC-1-N16R8
Power Supply used.
USB
What is the expected behavior?
Data is sent over SPI and control is returned from the spi_device_transmit() function.
What is the actual behavior?
Execution freezes inside spi_device_transmit() function, no data is sent over SPI.
Steps to reproduce.
- Execute this code on ESP32-S3 and it will freeze inside the spi_device_transmit().
- Execute it on a regular ESP32 and it will work as expected.
static spi_device_handle_t deviceSPI;
spi_bus_config_t buscfg = {
.mosi_io_num = GPIO_NUM_2, // SWD I/O
.miso_io_num = -1, // not connected
.sclk_io_num = GPIO_NUM_1, // SWD CLK
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0
};
spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_DISABLED);
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = 100000,
.spics_io_num = -1,
.flags = SPI_DEVICE_3WIRE | SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_BIT_LSBFIRST,
.queue_size = 24,
.pre_cb = NULL,
.post_cb = NULL
};
spi_bus_add_device(SPI2_HOST, &devcfg, &deviceSPI)
spi_transaction_t transSPI;
memset(&transSPI, 0, sizeof(spi_transaction_t));
// simulated transaction from libswd
transSPI.flags = SPI_TRANS_USE_TXDATA;
transSPI.cmd = 0;
transSPI.addr = 0;
transSPI.length = 1; // freeze with length=1 only
transSPI.rxlength = 0;
transSPI.tx_data[0] = 0;
transSPI.tx_data[1] = 0;
transSPI.tx_data[2] = 0;
transSPI.tx_data[3] = 0;
spi_device_transmit(deviceSPI, &transSPI); // <=== FREEZE HERE
Debug Logs.
Diagnostic report archive.
No response
More Information.
The error only happens with length set to 1 (2, 3, 8.. work as expected).
I tried to compile and run the same code on a regular ESP32 and it works there.
I tried ESP-IDF v4.4.8, V5.4.1 and master (v6.0), nothing changed.
I tried measuring the output of the clock pin and it does not generate the impulse when length is set to 1, but it works with length set to 2 (on picture).
@wanckl any updates on the issue?
@python-destroyer
You already set SPI_DEVICE_3WIRE , then don't need SPI_DEVICE_HALFDUPLEX, remove halfduplex flag will work.
But thank you for your report, I'll add check for this condition.
@wanckl I removed SPI_DEVICE_HALFDUPLEX flag and it is not stuck in spi_device_transmit() anymore, but now I'm getting this error when trying to read from SPI:
E (294) spi_master: check_trans_valid(1055): rx length > tx length in full duplex mode
Here is the test code:
spi_transaction_t transSPI;
memset(&transSPI, 0, sizeof(spi_transaction_t));
transSPI.flags = SPI_TRANS_USE_RXDATA;
transSPI.cmd = 0;
transSPI.addr = 0;
transSPI.length = 0;
transSPI.rxlength = 3;
spi_device_transmit(deviceSPI, &transSPI);
I also tried setting transSPI.length = 3; transSPI.rxlength = 3;. In that case clock pulses are generated, but data pin is stuck low, even though I pulled it up with 1k resistor and did not connect any devices.
When I put the SPI_DEVICE_HALFDUPLEX back, it switches to input as expected, but one bit transmit doesn't work again.
@wanckl any updates on this? If I wasn't clear in my previous post, removing SPI_DEVICE_HALFDUPLEX does not solve the issue as SPI stops receiving data without that flag. I need both RX and TX working.
@python-destroyer Sorry for late, maybe hardware limitation, need time to check it
Probably known chip/silicon bug of S3/C3 and possibly others, but not old ESP32 (it work ok). Here you could find details: https://github.com/espressif/esp-idf/issues/8487
@python-destroyer Not sure if this is useful but I was encountering the same issue while trying to get libswd working on the esp32. I was able to get it to work and receive data by removing SPI_DEVICE_HALFDUPLEX and ensuring that length was set equal to rxlength in the spi_tranaction_t structure where I'm only trying to receive data. This corresponds to the following note in the documentation:
size_t rxlength Total data length received, should be not greater than length in full-duplex mode (0 defaults this to the value of length).
The only issue that I'm having now is that there's a random left bit shift when I'm receiving data. @Maksons @wanckl Do you know anything about this
@YutongGu This issue is not present on a regular esp32. I have libswd-esp32 fully working there, default configuration from the example is working. No need to remove halfduplex flag, it is a halfduplex mode (transmit and receive is done in turns over one wire). RX and TX length also does not have to be the same in halfduplex mode, which is probably causing a bit shift for you with them set to the same value.