Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Spi device/peripheral docs #699

Merged
merged 4 commits into from
Oct 22, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions rp2040-hal/src/spi.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Serial Peripheral Interface (SPI)
//!
//! [`Spi`] is the main struct exported by this module, representing a configured Spi bus. See its
//! docs for more information on its type parameters.
//!
//! See [Chapter 4 Section 4](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details
//!
//! ## Usage
Expand All @@ -16,7 +19,11 @@
//! let sclk = pins.gpio2.into_function::<FunctionSpi>();
//! let mosi = pins.gpio3.into_function::<FunctionSpi>();
//!
//! let spi = Spi::<_, _, _, 8>::new(peripherals.SPI0, (mosi, sclk)).init(&mut peripherals.RESETS, 125_000_000u32.Hz(), 16_000_000u32.Hz(), MODE_0);
//! let spi_device = peripherals.SPI0;
//! let spi_pin_layout = (mosi, sclk);
//!
//! let spi = Spi::<_, _, _, 8>::new(spi_device, spi_pin_layout)
//! .init(&mut peripherals.RESETS, 125_000_000u32.Hz(), 16_000_000u32.Hz(), MODE_0);
//! ```

use core::{convert::Infallible, marker::PhantomData, ops::Deref};
Expand Down Expand Up @@ -147,8 +154,31 @@ impl DataSize for u16 {}
impl Sealed for u8 {}
impl Sealed for u16 {}

/// Spi
pub struct Spi<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> {
/// Configured Spi bus.
///
/// This struct implements the `embedded-hal` Spi-related traits. It represents unique ownership
/// of the entire Spi bus of a single configured RP2040 Spi peripheral.
///
/// `Spi` has four generic parameters:
/// - `S`: a typestate for whether the bus is [`Enabled`] or [`Disabled`]. Upon initial creation,
/// the bus is [`Disabled`]. You will then need to initialize it as either a main (master) or sub
/// (slave) device, providing the necessary configuration, at which point it will become [`Enabled`].
/// - `D`: Which of the concrete Spi peripherals is being used, [`pac::SPI0`] or [`pac::SPI1`]
/// - `P`: Which pins are being used to configure the Spi peripheral `D`. A table of valid
/// pinouts for each Spi peripheral can be found in section 1.4.3 of the RP2040 datasheet.
/// The [`ValidSpiPinout`] trait is implemented for tuples of pin types that follow the layout:
/// - `(Tx, Sck)` (i.e. first the "Tx"/"MOSI" pin, then the "Sck"/"Clock" pin)
/// - `(Tx, Rx, Sck)` (i.e. first "Tx"/"MOSI", then "Rx"/"MISO", then "Sck"/"Clock" pin)
/// If you select an invalid layout, you will get a compile error that `P` does not implement
/// [`ValidSpiPinout`] for your specified [`SpiDevice`] peripheral `D`
/// - `DS`: The "data size", i.e. the number of bits transferred per data frame. Defaults to 8.
///
/// In most cases you won't have to specify these types manually and can let the compiler infer
/// them for you based on the values you pass in to `new`. If you want to select a different
/// data frame size, you'll need to do that by specifying the `DS` parameter manually.
///
/// See [the module level docs][self] for an example.
pub struct Spi<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8 = 8u8> {
device: D,
pins: P,
state: PhantomData<S>,
Expand All @@ -168,9 +198,13 @@ impl<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<S, D, P, DS
self.device
}

/// Set baudrate based on peripheral clock
/// Set device pre-scale and post-div properties to match the given baudrate as
/// closely as possible based on the given peripheral clock frequency.
///
/// Typically the peripheral clock is set to 125_000_000 Hz.
///
/// Typically the peripheral clock is set to 125_000_000
/// Returns the frequency that we were able to achieve, which may not be exactly
/// the requested baudrate.
pub fn set_baudrate<F: Into<HertzU32>, B: Into<HertzU32>>(
&mut self,
peri_frequency: F,
Expand Down Expand Up @@ -218,7 +252,8 @@ impl<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<S, D, P, DS
}

impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Disabled, D, P, DS> {
/// Create new spi device
/// Create new not initialized Spi bus. Initialize it with [`.init`][Self::init]
/// or [`.init_slave`][Self::init_slave].
pub fn new(device: D, pins: P) -> Spi<Disabled, D, P, DS> {
Spi {
device,
Expand Down Expand Up @@ -327,7 +362,8 @@ impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Enabled, D, P, DS> {
self.device.sspsr.read().bsy().bit_is_set()
}

/// Disable the spi to reset its configuration
/// Disable the spi to reset its configuration. You'll then need to initialize it again to use
/// it.
pub fn disable(self) -> Spi<Disabled, D, P, DS> {
self.device.sspcr1.modify(|_, w| w.sse().clear_bit());

Expand Down