Is there a 32bit SPI slave Arduino uC?

Hi there,

I want to start a project where the Arduino hardware shall be a SPI slave and be able to receive 32bit data frames.

At the moment I tried 8bit Atmel controllers, hoping to be able to receive 4x8bit blocks of data fast enough, but I never succeeded.,
Then I used an ESP32, but here the ESP32 behaves in SPI slave mode different as I was expecting. It somehow acts like a serial eeprom. The first 8bit of data are the command and afterwards payload can be read or written. But this is not what I want to do. I want to receive 32bit of data.

Also other plattforms like the raspberry pi does not support SPI slave mode due to some hardware issues/erratas. (Please correct me if I am wrong. I never tried this.)

Do you know of any Arduino compatible board beeing a 32bit SPI slave?

ESP32 and SPI, did you use the Arduino Core or did you use the ESP32's SPI API?

I've used the ESP32's SPI API under the Arduino IDE for faster data transfers.

SPI Master Driver - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com)

SPI Slave Driver - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com)

ESP32_SPI_API.h

#include <driver/spi_master.h>
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
////////////////////////////////////
//
//#define MAGTYPE  true
//#define XGTYPE   false
//////////////////////////
///////////////////////////
//
////////////////////////////
 uint8_t GetLowBits();
 uint16_t GetHighBits();
 void fReadSPIdata16bits( spi_device_handle_t &h, int address );
 int fWriteSPIdata8bits( spi_device_handle_t &h, int address, int sendData );
 int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin);
// spi_device_handle_t fInitializeSPI_Devices( int csPin);
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA);
int fWriteSPIdata32bits( spi_device_handle_t &h, int _sendData0, int _sendData1, int _sendData2, int _sendData3 );
int fReadSPIdataXbits( spi_device_handle_t &h, int _readaddress, int *rxbuf, int rxlen );
int fWriteSPIdata8bits2( spi_device_handle_t &h, int _sendData );

ESP32_SPI.SPI.cpp

#include "ESP32_SPI_API.h"
/////////////////////////////
///////////////////////////
uint8_t txData[2] = { };
int8_t rxData[25] = { };
uint8_t low;
uint8_t high;
//////
//////////////////////////////////
uint8_t GetLowBits()
{
  return low;
}
uint16_t GetHighBits()
{
  return high;
}
////////////////////////////////////////
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA)
{
  esp_err_t intError;
  spi_bus_config_t bus_config = { };
  bus_config.sclk_io_num = spiCLK; // CLK
  bus_config.mosi_io_num = spiMOSI; // MOSI
  bus_config.miso_io_num = spiMISO; // MISO
  bus_config.quadwp_io_num = -1; // Not used
  bus_config.quadhd_io_num = -1; // Not used
  intError = spi_bus_initialize( HSPI_HOST, &bus_config, EnableDMA) ;
  return intError;
}
//////
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin)
{
  esp_err_t intError;
  spi_device_interface_config_t dev_config = { };  // initializes all field to 0
  dev_config.address_bits     = 0;
  dev_config.command_bits     = 0;
  dev_config.dummy_bits       = 0;
  dev_config.mode             = 3 ;
  dev_config.duty_cycle_pos   = 0;
  dev_config.cs_ena_posttrans = 0;
  dev_config.cs_ena_pretrans  = 0;
  dev_config.clock_speed_hz   = 5000000;
  dev_config.spics_io_num     = csPin;
  dev_config.flags            = 0;
  dev_config.queue_size       = 1;
  dev_config.pre_cb           = NULL;
  dev_config.post_cb          = NULL;
  spi_bus_add_device(HSPI_HOST, &dev_config, &h);
  return intError;
  // return h;
} // void fInitializeSPI_Devices()
///////////////////////////////////////////////////////////////
void fReadSPIdata16bits( spi_device_handle_t &h, int _address )
{
  uint8_t address = _address;
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = (8 * 3); // total data bits
  trans_desc.tx_buffer = txData;
  trans_desc.rxlength = 8 * 2 ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = rxData;
  txData[0] = address | 0x80;
  intError = spi_device_transmit( h, &trans_desc);
  low = rxData[0]; high = rxData[1];
  //  if ( intError != 0 )
  //  {
  //    Serial.print( " WHO I am LSM9DS1. Transmitting error = ");
  //    Serial.println ( esp_err_to_name(intError) );
  //  }
} // void fSendSPI( uint8_t count, uint8_t address, uint8_t DataToSend)
////
int fWriteSPIdata8bits( spi_device_handle_t &h, int _address, int _sendData )
{
  uint8_t address =  _address;
  uint8_t sendData = _sendData;
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = (8 * 2); // total data bits
  trans_desc.tx_buffer = txData;
  trans_desc.rxlength = 0 ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = NULL;
  txData[0] = address  & 0x7F;
  txData[1] = sendData;
  intError = spi_device_transmit( h, &trans_desc);
  //  //  if ( intError != 0 )
  //  //  {
  //  //    Serial.print( " LSM9DS1_REGISTER_CTRL_REG6_XL. Transmitting error = ");
  //  //    Serial.println ( esp_err_to_name(intError) );
  //  //  }
  return intError;
} // void fWriteSPIdata8bits(  spi_device_handle_t &h, uint8_t address, uint8_t sendData )
//
int fWriteSPIdata8bits2( spi_device_handle_t &h, int _sendData )
{
  rxData[0] = 0x00;
  // uint8_t address =  _address;
  uint8_t sendData = _sendData;
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = (8 * 2); // total data bits
  trans_desc.tx_buffer = txData;
  trans_desc.rxlength = 8 ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = rxData;
  txData[0] = sendData;
  // txData[0] = address;
  // txData[1] = sendData;
  intError = spi_device_transmit( h, &trans_desc);
  if ( intError == 0 )
  {
    return rxData[0];
  }
  else
  {
  return intError;  
  }
} // void fWriteSPIdata8bits(  spi_device_handle_t &h, uint8_t address, uint8_t sendData )
////
int fWriteSPIdata32bits( spi_device_handle_t &h, int _sendData0, int _sendData1, int _sendData2, int _sendData3 )
{
  // uint8_t address =  _address;
  // uint8_t sendData = _sendData;
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = (8 * 4); // total data bits
  trans_desc.tx_buffer = txData;
  trans_desc.rxlength = 0 ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = NULL;
  txData[0] = (uint8_t)_sendData0; // command bits
  txData[1] = (uint8_t)_sendData1; // lower bits
  txData[2] = (uint8_t)_sendData2; // higher bits
  txData[3] = (uint8_t)_sendData3; // address
  intError = spi_device_transmit( h, &trans_desc);
  return intError;
} // void fWriteSPIdata8bits(  spi_device_handle_t &h, uint8_t address, uint8_t sendData )
////
int fReadSPIdataXbits( spi_device_handle_t &h, int _readaddress, int *rxbuf, int rxlen )
{
  uint8_t address = _readaddress;
  int8_t rxBuf[rxlen] = {0};
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = ( (8 * 1) + (8 * rxlen)); // total data bits
  trans_desc.tx_buffer = txData ;
  trans_desc.rxlength = 8 * rxlen ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = rxBuf;
  txData[0] = address;
  // txData[1] = 0x00;
  intError = spi_device_transmit( h, &trans_desc);
  for (int i = 0; i < rxlen; i++)
  {
    rxbuf[i] = rxBuf[i];
  }
 return intError;
} // int fReadSPIdataXbits( spi_device_handle_t &h, int _readaddress, int *rxbuf, int rxlen )

A sampling of code I used to directly access the ESP32's SPI API. Note the extended feature set of the ESP32's SPI SPI.

Oh man. I just realized that I was trying this on a ESP8266! The problem with the ESP8266 was not, that i was not able to receive anything, the problem was that the first 8bits of the communication are used as command and therefore not visible for me.

--> see in comments. I am Zumlin :grin:

I had a look at the esp32 technical reference manual and in chapter 7.3 I found something like that:
[..]
Command Description
0x1 Received by slave; writes data sent by the master into the slave status register via MOSI.
[..]
This sounds very familiar to me what i have seen at the esp8266.

Did you also use a ESP32 with thsi SPI API as SPI master?

Yes.

Ah ok, then i would guess that you send this command, but maybe do not know.

Even a Cortex-M4 can only do 16 bit SPI frames. What is your master SPI device that needs to transfer 32 bit SPI frames?

An Aurix Tricore

You might be able to get away with a decent STM32. It has a 32 bit FIFO for SPI but can only support up to 16 bit frame. If you use DMA to move RXed data from SPI to memory, then the 32 bit FIFO would allow you to receive the lower 16 bit data while DMAing the upper 16 bit to SRAM. It will be able to keep up