1use crate::FunctionSelect;
2use crate::gpio::{DynPinId, IoPeriphPin};
3use crate::{PeripheralSelect, enable_peripheral_clock, pins::AnyPin, sealed::Sealed, time::Hertz};
4use core::{convert::Infallible, fmt::Debug, marker::PhantomData};
5use embedded_hal::spi::{MODE_0, Mode};
6
7use regs::{ClockPrescaler, Data, FifoClear, WordSize};
8#[cfg(feature = "vor1x")]
9use va108xx as pac;
10#[cfg(feature = "vor4x")]
11use va416xx as pac;
12
13pub use regs::{Bank, HwChipSelectId};
14
15pub mod asynch;
16pub mod regs;
17
18pub const FIFO_DEPTH: usize = 16;
19
20pub fn configure_pin_as_hw_cs_pin<P: AnyPin + HwCsProvider>(_pin: P) -> HwChipSelectId {
21 IoPeriphPin::new(P::ID, P::FUN_SEL, None);
22 P::CS_ID
23}
24
25pub trait PinSck0: AnyPin {
30 const SPI_ID: Bank = Bank::Spi0;
31 const FUN_SEL: FunctionSelect;
32}
33
34pub trait PinMosi0: AnyPin {
35 const SPI_ID: Bank = Bank::Spi0;
36 const FUN_SEL: FunctionSelect;
37}
38
39pub trait PinMiso0: AnyPin {
40 const SPI_ID: Bank = Bank::Spi0;
41 const FUN_SEL: FunctionSelect;
42}
43
44pub trait PinSck1: AnyPin {
45 const SPI_ID: Bank = Bank::Spi1;
46 const FUN_SEL: FunctionSelect;
47}
48
49pub trait PinMosi1: AnyPin {
50 const SPI_ID: Bank = Bank::Spi1;
51 const FUN_SEL: FunctionSelect;
52}
53
54pub trait PinMiso1: AnyPin {
55 const SPI_ID: Bank = Bank::Spi1;
56 const FUN_SEL: FunctionSelect;
57}
58
59pub trait PinSck2: AnyPin {
60 const SPI_ID: Bank = Bank::Spi2;
61 const FUN_SEL: FunctionSelect;
62}
63
64pub trait PinMosi2: AnyPin {
65 const SPI_ID: Bank = Bank::Spi2;
66 const FUN_SEL: FunctionSelect;
67}
68
69pub trait PinMiso2: AnyPin {
70 const SPI_ID: Bank = Bank::Spi2;
71 const FUN_SEL: FunctionSelect;
72}
73
74pub trait HwCsProvider {
75 const PIN_ID: DynPinId;
76 const SPI_ID: Bank;
77 const FUN_SEL: FunctionSelect;
78 const CS_ID: HwChipSelectId;
79}
80
81#[macro_use]
82mod macros {
83 #[cfg(not(feature = "va41628"))]
84 macro_rules! hw_cs_multi_pin {
85 (
86 $name:ident,
88 $pin_id:ident,
90 $spi_id:path,
92 $fun_sel:path,
94 $cs_id:path
96 ) => {
97 #[doc = concat!(
98 "Newtype wrapper to use [Pin] [`", stringify!($pin_id), "`] as a HW CS pin for [`", stringify!($spi_id), "`] with [`", stringify!($cs_id), "`]."
99 )]
100 pub struct $name(Pin<$pin_id>);
101
102 impl $name {
103 pub fn new(pin: Pin<$pin_id>) -> Self {
104 Self(pin)
105 }
106 }
107
108 impl crate::sealed::Sealed for $name {}
109
110 impl AnyPin for $name {
111 const ID: DynPinId = <$pin_id as PinId>::ID;
112 }
113
114 impl HwCsProvider for $name {
115 const PIN_ID: DynPinId = <$pin_id as PinId>::ID;
116 const SPI_ID: Bank = $spi_id;
117 const FUN_SEL: FunctionSelect = $fun_sel;
118 const CS_ID: HwChipSelectId = $cs_id;
119 }
120 };
121 }
122
123 #[macro_export]
124 macro_rules! hw_cs_pins {
125 ($SpiId:path, $(($Px:ident, $FunSel:path, $HwCsIdent:path)$(,)?)+) => {
126 $(
127 impl HwCsProvider for Pin<$Px> {
128 const PIN_ID: DynPinId = $Px::ID;
129 const SPI_ID: Bank = $SpiId;
130 const FUN_SEL: FunctionSelect = $FunSel;
131 const CS_ID: HwChipSelectId = $HwCsIdent;
132 }
133 )+
134 };
135 }
136}
137
138#[cfg(feature = "vor1x")]
139pub mod pins_vor1x;
140#[cfg(feature = "vor4x")]
141pub mod pins_vor4x;
142
143const FILL_DEPTH: usize = 12;
149
150pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
151pub const BMSKIPDATA_MASK: u32 = 1 << 30;
152
153pub const DEFAULT_CLK_DIV: u16 = 2;
154
155pub trait Spi0Instance: Sealed {
156 const ID: Bank = Bank::Spi0;
157 const PERIPH_SEL: PeripheralSelect;
158}
159
160pub trait Spi1Instance: Sealed {
161 const ID: Bank = Bank::Spi1;
162 const PERIPH_SEL: PeripheralSelect;
163}
164
165pub trait Spi2Instance: Sealed {
166 const ID: Bank = Bank::Spi2;
167 const PERIPH_SEL: PeripheralSelect;
168}
169
170#[cfg(feature = "vor4x")]
171pub trait Spi3Instance: Sealed {
172 const ID: Bank = Bank::Spi3;
173 const PERIPH_SEL: PeripheralSelect;
174}
175
176#[cfg(feature = "vor1x")]
177pub type Spi0 = pac::Spia;
178#[cfg(feature = "vor4x")]
179pub type Spi0 = pac::Spi0;
180
181impl Spi0Instance for Spi0 {
182 const ID: Bank = Bank::Spi0;
183 const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
184}
185impl Sealed for Spi0 {}
186
187#[cfg(feature = "vor1x")]
188pub type Spi1 = pac::Spib;
189#[cfg(feature = "vor4x")]
190pub type Spi1 = pac::Spi1;
191
192impl Spi1Instance for Spi1 {
193 const ID: Bank = Bank::Spi1;
194 const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
195}
196impl Sealed for Spi1 {}
197
198#[cfg(feature = "vor1x")]
199pub type Spi2 = pac::Spic;
200#[cfg(feature = "vor4x")]
201pub type Spi2 = pac::Spi2;
202
203impl Spi2Instance for Spi2 {
204 const ID: Bank = Bank::Spi2;
205 const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
206}
207impl Sealed for Spi2 {}
208
209#[cfg(feature = "vor4x")]
210impl Spi3Instance for pac::Spi3 {
211 const ID: Bank = Bank::Spi3;
212 const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi3;
213}
214#[cfg(feature = "vor4x")]
215impl Sealed for pac::Spi3 {}
216
217pub trait TransferConfigProvider {
222 fn sod(&mut self, sod: bool);
223 fn blockmode(&mut self, blockmode: bool);
224 fn mode(&mut self, mode: Mode);
225 fn clk_cfg(&mut self, clk_cfg: SpiClockConfig);
226 fn hw_cs_id(&self) -> u8;
227}
228
229#[derive(Copy, Clone, Debug)]
232#[cfg_attr(feature = "defmt", derive(defmt::Format))]
233pub struct TransferConfig {
234 pub clk_cfg: Option<SpiClockConfig>,
235 pub mode: Option<Mode>,
236 pub sod: bool,
237 pub blockmode: bool,
241 pub bmstall: bool,
244 pub hw_cs: Option<HwChipSelectId>,
245}
246
247impl TransferConfig {
248 pub fn new_with_hw_cs(
249 clk_cfg: Option<SpiClockConfig>,
250 mode: Option<Mode>,
251 blockmode: bool,
252 bmstall: bool,
253 sod: bool,
254 hw_cs_id: HwChipSelectId,
255 ) -> Self {
256 TransferConfig {
257 clk_cfg,
258 mode,
259 sod,
260 blockmode,
261 bmstall,
262 hw_cs: Some(hw_cs_id),
263 }
264 }
265}
266
267#[derive(Debug, Copy, Clone)]
269#[cfg_attr(feature = "defmt", derive(defmt::Format))]
270pub struct SpiConfig {
271 clk: SpiClockConfig,
272 pub init_mode: Mode,
274 pub blockmode: bool,
278 pub bmstall: bool,
281 pub slave_output_disable: bool,
283 pub loopback_mode: bool,
285 pub master_delayer_capture: bool,
287}
288
289impl Default for SpiConfig {
290 fn default() -> Self {
291 Self {
292 init_mode: MODE_0,
293 blockmode: true,
294 bmstall: true,
295 clk: SpiClockConfig::from_div(DEFAULT_CLK_DIV).unwrap(),
297 slave_output_disable: Default::default(),
298 loopback_mode: Default::default(),
299 master_delayer_capture: Default::default(),
300 }
301 }
302}
303
304impl SpiConfig {
305 pub fn loopback(mut self, enable: bool) -> Self {
306 self.loopback_mode = enable;
307 self
308 }
309
310 pub fn blockmode(mut self, enable: bool) -> Self {
311 self.blockmode = enable;
312 self
313 }
314
315 pub fn bmstall(mut self, enable: bool) -> Self {
316 self.bmstall = enable;
317 self
318 }
319
320 pub fn mode(mut self, mode: Mode) -> Self {
321 self.init_mode = mode;
322 self
323 }
324
325 pub fn clk_cfg(mut self, clk_cfg: SpiClockConfig) -> Self {
326 self.clk = clk_cfg;
327 self
328 }
329
330 pub fn slave_output_disable(mut self, sod: bool) -> Self {
331 self.slave_output_disable = sod;
332 self
333 }
334}
335
336pub trait SpiWord: Copy + Default + Into<u32> + TryFrom<u32> + 'static {
343 const MASK: u32;
344 const WORD_SIZE: regs::WordSize;
345 fn word_reg() -> u8;
346}
347
348impl SpiWord for u8 {
349 const MASK: u32 = 0xff;
350 const WORD_SIZE: regs::WordSize = regs::WordSize::EightBits;
351 fn word_reg() -> u8 {
352 0x07
353 }
354}
355
356impl SpiWord for u16 {
357 const MASK: u32 = 0xffff;
358 const WORD_SIZE: regs::WordSize = regs::WordSize::SixteenBits;
359 fn word_reg() -> u8 {
360 0x0f
361 }
362}
363
364pub trait SpiLowLevel {
370 fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible>;
375
376 fn write_fifo_unchecked(&mut self, data: u32);
382
383 fn read_fifo(&mut self) -> nb::Result<u32, Infallible>;
388
389 fn read_fifo_unchecked(&mut self) -> u32;
396}
397
398#[inline(always)]
399pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
400 match mode {
401 embedded_hal::spi::MODE_0 => (false, false),
402 embedded_hal::spi::MODE_1 => (false, true),
403 embedded_hal::spi::MODE_2 => (true, false),
404 embedded_hal::spi::MODE_3 => (true, true),
405 }
406}
407
408#[derive(Debug, Copy, Clone, PartialEq, Eq)]
409#[cfg_attr(feature = "defmt", derive(defmt::Format))]
410pub struct SpiClockConfig {
411 prescale_val: u8,
412 scrdv: u8,
413}
414
415impl SpiClockConfig {
416 pub fn prescale_val(&self) -> u8 {
417 self.prescale_val
418 }
419 pub fn scrdv(&self) -> u8 {
420 self.scrdv
421 }
422}
423
424impl SpiClockConfig {
425 pub fn new(prescale_val: u8, scrdv: u8) -> Self {
426 Self {
427 prescale_val,
428 scrdv,
429 }
430 }
431
432 pub fn from_div(div: u16) -> Result<Self, SpiClockConfigError> {
433 spi_clk_config_from_div(div)
434 }
435
436 #[cfg(feature = "vor1x")]
437 pub fn from_clk(sys_clk: Hertz, spi_clk: Hertz) -> Option<Self> {
438 clk_div_for_target_clock(sys_clk, spi_clk).map(|div| spi_clk_config_from_div(div).unwrap())
439 }
440
441 #[cfg(feature = "vor4x")]
442 pub fn from_clks(clks: &crate::clock::Clocks, spi_clk: Hertz) -> Option<Self> {
443 Self::from_apb1_clk(clks.apb1(), spi_clk)
444 }
445
446 #[cfg(feature = "vor4x")]
447 pub fn from_apb1_clk(apb1_clk: Hertz, spi_clk: Hertz) -> Option<Self> {
448 clk_div_for_target_clock(apb1_clk, spi_clk).map(|div| spi_clk_config_from_div(div).unwrap())
449 }
450}
451
452#[derive(Debug, thiserror::Error)]
453#[cfg_attr(feature = "defmt", derive(defmt::Format))]
454pub enum SpiClockConfigError {
455 #[error("division by zero")]
456 DivIsZero,
457 #[error("divide value is not even")]
458 DivideValueNotEven,
459 #[error("scrdv value is too large")]
460 ScrdvValueTooLarge,
461}
462
463#[inline]
464pub fn spi_clk_config_from_div(mut div: u16) -> Result<SpiClockConfig, SpiClockConfigError> {
465 if div == 0 {
466 return Err(SpiClockConfigError::DivIsZero);
467 }
468 if !div.is_multiple_of(2) {
469 return Err(SpiClockConfigError::DivideValueNotEven);
470 }
471 let mut prescale_val = 0;
472
473 for i in (2..=0xfe).rev().step_by(2) {
475 if div.is_multiple_of(i) {
476 prescale_val = i;
477 break;
478 }
479 }
480
481 if prescale_val == 0 {
482 return Err(SpiClockConfigError::DivideValueNotEven);
483 }
484
485 div /= prescale_val;
486 if div > u8::MAX as u16 + 1 {
487 return Err(SpiClockConfigError::ScrdvValueTooLarge);
488 }
489 Ok(SpiClockConfig {
490 prescale_val: prescale_val as u8,
491 scrdv: (div - 1) as u8,
492 })
493}
494
495#[inline]
496pub fn clk_div_for_target_clock(sys_clk: Hertz, spi_clk: Hertz) -> Option<u16> {
497 if spi_clk > sys_clk {
498 return None;
499 }
500
501 let raw_div = sys_clk.to_raw() / spi_clk.to_raw();
503 let remainder = sys_clk.to_raw() % spi_clk.to_raw();
504
505 let mut rounded_div = if remainder * 2 >= spi_clk.to_raw() {
507 raw_div + 1
508 } else {
509 raw_div
510 };
511
512 if !rounded_div.is_multiple_of(2) {
513 rounded_div += 1;
515 }
516 if rounded_div > u16::MAX as u32 {
517 return None;
518 }
519 Some(rounded_div as u16)
520}
521
522pub struct Spi<Word = u8> {
524 id: Bank,
525 regs: regs::MmioSpi<'static>,
526 fill_word: Word,
528 blockmode: bool,
529 bmstall: bool,
530 word: PhantomData<Word>,
531}
532
533impl<Word: SpiWord> Spi<Word>
534where
535 <Word as TryFrom<u32>>::Error: core::fmt::Debug,
536{
537 #[cfg(feature = "vor1x")]
544 pub fn new_for_rom<Spi: Spi2Instance>(_spi: Spi, spi_cfg: SpiConfig) -> Self {
545 Self::new_generic(Spi::ID, Spi::PERIPH_SEL, spi_cfg)
546 }
547
548 #[cfg(feature = "vor4x")]
555 pub fn new_for_rom<Spi: Spi3Instance>(_spi: Spi, spi_cfg: SpiConfig) -> Self {
556 Self::new_generic(Spi::ID, Spi::PERIPH_SEL, spi_cfg)
557 }
558
559 pub fn new_for_spi0<Spi: Spi0Instance, Sck: PinSck0, Miso: PinMiso0, Mosi: PinMosi0>(
568 _spi: Spi,
569 _pins: (Sck, Miso, Mosi),
570 spi_cfg: SpiConfig,
571 ) -> Self {
572 IoPeriphPin::new(Sck::ID, Sck::FUN_SEL, None);
573 IoPeriphPin::new(Miso::ID, Miso::FUN_SEL, None);
574 IoPeriphPin::new(Mosi::ID, Mosi::FUN_SEL, None);
575 Self::new_generic(Spi::ID, Spi::PERIPH_SEL, spi_cfg)
576 }
577
578 pub fn new_for_spi1<Spi: Spi1Instance, Sck: PinSck1, Miso: PinMiso1, Mosi: PinMosi1>(
587 _spi: Spi,
588 _pins: (Sck, Miso, Mosi),
589 spi_cfg: SpiConfig,
590 ) -> Self {
591 IoPeriphPin::new(Sck::ID, Sck::FUN_SEL, None);
592 IoPeriphPin::new(Miso::ID, Miso::FUN_SEL, None);
593 IoPeriphPin::new(Mosi::ID, Mosi::FUN_SEL, None);
594 Self::new_generic(Spi::ID, Spi::PERIPH_SEL, spi_cfg)
595 }
596
597 pub fn new_for_spi2<Spi: Spi2Instance, Sck: PinSck2, Miso: PinMiso2, Mosi: PinMosi2>(
606 _spi: Spi,
607 _pins: (Sck, Miso, Mosi),
608 spi_cfg: SpiConfig,
609 ) -> Self {
610 IoPeriphPin::new(Sck::ID, Sck::FUN_SEL, None);
611 IoPeriphPin::new(Miso::ID, Miso::FUN_SEL, None);
612 IoPeriphPin::new(Mosi::ID, Mosi::FUN_SEL, None);
613 Self::new_generic(Spi::ID, Spi::PERIPH_SEL, spi_cfg)
614 }
615
616 pub fn new_generic(spi_sel: Bank, periph_sel: PeripheralSelect, spi_cfg: SpiConfig) -> Self {
617 enable_peripheral_clock(periph_sel);
618 let mut regs = regs::Spi::new_mmio(spi_sel);
619 let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(spi_cfg.init_mode);
620 regs.write_ctrl0(
621 regs::Control0::builder()
622 .with_scrdv(spi_cfg.clk.scrdv)
623 .with_sph(cph_bit)
624 .with_spo(cpo_bit)
625 .with_word_size(Word::WORD_SIZE)
626 .build(),
627 );
628 regs.write_ctrl1(
629 regs::Control1::builder()
630 .with_mtxpause(false)
631 .with_mdlycap(spi_cfg.master_delayer_capture)
632 .with_bm_stall(spi_cfg.bmstall)
633 .with_bm_start(false)
634 .with_blockmode(spi_cfg.blockmode)
635 .with_ss(HwChipSelectId::Id0)
636 .with_sod(spi_cfg.slave_output_disable)
637 .with_slave_mode(false)
638 .with_enable(false)
639 .with_lbm(spi_cfg.loopback_mode)
640 .build(),
641 );
642 regs.write_clkprescale(ClockPrescaler::new(spi_cfg.clk.prescale_val));
643 regs.write_fifo_clear(
644 FifoClear::builder()
645 .with_tx_fifo(true)
646 .with_rx_fifo(true)
647 .build(),
648 );
649 regs.modify_ctrl1(|mut value| {
652 value.set_enable(true);
653 value
654 });
655 Spi {
656 id: spi_sel,
657 regs: regs::Spi::new_mmio(spi_sel),
658 fill_word: Default::default(),
659 bmstall: spi_cfg.bmstall,
660 blockmode: spi_cfg.blockmode,
661 word: PhantomData,
662 }
663 }
664
665 #[inline]
666 pub fn cfg_clock(&mut self, cfg: SpiClockConfig) {
667 self.regs.modify_ctrl0(|mut value| {
668 value.set_scrdv(cfg.scrdv);
669 value
670 });
671 self.regs
672 .write_clkprescale(regs::ClockPrescaler::new(cfg.prescale_val));
673 }
674
675 pub fn set_fill_word(&mut self, fill_word: Word) {
676 self.fill_word = fill_word;
677 }
678
679 #[inline]
680 pub fn configure_clock_from_div(&mut self, div: u16) -> Result<(), SpiClockConfigError> {
681 let val = spi_clk_config_from_div(div)?;
682 self.cfg_clock(val);
683 Ok(())
684 }
685
686 #[inline]
687 pub fn configure_mode(&mut self, mode: Mode) {
688 let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(mode);
689 self.regs.modify_ctrl0(|mut value| {
690 value.set_spo(cpo_bit);
691 value.set_sph(cph_bit);
692 value
693 });
694 }
695
696 #[inline]
697 pub fn fill_word(&self) -> Word {
698 self.fill_word
699 }
700
701 #[inline]
702 pub fn clear_tx_fifo(&mut self) {
703 self.regs.write_fifo_clear(
704 regs::FifoClear::builder()
705 .with_tx_fifo(true)
706 .with_rx_fifo(false)
707 .build(),
708 );
709 }
710
711 #[inline]
712 pub fn clear_rx_fifo(&mut self) {
713 self.regs.write_fifo_clear(
714 regs::FifoClear::builder()
715 .with_tx_fifo(false)
716 .with_rx_fifo(true)
717 .build(),
718 );
719 }
720
721 #[inline]
722 pub fn peripheral_id(&self) -> u32 {
723 self.regs.read_perid()
724 }
725
726 #[inline]
732 pub fn configure_hw_cs(&mut self, hw_cs: HwChipSelectId) {
733 self.regs.modify_ctrl1(|mut value| {
734 value.set_sod(false);
735 value.set_ss(hw_cs);
736 value
737 });
738 }
739
740 #[inline]
743 pub fn disable_hw_cs(&mut self) {
744 self.regs.modify_ctrl1(|mut value| {
745 value.set_sod(true);
746 value
747 });
748 }
749
750 pub fn configure_transfer(&mut self, transfer_cfg: &TransferConfig) {
754 if let Some(trans_clk_div) = transfer_cfg.clk_cfg {
755 self.cfg_clock(trans_clk_div);
756 }
757 if let Some(mode) = transfer_cfg.mode {
758 self.configure_mode(mode);
759 }
760 self.blockmode = transfer_cfg.blockmode;
761 self.regs.modify_ctrl1(|mut value| {
762 if transfer_cfg.sod {
763 value.set_sod(transfer_cfg.sod);
764 } else {
765 value.set_sod(false);
766 if let Some(hw_cs) = transfer_cfg.hw_cs {
767 value.set_ss(hw_cs);
768 }
769 }
770 value.set_blockmode(transfer_cfg.blockmode);
771 value.set_bm_stall(transfer_cfg.bmstall);
772 value
773 });
774 }
775
776 fn flush_internal(&mut self) {
777 let mut status_reg = self.regs.read_status();
778 while !status_reg.tx_empty() || status_reg.rx_not_empty() || status_reg.busy() {
779 if status_reg.rx_not_empty() {
780 self.read_fifo_unchecked();
781 }
782 status_reg = self.regs.read_status();
783 }
784 }
785
786 fn transfer_preparation(&mut self, words: &[Word]) {
787 if words.is_empty() {
788 return;
789 }
790 self.flush_internal();
791 }
792
793 fn initial_send_fifo_pumping_with_words(&mut self, words: &[Word]) -> usize {
796 if self.blockmode {
798 self.regs.modify_ctrl1(|mut value| {
799 value.set_mtxpause(true);
800 value
801 });
802 }
803 let mut current_write_idx = 0;
805 let smaller_idx = core::cmp::min(FILL_DEPTH, words.len());
806 for _ in 0..smaller_idx {
807 if current_write_idx == smaller_idx.saturating_sub(1) && self.bmstall {
808 self.write_fifo_unchecked(words[current_write_idx].into() | BMSTART_BMSTOP_MASK);
809 } else {
810 self.write_fifo_unchecked(words[current_write_idx].into());
811 }
812 current_write_idx += 1;
813 }
814 if self.blockmode {
815 self.regs.modify_ctrl1(|mut value| {
816 value.set_mtxpause(false);
817 value
818 });
819 }
820 current_write_idx
821 }
822
823 fn initial_send_fifo_pumping_with_fill_words(&mut self, send_len: usize) -> usize {
826 if self.blockmode {
827 self.regs.modify_ctrl1(|mut value| {
828 value.set_mtxpause(true);
829 value
830 });
831 }
832 let mut current_write_idx = 0;
834 let smaller_idx = core::cmp::min(FILL_DEPTH, send_len);
835 for _ in 0..smaller_idx {
836 if current_write_idx == smaller_idx.saturating_sub(1) && self.bmstall {
837 self.write_fifo_unchecked(self.fill_word.into() | BMSTART_BMSTOP_MASK);
838 } else {
839 self.write_fifo_unchecked(self.fill_word.into());
840 }
841 current_write_idx += 1;
842 }
843 if self.blockmode {
844 self.regs.modify_ctrl1(|mut value| {
845 value.set_mtxpause(false);
846 value
847 });
848 }
849 current_write_idx
850 }
851
852 pub fn read(&mut self, words: &mut [Word]) {
853 self.transfer_preparation(words);
854 let mut current_read_idx = 0;
855 let mut current_write_idx = self.initial_send_fifo_pumping_with_fill_words(words.len());
856 loop {
857 if current_read_idx < words.len() {
858 words[current_read_idx] = (nb::block!(self.read_fifo()).unwrap() & Word::MASK)
859 .try_into()
860 .unwrap();
861 current_read_idx += 1;
862 }
863 if current_write_idx < words.len() {
864 if current_write_idx == words.len() - 1 && self.bmstall {
865 nb::block!(self.write_fifo(self.fill_word.into() | BMSTART_BMSTOP_MASK))
866 .unwrap();
867 } else {
868 nb::block!(self.write_fifo(self.fill_word.into())).unwrap();
869 }
870 current_write_idx += 1;
871 }
872 if current_read_idx >= words.len() && current_write_idx >= words.len() {
873 break;
874 }
875 }
876 }
877
878 pub fn write(&mut self, words: &[Word]) {
879 self.transfer_preparation(words);
880 let mut current_write_idx = self.initial_send_fifo_pumping_with_words(words);
881 while current_write_idx < words.len() {
882 if current_write_idx == words.len() - 1 && self.bmstall {
883 nb::block!(self.write_fifo(words[current_write_idx].into() | BMSTART_BMSTOP_MASK))
884 .unwrap();
885 } else {
886 nb::block!(self.write_fifo(words[current_write_idx].into())).unwrap();
887 }
888 current_write_idx += 1;
889 if self.regs.read_status().rx_not_empty() {
891 self.clear_rx_fifo();
892 }
893 }
894 }
895
896 pub fn transfer(&mut self, read: &mut [Word], write: &[Word]) {
897 self.transfer_preparation(write);
898 let mut current_read_idx = 0;
899 let mut current_write_idx = self.initial_send_fifo_pumping_with_words(write);
900 let max_idx = core::cmp::max(read.len(), write.len());
901 while current_read_idx < read.len() || current_write_idx < write.len() {
902 if current_write_idx < max_idx {
903 if current_write_idx == write.len() - 1 && self.bmstall {
904 nb::block!(
905 self.write_fifo(write[current_write_idx].into() | BMSTART_BMSTOP_MASK)
906 )
907 .unwrap();
908 } else if current_write_idx < write.len() {
909 nb::block!(self.write_fifo(write[current_write_idx].into())).unwrap();
910 } else {
911 nb::block!(self.write_fifo(0)).unwrap();
912 }
913 current_write_idx += 1;
914 }
915 if current_read_idx < max_idx {
916 if current_read_idx < read.len() {
917 read[current_read_idx] = (nb::block!(self.read_fifo()).unwrap() & Word::MASK)
918 .try_into()
919 .unwrap();
920 } else {
921 nb::block!(self.read_fifo()).unwrap();
922 }
923 current_read_idx += 1;
924 }
925 }
926 }
927
928 pub fn transfer_in_place(&mut self, words: &mut [Word]) {
929 self.transfer_preparation(words);
930 let mut current_read_idx = 0;
931 let mut current_write_idx = self.initial_send_fifo_pumping_with_words(words);
932
933 while current_read_idx < words.len() || current_write_idx < words.len() {
934 if current_write_idx < words.len() {
935 if current_write_idx == words.len() - 1 && self.bmstall {
936 nb::block!(
937 self.write_fifo(words[current_write_idx].into() | BMSTART_BMSTOP_MASK)
938 )
939 .unwrap();
940 } else {
941 nb::block!(self.write_fifo(words[current_write_idx].into())).unwrap();
942 }
943 current_write_idx += 1;
944 }
945 if current_read_idx < words.len() && current_read_idx < current_write_idx {
946 words[current_read_idx] = (nb::block!(self.read_fifo()).unwrap() & Word::MASK)
947 .try_into()
948 .unwrap();
949 current_read_idx += 1;
950 }
951 }
952 }
953
954 pub fn flush(&mut self) {
955 self.flush_internal();
956 }
957}
958
959impl<W: SpiWord> SpiLowLevel for Spi<W>
960where
961 <W as TryFrom<u32>>::Error: core::fmt::Debug,
962{
963 #[inline(always)]
964 fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible> {
965 if !self.regs.read_status().tx_not_full() {
966 return Err(nb::Error::WouldBlock);
967 }
968 self.write_fifo_unchecked(data);
969 Ok(())
970 }
971
972 #[inline(always)]
973 fn write_fifo_unchecked(&mut self, data: u32) {
974 self.regs.write_data(Data::new_with_raw_value(data));
975 }
976
977 #[inline(always)]
978 fn read_fifo(&mut self) -> nb::Result<u32, Infallible> {
979 if !self.regs.read_status().rx_not_empty() {
980 return Err(nb::Error::WouldBlock);
981 }
982 Ok(self.read_fifo_unchecked())
983 }
984
985 #[inline(always)]
986 fn read_fifo_unchecked(&mut self) -> u32 {
987 self.regs.read_data().raw_value()
988 }
989}
990
991impl<Word: SpiWord> embedded_hal::spi::ErrorType for Spi<Word> {
992 type Error = Infallible;
993}
994
995impl<Word: SpiWord> embedded_hal::spi::SpiBus<Word> for Spi<Word>
996where
997 <Word as TryFrom<u32>>::Error: core::fmt::Debug,
998{
999 fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
1000 self.read(words);
1001 Ok(())
1002 }
1003
1004 fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
1005 self.write(words);
1006 Ok(())
1007 }
1008
1009 fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
1010 self.transfer(read, write);
1011 Ok(())
1012 }
1013
1014 fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
1015 self.transfer_in_place(words);
1016 Ok(())
1017 }
1018
1019 fn flush(&mut self) -> Result<(), Self::Error> {
1020 self.flush();
1021 Ok(())
1022 }
1023}
1024
1025impl From<Spi<u8>> for Spi<u16> {
1027 fn from(mut old_spi: Spi<u8>) -> Self {
1028 old_spi.regs.modify_ctrl0(|mut value| {
1029 value.set_word_size(WordSize::SixteenBits);
1030 value
1031 });
1032 Spi {
1033 id: old_spi.id,
1034 regs: old_spi.regs,
1035 blockmode: old_spi.blockmode,
1036 fill_word: Default::default(),
1037 bmstall: old_spi.bmstall,
1038 word: PhantomData,
1039 }
1040 }
1041}
1042
1043impl From<Spi<u16>> for Spi<u8> {
1044 fn from(mut old_spi: Spi<u16>) -> Self {
1045 old_spi.regs.modify_ctrl0(|mut value| {
1046 value.set_word_size(WordSize::EightBits);
1047 value
1048 });
1049 Spi {
1050 id: old_spi.id,
1051 regs: old_spi.regs,
1052 blockmode: old_spi.blockmode,
1053 fill_word: Default::default(),
1054 bmstall: old_spi.bmstall,
1055 word: PhantomData,
1056 }
1057 }
1058}
1059
1060pub struct HwCsPin {
1065 regs: regs::MmioSpi<'static>,
1066 id: HwChipSelectId,
1067}
1068
1069impl HwCsPin {
1070 pub fn new<P: HwCsProvider + AnyPin>(pin: P) -> Self {
1071 configure_pin_as_hw_cs_pin(pin);
1072 Self {
1073 regs: unsafe { P::SPI_ID.steal_regs() },
1074 id: P::CS_ID,
1075 }
1076 }
1077}
1078
1079impl embedded_hal::digital::ErrorType for HwCsPin {
1080 type Error = Infallible;
1081}
1082
1083impl embedded_hal::digital::OutputPin for HwCsPin {
1084 fn set_low(&mut self) -> Result<(), Self::Error> {
1085 self.regs
1086 .modify_ctrl1(|value| value.with_sod(false).with_ss(self.id));
1087 Ok(())
1088 }
1089
1090 fn set_high(&mut self) -> Result<(), Self::Error> {
1091 self.regs.modify_ctrl1(|value| value.with_sod(true));
1092 Ok(())
1093 }
1094}