I am trying to make an esp8266 (NodeMCU v3) board act as an SPI peripheral / slave with an Arduino ATMega2560 Rev3 board as the master. The problem I am having is that the esp8266-freertos-sdk version supplied by PlatformIO is too old, and I can’t find documentation on how to configure the ESP8266 as an SPI slave apart from a technical reference written in 2020 whose example only applies to the non-OS SDK version >= 1.5.3. This is the closest attempt I have, other attempts either never retriggers the spi_callback
function or triggers it before it finishes causing a stack overflow crash. This version retriggers the `spi_callback
Don’t mind the comments, those are from the example listed in the technical reference in Section 4, 6, and 7.
Here is the user_init
function:
// main.c
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_common.h>
#include <gpio.h>
#include <freertos/projdefs.h>
#include <freertos/semphr.h>
#include "spi.h"
void user_init(void) {
init_spi();
if (xTaskCreate(&spi_task, "spi_task", 256, NULL, 0, NULL) != pdPASS) {
os_printf("Failed to create spi_task.\n");
while (1) {
gpio_output_conf(0x4, 0, 0xFFFF, 0);
vTaskDelay(250/portTICK_RATE_MS);
gpio_output_conf(0, 0x4, 0xFFFF, 0);
vTaskDelay(250/portTICK_RATE_MS);
};
}
gpio_output_conf(0, 0x4, 0xFFFF, 0);
}
Here are all the SPI functions:
// spi.c
#include "spi.h"
#include <esp_common.h>
#include <esp8266/gpio_register.h>
#include <freertos/list.h>
int count = 0;
bool new = false;
void init_spi(void) {
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
SpiAttr attr = {
.bitOrder = SpiBitOrder_MSBFirst,
.mode = SpiMode_Slave,
.speed = SpiSpeed_5MHz,
.subMode = SpiSubMode_0
};
SPIInit(SpiNum_HSPI, &attr);
SPICsPinSelect(SpiNum_HSPI, SpiPinCS_0);
SPIIntEnable(SpiNum_HSPI,
SpiIntSrc_TransDoneEn
| SpiIntSrc_WrStaDoneEn
| SpiIntSrc_RdStaDoneEn
| SpiIntSrc_WrBufDoneEn
| SpiIntSrc_RdBufDoneEn
);
}
void ICACHE_FLASH_ATTR spi_callback(void *arg) {
uint32_t regvalue, write_status, read_status, counter;
os_printf("ISR triggered\n");
if (READ_PERI_REG(0x3ff00020) & BIT4) {
//following 3 lines is to clear isr signal
CLEAR_PERI_REG_MASK(SPI_SLAVE(SpiNum_SPI), 0x3ff);
} else if (READ_PERI_REG(0x3ff00020) & BIT7) {
regvalue = READ_PERI_REG(SPI_SLAVE(SpiNum_HSPI));
os_printf("spi_slave_isr_sta SPI_SLAVE[0x%08x]\n\r",
regvalue);
SPIIntClear(SpiNum_HSPI);
// SET_PERI_REG_MASK(SPI_SLAVE(SpiNum_HSPI), SPI_SYNC_RESET);
// SPIIntClear(SpiNum_HSPI);
if (regvalue & SPI_SLV_WR_BUF_DONE) {
// User can get data from the W0~W7
os_printf("spi_slave_isr_sta : SPI_SLV_WR_BUF_DONE\n\r");
os_printf("registers: %x, ", READ_PERI_REG(SPI_W0(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W1(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W2(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W3(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W4(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W5(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W6(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W7(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W8(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W9(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W10(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W11(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W12(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W13(SpiNum_HSPI)));
os_printf("%x, ", READ_PERI_REG(SPI_W14(SpiNum_HSPI)));
os_printf("%x\n", READ_PERI_REG(SPI_W15(SpiNum_HSPI)));
// Send data back to Arduino to check
count = READ_PERI_REG(SPI_W0(SpiNum_HSPI));
os_printf("Count: %x\n", count);
} else if (regvalue & SPI_SLV_RD_BUF_DONE) {
// TO DO
os_printf("spi_slave_isr_sta : SPI_SLV_RD_BUF_DONE\n\r");
}
if (regvalue & SPI_SLV_RD_STA_DONE) {
// read_status = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI));
// write_status = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI));
os_printf("spi_slave_isr_sta :SPI_SLV_RD_STA_DONE[R=0x%08x,W=0x%08x]\n\r", read_status, write_status);
}
if (regvalue & SPI_SLV_WR_STA_DONE) {
// read_status = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI));
// write_status = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI));
os_printf("spi_slave_isr_sta :SPI_SLV_WR_STA_DONE[R=0x%08x,W=0x%08x]\n\r", read_status, write_status);
}
if (regvalue & SPI_TRANS_DONE) {
WRITE_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI), 0x8A);
WRITE_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI), 0x83);
os_printf("spi_slave_isr_sta : SPI_TRANS_DONE\n\r");
}
new = true;
vTaskDelay(100/portTICK_RATE_MS);
}
}
void spi_task(void *arg) {
int res = -1;
res = SPISlaveRecvData(SpiNum_HSPI, spi_callback);
while (1) {
os_printf("[%s] Bytes used: %d\n", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
os_printf("[%s] Heap bytes remaining: %u\n", __FUNCTION__, xPortGetFreeHeapSize());
if (new) {
SPIIntEnable(SpiNum_HSPI,
SpiIntSrc_TransDoneEn
| SpiIntSrc_WrStaDoneEn
| SpiIntSrc_RdBufDoneEn
| SpiIntSrc_WrBufDoneEn
| SpiIntSrc_RdBufDoneEn);
new = false;
}
os_printf("count: 0x%x\n", count);
vTaskDelay(1000/portTICK_RATE_MS);
}
}
int16_t get_count(void) {
return count;
}
Here are my other attempts:
void spi_task(void *arg) {
int res = -1;
res = SPISlaveRecvData(SpiNum_HSPI, spi_callback);
while (1) {
// SHOWREG();
os_printf("[%s] Bytes used: %d\n", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
os_printf("[%s] Heap bytes remaining: %u\n", __FUNCTION__, xPortGetFreeHeapSize());
if (new) {
SPIIntEnable(SpiNum_HSPI,
SpiIntSrc_TransDoneEn
| SpiIntSrc_WrStaDoneEn
| SpiIntSrc_RdBufDoneEn
| SpiIntSrc_WrBufDoneEn
| SpiIntSrc_RdBufDoneEn);
new = false;
}
// os_printf("[%s] Receive result: %d (%s)\n", __FUNCTION__, res, res == -1 ? "Failed" : "Success");
os_printf("count: 0x%x\n", count);
// spi_callback();
vTaskDelay(1000/portTICK_RATE_MS);
}
}
Any help is appreciated.