Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn off input_enable for ADC capable pins #755

Merged
merged 5 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions on-target-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
103 changes: 103 additions & 0 deletions on-target-tests/tests/gpio.rs
Original file line number Diff line number Diff line change
@@ -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::<hal::gpio::FunctionSioInput>()
.ok()
.unwrap();
assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_set());
let pin = pin
.try_into_function::<hal::gpio::FunctionNull>()
.ok()
.unwrap();
assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear());
let pin = pin
.try_into_function::<hal::gpio::FunctionPio0>()
.ok()
.unwrap();
assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_set());
let _pin = pin
.try_into_function::<hal::gpio::FunctionNull>()
.ok()
.unwrap();
assert!(pac.PADS_BANK0.gpio(id).read().ie().bit_is_clear());
}
}
}
5 changes: 5 additions & 0 deletions rp2040-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
19 changes: 18 additions & 1 deletion rp2040-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!{
Expand All @@ -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 : [<IO_ $bank:upper>], pads: [<PADS_ $bank:upper>], sio: [<SioGpio $bank>], reset : &mut $crate::pac::RESETS) -> Self {
use crate::resets::SubsystemReset;
use $crate::resets::SubsystemReset;
pads.reset_bring_down(reset);
io.reset_bring_down(reset);

Expand All @@ -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)),+)
}
}
Expand Down
5 changes: 5 additions & 0 deletions rp2040-hal/src/gpio/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ pub(crate) fn set_function<P: PinId>(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));
}
Expand Down
Loading