ESP32 master to SAMD21(Arduino Zero) slave full duplex SPI data exchange issue.

newcomer777
Posts: 3
Joined: Tue Apr 11, 2023 6:57 am

ESP32 master to SAMD21(Arduino Zero) slave full duplex SPI data exchange issue.

Postby newcomer777 » Thu Jul 06, 2023 10:24 am

ESP32(master) and SAMD21(slave) use SPI bus to communicate. At ESP32 side MISO = GPIO_NUM_19, MOSI = GPIO_NUM_23, CLK = GPIO_NUM_18 though CS = GPIO 12(gpio 5 and 2 will be used for another SPI devices) . The master has 32 bytes TX buffer and the same size RX buffer. Once a second the master sends a pack of 32 bytes (0x00... 0x1F) and supposes to receive 32 bytes (0xA0... 0xBF).
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "freertos/FreeRTOS.h"
  4. #include "freertos/task.h"
  5. #include "driver/spi_master.h"
  6. #include "esp_log.h"
  7. #include "driver/gpio.h"
  8.  
  9. #define CS_SAMD21 GPIO_NUM_12
  10. #define RADIO_RX_BUF_LEN 32
  11. #define RADIO_TX_BUF_LEN 32
  12.  
  13. typedef enum{
  14.     NONE = 0xF0,
  15.     GET_ALL = 0xF1,
  16.     GET_RADIO = 0xF2,
  17.     GET_LASER = 0xF3,
  18.     GET_AUX = 0xF4,
  19.     GET_EXT = 0xF5,
  20.     TAKE_RADIO = 0xF6,
  21.     TAKE_DISCR = 0xF7
  22. }SPI_cmd_t;
  23.  
  24. #define SPI_CLOCK_SPEED     1000000  
  25. #define TAG "M"
  26.  
  27. spi_device_handle_t SPI_W25Q128;
  28. spi_device_handle_t SPI_SAMD21;
  29. spi_device_handle_t SPI_NANO;
  30. uint8_t tx_buf[RADIO_TX_BUF_LEN] = {
  31.         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  32.         10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  33.         20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  34.         30, 31
  35. };
  36.  
  37. void spi_init()
  38. {
  39.     esp_err_t ret;
  40.  
  41.     spi_bus_config_t buscfg = {
  42.         .miso_io_num = GPIO_NUM_19,  
  43.         .mosi_io_num = GPIO_NUM_23,  
  44.         .sclk_io_num = GPIO_NUM_18,  
  45.         .quadwp_io_num = -1,
  46.         .quadhd_io_num = -1,
  47.         .max_transfer_sz = 0,
  48.     };
  49.  
  50.     spi_device_interface_config_t devcfg = {
  51.         .command_bits = 0,
  52.         .address_bits = 0,
  53.         .dummy_bits = 0,
  54.         .mode = 0,
  55.         .duty_cycle_pos = 0,
  56.         .cs_ena_pretrans = 0,
  57.         .cs_ena_posttrans = 0,
  58.         .clock_speed_hz = SPI_CLOCK_SPEED,
  59.         .input_delay_ns = 0,
  60.         .spics_io_num = -1,
  61.         .flags = 0,
  62.         .queue_size = 1,
  63.         .pre_cb = NULL,
  64.         .post_cb = NULL,
  65.     };
  66.  
  67.     // SPI bus init
  68.     ret = spi_bus_initialize(SPI2_HOST, &buscfg, 1);
  69.     assert(ret == ESP_OK);
  70.     // add slave to the bus
  71.     devcfg.spics_io_num = CS_SAMD21;
  72.     ret = spi_bus_add_device(SPI2_HOST, &devcfg, &SPI_SAMD21);
  73.     assert(ret == ESP_OK);
  74. }
  75.  
  76. void spi_exchange_data(spi_device_handle_t device, const uint8_t *tx_data, uint8_t *rx_data, size_t len)
  77. {
  78.     spi_transaction_t t;
  79.     memset(&t, 0, sizeof(t));
  80.  
  81.     t.length = len * 8;  
  82.     t.rxlength = len * 8;
  83.     t.rx_buffer = rx_data;
  84.     t.tx_buffer = tx_data;
  85.     esp_err_t ret = spi_device_transmit(device, &t);
  86.     assert(ret == ESP_OK);
  87. }
  88.  
  89. void app_main(void)
  90. {
  91.     spi_init();
  92.     vTaskDelay(1000 / portTICK_PERIOD_MS);
  93.  
  94.     while (1)
  95.     {
  96.         vTaskDelay(1000 / portTICK_PERIOD_MS);
  97.         uint8_t rx_data[RADIO_RX_BUF_LEN] = {0};
  98.         spi_exchange_data(SPI_SAMD21, tx_buf, rx_data, RADIO_TX_BUF_LEN);
  99.         ESP_LOGI(TAG, "received: ");
  100.         for(uint8_t i = 0; i<RADIO_RX_BUF_LEN; i++){
  101.         printf("%x ", rx_data[i]);
  102.         }
  103.         printf("\n");
  104.  
  105.     }
  106. }
I implemented SPI handler logger at slave side and it seems that the slave receives/sends data all right. There is no data corruption at the slave side. However there are the first 4 spi handler envokings which look strange.
  1. trig 1  write A0  leave  //wtf?
  2. trig 8  SSL  leave  //wtf?
  3. trig 8  SSL  leave  //wtf?
  4. trig 2  TXC  leave  //wtf?
  5. trig 8  SSL  leave  // since here all looks as expected
  6. trig 5  read 0  write A0  leave  
  7. trig 5  read 1  write A1  leave  
  8. trig 5  read 2  write A2  leave  
  9. trig 5  read 3  write A3  leave  
  10. trig 5  read 4  write A4  leave
  11. ...etc
Unfortunately there is worse situation at the master's side. The received pack is always shifted to the right on 2 bytes because of unknown reason:
  1. I (10979324) M: received:
  2. 0 a0 a0 a1 a2 a3 a4 a5 a6 a7 9 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc
  3. I (10980324) M: received:
  4. bd be a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd
  5. I (10981324) M: received:
  6. be bf a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd
Any ideas why the master acts like that? Any suggestions?

newcomer777
Posts: 3
Joined: Tue Apr 11, 2023 6:57 am

Re: ESP32 master to SAMD21(Arduino Zero) slave full duplex SPI data exchange issue.

Postby newcomer777 » Fri Jul 07, 2023 9:22 am

Factually I made it working using sort of workaround:
in spi_device_interface_config_t devcfg configuration I used .command_bits = 16 as though the master sends 2 bytes command first. Definitely the RX buffer at the slave side should be 2 bytes larger since the first 2 bytes command ( which are actually zeros) have no sense. This way the master gets data as expected.
This workaround makes me thinking that there is a bug in the framework (v.5.0 btw), or there are specific SPI full duplex moments which are not documented. Feel free to correct me if I am mistaken.

Who is online

Users browsing this forum: No registered users and 105 guests