Getting garbage data or missing data in SPI communication with NRF52840 board with two SPI slaves. Using SDK 17.1

Hi, I am trying to do the SPI communication between  a SPI master and two SPI slaves. I am using NRF52840 Dev Kit as SPI master and 2 ESP32-S3 as SPI slaves. I am using SDK version 17.1 for NRF. I am  sending and receiving a 32 bytes of data. My work flow is to send a 32 Bytes of data from Master to Slave then Slave will respond on that . So as per the SPI I need to send two commands from Master to read the data from Slave. In first command '0x11', Slave will prepare the data on its side, then Master will send a dummy command  '0x13' to read that data. Currently for debugging I have added a  dummy data to transmit and receive. Total data which I may need to transmit or receive could be 2 Kbytes.

For template I have used the SPI example from the SDK peripheral example

I have used the following pins for SPI master on NRF side

#define ESP1_IO_PIN               36
#define ESP_32_S3_1_PWR      6              // MUX Select PIN
#define ESP_ESP_32_S3_1_TRIG 15

#define ESP_32_S3_1_SS         12       // P0.12
#define ESP1_SPI_MISO_PIN   11      // P0.11
#define ESP1_SPI_MOSI_PIN   41     // P1.09
#define ESP1_SPI_SCK_PIN     40    // P1.08
#define ESP1_EN_PIN               33   // P1.08


#define ESP2_IO_PIN                    43
#define ESP_32_S3_2_PWR          46


#define ESP_32_S3_2_SS          45
#define ESP2_SPI_MISO_PIN    13
#define ESP2_SPI_MOSI_PIN    17
#define ESP2_SPI_SCK_PIN      16
#define ESP2_EN_PIN                44 // P1.08


#define ESP_32_S3_1_SPI_INSTANCE 1
#define ESP_32_S3_2_SPI_INSTANCE 2

I have added the main.c code here

/**
 * Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include "nrf_drv_spi.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "boards.h"
#include "app_error.h"
#include <string.h>
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


 

#define DATA_CHECKSUM 255 // This value is calculated depending upon the value recevied by master.
uint8_t dataChecksum = 0;
void createChecksumforData();


#define ESP1_IO_PIN             36
#define	ESP_32_S3_1_PWR         6					// MUX Select PIN		        			
#define ESP_ESP_32_S3_1_TRIG    15
			
#define ESP_32_S3_1_SS          12          // P0.12
#define ESP1_SPI_MISO_PIN       11         // P0.11
#define ESP1_SPI_MOSI_PIN       41         // P1.09
#define ESP1_SPI_SCK_PIN        40        // P1.08
#define ESP1_EN_PIN             33        // P1.08


#define ESP2_IO_PIN             43 
#define ESP_32_S3_2_PWR         46
			// Chip select pin for SPI 2 interface
				
#define ESP_32_S3_2_SS          45 
#define ESP2_SPI_MISO_PIN       13
#define ESP2_SPI_MOSI_PIN       17 
#define ESP2_SPI_SCK_PIN        16  
#define ESP2_EN_PIN             44        // P1.08 


#define ESP_32_S3_1_SPI_INSTANCE 1
#define ESP_32_S3_2_SPI_INSTANCE 2

static const nrf_drv_spi_t esp_1_spi = NRF_DRV_SPI_INSTANCE(ESP_32_S3_1_SPI_INSTANCE);  /**< SPI instance. */
static const nrf_drv_spi_t esp_2_spi = NRF_DRV_SPI_INSTANCE(ESP_32_S3_2_SPI_INSTANCE);  /**< SPI instance. */


static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */

//uint8_t 
#define BUFFER_SIZE 32
uint8_t imageChecksum = 0;

static uint8_t       m_tx1_buf[BUFFER_SIZE] ={0};                
static uint8_t       m_rx1_buf[BUFFER_SIZE];    /**< RX buffer. */
static const uint8_t m_length1 = sizeof(m_tx1_buf);        /**< Transfer length. */

static uint8_t       m_tx2_buf[BUFFER_SIZE] ={0};                
static uint8_t       m_rx2_buf[BUFFER_SIZE];    /**< RX buffer. */
static const uint8_t m_length2 = sizeof(m_tx2_buf);        /**< Transfer length. */
/**
 * @brief SPI user event handler.
 * @param event
 */
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                       void *                    p_context)
{
    spi_xfer_done = true;
    NRF_LOG_INFO("Transfer completed.");
    // if (m_rx_buf[0] != 0) // Check received data in SPI Rx buffer
    {
        //NRF_LOG_INFO(" Received:");
        //NRF_LOG_HEXDUMP_INFO(m_rx_buf, sizeof(m_rx_buf));
    }
}

bool toggle = 1;

int main(void)
{

  nrf_gpio_cfg_output(ESP_32_S3_2_PWR);
  nrf_gpio_pin_clear(ESP_32_S3_2_PWR);

  nrf_gpio_cfg_output(ESP_32_S3_1_PWR);
  nrf_gpio_pin_clear(ESP_32_S3_1_PWR);

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    nrf_gpio_cfg_output(ESP_32_S3_2_PWR);
    nrf_gpio_pin_set(ESP_32_S3_2_PWR);
    nrf_gpio_cfg_output(ESP_32_S3_1_PWR);
    nrf_gpio_pin_set(ESP_32_S3_1_PWR);
    nrf_delay_ms(5000);

     nrf_drv_spi_config_t spi_esp1_config = NRF_DRV_SPI_DEFAULT_CONFIG;
     nrf_drv_spi_config_t spi_esp2_config = NRF_DRV_SPI_DEFAULT_CONFIG;

     spi_esp1_config.ss_pin   =  NRF_DRV_SPI_PIN_NOT_USED;//SPI_SS_PIN;//
     spi_esp1_config.miso_pin =  ESP1_SPI_MISO_PIN;        // SPI_MISO_PIN
     spi_esp1_config.mosi_pin =  ESP1_SPI_MOSI_PIN;        // SPI_MOSI_PIN;
     spi_esp1_config.sck_pin  =  ESP1_SPI_SCK_PIN;         // SPI_SCK_PIN;
     spi_esp1_config.mode     =  NRF_DRV_SPI_MODE_0;
     spi_esp1_config.frequency = NRF_DRV_SPI_FREQ_4M;

     spi_esp2_config.ss_pin   =  NRF_DRV_SPI_PIN_NOT_USED;//SPI_SS_PIN;//
     spi_esp2_config.miso_pin =  ESP2_SPI_MISO_PIN;        // SPI_MISO_PIN
     spi_esp2_config.mosi_pin =  ESP2_SPI_MOSI_PIN;        // SPI_MOSI_PIN;
     spi_esp2_config.sck_pin  =  ESP2_SPI_SCK_PIN;         // SPI_SCK_PIN;
     spi_esp2_config.mode     =  NRF_DRV_SPI_MODE_0;
     spi_esp2_config.frequency = NRF_DRV_SPI_FREQ_4M;

     APP_ERROR_CHECK(nrf_drv_spi_init(&esp_1_spi, &spi_esp1_config, NULL, NULL));
     APP_ERROR_CHECK(nrf_drv_spi_init(&esp_2_spi, &spi_esp2_config, NULL, NULL));

    NRF_P0->PIN_CNF[ESP2_SPI_SCK_PIN] |= (NRF_GPIO_PIN_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);
    NRF_P1->PIN_CNF[8] |= (NRF_GPIO_PIN_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);

    nrf_gpio_cfg_output(ESP_32_S3_1_SS);
    nrf_gpio_pin_set(ESP_32_S3_1_SS);
    nrf_gpio_cfg_output(ESP_32_S3_2_SS);
    nrf_gpio_pin_set(ESP_32_S3_2_SS);



    NRF_LOG_INFO("SPI example started.");
    int sent_once = 0;
    while (1)
    {
        // Reset rx buffer and transfer done flag
        memset(m_rx1_buf, 0, sizeof(m_rx1_buf));
        memset(m_rx2_buf, 0, sizeof(m_rx2_buf));
    if(toggle == 1){
        m_tx1_buf[0] = 0x11;
        m_tx1_buf[1] = 0xfa;
        m_tx1_buf[2] = 0xfb;
         for(uint8_t i =3;i<BUFFER_SIZE;i++){
            m_tx1_buf[i] =  i;
         }
         
        m_tx2_buf[0] = 0x12;
        m_tx2_buf[1] = 0xfa;
        m_tx2_buf[2] = 0xfb;
         for(uint8_t i =3;i<BUFFER_SIZE;i++){
            m_tx2_buf[i] =  i;
         }
        printf("Command sent- %xd \n",m_tx1_buf[0]);
        nrf_gpio_pin_clear(ESP_32_S3_1_SS);
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&esp_1_spi, m_tx1_buf,BUFFER_SIZE, NULL, 0));
        nrf_gpio_pin_set(ESP_32_S3_1_SS);
     
   }
   else{
        m_tx1_buf[0] = 0x13;
        for(uint8_t i =1;i<BUFFER_SIZE;i++){
          m_tx1_buf[i] =  0;
        }
        m_tx2_buf[0] = 0x13;
        for(uint8_t i =1;i<BUFFER_SIZE;i++){
          m_tx2_buf[i] =  0;
        }
 

        nrf_gpio_pin_clear(ESP_32_S3_1_SS);
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&esp_1_spi, m_tx1_buf, 1, NULL, 0));
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&esp_1_spi, NULL, 0, m_rx1_buf, BUFFER_SIZE));
        //APP_ERROR_CHECK(nrf_drv_spi_transfer(&esp_1_spi, m_tx1_buf, 1, m_rx1_buf, BUFFER_SIZE));
        nrf_gpio_pin_set(ESP_32_S3_1_SS);
        printf("Command sent- %xd \n",m_tx1_buf[0]);
        createChecksumforImage();
      }
      toggle = ! toggle;
      nrf_delay_ms(40);
  }
}

void createChecksumforImage()
{
  for (uint32_t i = 0; i < 32; i++)
  {
    imageChecksum = imageChecksum ^ m_rx1_buf[i];
    printf("Rx buff - %d\n",m_rx1_buf[i]);
  }
  printf("Calculated checksum - %d \n",imageChecksum);
  if((imageChecksum == DATA_CHECKSUM) || (imageChecksum == 0)){
       printf("correct checksum \n ");
  }
  else{
    printf("checksum wrong \n ");
    while(1);
  }
}

I have uploaded the SPI master code for NRF

spi_master_code_nrf_side_tested221222.zip

Here, I have uploaded the code for ESP32-S3 

3806.spi_slave_esp32s3.zip

Issues

  1. While communicating with NRF with ESP32-S3 I have to put delay in NRF side code.
  2. Otherwise it will receive some garbage for some bytes or zero
  3. I have tested with providing different delays like 30 ms, 40 ms , 50 ms, but I am able to get exact data without any loss or garbage on 50 ms delay or more than any value of 50 ms only.
  4. I have calculated the checksum for whole 32 Bytes of data to check if data get corrupted
  5. I want to remove that delay to get max speed for transmission.

    In case of setting the delay to 10 ms

In case of setting delay to 30 ms

In case of setting the delay to 50 ms

Please give me suggestion for how to resolve this issue for removing the delay from the code.

Parents Reply Children
No Data
Related