esp-idf icon indicating copy to clipboard operation
esp-idf copied to clipboard

ESP32-S3 freeze in spi_device_transmit() when transaction length is 1 bit (IDFGH-15396)

Open python-destroyer opened this issue 6 months ago • 5 comments

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.

  1. Execute this code on ESP32-S3 and it will freeze inside the spi_device_transmit().
  2. 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).

Image

python-destroyer avatar May 29 '25 15:05 python-destroyer

@wanckl any updates on the issue?

python-destroyer avatar Jun 04 '25 16:06 python-destroyer

@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 avatar Jun 05 '25 13:06 wanckl

@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.

Image

When I put the SPI_DEVICE_HALFDUPLEX back, it switches to input as expected, but one bit transmit doesn't work again.

Image

python-destroyer avatar Jun 05 '25 13:06 python-destroyer

@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 avatar Jun 15 '25 11:06 python-destroyer

@python-destroyer Sorry for late, maybe hardware limitation, need time to check it

wanckl avatar Jun 16 '25 13:06 wanckl

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

Maksons avatar Jul 06 '25 19:07 Maksons

@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 avatar Jul 31 '25 00:07 YutongGu

@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.

python-destroyer avatar Jul 31 '25 06:07 python-destroyer