Page 1 of 1

Problem with spi_master driver and two mixed-duplex devices

Posted: Sat Jan 04, 2020 6:18 pm
by Alemarius Nexus
Hi,

I'm trying to get the spi_master driver to work with two devices on the same bus. My problem is that when one device is half-duplex and the other is full-duplex, it doesn't behave as expected. I'm using the following code:

  1. #include <stdio.h>
  2. #include "esp_system.h"
  3. #include "esp_event.h"
  4. #include "driver/spi_master.h"
  5.  
  6.  
  7. #define TEST_MISO_PIN 19
  8. #define TEST_MOSI_PIN 18
  9. #define TEST_SCLK_PIN 5
  10. #define TEST_CS1_PIN 27
  11. #define TEST_CS2_PIN 32
  12.  
  13.  
  14. void app_main(void)
  15. {
  16.     static spi_device_handle_t spi1;
  17.     static spi_device_handle_t spi2;
  18.  
  19.  
  20.     // Initialize SPI bus
  21.     {
  22.         spi_bus_config_t buscfg = {
  23.             .miso_io_num = TEST_MISO_PIN,
  24.             .mosi_io_num = TEST_MOSI_PIN,
  25.             .sclk_io_num = TEST_SCLK_PIN,
  26.             .quadwp_io_num = -1,
  27.             .quadhd_io_num = -1
  28.         };
  29.  
  30.         ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &buscfg, 0));
  31.     }
  32.  
  33.     // Setup SPI device 1 (half-duplex)
  34.     {
  35.         spi_device_interface_config_t devcfg = {
  36.             .clock_speed_hz = 1*100*1000,
  37.             .mode = 0,
  38.             .queue_size = 1,
  39.             .flags = SPI_DEVICE_HALFDUPLEX,
  40.             .spics_io_num = TEST_CS1_PIN
  41.         };
  42.  
  43.         ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &spi1));
  44.     }
  45.  
  46.     // Setup SPI device 2 (full-duplex, 8 addr. bits)
  47.     {
  48.         spi_device_interface_config_t devcfg = {
  49.             .clock_speed_hz = 1*100*1000,
  50.             .mode = 0,
  51.             .queue_size = 1,
  52.             .flags = 0,
  53.             .command_bits = 0,
  54.             .address_bits = 8,
  55.             .spics_io_num = TEST_CS2_PIN
  56.         };
  57.  
  58.         ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &spi2));
  59.     }
  60.  
  61.  
  62.     printf("Starting in 2s...\n");
  63.     sleep(2);
  64.  
  65.     // Do a dummy transfer on device 1
  66.     {
  67.         uint8_t cmd = 0x3A;
  68.         spi_transaction_t t = {
  69.             .length = 8,
  70.             .tx_buffer = &cmd
  71.         };
  72.         spi_device_transmit(spi1, &t);
  73.     }
  74.  
  75.     // Do a 16-bit full-duplex transfer (+8 addr. bits) on device 2
  76.     {
  77.         spi_transaction_t t = {
  78.             .length = 16,
  79.             .rxlength = 16,
  80.             .flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA
  81.         };
  82.         uint8_t addr = 0x00;
  83.         t.addr = addr | 0x80;
  84.         t.tx_data[0] = (addr+1) | 0x80;
  85.         t.tx_data[1] = 0x00;
  86.         t.tx_data[2] = 0x13;
  87.         t.tx_data[3] = 0x37;
  88.         ESP_ERROR_CHECK(spi_device_transmit(spi2, &t));
  89.     }
  90. }

For debugging purposes, I have removed both of the actual SPI slaves from the bus, so the only thing that's connected to them is the ESP32. See the attached image for what my logic analyzer shows for this code.

For the second transaction, the driver seems to drive the chip for two more 8-bit cycles than expected. It looks like it's actually operating the transaction in half-duplex mode, although the device is configured as full-duplex. This happens only when I do the first dummy transaction - if I remove the first spi_device_transmit, the other transaction behaves as expected.

The logs don't seem to show anything useful:

I (28) boot: ESP-IDF v4.0-beta2-dirty 2nd stage bootloader
I (29) boot: compile time 18:44:54
I (29) boot: Enabling RNG early entropy source...
I (34) boot: SPI Speed : 40MHz
I (38) boot: SPI Mode : DIO
I (42) boot: SPI Flash Size : 2MB
I (46) boot: Partition Table:
I (50) boot: ## Label Usage Type ST Offset Length
I (57) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (72) boot: 2 factory factory app 00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x0717c ( 29052) map
I (103) esp_image: segment 1: paddr=0x000171a4 vaddr=0x3ffb0000 size=0x0207c ( 8316) load
I (107) esp_image: segment 2: paddr=0x00019228 vaddr=0x40080000 size=0x00400 ( 1024) load
0x40080000: _WindowOverflow4 at /opt/esp-idf/components/freertos/xtensa_vectors.S:1778

I (111) esp_image: segment 3: paddr=0x00019630 vaddr=0x40080400 size=0x069e0 ( 27104) load
I (131) esp_image: segment 4: paddr=0x00020018 vaddr=0x400d0018 size=0x14640 ( 83520) map
0x400d0018: _stext at ??:?

I (161) esp_image: segment 5: paddr=0x00034660 vaddr=0x40086de0 size=0x03aa0 ( 15008) load
0x40086de0: rtc_clk_cpu_freq_get_config at /opt/esp-idf/components/soc/esp32/rtc_clk.c:650

I (174) boot: Loaded app from partition at offset 0x10000
I (174) boot: Disabling RNG early entropy source...
I (175) cpu_start: Pro cpu up.
I (178) cpu_start: Application information:
I (183) cpu_start: Project name: app-template
I (189) cpu_start: App version: 1
I (193) cpu_start: Compile time: Jan 4 2020 18:44:43
I (199) cpu_start: ELF file SHA256: 78fef31c0db07f90...
I (205) cpu_start: ESP-IDF: v4.0-beta2-dirty
I (211) cpu_start: Starting app cpu, entry point is 0x400810a0
0x400810a0: call_start_cpu1 at /opt/esp-idf/components/esp32/cpu_start.c:272

I (0) cpu_start: App cpu up.
I (221) heap_init: Initializing. RAM available for dynamic allocation:
I (228) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (234) heap_init: At 3FFB30A8 len 0002CF58 (179 KiB): DRAM
I (240) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (247) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (253) heap_init: At 4008A880 len 00015780 (85 KiB): IRAM
I (259) cpu_start: Pro cpu start user code
I (277) spi_flash: detected chip: generic
I (278) spi_flash: flash io: dio
W (278) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (289) cpu_start: Chip Revision: 1
W (293) cpu_start: Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.
I (303) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Starting in 2s...

For reference, I'm using an Adafruit HUZZAH32 development board and ESP-IDF 4.0-beta2.

Any ideas?

Re: Problem with spi_master driver and two mixed-duplex devices

Posted: Wed Feb 10, 2021 11:05 pm
by iosixllc
I'm having the same problem, only on esp-idf 4+, works fine in 3.3.

Transactions are working fine, but as soon as I run a transaction with the half-duplex device, everything goes to hell on the other devices. See screenshots attached.

Re: Problem with spi_master driver and two mixed-duplex devices

Posted: Thu Feb 11, 2021 10:19 pm
by iosixllc
Bug fix for esp-idf 4.0, 4.1, 4.2 (code is different in 4.3):
Add line: hal->half_duplex = dev->cfg.flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;

To spi_setup_device() in components/driver/spi_master.c:

static void SPI_MASTER_ISR_ATTR spi_setup_device(spi_host_t *host, int dev_id)
{
//if the configuration is already applied, skip the following.
if (dev_id == host->prev_cs) {
return;
}

ESP_EARLY_LOGD(SPI_TAG, "SPI device changed from %d to %d", host->prev_cs, dev_id);
spi_device_t *dev = atomic_load(&host->device[dev_id]);

spi_hal_context_t *hal = &host->hal;
hal->mode = dev->cfg.mode;
hal->half_duplex = dev->cfg.flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
hal->tx_lsbfirst = dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST ? 1 : 0;
hal->rx_lsbfirst = dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST ? 1 : 0;
hal->no_compensate = dev->cfg.flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
hal->sio = dev->cfg.flags & SPI_DEVICE_3WIRE ? 1 : 0;
hal->dummy_bits = dev->cfg.dummy_bits;
hal->cs_setup = dev->cfg.cs_ena_pretrans;
hal->cs_hold =dev->cfg.cs_ena_posttrans;
//set hold_time to 0 will not actually append delay to CS
//set it to 1 since we do need at least one clock of hold time in most cases
if (hal->cs_hold == 0) hal->cs_hold = 1;
hal->cs_pin_id = dev_id;
hal->timing_conf = &dev->timing_conf;

spi_hal_setup_device(hal);

//Record the device just configured to save time for next time
host->prev_cs = dev_id;
}

Re: Problem with spi_master driver and two mixed-duplex devices

Posted: Wed Jun 16, 2021 7:49 am
by haraldnagy
Hi!

This solution doesn't work for me.
Setup: Two SPI devices; the first one is a full-duplex device with positive CS, the second one is a half-duplex device with "normal" negative CS.

The first one alone works perfectly, the second one alone works perfectly; if both are used nothing is working at all.

Any solution for this?

Re: Problem with spi_master driver and two mixed-duplex devices

Posted: Tue Jul 06, 2021 3:48 pm
by pipehappy
Any update on this issue and get fixed on new version of idf? I'm using 4.2 and have the exactly the same issue...

Re: Problem with spi_master driver and two mixed-duplex devices

Posted: Thu Dec 16, 2021 11:11 pm
by apuder
I also ran into the same issue: I'm using full-duplex to talk to a SD card and half-duplex to another SPI device. The patch that is mention in this thread unfortunately does not work for me.

AP