diff --git a/on-target-tests/tests/gpio.rs b/on-target-tests/tests/gpio.rs index 2dc1c5daf..ce85ca1cf 100644 --- a/on-target-tests/tests/gpio.rs +++ b/on-target-tests/tests/gpio.rs @@ -26,6 +26,7 @@ mod tests { use crate::hal::pac; use crate::XTAL_FREQ_HZ; use hal::watchdog::Watchdog; + use rp2040_hal::gpio::{PinGroup, PinState}; #[init] fn setup() -> () { @@ -100,4 +101,32 @@ mod tests { assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear()); } } + + #[test] + fn check_pin_groups() { + // Safety: Test cases do not run in parallel + let mut pac = unsafe { pac::Peripherals::steal() }; + let pingroup = PinGroup::new(); + let sio = hal::Sio::new(pac.SIO); + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + let pingroup = pingroup.add_pin(pins.gpio0.into_push_pull_output_in_state(PinState::Low)); + let pingroup = pingroup.add_pin(pins.gpio1.into_push_pull_output_in_state(PinState::Low)); + let pingroup = pingroup.add_pin(pins.gpio2.into_bus_keep_input()); + let mut pingroup = pingroup.add_pin(pins.gpio3.into_bus_keep_input()); + + cortex_m::asm::delay(10); + assert!(pingroup.read() == 0); + pingroup.toggle(); + cortex_m::asm::delay(10); + assert!(pingroup.read() == 0xf); + pingroup.toggle(); + cortex_m::asm::delay(10); + assert!(pingroup.read() == 0); + } } diff --git a/rp2040-hal/src/gpio/pin_group.rs b/rp2040-hal/src/gpio/pin_group.rs index ab2fbda0c..88ff8817a 100644 --- a/rp2040-hal/src/gpio/pin_group.rs +++ b/rp2040-hal/src/gpio/pin_group.rs @@ -159,6 +159,34 @@ where } } + /// Set this set of pins to the state given in a single operation. + /// + /// The state passed in must be a mask where each bit corresponds to a gpio. + /// + /// For example, if the group contains Gpio1 and Gpio3, a read may yield: + /// ```text + /// 0b0000_0000__0000_0000__0000_0000__0000_1010 + /// This is Gpio3 ↑↑↑ + /// Gpio2 is not used || + /// This is Gpio1 | + /// ``` + /// + /// State corresponding to bins not in this group are ignored. + pub fn set_u32(&mut self, state: u32) { + use super::pin::pin_sealed::PinIdOps; + let mask = self.0.write_mask(); + let state_masked = mask & state; + let head_id = self.0.head.borrow().id(); + // UNSAFE: this register is 32bit wide and all bits are valid. + // The value set is masked + head_id.sio_out().modify(|r, w| unsafe { + // clear all bit part of this group + let cleared = r.bits() & !mask; + // set bits according to state + w.bits(cleared | state_masked) + }); + } + /// Toggles this set of pins all at the same time. /// /// This only affects output pins. Input pins in the