embassy-rs/embassy · error
RTS and CTS pins must be either both set or none set.
Error message
RTS and CTS pins must be either both set or none set.
What it means
UARTE (UART with EasyDMA) construction checks that hardware flow control pins are configured consistently. RTS and CTS are a pair used by the hardware flow-control feature; enabling only one is meaningless at the hardware level, so `new_inner` panics when exactly one of the two pins is `Some`. Both set enables hardware flow control; neither set disables it.
Solutions
- Pass both RTS and CTS pins (or neither) so the pair matches.
- If the board only routes one flow-control pin, pass None for both and disable hardware flow control in the Config.
- Fix the board config/pin mapping so the flow-control pair is complete.
Example fix
// before let mut uarte = Uarte::new(p.UARTE0, irq, p.P0_06, p.P0_08, p.P0_05, NoPin, config); // after let mut uarte = Uarte::new(p.UARTE0, irq, p.P0_06, p.P0_08, p.P0_05, p.P0_07, config); // RTS + CTS both set (or use NoPin for both)
Defensive patterns
Strategy: validation
Validate before calling
fn flow_pins_consistent(rts: Option<AnyPin>, cts: Option<AnyPin>) -> bool {
rts.is_some() == cts.is_some()
}
assert!(flow_pins_consistent(rts, cts), "RTS/CTS must both be set or both None"); Type guard
fn both_or_none<T>(a: &Option<T>, b: &Option<T>) -> bool { a.is_some() == b.is_some() } Prevention
- Define a single board-config struct whose constructor takes flow-control pins as a pair (enum FlowControl { None, Pins { rts, cts } }).
- Copy pin assignments verbatim from the board support crate instead of hand-picking pins.
- Check the board schematic for RTS/CTS routing before configuring hardware flow control.
When it happens
Trigger: Calling `Uarte::new` / `Uarte::new_with_rtscts` (or the blocking variant) passing `rts: Some(pin)` with `cts: None`, or `rts: None` with `cts: Some(pin)`.
Common situations: Board support configs that define only a CTS pin (or only RTS) in pin mappings; copying an example and deleting one flow-control pin because it is not routed on the board; typos in peripheral config macros.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Failed to apply workaround for UART
- Boot prepare error
- BufferedUarte UART overrun
- unwrap of ` ` failed
- unwrap of ` ` failed
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/9faf9526b3ff73c2.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-nrf/src/uarte.rs:218
Some(rts.into()),
config,
)
}
fn new_inner<T: Instance>(
_uarte: Peri<'d, T>,
rxd: Peri<'d, AnyPin>,
txd: Peri<'d, AnyPin>,
cts: Option<Peri<'d, AnyPin>>,
rts: Option<Peri<'d, AnyPin>>,
config: Config,
) -> Self {
let r = T::regs();
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
(false, false) => false,
(true, true) => true,
_ => panic!("RTS and CTS pins must be either both set or none set."),
};
configure(r, config, hardware_flow_control);
configure_rx_pins(r, rxd, rts);
configure_tx_pins(r, txd, cts);
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
r.enable().write(|w| w.set_enable(vals::Enable::Enabled));
let s = T::state();
s.tx_rx_refcount.store(2, Ordering::Relaxed);
Self {
tx: UarteTx {
r: T::regs(),
state: T::state(),
_p: PhantomData {},
},View on GitHub (pinned to 463a07b963)