Skip to content

Commit

Permalink
Refactor spi modules to improve structure
Browse files Browse the repository at this point in the history
Make several improvements to the `sercom::v2::spi` module:
- Introduce a `Registers` type that acts as a task-focused API for the
  registers, as opposed to the register-focused API of the PAC. This
  abstraction also serves to remove interior mutability of the PAC
  struct and lets us implement `Sync` for `Registers`
- Add a `Capability` trait and three corresponding types: `Rx`, `Tx` and
  `Duplex`. Add a `Capability` type parameter to the `Spi` struct and
  use it to differentiate the various embedded HAL trait
  implementations. This is a better solution than the previous approach,
  which was a set of marker traits implemented on `Pads` types.
- Combine the `thumbv6m` and `thumbv7em` modules to reuse more code. The
  major differences between the two chips come in the `Pads` type, and
  the `Length` and `CharSize` types. Introduce a `Size` trait that
  essentially acts a trait alias for either `Length` or `CharSize`.
  Split up the modules and use conditional imports to handle everything
  correctly for the three different chips.

Because the `spi` module is no longer split between the two
chip-specific modules, also consolidate the `impl_pad` modules as well.

Finally, improve the documentation for the `spi` module itself, as well
as for the embedded HAL trait implementations.
  • Loading branch information
bradleyharden committed Jul 25, 2021
1 parent 0c39af6 commit 8fc3a97
Show file tree
Hide file tree
Showing 23 changed files with 4,050 additions and 4,180 deletions.
2 changes: 1 addition & 1 deletion boards/feather_m0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ pub type SpiPads = spi::Pads<Sercom4, Miso, Mosi, Sclk>;
/// SPI master for the labelled SPI peripheral
///
/// This type implements [`FullDuplex<u8>`](ehal::spi::FullDuplex).
pub type Spi = spi::Spi<spi::Config<SpiPads>>;
pub type Spi = spi::Spi<spi::Config<SpiPads>, spi::Duplex>;

/// Convenience for setting up the labelled SPI peripheral.
/// This powers up SERCOM4 and configures it for use as an
Expand Down
4 changes: 2 additions & 2 deletions boards/p1am_100/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ const BASE_CONTROLLER_SPI_MODE: embedded_hal::spi::Mode = spi::MODE_2;

pub type Spi0Pads = spi::Pads<Sercom1, Spi0Miso, Spi0Mosi, Spi0Sck>;

pub type Spi0 = spi::Spi<spi::Config<Spi0Pads>>;
pub type Spi0 = spi::Spi<spi::Config<Spi0Pads>, spi::Duplex>;

/// Convenience for setting up the labeled SPI0 peripheral.
/// SPI0 has the P1AM base controller connected.
Expand All @@ -228,7 +228,7 @@ pub fn base_controller_spi(

type SdPads = spi::Pads<Sercom2, SdMiso, SdMosi, SdSck>;

pub type SdSpi = spi::Spi<spi::Config<SdPads>>;
pub type SdSpi = spi::Spi<spi::Config<SdPads>, spi::Duplex>;

/// Convenience for setting up the labeled SPI2 peripheral.
/// SPI2 has the microSD card slot connected.
Expand Down
4 changes: 2 additions & 2 deletions boards/pygamer/src/pins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ pub struct Display {
}

pub type TftPads = spi::Pads<Sercom4, IoSet1, NoneT, TftMosi, TftSclk>;
pub type TftSpi = spi::Spi<spi::Config<TftPads>>;
pub type TftSpi = spi::Spi<spi::Config<TftPads>, spi::Tx>;

#[cfg(feature = "unproven")]
impl Display {
Expand Down Expand Up @@ -658,7 +658,7 @@ pub struct SPI {
pub type SpiPads = spi::Pads<Sercom1, UndocIoSet1, SpiMiso, SpiMosi, SpiSclk>;

/// SPI master for the labelled pins
pub type Spi = spi::Spi<spi::Config<SpiPads>>;
pub type Spi = spi::Spi<spi::Config<SpiPads>, spi::Duplex>;

impl SPI {
/// Convenience for setting up the labelled pins to operate
Expand Down
7 changes: 4 additions & 3 deletions boards/wio_terminal/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use atsamd_hal::gpio::*;
use atsamd_hal::hal::blocking::delay::DelayMs;
use atsamd_hal::hal::spi::{Phase, Polarity};
use atsamd_hal::prelude::*;
use atsamd_hal::sercom::v2::spi::{self, Spi};
use atsamd_hal::sercom::v2::spi;
use atsamd_hal::sercom::v2::{IoSet4, Sercom7};
use atsamd_hal::target_device::{MCLK, SERCOM7};
use atsamd_hal::time::Hertz;
Expand Down Expand Up @@ -36,11 +36,12 @@ pub struct Display {
pub backlight: Pc5<Input<Floating>>,
}

pub type SpiPads = spi::PadsFromIds<Sercom7, IoSet4, NoneT, PB19, PB20>;
pub type LcdPads = spi::PadsFromIds<Sercom7, IoSet4, NoneT, PB19, PB20>;
pub type LcdSpi = spi::Spi<spi::Config<LcdPads>, spi::Tx>;

/// Type alias for the ILI9341 LCD display.
pub type LCD = Ili9341<
SPIInterface<Spi<spi::Config<SpiPads>>, Pc6<Output<PushPull>>, Pb21<Output<PushPull>>>,
SPIInterface<LcdSpi, Pc6<Output<PushPull>>, Pb21<Output<PushPull>>>,
Pc7<Output<PushPull>>,
>;

Expand Down
9 changes: 3 additions & 6 deletions hal/src/sercom/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,16 @@ use pac::{SERCOM4, SERCOM5};
#[cfg(feature = "min-samd51n")]
use pac::{SERCOM6, SERCOM7};

#[cfg(any(feature = "samd11", feature = "samd21"))]
pub use crate::common::thumbv6m::sercom::v2::*;

#[cfg(feature = "min-samd51g")]
pub use crate::common::thumbv7em::sercom::v2::*;

#[cfg(feature = "dma")]
use crate::common::dmac::TriggerSource;

use crate::typelevel::Sealed;

pub mod pad;
pub use pad::*;

pub mod spi;

pub mod spi_future;

//==============================================================================
Expand Down
106 changes: 59 additions & 47 deletions hal/src/sercom/v2/pad.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Define a SERCOM pad type
//! Type-level tools to configure SERCOM pads
//!
//! This module helps configure [`Pin`]s as SERCOM pads. It provides type-level
//! tools to convert `Pin`s to the correct [`PinMode`] and to enforce type-level
Expand Down Expand Up @@ -48,6 +48,14 @@ use crate::gpio::v2::OptionalPinId;
use crate::gpio::v2::{AnyPin, OptionalPin, Pin, PinId, PinMode};
use crate::typelevel::{NoneT, Sealed};

#[cfg(any(feature = "samd11", feature = "samd21"))]
#[path = "pad/impl_pad_thumbv6m.rs"]
mod impl_pad;

#[cfg(feature = "min-samd51g")]
#[path = "pad/impl_pad_thumbv7em.rs"]
mod impl_pad;

//==============================================================================
// PadNum
//==============================================================================
Expand Down Expand Up @@ -252,53 +260,57 @@ where
// IoSet
//==============================================================================

/// Type-level enum representing a SERCOM IOSET
///
/// See the [type-level enum] documentation for more details on the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
#[cfg(feature = "min-samd51g")]
pub trait IoSet: Sealed {}

#[cfg(feature = "min-samd51g")]
seq!(N in 1..=6 {
paste! {
#[doc = "Type-level variant of [`IoSet`] representing SERCOM IOSET " N]
///
/// See the [type-level enum] documentation for more details on the
/// pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum IoSet#N {}
impl Sealed for IoSet#N {}
impl IoSet for IoSet#N {}
mod ioset {

use super::*;

/// Type-level enum representing a SERCOM IOSET
///
/// See the [type-level enum] documentation for more details on the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub trait IoSet: Sealed {}

seq!(N in 1..=6 {
paste! {
#[doc = "Type-level variant of [`IoSet`] representing SERCOM IOSET " N]
///
/// See the [type-level enum] documentation for more details on the
/// pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum IoSet#N {}
impl Sealed for IoSet#N {}
impl IoSet for IoSet#N {}
}
});

/// Type-level variant of [`IoSet`] representing an undocumented SERCOM
/// IOSET
///
/// See the [type-level enum] documentation for more details on the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum UndocIoSet1 {}
impl Sealed for UndocIoSet1 {}
impl IoSet for UndocIoSet1 {}

/// Type class for SERCOM pads in a given [`IoSet`]
///
/// This trait is used to label each [`Pin`] implementing [`IsPad`] with its
/// corresponding [`IoSet`]\(s). Downstream types can use this trait as a
/// [type class] to restrict [`Pin`]s to a given [`IoSet`]. See the [type
/// class] documentation for more details on the pattern.
///
/// [type class]: crate::typelevel#type-classes
pub trait InIoSet<I>
where
Self: IsPad,
I: IoSet,
{
}
});

/// Type-level variant of [`IoSet`] representing an undocumented SERCOM IOSET
///
/// See the [type-level enum] documentation for more details on the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
#[cfg(feature = "min-samd51g")]
pub enum UndocIoSet1 {}
#[cfg(feature = "min-samd51g")]
impl Sealed for UndocIoSet1 {}
#[cfg(feature = "min-samd51g")]
impl IoSet for UndocIoSet1 {}
}

/// Type class for SERCOM pads in a given [`IoSet`]
///
/// This trait is used to label each [`Pin`] implementing [`IsPad`] with its
/// corresponding [`IoSet`]\(s). Downstream types can use this trait as a
/// [type class] to restrict [`Pin`]s to a given [`IoSet`]. See the [type class]
/// documentation for more details on the pattern.
///
/// [type class]: crate::typelevel#type-classes
#[cfg(feature = "min-samd51g")]
pub trait InIoSet<I>
where
Self: IsPad,
I: IoSet,
{
}
pub use ioset::*;
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 8fc3a97

Please sign in to comment.