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

Rework GPIO API and fix a few inconsistencies #585

Merged
merged 26 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
02b7702
Leverage typelevel implementation in i2c, pwm (and a little bit in ua…
ithinuel Mar 4, 2023
f4e4dee
Use an enum for core identification
ithinuel May 21, 2023
be0a95d
Overhaul pin modules and related changes.
ithinuel May 16, 2023
c6b8db4
Address first review round from @thejpster.
ithinuel Apr 23, 2023
5706a0b
Add a few inline to enable better optimisation.
ithinuel Apr 23, 2023
2512b10
Expand documentation for the `Adc`
ithinuel Apr 23, 2023
cd1ba03
Refactor the ADC module and remove redundant ts_en.set_bit()
ithinuel Apr 23, 2023
be59518
Spacersssss :) and unicity -> uniqueness
ithinuel Apr 23, 2023
509160a
Add sio bypass when pin is in Sio Function
ithinuel Apr 24, 2023
f7c9bab
Rename `DontInvert` to `Normal`
ithinuel Apr 26, 2023
24b3774
Prevent the creation of multiple instances of TempSensor
ithinuel May 4, 2023
54c9ae1
Add missing updates on on-target-tests
ithinuel May 5, 2023
e2e7ebd
rename `PullBoth` to the more accurate `PullBusKeep`
ithinuel May 8, 2023
f8567f6
Enable dyn-pin to be used with peripherals
ithinuel May 10, 2023
b5f2099
update deprecation notice.
ithinuel May 10, 2023
ff0dc59
Add `try_into_function` for dynpin'ed Pins.
ithinuel May 10, 2023
34c4cda
Fix some doc warnings
ithinuel May 11, 2023
c5d5357
Implement `PinGroup`
ithinuel May 11, 2023
074dde4
Update type-level documentation.
ithinuel May 11, 2023
23e728e
rename `Pin::into()` to `Pin::into_typestate()` to avoid conflicts wi…
ithinuel May 11, 2023
6c101ed
Update rp2040-hal/src/gpio/mod.rs
ithinuel May 12, 2023
4a7b9d6
Remove unused NoneT and fix AnyKind documentation's link
ithinuel May 15, 2023
62af23e
Remove remaining occurences of "into_mode" in examples
ithinuel May 16, 2023
94b1c03
Enhance documentation
ithinuel May 18, 2023
b83633f
doc: fix placeholder names
ithinuel May 20, 2023
5971c03
Rename `into_typestate` to the more explicit `reconfigure`.
ithinuel May 28, 2023
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
14 changes: 9 additions & 5 deletions on-target-tests/tests/dma_spi_loopback_u16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use crate::hal::dma::Channels;
use defmt_rtt as _; // defmt transport
use defmt_test as _;
use hal::gpio::{self, Pin};
use panic_probe as _;
use rp2040_hal as hal; // memory layout // panic handler
use rp2040_hal::pac::SPI0;
Expand All @@ -24,9 +25,12 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
/// if your board has a different frequency
const XTAL_FREQ_HZ: u32 = 12_000_000u32;

type MISO = Pin<gpio::bank0::Gpio4, gpio::FunctionSpi, gpio::PullNone>;
type MOSI = Pin<gpio::bank0::Gpio7, gpio::FunctionSpi, gpio::PullNone>;
type SCLK = Pin<gpio::bank0::Gpio6, gpio::FunctionSpi, gpio::PullNone>;
struct State {
channels: Option<Channels>,
spi: Option<spi::Spi<spi::Enabled, SPI0, 16>>,
spi: Option<spi::Spi<spi::Enabled, SPI0, (MOSI, MISO, SCLK), 16>>,
}

mod testdata {
Expand Down Expand Up @@ -91,10 +95,10 @@ mod tests {
);

// These are implicitly used by the spi driver if they are in the correct mode
let _spi_sclk = pins.gpio6.into_mode::<hal::gpio::FunctionSpi>();
let _spi_mosi = pins.gpio7.into_mode::<hal::gpio::FunctionSpi>();
let _spi_miso = pins.gpio4.into_mode::<hal::gpio::FunctionSpi>();
let spi = hal::spi::Spi::<_, _, 16>::new(pac.SPI0);
let spi_sclk = pins.gpio6.into();
let spi_mosi = pins.gpio7.into();
let spi_miso = pins.gpio4.into();
let spi = hal::spi::Spi::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

// Exchange the uninitialised SPI driver for an initialised one
let spi = spi.init(
Expand Down
14 changes: 9 additions & 5 deletions on-target-tests/tests/dma_spi_loopback_u8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use defmt_rtt as _; // defmt transport
use defmt_test as _;
use panic_probe as _;
use rp2040_hal as hal; // memory layout // panic handler
use rp2040_hal::gpio::{self, Pin};
use rp2040_hal::pac::SPI0;
use rp2040_hal::spi;

Expand All @@ -24,9 +25,12 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
/// if your board has a different frequency
const XTAL_FREQ_HZ: u32 = 12_000_000u32;

type MISO = Pin<gpio::bank0::Gpio4, gpio::FunctionSpi, gpio::PullNone>;
type MOSI = Pin<gpio::bank0::Gpio7, gpio::FunctionSpi, gpio::PullNone>;
type SCLK = Pin<gpio::bank0::Gpio6, gpio::FunctionSpi, gpio::PullNone>;
struct State {
channels: Option<Channels>,
spi: Option<spi::Spi<spi::Enabled, SPI0, 8>>,
spi: Option<spi::Spi<spi::Enabled, SPI0, (MOSI, MISO, SCLK), 8>>,
}

mod testdata {
Expand Down Expand Up @@ -92,10 +96,10 @@ mod tests {
);

// These are implicitly used by the spi driver if they are in the correct mode
let _spi_sclk = pins.gpio6.into_mode::<hal::gpio::FunctionSpi>();
let _spi_mosi = pins.gpio7.into_mode::<hal::gpio::FunctionSpi>();
let _spi_miso = pins.gpio4.into_mode::<hal::gpio::FunctionSpi>();
let spi = hal::spi::Spi::<_, _, 8>::new(pac.SPI0);
let spi_sclk = pins.gpio6.into();
let spi_mosi = pins.gpio7.into();
let spi_miso = pins.gpio4.into();
let spi = hal::spi::Spi::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

// Exchange the uninitialised SPI driver for an initialised one
let spi = spi.init(
Expand Down
21 changes: 17 additions & 4 deletions rp2040-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- multicore: remove the requirement on the closure to never return - #594 @ithinuel
- Updated dependency on rp2040-boot2 to version 0.3.0. - @jannic
- This doubles the flash access speed to the value used by the C SDK by
default. So it should usually be safe. However, if you are overclocking
the RP2040, you might need to lower the flash speed accordingly.
- timer: Make sure clocks are initialized before creating a timer - #618 @jannic
This doubles the flash access speed to the value used by the C SDK by
default. So it should usually be safe. However, if you are overclocking
the RP2040, you might need to lower the flash speed accordingly.
- Doc: Several improvements have been made to documentation: #607 #597
- DMA: Check for valid word sizes at compile time - #600 @jannic
- Use an enum for core identification. - @ithinuel
- Merge DynPin and Pin into Pin. The type class used in Pin now have a runtime variant allowing for
the creation of uniform array of pins (eg: `[Pin<DynPinId, PinFnSio, PullDown>]`). - @ithinuel
- Fix miss defined ValidPinMode bound allowing any Bank0 pin to be Xip and any Qspi pin to be any
other function (except for clock). - @ithinuel
- Use `let _ =` to ignore result rather than `.ok();` as this gives a false sense the result is
checked. - @ithinuel
- Reduce code repetition in i2c modules. - @ithinuel
- Rename `DontInvert` to `Normal`. - @ithinuel
- Prevent the creation of multiple instances of `adc::TempSensor` - @ithinuel

### Added

- timer::Timer implements the embedded-hal delay traits and Copy/Clone - #614 @ithinuel @jannic
- DMA: Allow access to the DMA engine's byteswapping feature - #603 @Gip-Gip
- Added `AdcPin` wrapper to disable digital function for ADC operations - @ithinuel
- Added `Sealed` supertrait to `PIOExt` - @ithinuel
- Added pins to `Spi` to fix inconsistencies in gpio bounds in peripheral (i2c, uart, spi) - @ithinuel
- Added `sio::Sio::read_bank0() -> u32` to provide single instruction multiple io read.

## [0.8.1] - 2023-05-05

Expand Down
2 changes: 2 additions & 0 deletions rp2040-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ defmt = { version = ">=0.2.0, <0.4", optional = true }

rtic-monotonic = { version = "1.0.0", optional = true }

frunk = { version = "0.4.1", default-features = false }

[dev-dependencies]
cortex-m-rt = "0.7"
panic-halt = "0.2.0"
Expand Down
8 changes: 4 additions & 4 deletions rp2040-hal/examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ fn main() -> ! {

// UART TX (characters sent from pico) on pin 1 (GPIO0) and RX (on pin 2 (GPIO1)
let uart_pins = (
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio0.into_function::<hal::gpio::FunctionUart>(),
pins.gpio1.into_function::<hal::gpio::FunctionUart>(),
);

// Create a UART driver
Expand All @@ -107,10 +107,10 @@ fn main() -> ! {
let mut adc = hal::Adc::new(pac.ADC, &mut pac.RESETS);

// Enable the temperature sense channel
let mut temperature_sensor = adc.enable_temp_sensor();
let mut temperature_sensor = adc.take_temp_sensor().unwrap();

// Configure GPIO26 as an ADC input
let mut adc_pin_0 = pins.gpio26.into_floating_input();
let mut adc_pin_0 = hal::adc::AdcPin::new(pins.gpio26);
loop {
// Read the raw ADC counts from the temperature sensor channel.
let temp_sens_adc_counts: u16 = adc.read(&mut temperature_sensor).unwrap();
Expand Down
48 changes: 2 additions & 46 deletions rp2040-hal/examples/dht11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ use rp2040_hal as hal;
use hal::pac;

// Some traits we need
use embedded_hal::digital::v2::InputPin;
use embedded_hal::digital::v2::OutputPin;
use hal::gpio::dynpin::DynPin;
use hal::Clock;

/// The linker will place this boot block at the start of our program image. We
Expand All @@ -43,48 +41,6 @@ const XTAL_FREQ_HZ: u32 = 12_000_000u32;

use dht_sensor::{dht11, DhtReading};

/// A wrapper for DynPin, implementing both InputPin and OutputPin, to simulate
/// an open-drain pin as needed by the wire protocol the DHT11 sensor speaks.
/// https://how2electronics.com/interfacing-dht11-temperature-humidity-sensor-with-raspberry-pi-pico/
struct InOutPin {
inner: DynPin,
}

impl InOutPin {
fn new(inner: DynPin) -> Self {
Self { inner }
}
}

impl InputPin for InOutPin {
type Error = rp2040_hal::gpio::Error;
fn is_high(&self) -> Result<bool, <Self as embedded_hal::digital::v2::InputPin>::Error> {
self.inner.is_high()
}
fn is_low(&self) -> Result<bool, <Self as embedded_hal::digital::v2::InputPin>::Error> {
self.inner.is_low()
}
}

impl OutputPin for InOutPin {
type Error = rp2040_hal::gpio::Error;
fn set_low(&mut self) -> Result<(), <Self as embedded_hal::digital::v2::OutputPin>::Error> {
// To actively pull the pin low, it must also be configured as a (readable) output pin
self.inner.into_readable_output();
// In theory, we should set the pin to low first, to make sure we never actively
// pull it up. But if we try it on the input pin, we get Err(Gpio(InvalidPinType)).
self.inner.set_low()?;
Ok(())
}
fn set_high(&mut self) -> Result<(), <Self as embedded_hal::digital::v2::OutputPin>::Error> {
// To set the open-drain pin to high, just disable the output driver by changing the
// pin to input mode with pull-up. That way, the DHT11 can still pull the data line down
// to send its response.
self.inner.into_pull_up_input();
Ok(())
}
}

/// Entry point to our bare-metal application.
///
/// The `#[rp2040_hal::entry]` macro ensures the Cortex-M start-up code calls this function
Expand Down Expand Up @@ -128,8 +84,8 @@ fn main() -> ! {
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

// Use GPIO 28 as an InOutPin
let mut pin = InOutPin::new(pins.gpio28.into());
pin.set_high().ok();
let mut pin = hal::gpio::InOutPin::new(pins.gpio28);
let _ = pin.set_high();

// Perform a sensor reading
let _measurement = dht11::Reading::read(&mut delay, &mut pin);
Expand Down
10 changes: 5 additions & 5 deletions rp2040-hal/examples/gpio_irq_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ const XTAL_FREQ_HZ: u32 = 12_000_000u32;
// We'll create some type aliases using `type` to help with that

/// This pin will be our output - it will drive an LED if you run this on a Pico
type LedPin = gpio::Pin<gpio::bank0::Gpio25, gpio::PushPullOutput>;
type LedPin = gpio::Pin<gpio::bank0::Gpio25, gpio::FunctionSioOutput, gpio::PullNone>;

/// This pin will be our interrupt source.
/// It will trigger an interrupt if pulled to ground (via a switch or jumper wire)
type ButtonPin = gpio::Pin<gpio::bank0::Gpio26, gpio::PullUpInput>;
type ButtonPin = gpio::Pin<gpio::bank0::Gpio26, gpio::FunctionSioInput, gpio::PullUp>;

/// Since we're always accessing these pins together we'll store them in a tuple.
/// Giving this tuple a type alias means we won't need to use () when putting them
Expand Down Expand Up @@ -119,12 +119,12 @@ fn main() -> ! {
);

// Configure GPIO 25 as an output to drive our LED.
// we can use into_mode() instead of into_pull_up_input()
// we can use reconfigure() instead of into_pull_up_input()
// since the variable we're pushing it into has that type
let led = pins.gpio25.into_mode();
let led = pins.gpio25.reconfigure();

// Set up the GPIO pin that will be our input
let in_pin = pins.gpio26.into_mode();
let in_pin = pins.gpio26.reconfigure();

// Trigger on the 'falling edge' of the input pin.
// This will happen as the button is being pressed
Expand Down
6 changes: 3 additions & 3 deletions rp2040-hal/examples/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ fn main() -> ! {
);

// Configure two pins as being I²C, not GPIO
let sda_pin = pins.gpio18.into_mode::<hal::gpio::FunctionI2C>();
let scl_pin = pins.gpio19.into_mode::<hal::gpio::FunctionI2C>();
// let not_an_scl_pin = pins.gpio20.into_mode::<hal::gpio::FunctionI2C>();
let sda_pin = pins.gpio18.into_function::<hal::gpio::FunctionI2C>();
let scl_pin = pins.gpio19.into_function::<hal::gpio::FunctionI2C>();
// let not_an_scl_pin = pins.gpio20.into_function::<hal::gpio::FunctionI2C>();

// Create the I²C drive, using the two pre-configured pins. This will fail
// at compile time if the pins are in the wrong mode, or if this I²C
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/pio_blink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ fn main() -> ! {
);

// configure LED pin for Pio0.
let _led: Pin<_, FunctionPio0> = pins.gpio25.into_mode();
let led: Pin<_, FunctionPio0, _> = pins.gpio25.into_function();
// PIN id for use inside of PIO
let led_pin_id = 25;
let led_pin_id = led.id().num;

// Define some simple PIO program.
const MAX_DELAY: u8 = 31;
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/pio_dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ fn main() -> ! {
);

// configure LED pin for Pio0.
let _led: Pin<_, FunctionPio0> = pins.gpio25.into_mode();
let led: Pin<_, FunctionPio0, _> = pins.gpio25.into_function();
// PIN id for use inside of PIO
let led_pin_id = 25;
let led_pin_id = led.id().num;

// HELLO WORLD in morse code:
// .... . .-.. .-.. --- / .-- --- .-. .-.. -..
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/pio_proc_blink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ fn main() -> ! {
);

// configure LED pin for Pio0.
let _led: Pin<_, FunctionPio0> = pins.gpio25.into_mode();
let led: Pin<_, FunctionPio0, _> = pins.gpio25.into_function();
// PIN id for use inside of PIO
let led_pin_id = 25;
let led_pin_id = led.id().num;

// Define some simple PIO program.
let program = pio_proc::pio_asm!(
Expand Down
2 changes: 1 addition & 1 deletion rp2040-hal/examples/pio_side_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn main() -> ! {
);

// configure LED pin for Pio0.
let led: Pin<_, FunctionPio0> = pins.gpio25.into_mode();
let led: Pin<_, FunctionPio0, _> = pins.gpio25.into_function();
// PIN id for use inside of PIO
let led_pin_id = led.id().num;

Expand Down
8 changes: 4 additions & 4 deletions rp2040-hal/examples/pio_synchronized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ fn main() -> ! {
);

// configure pins for Pio0.
let _: Pin<_, FunctionPio0> = pins.gpio0.into_mode();
let _: Pin<_, FunctionPio0> = pins.gpio1.into_mode();
let gp0: Pin<_, FunctionPio0, _> = pins.gpio0.into_function();
let gp1: Pin<_, FunctionPio0, _> = pins.gpio1.into_function();

// PIN id for use inside of PIO
let pin0 = 0;
let pin1 = 1;
let pin0 = gp0.id().num;
let pin1 = gp1.id().num;

// Define some simple PIO program.
let program = pio_proc::pio_asm!(
Expand Down
18 changes: 9 additions & 9 deletions rp2040-hal/examples/pwm_irq_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ const XTAL_FREQ_HZ: u32 = 12_000_000u32;
/// We'll create some type aliases using `type` to help with that

/// This pin will be our output - it will drive an LED if you run this on a Pico
type LedPin = gpio::Pin<gpio::bank0::Gpio25, gpio::PushPullOutput>;
type LedPin = gpio::Pin<gpio::bank0::Gpio25, gpio::FunctionSio<gpio::SioOutput>, gpio::PullNone>;

/// This pin will be our input for a 50 Hz servo PWM signal
type InputPwmPin = gpio::Pin<gpio::bank0::Gpio1, gpio::FunctionPwm>;
type InputPwmPin = gpio::Pin<gpio::bank0::Gpio1, gpio::FunctionPwm, gpio::PullNone>;

/// This will be our PWM Slice - it will interpret the PWM signal from the pin
type PwmSlice = pwm::Slice<pwm::Pwm0, pwm::InputHighRunning>;
Expand Down Expand Up @@ -134,17 +134,17 @@ fn main() -> ! {
pwm.enable();

// Connect to GPI O1 as the input to channel B on PWM0
let input_pin = pins.gpio1.reconfigure();
let channel = &mut pwm.channel_b;
let input_pin = channel.input_from(pins.gpio1);
channel.enable();

// Enable an interrupt whenever GPI O1 goes from high to low (the end of a pulse)
input_pin.set_interrupt_enabled(gpio::Interrupt::EdgeLow, true);

// Configure GPIO 25 as an output to drive our LED.
// we can use into_mode() instead of into_pull_up_input()
// we can use reconfigure() instead of into_pull_up_input()
// since the variable we're pushing it into has that type
let led = pins.gpio25.into_mode();
let led = pins.gpio25.reconfigure();

// Give away our pins by moving them into the `GLOBAL_PINS` variable.
// We won't need to access them in the main thread again
Expand Down Expand Up @@ -193,14 +193,14 @@ fn IO_IRQ_BANK0() {
// if the PWM signal indicates low, turn off the LED
if pulse_width_us < LOW_US {
// set_low can't fail, but the embedded-hal traits always allow for it
// we can discard the Result by transforming it to an Option
led.set_low().ok();
// we can discard the Result
let _ = led.set_low();
}
// if the PWM signal indicates low, turn on the LED
else if pulse_width_us > HIGH_US {
// set_high can't fail, but the embedded-hal traits always allow for it
// we can discard the Result by transforming it to an Option
led.set_high().ok();
// we can discard the Result
let _ = led.set_high();
}

// If the PWM signal was in the dead-zone between LOW and HIGH, don't change the LED's
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/rom_funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ fn main() -> ! {

let uart_pins = (
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio0.into_function::<hal::gpio::FunctionUart>(),
// UART RX (characters received by RP2040) on pin 2 (GPIO1)
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio1.into_function::<hal::gpio::FunctionUart>(),
);
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
.enable(
Expand Down
8 changes: 4 additions & 4 deletions rp2040-hal/examples/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ fn main() -> ! {
);

// These are implicitly used by the spi driver if they are in the correct mode
let _spi_sclk = pins.gpio6.into_mode::<hal::gpio::FunctionSpi>();
let _spi_mosi = pins.gpio7.into_mode::<hal::gpio::FunctionSpi>();
let _spi_miso = pins.gpio4.into_mode::<hal::gpio::FunctionSpi>();
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
let spi_mosi = pins.gpio7.into_function::<hal::gpio::FunctionSpi>();
let spi_miso = pins.gpio4.into_function::<hal::gpio::FunctionSpi>();
let spi_sclk = pins.gpio6.into_function::<hal::gpio::FunctionSpi>();
let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

// Exchange the uninitialised SPI driver for an initialised one
let mut spi = spi.init(
Expand Down
Loading