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

[spi] Make SPI set_format accept frame format #654

Merged
merged 7 commits into from
Aug 8, 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
81 changes: 55 additions & 26 deletions rp2040-hal/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,42 +38,50 @@ use crate::{resets::SubsystemReset, typelevel::Sealed};
mod pins;
pub use pins::*;

/// Spi mode
pub struct Mode(embedded_hal::spi::Mode);

impl From<embedded_hal::spi::Mode> for Mode {
impl From<embedded_hal::spi::Mode> for FrameFormat {
fn from(f: embedded_hal::spi::Mode) -> Self {
Mode(f)
Self::MotorolaSpi(f)
}
}

impl From<&embedded_hal::spi::Mode> for Mode {
impl From<&embedded_hal::spi::Mode> for FrameFormat {
fn from(f: &embedded_hal::spi::Mode) -> Self {
Mode(*f)
Self::MotorolaSpi(*f)
}
}

/// SPI frame format
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum FrameFormat {
ithinuel marked this conversation as resolved.
Show resolved Hide resolved
/// Motorola SPI format. See section 4.4.3.9 of RP2040 datasheet.
MotorolaSpi(embedded_hal::spi::Mode),
/// Texas Instruments synchronous serial frame format. See section 4.4.3.8 of RP2040 datasheet.
TexasInstrumentsSynchronousSerial,
/// National Semiconductor Microwire frame format. See section 4.4.3.14 of RP2040 datasheet.
NationalSemiconductorMicrowire,
}

#[cfg(feature = "eh1_0_alpha")]
impl From<eh1_0_alpha::spi::Mode> for Mode {
impl From<eh1_0_alpha::spi::Mode> for FrameFormat {
fn from(f: eh1_0_alpha::spi::Mode) -> Self {
let eh1_0_alpha::spi::Mode { polarity, phase } = f;
match (polarity, phase) {
(
eh1_0_alpha::spi::Polarity::IdleLow,
eh1_0_alpha::spi::Phase::CaptureOnFirstTransition,
) => Mode(embedded_hal::spi::MODE_0),
) => FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_0),
(
eh1_0_alpha::spi::Polarity::IdleLow,
eh1_0_alpha::spi::Phase::CaptureOnSecondTransition,
) => Mode(embedded_hal::spi::MODE_1),
) => FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_1),
(
eh1_0_alpha::spi::Polarity::IdleHigh,
eh1_0_alpha::spi::Phase::CaptureOnFirstTransition,
) => Mode(embedded_hal::spi::MODE_2),
) => FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_2),
(
eh1_0_alpha::spi::Polarity::IdleHigh,
eh1_0_alpha::spi::Phase::CaptureOnSecondTransition,
) => Mode(embedded_hal::spi::MODE_3),
) => FrameFormat::MotorolaSpi(embedded_hal::spi::MODE_3),
}
}
}
Expand Down Expand Up @@ -217,14 +225,25 @@ impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Disabled, D, P, DS> {
}

/// Set format and datasize
fn set_format(&mut self, data_bits: u8, mode: Mode) {
fn set_format(&mut self, data_bits: u8, frame_format: FrameFormat) {
self.device.sspcr0.modify(|_, w| unsafe {
w.dss()
.bits(data_bits - 1)
.spo()
.bit(mode.0.polarity == Polarity::IdleHigh)
.sph()
.bit(mode.0.phase == Phase::CaptureOnSecondTransition)
w.dss().bits(data_bits - 1).frf().bits(match &frame_format {
FrameFormat::MotorolaSpi(_) => 0x00,
FrameFormat::TexasInstrumentsSynchronousSerial => 0x01,
FrameFormat::NationalSemiconductorMicrowire => 0x10,
NelsonAPenn marked this conversation as resolved.
Show resolved Hide resolved
});

/*
* Clock polarity (SPO) and clock phase (SPH) are only applicable to
* the Motorola SPI frame format.
*/
if let FrameFormat::MotorolaSpi(ref mode) = frame_format {
w.spo()
.bit(mode.polarity == Polarity::IdleHigh)
.sph()
.bit(mode.phase == Phase::CaptureOnSecondTransition);
}
w
});
}

Expand All @@ -242,14 +261,14 @@ impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Disabled, D, P, DS> {
resets: &mut RESETS,
peri_frequency: F,
baudrate: B,
mode: Mode,
frame_format: FrameFormat,
slave: bool,
) -> Spi<Enabled, D, P, DS> {
self.device.reset_bring_down(resets);
self.device.reset_bring_up(resets);

self.set_baudrate(peri_frequency, baudrate);
self.set_format(DS, mode);
self.set_format(DS, frame_format);
self.set_slave(slave);
// Always enable DREQ signals -- harmless if DMA is not listening
self.device
Expand All @@ -263,22 +282,32 @@ impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Disabled, D, P, DS> {
}

/// Initialize the SPI in master mode
pub fn init<F: Into<HertzU32>, B: Into<HertzU32>, M: Into<Mode>>(
pub fn init<F: Into<HertzU32>, B: Into<HertzU32>, M: Into<FrameFormat>>(
self,
resets: &mut RESETS,
peri_frequency: F,
baudrate: B,
mode: M,
frame_format: M,
) -> Spi<Enabled, D, P, DS> {
self.init_spi(resets, peri_frequency, baudrate, mode.into(), false)
self.init_spi(resets, peri_frequency, baudrate, frame_format.into(), false)
}

/// Initialize the SPI in slave mode
pub fn init_slave<M: Into<Mode>>(self, resets: &mut RESETS, mode: M) -> Spi<Enabled, D, P, DS> {
pub fn init_slave<M: Into<FrameFormat>>(
self,
resets: &mut RESETS,
frame_format: M,
) -> Spi<Enabled, D, P, DS> {
// Use dummy values for frequency and baudrate.
// With both values 0, set_baudrate will set prescale == u8::MAX, which will break if debug assertions are enabled.
// u8::MAX is outside the allowed range 2..=254 for CPSDVSR, which might interfere with proper operation in slave mode.
self.init_spi(resets, 1000u32.Hz(), 1000u32.Hz(), mode.into(), true)
self.init_spi(
resets,
1000u32.Hz(),
1000u32.Hz(),
frame_format.into(),
true,
)
}
}

Expand Down
Loading