Originally posted by begeistert June 25, 2026
Hi! I've built PIO (Programmable I/O) support for RP2040 / RP2350 in nanoFramework and would love to contribute it upstream — opening this to gauge interest and figure out the preferred path before a formal feature request.
The gap
Today a Pico app can do GPIO / I2C / SPI / PWM / ADC from C#, but PIO — the chip's headline feature — isn't reachable at all. PIO is the reason people reach for a Pico: WS2812/NeoPixel, custom serial protocols, precise timing, quadrature decoding, DPI/HUB75, etc. There's also no managed way to author PIO programs (other approaches force the external pioasm tool + a raw ushort[], which loses the program metadata the runtime needs).
What I have (working prototype)
- An in-CLR inline PIO assembler — write PIO programs in C# with a fluent /
System.Reflection.Emit-style builder (no external pioasm, no raw ushort[]), byte-exact vs pioasm (golden tests). It returns a rich PioProgram (wrap / side-set / shift metadata) that seeds the state-machine config automatically.
- A thin runtime API (
Pio / PioBlock / PioStateMachine) backed by InternalCall native interop in nf-interpreter, version-aware for RP2350 PIO v1 (3rd block PIO2, FIFO PUTGET join, GPIO base).
- Validated end-to-end: byte-exact golden tests, behaviour on an RP2040/RP2350 emulator, and on real silicon — a Pico 2 blinking & fading its on-board LED via a C#-assembled PIO program running through the nanoCLR.
// Assemble a PIO program in C# (byte-exact vs pioasm), then run it on a state machine:
PioBlock pio = Pio.Get(0); // 0..1 (RP2040) / 0..2 (RP2350)
uint offset = pio.AddProgram(ws2812); // loads instr memory, relocates JMPs
PioStateMachine sm = pio.ClaimStateMachine();
sm.Init(offset, PioStateMachineConfig.FromProgram(ws2812, (int)offset) // wrap/side-set/shift auto-applied
.SideSetPins(2).OutPins(2, 1).ClockDivisor(15.625f));
pio.InitGpio(2);
sm.SetConsecutivePinDirs(2, 1, true);
sm.Enabled = true;
sm.Put(grb << 8); // CPU just feeds the FIFO; the SM bit-bangs in hardware
Proposed shape
A nanoFramework.Hardware.Rp2040 library (same pattern as nanoFramework.Hardware.Esp32.Rmt, a chip-specific programmable-timing peripheral) + the PIO native in nf-interpreter, bound by the usual MDP checksum/version stubs.
Questions for the team
- Is there interest in upstreaming PIO support for the RP2040/RP2350 family?
- Preferred structure — a new
nanoFramework.Hardware.Rp2040 org repo + the native in nf-interpreter?
- How would you like the RP2350 PIO-v1 version-awareness handled?
I have a feature request drafted and runnable demo samples (WS2812 / blink / fade), and I'm happy to open the formal issue, split the work into the managed-library PR(s) and the nf-interpreter native PR(s), and demo the silicon run. Thanks! 🙏
Discussed in https://github.com/orgs/nanoframework/discussions/1807
Originally posted by begeistert June 25, 2026
Hi! I've built PIO (Programmable I/O) support for RP2040 / RP2350 in nanoFramework and would love to contribute it upstream — opening this to gauge interest and figure out the preferred path before a formal feature request.
The gap
Today a Pico app can do GPIO / I2C / SPI / PWM / ADC from C#, but PIO — the chip's headline feature — isn't reachable at all. PIO is the reason people reach for a Pico: WS2812/NeoPixel, custom serial protocols, precise timing, quadrature decoding, DPI/HUB75, etc. There's also no managed way to author PIO programs (other approaches force the external
pioasmtool + a rawushort[], which loses the program metadata the runtime needs).What I have (working prototype)
System.Reflection.Emit-style builder (no externalpioasm, no rawushort[]), byte-exact vspioasm(golden tests). It returns a richPioProgram(wrap / side-set / shift metadata) that seeds the state-machine config automatically.Pio/PioBlock/PioStateMachine) backed byInternalCallnative interop innf-interpreter, version-aware for RP2350 PIO v1 (3rd block PIO2, FIFO PUTGET join, GPIO base).Proposed shape
A
nanoFramework.Hardware.Rp2040library (same pattern asnanoFramework.Hardware.Esp32.Rmt, a chip-specific programmable-timing peripheral) + the PIO native innf-interpreter, bound by the usual MDP checksum/version stubs.Questions for the team
nanoFramework.Hardware.Rp2040org repo + the native innf-interpreter?I have a feature request drafted and runnable demo samples (WS2812 / blink / fade), and I'm happy to open the formal issue, split the work into the managed-library PR(s) and the
nf-interpreternative PR(s), and demo the silicon run. Thanks! 🙏