#include <stdlib.h>
#include <string.h>
#include "driver/rtc_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_slave.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define PIN_NUM_FSPID_Data0 11 /* GPIO for SPI Data0 (MOSI in master mode, or Data0 in Quad SPI mode) */
#define PIN_NUM_FSPIQ_Data1 13 /* GPIO for SPI Data1 (MISO in master mode, or Data1 in Quad SPI mode) */
#define PIN_NUM_FSPIWP_Data2 14 /* GPIO for SPI Data2 (WP in Quad SPI mode) */
#define PIN_NUM_FSPIHD_Data3 9 /* GPIO for SPI Data3 (HD in Quad SPI mode) */
#define PIN_NUM_FSPICLK 12 /* GPIO for SPI Clock */
#define PIN_NUM_FSPICS0 10 /* GPIO for SPI Chip Select (CS) */
// this is used to simulate a spio data traffic and test the reception of the spi-slave config
#define PIN_CLK_OUT 4
#define PIN_CS_OUT 5
#define CLK_FREQUENCY_HZ 1000
static const char TAG[] = "main";
/* DMA buffer for received data */
#define MAX_TRANSFER_SIZE 20 /* Maximum transfer size for one DMA transaction (in bytes) */
spi_slave_transaction_t trans = { 0 };
/* Allocate DMA-compatible buffer for receiving data */
WORD_ALIGNED_ATTR uint8_t rx_buffer[MAX_TRANSFER_SIZE] = {0};
WORD_ALIGNED_ATTR uint8_t tx_buffer[MAX_TRANSFER_SIZE] = {0};
/* ISR handler for SPI DMA transactions */
static void spi_slave_isr_post_setup(spi_slave_transaction_t *trans) {
__asm__ volatile("nop");
}
static void spi_slave_isr_post_trans(spi_slave_transaction_t *trans) {
__asm__ volatile("nop");
}
void spi_master_sim_task(void *pvParameter) {
static uint8_t cntr = 0;
static uint8_t data = 1;
gpio_set_level(PIN_CS_OUT, 0);
vTaskDelay(pdMS_TO_TICKS(10));
while (1) {
if(cntr < MAX_TRANSFER_SIZE * 8){ // send 20 bytes of data
// data is changed on the negative edge of SCK and sampled on the positive edge.
vTaskDelay(pdMS_TO_TICKS(5));
gpio_set_level(PIN_CLK_OUT, 1);
vTaskDelay(pdMS_TO_TICKS(5));
gpio_set_pull_mode(PIN_NUM_FSPID_Data0, data);
data = !data;
gpio_set_pull_mode(PIN_NUM_FSPIQ_Data1, GPIO_PULLDOWN_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPIWP_Data2, GPIO_PULLDOWN_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPIHD_Data3, GPIO_PULLDOWN_ONLY);
vTaskDelay(pdMS_TO_TICKS(5));
gpio_set_level(PIN_CLK_OUT, 0);
vTaskDelay(pdMS_TO_TICKS(5));
cntr++;
}else{
cntr=0;
gpio_set_level(PIN_CS_OUT, 1);
vTaskDelay(3000);
gpio_set_level(PIN_CS_OUT, 0);
}
}
}
void app_main(void) {
esp_err_t ret;
ESP_LOGI(TAG, "Initializing SPI as slave...");
/* Configure SPI slave interface */
spi_bus_config_t buscfg = {
.data0_io_num = PIN_NUM_FSPID_Data0, /* Pin for SPI Data0 */
.data1_io_num = PIN_NUM_FSPIQ_Data1, /* Pin for SPI Data1 */
.data2_io_num = PIN_NUM_FSPIWP_Data2, /* Pin for SPI Data2 */
.data3_io_num = PIN_NUM_FSPIHD_Data3, /* Pin for SPI Data3 */
.data4_io_num = -1,
.data5_io_num = -1,
.data6_io_num = -1,
.data7_io_num = -1,
.sclk_io_num = PIN_NUM_FSPICLK, /* Pin for SPI Clock */
.flags = SPICOMMON_BUSFLAG_QUAD, /* Quad SPI mode */
.isr_cpu_id = 0,
.max_transfer_sz = MAX_TRANSFER_SIZE, /* Max DMA transfer size in bytes */
};
/* SPI slave interface configuration */
spi_slave_interface_config_t slvcfg = {
.spics_io_num = PIN_NUM_FSPICS0, /* Pin for SPI CS (Chip Select) */
.flags = 0, /* Default flags */
.queue_size = MAX_TRANSFER_SIZE, /* Transaction queue size */
.mode = 1, /* SPI mode (CPOL, CPHA) */
.post_setup_cb = spi_slave_isr_post_setup, /* ISR for post-setup actions */
.post_trans_cb = spi_slave_isr_post_trans, /* ISR for post-transaction actions */
};
// Enable pull-ups on SPI lines to simulate data when no master is connected on data lines.
gpio_set_pull_mode(PIN_NUM_FSPID_Data0, GPIO_PULLDOWN_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPIQ_Data1, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPIWP_Data2, GPIO_PULLDOWN_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPIHD_Data3, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPICLK, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(PIN_NUM_FSPICS0, GPIO_PULLUP_ONLY);
// We use only CS and CLK, initialize it here
gpio_set_direction(PIN_CLK_OUT, GPIO_MODE_OUTPUT);
gpio_set_direction(PIN_CS_OUT, GPIO_MODE_OUTPUT);
gpio_set_level(PIN_CLK_OUT, 0);
gpio_set_level(PIN_CS_OUT, 1);
/* Initialize and attach SPI slave interface */
ret = spi_slave_initialize(SPI2_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO);
ESP_ERROR_CHECK(ret);
memset(&trans, 0, sizeof(trans));
ESP_LOGI(TAG, "SPI slave ready to receive data.");
// Create Test task
xTaskCreate(spi_master_sim_task, "clock_task", 2048, NULL, 5, NULL);
while (1)
{
trans.rx_buffer = rx_buffer;
trans.tx_buffer = tx_buffer;
trans.length = MAX_TRANSFER_SIZE * 8; /* Length in bits, send only 20 bytes for testing */
ret = spi_slave_transmit(SPI2_HOST, &trans, portMAX_DELAY);
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "Transaction complete.");
}
}