Merge pull request #258 from embassy-rs/rp-clocks
rp/gpio: add optional pins
This commit is contained in:
commit
3059923b4f
2 changed files with 87 additions and 21 deletions
|
@ -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<Target = Self> + 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<Target = Self> + 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<AnyPin>`.
|
||||
#[inline]
|
||||
fn degrade_optional(mut self) -> Option<AnyPin> {
|
||||
self.pin_mut()
|
||||
.map(|pin| unsafe { core::ptr::read(pin) }.degrade())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pin> sealed::OptionalPin for T {}
|
||||
impl<T: Pin> 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 {}
|
||||
|
|
|
@ -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<Target = impl ClkPin<T>>,
|
||||
mosi: impl Unborrow<Target = impl MosiPin<T>>,
|
||||
miso: impl Unborrow<Target = impl MisoPin<T>>,
|
||||
cs: impl Unborrow<Target = impl CsPin<T>>,
|
||||
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<u8> for Spi<'d, T> {
|
||||
|
@ -145,10 +150,19 @@ macro_rules! impl_instance {
|
|||
impl_instance!(SPI0, Spi0);
|
||||
impl_instance!(SPI1, Spi1);
|
||||
|
||||
pub trait ClkPin<T: Instance>: sealed::ClkPin<T> + Pin {}
|
||||
pub trait CsPin<T: Instance>: sealed::CsPin<T> + Pin {}
|
||||
pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + Pin {}
|
||||
pub trait MisoPin<T: Instance>: sealed::MisoPin<T> + Pin {}
|
||||
pub trait ClkPin<T: Instance>: sealed::ClkPin<T> + OptionalPin {}
|
||||
pub trait CsPin<T: Instance>: sealed::CsPin<T> + OptionalPin {}
|
||||
pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + OptionalPin {}
|
||||
pub trait MisoPin<T: Instance>: sealed::MisoPin<T> + OptionalPin {}
|
||||
|
||||
impl<T: Instance> sealed::ClkPin<T> for NoPin {}
|
||||
impl<T: Instance> ClkPin<T> for NoPin {}
|
||||
impl<T: Instance> sealed::CsPin<T> for NoPin {}
|
||||
impl<T: Instance> CsPin<T> for NoPin {}
|
||||
impl<T: Instance> sealed::MosiPin<T> for NoPin {}
|
||||
impl<T: Instance> MosiPin<T> for NoPin {}
|
||||
impl<T: Instance> sealed::MisoPin<T> for NoPin {}
|
||||
impl<T: Instance> MisoPin<T> for NoPin {}
|
||||
|
||||
macro_rules! impl_pin {
|
||||
($pin:ident, $instance:ident, $function:ident) => {
|
||||
|
|
Loading…
Reference in a new issue