Module serpente::sercom::v2::spi[][src]

Expand description

Use the SERCOM peripheral for SPI transactions

Configuring an SPI peripheral occurs in three steps. First, you must create a set of Pads for use by the peripheral. Next, you assemble pieces into a Config struct. After configuring the peripheral, you then enable it, yielding a functional Spi struct. Transactions are performed using the spi and serial traits from embedded HAL.

Pads

A Sercom can use up to four Pins as configured as SERCOM pads, but only certain Pin combinations are acceptable. In particular, all Pins must be mapped to the same Sercom (see the datasheet). This HAL makes it impossible to use invalid Pin combinations, and the Pads struct is responsible for enforcing these constraints.

A Pads type takes five type parameters. The first specifies the Sercom, while the remaining four, DI, DO, CK and SS, represent the Data In, Data Out, Sclk and SS pads respectively. Each of the remaining type parameters is an OptionalPad and defaults to NoneT. Aliases defining the pad types can be provided by the bsp_pins! macro.

use atsamd_hal::gpio::v2::{PA08, PA09, AlternateC, AlternateD};
use atsamd_hal::sercom::v2::{Sercom0, spi};
use atsamd_hal::typelevel::NoneT;

type Miso = Pin<PA08, AlternateC>;
type Sclk = Pin<PA09, AlternateC>;
type Pads = spi::Pads<Sercom0, Miso, NoneT, Sclk>;

Alternatively, you can use the PadsFromIds alias to define a set of Pads in terms of PinIds instead of Pins. This is useful when you don’t have Pin aliases pre-defined.

use atsamd_hal::gpio::v2::{PA08, PA09};
use atsamd_hal::sercom::v2::{Sercom0, spi};
use atsamd_hal::typelevel::NoneT;

type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;

Instaces of Pads are created using the builder pattern. Start by creating an empty set of Pads using Default. Then pass each respective Pin using the corresponding methods. Both v1::Pin and v2::Pin types are accepted here.

On SAMD21 chips, the builder methods automatically convert each pin to the correct PinMode. But for SAMD11 chips, users must manually convert each pin before calling the builder methods. This is a consequence of inherent ambiguities in the SAMD11 SERCOM pad definitions. Specifically, the same PinId can correspond to two different PadNums for the same Sercom.

use atsamd_hal::pac::Peripherals;
use atsamd_hal::gpio::v2::Pins;
use atsamd_hal::sercom::v2::{Sercom0, spi};

let mut peripherals = Peripherals::take().unwrap();
let pins = Pins::new(peripherals.PORT);
let pads = spi::Pads::<Sercom0>::default()
    .sclk(pins.pa09)
    .data_in(pins.pa08)
    .data_out(pins.pa11);

To be accepted as ValidPads, a set of Pads must do two things:

  • Specify a type for CK and at least one of DI or DO
  • Satisfy the DipoDopo trait

Config

Next, create a Config struct, which represents the SPI peripheral in its disabled state. A Config is specified with three type parameters: the Pads type; an OpMode, which defaults to Master; and a CharSize, which defaults to EightBit.

use atsamd_hal::gpio::v2::{PA08, PA09};
use atsamd_hal::sercom::v2::{Sercom0, spi};
use atsamd_hal::sercom::v2::spi::{Master, NineBit};
use atsamd_hal::typelevel::NoneT;

type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
type Config = spi::Config<Pads, Master, NineBit>;

Upon creation, the Config takes ownership of both the Pads struct and the PAC Sercom struct. It takes a reference to the PM, so that it can enable the APB clock, and it takes a frequency to indicate the GCLK configuration. Users are responsible for correctly configuring the GCLK.

use atsamd_hal::time::U32Ext;

let pm = peripherals.PM;
let sercom = peripherals.SERCOM0;
// Configure GCLK for 10 MHz
let freq = 10.mhz();
let config = spi::Config::new(&pm, sercom, pads, freq);

The Config struct uses the builder pattern to configure the peripheral, ending with a call to enable, which consumes the Config and returns an enabled Spi peripheral.

use embedded_hal::spi::MODE_1;
use atsamd_hal::sercom::v2::spi::NineBit;

let spi = spi::Config::new(&mclk, sercom, pads, freq)
    .baud(1.mhz())
    .char_size::<NineBit>()
    .msb_first(false)
    .spi_mode(MODE_1)
    .enable();

To be accepted as a ValidConfig, the Config must have all the necessary pads for its OpMode.

Spi

An Spi struct can only be created from a ValidConfig, and it has only one type parameter, the corresponding Configuration.

use atsamd_hal::gpio::v2::{PA08, PA09};
use atsamd_hal::sercom::v2::{Sercom0, spi};
use atsamd_hal::sercom::v2::spi::{Master, NineBit};
use atsamd_hal::typelevel::NoneT;

// Assuming SAMD21
type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
type Config = spi::Config<Pads, Master, NineBit>;
type Spi = spi::Spi<Config>;

Only the Spi struct can actually perform transactions. To do so, use the embedded HAL traits, like spi::FullDuplex, serial::Read and serial::Write. See the Spi documentation for more information about the trait implementations, which vary based on the CharSize and Pads. For instance, FullDuplex is only implemented if the Pads are both Tx and Rx, and its word size varies between u8 and u16, depending on CharSize.

use nb::block;
use embedded_hal::spi::FullDuplex;

block!(spi.send(0x0155));
let rcvd: u16 = block!(spi.read());

Structs

A configurable, disabled SPI peripheral

Error bit flags for SPI transactions

Interrupt bit flags for SPI transactions

Container for a set of SERCOM pads

An enabled SPI peripheral that can perform transactions using the embedded HAL traits

Enums

CharSize variant for 8-bit transactions

Error enum for SPI transactions

OpMode variant for Master mode

OpMode variant for Master mode with hardware-controlled slave select

CharSize variant for 9-bit transactions

Clock phase

Clock polarity

OpMode variant for Slave mode

Constants

Helper for CPOL = 0, CPHA = 0

Helper for CPOL = 0, CPHA = 1

Helper for CPOL = 1, CPHA = 0

Helper for CPOL = 1, CPHA = 1

Traits

Type class for all possible Config types

Type class for all possible Spi types

Type-level enum representing the SPI character size

Configure the DIPO and DOPO fields based on a set of Pads

Marker trait for Master operating modes

Marker trait for a set of Pads that cannot receive

Marker trait for a set of Pads that cannot transmit

Type-level enum representing the SPI operating mode

Type-level function to recover the OptionalPad types from a generic set of Pads

Marker trait for a set of Pads that can receive

Marker trait for a set of Pads that can transmit

Marker trait for a set of Pads that can transmit OR receive

Marker trait for valid SPI Configurations

Marker trait for valid sets of Pads

Type Definitions

Define a set of Pads using PinIds instead of Pins

Type alias to recover the specific Config type from an implementation of AnyConfig

Type alias to recover the specific Spi type from an implementation of AnySpi

Type alias to recover the Word type from an implementation of CharSize