Skip to content

Commit

Permalink
Leverage typelevel implementation in i2c, pwm (and a little bit in ua…
Browse files Browse the repository at this point in the history
…rt).

This notably makes the documentation more readable.
  • Loading branch information
ithinuel committed Mar 4, 2023
1 parent aaa306f commit ae59170
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 252 deletions.
4 changes: 2 additions & 2 deletions rp2040-hal/examples/uart.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_mode(),
// UART RX (characters received by RP2040) on pin 2 (GPIO1)
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio1.into_mode(),
);
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
.enable(
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/uart_dma.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_mode(),
// UART RX (characters received by RP2040) on pin 2 (GPIO1)
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
pins.gpio1.into_mode(),
);
let uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
.enable(
Expand Down
56 changes: 21 additions & 35 deletions rp2040-hal/src/gpio/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,8 @@ use eh1_0_alpha::digital as eh1;
pub use embedded_hal::digital::v2::PinState;
use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};

use core::mem::transmute;

/// Type-level marker for tracking which pin modes are valid for which pins
pub trait ValidPinMode<I: PinId>: Sealed {}
pub trait ValidPinMode<I: PinId>: Sealed + PinMode {}

//==============================================================================
// Disabled configurations
Expand Down Expand Up @@ -437,7 +435,7 @@ impl<I: PinId> Registers<I> {
/// Provide a type-level equivalent for the
/// [`RegisterInterface::change_mode`] method.
#[inline]
fn change_mode<M: PinMode + ValidPinMode<I>>(&mut self) {
fn change_mode<M: ValidPinMode<I>>(&mut self) {
RegisterInterface::do_change_mode(self, M::DYN);
}
}
Expand All @@ -450,7 +448,7 @@ impl<I: PinId> Registers<I> {
pub struct Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
M: ValidPinMode<I>,
{
regs: Registers<I>,
mode: PhantomData<M>,
Expand All @@ -459,7 +457,7 @@ where
impl<I, M> Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
M: ValidPinMode<I>,
{
/// Create a new [`Pin`]
///
Expand All @@ -483,7 +481,7 @@ where
///
/// ```no_run
/// # use rp2040_hal::gpio::{Pin, PinId, PinMode, ValidPinMode};
/// # fn get_id<I: PinId, M: PinMode + ValidPinMode<I>> (pin: Pin<I, M>) -> u8 {
/// # fn get_id<I: PinId, M: ValidPinMode<I>> (pin: Pin<I, M>) -> u8 {
/// pin.id().num
/// # }
/// ````
Expand All @@ -494,7 +492,7 @@ where

/// Convert the pin to the requested [`PinMode`]
#[inline]
pub fn into_mode<N: PinMode + ValidPinMode<I>>(mut self) -> Pin<I, N> {
pub fn into_mode<N: ValidPinMode<I>>(mut self) -> Pin<I, N> {
if N::DYN != M::DYN {
self.regs.change_mode::<N>();
}
Expand Down Expand Up @@ -733,14 +731,14 @@ where
impl<I, M> Sealed for Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
M: ValidPinMode<I>,
{
}

impl<I, M> AnyPin for Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
M: ValidPinMode<I>,
{
type Id = I;
type Mode = M;
Expand All @@ -754,28 +752,6 @@ where
/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
pub type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;

impl<P: AnyPin> AsRef<P> for SpecificPin<P> {
#[inline]
fn as_ref(&self) -> &P {
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
// Transmuting between `v1` and `v2` `Pin` types is also safe, because
// both are zero-sized, and single-field, newtype structs are guaranteed
// to have the same layout as the field anyway, even for repr(Rust).
unsafe { transmute(self) }
}
}

impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
#[inline]
fn as_mut(&mut self) -> &mut P {
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
// Transmuting between `v1` and `v2` `Pin` types is also safe, because
// both are zero-sized, and single-field, newtype structs are guaranteed
// to have the same layout as the field anyway, ValidPinMode<P::Id> en for repr(Rust).
unsafe { transmute(self) }
}
}

//==============================================================================
// Optional pins
//==============================================================================
Expand All @@ -788,23 +764,33 @@ impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
pub trait OptionalPin: Sealed {
#[allow(missing_docs)]
type Id: OptionalPinId;
#[allow(missing_docs)]
const IS_NONE: bool;
}

impl OptionalPin for NoneT {
type Id = NoneT;
const IS_NONE: bool = true;
}

impl<P: AnyPin> OptionalPin for P {
type Id = P::Id;
/// Value-level translation of the Type-level equivalent of [`Option::is_none`].
const IS_NONE: bool = false;
}

/// Type-level equivalent of `Some(PinId)`
///
/// See the [`OptionalKind`] documentation for more details on the pattern.
///
/// [`OptionalKind`]: crate::typelevel#optionalkind-trait-pattern
pub trait SomePin: AnyPin + Sealed {}
impl<P: AnyPin> SomePin for P {}
pub trait SomePin: OptionalPin + Sealed {
/// Value-level translation of the Type-level equivalent of [`Option::is_some`].
const IS_SOME: bool;
}
impl<P: OptionalPin> SomePin for P {
const IS_SOME: bool = !P::IS_NONE;
}

//==============================================================================
// Embedded HAL traits
Expand Down Expand Up @@ -1048,7 +1034,7 @@ macro_rules! gpio {
}
}

$( impl<I: PinId + BankPinId> super::ValidPinMode<I> for super::[<Function $Func>] {} )+
$( impl<I: PinId> super::ValidPinMode<I> for super::[<Function $Func>] {} )+
}
}
}
Expand Down
33 changes: 15 additions & 18 deletions rp2040-hal/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ use core::{marker::PhantomData, ops::Deref};

use crate::{
gpio::pin::bank0::{
BankPinId, Gpio0, Gpio1, Gpio10, Gpio11, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17,
Gpio18, Gpio19, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio24, Gpio25, Gpio26, Gpio27,
Gpio28, Gpio29, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8, Gpio9,
Gpio0, Gpio1, Gpio10, Gpio11, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17, Gpio18,
Gpio19, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio24, Gpio25, Gpio26, Gpio27, Gpio28,
Gpio29, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8, Gpio9,
},
gpio::pin::{FunctionI2C, Pin, PinId},
gpio::pin::{AnyPin, FunctionI2C},
resets::SubsystemReset,
typelevel::Sealed,
};
Expand Down Expand Up @@ -223,19 +223,13 @@ fn i2c_reserved_addr(addr: u16) -> bool {
(addr & 0x78) == 0 || (addr & 0x78) == 0x78
}

impl<Block, Sda, Scl, Mode> I2C<Block, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Mode>
impl<Block, Sda, Scl, Mode> I2C<Block, (Sda, Scl), Mode>
where
Block: SubsystemReset + Deref<Target = I2CBlock>,
Sda: PinId + BankPinId,
Scl: PinId + BankPinId,
Mode: I2CMode,
{
/// Releases the I2C peripheral and associated pins
#[allow(clippy::type_complexity)]
pub fn free(
self,
resets: &mut RESETS,
) -> (Block, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>)) {
pub fn free(self, resets: &mut RESETS) -> (Block, (Sda, Scl)) {
self.i2c.reset_bring_down(resets);

(self.i2c, self.pins)
Expand Down Expand Up @@ -283,20 +277,23 @@ impl<Block: Deref<Target = I2CBlock>, PINS, Mode> I2C<Block, PINS, Mode> {
macro_rules! hal {
($($I2CX:ident: ($i2cX:ident),)+) => {
$(
impl<Sda: PinId + BankPinId, Scl: PinId + BankPinId>
I2C<$I2CX, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>)> {
impl<Sda, Scl> I2C<$I2CX, (Sda, Scl)>
where
Sda: AnyPin<Mode = FunctionI2C>,
Scl: AnyPin<Mode = FunctionI2C>,
{
/// Configures the I2C peripheral to work in master mode
pub fn $i2cX<F, SystemF>(
i2c: $I2CX,
sda_pin: Pin<Sda, FunctionI2C>,
scl_pin: Pin<Scl, FunctionI2C>,
sda_pin: Sda,
scl_pin: Scl,
freq: F,
resets: &mut RESETS,
system_clock: SystemF) -> Self
where
F: Into<HertzU32>,
Sda: SdaPin<$I2CX>,
Scl: SclPin<$I2CX>,
Sda::Id: SdaPin<$I2CX>,
Scl::Id: SclPin<$I2CX>,
SystemF: Into<HertzU32>,
{
Self::new_controller(i2c, sda_pin, scl_pin, freq.into(), resets, system_clock.into())
Expand Down
22 changes: 11 additions & 11 deletions rp2040-hal/src/i2c/controller.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use core::{marker::PhantomData, ops::Deref};

use crate::{
gpio::pin::bank0::BankPinId,
gpio::pin::{FunctionI2C, Pin, PinId},
gpio::{pin::FunctionI2C, AnyPin},
resets::SubsystemReset,
};
use fugit::HertzU32;
Expand All @@ -14,22 +13,23 @@ use eh1_0_alpha::i2c as eh1;

use super::{i2c_reserved_addr, Controller, Error, SclPin, SdaPin, I2C};

impl<T: SubsystemReset + Deref<Target = Block>, Sda: PinId + BankPinId, Scl: PinId + BankPinId>
I2C<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Controller>
impl<T, Sda, Scl> I2C<T, (Sda, Scl), Controller>
where
T: SubsystemReset + Deref<Target = Block>,
Sda: AnyPin<Mode = FunctionI2C>,
Scl: AnyPin<Mode = FunctionI2C>,
Sda::Id: SdaPin<T>,
Scl::Id: SclPin<T>,
{
/// Configures the I2C peripheral to work in controller mode
pub fn new_controller(
i2c: T,
sda_pin: Pin<Sda, FunctionI2C>,
scl_pin: Pin<Scl, FunctionI2C>,
sda_pin: Sda,
scl_pin: Scl,
freq: HertzU32,
resets: &mut RESETS,
system_clock: HertzU32,
) -> Self
where
Sda: SdaPin<T>,
Scl: SclPin<T>,
{
) -> Self {
let freq = freq.to_Hz();
assert!(freq <= 1_000_000);
assert!(freq > 0);
Expand Down
31 changes: 11 additions & 20 deletions rp2040-hal/src/i2c/peripheral.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use core::{marker::PhantomData, ops::Deref};

use crate::{
gpio::pin::bank0::BankPinId,
gpio::pin::{FunctionI2C, Pin, PinId},
gpio::{pin::FunctionI2C, AnyPin},
resets::SubsystemReset,
};
use pac::{i2c0::RegisterBlock as I2CBlock, RESETS};
Expand Down Expand Up @@ -38,27 +37,25 @@ pub struct I2CPeripheralEventIterator<Block, Pins> {
state: State,
}

impl<T, Sda, Scl> I2C<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>), Peripheral>
impl<T, Sda, Scl> I2C<T, (Sda, Scl), Peripheral>
where
T: SubsystemReset + Deref<Target = I2CBlock>,
Sda: PinId + BankPinId,
Scl: PinId + BankPinId,
Sda: AnyPin<Mode = FunctionI2C>,
Scl: AnyPin<Mode = FunctionI2C>,
Sda::Id: SdaPin<T>,
Scl::Id: SclPin<T>,
{
/// Configures the I2C peripheral to work in peripheral mode
///
/// The bus *MUST* be idle when this method is called.
#[allow(clippy::type_complexity)]
pub fn new_peripheral_event_iterator(
i2c: T,
sda_pin: Pin<Sda, FunctionI2C>,
scl_pin: Pin<Scl, FunctionI2C>,
sda_pin: Sda,
scl_pin: Scl,
resets: &mut RESETS,
addr: u16,
) -> I2CPeripheralEventIterator<T, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>)>
where
Sda: SdaPin<T>,
Scl: SclPin<T>,
{
) -> I2CPeripheralEventIterator<T, (Sda, Scl)> {
i2c.reset_bring_down(resets);
i2c.reset_bring_up(resets);

Expand Down Expand Up @@ -184,19 +181,13 @@ impl<T: Deref<Target = I2CBlock>, PINS> Iterator for I2CPeripheralEventIterator<
}
}

impl<Block, Sda, Scl>
I2CPeripheralEventIterator<Block, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>)>
impl<Block, Sda, Scl> I2CPeripheralEventIterator<Block, (Sda, Scl)>
where
Block: SubsystemReset + Deref<Target = I2CBlock>,
Sda: PinId + BankPinId,
Scl: PinId + BankPinId,
{
/// Releases the I2C peripheral and associated pins
#[allow(clippy::type_complexity)]
pub fn free(
self,
resets: &mut RESETS,
) -> (Block, (Pin<Sda, FunctionI2C>, Pin<Scl, FunctionI2C>)) {
pub fn free(self, resets: &mut RESETS) -> (Block, (Sda, Scl)) {
self.i2c.free(resets)
}
}
Loading

0 comments on commit ae59170

Please sign in to comment.