#include "driver/spi_slave.h"
// SPI Chip example https://wokwi.com/projects/330669951756010068
// playground https://wokwi.com/projects/327144279206003284
// docs: https://docs.wokwi.com/chips-api/getting-started
/*
SPI receiver (slave) example.
This example is supposed to work together with the SPI sender. It uses the standard SPI pins (MISO, MOSI, SCLK, CS) to
transmit data over in a full-duplex fashion, that is, while the master puts data on the MOSI pin, the slave puts its own
data on the MISO pin.
This example uses one extra pin: GPIO_HANDSHAKE is used as a handshake pin. After a transmission has been set up and we're
ready to send/receive data, this code uses a callback to set the handshake pin high. The sender will detect this and start
sending a transaction. As soon as the transaction is done, the line gets set low again.
*/
/*
Pins in use. The SPI Master can use the GPIO mux, so feel free to change these if needed.
*/
/*
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 23
#define GPIO_MISO 19
#define GPIO_SCLK 18
#define GPIO_CS 5
*/
// jzg: note DOIT DevBoard V1 has the following already defined for these pins: SS, MOSI, MISO, SCK
#define RCV_HOST VSPI_HOST
// --- globals ---
int n = 0;
esp_err_t ret;
WORD_ALIGNED_ATTR char sendbuf[129] = "";
WORD_ALIGNED_ATTR char recvbuf[129] = "";
spi_slave_transaction_t t;
// --- callbacks ---
// Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
void my_post_setup_cb(spi_slave_transaction_t *trans)
{
// WRITE_PERI_REG(GPIO_OUT_W1TS_REG, (1 << GPIO_HANDSHAKE));
}
// Called after transaction is sent/received. We use this to set the handshake line low.
void my_post_trans_cb(spi_slave_transaction_t *trans)
{
// WRITE_PERI_REG(GPIO_OUT_W1TC_REG, (1 << GPIO_HANDSHAKE));
}
// --- initialisation ---
void setup()
{
// Configuration for the SPI bus
spi_bus_config_t buscfg =
{
.mosi_io_num = MOSI,
.miso_io_num = MISO,
.sclk_io_num = SCK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
// Configuration for the SPI slave interface
// jzg: had to swap these (setup and trans) around to fix compile errors (in line with below)
// https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/esp32/include/driver/include/driver/spi_slave.h
// i.e. lines 44 and 54
spi_slave_interface_config_t slvcfg =
{
.spics_io_num = SS,
.flags = 0,
.queue_size = 3,
.mode = 0,
.post_setup_cb = my_post_setup_cb,
.post_trans_cb = my_post_trans_cb
};
// Configuration for the handshake line
// jzg: had to swap these around to fix compile errors (in line with below)
// https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c
/* gpio_config_t io_conf =
{
.pin_bit_mask = (1 << GPIO_HANDSHAKE),
.mode = GPIO_MODE_OUTPUT,
.intr_type = GPIO_INTR_DISABLE
}; */
// jzg: leaving in to remind me to report but not actually using here
// Configure handshake line as output
// gpio_config(&io_conf);
// jzg: HERE suspect this pulling high is what might be causing the issues for receiving...
// Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected.
pinMode(MOSI, INPUT/*_PULLUP*/); //gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);
pinMode(SCK, INPUT/*_PULLUP*/); //gpio_set_pull_mode(GPIO_SCLK, GPIO_PULLUP_ONLY);
pinMode(SS, INPUT/*_PULLUP*/); //gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
// Initialize SPI slave interface
ret = spi_slave_initialize(RCV_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO);
assert(ret == ESP_OK);
memset(recvbuf, 0, 33);
memset(&t, 0, sizeof(t));
}
// --- main loop ---
void loop()
{
// Clear receive buffer, set send buffer to something sane
// was 0xA5
memset(recvbuf, 0, 129);
sprintf(sendbuf, "_This is the receiver, sending data for transmission number %04d.", n);
// Set up a transaction of 128 bytes to send/receive
t.length = 128 * 8;
t.tx_buffer = sendbuf;
t.rx_buffer = recvbuf;
printf("Prepping for SPI slavery... MOSI = %d\n", MOSI);
/* This call enables the SPI slave interface to send/receive to the sendbuf and recvbuf. The transaction is
initialized by the SPI master, however, so it will not actually happen until the master starts a hardware transaction
by pulling CS low and pulsing the clock etc. In this specific example, we use the handshake line, pulled up by the
.post_setup_cb callback that is called as soon as a transaction is ready, to let the master know it is free to transfer
data.
*/
ret = spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY); // portMAX_DELAY = BLOCKING! (infinite timeout)
// spi_slave_transmit does not return until the master has done a transmission, so by here we have sent our data and
// received data from the master. Print it.
printf("Received: %s\n", recvbuf);
n++;
}