#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/spi_slave.h" #include "esp_log.h" #include "esp_err.h" #include "esp_wifi.h" #include "esp_now.h" #include "esp_netif.h" #include "nvs_flash.h" #include "esp_timer.h" static const char *TAG = "SPI_SLAVE"; // SPI Slave configuration for ESP32-C3 #define SPI_SLAVE_HOST SPI2_HOST #define SPI_SLAVE_MOSI 10 #define SPI_SLAVE_MISO 9 #define SPI_SLAVE_SCLK 20 #define SPI_SLAVE_CS 7 #define SPI_SLAVE_DMA_CHAN SPI_DMA_CH_AUTO // Buffer size for SPI communication #define BUFFER_SIZE 256 // ESP-NOW configuration #define ESPNOW_MAXDELAY 512 #define ESPNOW_QUEUE_SIZE 6 // Max ESP-NOW payload length; keep within safe limit #define ESPNOW_MAX_PAYLOAD 200 // SPI slave receive buffer static uint8_t recvbuf[BUFFER_SIZE]; static uint8_t sendbuf[BUFFER_SIZE]; // ESP-NOW broadcast MAC address (broadcast to all devices) static uint8_t broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // SPI slave configuration structure static spi_slave_transaction_t slave_trans; // ESP-NOW callback functions static void espnow_send_cb(const esp_now_send_info_t *send_info, esp_now_send_status_t status) { ESP_LOGI(TAG, "ESP-NOW send status: %s", status == ESP_NOW_SEND_SUCCESS ? "SUCCESS" : "FAIL"); } static void espnow_recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len) { ESP_LOGI(TAG, "ESP-NOW received %d bytes from %02x:%02x:%02x:%02x:%02x:%02x", len, recv_info->src_addr[0], recv_info->src_addr[1], recv_info->src_addr[2], recv_info->src_addr[3], recv_info->src_addr[4], recv_info->src_addr[5]); } // Initialize ESP-NOW static esp_err_t espnow_init(void) { // Initialize NVS esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // Initialize network interface ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); // Initialize WiFi wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); // Initialize ESP-NOW ESP_ERROR_CHECK(esp_now_init()); ESP_ERROR_CHECK(esp_now_register_send_cb(espnow_send_cb)); ESP_ERROR_CHECK(esp_now_register_recv_cb(espnow_recv_cb)); // Add peer (broadcast) esp_now_peer_info_t peer; memset(&peer, 0, sizeof(esp_now_peer_info_t)); memcpy(peer.peer_addr, broadcast_mac, ESP_NOW_ETH_ALEN); peer.channel = 0; peer.ifidx = WIFI_IF_STA; peer.encrypt = false; ESP_ERROR_CHECK(esp_now_add_peer(&peer)); ESP_LOGI(TAG, "ESP-NOW initialized successfully"); return ESP_OK; } // Broadcast raw SPI bytes via ESP-NOW static void broadcast_spi_data(uint8_t *data, uint8_t length) { uint8_t send_len = length > ESPNOW_MAX_PAYLOAD ? ESPNOW_MAX_PAYLOAD : length; // Send raw payload directly; receiver can json.loads if payload is JSON esp_err_t result = esp_now_send(broadcast_mac, data, send_len); if (result != ESP_OK) { ESP_LOGE(TAG, "ESP-NOW send failed: %s", esp_err_to_name(result)); } else { ESP_LOGI(TAG, "Broadcasting %d bytes via ESP-NOW", send_len); } } void app_main(void) { ESP_LOGI(TAG, "Starting SPI Slave with ESP-NOW example"); // Initialize ESP-NOW first esp_err_t ret = espnow_init(); if (ret != ESP_OK) { ESP_LOGE(TAG, "ESP-NOW initialization failed: %s", esp_err_to_name(ret)); return; } // Configure SPI slave bus spi_bus_config_t buscfg = { .mosi_io_num = SPI_SLAVE_MOSI, .miso_io_num = SPI_SLAVE_MISO, .sclk_io_num = SPI_SLAVE_SCLK, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = BUFFER_SIZE, }; // Configure SPI slave interface spi_slave_interface_config_t slvcfg = { .mode = 0, // SPI mode 0 (CPOL=0, CPHA=0) .spics_io_num = SPI_SLAVE_CS, .queue_size = 3, .flags = 0, }; // Initialize SPI slave bus ret = spi_slave_initialize(SPI_SLAVE_HOST, &buscfg, &slvcfg, SPI_SLAVE_DMA_CHAN); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize SPI slave: %s", esp_err_to_name(ret)); return; } ESP_LOGI(TAG, "SPI Slave initialized successfully"); ESP_LOGI(TAG, "MOSI: GPIO%d, MISO: GPIO%d, SCLK: GPIO%d, CS: GPIO%d", SPI_SLAVE_MOSI, SPI_SLAVE_MISO, SPI_SLAVE_SCLK, SPI_SLAVE_CS); // Prepare send buffer with some test data for (int i = 0; i < BUFFER_SIZE; i++) { sendbuf[i] = i; } // Main loop while (1) { // Clear receive buffer memset(recvbuf, 0, BUFFER_SIZE); // Prepare transaction slave_trans.length = BUFFER_SIZE * 8; // Length in bits slave_trans.trans_len = 0; slave_trans.tx_buffer = sendbuf; slave_trans.rx_buffer = recvbuf; // Wait for SPI master to initiate transaction ret = spi_slave_transmit(SPI_SLAVE_HOST, &slave_trans, portMAX_DELAY); if (ret != ESP_OK) { ESP_LOGE(TAG, "SPI slave transmit failed: %s", esp_err_to_name(ret)); continue; } // Print received data uint8_t received_bytes = slave_trans.trans_len / 8; ESP_LOGI(TAG, "Received %d bytes:", received_bytes); for (int i = 0; i < received_bytes && i < 32; i++) { printf("0x%02x ", recvbuf[i]); if ((i + 1) % 16 == 0) printf("\n"); } if (received_bytes % 16 != 0) printf("\n"); // Broadcast received data via ESP-NOW if (received_bytes > 0) { broadcast_spi_data(recvbuf, received_bytes); } // Small delay before next transaction vTaskDelay(pdMS_TO_TICKS(100)); } }