arduino-esp32 icon indicating copy to clipboard operation
arduino-esp32 copied to clipboard

ADD: SPI Slave Support

Open andrewjaykeller opened this issue 8 years ago • 30 comments

Description:

Add support for SPISlave mode like the ESP8266 SPISlave arduino library..

andrewjaykeller avatar Sep 09 '17 15:09 andrewjaykeller

Any idea when?

andrewjaykeller avatar Oct 30 '17 14:10 andrewjaykeller

do you still need the slave spi? made a little library that works with my project.

shaielc avatar Nov 21 '17 09:11 shaielc

100%

andrewjaykeller avatar Nov 21 '17 15:11 andrewjaykeller

enjoy! note: the master device that I am using doesn't have anything to do with income data so i couldn't test that. https://gist.github.com/shaielc/e0937d68978b03b2544474b641328145

EDIT: ehh, I am going to try and and test it with the esp as master.

shaielc avatar Nov 21 '17 21:11 shaielc

@shaielc

Is there any particular rational behind your GPIO pin choices for the Slave? The documentation says any GPIO works.

MISO 32 MOSI 25 SCLK 27 SS 34

andrewjaykeller avatar Jan 08 '18 16:01 andrewjaykeller

no it's just an example any GPIO works

shaielc avatar Jan 08 '18 16:01 shaielc

I tried this. It works, thank you. Any idea why the transmitted data is shifted left one bit?

patricklenders avatar May 09 '18 01:05 patricklenders

@patrickwyggle check your SPI_MODE value,

Chuck.

stickbreaker avatar May 09 '18 03:05 stickbreaker

Thank you Chuck. I tried the different modes. Same result. I don't have an oscilloscope.

patricklenders avatar May 11 '18 02:05 patricklenders

Sounds like it's possibly a timing issue. Meaning the spi master gets the clk and and select signal b4 the first bit is sent.

shaielc avatar May 16 '18 16:05 shaielc

I just opened #1413 to try and close this issue!

andrewjaykeller avatar May 16 '18 17:05 andrewjaykeller

@shaielc any idea why the test SPISlave code is not compiling on #1413

andrewjaykeller avatar May 17 '18 15:05 andrewjaykeller

@copercini checkout #1413 please :)

andrewjaykeller avatar May 17 '18 15:05 andrewjaykeller

@aj-ptw : @me-no-dev is your guy

copercini avatar May 17 '18 15:05 copercini

My bad this is from esp32 sdk header file...

They have added the spi_slave library: https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/spi_slave.h

An example would be nice though :)

Erol444 avatar Aug 13 '18 14:08 Erol444

Hi There! I second the need for some demo code !

euquiq avatar Aug 30 '18 19:08 euquiq

As Erol444 noted, that library is in ESP-IDF, not arduino-esp32. The example is at https://github.com/espressif/esp-idf/tree/master/examples/peripherals/spi_slave

lbernstone avatar Aug 30 '18 20:08 lbernstone

In short, for ESP32 Arduino, there is no official SPI slave library ? I am trying the one that user @shaielc posted earlier on: https://gist.github.com/shaielc/e0937d68978b03b2544474b641328145

But I am struggling to understand how does it work. The library seems to collect the data sent by the Master SPI device inside a String ?

I will keep at it, trying to understand the whole thing and hopefully I can build on it something that suits my needs :)

euquiq avatar Aug 30 '18 23:08 euquiq

Hi, The class I made tries to mimic the operation of the SPI master class basically you queue data in a buffer (as a string) that waits for a master to initiate connection when there's a connection the slave outputs the data from the buffer while reading the input from the master and putting it in a buffer which is also a string. (in the class there are two string one called buffer -> this is the input buffer , transBuffer this is the output queue buffer)

use read() to read the buffer char by char u can also use getBuff() to get the whole string use flush() to empty the buffer

if u want to send data to the master queue it using trans_queue()

Basically there's an example that uses the class in the gist the example initiates a master and slave on the esp and communicates between them.

shaielc avatar Aug 31 '18 00:08 shaielc

Yep I get the idea, but I have weird results. IF I do what you say, I get the first byte OK and then only zeros (byte = 0).

But then I noticed inside your demo the test() sub with the commented out code, and did the following instead:

void test() {
	byte valor = slave.read();
	Serial.print((String)valor + ",");
}

and I get a bunch of bytes with different values, which seems to be close to the data my master device is sending (that is another problem, entirely) ... mixed with zeros along.

Point is: I get one behavior (full of zeros) when I try inside loop() your code, but I get a different behavior when I use the test() sub.

Any help or hint is appreciated! Thanks for answering btw, @shaielc !

euquiq avatar Aug 31 '18 15:08 euquiq

Update: It seems I was receiving zeros because I was doing:

slave.begin((gpio_num_t)SO, (gpio_num_t)SI, (gpio_num_t)SCLK, (gpio_num_t)SS,1, test);//seems to work with groups of 4 bytes

Now I am trying different size values, like:

slave.begin((gpio_num_t)SO, (gpio_num_t)SI, (gpio_num_t)SCLK, (gpio_num_t)SS,40, test);//seems to work with groups of 4 bytes But anything bigger than 8, just trails zero value.

ALSO: @shaielc if you are using a String to buffer the incoming data ... what happens if the Master device sends a zero ? You would be terminating the string, thus LENGTH would give you a truncated length ?

euquiq avatar Aug 31 '18 17:08 euquiq

@shaielc I used your library as an example, and did this code, which is getting me all bytes in correct form: It is a "super-simplification" of your library, but perhaps it can be of use to others so they can better understand the receiving part on SPI Slave.

#include "driver/spi_slave.h"
#include <SPI.h>

#define SO 19
#define SI 23
#define SCLK 18
#define SS 21

spi_slave_transaction_t * driver;

uint16_t t_size = 20;//length of transaction buffer, (should be set to maximum transition size)

void setup() {
	Serial.begin(115200);
	SPI.begin();
	gpio_set_pull_mode((gpio_num_t)SCLK, GPIO_PULLUP_ONLY);
	gpio_set_pull_mode((gpio_num_t)SS, GPIO_PULLUP_ONLY);
	//Driver acts as buffer for incoming spi data, last null is optional, may be used to flag each transaction with your own data / variable.
	driver = new spi_slave_transaction_t{ t_size * 8 ,	0 ,	heap_caps_malloc(max(t_size,32), MALLOC_CAP_DMA),	heap_caps_malloc(max(t_size,32), MALLOC_CAP_DMA),NULL };
	spi_bus_config_t buscfg = {
		buscfg.mosi_io_num = SI,
		buscfg.miso_io_num = SO,
		buscfg.sclk_io_num = SCLK
	};
	spi_slave_interface_config_t slvcfg = { SS,0,1,0,setupIntr,transIntr };//check the IDF for further explanation
	spi_slave_initialize(HSPI_HOST, &buscfg, &slvcfg, 1); //DMA channel 1
	spi_slave_queue_trans(HSPI_HOST, driver, portMAX_DELAY);//ready for input (no transmit)
	//exter_intr = ext;		
	SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));
}

//Callback called after the SPI registers are loaded with new data.
void setupIntr(spi_slave_transaction_t * trans) {
	//I do not use this...
}

//Callback called after a transaction is done.
void transIntr(spi_slave_transaction_t * trans) {
	byte value = 0;	
	uint16_t largo = driver->trans_len;
	largo = largo / 8; //this value is in bits
	Serial.println("INCOMING: ");
	for (int i = 0; i<largo; i++)
	{
		value = ((char*)driver->rx_buffer)[i];
		Serial.print((String)value + ",");
	}
	Serial.println(" --- " + (String)largo);
	//Set it to listen again into Master SPI
	driver->length = t_size * 8;
	driver->trans_len = 0;
	spi_slave_queue_trans(HSPI_HOST, driver, portMAX_DELAY);
}

euquiq avatar Aug 31 '18 21:08 euquiq

Hi, @euquiq
a) you were getting trailing zeros because the rx_buffer didn't get a transaction with 40 bytes it got an 8 byte transaction your master probably resets (HIGH then LOW) the select line which causes in trans_intr to trail zeros since a transaction WAS finished. EDIT: If I am right your t_size SHOULD be 8 b) you are right about the fact that the string length would be wrong checked my own project I got the length from the master device in another way I will edit the class to keep track of the length. c) can you highlight the changes you made so I would change it in the class? EDIT:

  1. I think I found the major flaw in my code I was assuming I got t_size of transmission changed the code so it would only read (driver->trans_len/8) bytes and on transBuffer would only move the same amount now t_size only changes maximum possible transmission (it defines the DMA buffer size)
  2. added a public size that increments with every transaction by the transaction size on read() decrements by one and set to zero on flush()

If you could test that would be appreciated I don't have an esp at the moment.

shaielc avatar Sep 01 '18 17:09 shaielc

@shaielc I will continue my comments on your github code posting, instead of here, since it may be related specifically to your code, and this here is a request in general terms for official SPIslave support inside Arduino framework for esp32.

euquiq avatar Sep 02 '18 15:09 euquiq

Is there an update regarding SPI slave support in the official Arduino Core? I'm trying to use an USB-to-SPI FT232H converter to communicate with an ESP32 slave via SPI.

hgpt avatar Mar 11 '19 06:03 hgpt

I too would love to see this implemented, looking at the code it appears a slave_spi driver was put in at some point but i see no explanation on how to use it I have a 2 wire SPI device i need to read from (only clock and data) and would love to have a clean way to do so

onebiozz avatar May 23 '19 01:05 onebiozz

Please see: https://github.com/espressif/arduino-esp32/issues/3061#issue-476312646 It describes a problem I am seeing when using spi_slave along with SPIFFS.

DMD-Engineering avatar Aug 02 '19 19:08 DMD-Engineering

So, I searched for so long to find out that ESP32 doesn't have the Slave mode implemented in Arduino :((( A big shame. This makes my project impossible to implement as I use Arduino based code all over the place (ESPhome framework).

Espressif - WE NEED THIS SORTED! PLEASE!

dgtal1 avatar Sep 27 '21 18:09 dgtal1

Status update: we need to investigate how much we can adhere to the official SPISlave library API if we decide to implement this one.

igrr avatar Apr 05 '22 12:04 igrr

I also need this functionality, I was about to start a new feature request but double checked and found this thread. I am using the SPI library in master mode as in the Spi example for one device. I need the esp32 s3 to act as a slave to a different device and interrupt functionality for chip select pin.

In arduino environment if you select cs pin as input then spi knows it needs to work in slave mode. A SPI_Multiple_Buses.ino example where hspi is master and vspi is slave would be nice.

I considered using this library in combination with the spi library that I am already using. But I'm either not familiar with the terminology or how it works to be able to modify the examples to my needs. https://github.com/hideakitai/ESP32SPISlave

SiMachines avatar Aug 02 '24 02:08 SiMachines