// Standalone diagnostic firmware - NOT part of the real esp-spi project. // Purpose: bypass the SPI slave peripheral entirely and watch the raw GPIO // pins (plain digital input, interrupt on every edge) that our real // firmware's spi_slave.cpp configures for SPI slave use on ESP32-S3: // CS=GPIO10, SCLK=GPIO12, MOSI=GPIO13, MISO=GPIO11 // Logs every CS/SCLK edge with a microsecond timestamp and the // MOSI/MISO/CS level sampled at that instant, so a real transaction // attempt from the CH341A bridge can be visually reconstructed from the // console log - answers directly whether the ESP32 sees anything at all // on these pins, and if so, whether it looks like a sane SPI waveform // (CS low, some number of SCLK edges, CS high) or not. #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/gpio.h" #include "esp_timer.h" #define PIN_CS 10 #define PIN_SCLK 12 #define PIN_MOSI 13 #define PIN_MISO 11 typedef struct { int64_t us; uint8_t pin; // which pin's edge triggered this event (PIN_CS or PIN_SCLK) uint8_t level; // level that pin transitioned TO uint8_t cs; uint8_t sclk; uint8_t mosi; uint8_t miso; } event_t; #define EVQ_LEN 4096 static QueueHandle_t evq; static void IRAM_ATTR gpio_isr(void *arg) { uint32_t pin = (uint32_t)(uintptr_t)arg; event_t ev; ev.us = esp_timer_get_time(); ev.pin = (uint8_t)pin; ev.level = (uint8_t)gpio_get_level((gpio_num_t)pin); ev.cs = (uint8_t)gpio_get_level(PIN_CS); ev.sclk = (uint8_t)gpio_get_level(PIN_SCLK); ev.mosi = (uint8_t)gpio_get_level(PIN_MOSI); ev.miso = (uint8_t)gpio_get_level(PIN_MISO); BaseType_t hpw = pdFALSE; xQueueSendFromISR(evq, &ev, &hpw); if (hpw) portYIELD_FROM_ISR(); } void app_main(void) { printf("\n\n=== spi_gpio_probe starting ===\n"); printf("Pins: CS=GPIO%d SCLK=GPIO%d MOSI=GPIO%d MISO=GPIO%d\n", PIN_CS, PIN_SCLK, PIN_MOSI, PIN_MISO); printf("Watching CS + SCLK edges only (plain digital input, no SPI peripheral involved).\n\n"); evq = xQueueCreate(EVQ_LEN, sizeof(event_t)); gpio_config_t io = { 0 }; io.pin_bit_mask = (1ULL << PIN_CS) | (1ULL << PIN_SCLK) | (1ULL << PIN_MOSI) | (1ULL << PIN_MISO); io.mode = GPIO_MODE_INPUT; io.pull_up_en = GPIO_PULLUP_DISABLE; io.pull_down_en = GPIO_PULLDOWN_DISABLE; io.intr_type = GPIO_INTR_ANYEDGE; gpio_config(&io); gpio_install_isr_service(0); gpio_isr_handler_add((gpio_num_t)PIN_CS, gpio_isr, (void*)(uintptr_t)PIN_CS); gpio_isr_handler_add((gpio_num_t)PIN_SCLK, gpio_isr, (void*)(uintptr_t)PIN_SCLK); printf("Idle levels right now: CS=%d SCLK=%d MOSI=%d MISO=%d\n\n", gpio_get_level(PIN_CS), gpio_get_level(PIN_SCLK), gpio_get_level(PIN_MOSI), gpio_get_level(PIN_MISO)); int64_t last_us = 0; unsigned long total_events = 0; unsigned long cs_high_count = 0; for (;;) { event_t ev; if (xQueueReceive(evq, &ev, pdMS_TO_TICKS(3000))) { const char *pin_name = (ev.pin == PIN_CS) ? "CS " : "SCLK"; long long delta = last_us ? (long long)(ev.us - last_us) : 0; printf("[t=%10lld us d=%6lld us] %s -> %d | CS=%d SCLK=%d MOSI=%d MISO=%d\n", (long long)ev.us, delta, pin_name, ev.level, ev.cs, ev.sclk, ev.mosi, ev.miso); last_us = ev.us; total_events++; if (ev.pin == PIN_CS && ev.level == 1) cs_high_count++; } else { printf("--- idle (no CS/SCLK edges in last 3s) --- total_events=%lu cs_high_transitions=%lu\n", total_events, cs_high_count); } } }