This is a simple example on how to communicate, over SPI, with the ESP32C3 on board the Challenger RP2040 WiFi/BLE board. The example implements a simple terminal interface that lets you send AT commands via the SPI line. It implements all the protocolly stuff needed by the SPI version of the esp-at stack.
/*
* SPI test program for the Challenger WiFi/BLE board.
*
* This program shows how to do basic SPI communication with the ESP32C3
* device.
*
*/
#include <ChallengerWiFi.h>
#include <SPI.h>
#define PC_PORT Serial
#define PACKET_SIZE 64
char buffer[PACKET_SIZE];
#pragma pack(push, 4)
typedef struct {
uint8_t magic;
uint8_t seq;
uint16_t length;
} data_info_t;
typedef struct {
uint8_t status;
uint8_t seq;
uint16_t length;
} slave_status_t;
typedef struct {
uint8_t CMD;
uint8_t ADDR;
uint8_t DUMMY;
} spi_header_t;
#pragma pack(pop)
enum {
SPI_NULL = 0,
SPI_READ, // slave -> master
SPI_WRITE, // master -> slave
};
static volatile bool hs_request = false;
SPISettings spiSettings(10000000, MSBFIRST, SPI_MODE0);
/************************* Code *************************/
void requestToSend(uint16_t length) {
static uint8_t seq = 1;
spi_header_t sh = {1, 0, 0};
data_info_t di = {0xfe, 0, 0};
di.length = length;
di.seq = seq++;
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
ESP32_SPI.transfer((void *)&di, NULL, sizeof di);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
}
/*
* Send the data to the ESP SPI device.
* The buffer is a char * as we are expecting to se standard
* AT command sequences here.
*/
void sendData(const char *buffer, size_t length) {
spi_header_t sh = {3, 0, 0};
uint16_t len = (uint16_t)length;
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
ESP32_SPI.transfer((void *)buffer, NULL, len);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
}
/*
* read data from the ESP SPI device.
* The buffer must be sufficiently large to hold all the data that
* is required.
*/
void readData(char *buffer, uint16_t length) {
spi_header_t sh = {4, 0, 0};
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
ESP32_SPI.transfer(NULL, (void *)buffer, length);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
}
void sendWriteDone() {
spi_header_t sh = {7, 0, 0};
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
}
void sendReceiveDone() {
spi_header_t sh = {8, 0, 0};
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
}
slave_status_t readStatus() {
spi_header_t sh = {2, 4, 0};
slave_status_t ss;
ESP32_SPI.beginTransaction(spiSettings);
digitalWrite(PIN_SPI1_SS, LOW);
ESP32_SPI.transfer((void *)&sh, NULL, sizeof sh);
ESP32_SPI.transfer(NULL, (void *)&ss, sizeof ss);
digitalWrite(PIN_SPI1_SS, HIGH);
ESP32_SPI.endTransaction();
return ss;
}
// Just wait for the handshake signal to go high here.
bool pollHS() {
bool status = true;
uint32_t timeout = millis();
while (!hs_request && ((millis() - timeout) < 500))
yield();
if (!hs_request)
status = false;
return status;
}
/*
* Send the AT command in the buffer
*/
void atSend(const char *buf) {
char tempbuf[64];
Serial.printf("--> %s", buf);
uint16_t len = strlen(buf);
requestToSend(len);
if (!pollHS()) {
Serial.println("Timeout waiting for response from ESP!");
return;
}
hs_request = false;
slave_status_t espStatus = readStatus();
if (espStatus.status == SPI_WRITE) {
sendData(buf, len);
sendWriteDone();
} else if (espStatus.status == SPI_READ) {
Serial.printf("ERROR: Expected SPI_WRITE response, got SPI_READ instead.\n");
} else {
Serial.printf("ERROR: Unknown respone from ESP device %d\n", espStatus.status);
}
}
/*
* Interrupt for the handshake signal from the ESP
* Here we just signal to the system that the interrupt has occured
*/
void hs_interrupt() {
hs_request = true;
}
void setup() {
Serial.begin(115200);
while (!Serial)
delay(10);
ESP_SERIAL_PORT.begin(115200);
Serial.println(F("Test started !"));
pinMode(PIN_ESP_RST, OUTPUT);
digitalWrite(PIN_ESP_RST, LOW); // Reset
pinMode(PIN_ESP_MODE, OUTPUT);
digitalWrite(PIN_ESP_MODE, HIGH); // Normal start
// Make control pins are in correct state when the device starts up
pinMode(PIN_SPI1_SS, OUTPUT);
digitalWrite(PIN_SPI1_SS, HIGH);
// Setup interrupt pin
pinMode(ESP32_HS, INPUT_PULLUP);
delay(1);
digitalWrite(PIN_ESP_RST, HIGH); // START
// Start and enable SPI
ESP32_SPI.begin();
attachInterrupt(digitalPinToInterrupt(ESP32_HS), hs_interrupt, RISING);
Serial.println(F("SPI communication tests starting !"));
}
int available, received;
void loop() {
// Handle data from the USB port meant for the ESP32C3
available = PC_PORT.available();
if (available) {
char temparray[64];
memset(temparray, 0, 64);
String send = PC_PORT.readStringUntil('\n');
send += '\n';
send.toCharArray(temparray, 64);
atSend(temparray);
}
// Handle response data from the ESP8285/ESP32C3
available = ESP_SERIAL_PORT.available();
if (available) {
received = ESP_SERIAL_PORT.readBytes(buffer, available);
PC_PORT.write(buffer, received);
}
// Take care of the response from the ESP32C3
if (hs_request) {
char buf[128];
hs_request = false;
slave_status_t ss = readStatus();
readData(buf, ss.length);
sendReceiveDone();
Serial.printf("<-- %s", buf);
}
}
0 Comments for “SPI communication with the ESP32C3”