imxrt_hal/common/lpspi.rs
1//! Low-power serial peripheral interface.
2//!
3//! [`Lpspi`] implements select embedded HAL SPI traits for coordinating SPI I/O.
4//! When using the trait implementations, make sure that [`set_bit_order`](Lpspi::set_bit_order)
5//! is correct for your device. These settings apply when the driver internally defines the transaction.
6//!
7//! This driver also exposes the peripheral's lower-level, hardware-dependent transaction interface.
8//! Create a [`Transaction`], then [`enqueue_transaction`](Lpspi::enqueue_transaction) before
9//! sending data with [`enqueue_data`](Lpspi::enqueue_data). When using the transaction interface,
10//! you're responsible for serializing your data into `u32` SPI words.
11//!
12//! # Chip selects (CS) for SPI peripherals
13//!
14//! The iMXRT SPI peripherals have one or more peripheral-controlled chip selects (CS). Using
15//! the peripheral-controlled CS means that you do not need a GPIO to coordinate SPI operations.
16//! Blocking full-duplex transfers and writes will observe an asserted chip select while data
17//! frames are exchanged / written.
18//!
19//! This driver generally assumes that you're using the peripheral-controlled chip select. If
20//! you instead want to manage chip select in software, you should be able to multiplex your own
21//! pins, then construct the driver [`without_pins`](Lpspi::without_pins).
22//!
23//! # Device support
24//!
25//! By default, the driver behaves as a SPI controller, coordinating I/O for other SPI peripherals.
26//! To behave like a peripheral, use [`set_peripheral_enable`](Disabled::set_peripheral_enable).
27//!
28//! As of this writing, you're expected to use the lower-level interface to perform device I/O.
29//!
30//! # Example
31//!
32//! Initialize an LPSPI controller with a 1MHz SCK. To understand how to configure the LPSPI
33//! peripheral clock, see the [`ccm::lpspi_clk`](crate::ccm::lpspi_clk) documentation.
34//!
35//! ```no_run
36//! use imxrt_hal as hal;
37//! use imxrt_ral as ral;
38//! # use eh02 as embedded_hal;
39//! use embedded_hal::blocking::spi::Transfer;
40//! use hal::lpspi::{Lpspi, Pins, SamplePoint};
41//! use ral::lpspi::LPSPI4;
42//!
43//! let mut pads = // Handle to all processor pads...
44//! # unsafe { imxrt_iomuxc::imxrt1060::Pads::new() };
45//!
46//! # || -> Option<()> {
47//! let spi_pins = Pins {
48//! sdo: pads.gpio_b0.p02,
49//! sdi: pads.gpio_b0.p01,
50//! sck: pads.gpio_b0.p03,
51//! pcs0: pads.gpio_b0.p00,
52//! };
53//!
54//! let mut spi4 = unsafe { LPSPI4::instance() };
55//! let mut spi = Lpspi::new(
56//! spi4,
57//! spi_pins,
58//! );
59//!
60//! # const LPSPI_CLK_HZ: u32 = 1;
61//! spi.disabled(|spi| {
62//! spi.set_clock_hz(LPSPI_CLK_HZ, 1_000_000);
63//! spi.set_sample_point(SamplePoint::Edge);
64//! });
65//!
66//! let mut buffer: [u8; 3] = [1, 2, 3];
67//! spi.transfer(&mut buffer).ok()?;
68//!
69//! let (spi4, pins) = spi.release();
70//!
71//! // Re-construct without pins:
72//! let mut spi = Lpspi::without_pins(spi4);
73//! # Some(()) }();
74//! ```
75//!
76//! # Limitations
77//!
78//! Due to [a hardware defect][1], this driver does not yet support the EH02 SPI transaction API.
79//! An early iteration of this driver reproduced the issue discussed in that forum. This driver may
80//! be able to work around the defect in software, but it hasn't been explored.
81//!
82//! [1]: https://community.nxp.com/t5/i-MX-RT/RT1050-LPSPI-last-bit-not-completing-in-continuous-mode/m-p/898460
83//!
84//! [`Transaction`] exposes the continuous / continuing flags, so you're free to model advanced
85//! transactions. However, keep in mind that disabling the receiver during a continuous transaction
86//! may not work as expected.
87
88use core::marker::PhantomData;
89use core::task::Poll;
90
91use crate::iomuxc::{consts, lpspi};
92use crate::ral;
93
94pub use eh02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
95
96/// Data direction.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum Direction {
99 /// Transmit direction (leaving the peripheral).
100 Tx,
101 /// Receive direction (entering the peripheral).
102 Rx,
103}
104
105/// Bit order.
106#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
107#[repr(u32)]
108pub enum BitOrder {
109 /// Data is transferred most significant bit first (default).
110 #[default]
111 Msb,
112 /// Data is transferred least significant bit first.
113 Lsb,
114}
115
116/// Receive sample point behavior.
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum SamplePoint {
119 /// Input data is sampled on SCK edge.
120 Edge,
121 /// Input data is sampled on delayed SCK edge.
122 DelayedEdge,
123}
124
125/// Possible errors when interfacing the LPSPI.
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum LpspiError {
128 /// The transaction frame size is incorrect.
129 ///
130 /// The frame size, in bits, must be between 8 bits and
131 /// 4095 bits.
132 FrameSize,
133 /// FIFO error in the given direction.
134 Fifo(Direction),
135 /// Bus is busy at the start of a transfer.
136 Busy,
137 /// Caller provided no data.
138 NoData,
139}
140
141/// An LPSPI transaction definition.
142///
143/// The transaction defines how many bits the driver sends or recieves.
144/// It also describes
145///
146/// - endianness
147/// - bit order
148/// - transmit and receive masking
149/// - continuous and continuing transfers (default: both disabled)
150///
151/// The LPSPI enqueues the transaction data into the transmit
152/// FIFO. When it pops the values from the FIFO, the values take
153/// effect immediately. This may affect, or abort, any ongoing
154/// transactions. Consult the reference manual to understand when
155/// you should enqueue transaction definitions, since it may only
156/// be supported on word / frame boundaries.
157///
158/// Construct `Transaction` with [`new`](Self::new), and supply
159/// the number of **bits** to transmit per frame.
160///
161/// ```
162/// use imxrt_hal as hal;
163/// use hal::lpspi::Transaction;
164///
165/// // Send one u32.
166/// let mut transaction
167/// = Transaction::new(8 * core::mem::size_of::<u32>() as u16);
168/// ```
169///
170/// Once constructed, manipulate the public members to change the
171/// configuration.
172///
173/// # Continuous transactions
174///
175/// The pseudo-code below shows how to set [`continuous`](Self::continuous) and
176/// [`continuing`](Self::continuing) to model a continuous transaction. Keep in
177/// mind the hardware limitations; see the [module-level docs](crate::lpspi#limitations) for
178/// details.
179///
180/// ```
181/// use imxrt_hal as hal;
182/// use hal::lpspi::Transaction;
183///
184/// // Skipping LPSPI initialization; see module-level example.
185///
186/// // Start byte exchange as a continuous transaction. Each frame
187/// // exchanges one byte (eight bits) with a device.
188/// # || -> Result<(), hal::lpspi::LpspiError> {
189/// let mut transaction = Transaction::new(8)?;
190/// transaction.continuous = true;
191/// // Enqueue transaction with LPSPI...
192/// // Enqueue one byte with LPSPI... <-- PCS asserts here.
193///
194/// # let buffer: [u8; 5] = [0; 5];
195/// for byte in buffer {
196/// // Set 'continuing' to indicate that the next
197/// // transaction continues the previous one...
198/// transaction.continuing = true;
199///
200/// // Enqueue transaction with LPSPI...
201/// // Enqueue byte with LPSPI...
202/// }
203///
204/// transaction.continuous = false;
205/// transaction.continuing = false;
206/// // Enqueue transaction with LPSPI... <-- PCS de-asserts here.
207/// # Ok(()) }().unwrap();
208/// ```
209pub struct Transaction {
210 /// Enable byte swap.
211 ///
212 /// When enabled (`true`), swap bytes within the `u32` word. This allows
213 /// you to change the endianness of the 32-bit word transfer. The
214 /// default is `false`.
215 pub byte_swap: bool,
216 /// Bit order.
217 ///
218 /// See [`BitOrder`] for details. The default is [`BitOrder::Msb`].
219 pub bit_order: BitOrder,
220 /// Mask the received data.
221 ///
222 /// If `true`, the peripheral discards received data. Use this
223 /// when you only care about sending data. The default is `false`;
224 /// the peripheral puts received data in the receive FIFO.
225 pub receive_data_mask: bool,
226 /// Mask the transmit data.
227 ///
228 /// If `true`, the peripheral doesn't send any data. Use this when
229 /// you only care about receiving data. The default is `false`;
230 /// the peripheral expects to send data using the transmit FIFO.
231 pub transmit_data_mask: bool,
232 /// Indicates (`true`) the start of a continuous transfer.
233 ///
234 /// If set, the peripherals chip select will remain asserted after
235 /// exchanging the frame. This allows you to enqueue new commands
236 /// and data words within the same transaction. Those new commands
237 /// should have [`continuing`](Self::continuing) set to `true`.
238 ///
239 /// The default is `false`; chip select de-asserts after exchanging
240 /// the frame. To stop a continuous transfer, enqueue a new `Transaction`
241 /// in which this flag, and `continuing`, is false.
242 pub continuous: bool,
243 /// Indicates (`true`) that this command belongs to a previous transaction.
244 ///
245 /// Set this to indicate that this new `Transaction` belongs to a previous
246 /// `Transaction`, one that had [`continuous`](Self::continuous) set.
247 /// The default value is `false`.
248 pub continuing: bool,
249
250 frame_size: u16,
251}
252
253impl Transaction {
254 /// Defines a transaction for a `u32` buffer.
255 ///
256 /// After successfully defining a transaction of this buffer,
257 /// supply it to the LPSPI driver, then start sending the
258 /// data.
259 ///
260 /// Returns an error if any are true:
261 ///
262 /// - the buffer is empty.
263 /// - there's more than 128 elements in the buffer.
264 pub fn new_u32s(data: &[u32]) -> Result<Self, LpspiError> {
265 Transaction::new_words(data)
266 }
267
268 fn new_words<W>(data: &[W]) -> Result<Self, LpspiError> {
269 if let Ok(frame_size) = u16::try_from(8 * core::mem::size_of_val(data)) {
270 Transaction::new(frame_size)
271 } else {
272 Err(LpspiError::FrameSize)
273 }
274 }
275
276 fn frame_size_valid(frame_size: u16) -> bool {
277 const MIN_FRAME_SIZE: u16 = 8;
278 const MAX_FRAME_SIZE: u16 = 1 << 12;
279 const WORD_SIZE: u16 = 32;
280
281 let last_frame_size = frame_size % WORD_SIZE;
282
283 (MIN_FRAME_SIZE..=MAX_FRAME_SIZE).contains(&frame_size) && (1 != last_frame_size)
284 }
285
286 /// Define a transaction by specifying the frame size, in bits.
287 ///
288 /// The frame size describes the number of bits that will be transferred and
289 /// received during the next transaction. Specifically, it describes the number
290 /// of bits for which the PCS pin signals a transaction.
291 ///
292 /// # Requirements
293 ///
294 /// - `frame_size` fits within 12 bits; the implementation enforces this maximum value.
295 /// - The minimum value for `frame_size` is 8; the implementation enforces this minimum
296 /// value.
297 /// - The last 32-bit word in the frame is at least 2 bits long.
298 pub fn new(frame_size: u16) -> Result<Self, LpspiError> {
299 if Self::frame_size_valid(frame_size) {
300 Ok(Self {
301 byte_swap: false,
302 bit_order: Default::default(),
303 receive_data_mask: false,
304 transmit_data_mask: false,
305 frame_size: frame_size - 1,
306 continuing: false,
307 continuous: false,
308 })
309 } else {
310 Err(LpspiError::FrameSize)
311 }
312 }
313}
314
315/// Sets the clock speed parameters.
316///
317/// This should only happen when the LPSPI peripheral is disabled.
318fn set_spi_clock(source_clock_hz: u32, spi_clock_hz: u32, reg: &ral::lpspi::RegisterBlock) {
319 // Round up, so we always get a resulting SPI clock that is
320 // equal or less than the requested frequency.
321 let half_div =
322 u32::try_from(1 + u64::from(source_clock_hz - 1) / (u64::from(spi_clock_hz) * 2)).unwrap();
323
324 // Make sure SCKDIV is between 0 and 255
325 // For some reason SCK starts to misbehave in between frames
326 // if half_div is less than 3.
327 let half_div = half_div.clamp(3, 128);
328 // Because half_div is in range [3,128], sckdiv is in range [4, 254].
329 let sckdiv = 2 * (half_div - 1);
330
331 ral::write_reg!(ral::lpspi, reg, CCR,
332 // Delay between two clock transitions of two consecutive transfers
333 // is exactly sckdiv/2, which causes the transfer to be seamless.
334 DBT: half_div - 1,
335 // Add one sckdiv/2 setup and hold time before and after the transfer,
336 // to make sure the signal is stable at sample time
337 PCSSCK: half_div - 1,
338 SCKPCS: half_div - 1,
339 SCKDIV: sckdiv
340 );
341}
342
343/// LPSPI clock configurations.
344///
345/// This is a low-level API. You should prefer [`set_clock_hz`](Disabled::set_clock_hz)
346/// if you're not sure how to use these configurations.
347///
348/// All delays and dividers are in terms of the LPSPI functional clock cycles. They're
349/// written directly to the corresponding clock configuration register fields. See inline
350/// documentation to understand what values of zero represent.
351#[derive(Clone, Copy, PartialEq, Eq)]
352pub struct ClockConfigs {
353 /// SCK-to-PCS delay.
354 ///
355 /// This value is off-by-one: a value of zero indicates one cycle.
356 pub sckpcs: u8,
357 /// PCS-to-SCK delay.
358 ///
359 /// This value is off-by-one: a value of zero indicates one cycle.
360 pub pcssck: u8,
361 /// Delay between transfers.
362 ///
363 /// For normal transactions, this affects the PCS negation duration. In this
364 /// configuration, this value is off-by-two: a value of zero indicates two cycle.
365 ///
366 /// For continuous transactions, this affects the clock delay between words.
367 /// In this configuration, this value is off-by-one.
368 pub dbt: u8,
369 /// SCK divider.
370 ///
371 /// This value is off-by-two: a value of zero indicates two cycles.
372 pub sckdiv: u8,
373}
374
375/// An LPSPI driver.
376///
377/// The driver exposes low-level methods for coordinating
378/// DMA transfers. However, you may find it easier to use the
379/// [`dma`](crate::dma) interface to coordinate DMA transfers.
380///
381/// The driver implements `embedded-hal` SPI traits. You should prefer
382/// these implementations for their ease of use.
383///
384/// See the [module-level documentation](crate::lpspi) for an example
385/// of how to construct this driver.
386pub struct Lpspi<P, const N: u8> {
387 lpspi: ral::lpspi::Instance<N>,
388 pins: P,
389 bit_order: BitOrder,
390 mode: Mode,
391}
392
393/// Pins for a LPSPI device.
394///
395/// Consider using type aliases to simplify your usage:
396///
397/// ```no_run
398/// use imxrt_hal as hal;
399/// use imxrt_iomuxc::imxrt1060::gpio_b0::*;
400///
401/// // SPI pins used in my application
402/// type LpspiPins = hal::lpspi::Pins<
403/// GPIO_B0_02,
404/// GPIO_B0_01,
405/// GPIO_B0_03,
406/// GPIO_B0_00,
407/// >;
408///
409/// // Helper type for your SPI peripheral
410/// type Lpspi<const N: u8> = hal::lpspi::Lpspi<LpspiPins, N>;
411/// ```
412pub struct Pins<SDO, SDI, SCK, PCS0> {
413 /// Serial data out
414 ///
415 /// Data travels from the SPI host controller to the SPI device.
416 pub sdo: SDO,
417 /// Serial data in
418 ///
419 /// Data travels from the SPI device to the SPI host controller.
420 pub sdi: SDI,
421 /// Serial clock
422 pub sck: SCK,
423 /// Chip select 0
424 ///
425 /// (PCSx) convention matches the hardware.
426 pub pcs0: PCS0,
427}
428
429impl<SDO, SDI, SCK, PCS0, const N: u8> Lpspi<Pins<SDO, SDI, SCK, PCS0>, N>
430where
431 SDO: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sdo>,
432 SDI: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sdi>,
433 SCK: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sck>,
434 PCS0: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Pcs0>,
435{
436 /// Create a new LPSPI driver from the RAL LPSPI instance and a set of pins.
437 ///
438 /// When this call returns, the LPSPI pins are configured for their function.
439 /// The peripheral is enabled after reset. The LPSPI clock speed is unspecified.
440 /// The mode is [`MODE_0`]. The sample point is [`SamplePoint::DelayedEdge`].
441 pub fn new(lpspi: ral::lpspi::Instance<N>, mut pins: Pins<SDO, SDI, SCK, PCS0>) -> Self {
442 lpspi::prepare(&mut pins.sdo);
443 lpspi::prepare(&mut pins.sdi);
444 lpspi::prepare(&mut pins.sck);
445 lpspi::prepare(&mut pins.pcs0);
446 Self::init(lpspi, pins)
447 }
448}
449
450impl<const N: u8> Lpspi<(), N> {
451 /// Create a new LPSPI driver from the RAL LPSPI instance.
452 ///
453 /// This is similar to [`new()`](Self::new), but it does not configure
454 /// pins. You're responsible for configuring pins, and for making sure
455 /// the pin configuration doesn't change while this driver is in use.
456 pub fn without_pins(lpspi: ral::lpspi::Instance<N>) -> Self {
457 Self::init(lpspi, ())
458 }
459}
460
461impl<P, const N: u8> Lpspi<P, N> {
462 /// The peripheral instance.
463 pub const N: u8 = N;
464
465 fn init(lpspi: ral::lpspi::Instance<N>, pins: P) -> Self {
466 let spi = Lpspi {
467 lpspi,
468 pins,
469 bit_order: BitOrder::default(),
470 mode: MODE_0,
471 };
472
473 // Reset and disable
474 ral::modify_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_0, RST: RST_1);
475 while spi.is_enabled() {}
476 ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0);
477
478 // Reset Fifos
479 ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
480
481 // Configure master mode
482 ral::write_reg!(
483 ral::lpspi,
484 spi.lpspi,
485 CFGR1,
486 MASTER: MASTER_1,
487 SAMPLE: SAMPLE_1
488 );
489
490 let tx_fifo_size = spi.max_watermark(Direction::Tx);
491 // Configure watermarks
492 ral::write_reg!(ral::lpspi, spi.lpspi, FCR,
493 RXWATER: 0, // Notify when we have any data available
494 TXWATER: u32::from(tx_fifo_size) / 2 // Nofify when we have at least tx_fifo_size/2 space available
495 );
496
497 ral::write_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_1);
498
499 spi
500 }
501
502 /// Indicates if the driver is (`true`) or is not (`false`) enabled.
503 pub fn is_enabled(&self) -> bool {
504 ral::read_reg!(ral::lpspi, self.lpspi, CR, MEN == MEN_1)
505 }
506
507 /// Enable (`true`) or disable (`false`) the peripheral.
508 ///
509 /// Note that disabling does not take effect immediately; instead the
510 /// peripheral finishes the current transfer and then disables itself.
511 /// It is required to check [`is_enabled()`](Self::is_enabled) repeatedly until the
512 /// peripheral is actually disabled.
513 pub fn set_enable(&mut self, enable: bool) {
514 ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: enable as u32)
515 }
516
517 /// Reset the driver.
518 ///
519 /// Note that this may not not reset all peripheral state, like the
520 /// enabled state.
521 pub fn reset(&mut self) {
522 ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_1);
523 while ral::read_reg!(ral::lpspi, self.lpspi, CR, RST == RST_1) {
524 ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0);
525 }
526 }
527
528 /// Release the SPI driver components.
529 ///
530 /// This does not change any component state; it releases the components as-is.
531 /// If you need to obtain the registers in a known, good state, consider calling
532 /// methods like [`reset()`](Self::reset) before releasing the registers.
533 pub fn release(self) -> (ral::lpspi::Instance<N>, P) {
534 (self.lpspi, self.pins)
535 }
536
537 /// Returns the bit order configuration.
538 ///
539 /// See notes in [`set_bit_order`](Lpspi::set_bit_order) to
540 /// understand when this configuration takes effect.
541 pub fn bit_order(&self) -> BitOrder {
542 self.bit_order
543 }
544
545 /// Set the bit order configuration.
546 ///
547 /// This applies to all higher-level write and transfer operations.
548 /// If you're using the [`Transaction`] API with manual word reads
549 /// and writes, set the configuration as part of the transaction.
550 pub fn set_bit_order(&mut self, bit_order: BitOrder) {
551 self.bit_order = bit_order;
552 }
553
554 /// Temporarily disable the LPSPI peripheral.
555 ///
556 /// The handle to a [`Disabled`](crate::lpspi::Disabled) driver lets you modify
557 /// LPSPI settings that require a fully disabled peripheral.
558 pub fn disabled<R>(&mut self, func: impl FnOnce(&mut Disabled<N>) -> R) -> R {
559 let mut disabled = Disabled::new(&mut self.lpspi, &mut self.mode);
560 func(&mut disabled)
561 }
562
563 /// Read the status register.
564 pub fn status(&self) -> Status {
565 Status::from_bits_truncate(ral::read_reg!(ral::lpspi, self.lpspi, SR))
566 }
567
568 /// Clear the status flags.
569 ///
570 /// To clear status flags, set them high, then call `clear_status()`.
571 ///
572 /// The implementation will ensure that only the W1C bits are written, so it's
573 /// OK to supply `Status::all()` to clear all bits.
574 pub fn clear_status(&self, flags: Status) {
575 let flags = flags & Status::W1C;
576 ral::write_reg!(ral::lpspi, self.lpspi, SR, flags.bits());
577 }
578
579 /// Read the interrupt enable bits.
580 pub fn interrupts(&self) -> Interrupts {
581 Interrupts::from_bits_truncate(ral::read_reg!(ral::lpspi, self.lpspi, IER))
582 }
583
584 /// Set the interrupt enable bits.
585 ///
586 /// This writes the bits described by `interrupts` as is to the register.
587 /// To modify the existing interrupts flags, you should first call [`interrupts`](Lpspi::interrupts)
588 /// to get the current state, then modify that state.
589 pub fn set_interrupts(&self, interrupts: Interrupts) {
590 ral::write_reg!(ral::lpspi, self.lpspi, IER, interrupts.bits());
591 }
592
593 /// Clear any existing data in the SPI receive or transfer FIFOs.
594 #[inline]
595 pub fn clear_fifo(&mut self, direction: Direction) {
596 match direction {
597 Direction::Tx => ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1),
598 Direction::Rx => ral::modify_reg!(ral::lpspi, self.lpspi, CR, RRF: RRF_1),
599 }
600 }
601
602 /// Clear both FIFOs.
603 pub fn clear_fifos(&mut self) {
604 ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
605 }
606
607 /// Returns the watermark level for the given direction.
608 #[inline]
609 pub fn watermark(&self, direction: Direction) -> u8 {
610 (match direction {
611 Direction::Rx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, RXWATER),
612 Direction::Tx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, TXWATER),
613 }) as u8
614 }
615
616 /// Returns the FIFO status.
617 #[inline]
618 pub fn fifo_status(&self) -> FifoStatus {
619 let (rxcount, txcount) = ral::read_reg!(ral::lpspi, self.lpspi, FSR, RXCOUNT, TXCOUNT);
620 FifoStatus {
621 rxcount: rxcount as u16,
622 txcount: txcount as u16,
623 }
624 }
625
626 /// Simply read whatever is in the receiver data register.
627 fn read_data_unchecked(&self) -> u32 {
628 ral::read_reg!(ral::lpspi, self.lpspi, RDR)
629 }
630
631 /// Read the data register.
632 ///
633 /// Returns `None` if the receive FIFO is empty. Otherwise, returns the complete
634 /// read of the register. You're reponsible for interpreting the raw value as
635 /// a data word, depending on the frame size.
636 pub fn read_data(&mut self) -> Option<u32> {
637 if ral::read_reg!(ral::lpspi, self.lpspi, RSR, RXEMPTY == RXEMPTY_0) {
638 Some(self.read_data_unchecked())
639 } else {
640 None
641 }
642 }
643
644 /// Place `word` into the transmit FIFO.
645 ///
646 /// This will result in the value being sent from the LPSPI.
647 /// You're responsible for making sure that the transmit FIFO can
648 /// fit this word.
649 pub fn enqueue_data(&self, word: u32) {
650 ral::write_reg!(ral::lpspi, self.lpspi, TDR, word);
651 }
652
653 /// Wait for transmit FIFO space in a (concurrent) spin loop.
654 ///
655 /// This future does not care about the TX FIFO watermark. Instead, it
656 /// checks the FIFO's size with an additional read.
657 pub(crate) async fn spin_for_fifo_space(&self) -> Result<(), LpspiError> {
658 core::future::poll_fn(|_| {
659 let status = self.status();
660 if status.intersects(Status::TRANSMIT_ERROR) {
661 return Poll::Ready(Err(LpspiError::Fifo(Direction::Tx)));
662 }
663 let fifo_status = self.fifo_status();
664 if !fifo_status.is_full(Direction::Tx) {
665 Poll::Ready(Ok(()))
666 } else {
667 Poll::Pending
668 }
669 })
670 .await
671 }
672
673 pub(crate) fn wait_for_transmit_fifo_space(&self) -> Result<(), LpspiError> {
674 crate::spin_on(self.spin_for_fifo_space())
675 }
676
677 /// Wait for receive data in a (concurrent) spin loop.
678 ///
679 /// This future does not care about the RX FIFO watermark. Instead, it
680 /// checks the FIFO's size with an additional read.
681 async fn spin_for_word(&self) -> Result<u32, LpspiError> {
682 core::future::poll_fn(|_| {
683 let status = self.status();
684 if status.intersects(Status::RECEIVE_ERROR) {
685 return Poll::Ready(Err(LpspiError::Fifo(Direction::Rx)));
686 }
687
688 let fifo_status = self.fifo_status();
689 if !fifo_status.is_empty(Direction::Rx) {
690 let data = self.read_data_unchecked();
691 Poll::Ready(Ok(data))
692 } else {
693 Poll::Pending
694 }
695 })
696 .await
697 }
698
699 /// Send `len` LPSPI words (u32s) out of the peripheral.
700 ///
701 /// Expected to run in a (concurrent) spin loop, possibly with
702 /// `spin_receive`.
703 async fn spin_transmit(
704 &self,
705 mut data: impl TransmitData,
706 len: usize,
707 ) -> Result<(), LpspiError> {
708 for _ in 0..len {
709 self.spin_for_fifo_space().await?;
710 let word = data.next_word(self.bit_order);
711 self.enqueue_data(word);
712 }
713 Ok(())
714 }
715
716 /// Accept `len` LPSPI words (u32s) from the peripheral.
717 ///
718 /// Expected to run in a (concurrent) spin loop, possibly with
719 /// `spin_transmit`.
720 async fn spin_receive(&self, mut data: impl ReceiveData, len: usize) -> Result<(), LpspiError> {
721 for _ in 0..len {
722 let word = self.spin_for_word().await?;
723 data.next_word(self.bit_order, word);
724 }
725 Ok(())
726 }
727
728 /// Set the SPI mode for the peripheral.
729 ///
730 /// This only affects the next transfer; ongoing transfers
731 /// will not be influenced.
732 pub fn set_mode(&mut self, mode: Mode) {
733 self.mode = mode;
734 }
735
736 /// Place a transaction definition into the transmit FIFO.
737 ///
738 /// Once this definition is popped from the transmit FIFO, this may
739 /// affect, or abort, any ongoing transactions.
740 ///
741 /// You're responsible for making sure there's space in the transmit
742 /// FIFO for this transaction command.
743 pub fn enqueue_transaction(&mut self, transaction: &Transaction) {
744 ral::write_reg!(ral::lpspi, self.lpspi, TCR,
745 CPOL: if self.mode.polarity == Polarity::IdleHigh { CPOL_1 } else { CPOL_0 },
746 CPHA: if self.mode.phase == Phase::CaptureOnSecondTransition { CPHA_1 } else { CPHA_0 },
747 PRESCALE: PRESCALE_0,
748 PCS: PCS_0,
749 WIDTH: WIDTH_0,
750 LSBF: transaction.bit_order as u32,
751 BYSW: transaction.byte_swap as u32,
752 RXMSK: transaction.receive_data_mask as u32,
753 TXMSK: transaction.transmit_data_mask as u32,
754 FRAMESZ: transaction.frame_size as u32,
755 CONT: transaction.continuous as u32,
756 CONTC: transaction.continuing as u32
757 );
758 }
759
760 /// Wait for all ongoing transactions to be finished.
761 pub fn flush(&mut self) -> Result<(), LpspiError> {
762 loop {
763 let status = self.status();
764
765 if status.intersects(Status::RECEIVE_ERROR) {
766 return Err(LpspiError::Fifo(Direction::Rx));
767 }
768 if status.intersects(Status::TRANSMIT_ERROR) {
769 return Err(LpspiError::Fifo(Direction::Tx));
770 }
771
772 // Contributor testing reveals that the busy flag may not set once
773 // the TX FIFO is filled. This means a sequence like
774 //
775 // lpspi.write(&[...])?;
776 // lpspi.flush()?;
777 //
778 // could pass through flush without observing busy. Therefore, we
779 // also check the FIFO contents. Even if the peripheral isn't
780 // busy, the FIFO should be non-empty.
781 //
782 // We can't just rely on the FIFO contents, since the FIFO could be
783 // empty while the transaction is completing. (There's data in the
784 // shift register, and PCS is still asserted.)
785 if !status.intersects(Status::BUSY) && self.fifo_status().is_empty(Direction::Tx) {
786 return Ok(());
787 }
788 }
789 }
790
791 fn exchange<W: Word>(&mut self, data: &mut [W]) -> Result<(), LpspiError> {
792 if data.is_empty() {
793 return Ok(());
794 }
795
796 let mut transaction = Transaction::new_words(data)?;
797 transaction.bit_order = self.bit_order();
798
799 self.wait_for_transmit_fifo_space()?;
800 self.enqueue_transaction(&transaction);
801
802 let word_count = word_count(data);
803 let (tx, rx) = transfer_in_place(data);
804
805 crate::spin_on(futures::future::try_join(
806 self.spin_transmit(tx, word_count),
807 self.spin_receive(rx, word_count),
808 ))
809 .inspect_err(|_| self.recover_from_error())?;
810
811 self.flush()?;
812
813 Ok(())
814 }
815
816 fn write_no_read<W: Word>(&mut self, data: &[W]) -> Result<(), LpspiError> {
817 if data.is_empty() {
818 return Ok(());
819 }
820
821 let mut transaction = Transaction::new_words(data)?;
822 transaction.receive_data_mask = true;
823 transaction.bit_order = self.bit_order();
824
825 self.wait_for_transmit_fifo_space()?;
826 self.enqueue_transaction(&transaction);
827
828 let word_count = word_count(data);
829 let tx = TransmitBuffer::new(data);
830
831 crate::spin_on(self.spin_transmit(tx, word_count)).inspect_err(|_| {
832 self.recover_from_error();
833 })?;
834
835 self.flush()?;
836
837 Ok(())
838 }
839
840 /// Let the peripheral act as a DMA source.
841 ///
842 /// After this call, the peripheral will signal to the DMA engine whenever
843 /// it has data available to read.
844 pub fn enable_dma_receive(&mut self) {
845 ral::modify_reg!(ral::lpspi, self.lpspi, FCR, RXWATER: 0); // No watermarks; affects DMA signaling
846 ral::modify_reg!(ral::lpspi, self.lpspi, DER, RDDE: 1);
847 }
848
849 /// Stop the peripheral from acting as a DMA source.
850 ///
851 /// See the DMA chapter in the reference manual to understand when this
852 /// should be called in the DMA transfer lifecycle.
853 pub fn disable_dma_receive(&mut self) {
854 while ral::read_reg!(ral::lpspi, self.lpspi, DER, RDDE == 1) {
855 ral::modify_reg!(ral::lpspi, self.lpspi, DER, RDDE: 0);
856 }
857 }
858
859 /// Let the peripheral act as a DMA destination.
860 ///
861 /// After this call, the peripheral will signal to the DMA engine whenever
862 /// it has free space in its transfer buffer.
863 pub fn enable_dma_transmit(&mut self) {
864 ral::modify_reg!(ral::lpspi, self.lpspi, FCR, TXWATER: 0); // No watermarks; affects DMA signaling
865 ral::modify_reg!(ral::lpspi, self.lpspi, DER, TDDE: 1);
866 }
867
868 /// Stop the peripheral from acting as a DMA destination.
869 ///
870 /// See the DMA chapter in the reference manual to understand when this
871 /// should be called in the DMA transfer lifecycle.
872 pub fn disable_dma_transmit(&mut self) {
873 while ral::read_reg!(ral::lpspi, self.lpspi, DER, TDDE == 1) {
874 ral::modify_reg!(ral::lpspi, self.lpspi, DER, TDDE: 0);
875 }
876 }
877
878 /// Produces a pointer to the receiver data register.
879 ///
880 /// You should use this pointer when coordinating a DMA transfer.
881 /// You're not expected to read from this pointer in software.
882 pub fn rdr(&self) -> *const ral::RORegister<u32> {
883 core::ptr::addr_of!(self.lpspi.RDR)
884 }
885
886 /// Produces a pointer to the transfer data register.
887 ///
888 /// You should use this pointer when coordinating a DMA transfer.
889 /// You're not expected to read from this pointer in software.
890 pub fn tdr(&self) -> *const ral::WORegister<u32> {
891 core::ptr::addr_of!(self.lpspi.TDR)
892 }
893
894 fn max_watermark(&self, direction: Direction) -> u8 {
895 (match direction {
896 Direction::Rx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, RXFIFO),
897 Direction::Tx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, TXFIFO),
898 }) as u8
899 }
900
901 /// Reset all internal logic while preserving the driver's configurations.
902 ///
903 /// Unlike [`reset()`](Self::reset), this preserves all peripheral registers.
904 pub fn soft_reset(&mut self) {
905 // Backup previous registers
906 let ier = ral::read_reg!(ral::lpspi, self.lpspi, IER);
907 let der = ral::read_reg!(ral::lpspi, self.lpspi, DER);
908 let cfgr0 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR0);
909 let cfgr1 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR1);
910 let dmr0 = ral::read_reg!(ral::lpspi, self.lpspi, DMR0);
911 let dmr1 = ral::read_reg!(ral::lpspi, self.lpspi, DMR1);
912 let ccr = ral::read_reg!(ral::lpspi, self.lpspi, CCR);
913 let fcr = ral::read_reg!(ral::lpspi, self.lpspi, FCR);
914
915 // Backup enabled state
916 let enabled = self.is_enabled();
917
918 // Reset and disable
919 ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: MEN_0, RST: RST_1);
920 while self.is_enabled() {}
921 ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0);
922
923 // Reset fifos
924 ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
925
926 // Restore settings
927 ral::write_reg!(ral::lpspi, self.lpspi, IER, ier);
928 ral::write_reg!(ral::lpspi, self.lpspi, DER, der);
929 ral::write_reg!(ral::lpspi, self.lpspi, CFGR0, cfgr0);
930 ral::write_reg!(ral::lpspi, self.lpspi, CFGR1, cfgr1);
931 ral::write_reg!(ral::lpspi, self.lpspi, DMR0, dmr0);
932 ral::write_reg!(ral::lpspi, self.lpspi, DMR1, dmr1);
933 ral::write_reg!(ral::lpspi, self.lpspi, CCR, ccr);
934 ral::write_reg!(ral::lpspi, self.lpspi, FCR, fcr);
935
936 // Restore enabled state
937 self.set_enable(enabled);
938 }
939
940 /// Set the watermark level for a given direction.
941 ///
942 /// Returns the watermark level committed to the hardware. This may be different
943 /// than the supplied `watermark`, since it's limited by the hardware.
944 ///
945 /// When `direction == Direction::Rx`, the receive data flag is set whenever the
946 /// number of words in the receive FIFO is greater than `watermark`.
947 ///
948 /// When `direction == Direction::Tx`, the transmit data flag is set whenever the
949 /// the number of words in the transmit FIFO is less than, or equal, to `watermark`.
950 #[inline]
951 pub fn set_watermark(&mut self, direction: Direction, watermark: u8) -> u8 {
952 set_watermark(&self.lpspi, direction, watermark)
953 }
954
955 /// Recover from a transaction error.
956 fn recover_from_error(&mut self) {
957 // Resets the peripheral and flushes whatever is in the FIFOs.
958 self.soft_reset();
959
960 // Reset the status flags, clearing the error condition for the next use.
961 self.clear_status(Status::TRANSMIT_ERROR | Status::RECEIVE_ERROR);
962 }
963
964 /// Return the driver's clock configurations.
965 ///
966 /// These values are decided by calls to [`set_clock_hz`](Disabled::set_clock_hz)
967 /// and [`set_clock_configs`](Disabled::set_clock_configs).
968 pub fn clock_configs(&self) -> ClockConfigs {
969 let (sckpcs, pcssck, dbt, sckdiv) =
970 ral::read_reg!(ral::lpspi, self.lpspi, CCR, SCKPCS, PCSSCK, DBT, SCKDIV);
971 ClockConfigs {
972 sckpcs: sckpcs as u8,
973 pcssck: pcssck as u8,
974 dbt: dbt as u8,
975 sckdiv: sckdiv as u8,
976 }
977 }
978}
979
980bitflags::bitflags! {
981 /// Status flags for the LPSPI interface.
982 pub struct Status : u32 {
983 /// Module busy flag.
984 ///
985 /// This flag is read only.
986 const BUSY = 1 << 24;
987
988 //
989 // Start W1C bits.
990 //
991
992 /// Data match flag.
993 ///
994 /// Indicates that received data has matched one or both of the match
995 /// fields. To clear this flag, write this bit to the status register
996 /// (W1C).
997 const DATA_MATCH = 1 << 13;
998 /// Receive error flag.
999 ///
1000 /// Set when the receive FIFO has overflowed. Before clearing this bit,
1001 /// empty the receive FIFO. Then, write this bit to clear the flag (W1C).
1002 const RECEIVE_ERROR = 1 << 12;
1003 /// Transmit error flag.
1004 ///
1005 /// Set when the transmit FIFO has underruns. Before clearing this bit,
1006 /// end the transfer. Then, write this bit to clear the flag (W1C).
1007 const TRANSMIT_ERROR = 1 << 11;
1008 /// Transfer complete flag.
1009 ///
1010 /// Set when the LPSPI returns to an idle state, and the transmit FIFO
1011 /// is empty. To clear this flag, write this bit (W1C).
1012 const TRANSFER_COMPLETE = 1 << 10;
1013 /// Frame complete flag.
1014 ///
1015 /// Set at the end of each frame transfer, when PCS negates. To clear this
1016 /// flag, write this bit (W1C).
1017 const FRAME_COMPLETE = 1 << 9;
1018 /// Word complete flag.
1019 ///
1020 /// Set when the last bit of a received word is sampled. To clear this flag, write
1021 /// this bit (W1C).
1022 const WORD_COMPLETE = 1 << 8;
1023
1024 //
1025 // End W1C bits.
1026 //
1027
1028 /// Receive data flag.
1029 ///
1030 /// Set when the number of words in the receive FIFO is greater than the watermark.
1031 /// This flag is read only. To clear the flag, exhaust the receive FIFO.
1032 const RECEIVE_DATA = 1 << 1;
1033 /// Transmit data flag.
1034 ///
1035 /// Set when the number of words in the transmit FIFO is less than or equal to the
1036 /// watermark. This flag is read only. TO clear the flag, fill the transmit FIFO.
1037 const TRANSMIT_DATA = 1 << 0;
1038 }
1039}
1040
1041impl Status {
1042 const W1C: Self = Self::from_bits_truncate(
1043 Self::DATA_MATCH.bits()
1044 | Self::RECEIVE_ERROR.bits()
1045 | Self::TRANSMIT_ERROR.bits()
1046 | Self::TRANSFER_COMPLETE.bits()
1047 | Self::FRAME_COMPLETE.bits()
1048 | Self::WORD_COMPLETE.bits(),
1049 );
1050}
1051
1052/// The number of words in each FIFO.
1053#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1054pub struct FifoStatus {
1055 /// Number of words in the receive FIFO.
1056 pub rxcount: u16,
1057 /// Number of words in the transmit FIFO.
1058 pub txcount: u16,
1059}
1060
1061impl FifoStatus {
1062 /// Indicates if the FIFO is full for the given direction.
1063 #[inline]
1064 pub const fn is_full(self, direction: Direction) -> bool {
1065 /// See PARAM register docs.
1066 const MAX_FIFO_SIZE: u16 = 16;
1067 let count = match direction {
1068 Direction::Tx => self.txcount,
1069 Direction::Rx => self.rxcount,
1070 };
1071 count >= MAX_FIFO_SIZE
1072 }
1073 /// Indicates if the FIFO is empty for the given direction.
1074 #[inline]
1075 const fn is_empty(self, direction: Direction) -> bool {
1076 0 == match direction {
1077 Direction::Tx => self.txcount,
1078 Direction::Rx => self.rxcount,
1079 }
1080 }
1081}
1082
1083bitflags::bitflags! {
1084 /// Interrupt flags.
1085 ///
1086 /// A high bit indicates that the condition generates an interrupt.
1087 /// See the status bits for more information.
1088 pub struct Interrupts : u32 {
1089 /// Data match interrupt enable.
1090 const DATA_MATCH = 1 << 13;
1091 /// Receive error interrupt enable.
1092 const RECEIVE_ERROR = 1 << 12;
1093 /// Transmit error interrupt enable.
1094 const TRANSMIT_ERROR = 1 << 11;
1095 /// Transmit complete interrupt enable.
1096 const TRANSMIT_COMPLETE = 1 << 10;
1097 /// Frame complete interrupt enable.
1098 const FRAME_COMPLETE = 1 << 9;
1099 /// Word complete interrupt enable.
1100 const WORD_COMPLETE = 1 << 8;
1101
1102 /// Receive data interrupt enable.
1103 const RECEIVE_DATA = 1 << 1;
1104 /// Transmit data interrupt enable.
1105 const TRANSMIT_DATA = 1 << 0;
1106 }
1107}
1108
1109#[inline]
1110fn set_watermark(lpspi: &ral::lpspi::RegisterBlock, direction: Direction, watermark: u8) -> u8 {
1111 let max_watermark = match direction {
1112 Direction::Rx => 1 << ral::read_reg!(ral::lpspi, lpspi, PARAM, RXFIFO),
1113 Direction::Tx => 1 << ral::read_reg!(ral::lpspi, lpspi, PARAM, TXFIFO),
1114 };
1115
1116 let watermark = watermark.min(max_watermark - 1);
1117
1118 match direction {
1119 Direction::Rx => {
1120 ral::modify_reg!(ral::lpspi, lpspi, FCR, RXWATER: watermark as u32)
1121 }
1122 Direction::Tx => {
1123 ral::modify_reg!(ral::lpspi, lpspi, FCR, TXWATER: watermark as u32)
1124 }
1125 }
1126
1127 watermark
1128}
1129
1130/// An LPSPI peripheral which is temporarily disabled.
1131pub struct Disabled<'a, const N: u8> {
1132 lpspi: &'a ral::lpspi::Instance<N>,
1133 mode: &'a mut Mode,
1134 men: bool,
1135}
1136
1137impl<'a, const N: u8> Disabled<'a, N> {
1138 fn new(lpspi: &'a mut ral::lpspi::Instance<N>, mode: &'a mut Mode) -> Self {
1139 let men = ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1);
1140
1141 // Request disable
1142 ral::modify_reg!(ral::lpspi, lpspi, CR, MEN: MEN_0);
1143 // Wait for the driver to finish its current transfer
1144 // and enter disabled state
1145 while ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1) {}
1146 Self { lpspi, mode, men }
1147 }
1148
1149 /// Set the SPI mode for the peripheral
1150 #[deprecated(
1151 since = "0.5.5",
1152 note = "Use Lpspi::set_mode to change modes while enabled."
1153 )]
1154 pub fn set_mode(&mut self, mode: Mode) {
1155 *self.mode = mode;
1156 }
1157
1158 /// Set the LPSPI clock speed (Hz).
1159 ///
1160 /// `source_clock_hz` is the LPSPI peripheral clock speed. To specify the
1161 /// peripheral clock, see the [`ccm::lpspi_clk`](crate::ccm::lpspi_clk) documentation.
1162 pub fn set_clock_hz(&mut self, source_clock_hz: u32, clock_hz: u32) {
1163 set_spi_clock(source_clock_hz, clock_hz, self.lpspi);
1164 }
1165
1166 /// Set LPSPI timing configurations.
1167 ///
1168 /// If you're not sure how to select these timing values, prefer
1169 /// [`set_clock_hz`](Self::set_clock_hz).
1170 pub fn set_clock_configs(&mut self, timing: ClockConfigs) {
1171 ral::write_reg!(ral::lpspi, self.lpspi, CCR,
1172 SCKPCS: timing.sckpcs as u32,
1173 PCSSCK: timing.pcssck as u32,
1174 DBT: timing.dbt as u32,
1175 SCKDIV: timing.sckdiv as u32,
1176 );
1177 }
1178
1179 /// Set the watermark level for a given direction.
1180 ///
1181 /// Returns the watermark level committed to the hardware. This may be different
1182 /// than the supplied `watermark`, since it's limited by the hardware.
1183 ///
1184 /// When `direction == Direction::Rx`, the receive data flag is set whenever the
1185 /// number of words in the receive FIFO is greater than `watermark`.
1186 ///
1187 /// When `direction == Direction::Tx`, the transmit data flag is set whenever the
1188 /// the number of words in the transmit FIFO is less than, or equal, to `watermark`.
1189 #[inline]
1190 #[deprecated(
1191 since = "0.5.5",
1192 note = "Use Lpspi::set_watermark to change watermark while enabled"
1193 )]
1194 pub fn set_watermark(&mut self, direction: Direction, watermark: u8) -> u8 {
1195 set_watermark(self.lpspi, direction, watermark)
1196 }
1197
1198 /// Set the sampling point of the LPSPI peripheral.
1199 ///
1200 /// When set to `SamplePoint::DelayedEdge`, the LPSPI will sample the input data
1201 /// on a delayed LPSPI_SCK edge, which improves the setup time when sampling data.
1202 #[inline]
1203 pub fn set_sample_point(&mut self, sample_point: SamplePoint) {
1204 match sample_point {
1205 SamplePoint::Edge => ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, SAMPLE: SAMPLE_0),
1206 SamplePoint::DelayedEdge => {
1207 ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, SAMPLE: SAMPLE_1)
1208 }
1209 }
1210 }
1211
1212 /// Become an LPSPI peripheral.
1213 ///
1214 /// By default, the LPSPI driver acts as a controller, driving I/O.
1215 /// By enabling peripheral functions (`true`), you can accept
1216 /// and react to another controller's I/O. When you're acting as a
1217 /// peripheral, you don't control the clock and chip select lines.
1218 #[inline]
1219 pub fn set_peripheral_enable(&mut self, enable: bool) {
1220 ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, MASTER: !enable as u32);
1221 }
1222}
1223
1224impl<const N: u8> Drop for Disabled<'_, N> {
1225 fn drop(&mut self) {
1226 ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: self.men as u32);
1227 }
1228}
1229
1230impl<P, const N: u8> eh02::blocking::spi::Transfer<u8> for Lpspi<P, N> {
1231 type Error = LpspiError;
1232
1233 fn transfer<'a>(&mut self, words: &'a mut [u8]) -> Result<&'a [u8], Self::Error> {
1234 self.exchange(words)?;
1235 Ok(words)
1236 }
1237}
1238
1239impl<P, const N: u8> eh02::blocking::spi::Transfer<u16> for Lpspi<P, N> {
1240 type Error = LpspiError;
1241
1242 fn transfer<'a>(&mut self, words: &'a mut [u16]) -> Result<&'a [u16], Self::Error> {
1243 self.exchange(words)?;
1244 Ok(words)
1245 }
1246}
1247
1248impl<P, const N: u8> eh02::blocking::spi::Transfer<u32> for Lpspi<P, N> {
1249 type Error = LpspiError;
1250
1251 fn transfer<'a>(&mut self, words: &'a mut [u32]) -> Result<&'a [u32], Self::Error> {
1252 self.exchange(words)?;
1253 Ok(words)
1254 }
1255}
1256
1257impl<P, const N: u8> eh02::blocking::spi::Write<u8> for Lpspi<P, N> {
1258 type Error = LpspiError;
1259
1260 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1261 self.write_no_read(words)
1262 }
1263}
1264
1265impl<P, const N: u8> eh02::blocking::spi::Write<u16> for Lpspi<P, N> {
1266 type Error = LpspiError;
1267
1268 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
1269 self.write_no_read(words)
1270 }
1271}
1272
1273impl<P, const N: u8> eh02::blocking::spi::Write<u32> for Lpspi<P, N> {
1274 type Error = LpspiError;
1275
1276 fn write(&mut self, words: &[u32]) -> Result<(), Self::Error> {
1277 self.write_no_read(words)
1278 }
1279}
1280
1281// Not supporting WriteIter right now. Since we don't know how many bytes we're
1282// going to write, we can't specify the frame size. There might be ways around
1283// this by playing with CONTC and CONT bits, but we can evaluate that later.
1284
1285/// Describes SPI words that can participate in transactions.
1286trait Word: Copy + Into<u32> + TryFrom<u32> {
1287 /// Repeatedly call `provider` to produce yourself,
1288 /// then turn yourself into a LPSPI word.
1289 fn pack_word(bit_order: BitOrder, provider: impl FnMut() -> Option<Self>) -> u32;
1290
1291 /// Given a word, deconstruct the word and call the
1292 /// `sink` with those components. `valid_bytes` conveys
1293 /// how many bytes in `word` are valid. It's never more
1294 /// than four, and it's never zero.
1295 fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, sink: impl FnMut(Self));
1296}
1297
1298impl Word for u8 {
1299 fn pack_word(bit_order: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
1300 let mut word = 0;
1301 match bit_order {
1302 BitOrder::Msb => {
1303 for _ in 0..4 {
1304 if let Some(byte) = provider() {
1305 word <<= 8;
1306 word |= u32::from(byte);
1307 }
1308 }
1309 }
1310 BitOrder::Lsb => {
1311 for offset in 0..4 {
1312 if let Some(byte) = provider() {
1313 word |= u32::from(byte) << (8 * offset);
1314 }
1315 }
1316 }
1317 }
1318
1319 word
1320 }
1321 fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, mut sink: impl FnMut(Self)) {
1322 let mut offsets = [0usize, 8, 16, 24];
1323 let valid = &mut offsets[..valid_bytes];
1324 if matches!(bit_order, BitOrder::Msb) {
1325 valid.reverse();
1326 }
1327 for offset in valid {
1328 sink((word >> *offset) as u8);
1329 }
1330 }
1331}
1332
1333impl Word for u16 {
1334 fn pack_word(bit_order: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
1335 let mut word = 0;
1336 match bit_order {
1337 BitOrder::Msb => {
1338 for _ in 0..2 {
1339 if let Some(half) = provider() {
1340 word <<= 16;
1341 word |= u32::from(half);
1342 }
1343 }
1344 }
1345 BitOrder::Lsb => {
1346 for offset in 0..2 {
1347 if let Some(half) = provider() {
1348 word |= u32::from(half) << (16 * offset);
1349 }
1350 }
1351 }
1352 }
1353
1354 word
1355 }
1356 fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, mut sink: impl FnMut(Self)) {
1357 let mut offsets = [0usize, 16];
1358 let valid = &mut offsets[..valid_bytes / 2];
1359
1360 if matches!(bit_order, BitOrder::Msb) {
1361 valid.reverse();
1362 }
1363
1364 for offset in valid {
1365 sink((word >> *offset) as u16);
1366 }
1367 }
1368}
1369
1370impl Word for u32 {
1371 fn pack_word(_: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
1372 provider().unwrap_or(0)
1373 }
1374 fn unpack_word(word: u32, _: BitOrder, _: usize, mut sink: impl FnMut(Self)) {
1375 sink(word)
1376 }
1377}
1378
1379/// Generalizes how we prepare LPSPI words for transmit.
1380trait TransmitData {
1381 /// Get the next word for the transmit FIFO.
1382 ///
1383 /// If you're out of words, return 0.
1384 fn next_word(&mut self, bit_order: BitOrder) -> u32;
1385}
1386
1387/// Generalizes how we save LPSPI data into memory.
1388trait ReceiveData {
1389 /// Invoked each time we read data from the queue.
1390 fn next_word(&mut self, bit_order: BitOrder, word: u32);
1391}
1392
1393/// Transmit data from a buffer.
1394struct TransmitBuffer<'a, W> {
1395 /// The read position.
1396 ptr: *const W,
1397 /// At the end of the buffer.
1398 end: *const W,
1399 _buffer: PhantomData<&'a [W]>,
1400}
1401
1402impl<'a, W> TransmitBuffer<'a, W>
1403where
1404 W: Word,
1405{
1406 fn new(buffer: &'a [W]) -> Self {
1407 // Safety: pointer offset math meets expectations.
1408 unsafe { Self::from_raw(buffer.as_ptr(), buffer.len()) }
1409 }
1410
1411 /// # Safety
1412 ///
1413 /// `ptr + len` must be in bounds, or at the end of the
1414 /// allocation.
1415 unsafe fn from_raw(ptr: *const W, len: usize) -> Self {
1416 Self {
1417 ptr,
1418 // Safety: caller upholds contract that ptr + len
1419 // must be in bounds, or at the end.
1420 end: unsafe { ptr.add(len) },
1421 _buffer: PhantomData,
1422 }
1423 }
1424
1425 /// Read the next element from the buffer.
1426 fn next_read(&mut self) -> Option<W> {
1427 // Safety: read the next word only if we're in bounds.
1428 unsafe {
1429 (!core::ptr::eq(self.ptr, self.end)).then(|| {
1430 let word = self.ptr.read();
1431 self.ptr = self.ptr.add(1);
1432 word
1433 })
1434 }
1435 }
1436}
1437
1438impl<W> TransmitData for TransmitBuffer<'_, W>
1439where
1440 W: Word,
1441{
1442 fn next_word(&mut self, bit_order: BitOrder) -> u32 {
1443 W::pack_word(bit_order, || self.next_read())
1444 }
1445}
1446
1447/// Receive data into a buffer.
1448struct ReceiveBuffer<'a, W> {
1449 /// The write position.
1450 ptr: *mut W,
1451 /// At the end of the buffer.
1452 end: *const W,
1453 _buffer: PhantomData<&'a [W]>,
1454}
1455
1456impl<W> ReceiveBuffer<'_, W>
1457where
1458 W: Word,
1459{
1460 #[cfg(test)] // TODO(mciantyre) remove once needed in non-test code.
1461 fn new(buffer: &mut [W]) -> Self {
1462 // Safety: pointer offset math meets expectations.
1463 unsafe { Self::from_raw(buffer.as_mut_ptr(), buffer.len()) }
1464 }
1465
1466 /// # Safety
1467 ///
1468 /// `ptr + len` must be in bounds, or at the end of the
1469 /// allocation.
1470 unsafe fn from_raw(ptr: *mut W, len: usize) -> Self {
1471 Self {
1472 ptr,
1473 // Safety: caller upholds contract that ptr + len
1474 // must be in bounds, or at the end.
1475 end: unsafe { ptr.cast_const().add(len) },
1476 _buffer: PhantomData,
1477 }
1478 }
1479
1480 /// Put the next element into the buffer.
1481 fn next_write(&mut self, elem: W) {
1482 // Safety: write the next word only if we're in bounds.
1483 // Words are primitive types; we don't need to execute
1484 // a drop when we overwrite a value in memory.
1485 unsafe {
1486 if !core::ptr::eq(self.ptr.cast_const(), self.end) {
1487 self.ptr.write(elem);
1488 self.ptr = self.ptr.add(1);
1489 }
1490 }
1491 }
1492
1493 fn array_len(&self) -> usize {
1494 // Safety: end and ptr derive from the same allocation.
1495 // We always update ptr in multiples of it's object type.
1496 // The end pointer is always at a higher address in memory.
1497 unsafe { self.end.byte_offset_from(self.ptr) as _ }
1498 }
1499}
1500
1501impl<W> ReceiveData for ReceiveBuffer<'_, W>
1502where
1503 W: Word,
1504{
1505 fn next_word(&mut self, bit_order: BitOrder, word: u32) {
1506 let valid_bytes = self.array_len().min(size_of_val(&word));
1507 W::unpack_word(word, bit_order, valid_bytes, |elem| self.next_write(elem));
1508 }
1509}
1510
1511/// Computes how may Ws fit inside a LPSPI word.
1512const fn per_word<W: Word>() -> usize {
1513 core::mem::size_of::<u32>() / core::mem::size_of::<W>()
1514}
1515
1516/// Computes how many u32 words we need to transact this buffer.
1517const fn word_count<W: Word>(words: &[W]) -> usize {
1518 words.len().div_ceil(per_word::<W>())
1519}
1520
1521/// Creates the transmit and receive buffer objects for an
1522/// in-place transfer.
1523fn transfer_in_place<W: Word>(buffer: &mut [W]) -> (TransmitBuffer<'_, W>, ReceiveBuffer<'_, W>) {
1524 // Safety: pointer math meets expectation. This produces
1525 // a mutable and immutable pointer to the same mutable buffer.
1526 // Module inspection shows that these pointers never become
1527 // references. We maintain the lifetime across both objects,
1528 // so the buffer isn't dropped.
1529 unsafe {
1530 let len = buffer.len();
1531 let ptr = buffer.as_mut_ptr();
1532 (
1533 TransmitBuffer::from_raw(ptr, len),
1534 ReceiveBuffer::from_raw(ptr, len),
1535 )
1536 }
1537}
1538
1539/// Tests try to approximate the way we'll use TransmitBuffer and ReceiveBuffer
1540/// in firmware. Consider running these with miri to evaluate unsafe usages.
1541#[cfg(test)]
1542mod tests {
1543 #[test]
1544 fn transfer_in_place_interleaved_read_write_u32() {
1545 const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
1546 let mut buffer = BUFFER;
1547 let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
1548
1549 for elem in BUFFER {
1550 assert_eq!(elem, tx.next_read().unwrap());
1551 rx.next_write(elem + 1);
1552 }
1553
1554 assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
1555 }
1556
1557 #[test]
1558 fn transfer_in_place_interleaved_write_read_u32() {
1559 const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
1560 let mut buffer = BUFFER;
1561 let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
1562
1563 for elem in BUFFER {
1564 rx.next_write(elem + 1);
1565 assert_eq!(elem + 1, tx.next_read().unwrap());
1566 }
1567
1568 assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
1569 }
1570
1571 #[test]
1572 fn transfer_in_place_bulk_read_write_u32() {
1573 const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
1574 let mut buffer = BUFFER;
1575 let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
1576
1577 for elem in BUFFER {
1578 assert_eq!(elem, tx.next_read().unwrap());
1579 }
1580 for elem in BUFFER {
1581 rx.next_write(elem + 1);
1582 }
1583
1584 assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
1585 }
1586
1587 #[test]
1588 fn transfer_in_place_bulk_write_read_u32() {
1589 const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
1590 let mut buffer = BUFFER;
1591 let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
1592
1593 for elem in BUFFER {
1594 rx.next_write(elem + 1);
1595 }
1596 for elem in BUFFER {
1597 assert_eq!(elem + 1, tx.next_read().unwrap());
1598 }
1599
1600 assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
1601 }
1602
1603 #[test]
1604 fn transmit_buffer() {
1605 use super::{BitOrder::*, TransmitBuffer, TransmitData};
1606
1607 //
1608 // u32
1609 //
1610 // This is the easiest to understand w.r.t. the bit order, since this is the natural word
1611 // size of the peripheral. No matter the bit order, we produce the same word for the TX
1612 // FIFO. The hardware handles the MSB or LSB transform.
1613
1614 let mut tx = TransmitBuffer::new(&[0xDEADBEEFu32, 0xAD1CAC1D]);
1615 assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
1616 assert_eq!(tx.next_word(Msb), 0xAD1CAC1D);
1617 assert_eq!(tx.next_word(Msb), 0);
1618
1619 let mut tx = TransmitBuffer::new(&[0xDEADBEEFu32, 0xAD1CAC1D]);
1620 assert_eq!(tx.next_word(Lsb), 0xDEADBEEF);
1621 assert_eq!(tx.next_word(Lsb), 0xAD1CAC1D);
1622 assert_eq!(tx.next_word(Lsb), 0);
1623
1624 //
1625 // u8
1626 //
1627 // If the user prefers u8 words, then we should pack the bytes into a u32 such that the
1628 // hardware's MSB/LSB transform maintains the (literal) byte order.
1629
1630 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D]);
1631 assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
1632 assert_eq!(tx.next_word(Msb), 0x00A5001D);
1633 assert_eq!(tx.next_word(Msb), 0);
1634 assert_eq!(tx.next_word(Msb), 0);
1635
1636 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D]);
1637 assert_eq!(tx.next_word(Lsb), 0xEFBEADDE);
1638 assert_eq!(tx.next_word(Lsb), 0x001D00A5);
1639 assert_eq!(tx.next_word(Lsb), 0);
1640 assert_eq!(tx.next_word(Lsb), 0);
1641
1642 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF]);
1643 assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
1644 assert_eq!(tx.next_word(Msb), 0);
1645 assert_eq!(tx.next_word(Msb), 0);
1646
1647 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF]);
1648 assert_eq!(tx.next_word(Lsb), 0xEFBEADDE);
1649 assert_eq!(tx.next_word(Lsb), 0);
1650 assert_eq!(tx.next_word(Lsb), 0);
1651
1652 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE]);
1653 assert_eq!(tx.next_word(Msb), 0x00DEADBE);
1654 assert_eq!(tx.next_word(Msb), 0);
1655 assert_eq!(tx.next_word(Msb), 0);
1656
1657 let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE]);
1658 assert_eq!(tx.next_word(Lsb), 0x00BEADDE);
1659 assert_eq!(tx.next_word(Lsb), 0);
1660 assert_eq!(tx.next_word(Lsb), 0);
1661
1662 //
1663 // u16
1664 //
1665 // Same goes here: we should combine u16s such that the hardware transfers elements
1666 // in order while applying the MSB/LSB transform on each u16.
1667
1668 let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF, 0xA5A5]);
1669 assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
1670 assert_eq!(tx.next_word(Msb), 0x0000A5A5);
1671 assert_eq!(tx.next_word(Msb), 0);
1672 assert_eq!(tx.next_word(Msb), 0);
1673
1674 let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF, 0xA5A5]);
1675 assert_eq!(tx.next_word(Lsb), 0xBEEFDEAD);
1676 assert_eq!(tx.next_word(Lsb), 0x0000A5A5);
1677 assert_eq!(tx.next_word(Lsb), 0);
1678 assert_eq!(tx.next_word(Lsb), 0);
1679
1680 let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF]);
1681 assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
1682 assert_eq!(tx.next_word(Msb), 0);
1683 assert_eq!(tx.next_word(Msb), 0);
1684
1685 let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF]);
1686 assert_eq!(tx.next_word(Lsb), 0xBEEFDEAD);
1687 assert_eq!(tx.next_word(Lsb), 0);
1688 assert_eq!(tx.next_word(Lsb), 0);
1689
1690 let mut tx = TransmitBuffer::new(&[0xDEADu16]);
1691 assert_eq!(tx.next_word(Msb), 0x0000DEAD);
1692 assert_eq!(tx.next_word(Msb), 0);
1693 assert_eq!(tx.next_word(Msb), 0);
1694
1695 let mut tx = TransmitBuffer::new(&[0xDEADu16]);
1696 assert_eq!(tx.next_word(Lsb), 0x0000DEAD);
1697 assert_eq!(tx.next_word(Lsb), 0);
1698 assert_eq!(tx.next_word(Lsb), 0);
1699 }
1700
1701 #[test]
1702 fn receive_buffer() {
1703 // See notes in transmit_buffer test to understand MSB and LSB
1704 // transformations.
1705
1706 use super::{BitOrder::*, ReceiveBuffer, ReceiveData};
1707
1708 //
1709 // u8
1710 //
1711
1712 let mut buffer = [0u8; 9];
1713 let mut rx = ReceiveBuffer::new(&mut buffer);
1714 rx.next_word(Msb, 0xDEADBEEF);
1715 rx.next_word(Msb, 0xAD1CAC1D);
1716 rx.next_word(Msb, 0x04030201);
1717 rx.next_word(Msb, 0x55555555);
1718 assert_eq!(
1719 buffer,
1720 [0xDE, 0xAD, 0xBE, 0xEF, 0xAD, 0x1C, 0xAC, 0x1D, 0x01]
1721 );
1722
1723 let mut buffer = [0u8; 9];
1724 let mut rx = ReceiveBuffer::new(&mut buffer);
1725 rx.next_word(Lsb, 0xDEADBEEF);
1726 rx.next_word(Lsb, 0xAD1CAC1D);
1727 rx.next_word(Lsb, 0x04030201);
1728 rx.next_word(Lsb, 0x55555555);
1729 assert_eq!(
1730 buffer,
1731 [0xEF, 0xBE, 0xAD, 0xDE, 0x1D, 0xAC, 0x1C, 0xAD, 0x01]
1732 );
1733
1734 //
1735 // u16
1736 //
1737
1738 let mut buffer = [0u16; 5];
1739 let mut rx = ReceiveBuffer::new(&mut buffer);
1740 rx.next_word(Msb, 0xDEADBEEF);
1741 rx.next_word(Msb, 0xAD1CAC1D);
1742 rx.next_word(Msb, 0x04030201);
1743 rx.next_word(Msb, 0x55555555);
1744 assert_eq!(buffer, [0xDEAD, 0xBEEF, 0xAD1C, 0xAC1D, 0x0201]);
1745
1746 let mut buffer = [0u16; 5];
1747 let mut rx = ReceiveBuffer::new(&mut buffer);
1748 rx.next_word(Lsb, 0xDEADBEEF);
1749 rx.next_word(Lsb, 0xAD1CAC1D);
1750 rx.next_word(Lsb, 0x04030201);
1751 rx.next_word(Lsb, 0x55555555);
1752 assert_eq!(buffer, [0xBEEF, 0xDEAD, 0xAC1D, 0xAD1C, 0x0201]);
1753
1754 //
1755 // u32
1756 //
1757
1758 let mut buffer = [0u32; 3];
1759 let mut rx = ReceiveBuffer::new(&mut buffer);
1760 rx.next_word(Msb, 0xDEADBEEF);
1761 rx.next_word(Msb, 0xAD1CAC1D);
1762 rx.next_word(Msb, 0x77777777);
1763 rx.next_word(Msb, 0x55555555);
1764 assert_eq!(buffer, [0xDEADBEEF, 0xAD1CAC1D, 0x77777777]);
1765
1766 let mut buffer = [0u32; 3];
1767 let mut rx = ReceiveBuffer::new(&mut buffer);
1768 rx.next_word(Lsb, 0xDEADBEEF);
1769 rx.next_word(Lsb, 0xAD1CAC1D);
1770 rx.next_word(Lsb, 0x77777777);
1771 rx.next_word(Lsb, 0x55555555);
1772 assert_eq!(buffer, [0xDEADBEEF, 0xAD1CAC1D, 0x77777777]);
1773 }
1774
1775 #[test]
1776 fn transaction_frame_sizes() {
1777 assert!(super::Transaction::new_words(&[1u8]).is_ok());
1778 assert!(super::Transaction::new_words(&[1u8, 2]).is_ok());
1779 assert!(super::Transaction::new_words(&[1u8, 2, 3]).is_ok());
1780 assert!(super::Transaction::new_words(&[1u8, 2, 3, 4]).is_ok());
1781 assert!(super::Transaction::new_words(&[1u8, 2, 3, 4, 5]).is_ok());
1782
1783 assert!(super::Transaction::new_words(&[1u16]).is_ok());
1784 assert!(super::Transaction::new_words(&[1u16, 2]).is_ok());
1785 assert!(super::Transaction::new_words(&[1u16, 2, 3]).is_ok());
1786 assert!(super::Transaction::new_words(&[1u16, 2, 3, 4]).is_ok());
1787 assert!(super::Transaction::new_words(&[1u16, 2, 3, 4, 5]).is_ok());
1788
1789 assert!(super::Transaction::new_words(&[1u32]).is_ok());
1790 assert!(super::Transaction::new_words(&[1u32, 2]).is_ok());
1791 assert!(super::Transaction::new_words(&[1u32, 2, 3]).is_ok());
1792 assert!(super::Transaction::new_words(&[1u32, 2, 3, 4]).is_ok());
1793 assert!(super::Transaction::new_words(&[1u32, 2, 3, 4, 5]).is_ok());
1794
1795 assert!(super::Transaction::new(7).is_err());
1796 assert!(super::Transaction::new(8).is_ok());
1797 assert!(super::Transaction::new(9).is_ok());
1798 assert!(super::Transaction::new(31).is_ok());
1799 assert!(super::Transaction::new(32).is_ok());
1800 assert!(super::Transaction::new(33).is_err());
1801 assert!(super::Transaction::new(34).is_ok());
1802 assert!(super::Transaction::new(95).is_ok());
1803 assert!(super::Transaction::new(96).is_ok());
1804 assert!(super::Transaction::new(97).is_err());
1805 assert!(super::Transaction::new(98).is_ok());
1806 }
1807}