Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By martinayotte
#50014 Thanks @Me-no-dev for this SPI Slave code !

I know that @ruby mentioned on ESP32 forum that he got some code working on ESP8266 Slaves connected to an ESP31 Master, but he never published his code yet.

Do you have plan to make it Official into the official github ?
User avatar
By Vicne
#50047 Hi, Me-no-dev,
I was expecting tips and I'm getting code. Christmas in July :-)
Thanks very much, I'll try that tomorrow and will let you know how it goes.
Thanks again,

Vicne

Edit: no missing include, but I guess
SPI1S1 = (((status_len * 8) - 1) << SPISLSTA) | (0xff << SPISLBUF) | (7 << SPISLWBA) | (7 << SPISLRBA) | (1 << SPISRSTA);
should read
SPI1S1 = (((status_len * 8) - 1) << SPIS1LSTA) | (0xff << SPIS1LBUF) | (7 << SPIS1LWBA) | (7 << SPIS1LRBA) | (1 << SPIS1RSTA);
(note the SPISxxx > SPIS1xxx changes for all flags)
Now the code compiles. Will test it tomorrow
User avatar
By Vicne
#50086 Hi, Me-no-dev, hi all,

I tested your code but can't get it to work unfortunately.

Here's what I did:
1) Used your "master" sketch to generate the signal from an Arduino, with slight changes (e.g the loop sends a status 2 times/second)
Here's the code:
Code: Select all#include <SPI.h>

// Code by Me-no-dev http://www.esp8266.com/viewtopic.php?f=32&t=10579#p50011

// PIN  SPI Function
// 10   CS / SS (green)
// 11   MOSI (purple)
// 12   MISO (grey)
// 13   CLOCK (orange)

void readSpiStatus(){
  uint8_t data[4];
  digitalWrite(SS, LOW);
  SPI.transfer(0x04);
  for(uint8_t i=0; i<4; i++){
    data[i] = SPI.transfer(0);
  }
  digitalWrite(SS, HIGH);
  uint32_t status = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
  Serial.print("Status: "); Serial.println(status, HEX);
}

void readSpiBuffer(){
  uint8_t data[32];
  digitalWrite(SS, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0x00);
  for(uint8_t i=0; i<32; i++) data[i] = SPI.transfer(0);
  digitalWrite(SS, HIGH);
  Serial.print("Data: "); Serial.println((char *)data);
}

void writeSpiBuffer(char *str){
  uint8_t i=0;
  digitalWrite(SS, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0x00);
  while(*str && i++ < 32) SPI.transfer(*str++);
  while(i++ < 32) SPI.transfer(0);
  digitalWrite(SS, HIGH);
}

void writeSpiStatus(uint32_t status){
  digitalWrite(SS, LOW);
  SPI.transfer(0x01);
  // Transfer status, LSB first
  SPI.transfer(status & 0xFF);
  SPI.transfer((status >> 8) & 0xFF);
  SPI.transfer((status >> 16) & 0xFF);
  SPI.transfer((status >> 32) & 0xFF);
  digitalWrite(SS, HIGH);
}


void setup() {
  Serial.begin(115200);
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2);
}

void loop() { 
  writeSpiStatus(0x00FF0F55);
  delay(500);
}


The generated signal looks OK to me (well, a bit noisy due to the dangling cables and probes, but mostly OK) :
DS1Z_QuickPrint29.png

(Signals are CLK - SS - MOSI - MISO, in that order)


2) Uploaded your "slave" code to an ESP8266, with slight modifications, (e.g. implementing the callback functions). I also added serial debug code to try to understand what was going on. I know it's probably not a good idea because they'll be called synchronously from the interrupt handler, but I was just trying to see *something* getting out of the ESP.
Here's the exact code I'm using :
Code: Select all#include "esp8266_peri.h"

// Code by Me-no-dev http://www.esp8266.com/viewtopic.php?f=32&t=10579#p50011

// Pinout from http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/
// GPIO #  HSPI Function
// GPIO12  MISO (grey)
// GPIO13  MOSI (purple)
// GPIO14  CLOCK (orange)
// GPIO15  CS / SS (green)

byte data = 0;

void (*hspi_slave_rx_data_cb)(uint8_t * data, uint8_t len);
void (*hspi_slave_tx_data_cb)(void);
void (*hspi_slave_rx_status_cb)(uint32_t data);
void (*hspi_slave_tx_status_cb)(void);

//set the callbacks
void hspi_slave_setCallbacks(void (*rxd_cb)(uint8_t *, uint8_t), void (*txd_cb)(void), void (*rxs_cb)(uint32_t), void (*txs_cb)(void)){
  hspi_slave_rx_data_cb = rxd_cb;
  hspi_slave_tx_data_cb = txd_cb;
  hspi_slave_rx_status_cb = rxs_cb;
  hspi_slave_tx_status_cb = txs_cb;
}

//set the status register so the master can read it
void hspi_slave_setStatus(uint32_t status){
  SPI1WS = status;
}

//set the data registers (max 32 bytes at a time)
void hspi_slave_setData(uint8_t *data, uint8_t len){
  uint8_t i;
  uint32_t out = 0;
  uint8_t bi = 0;
  uint8_t wi = 8;

  for(i=0; i<32; i++) {
    out |= (i<len)?(data[i] << (bi * 8)):0;
    bi++; bi &= 3; if(!bi) {
      SPI1W(wi) = out;
      out = 0;
      wi++;
    }
  }
}

//SPI Slave Interrupt Handler
void hspi_slave_isr_handler(void *para){
  Serial.print('.');
  uint32_t status;
  uint32_t istatus;

  istatus = SPIIR;

  if(istatus & (1 << SPII1)) { //SPI1 ISR
    status = SPI1S;
    SPI1S &= ~(0x3E0);//disable interrupts
    SPI1S |= (1 << SPISSRES);//reset
    SPI1S &= ~(0x1F);//clear interrupts
    SPI1S |= (0x3E0);//enable interrupts

    if((status & (1 << SPISWBIS)) != 0 && (hspi_slave_rx_data_cb)) {
      uint8_t i;
      uint32_t data;
      uint8_t buffer[32];
      for(i=0;i<8;i++){
        data=SPI1W(i);
        buffer[i<<2] = data & 0xff;
        buffer[(i<<2)+1] = (data >> 8) & 0xff;
        buffer[(i<<2)+2] = (data >> 16) & 0xff;
        buffer[(i<<2)+3] = (data >> 24) & 0xff;
      }
      hspi_slave_rx_data_cb(buffer, 32);
    }
    if((status & (1 << SPISRBIS)) != 0 && (hspi_slave_tx_data_cb)) hspi_slave_tx_data_cb();
    if((status & (1 << SPISWSIS)) != 0 && (hspi_slave_rx_status_cb)) hspi_slave_rx_status_cb(SPI1WS);
    if((status & (1 << SPISRSIS)) != 0 && (hspi_slave_tx_status_cb)) hspi_slave_tx_status_cb();
  }
  else if(istatus & (1 << SPII0)){
    //SPI0 ISR
    SPI0S &= ~(0x3ff);//clear SPI ISR
  }
  else if(istatus & (1 << SPII2)) {
    //I2S ISR
  }
}

//Start SPI Slave
void hspi_slave_begin(uint8_t status_len){
  status_len &= 7;
  if(status_len > 4) status_len == 4;//max 32 bits
  if(status_len == 0) status_len == 1;//min 8 bits

  pinMode(SS, SPECIAL);
  pinMode(SCK, SPECIAL);
  pinMode(MISO, SPECIAL);
  pinMode(MOSI, SPECIAL);

  SPI1S = (1 << SPISE) | (1 << SPISBE) | 0x3E0;
  SPI1U = SPIUMISOH | SPIUCOMMAND | SPIUSSE;
  SPI1CLK = 0;
  SPI1U2 = (7 << SPILCOMMAND);
  SPI1S1 = (((status_len * 8) - 1) << SPIS1LSTA) | (0xff << SPIS1LBUF) | (7 << SPIS1LWBA) | (7 << SPIS1LRBA) | (1 << SPIS1RSTA);
  SPI1P = (1 << 19);
  SPI1CMD = SPIBUSY;
 
  ETS_SPI_INTR_ATTACH(hspi_slave_isr_handler, NULL);
  ETS_SPI_INTR_ENABLE();
}

void my_hspi_slave_rx_data_cb(uint8_t * data, uint8_t len) {
  Serial.print("Number of data bytes received: "); Serial.println(len);
  hspi_slave_setStatus(0xFF555555);
}

void my_hspi_slave_tx_data_cb(void) {
  Serial.println("Data sent");
  hspi_slave_setStatus(0xFF333333);
}

void my_hspi_slave_rx_status_cb(uint32_t data){
  Serial.print("Status received: "); Serial.println(data, HEX);
  hspi_slave_setStatus(0xFF0F0F0F);
}

void my_hspi_slave_tx_status_cb(void){
  Serial.println("Status Sent");
  hspi_slave_setStatus(0xFF00FF00); 
}


void setup() {
  Serial.begin(115200); 
  hspi_slave_setCallbacks(my_hspi_slave_rx_data_cb, my_hspi_slave_tx_data_cb, my_hspi_slave_rx_status_cb, my_hspi_slave_tx_status_cb);
  hspi_slave_begin(4); // 4 status byte
  Serial.println("SPI slave started");
  hspi_slave_setStatus(0xFFFF0000);
}

void loop() {
}



The first issue I had was that when booting the ESP with the generator already running, the SS (SPIO15) is high, causing the ESP to boot in a wrong mode. For the time being, I solved this by connecting the SS only after the ESP has booted. I'll make that automatic later on.

Once the ESP boots, I'm getting the following trace immediately (before CS or even CLK is connected) :
Code: Select all.Status received: 0                                                                     
Status Sent                                                                   
..SPI slave started

In other words, the isr is called once and considers the ESP has received a status of 0, and sends a status in return (which I don't understand as clock isn't even connected from the master)
Then two more interrupts come in, not causing any callback (probably SPI0 or I2S).
And finally the chip exits the "begin" section and waits (the loop is executed. I tried to add a Serial print and a delay inside and it is indeed looping).
But nothing ever comes in again.

@Me-no-dev, is there something I'm missing in the code I need to implement ?

If not, does anyone have an idea what I'm doing wrong ?

Kind regards,

Vicne
You do not have the required permissions to view the files attached to this post.