From fbc4ad400d44889fed7cb29502b78507560302e8 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 13:31:19 +0100 Subject: [PATCH 01/15] Rework clock settings --- src/common/lpspi.rs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 802abe0b..b1c0cb6d 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -293,24 +293,27 @@ impl Transaction { /// /// This should only happen when the LPSPI peripheral is disabled. fn set_spi_clock(source_clock_hz: u32, spi_clock_hz: u32, reg: &ral::lpspi::RegisterBlock) { - let mut div = source_clock_hz / spi_clock_hz; - - if source_clock_hz / div > spi_clock_hz { - div += 1; - } - - // 0 <= div <= 255, and the true coefficient is really div + 2 - let div = div.saturating_sub(2).clamp(0, 255); - ral::write_reg!( - ral::lpspi, - reg, - CCR, - SCKDIV: div, - // Both of these delays are arbitrary choices, and they should - // probably be configurable by the end-user. - DBT: div / 2, - SCKPCS: 0x1F, - PCSSCK: 0x1F + // Round up, so we always get a resulting SPI clock that is + // equal or less than the requested frequency. + let half_div = + u32::try_from(1 + u64::from(source_clock_hz - 1) / (u64::from(spi_clock_hz) * 2)).unwrap(); + + // Make sure SCKDIV is between 0 and 255 + // For some reason SCK starts to misbehave in between frames + // if half_div is less than 3. + let half_div = half_div.clamp(3, 128); + // Because half_div is in range [3,128], sckdiv is in range [4, 254]. + let sckdiv = 2 * (half_div - 1); + + ral::write_reg!(ral::lpspi, reg, CCR, + // Delay between two clock transitions of two consecutive transfers + // is exactly sckdiv/2, which causes the transfer to be seamless. + DBT: half_div - 1, + // Add one sckdiv/2 setup and hold time before and after the transfer, + // to make sure the signal is stable at sample time + PCSSCK: half_div - 1, + SCKPCS: half_div - 1, + SCKDIV: sckdiv ); } From 905370e102ba78e2e19d36d9a894977f523324fa Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 13:55:44 +0100 Subject: [PATCH 02/15] Rework transaction --- src/common/lpspi.rs | 48 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index b1c0cb6d..60add16f 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -197,9 +197,19 @@ pub enum LpspiError { /// # Ok(()) }().unwrap(); /// ``` pub struct Transaction { + /// Polarity and phase. + /// + /// This only has an effect if we are on a frame border + /// and `continuous` is not active. + pub mode: Mode, + /// Divides the SPI clock by `2^prescaler`. + /// + /// This only has an effect if we are on a frame border + /// and `continuous` is not active. + pub prescaler: u8, /// Enable byte swap. /// - /// When enabled (`true`), swap bytes with the `u32` word. This allows + /// When enabled (`true`), swap bytes within the `u32` word. This allows /// you to change the endianness of the 32-bit word transfer. The /// default is `false`. pub byte_swap: bool, @@ -251,12 +261,29 @@ impl Transaction { /// /// - the buffer is empty. /// - there's more than 128 elements in the buffer. - pub fn new_u32s(data: &[u32]) -> Result { - Transaction::new_words(data) + pub fn new_u32s(data: &[u32], mode: Mode) -> Result { + Transaction::new_words(data, mode) } - fn new_words(data: &[W]) -> Result { - Transaction::new(8 * core::mem::size_of_val(data) as u16) + fn new_words(data: &[W], mode: Mode) -> Result { + if let Ok(frame_size) = u16::try_from(8 * core::mem::size_of_val(data)) { + Transaction::new(frame_size, word) + } else { + Err(LpspiError::FrameSize) + } + } + + fn frame_size_valid(frame_size: u16) -> bool { + const MIN_FRAME_SIZE: u16 = 8; + const MAX_FRAME_SIZE: u16 = 1 << 12; + const MIN_WORD_SIZE: u16 = 2; + const WORD_SIZE: u16 = 32; + + let last_word_size = frame_size % WORD_SIZE; + + (frame_size >= MIN_FRAME_SIZE) + && (frame_size <= MAX_FRAME_SIZE) + && (last_word_size >= MIN_WORD_SIZE) } /// Define a transaction by specifying the frame size, in bits. @@ -270,11 +297,14 @@ impl Transaction { /// - `frame_size` fits within 12 bits; the implementation enforces this maximum value. /// - The minimum value for `frame_size` is 8; the implementation enforces this minimum /// value. - pub fn new(frame_size: u16) -> Result { + /// - The last 32-bit word in the frame is at least 2 bits long. + pub fn new(frame_size: u16, mode: Mode) -> Result { const MIN_FRAME_SIZE: u16 = 8; const MAX_FRAME_SIZE: u16 = 1 << 12; - if (MIN_FRAME_SIZE..MAX_FRAME_SIZE).contains(&frame_size) { + if Self::frame_size_valid(frame_size) { Ok(Self { + mode, + prescaler: 0, byte_swap: false, bit_order: Default::default(), receive_data_mask: false, @@ -640,7 +670,7 @@ impl Lpspi { self.clear_fifos(); - let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16)?; + let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16, todo!())?; transaction.bit_order = self.bit_order(); transaction.continuous = true; @@ -699,7 +729,7 @@ impl Lpspi { self.clear_fifos(); - let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16)?; + let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16, todo!())?; transaction.bit_order = self.bit_order(); transaction.continuous = true; transaction.receive_data_mask = true; From 1a6cd49b48f1281e649c7ed6a3cba5af648e3c49 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 14:14:49 +0100 Subject: [PATCH 03/15] Rework init, remove CS pin --- src/common/lpspi.rs | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 60add16f..a99b2a90 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -362,6 +362,9 @@ pub struct Lpspi { lpspi: ral::lpspi::Instance, pins: P, bit_order: BitOrder, + tx_fifo_size: u32, + rx_fifo_size: u32, + mode: Mode, } /// Pins for a LPSPI device. @@ -377,13 +380,12 @@ pub struct Lpspi { /// GPIO_B0_02, /// GPIO_B0_01, /// GPIO_B0_03, -/// GPIO_B0_00, /// >; /// /// // Helper type for your SPI peripheral /// type Lpspi = hal::lpspi::Lpspi; /// ``` -pub struct Pins { +pub struct Pins { /// Serial data out /// /// Data travels from the SPI host controller to the SPI device. @@ -394,29 +396,24 @@ pub struct Pins { pub sdi: SDI, /// Serial clock pub sck: SCK, - /// Chip select 0 - /// - /// (PCSx) convention matches the hardware. - pub pcs0: PCS0, } -impl Lpspi, N> +impl Lpspi, N> where SDO: lpspi::Pin, Signal = lpspi::Sdo>, SDI: lpspi::Pin, Signal = lpspi::Sdi>, SCK: lpspi::Pin, Signal = lpspi::Sck>, - PCS0: lpspi::Pin, Signal = lpspi::Pcs0>, { /// Create a new LPSPI driver from the RAL LPSPI instance and a set of pins. /// /// When this call returns, the LPSPI pins are configured for their function. /// The peripheral is enabled after reset. The LPSPI clock speed is unspecified. /// The mode is [`MODE_0`]. The sample point is [`SamplePoint::DelayedEdge`]. - pub fn new(lpspi: ral::lpspi::Instance, mut pins: Pins) -> Self { + pub fn new(lpspi: ral::lpspi::Instance, mut pins: Pins) -> Self { lpspi::prepare(&mut pins.sdo); lpspi::prepare(&mut pins.sdi); lpspi::prepare(&mut pins.sck); - lpspi::prepare(&mut pins.pcs0); + Self::init(lpspi, pins) } } @@ -437,13 +434,26 @@ impl Lpspi { pub const N: u8 = N; fn init(lpspi: ral::lpspi::Instance, pins: P) -> Self { + let (tx_fifo_size_exp, rx_fifo_size_exp) = + ral::read_reg!(ral::lpspi, lpspi, PARAM, TXFIFO, RXFIFO); + let tx_fifo_size = 1 << tx_fifo_size_exp; + let rx_fifo_size = 1 << rx_fifo_size_exp; + let mut spi = Lpspi { lpspi, pins, bit_order: BitOrder::default(), + tx_fifo_size, + rx_fifo_size, + mode: MODE_0, }; - ral::write_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_1); - ral::write_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0); + + // Reset and disable + ral::modify_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_0, RST: RST_1); + while ral::read_reg!(ral::lpspi, spi.lpspi, CR, MEN == MEN_1) {} + ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0, RTF: RTF_1, RRF: RRF_1); + + // Configure master mode ral::write_reg!( ral::lpspi, spi.lpspi, @@ -451,9 +461,15 @@ impl Lpspi { MASTER: MASTER_1, SAMPLE: SAMPLE_1 ); - Disabled::new(&mut spi.lpspi).set_mode(MODE_0); - ral::write_reg!(ral::lpspi, spi.lpspi, FCR, RXWATER: 0xF, TXWATER: 0xF); + + // 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 + ); + ral::write_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_1); + spi } From d4ae27311849e5ffdbf3e4bb446cd766fee12583 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 14:31:38 +0100 Subject: [PATCH 04/15] Add soft reset --- src/common/lpspi.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index a99b2a90..c6aab932 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -450,7 +450,7 @@ impl Lpspi { // Reset and disable ral::modify_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_0, RST: RST_1); - while ral::read_reg!(ral::lpspi, spi.lpspi, CR, MEN == MEN_1) {} + while spi.is_enabled() {} ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0, RTF: RTF_1, RRF: RRF_1); // Configure master mode @@ -479,6 +479,11 @@ impl Lpspi { } /// Enable (`true`) or disable (`false`) the peripheral. + /// + /// Note that disabling does not take effect immediately; instead the + /// peripheral finishes the current transfer and then disables itself. + /// It is required to check [`is_enabled`] repeatedly until the + /// peripheral is actually disabled. pub fn set_enable(&mut self, enable: bool) { ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: enable as u32) } @@ -494,6 +499,46 @@ impl Lpspi { } } + /// Cancel the current transfer and force the driver back into idle + /// state. + /// + /// This should be done whenever an error occurred. + pub fn soft_reset(&mut self) { + // Backup previous registers + let ier = ral::read_reg!(ral::lpspi, self.lpspi, IER); + let der = ral::read_reg!(ral::lpspi, self.lpspi, DER); + let cfgr0 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR0); + let cfgr1 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR1); + let dmr0 = ral::read_reg!(ral::lpspi, self.lpspi, DMR0); + let dmr1 = ral::read_reg!(ral::lpspi, self.lpspi, DMR1); + let ccr = ral::read_reg!(ral::lpspi, self.lpspi, CCR); + let fcr = ral::read_reg!(ral::lpspi, self.lpspi, FCR); + + // Backup enabled state + let enabled = self.is_enabled(); + + // Reset and disable + ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: MEN_0, RST: RST_1); + while self.is_enabled() {} + ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0, RTF: RTF_1, RRF: RRF_1); + + // Reset fifos + ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1); + + // Restore settings + ral::write_reg!(ral::lpspi, self.lpspi, IER, ier); + ral::write_reg!(ral::lpspi, self.lpspi, DER, der); + ral::write_reg!(ral::lpspi, self.lpspi, CFGR0, cfgr0); + ral::write_reg!(ral::lpspi, self.lpspi, CFGR1, cfgr1); + ral::write_reg!(ral::lpspi, self.lpspi, DMR0, dmr0); + ral::write_reg!(ral::lpspi, self.lpspi, DMR1, dmr1); + ral::write_reg!(ral::lpspi, self.lpspi, CCR, ccr); + ral::write_reg!(ral::lpspi, self.lpspi, FCR, fcr); + + // Restore enabled state + self.set_enable(enabled); + } + /// Release the SPI driver components. /// /// This does not change any component state; it releases the components as-is. From 88f7ee6ff79fcc465ec874b9a552ee0d40cf99d3 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 14:57:19 +0100 Subject: [PATCH 05/15] Rework disabled state --- examples/rtic_spi.rs | 2 +- src/common/lpspi.rs | 97 +++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 56 deletions(-) diff --git a/examples/rtic_spi.rs b/examples/rtic_spi.rs index 29fe5faa..88a9f158 100644 --- a/examples/rtic_spi.rs +++ b/examples/rtic_spi.rs @@ -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::() as u16) + let transaction = Transaction::new(2 * 8 * core::mem::size_of::() as u16, todo!()) .expect("Transaction frame size is within bounds"); spi.enqueue_transaction(&transaction); diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index c6aab932..ae12b6cf 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -267,7 +267,7 @@ impl Transaction { fn new_words(data: &[W], mode: Mode) -> Result { 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) } @@ -362,8 +362,8 @@ pub struct Lpspi { lpspi: ral::lpspi::Instance, pins: P, bit_order: BitOrder, - tx_fifo_size: u32, - rx_fifo_size: u32, + tx_fifo_size: u16, + rx_fifo_size: u16, mode: Mode, } @@ -465,7 +465,7 @@ impl Lpspi { // 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); @@ -568,10 +568,8 @@ impl Lpspi { /// 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(&mut self, func: impl FnOnce(&mut Disabled) -> R) -> R { - self.clear_fifos(); let mut disabled = Disabled::new(&mut self.lpspi); func(&mut disabled) } @@ -606,6 +604,37 @@ impl Lpspi { 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) { @@ -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) -> 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). @@ -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 From 34fed2a40325131edf3d56486e858a2b37216d99 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 15:13:11 +0100 Subject: [PATCH 06/15] Rework watermark data types; minor refactoring on fifo state --- src/common/lpspi.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index ae12b6cf..8d509ecd 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -600,6 +600,9 @@ impl Lpspi { /// This writes the bits described by `interrupts` as is to the register. /// To modify the existing interrupts flags, you should first call [`interrupts`](Lpspi::interrupts) /// to get the current state, then modify that state. + /// + /// Be aware that a critical section might be required to avoid a read-modify-write race condition + /// between [`interrupts`] and [`set_interrupts`]. pub fn set_interrupts(&self, interrupts: Interrupts) { ral::write_reg!(ral::lpspi, self.lpspi, IER, interrupts.bits()); } @@ -636,6 +639,9 @@ impl Lpspi { } /// Clear any existing data in the SPI receive or transfer FIFOs. + /// + /// Note that this will **not** cancel a running transfer. + /// Use [`soft_reset`] for that usecase instead. #[inline] pub fn clear_fifo(&mut self, direction: Direction) { match direction { @@ -645,17 +651,20 @@ impl Lpspi { } /// Clear both FIFOs. + /// + /// Note that this will **not** cancel a running transfer. + /// Use [`soft_reset`] for that usecase instead. pub fn clear_fifos(&mut self) { ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1); } /// Returns the watermark level for the given direction. #[inline] - pub fn watermark(&self, direction: Direction) -> u8 { + pub fn watermark(&self, direction: Direction) -> u16 { (match direction { Direction::Rx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, RXWATER), Direction::Tx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, TXWATER), - }) as u8 + }) as u16 } /// Returns the FIFO status. @@ -712,7 +721,7 @@ impl Lpspi { return Err(LpspiError::Fifo(Direction::Tx)); } let fifo_status = self.fifo_status(); - if !fifo_status.is_full(Direction::Tx) { + if fifo_status.txcount < self.tx_fifo_size { return Ok(()); } } @@ -726,7 +735,12 @@ impl Lpspi { /// You're responsible for making sure there's space in the transmit /// FIFO for this transaction command. pub fn enqueue_transaction(&mut self, transaction: &Transaction) { - ral::modify_reg!(ral::lpspi, self.lpspi, TCR, + ral::write_reg!(ral::lpspi, self.lpspi, TCR, + CPOL: if transaction.mode.polarity == Polarity::IdleHigh {CPOL_1} else {CPOL_0}, + CPHA: if transaction.mode.phase == Phase::CaptureOnSecondTransition {CPHA_1} else {CPHA_0}, + PRESCALE: PRESCALE_0, + PCS: PCS_0, + WIDTH: WIDTH_0, LSBF: transaction.bit_order as u32, BYSW: transaction.byte_swap as u32, RXMSK: transaction.receive_data_mask as u32, @@ -978,20 +992,6 @@ pub struct FifoStatus { pub txcount: u16, } -impl FifoStatus { - /// Indicates if the FIFO is full for the given direction. - #[inline] - pub const fn is_full(self, direction: Direction) -> bool { - /// See PARAM register docs. - const MAX_FIFO_SIZE: u16 = 16; - let count = match direction { - Direction::Tx => self.txcount, - Direction::Rx => self.rxcount, - }; - count >= MAX_FIFO_SIZE - } -} - bitflags::bitflags! { /// Interrupt flags. /// From cb462f7a34d9796558776661427f24d9803b0930 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 15:46:47 +0100 Subject: [PATCH 07/15] More cleanup --- board/src/teensy4.rs | 2 -- examples/rtic_spi.rs | 14 ++++++------ src/common/lpspi.rs | 52 ++++++++++++++++++++++++-------------------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/board/src/teensy4.rs b/board/src/teensy4.rs index 97e42293..2f50d6e0 100644 --- a/board/src/teensy4.rs +++ b/board/src/teensy4.rs @@ -49,7 +49,6 @@ pub type SpiPins = hal::lpspi::Pins< iomuxc::gpio_b0::GPIO_B0_02, // SDO, P11 iomuxc::gpio_b0::GPIO_B0_01, // SDI, P12 iomuxc::gpio_b0::GPIO_B0_03, // SCK, P13 - iomuxc::gpio_b0::GPIO_B0_00, // PCS0, P10 >; #[cfg(not(feature = "spi"))] @@ -153,7 +152,6 @@ impl Specifics { sdo: iomuxc.gpio_b0.p02, sdi: iomuxc.gpio_b0.p01, sck: iomuxc.gpio_b0.p03, - pcs0: iomuxc.gpio_b0.p00, }; let mut spi = Spi::new(lpspi4, pins); spi.disabled(|spi| { diff --git a/examples/rtic_spi.rs b/examples/rtic_spi.rs index 88a9f158..a3d414d2 100644 --- a/examples/rtic_spi.rs +++ b/examples/rtic_spi.rs @@ -25,12 +25,12 @@ mod app { #[init] fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { let (_, board::Specifics { mut spi, .. }) = board::new(); - spi.disabled(|spi| { - // Trigger when the TX FIFO is empty. - spi.set_watermark(Direction::Tx, 0); - // Wait to receive at least 2 u32s. - spi.set_watermark(Direction::Rx, 1); - }); + + // Wait to receive at least 2 u32s. + spi.set_watermark(Direction::Rx, 1); + // Trigger when the TX FIFO is empty. + spi.set_watermark(Direction::Tx, 0); + // Starts the I/O as soon as we're done initializing, since // the TX FIFO is empty. spi.set_interrupts(Interrupts::TRANSMIT_DATA); @@ -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::() as u16, todo!()) + let transaction = Transaction::new(2 * 8 * core::mem::size_of::() as u16) .expect("Transaction frame size is within bounds"); spi.enqueue_transaction(&transaction); diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 8d509ecd..09532a77 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -197,16 +197,6 @@ pub enum LpspiError { /// # Ok(()) }().unwrap(); /// ``` pub struct Transaction { - /// Polarity and phase. - /// - /// This only has an effect if we are on a frame border - /// and `continuous` is not active. - pub mode: Mode, - /// Divides the SPI clock by `2^prescaler`. - /// - /// This only has an effect if we are on a frame border - /// and `continuous` is not active. - pub prescaler: u8, /// Enable byte swap. /// /// When enabled (`true`), swap bytes within the `u32` word. This allows @@ -261,13 +251,13 @@ impl Transaction { /// /// - the buffer is empty. /// - there's more than 128 elements in the buffer. - pub fn new_u32s(data: &[u32], mode: Mode) -> Result { - Transaction::new_words(data, mode) + pub fn new_u32s(data: &[u32]) -> Result { + Transaction::new_words(data) } - fn new_words(data: &[W], mode: Mode) -> Result { + fn new_words(data: &[W]) -> Result { if let Ok(frame_size) = u16::try_from(8 * core::mem::size_of_val(data)) { - Transaction::new(frame_size, mode) + Transaction::new(frame_size) } else { Err(LpspiError::FrameSize) } @@ -298,13 +288,9 @@ impl Transaction { /// - The minimum value for `frame_size` is 8; the implementation enforces this minimum /// value. /// - The last 32-bit word in the frame is at least 2 bits long. - pub fn new(frame_size: u16, mode: Mode) -> Result { - const MIN_FRAME_SIZE: u16 = 8; - const MAX_FRAME_SIZE: u16 = 1 << 12; + pub fn new(frame_size: u16) -> Result { if Self::frame_size_valid(frame_size) { Ok(Self { - mode, - prescaler: 0, byte_swap: false, bit_order: Default::default(), receive_data_mask: false, @@ -439,7 +425,7 @@ impl Lpspi { let tx_fifo_size = 1 << tx_fifo_size_exp; let rx_fifo_size = 1 << rx_fifo_size_exp; - let mut spi = Lpspi { + let spi = Lpspi { lpspi, pins, bit_order: BitOrder::default(), @@ -736,8 +722,8 @@ impl Lpspi { /// FIFO for this transaction command. pub fn enqueue_transaction(&mut self, transaction: &Transaction) { ral::write_reg!(ral::lpspi, self.lpspi, TCR, - CPOL: if transaction.mode.polarity == Polarity::IdleHigh {CPOL_1} else {CPOL_0}, - CPHA: if transaction.mode.phase == Phase::CaptureOnSecondTransition {CPHA_1} else {CPHA_0}, + CPOL: if self.mode.polarity == Polarity::IdleHigh {CPOL_1} else {CPOL_0}, + CPHA: if self.mode.phase == Phase::CaptureOnSecondTransition {CPHA_1} else {CPHA_0}, PRESCALE: PRESCALE_0, PCS: PCS_0, WIDTH: WIDTH_0, @@ -751,6 +737,24 @@ impl Lpspi { ); } + /// Wait for all ongoing transactions to be finished. + pub fn flush(&mut self) -> Result<(), LpspiError> { + loop { + let status = self.status(); + + if status.intersects(Status::RECEIVE_ERROR) { + return Err(LpspiError::Fifo(Direction::Rx)); + } + if status.intersects(Status::TRANSMIT_ERROR) { + return Err(LpspiError::Fifo(Direction::Tx)); + } + + if !status.intersects(Status::BUSY) { + return Ok(()); + } + } + } + /// Exchanges data with the SPI device. /// /// This routine uses continuous transfers to perform the transaction, no matter the @@ -774,7 +778,7 @@ impl Lpspi { self.clear_fifos(); - let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16, todo!())?; + let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16)?; transaction.bit_order = self.bit_order(); transaction.continuous = true; @@ -833,7 +837,7 @@ impl Lpspi { self.clear_fifos(); - let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16, todo!())?; + let mut transaction = Transaction::new(8 * core::mem::size_of::() as u16)?; transaction.bit_order = self.bit_order(); transaction.continuous = true; transaction.receive_data_mask = true; From 6195b6e00f4d43dfd534a10b48cbafcbbc55d39f Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 15:48:58 +0100 Subject: [PATCH 08/15] Add set_mode again --- src/common/lpspi.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 09532a77..57c48930 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -624,6 +624,14 @@ impl Lpspi { watermark } + /// Set the SPI mode for the peripheral. + /// + /// This only affects the next transfer; ongoing transfers + /// will not be influenced. + pub fn set_mode(&mut self, mode: Mode) { + self.mode = mode; + } + /// Clear any existing data in the SPI receive or transfer FIFOs. /// /// Note that this will **not** cancel a running transfer. From d727e6cbcdb89747f5ec52841ebeeb36e7a525fc Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 22 Dec 2023 15:56:57 +0100 Subject: [PATCH 09/15] Minor fix --- src/common/lpspi.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 57c48930..53b1d330 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -437,7 +437,10 @@ impl Lpspi { // Reset and disable ral::modify_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_0, RST: RST_1); while spi.is_enabled() {} - ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0, RTF: RTF_1, RRF: RRF_1); + ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0); + + // Reset Fifos + ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RTF: RTF_1, RRF: RRF_1); // Configure master mode ral::write_reg!( @@ -506,7 +509,7 @@ impl Lpspi { // Reset and disable ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: MEN_0, RST: RST_1); while self.is_enabled() {} - ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0, RTF: RTF_1, RRF: RRF_1); + ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0); // Reset fifos ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1); From 9f394ca0de76e42d25a3742739bb73b69bb95776 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 23 Dec 2023 13:12:25 +0100 Subject: [PATCH 10/15] Fix clippy warning --- src/common/lpspi.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 53b1d330..4ce10393 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -271,9 +271,7 @@ impl Transaction { let last_word_size = frame_size % WORD_SIZE; - (frame_size >= MIN_FRAME_SIZE) - && (frame_size <= MAX_FRAME_SIZE) - && (last_word_size >= MIN_WORD_SIZE) + (MIN_FRAME_SIZE..=MAX_FRAME_SIZE).contains(&frame_size) && (last_word_size >= MIN_WORD_SIZE) } /// Define a transaction by specifying the frame size, in bits. From 2b3e9ec1657a0c38776eb2db915d8beeb0779610 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 23 Dec 2023 13:13:52 +0100 Subject: [PATCH 11/15] Fix doctest --- src/common/lpspi.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 4ce10393..d001bc56 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -41,7 +41,6 @@ //! sdo: pads.gpio_b0.p02, //! sdi: pads.gpio_b0.p01, //! sck: pads.gpio_b0.p03, -//! pcs0: pads.gpio_b0.p00, //! }; //! //! let mut spi4 = unsafe { LPSPI4::instance() }; From 9e25bf4d26b8cda9c56e5524c354343dd10194e3 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 23 Dec 2023 14:04:04 +0100 Subject: [PATCH 12/15] Fix docs --- src/common/lpspi.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index d001bc56..732d272f 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -468,7 +468,7 @@ impl Lpspi { /// /// Note that disabling does not take effect immediately; instead the /// peripheral finishes the current transfer and then disables itself. - /// It is required to check [`is_enabled`] repeatedly until the + /// It is required to check [`is_enabled()`](Self::is_enabled) repeatedly until the /// peripheral is actually disabled. pub fn set_enable(&mut self, enable: bool) { ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: enable as u32) @@ -588,7 +588,7 @@ impl Lpspi { /// to get the current state, then modify that state. /// /// Be aware that a critical section might be required to avoid a read-modify-write race condition - /// between [`interrupts`] and [`set_interrupts`]. + /// between [`interrupts`](Self::interrupts) and [`set_interrupts`](Self::set_interrupts). pub fn set_interrupts(&self, interrupts: Interrupts) { ral::write_reg!(ral::lpspi, self.lpspi, IER, interrupts.bits()); } @@ -635,7 +635,7 @@ impl Lpspi { /// Clear any existing data in the SPI receive or transfer FIFOs. /// /// Note that this will **not** cancel a running transfer. - /// Use [`soft_reset`] for that usecase instead. + /// Use [`soft_reset()`](Self::soft_reset) for that usecase instead. #[inline] pub fn clear_fifo(&mut self, direction: Direction) { match direction { @@ -647,7 +647,7 @@ impl Lpspi { /// Clear both FIFOs. /// /// Note that this will **not** cancel a running transfer. - /// Use [`soft_reset`] for that usecase instead. + /// Use [`soft_reset()`](Self::soft_reset) for that usecase instead. pub fn clear_fifos(&mut self) { ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1); } From 63a09276bd8fc0ffe22478c83aeaf23dda4ef724 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 23 Dec 2023 14:39:35 +0100 Subject: [PATCH 13/15] Add initial value to GPIO output pins --- src/common/gpio.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/common/gpio.rs b/src/common/gpio.rs index 74f61336..d2032975 100644 --- a/src/common/gpio.rs +++ b/src/common/gpio.rs @@ -60,12 +60,14 @@ impl Port { } /// Allocate an output GPIO. - pub fn output

(&mut self, mut pin: P) -> Output

+ /// + /// `set` defines the initial state of the pin; `true` sets it high. + pub fn output

(&mut self, mut pin: P, set: bool) -> Output

where P: iomuxc::gpio::Pin, { iomuxc::gpio::prepare(&mut pin); - Output::new(pin, self.register_block(), P::OFFSET) + Output::new(pin, self.register_block(), P::OFFSET, set) } /// Allocate an input GPIO. @@ -134,8 +136,13 @@ pub struct Output

{ unsafe impl Send for Output

{} impl

Output

{ - fn new(pin: P, gpio: &'static ral::gpio::RegisterBlock, offset: u32) -> Self { + fn new(pin: P, gpio: &'static ral::gpio::RegisterBlock, offset: u32, set: bool) -> Self { let output = Self { pin, gpio, offset }; + if set { + output.set(); + } else { + output.clear(); + } ral::modify_reg!(ral::gpio, gpio, GDIR, |gdir| gdir | output.mask()); output } @@ -189,7 +196,7 @@ impl

Output

{ impl Output<()> { /// Allocate an output GPIO without a pin. /// - /// Prefer using [`Port::output`](Port::output) to create a GPIO ouptut with a + /// Prefer using [`Port::output`](Port::output) to create a GPIO output with a /// pin resource. That method ensures that pin resources are managed throughout /// your program, and that the pin is configured to operate as a GPIO output. /// @@ -199,8 +206,10 @@ impl Output<()> { /// /// If you use this constructor, you're responsible for configuring the IOMUX /// multiplexer register. - pub fn without_pin(port: &mut Port, offset: u32) -> Self { - Self::new((), port.register_block(), offset) + /// + /// `set` defines the initial state of the pin; `true` sets it high. + pub fn without_pin(port: &mut Port, offset: u32, set: bool) -> Self { + Self::new((), port.register_block(), offset, set) } } From bf5526e39974621113f8a927d8cfe24f65f6e357 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 24 Feb 2024 14:38:31 +0100 Subject: [PATCH 14/15] Split SPI and CS pins in board subcrate --- board/src/imxrt1010evk.rs | 14 ++++++++++---- board/src/imxrt1060evk.rs | 14 ++++++++++---- board/src/imxrt1170evk-cm7.rs | 15 +++++++++++---- board/src/teensy4.rs | 15 +++++++++++---- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/board/src/imxrt1010evk.rs b/board/src/imxrt1010evk.rs index eb3b3af2..81f46cf1 100644 --- a/board/src/imxrt1010evk.rs +++ b/board/src/imxrt1010evk.rs @@ -61,14 +61,17 @@ pub type SpiPins = hal::lpspi::Pins< iomuxc::gpio_ad::GPIO_AD_04, // SDO, J57_8 iomuxc::gpio_ad::GPIO_AD_03, // SDI, J57_10 iomuxc::gpio_ad::GPIO_AD_06, // SCK, J57_12 - iomuxc::gpio_ad::GPIO_AD_05, // PCS0, J57_6 >; #[cfg(feature = "spi")] pub type Spi = hal::lpspi::Lpspi; +#[cfg(feature = "spi")] +pub type SpiCsPin = hal::gpio::Output; // PCS0, J57_6 #[cfg(not(feature = "spi"))] pub type Spi = (); +#[cfg(not(feature = "spi"))] +pub type SpiCsPin = (); pub type I2cPins = hal::lpi2c::Pins< iomuxc::gpio::GPIO_02, // SCL, J57_20 @@ -145,6 +148,7 @@ pub struct Specifics { pub ports: GpioPorts, pub console: Console, pub spi: Spi, + pub spi_cs: SpiCsPin, pub i2c: I2c, pub pwm: Pwm, pub tp34: Tp34, @@ -181,7 +185,7 @@ impl Specifics { }); #[cfg(feature = "spi")] - let spi = { + let (spi, spi_cs) = { let lpspi1 = unsafe { ral::lpspi::LPSPI1::instance() }; let pins = SpiPins { sdo: iomuxc.gpio_ad.p04, @@ -193,12 +197,13 @@ impl Specifics { spi.disabled(|spi| { spi.set_clock_hz(super::LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - spi + let spi_cs = todo!(); + (spi, spi_cs) }; #[cfg(not(feature = "spi"))] #[allow(clippy::let_unit_value)] - let spi = (); + let (spi, spi_cs) = ((), ()); let lpi2c1 = unsafe { ral::lpi2c::LPI2C1::instance() }; let i2c = I2c::new( @@ -247,6 +252,7 @@ impl Specifics { ports: GpioPorts { gpio2 }, console, spi, + spi_cs, i2c, pwm, tp34: iomuxc.gpio_sd.p02, diff --git a/board/src/imxrt1060evk.rs b/board/src/imxrt1060evk.rs index 042938dd..973a46e7 100644 --- a/board/src/imxrt1060evk.rs +++ b/board/src/imxrt1060evk.rs @@ -60,16 +60,19 @@ pub type SpiPins = hal::lpspi::Pins< iomuxc::gpio_sd_b0::GPIO_SD_B0_02, // SDO, J24_4 iomuxc::gpio_sd_b0::GPIO_SD_B0_03, // SDI, J24_5 iomuxc::gpio_sd_b0::GPIO_SD_B0_00, // SCK, J24_6 - iomuxc::gpio_sd_b0::GPIO_SD_B0_01, // PCS0, J24_3 >; #[cfg(not(feature = "spi"))] /// Activate the `"spi"` feature to configure the SPI peripheral. pub type Spi = (); +#[cfg(not(feature = "spi"))] +pub type SpiCsPin = (); #[cfg(feature = "spi")] /// SPI peripheral. pub type Spi = hal::lpspi::Lpspi; +#[cfg(feature = "spi")] +pub type SpiCsPin = hal::gpio::Output; // PCS0, J24_3 type I2cScl = iomuxc::gpio_ad_b1::GPIO_AD_B1_00; // J24_10 type I2cSda = iomuxc::gpio_ad_b1::GPIO_AD_B1_01; // J24_9 @@ -130,6 +133,7 @@ pub struct Specifics { pub ports: GpioPorts, pub console: Console, pub spi: Spi, + pub spi_cs: SpiCsPin, pub i2c: I2c, pub pwm: Pwm, pub trng: hal::trng::Trng, @@ -172,7 +176,7 @@ impl Specifics { }); #[cfg(feature = "spi")] - let spi = { + let (spi, spi_cs) = { let lpspi1 = unsafe { ral::lpspi::LPSPI1::instance() }; let pins = SpiPins { sdo: iomuxc.gpio_sd_b0.p02, @@ -184,11 +188,12 @@ impl Specifics { spi.disabled(|spi| { spi.set_clock_hz(super::LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - spi + let spi_cs = todo!(); + (spi, spi_cs) }; #[cfg(not(feature = "spi"))] #[allow(clippy::let_unit_value)] - let spi = (); + let (spi, spi_cs) = ((), ()); let lpi2c1 = unsafe { ral::lpi2c::LPI2C1::instance() }; let i2c = I2c::new( @@ -228,6 +233,7 @@ impl Specifics { ports: GpioPorts { gpio5 }, console, spi, + spi_cs, i2c, pwm, trng, diff --git a/board/src/imxrt1170evk-cm7.rs b/board/src/imxrt1170evk-cm7.rs index 9a8246a8..f7ff57cb 100644 --- a/board/src/imxrt1170evk-cm7.rs +++ b/board/src/imxrt1170evk-cm7.rs @@ -92,14 +92,18 @@ pub type SpiPins = hal::lpspi::Pins< iomuxc::gpio_ad::GPIO_AD_30, // SDO, J10_8 iomuxc::gpio_ad::GPIO_AD_31, // SDI, J10_10 iomuxc::gpio_ad::GPIO_AD_28, // SCK, J10_12 - iomuxc::gpio_ad::GPIO_AD_29, // PCS0, J10_6 >; const SPI_INSTANCE: u8 = 1; #[cfg(feature = "spi")] pub type Spi = hal::lpspi::Lpspi; +#[cfg(feature = "spi")] +pub type SpiCsPin = hal::gpio::Output; // PCS0, J10_6 + #[cfg(not(feature = "spi"))] pub type Spi = (); +#[cfg(not(feature = "spi"))] +pub type SpiCsPin = (); pub type I2cPins = hal::lpi2c::Pins< iomuxc::gpio_lpsr::GPIO_LPSR_05, // SCL, J10_20 @@ -160,6 +164,7 @@ pub struct Specifics { pub tp1002: Tp1002, pub tp1003: Tp1003, pub spi: Spi, + pub spi_cs: SpiCsPin, pub pwm: Pwm, pub i2c: I2c, } @@ -201,7 +206,7 @@ impl Specifics { hal::usbphy::restart_pll(&mut common.usbphy1); #[cfg(feature = "spi")] - let spi = { + let (spi, spi_cs) = { let lpspi1 = unsafe { ral::lpspi::LPSPI1::instance() }; let pins = SpiPins { sdo: iomuxc.gpio_ad.p30, @@ -213,11 +218,12 @@ impl Specifics { spi.disabled(|spi| { spi.set_clock_hz(LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - spi + let spi_cs = todo!(); + (spi, spi_cs) }; #[cfg(not(feature = "spi"))] #[allow(clippy::let_unit_value)] - let spi = (); + let (spi, spi_cs) = ((), ()); #[cfg(not(feature = "spi"))] let pwm = { @@ -259,6 +265,7 @@ impl Specifics { tp1002: iomuxc.gpio_emc_b1.p40, tp1003: iomuxc.gpio_emc_b1.p41, spi, + spi_cs, pwm, i2c, } diff --git a/board/src/teensy4.rs b/board/src/teensy4.rs index 2f50d6e0..9826cea7 100644 --- a/board/src/teensy4.rs +++ b/board/src/teensy4.rs @@ -54,10 +54,14 @@ pub type SpiPins = hal::lpspi::Pins< #[cfg(not(feature = "spi"))] /// Activate the `"spi"` feature to configure the SPI peripheral. pub type Spi = (); +#[cfg(not(feature = "spi"))] +pub type SpiCsPin = (); #[cfg(feature = "spi")] /// SPI peripheral. pub type Spi = hal::lpspi::Lpspi; +#[cfg(feature = "spi")] +pub type SpiCsPin = hal::gpio::Output; // PCS0, P10 pub type I2cPins = hal::lpi2c::Pins< iomuxc::gpio_ad_b1::GPIO_AD_B1_07, // SCL, P16 @@ -110,6 +114,7 @@ pub struct Specifics { pub ports: GpioPorts, pub console: Console, pub spi: Spi, + pub spi_cs: SpiCsPin, pub i2c: I2c, pub pwm: Pwm, pub trng: hal::trng::Trng, @@ -126,7 +131,7 @@ impl Specifics { let mut gpio2 = hal::gpio::Port::new(gpio2); #[cfg(not(feature = "spi"))] - let led = gpio2.output(iomuxc.gpio_b0.p03); + let led = gpio2.output(iomuxc.gpio_b0.p03, false); #[cfg(feature = "spi")] let led = (); @@ -146,7 +151,7 @@ impl Specifics { }); #[cfg(feature = "spi")] - let spi = { + let (spi, spi_cs) = { let lpspi4 = unsafe { ral::lpspi::LPSPI4::instance() }; let pins = SpiPins { sdo: iomuxc.gpio_b0.p02, @@ -157,11 +162,12 @@ impl Specifics { spi.disabled(|spi| { spi.set_clock_hz(super::LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - spi + let spi_cs = gpio2.output(iomuxc.gpio_b0.p00, true); + (spi, spi_cs) }; #[cfg(not(feature = "spi"))] #[allow(clippy::let_unit_value)] - let spi = (); + let (spi, spi_cs) = ((), ()); let lpi2c3 = unsafe { ral::lpi2c::LPI2C3::instance() }; let i2c = I2c::new( @@ -201,6 +207,7 @@ impl Specifics { ports: GpioPorts { gpio2 }, console, spi, + spi_cs, i2c, pwm, trng, From 90322f75a07ac8c5cfe816b9238cfbd9c174d126 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sat, 24 Feb 2024 14:58:07 +0100 Subject: [PATCH 15/15] More cs pin fixes --- board/src/imxrt1010evk.rs | 5 ++--- board/src/imxrt1060evk.rs | 8 +++++--- board/src/imxrt1170evk-cm7.rs | 5 ++--- src/common/gpio.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/board/src/imxrt1010evk.rs b/board/src/imxrt1010evk.rs index 81f46cf1..a302c9d0 100644 --- a/board/src/imxrt1010evk.rs +++ b/board/src/imxrt1010evk.rs @@ -168,7 +168,7 @@ impl Specifics { let gpio2 = unsafe { ral::gpio::GPIO2::instance() }; let mut gpio2 = hal::gpio::Port::new(gpio2); - let led = gpio1.output(iomuxc.gpio.p11); + let led = gpio1.output(iomuxc.gpio.p11, false); let button = gpio2.input(iomuxc.gpio_sd.p05); let lpuart1 = unsafe { ral::lpuart::LPUART1::instance() }; @@ -191,13 +191,12 @@ impl Specifics { sdo: iomuxc.gpio_ad.p04, sdi: iomuxc.gpio_ad.p03, sck: iomuxc.gpio_ad.p06, - pcs0: iomuxc.gpio_ad.p05, }; let mut spi = Spi::new(lpspi1, pins); spi.disabled(|spi| { spi.set_clock_hz(super::LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - let spi_cs = todo!(); + let spi_cs = gpio1.output(iomuxc.gpio_ad.p05, true); (spi, spi_cs) }; diff --git a/board/src/imxrt1060evk.rs b/board/src/imxrt1060evk.rs index 973a46e7..9630603e 100644 --- a/board/src/imxrt1060evk.rs +++ b/board/src/imxrt1060evk.rs @@ -156,12 +156,15 @@ impl Specifics { let gpio1 = unsafe { ral::gpio::GPIO1::instance() }; let mut gpio1 = hal::gpio::Port::new(gpio1); - let led = gpio1.output(iomuxc.gpio_ad_b0.p09); + let led = gpio1.output(iomuxc.gpio_ad_b0.p09, false); let gpio5 = unsafe { ral::gpio::GPIO5::instance() }; let mut gpio5 = hal::gpio::Port::new(gpio5); let button = hal::gpio::Input::without_pin(&mut gpio5, 0); + let gpio3 = unsafe { ral::gpio::GPIO3::instance() }; + let mut gpio3 = hal::gpio::Port::new(gpio3); + let lpuart1 = unsafe { ral::lpuart::LPUART1::instance() }; let mut console = hal::lpuart::Lpuart::new( lpuart1, @@ -182,13 +185,12 @@ impl Specifics { sdo: iomuxc.gpio_sd_b0.p02, sdi: iomuxc.gpio_sd_b0.p03, sck: iomuxc.gpio_sd_b0.p00, - pcs0: iomuxc.gpio_sd_b0.p01, }; let mut spi = Spi::new(lpspi1, pins); spi.disabled(|spi| { spi.set_clock_hz(super::LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - let spi_cs = todo!(); + let spi_cs = gpio3.output(iomuxc.gpio_sd_b0.p01, true); (spi, spi_cs) }; #[cfg(not(feature = "spi"))] diff --git a/board/src/imxrt1170evk-cm7.rs b/board/src/imxrt1170evk-cm7.rs index f7ff57cb..5adfc4a8 100644 --- a/board/src/imxrt1170evk-cm7.rs +++ b/board/src/imxrt1170evk-cm7.rs @@ -189,7 +189,7 @@ impl Specifics { let gpio9 = unsafe { ral::gpio::GPIO9::instance() }; let mut gpio9 = hal::gpio::Port::new(gpio9); - let led = gpio9.output(iomuxc.gpio_ad.p04); + let led = gpio9.output(iomuxc.gpio_ad.p04, false); let console = unsafe { ral::lpuart::Instance::<{ CONSOLE_INSTANCE }>::instance() }; let mut console = hal::lpuart::Lpuart::new( @@ -212,13 +212,12 @@ impl Specifics { sdo: iomuxc.gpio_ad.p30, sdi: iomuxc.gpio_ad.p31, sck: iomuxc.gpio_ad.p28, - pcs0: iomuxc.gpio_ad.p29, }; let mut spi = Spi::new(lpspi1, pins); spi.disabled(|spi| { spi.set_clock_hz(LPSPI_CLK_FREQUENCY, super::SPI_BAUD_RATE_FREQUENCY); }); - let spi_cs = todo!(); + let spi_cs = gpio9.output(iomuxc.gpio_ad.p29, true); (spi, spi_cs) }; #[cfg(not(feature = "spi"))] diff --git a/src/common/gpio.rs b/src/common/gpio.rs index d2032975..56f33988 100644 --- a/src/common/gpio.rs +++ b/src/common/gpio.rs @@ -23,7 +23,7 @@ //! let gpio_b0_04 = // Handle to GPIO_B0_04 IOMUXC pin, provided by BSP or higher-level HAL... //! # unsafe { imxrt_iomuxc::imxrt1060::gpio_b0::GPIO_B0_04::new() }; //! -//! let output = gpio2.output(gpio_b0_04); +//! let output = gpio2.output(gpio_b0_04, false); //! output.set(); //! output.clear(); //! output.toggle();