arduino-esp32
arduino-esp32 copied to clipboard
ADD: SPI Slave Support
Any idea when?
do you still need the slave spi? made a little library that works with my project.
100%
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
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
no it's just an example any GPIO works
I tried this. It works, thank you. Any idea why the transmitted data is shifted left one bit?
@patrickwyggle check your SPI_MODE value,
Chuck.
Thank you Chuck. I tried the different modes. Same result. I don't have an oscilloscope.
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.
I just opened #1413 to try and close this issue!
@shaielc any idea why the test SPISlave code is not compiling on #1413
@copercini checkout #1413 please :)
@aj-ptw : @me-no-dev is your guy
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 :)
Hi There! I second the need for some demo code !
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
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 :)
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.
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 !
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 ?
@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);
}
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:
- 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)
- 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 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.
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.
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
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.
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!
Status update: we need to investigate how much we can adhere to the official SPISlave library API if we decide to implement this one.
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