diff --git a/on-target-tests/Cargo.toml b/on-target-tests/Cargo.toml index eb78438ed..90b9274b1 100644 --- a/on-target-tests/Cargo.toml +++ b/on-target-tests/Cargo.toml @@ -36,6 +36,10 @@ harness = false name = "i2c_loopback_async" harness = false +[[test]] +name = "gpio" +harness = false + [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" diff --git a/on-target-tests/tests/gpio.rs b/on-target-tests/tests/gpio.rs new file mode 100644 index 000000000..2dc1c5daf --- /dev/null +++ b/on-target-tests/tests/gpio.rs @@ -0,0 +1,103 @@ +#![no_std] +#![no_main] +#![cfg(test)] + +use defmt_rtt as _; // defmt transport +use defmt_test as _; +use panic_probe as _; +use rp2040_hal as hal; // memory layout // panic handler + +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. +/// Note: This boot block is not necessary when using a rp-hal based BSP +/// as the BSPs already perform this step. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H; + +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +#[defmt_test::tests] +mod tests { + use crate::hal; + use crate::hal::clocks::init_clocks_and_plls; + use crate::hal::pac; + use crate::XTAL_FREQ_HZ; + use hal::watchdog::Watchdog; + + #[init] + fn setup() -> () { + unsafe { + hal::sio::spinlock_reset(); + } + let mut pac = pac::Peripherals::take().unwrap(); + let _core = pac::CorePeripherals::take().unwrap(); + let mut watchdog = Watchdog::new(pac.WATCHDOG); + + let _clocks = init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + 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, + ); + } + + #[test] + fn check_ie() { + // Safety: Test cases do not run in parallel + let pac = unsafe { pac::Peripherals::steal() }; + for id in 0..=29 { + assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear()); + } + } + + #[test] + fn check_ie_gets_enabled() { + // Safety: Test cases do not run in parallel + let pac = unsafe { pac::Peripherals::steal() }; + for id in 0..=29 { + let pin = unsafe { + hal::gpio::new_pin(hal::gpio::DynPinId { + bank: hal::gpio::DynBankId::Bank0, + num: id as u8, + }) + }; + let pin = pin + .try_into_function::() + .ok() + .unwrap(); + assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_set()); + let pin = pin + .try_into_function::() + .ok() + .unwrap(); + assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear()); + let pin = pin + .try_into_function::() + .ok() + .unwrap(); + assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_set()); + let _pin = pin + .try_into_function::() + .ok() + .unwrap(); + assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear()); + } + } +} diff --git a/rp2040-hal/CHANGELOG.md b/rp2040-hal/CHANGELOG.md index 02fa4488b..e0dd1920e 100644 --- a/rp2040-hal/CHANGELOG.md +++ b/rp2040-hal/CHANGELOG.md @@ -18,6 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 more slowly than on the Raspberry Pico. - Some reorganization of ADC code, making sure that AdcPin can only be created for pins that can actually be used as ADC channels. +- Breaking change: Clear the input-enable flag of all pins on bank 0 in `Pins::new`. + They will automatically be enabled when setting a pin function, so most users + won't be affected by that change. Notable exception: If you rely on the fact that + PIO can read all pins as input even if the pin is not configured to the PIO function, + you may need to set the input-enable flag manually. - #755 @jannic ## [0.9.1] diff --git a/rp2040-hal/src/gpio/mod.rs b/rp2040-hal/src/gpio/mod.rs index ee826e882..d8fb75e89 100644 --- a/rp2040-hal/src/gpio/mod.rs +++ b/rp2040-hal/src/gpio/mod.rs @@ -1015,6 +1015,20 @@ pub trait DefaultTypeState: crate::typelevel::Sealed { type PullType: PullType; } +// Clear input enable for pins of bank0. +// Pins 26-29 are ADC pins. If the pins are connected to an analog input, +// the signal level may not be valid for a digital input. Therefore, input +// should be disabled by default. +// For the other GPIO pins, the same setting is applied for consistency. +macro_rules! reset_ie { + ( Bank0, $pads:ident ) => { + for id in (0..=29) { + $pads.gpio(id).modify(|_, w| w.ie().clear_bit()); + } + }; + ( Qspi, $pads:ident ) => {}; +} + macro_rules! gpio { ( $bank:ident:$prefix:ident, [ $(($id:expr, $pull_type:ident, $func:ident)),* ] ) => { paste::paste!{ @@ -1035,8 +1049,10 @@ macro_rules! gpio { impl Pins { /// Take ownership of the PAC peripherals and SIO slice and split it into discrete [`Pin`]s + /// + /// This clears the input-enable flag for all Bank0 pads. pub fn new(io : [], pads: [], sio: [], reset : &mut $crate::pac::RESETS) -> Self { - use crate::resets::SubsystemReset; + use $crate::resets::SubsystemReset; pads.reset_bring_down(reset); io.reset_bring_down(reset); @@ -1055,6 +1071,7 @@ macro_rules! gpio { io.reset_bring_up(reset); pads.reset_bring_up(reset); + reset_ie!($bank, pads); gpio!(members: io, pads, sio, $(([<$prefix $id>], $func, $pull_type)),+) } } diff --git a/rp2040-hal/src/gpio/pin.rs b/rp2040-hal/src/gpio/pin.rs index 0fdaf69ed..1f3689555 100644 --- a/rp2040-hal/src/gpio/pin.rs +++ b/rp2040-hal/src/gpio/pin.rs @@ -153,6 +153,11 @@ pub(crate) fn set_function(pin: &P, function: DynFunction) { DynFunction::Usb => FUNCSEL_A::USB, DynFunction::Null => FUNCSEL_A::NULL, }; + if funcsel != FUNCSEL_A::NULL { + pin.pad_ctrl().modify(|_, w| w.ie().set_bit()); + } else { + pin.pad_ctrl().modify(|_, w| w.ie().clear_bit()); + } pin.io_ctrl().modify(|_, w| w.funcsel().variant(funcsel)); }