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

Prepare LPSPI driver for embedded-hal 1.0 rework #149

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
Rework disabled state
  • Loading branch information
Finomnis committed Dec 22, 2023
commit 88f7ee6ff79fcc465ec874b9a552ee0d40cf99d3
2 changes: 1 addition & 1 deletion examples/rtic_spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ mod app {
spi.set_interrupts(Interrupts::RECEIVE_DATA);

// Sending two u32s. Frame size is represented by bits.
let transaction = Transaction::new(2 * 8 * core::mem::size_of::<u32>() as u16)
let transaction = Transaction::new(2 * 8 * core::mem::size_of::<u32>() as u16, todo!())
.expect("Transaction frame size is within bounds");
spi.enqueue_transaction(&transaction);

Expand Down
97 changes: 42 additions & 55 deletions src/common/lpspi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ impl Transaction {

fn new_words<W>(data: &[W], mode: Mode) -> Result<Self, LpspiError> {
if let Ok(frame_size) = u16::try_from(8 * core::mem::size_of_val(data)) {
Transaction::new(frame_size, word)
Transaction::new(frame_size, mode)
} else {
Err(LpspiError::FrameSize)
}
Expand Down Expand Up @@ -362,8 +362,8 @@ pub struct Lpspi<P, const N: u8> {
lpspi: ral::lpspi::Instance<N>,
pins: P,
bit_order: BitOrder,
tx_fifo_size: u32,
rx_fifo_size: u32,
tx_fifo_size: u16,
rx_fifo_size: u16,
mode: Mode,
}

Expand Down Expand Up @@ -465,7 +465,7 @@ impl<P, const N: u8> Lpspi<P, N> {
// Configure watermarks
ral::write_reg!(ral::lpspi, spi.lpspi, FCR,
RXWATER: 0, // Notify when we have any data available
TXWATER: tx_fifo_size / 2 // Nofify when we have at least tx_fifo_size/2 space available
TXWATER: u32::from(tx_fifo_size) / 2 // Nofify when we have at least tx_fifo_size/2 space available
);

ral::write_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_1);
Expand Down Expand Up @@ -568,10 +568,8 @@ impl<P, const N: u8> Lpspi<P, N> {
/// Temporarily disable the LPSPI peripheral.
///
/// The handle to a [`Disabled`](crate::lpspi::Disabled) driver lets you modify
/// LPSPI settings that require a fully disabled peripheral. This will clear the transmit
/// and receive FIFOs.
/// LPSPI settings that require a fully disabled peripheral.
pub fn disabled<R>(&mut self, func: impl FnOnce(&mut Disabled<N>) -> R) -> R {
self.clear_fifos();
let mut disabled = Disabled::new(&mut self.lpspi);
func(&mut disabled)
}
Expand Down Expand Up @@ -606,6 +604,37 @@ impl<P, const N: u8> Lpspi<P, N> {
ral::write_reg!(ral::lpspi, self.lpspi, IER, interrupts.bits());
}

/// Set the watermark level for a given direction.
///
/// Returns the watermark level committed to the hardware. This may be different
/// than the supplied `watermark`, since it's limited by the hardware.
///
/// When `direction == Direction::Rx`, the receive data flag is set whenever the
/// number of words in the receive FIFO is greater than `watermark`.
///
/// When `direction == Direction::Tx`, the transmit data flag is set whenever the
/// the number of words in the transmit FIFO is less than, or equal, to `watermark`.
#[inline]
pub fn set_watermark(&mut self, direction: Direction, watermark: u16) -> u16 {
let max_watermark = match direction {
Direction::Rx => self.rx_fifo_size - 1,
Direction::Tx => self.tx_fifo_size - 1,
};

let watermark = watermark.min(max_watermark);

match direction {
Direction::Rx => {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, RXWATER: u32::from(watermark))
}
Direction::Tx => {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, TXWATER: u32::from(watermark))
}
}

watermark
}

/// Clear any existing data in the SPI receive or transfer FIFOs.
#[inline]
pub fn clear_fifo(&mut self, direction: Direction) {
Expand Down Expand Up @@ -998,25 +1027,14 @@ pub struct Disabled<'a, const N: u8> {
impl<'a, const N: u8> Disabled<'a, N> {
fn new(lpspi: &'a mut ral::lpspi::Instance<N>) -> Self {
let men = ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1);

// Request disable
ral::modify_reg!(ral::lpspi, lpspi, CR, MEN: MEN_0);
Self { lpspi, men }
}
// Wait for the driver to finish its current transfer
// and enter disabled state
while ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1) {}

/// Set the SPI mode for the peripheral
pub fn set_mode(&mut self, mode: Mode) {
// This could probably be changed when we're not disabled.
// However, there's rules about when you can read TCR.
// Specifically, reading TCR while it's being loaded from
// the transmit FIFO could result in an incorrect reading.
// Only permitting this when we're disabled might help
// us avoid something troublesome.
ral::modify_reg!(
ral::lpspi,
self.lpspi,
TCR,
CPOL: ((mode.polarity == Polarity::IdleHigh) as u32),
CPHA: ((mode.phase == Phase::CaptureOnSecondTransition) as u32)
);
Self { lpspi, men }
}

/// Set the LPSPI clock speed (Hz).
Expand All @@ -1027,37 +1045,6 @@ impl<'a, const N: u8> Disabled<'a, N> {
set_spi_clock(source_clock_hz, clock_hz, self.lpspi);
}

/// Set the watermark level for a given direction.
///
/// Returns the watermark level committed to the hardware. This may be different
/// than the supplied `watermark`, since it's limited by the hardware.
///
/// When `direction == Direction::Rx`, the receive data flag is set whenever the
/// number of words in the receive FIFO is greater than `watermark`.
///
/// When `direction == Direction::Tx`, the transmit data flag is set whenever the
/// the number of words in the transmit FIFO is less than, or equal, to `watermark`.
#[inline]
pub fn set_watermark(&mut self, direction: Direction, watermark: u8) -> u8 {
let max_watermark = match direction {
Direction::Rx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, RXFIFO),
Direction::Tx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, TXFIFO),
};

let watermark = watermark.min(max_watermark - 1);

match direction {
Direction::Rx => {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, RXWATER: watermark as u32)
}
Direction::Tx => {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, TXWATER: watermark as u32)
}
}

watermark
}

/// Set the sampling point of the LPSPI peripheral.
///
/// When set to `SamplePoint::DelayedEdge`, the LPSPI will sample the input data
Expand Down