diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 1eddce18..5edf47f5 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -223,9 +223,11 @@ pub(crate) mod sealed { SIO.gpio_in(self.bank() as _) } } + + pub trait OptionalPin {} } -pub trait Pin: sealed::Pin { +pub trait Pin: Unborrow + sealed::Pin { /// Degrade to a generic pin struct fn degrade(self) -> AnyPin { AnyPin { @@ -245,6 +247,56 @@ impl sealed::Pin for AnyPin { } } +// ========================== + +pub trait OptionalPin: Unborrow + sealed::OptionalPin + Sized { + type Pin: Pin; + fn pin(&self) -> Option<&Self::Pin>; + fn pin_mut(&mut self) -> Option<&mut Self::Pin>; + + /// Convert from concrete pin type PIN_XX to type erased `Option`. + #[inline] + fn degrade_optional(mut self) -> Option { + self.pin_mut() + .map(|pin| unsafe { core::ptr::read(pin) }.degrade()) + } +} + +impl sealed::OptionalPin for T {} +impl OptionalPin for T { + type Pin = T; + + #[inline] + fn pin(&self) -> Option<&T> { + Some(self) + } + + #[inline] + fn pin_mut(&mut self) -> Option<&mut T> { + Some(self) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct NoPin; +unsafe_impl_unborrow!(NoPin); +impl sealed::OptionalPin for NoPin {} +impl OptionalPin for NoPin { + type Pin = AnyPin; + + #[inline] + fn pin(&self) -> Option<&AnyPin> { + None + } + + #[inline] + fn pin_mut(&mut self) -> Option<&mut AnyPin> { + None + } +} + +// ========================== + macro_rules! impl_pin { ($name:ident, $bank:expr, $pin_num:expr) => { impl Pin for peripherals::$name {} diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index fb8e8423..766f0861 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -3,9 +3,10 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; use embedded_hal::blocking::spi as eh; -use gpio::Pin; -use crate::{gpio, pac, peripherals}; +use crate::gpio::sealed::Pin as _; +use crate::gpio::{NoPin, OptionalPin}; +use crate::{pac, peripherals}; #[non_exhaustive] pub struct Config { @@ -31,9 +32,10 @@ impl<'d, T: Instance> Spi<'d, T> { clk: impl Unborrow>, mosi: impl Unborrow>, miso: impl Unborrow>, + cs: impl Unborrow>, config: Config, ) -> Self { - unborrow!(inner, clk, mosi, miso); + unborrow!(inner, clk, mosi, miso, cs); unsafe { let p = inner.regs(); @@ -41,6 +43,8 @@ impl<'d, T: Instance> Spi<'d, T> { let clk_peri = crate::clocks::clk_peri_freq(); assert!(config.frequency <= clk_peri); + // TODO replace these trial-and-error loops with decent calculations. + // Find smallest prescale value which puts output frequency in range of // post-divide. Prescale is an even number from 2 to 254 inclusive. let presc = (2u32..=254).step_by(2).find(|&presc| { @@ -52,7 +56,8 @@ impl<'d, T: Instance> Spi<'d, T> { // Find largest post-divide which makes output <= baudrate. Post-divide is // an integer in the range 1 to 256 inclusive. - let postdiv = (1u32..=256) + // TODO figure what's up with postdiv=1, it is dividing by 0. Iterate down to 2 for now. + let postdiv = (2u32..=256) .rev() .find(|&postdiv| clk_peri / (presc * (postdiv - 1)) > config.frequency); let postdiv = unwrap!(postdiv); @@ -70,9 +75,18 @@ impl<'d, T: Instance> Spi<'d, T> { info!("SPI freq: {=u32}", clk_peri / (presc * postdiv)); - clk.io().ctrl().write(|w| w.set_funcsel(1)); - mosi.io().ctrl().write(|w| w.set_funcsel(1)); - miso.io().ctrl().write(|w| w.set_funcsel(1)); + if let Some(pin) = clk.pin_mut() { + pin.io().ctrl().write(|w| w.set_funcsel(1)); + } + if let Some(pin) = mosi.pin_mut() { + pin.io().ctrl().write(|w| w.set_funcsel(1)); + } + if let Some(pin) = miso.pin_mut() { + pin.io().ctrl().write(|w| w.set_funcsel(1)); + } + if let Some(pin) = cs.pin_mut() { + pin.io().ctrl().write(|w| w.set_funcsel(1)); + } } Self { inner, @@ -97,15 +111,6 @@ impl<'d, T: Instance> Spi<'d, T> { while p.sr().read().bsy() {} } } - - fn drain_rx(&mut self) { - unsafe { - let p = self.inner.regs(); - while !p.sr().read().rne() { - p.dr().read(); - } - } - } } impl<'d, T: Instance> eh::Write for Spi<'d, T> { @@ -145,10 +150,19 @@ macro_rules! impl_instance { impl_instance!(SPI0, Spi0); impl_instance!(SPI1, Spi1); -pub trait ClkPin: sealed::ClkPin + Pin {} -pub trait CsPin: sealed::CsPin + Pin {} -pub trait MosiPin: sealed::MosiPin + Pin {} -pub trait MisoPin: sealed::MisoPin + Pin {} +pub trait ClkPin: sealed::ClkPin + OptionalPin {} +pub trait CsPin: sealed::CsPin + OptionalPin {} +pub trait MosiPin: sealed::MosiPin + OptionalPin {} +pub trait MisoPin: sealed::MisoPin + OptionalPin {} + +impl sealed::ClkPin for NoPin {} +impl ClkPin for NoPin {} +impl sealed::CsPin for NoPin {} +impl CsPin for NoPin {} +impl sealed::MosiPin for NoPin {} +impl MosiPin for NoPin {} +impl sealed::MisoPin for NoPin {} +impl MisoPin for NoPin {} macro_rules! impl_pin { ($pin:ident, $instance:ident, $function:ident) => {