Add ESP32-C3 SPI slave with ESP-NOW, Raspberry Pi test tools, and updated project structure

- ESP32-C3 SPI slave project with ESP-NOW broadcast functionality
- Raspberry Pi SPI master test tools and CLI for JSON communication
- Merged src/ directory from full branch with lighting controller code
- Updated Pipfile with system install scripts and ESP32 monitoring
- Added comprehensive test suite for SPI communication
This commit is contained in:
Pi User
2025-10-01 21:08:28 +13:00
parent aa9b5bb324
commit 5a05ee99a1
1356 changed files with 190644 additions and 87 deletions

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

191
esp32/main/main.c Normal file
View File

@@ -0,0 +1,191 @@
#include <stdio.h>
#include <string.h>
#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));
}
}