"# PIO-RX"
A robust UART receiver for unstable / drifting / low-quality serial devices, built using:
- PIO (RP2040 / RP2350) → precise edge timing capture
- CPU (C) → adaptive UART reconstruction
Standard UART (including PIO UART RX) assumes:
- stable baud rate
- clean edges
- consistent timing
Cheap devices break those assumptions:
- baud drift mid-stream
- slow edge slew
- oscillator instability
Result:
- last digits corrupted
- intermittent framing errors
- "works at 9630 but not 9600" type behaviour
Instead of sampling bits at fixed timing:
👉 Measure actual edge timing and reconstruct the signal
UART line │ ▼ PIO (edge detector + cycle counter) │ ▼ FIFO (edge timing events) │ ▼ CPU (adaptive decode) │ ▼ Recovered UART bytes
- Handles baud drift mid-stream
- Works with slow / smeared edges
- No fixed sampling point
- Automatically adapts to real timing
- Low CPU load (event-driven)
edge_uart_rx/ ├─ main.c → decode + runtime ├─ edge_delta_uart.pio → PIO edge timing engine ├─ CMakeLists.txt
- PIO detects every signal transition (edge)
- PIO measures time since last edge
- CPU receives edge timing events
- CPU reconstructs:
- bit timing
- bit values
- UART frames
- Weight scale sending 5-byte packets
- 9600 baud
- cheap oscillator
- drifting timing
👉 This system recovers clean data where normal UART fails
- RP2040 or RP2350 (Pico / Pico 2)
- UART TX line connected to
RX_PIN(default = GPIO 2)
mkdir build
cd build
cmake ..
make -j
Flash
Drag UF2 or use picotool.
🛠 Configuration
In main.c:
#define RX_PIN 2
#define UART_BAUD 9600.0
📈 Key tuning parameters
Parameter Meaning
bit_us Expected bit time
edge filter Rejects noise / tiny pulses
baud adaptation Tracks drift
idle flush completes trailing bytes
⚠️ Limitations
Extremely noisy signals may need hardware cleanup
Very long runs with no edges rely on timing estimation
Not a drop-in replacement for high-speed UART
💥 When to use this
Use this when:
UART hardware fails intermittently
PIO UART RX loses sync
You see "last digits corrupted"
Adjusting baud manually sometimes helps
🧾 TLDR
This is a timing-based UART decoder, not a sampling-based one.
👉 It follows the signal instead of assuming it.
"# PIO-RX"