I am trying to set up an SPI comunication between two ESP32 DevKit, both with WROOM-32 chip on. I already have programming and comunication protocol knowledge but it seems like I cannot set up the slave to receive the data. I managed to send the data from the master device, even if the CS channels is a bit out of synch ( on an oscilloscope I could count 1 clock strike between the CS going low and the shared clock start, and 2 more clock strike in the end, before the CS goes UP again), which is strange, but the shared clock and the data channels seems good.
On the slave device I use digitalRead() function to check whenever the CS channel is LOW/HIGH, and indeed the slave receive this channel, but the data printed is always 0 (I am sending 200 as uint8_t from the master).
Anyone can explain to me how to properly set an SPI comunication between these two modules? I can include code, or more details, if needed in this thread.
Welcome to the forum
Please post both sketches, using code tags when you do. This prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination
In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.
what is the distance between the master and slave? what types of connections are you using? post a photo?
probably simpler to use serial or WiFi?
Wi-fi and bluetooth
Thanks for the advice. I'll explain it better:
- distance is minimal, I'm using simple jumper cable to connect the devices and probably the final system will be even shorter;
- for connections I am using the GPIO pins on both the ESP32; I have tried both VSPI and HSPI;
- the real system will use only one ESP32 to just receive the data (SPI is preferred since UART is too slow and I don't want to up the baud rate and risk to lose data).
For clarity: the output of the main, real board is this:
where red is CS, blue is master clock propagated out and green is data (I was sending 5 in 8 bit so you can count to 00000101) Ignore the clock div, that will not be final.
The problem is that I cannot receive from the ESP32 side.
I cannot use WiFi or BT, since that part is already used further in the project, I just need to receive data through a wired connection, not wireless.
I'll attach what I got from the ESP32 master:
without manual piloting the CS pin I get this:
the red channel is CS and it's just noise.
When manual piloting the CS Pin, things get a little better:
but, as I already said you can clearly count at least one clock strike since the CS goes low and the clock is propagated, and at least 2 clock strike after the clock goes low before rising the CS signal. This is clearly not optimal. In addition, in both mode the ESP32 on the receiving side never get usefull data (mostly 0)
How about posting your code
Sure. The master's code is:
#include <SPI.h>
#define CS 15
#define SCK 14
#define MOSI 13
#define MISO 12
uint8_t send_data = 200;
void setup() {
Serial.begin(115200);
pinMode(CS, OUTPUT);
SPI.begin(SCK, MISO, MOSI, CS);
digitalWrite(CS, HIGH);
}
void loop() {
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus
digitalWrite(CS, LOW);
SPI.transfer(send_data);
digitalWrite(CS, HIGH);
SPI.endTransaction();
}
while the slave's code is:
#include <SPI.h>
#define CS 15
#define SCK 14
#define MOSI 13
#define MISO 12
uint8_t received_data;
void setup() {
Serial.begin(115200);
pinMode(CS, INPUT_PULLUP);
pinMode(SCK, INPUT);
pinMode(MOSI, INPUT);
pinMode(MISO, OUTPUT);
Serial.println("SPI Slave initialized.");
}
void loop() {
// Polling method to check if data is available
if (digitalRead(CS) == LOW) {
received_data = SPI.transfer(0x00);
Serial.print("Received Data: ");
Serial.println(received_data);
}
}
Honestly I am a bit perplexed by the SPI.h library, I used the ST ones and I never had a problem. Now I am trying with other libraries (spi_master and spi_slave) that I have found in the driver folder
Have you tried this library
Thank you for your advice. I managed to make the two kit comunicate using the libraries I mentioned before. They can be found in the espress-if github at this link, if anyone is interested.
The problem was indeed the SPI.h basic library.
Hello again everyone,
I have managed to set up the comunication between my esp32 and the fpga. I now have two problems:
- the comunication is a bit rusty: I can properly send batch of 1 byte, but as soon as I try to send a bigger buffer of data, the comunication does not work anymore. It's a strange behaviour, since I need to send at least batch of 20 byte in my final project (probably even more).
This is my code for the SPI comms, using the "spi_slave.h" library, as mentioned beore in this thread:
#include "driver/spi_slave.h"
#include "driver/gpio.h"
#include <string.h>
#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
// Buffer size for data reception
#define BUFFER_SIZE 2
spi_slave_transaction_t t;
uint8_t recv_buf[BUFFER_SIZE]; // Buffer for receiving data
void init_spi_slave() {
esp_err_t ret = ESP_FAIL;
// SPI bus configuration
spi_bus_config_t buscfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1, // Not used
.quadhd_io_num = -1 // Not used
};
// SPI slave interface configuration
spi_slave_interface_config_t slvcfg = {
.spics_io_num = PIN_NUM_CS, // CS pin
.flags = 0, // No specific flags
.queue_size = 3, // Transaction queue depth
.mode = 1, // SPI mode 0
.post_setup_cb = NULL, // No post-setup callback
.post_trans_cb = NULL // No post-transaction callback
};
memset(&t, 0, sizeof(t)*BUFFER_SIZE);
// Attach the SPI slave driver to the bus
ret = spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, SPI_DMA_DISABLED);
if (ret != ESP_OK) {
Serial.println("Failed to initialize SPI slave device\n");
}else{
Serial.println("SPI Slave Initialized and ready to receive data.\n");
}
}
void spi_slave_receive_data() {
esp_err_t ret = ESP_FAIL;
//memset(&recv_buf, 0, BUFFER_SIZE);
// Setup buffer for receiving data
t.length = BUFFER_SIZE * 8; // Data length in bit
// Wait for the master to send data and receive it
ret = spi_slave_transmit(VSPI_HOST, &t, portMAX_DELAY);
if(ret != ESP_FAIL){
t.rx_buffer = recv_buf;
Serial.printf("%d - %d", recv_buf[0], recv_buf[1]);
/*for (int i = 0; i < BUFFER_SIZE; i++) {
Serial.printf("%02X ", recv_buf[i]);
}*/
Serial.println();
}else{
Serial.printf("Failed to receive SPI data\n");
}
}
void setup() {
Serial.begin(115200);
init_spi_slave();
}
void loop() {
spi_slave_receive_data();
}
- I am trying to set up a two parallel tasks program, so that I can do SPI receives and write on file at the same times. I am using littleFS as library for writing on file, although this is a temporary script to avoid printing on serial and try to see if I can successfully receive bigger batches of data. The problem is that I am not sure if the function to write on file is faster enough to not lose any data inbetween, since I must receive new data every 1 ms. I was thinking if it was possible to write using the DMA.
Are you using the Arduino IDE or the Espressif IDF?
I'm using the Arduino IDE, are there any differences with the Espressif IDE? I have both of them installed at the moment, but never used the second one
Yes but not important for this discussion.
I asked only because you gave a link to the espressif IDF drivers.
Yes I am using those drivers, since most of them are included in the Arduino IDE too
A little update: I created the program with the two task but the problem persists. I send 2 byte from the FPGA (which I know are correct, I've seen on the oscilloscope) but I can only receive the first one always correct, while the second byte sometimes seems like not updating (it remains the same number, instead of increasing by 1, for some cycle).
EDIT: I am using the ring buffer too. I can upload the entire code if needed.
Another update: I am trying to use the library you mentioned and the behaviour is similar to the others.
This is the code:
#include "ESP32SPISlave.h"
#define BUFF_SIZE 4
#define MAX_MS_WAIT 1
uint8_t rx_buff[BUFF_SIZE];
ESP32SPISlave SPI_SLAVE;
void setup() {
Serial.begin(115200); // Start serial communication for debugging
// Initialize the SPI slave
if (!SPI_SLAVE.begin(VSPI, /*sck=*/18, /*miso=*/19, /*mosi=*/23, /*ss=*/5)) {
Serial.println("Failed to initialize SPI slave.");
while (1); // Stop if SPI initialization fails
}else{
SPI_SLAVE.setDataMode(SPI_MODE1);
}
Serial.println("SPI slave initialized. Waiting for data from master...");
}
void loop() {
// Check if data is available from the master
SPI_SLAVE.transfer(NULL, rx_buff, BUFF_SIZE, MAX_MS_WAIT);
Serial.print("Received data: ");
printf("%d - %d - %d - %d\r\n", rx_buff[0], rx_buff[1], rx_buff[2], rx_buff[3]);
}
and this is the output I'm getting:
It's strange that it says I received 0 bits and 0 bytes but still print something. In addition sometimes the first three printed number are correct, but the fourth one is always wrong.
So then, you're using SPI_MODE1
. OK, why not but you of course need to make sure this is SPI_MODE1. I mean first example (post #8) used SPI_MODE0 !
Code post #17 has a transfer timeout of 1ms, that's rather short, are you sure the master transmitted the data (at least one byte) during that millisecond ? (see note below) You didn't check the number of received bytes :
numOfReceivedBytes = SPI_SLAVE.transfer(NULL, rx_buff, BUFF_SIZE, MAX_MS_WAIT);
Based on the output you get, I suspect it didn't receive anything and simply timed out.
Printing data ? There's always data inside a memory byte. Whether it's garbage or not depends on the program. Output shows garbage in my opinion...
Note : with SPI transmission, the master generates the clock, the slave uses the master's clock to shift data in (and out simultaneously).
Honestly, even if this makes no sense, I was desperate and tryied all SPI modes. The FPGA send with SPI_MODE_0 for sure, so that SPI_MODE_1 you see there was just one of the tries I made.
I probably solved the problem with the spi_slave.h library: for some reason in the examples there was a command to copy a variable (t.rx_buffer = rcv_buff) in the wrong place. I never picked this up but it was done before the actuale receive and so this caused all the problem I had. I will do more tests next week and hope that was the mistake. I'll keep this thread updated anyway with any solution I find.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.