Skip to content

Instantly share code, notes, and snippets.

@shaielc
Last active April 28, 2023 10:18
Show Gist options
  • Save shaielc/e0937d68978b03b2544474b641328145 to your computer and use it in GitHub Desktop.
Save shaielc/e0937d68978b03b2544474b641328145 to your computer and use it in GitHub Desktop.
SlaveSPIClass_esp32_Arduino
#include<SlaveSPIClass.h>
int SlaveSPI::size = 0;
SlaveSPI** SlaveSPI::SlaveSPIVector = NULL;
void setupIntr(spi_slave_transaction_t * trans)
{
for(int i=0 ; i<SlaveSPI::size;i++)
{
if(SlaveSPI::SlaveSPIVector[i]->match(trans))
SlaveSPI::SlaveSPIVector[i]->setup_intr(trans);
}
}
void transIntr(spi_slave_transaction_t * trans)
{
for(int i=0 ; i<SlaveSPI::size;i++)
{
if(SlaveSPI::SlaveSPIVector[i]->match(trans))
SlaveSPI::SlaveSPIVector[i]->trans_intr(trans);
}
}
SlaveSPI::SlaveSPI()
{
SlaveSPI** temp = new SlaveSPI * [size+1];
for (int i=0;i<size;i++)
{
temp[i]=SlaveSPIVector[i];
}
temp[size] = this;
size++;
delete [] SlaveSPIVector;
SlaveSPIVector = temp;
buff = "";
transBuffer = "";
}
void SlaveSPI::begin(gpio_num_t so,gpio_num_t si,gpio_num_t sclk,gpio_num_t ss,size_t length,void(* ext)())
{
//should set to the minimum transaction length
t_size = length;
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={
.mosi_io_num=si,
.miso_io_num=so,
.sclk_io_num=sclk
};
gpio_set_pull_mode(sclk, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(ss, GPIO_PULLUP_ONLY);
spi_slave_interface_config_t slvcfg={ss,0,1,0,setupIntr,transIntr};//check the IDF for further explenation
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;
}
void SlaveSPI::setup_intr(spi_slave_transaction_t *trans)
{//called when the trans is set in the queue
//didn't find use for it in the end.
}
void SlaveSPI::trans_intr(spi_slave_transaction_t *trans)
{//called when the trans has finished
for(int i=0;i<(driver->trans_len/8);i++)
{
buff += ((char*)driver->rx_buffer)[i];
((char*) driver->rx_buffer)[i] = (char)0;
size++;
}
setDriver();
exter_intr();
}
void SlaveSPI::trans_queue(String& transmission){
//used to queue data to transmit
for (int i=0;i<transmission.length();i++)
transBuffer += transmission[i];
}
inline bool SlaveSPI::match(spi_slave_transaction_t * trans)
{
return (this->driver == trans);
}
void SlaveSPI::setDriver()
{
driver->user = NULL;
int i=0;
for(;i<(driver->trans_len/8)&&i<transBuffer.length();i++)
{
((char*) driver->tx_buffer)[i] = transBuffer[i];
}
transBuffer = &(transBuffer[i]);
driver->length=t_size*8;
driver->trans_len = 0;
spi_slave_queue_trans(HSPI_HOST,driver,portMAX_DELAY);
}
char SlaveSPI::read()
{
char temp = buff[0];
buff.remove(0,1);
size--;
return temp;
}
#ifndef SLAVE_SPI_CLASS
#define SLAVE_SPI_CLASS
#include "Arduino.h"
#include "driver/spi_slave.h"
void setupIntr(spi_slave_transaction_t * trans);
void transIntr(spi_slave_transaction_t * trans);
class SlaveSPI
{
static SlaveSPI** SlaveSPIVector;
static int size;
friend void setupIntr(spi_slave_transaction_t * trans);
friend void transIntr(spi_slave_transaction_t * trans);
String buff;//used to save incoming data
String transBuffer;//used to buffer outgoing data !not tested!
spi_slave_transaction_t * driver;
void (*exter_intr)();//interrupt at the end of transmission , if u need to do something at the end of each transmission
size_t t_size;//length of transaction buffer, (should be set to maximum transition size)
public:
SlaveSPI();
int size;
void setup_intr(spi_slave_transaction_t *trans);//called when the trans is set in the queue
void trans_intr(spi_slave_transaction_t *trans);//called when the trans has finished
void begin(gpio_num_t so,gpio_num_t si,gpio_num_t sclk,gpio_num_t ss,size_t length=128,void(* ext)() = NULL);
void trans_queue(String& transmission);//used to queue data to transmit
inline char* operator[](int i){return (&buff[i]);}
inline void flush(){buff = "";size=0;}
inline bool match(spi_slave_transaction_t * trans);
void setDriver();
char read();
inline String* getBuff(){return &buff;}
};
#endif
#include <SlaveSPIClass.h>
#include <SPI.h>
#define MO 22
#define MI 23
#define MCLK 19
#define MS 18
#define SO 32
#define SI 25
#define SCLK 27
#define SS 34
SlaveSPI slave;
SPIClass master(VSPI);
void test();
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
master.begin(MCLK,MI,MO);
slave.begin((gpio_num_t)SO,(gpio_num_t)SI,(gpio_num_t)SCLK,(gpio_num_t)SS,8,test);//seems to work with groups of 4 bytes
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
pinMode(MS,OUTPUT);
}
String txt = "";
String cmd ="";
void loop() {
// put your main code here, to run repeatedly:
if(slave.getBuff()->length()&&digitalRead(SS)==HIGH)
{
while(slave.getBuff()->length())
txt+=slave.read();
Serial.println("slave input:");
Serial.println(txt);
}
while(Serial.available())
{
cmd +=(char) Serial.read();
}
while(txt.length()>0)
{
slave.trans_queue(txt);
Serial.println("slave output:");
Serial.println(txt);
txt ="";
}
while(cmd.length()>0)
{
Serial.println("input:");
Serial.println(cmd);
Serial.println("Master input:");
digitalWrite(MS,LOW);
for(int i=0;i<cmd.length();i++)
{
cmd[i] = master.transfer(cmd[i]); //ERROR : gives the transmitted data <<1
}
digitalWrite(MS,HIGH);
for(int i=0;i<cmd.length();i++)
Serial.print(cmd[i],HEX);
cmd ="";
}
}
void test()
{
//Serial.println("test");
//Serial.println(slave[0]);
}
@EstevanTH
Copy link

Hey there,
I could fix the compile errors and warnings, which turned out to be just 2 tiny problems.

At the moment I do not know if it makes the program work.

Fix #1

The same name is used for a static member and an instance member.

In SlaveSPIClass.h @ line 2

static int size;

becomes

static int size_;

In SlaveSPIClass.cpp @ lines 2, 6, 14: replace occurrences of SlaveSPI::size with SlaveSPI::size_.

Fix #2

The compiler messes up the implicit conversion from integer literal to t_size.

SlaveSPIClass.cpp @ line 41

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};

becomes

driver = new spi_slave_transaction_t{(size_t)(t_size * 8) ,	0 ,	heap_caps_malloc(max(t_size,(size_t)32), MALLOC_CAP_DMA),	heap_caps_malloc(max(t_size,(size_t)32), MALLOC_CAP_DMA),NULL};

@EstevanTH
Copy link

EstevanTH commented Mar 25, 2019

I feel like something else is wrong with size and size_.

Fix #3

It does not make sense that an instance value is used in the constructor SlaveSPI::SlaveSPI() because size is only used to affect the static member SlaveSPIVector.

SlaveSPIClass.cpp @ lines 20 to 33: replace every size with SlaveSPI::size_.

Possible fix

The instance's size is not explicitly initialized. It looks like a buffer count. It should probably be initialized to 0 in the member initialization part of the constructor. The default value is to be checked.

EDIT #1

Yes! My fixes #1 to #3 made it work somehow! I was receiving nothing at all without the fix #3. Now I'm receiving a corrupted message but at least I have a correct piece of it.

@MateoSegura
Copy link

I am using platform IO, and after implementing all the fixes above, I cannot compile:

My error is inline 29 of .cpp file: tx_buffer = (uint8_t *)heap_caps_malloc(max(max_buffer_size, 32), SPI_MALLOC_CAP);

the error is: no instance of max(size_t,int)

any help or suggestions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment