← All Pull Requests

programming: accept UPDI (AVR 0/1/2-series, ATtiny) as an interface #73

Closed opened by John Lauer 2026-11-07

Why

finish refuses a board with an AVR 0/1/2-series MCU (ATtiny1616 here) even when its programming interface is brought out to machine contacts: the only accepted interfaces are swd, uart-boot and usb-dfu, and these parts are programmed over one-wire UPDI (Microchip's serialUPDI / pymcuprog, PICkit, Atmel-ICE). deviate was the only way through.

Change

programming::required("updi") needs UPDI and GND at a machine contact or a labelled test pad, like the other interfaces. The refusal text and its test name the new interface.

Record example:

{"interface":"updi","pins":{"UPDI":"MC4","GND":"MC1"},"targetRef":"U1","target":"ATtiny1616-MNR","boot":"no boot strap: UPDI is always on PA0"}

Tested

Base: adom-aiflow 0.2.56 source as installed. cargo test --release -p adom-aiflow programming: 4 passed. The ATtiny1616 molecule board with the record above passed finish with this build.

🤖 Generated with Claude Code

Diff Skip to comments (1)

--- a/crates/adom-aiflow/src/programming.rs+++ b/crates/adom-aiflow/src/programming.rs@@ -1,380 +1,383 @@⋯ 23 unchanged lines ⋯         "swd" => Some(&["SWDIO", "SWCLK", "NRST", "GND"]),         "uart-boot" => Some(&["TX", "RX", "GND"]),         "usb-dfu" => Some(&["D+|DP|USB_DP", "D-|DM|USB_DM", "GND"]),+        // AVR 0/1/2-series (ATtiny, AVR-DA/DB/DD) and megaAVR 0: one-wire UPDI plus GND.+        "updi" => Some(&["UPDI", "GND"]),         _ => None,     } }⋯ 168 unchanged lines ⋯     let iface = rec["interface"].as_str().unwrap_or("");     let pins = rec["pins"].as_object().cloned().unwrap_or_default();     match required(iface) {-        None => p.push(format!("interface {iface:?} is not swd, uart-boot or usb-dfu")),+        None => p.push(format!("interface {iface:?} is not swd, uart-boot, usb-dfu or updi")),         Some(req) => for need in req {             let alias: Vec<&str> = need.split('|').collect();             if !pins.keys().any(|k| alias.iter().any(|a| a.eq_ignore_ascii_case(k))) { p.push(format!("pins.{} missing", alias[0])); }⋯ 127 unchanged lines ⋯         spec["programming"]["pins"].as_object_mut().unwrap().remove("GND");         assert!(check("/nonexistent/b.kicad_pcb", &b2, &spec).unwrap_err().contains(&"pins.GND missing".to_string()));         spec["programming"]["interface"] = json!("jtag");-        assert!(gate_message(&check("/nonexistent/b.kicad_pcb", &b2, &spec).unwrap_err()).starts_with("programming: interface \"jtag\" is not swd, uart-boot or usb-dfu"));+        assert!(gate_message(&check("/nonexistent/b.kicad_pcb", &b2, &spec).unwrap_err()).starts_with("programming: interface \"jtag\" is not swd, uart-boot, usb-dfu or updi"));     }      #[test]⋯ 39 unchanged lines ⋯     }  }+

Comments

John Lauer · 1d ago

In adom-aiflow 0.2.58. It shipped in the same release as fifteen issue fixes, so I applied it to the release tree here rather than merging the PR on top of it (a wiki merge would have put the PR's whole files over the release). That's the only reason I'm closing the PR; the code is in as written.

UPDI is now a programming interface, next to swd, uart-boot and usb-dfu. Like the others, it needs UPDI and GND at a machine contact or a labelled test pad. An AVR 0/1/2-series board no longer needs a deviation. Noah's #173 (SWD cable headers) builds on it in the same release. Checked with the programming unit tests and all workflow suites.

Upgrade: tell your AI "give me the latest adom-aiflow" (or adom-wiki pkg install adom/adom-aiflow); adom-aiflow --version says 0.2.58.

Log in to comment.