From ea36d121db8dc71ebd205040cdd4b99fe5c2086c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 22 May 2025 14:01:40 -0700 Subject: [PATCH] embassy-rp: implement input/output inversion RP2040/RP23xx support inversion in HW of the inputs and outputs. Implement minimal support for that. --- embassy-rp/src/gpio.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/rp/src/bin/gpio.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 2fb2d65c2..9b5faac15 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -146,6 +146,12 @@ impl<'d> Input<'d> { self.pin.get_level() } + /// Configure the input logic inversion of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_input_inversion(invert) + } + /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { @@ -382,6 +388,12 @@ impl<'d> Output<'d> { self.pin.set_slew_rate(slew_rate) } + /// Configure the output logic inversion of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_output_inversion(invert) + } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -685,6 +697,30 @@ impl<'d> Flex<'d> { self.pin.sio_oe().value_xor().write_value(self.bit()) } + /// Configure the input logic inversion of this pin. + #[inline] + pub fn set_input_inversion(&mut self, invert: bool) { + self.pin.gpio().ctrl().modify(|w| { + w.set_inover(if invert { + pac::io::vals::Inover::INVERT + } else { + pac::io::vals::Inover::NORMAL + }) + }); + } + + /// Configure the output logic inversion of this pin. + #[inline] + pub fn set_output_inversion(&mut self, invert: bool) { + self.pin.gpio().ctrl().modify(|w| { + w.set_outover(if invert { + pac::io::vals::Outover::INVERT + } else { + pac::io::vals::Outover::NORMAL + }) + }); + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -815,6 +851,8 @@ impl<'d> Drop for Flex<'d> { self.pin.pad_ctrl().write(|_| {}); self.pin.gpio().ctrl().write(|w| { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _); + w.set_inover(pac::io::vals::Inover::NORMAL); + w.set_outover(pac::io::vals::Outover::NORMAL); }); self.pin.io().int_dormant_wake().inte(idx / 8).write_clear(|w| { w.set_edge_high(idx % 8, true); diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index 614b6317a..8bd0df8d8 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -67,6 +67,40 @@ async fn main(_spawner: Spawner) { } } + // Test input inversion + { + let mut b = Input::new(b.reborrow(), Pull::None); + b.set_inversion(true); + // no pull, the status is undefined + + let mut a = Output::new(a.reborrow(), Level::Low); + delay(); + assert!(b.is_high()); + a.set_high(); + delay(); + assert!(b.is_low()); + + b.set_inversion(false); + a.set_inversion(true); + + a.set_low(); + delay(); + assert!(b.is_high()); + + a.set_high(); + delay(); + assert!(b.is_low()); + + b.set_inversion(true); + a.set_high(); + delay(); + assert!(b.is_high()); + + a.set_high(); + delay(); + assert!(b.is_high()); + } + // Test input no pull { let b = Input::new(b.reborrow(), Pull::None);