rp/gpio: add optional pins
This commit is contained in:
parent
da014afb89
commit
749f4838d5
@ -223,9 +223,11 @@ pub(crate) mod sealed {
|
|||||||
SIO.gpio_in(self.bank() as _)
|
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
|
/// Degrade to a generic pin struct
|
||||||
fn degrade(self) -> AnyPin {
|
fn degrade(self) -> AnyPin {
|
||||||
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 {
|
macro_rules! impl_pin {
|
||||||
($name:ident, $bank:expr, $pin_num:expr) => {
|
($name:ident, $bank:expr, $pin_num:expr) => {
|
||||||
impl Pin for peripherals::$name {}
|
impl Pin for peripherals::$name {}
|
||||||
|
@ -3,9 +3,10 @@ use core::marker::PhantomData;
|
|||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_extras::unborrow;
|
use embassy_extras::unborrow;
|
||||||
use embedded_hal::blocking::spi as eh;
|
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]
|
#[non_exhaustive]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -31,9 +32,10 @@ impl<'d, T: Instance> Spi<'d, T> {
|
|||||||
clk: impl Unborrow<Target = impl ClkPin<T>>,
|
clk: impl Unborrow<Target = impl ClkPin<T>>,
|
||||||
mosi: impl Unborrow<Target = impl MosiPin<T>>,
|
mosi: impl Unborrow<Target = impl MosiPin<T>>,
|
||||||
miso: impl Unborrow<Target = impl MisoPin<T>>,
|
miso: impl Unborrow<Target = impl MisoPin<T>>,
|
||||||
|
cs: impl Unborrow<Target = impl CsPin<T>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
unborrow!(inner, clk, mosi, miso);
|
unborrow!(inner, clk, mosi, miso, cs);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let p = inner.regs();
|
let p = inner.regs();
|
||||||
@ -41,6 +43,8 @@ impl<'d, T: Instance> Spi<'d, T> {
|
|||||||
let clk_peri = crate::clocks::clk_peri_freq();
|
let clk_peri = crate::clocks::clk_peri_freq();
|
||||||
assert!(config.frequency <= clk_peri);
|
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
|
// Find smallest prescale value which puts output frequency in range of
|
||||||
// post-divide. Prescale is an even number from 2 to 254 inclusive.
|
// post-divide. Prescale is an even number from 2 to 254 inclusive.
|
||||||
let presc = (2u32..=254).step_by(2).find(|&presc| {
|
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
|
// Find largest post-divide which makes output <= baudrate. Post-divide is
|
||||||
// an integer in the range 1 to 256 inclusive.
|
// 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()
|
.rev()
|
||||||
.find(|&postdiv| clk_peri / (presc * (postdiv - 1)) > config.frequency);
|
.find(|&postdiv| clk_peri / (presc * (postdiv - 1)) > config.frequency);
|
||||||
let postdiv = unwrap!(postdiv);
|
let postdiv = unwrap!(postdiv);
|
||||||
@ -70,9 +75,18 @@ impl<'d, T: Instance> Spi<'d, T> {
|
|||||||
|
|
||||||
info!("SPI freq: {=u32}", clk_peri / (presc * postdiv));
|
info!("SPI freq: {=u32}", clk_peri / (presc * postdiv));
|
||||||
|
|
||||||
clk.io().ctrl().write(|w| w.set_funcsel(1));
|
if let Some(pin) = clk.pin_mut() {
|
||||||
mosi.io().ctrl().write(|w| w.set_funcsel(1));
|
pin.io().ctrl().write(|w| w.set_funcsel(1));
|
||||||
miso.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 {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
@ -97,15 +111,6 @@ impl<'d, T: Instance> Spi<'d, T> {
|
|||||||
while p.sr().read().bsy() {}
|
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> {
|
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!(SPI0, Spi0);
|
||||||
impl_instance!(SPI1, Spi1);
|
impl_instance!(SPI1, Spi1);
|
||||||
|
|
||||||
pub trait ClkPin<T: Instance>: sealed::ClkPin<T> + Pin {}
|
pub trait ClkPin<T: Instance>: sealed::ClkPin<T> + OptionalPin {}
|
||||||
pub trait CsPin<T: Instance>: sealed::CsPin<T> + Pin {}
|
pub trait CsPin<T: Instance>: sealed::CsPin<T> + OptionalPin {}
|
||||||
pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + Pin {}
|
pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + OptionalPin {}
|
||||||
pub trait MisoPin<T: Instance>: sealed::MisoPin<T> + Pin {}
|
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 {
|
macro_rules! impl_pin {
|
||||||
($pin:ident, $instance:ident, $function:ident) => {
|
($pin:ident, $instance:ident, $function:ident) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user