What I've confirmed, in order:
1. Radar confirmed working via direct USB-serial connection to a PC — correct, continuous ~1Hz heartbeat frames (0xF4F3F2F1 header, correct tail, valid payload).
2. Continuity confirmed end-to-end, radar TX pin → GPIO42 header pin, with the full test setup wired and both listeners attached — no shorts to GND.
3. Voltage confirmed 5.1V at the radar's VCC.
4. A raw digitalRead() polling test (bypassing UART entirely, ~900k samples/sec for 10s) initially showed GPIO42 stuck flat LOW — turned out GPIO41/42 are part of the ESP32-S3's JTAG pin group (MTDI/MTMS), and the pin was apparently claimed by the USB-JTAG peripheral. Calling gpio_reset_pin() fixed this — pin now idles correctly HIGH and shows real transitions on the raw digitalRead test.
5. Despite that fix, the actual UART peripheral (tried via both Arduino HardwareSerial and raw ESP-IDF uart_driver_install/uart_param_config/uart_set_pin, all returning ESP_OK) still receives nothing.
6. Simultaneous check: tapped the radar's TX line to both the ESP32 and a USB-serial adapter → PC at the same physical node, same GND. PC reliably captures real frames. ESP32, on the identical wiring, still shows nothing but that one init byte.
What I'm ruling out: radar hardware, the wire/tap point (continuity confirmed on the exact live configuration), UART config/baud/framing (matches a validated Python reference implementation exactly), and JTAG pin claim (fixed, confirmed via raw pin toggling, didn't change the outcome). What's left, that I can't explain: the raw GPIO pad electrically toggles correctly, uart_set_pin() reports successful GPIO-matrix binding, and yet the UART peripheral itself never sees real traffic. What am I missing?
Do you have ANY suggestions or ways to fix this?
Raw ESP-IDF UART init (bypassing HardwareSerial entirely):
Code: Select all
// Standalone diagnostic — separate firmware image, on-device equivalent of
// radar_test/radar_raw_test.py's "Step 1" raw connectivity check.
//
// Not timing-sensitive (this is not radar_latency_test) — prints freely.
//
// 2026-07-13: GPIO41/42 are ESP32-S3's dedicated external JTAG pins
// (MTDI/MTMS). gpio42_signal_test showed a real behavioral change on GPIO42
// after calling gpio_reset_pin() (idle level went from stuck LOW/0
// transitions to HIGH/9 transitions in 10s), but even with that fix, the
// HardwareSerial-based version of this test still received nothing but a
// single init-artifact byte over 130s — while a simultaneous PC capture on
// the same physical tap point confirmed the radar IS transmitting real,
// correct frames. That rules out the radar side entirely and points at a
// GPIO-matrix binding problem specific to the UART peripheral (the pin
// toggles per digitalRead(), so it's not a dead/floating pin).
//
// This version bypasses HardwareSerial entirely and drives the raw ESP-IDF
// UART driver directly (uart_driver_install + uart_param_config +
// uart_set_pin + uart_read_bytes), printing the return code of every init
// call — especially uart_set_pin(), which is the exact call that binds the
// UART peripheral to GPIO pins via the GPIO matrix. If that returns ESP_OK
// but bytes still don't arrive, HardwareSerial itself is cleared as a
// suspect; if it errors, that's the smoking gun.
//
// Build/run as its own PlatformIO environment:
// pio run -e radar-uart-raw-dump -t upload -t monitor
#include <Arduino.h>
#include "driver/gpio.h"
#include "driver/uart.h"
static const int RADAR_RX_PIN = 42; // ESP32 RX <- radar TX
static const int RADAR_TX_PIN = 41; // ESP32 TX -> radar RX
static const unsigned long RADAR_BAUD = 115200;
static const uart_port_t RADAR_UART_NUM = UART_NUM_2;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("Radar raw ESP-IDF UART driver test — bypasses HardwareSerial entirely");
Serial.printf("GPIO%d=RX<-radar TX, GPIO%d=TX->radar RX, %lu 8N1, UART_NUM_2\n", RADAR_RX_PIN, RADAR_TX_PIN, RADAR_BAUD);
Serial.println();
gpio_reset_pin((gpio_num_t)RADAR_TX_PIN);
gpio_reset_pin((gpio_num_t)RADAR_RX_PIN);
uart_config_t uart_config = {};
uart_config.baud_rate = RADAR_BAUD;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_APB;
esp_err_t err;
err = uart_driver_install(RADAR_UART_NUM, 256, 0, 0, NULL, 0);
Serial.printf("uart_driver_install: %s (%d)\n", esp_err_to_name(err), err);
err = uart_param_config(RADAR_UART_NUM, &uart_config);
Serial.printf("uart_param_config: %s (%d)\n", esp_err_to_name(err), err);
err = uart_set_pin(RADAR_UART_NUM, RADAR_TX_PIN, RADAR_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
Serial.printf("uart_set_pin: %s (%d) <-- actual GPIO-matrix binding call\n", esp_err_to_name(err), err);
Serial.println();
Serial.println("Reading raw bytes via uart_read_bytes() (non-blocking). Printing as hex, 32/line.");
Serial.println();
}
void loop() {
static uint32_t totalBytes = 0;
static uint8_t col = 0;
static uint32_t lastReportMs = 0;
uint8_t b;
int len = uart_read_bytes(RADAR_UART_NUM, &b, 1, 0); // 0 ticks = non-blocking
if (len > 0) {
Serial.printf("%02X ", b);
totalBytes++;
col++;
if (col >= 32) {
col = 0;
Serial.println();
}
}
uint32_t now = millis();
if (now - lastReportMs >= 5000) {
lastReportMs = now;
Serial.printf("\n[%lu ms] total bytes so far: %lu\n", now, totalBytes);
}
}
