Skip to content
Closed
Show file tree
Hide file tree
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
91 changes: 86 additions & 5 deletions esp-hal-common/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

use core::convert::Infallible;

use fugit::HertzU32;
use fugit::{HertzU32, RateExtU32};

use crate::{
clock::Clocks,
Expand Down Expand Up @@ -55,6 +55,86 @@ pub struct Spi<T> {
spi: T,
}


pub struct SpiBuilder<'a, T> {
instance: T,
frequency: HertzU32, // 100u32.kHz(),
mode: SpiMode, // SpiMode::Mode0,
peripheral_clock_control: &'a mut PeripheralClockControl,
clocks: &'a Clocks,
}

impl<'a, T> SpiBuilder<'a, T>
where
T: Instance,
{
/// Create a new SPI builder instance.
pub fn new<SCK: OutputPin>(
spi: T,
peripheral_clock_control: &'a mut PeripheralClockControl,
clocks: &'a Clocks,
mut sck: SCK,
) -> Self {
sck.set_to_push_pull_output()
.connect_peripheral_to_output(spi.sclk_signal());

SpiBuilder {
instance: spi,
frequency: 100u32.kHz(),
mode: SpiMode::Mode0,
peripheral_clock_control,
clocks,
}
}

/// Set SPI bus frequency. Defaults to 100 kHz.
pub fn frequency(mut self, frequency: HertzU32) -> Self {
self.frequency = frequency;
self
}

/// Set SPI bus operation mode. Defaults to Mode 0.
pub fn mode(mut self, mode: SpiMode) -> Self {
self.mode = mode;
self
}

/// (Optional) Add a chip select line.
///
/// If you intend to use multiple devices on the same SPI bus (i.e. you share the bus),
/// don't add a CS line and prefer to use [`SpiBusDevice`](TODO) instead.
pub fn cs<CS: OutputPin>(self, mut cs: CS) -> Self {
cs.set_to_push_pull_output()
.connect_peripheral_to_output(self.instance.cs_signal());
self
}

/// (Optional) Add a MISO line.
pub fn miso<MISO: InputPin>(self, mut miso: MISO) -> Self {
miso.set_to_input()
.connect_input_to_peripheral(self.instance.miso_signal());
self
}

/// (Optional) Add a MOSI line.
pub fn mosi<MOSI: OutputPin>(self, mut mosi: MOSI) -> Self {
mosi.set_to_push_pull_output()
.connect_peripheral_to_output(self.instance.mosi_signal());
self
}

/// Build a [`Spi`] instance.
pub fn build(self) -> Spi<T> {
Spi::new_internal(
self.instance,
self.frequency,
self.mode,
self.peripheral_clock_control,
self.clocks,
)
}
}

impl<T> Spi<T>
where
T: Instance,
Expand Down Expand Up @@ -561,7 +641,7 @@ pub trait Instance {
/// sequential transfers are performed. This function will return before
/// all bytes of the last chunk to transmit have been sent to the wire. If
/// you must ensure that the whole messages was written correctly, use
/// [`flush`].
/// [`flush`](Instance::flush).
// FIXME: See below.
fn write_bytes(&mut self, words: &[u8]) -> Result<(), Infallible> {
let reg_block = self.register_block();
Expand Down Expand Up @@ -605,7 +685,8 @@ pub trait Instance {
///
/// Sends out a stuffing byte for every byte to read. This function doesn't
/// perform flushing. If you want to read the response to something you
/// have written before, consider using [`transfer`] instead.
/// have written before, consider using [`transfer`](Instance::transfer)
/// instead.
fn read_bytes(&mut self, words: &mut [u8]) -> Result<(), Infallible> {
let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];

Expand All @@ -621,8 +702,8 @@ pub trait Instance {
///
/// Copies the contents of the SPI receive FIFO into `words`. This function
/// doesn't perform flushing. If you want to read the response to
/// something you have written before, consider using [`transfer`]
/// instead.
/// something you have written before, consider
/// using [`transfer`](Instance::transfer) instead.
// FIXME: Using something like `core::slice::from_raw_parts` and
// `copy_from_slice` on the receive registers works only for the esp32 and
// esp32c3 varaints. The reason for this is unknown.
Expand Down
19 changes: 10 additions & 9 deletions esp32-hal/examples/spi_eh1_loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use esp32_hal::{
gpio::IO,
pac::Peripherals,
prelude::*,
spi::{Spi, SpiMode},
spi::{SpiBuilder, SpiMode},
timer::TimerGroup,
Delay,
Rtc,
Expand Down Expand Up @@ -55,17 +55,18 @@ fn main() -> ! {
let mosi = io.pins.gpio23;
let cs = io.pins.gpio22;

let mut spi = Spi::new(
let mut spi = SpiBuilder::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
1000u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
);
sclk,
)
.frequency(1000u32.kHz())
.mode(SpiMode::Mode0)
.mosi(mosi)
.miso(miso)
.cs(cs)
.build();

let mut delay = Delay::new(&clocks);
writeln!(serial0, "=== SPI example with embedded-hal-1 traits ===").unwrap();
Expand Down