Skip to content

Commit

Permalink
gpio: add PinGroup::set_u32 to allow setting each pin to a differen…
Browse files Browse the repository at this point in the history
…t state (#811)

* gpio: add `PinGroup::set_u32` to allow setting each pin to a different state

* Add on-target-test for pin groups

---------

Co-authored-by: Jan Niehusmann <[email protected]>
  • Loading branch information
ithinuel and jannic authored Jun 30, 2024
1 parent 1da07a0 commit 549ddbf
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
29 changes: 29 additions & 0 deletions on-target-tests/tests/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() -> () {
Expand Down Expand Up @@ -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);
}
}
28 changes: 28 additions & 0 deletions rp2040-hal/src/gpio/pin_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 549ddbf

Please sign in to comment.