1use core::convert::Infallible;
7
8use crate::clocks::Clocks;
9use crate::gpio::IoPeriphPin;
10use crate::gpio::mio::{
11 Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34,
12 Mio35, Mio36, Mio37, Mio38, Mio39, MioPin, MuxConfig, Pin,
13};
14#[cfg(not(feature = "7z010-7z007s-clg225"))]
15use crate::gpio::mio::{
16 Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
17 Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio48, Mio49, Mio50, Mio51,
18};
19use crate::{enable_amba_peripheral_clock, spi_mode_const_to_cpol_cpha};
20
21use crate::{clocks::IoClocks, slcr::Slcr, time::Hertz};
22use arbitrary_int::{prelude::*, u3, u4, u6};
23use embedded_hal::delay::DelayNs;
24pub use embedded_hal::spi::Mode;
25use embedded_hal::spi::SpiBus as _;
26use zynq7000::slcr::reset::DualRefAndClockReset;
27use zynq7000::spi::{
28 BaudDivSel, DelayControl, FifoWrite, InterruptControl, InterruptMask, InterruptStatus, MmioSpi,
29 SPI_0_BASE_ADDR, SPI_1_BASE_ADDR,
30};
31
32pub const FIFO_DEPTH: usize = 128;
33pub const MODULE_ID: u32 = 0x90106;
34
35pub mod asynch;
36pub use asynch::*;
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum SpiId {
40 Spi0 = 0,
41 Spi1 = 1,
42}
43
44pub trait PsSpi {
45 fn reg_block(&self) -> MmioSpi<'static>;
46 fn id(&self) -> Option<SpiId>;
47}
48
49impl PsSpi for MmioSpi<'static> {
50 #[inline]
51 fn reg_block(&self) -> MmioSpi<'static> {
52 unsafe { self.clone() }
53 }
54
55 #[inline]
56 fn id(&self) -> Option<SpiId> {
57 let base_addr = unsafe { self.ptr() } as usize;
58 if base_addr == SPI_0_BASE_ADDR {
59 return Some(SpiId::Spi0);
60 } else if base_addr == SPI_1_BASE_ADDR {
61 return Some(SpiId::Spi1);
62 }
63 None
64 }
65}
66
67pub trait SckPin: MioPin {
68 const SPI: SpiId;
69 const GROUP: usize;
70}
71
72pub trait MosiPin: MioPin {
73 const SPI: SpiId;
74 const GROUP: usize;
75}
76
77pub trait MisoPin: MioPin {
78 const SPI: SpiId;
79 const GROUP: usize;
80}
81
82pub trait SsPin: MioPin {
83 const IDX: usize;
84 const SPI: SpiId;
85 const GROUP: usize;
86}
87
88pub const SPI_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b101));
89
90#[cfg(not(feature = "7z010-7z007s-clg225"))]
92impl SckPin for Pin<Mio16> {
93 const SPI: SpiId = SpiId::Spi0;
94 const GROUP: usize = 0;
95}
96#[cfg(not(feature = "7z010-7z007s-clg225"))]
97impl MosiPin for Pin<Mio21> {
98 const SPI: SpiId = SpiId::Spi0;
99 const GROUP: usize = 0;
100}
101#[cfg(not(feature = "7z010-7z007s-clg225"))]
102impl MisoPin for Pin<Mio17> {
103 const SPI: SpiId = SpiId::Spi0;
104 const GROUP: usize = 0;
105}
106#[cfg(not(feature = "7z010-7z007s-clg225"))]
107impl SsPin for Pin<Mio18> {
108 const SPI: SpiId = SpiId::Spi0;
109 const GROUP: usize = 0;
110 const IDX: usize = 0;
111}
112#[cfg(not(feature = "7z010-7z007s-clg225"))]
113impl SsPin for Pin<Mio19> {
114 const SPI: SpiId = SpiId::Spi0;
115 const GROUP: usize = 0;
116 const IDX: usize = 1;
117}
118#[cfg(not(feature = "7z010-7z007s-clg225"))]
119impl SsPin for Pin<Mio20> {
120 const SPI: SpiId = SpiId::Spi0;
121 const GROUP: usize = 0;
122 const IDX: usize = 2;
123}
124
125impl SckPin for Pin<Mio28> {
127 const SPI: SpiId = SpiId::Spi0;
128 const GROUP: usize = 1;
129}
130impl MosiPin for Pin<Mio33> {
131 const SPI: SpiId = SpiId::Spi0;
132 const GROUP: usize = 1;
133}
134impl MisoPin for Pin<Mio29> {
135 const SPI: SpiId = SpiId::Spi0;
136 const GROUP: usize = 1;
137}
138impl SsPin for Pin<Mio30> {
139 const SPI: SpiId = SpiId::Spi0;
140 const GROUP: usize = 1;
141 const IDX: usize = 0;
142}
143impl SsPin for Pin<Mio31> {
144 const SPI: SpiId = SpiId::Spi0;
145 const GROUP: usize = 1;
146 const IDX: usize = 1;
147}
148impl SsPin for Pin<Mio32> {
149 const SPI: SpiId = SpiId::Spi0;
150 const GROUP: usize = 1;
151 const IDX: usize = 2;
152}
153
154#[cfg(not(feature = "7z010-7z007s-clg225"))]
156impl SckPin for Pin<Mio40> {
157 const SPI: SpiId = SpiId::Spi0;
158 const GROUP: usize = 2;
159}
160#[cfg(not(feature = "7z010-7z007s-clg225"))]
161impl MosiPin for Pin<Mio45> {
162 const SPI: SpiId = SpiId::Spi0;
163 const GROUP: usize = 2;
164}
165#[cfg(not(feature = "7z010-7z007s-clg225"))]
166impl MisoPin for Pin<Mio41> {
167 const SPI: SpiId = SpiId::Spi0;
168 const GROUP: usize = 2;
169}
170#[cfg(not(feature = "7z010-7z007s-clg225"))]
171impl SsPin for Pin<Mio42> {
172 const SPI: SpiId = SpiId::Spi0;
173 const GROUP: usize = 2;
174 const IDX: usize = 0;
175}
176#[cfg(not(feature = "7z010-7z007s-clg225"))]
177impl SsPin for Pin<Mio43> {
178 const SPI: SpiId = SpiId::Spi0;
179 const GROUP: usize = 2;
180 const IDX: usize = 1;
181}
182#[cfg(not(feature = "7z010-7z007s-clg225"))]
183impl SsPin for Pin<Mio44> {
184 const SPI: SpiId = SpiId::Spi0;
185 const GROUP: usize = 2;
186 const IDX: usize = 2;
187}
188
189impl SckPin for Pin<Mio12> {
191 const SPI: SpiId = SpiId::Spi1;
192 const GROUP: usize = 0;
193}
194impl MosiPin for Pin<Mio10> {
195 const SPI: SpiId = SpiId::Spi1;
196 const GROUP: usize = 0;
197}
198impl MisoPin for Pin<Mio11> {
199 const SPI: SpiId = SpiId::Spi1;
200 const GROUP: usize = 0;
201}
202impl SsPin for Pin<Mio13> {
203 const SPI: SpiId = SpiId::Spi1;
204 const GROUP: usize = 0;
205 const IDX: usize = 0;
206}
207impl SsPin for Pin<Mio14> {
208 const SPI: SpiId = SpiId::Spi1;
209 const GROUP: usize = 0;
210 const IDX: usize = 1;
211}
212impl SsPin for Pin<Mio15> {
213 const SPI: SpiId = SpiId::Spi1;
214 const GROUP: usize = 0;
215 const IDX: usize = 2;
216}
217
218#[cfg(not(feature = "7z010-7z007s-clg225"))]
220impl SckPin for Pin<Mio24> {
221 const SPI: SpiId = SpiId::Spi1;
222 const GROUP: usize = 1;
223}
224#[cfg(not(feature = "7z010-7z007s-clg225"))]
225impl MosiPin for Pin<Mio22> {
226 const SPI: SpiId = SpiId::Spi1;
227 const GROUP: usize = 1;
228}
229#[cfg(not(feature = "7z010-7z007s-clg225"))]
230impl MisoPin for Pin<Mio23> {
231 const SPI: SpiId = SpiId::Spi1;
232 const GROUP: usize = 1;
233}
234#[cfg(not(feature = "7z010-7z007s-clg225"))]
235impl SsPin for Pin<Mio25> {
236 const SPI: SpiId = SpiId::Spi1;
237 const GROUP: usize = 1;
238 const IDX: usize = 0;
239}
240#[cfg(not(feature = "7z010-7z007s-clg225"))]
241impl SsPin for Pin<Mio26> {
242 const SPI: SpiId = SpiId::Spi1;
243 const GROUP: usize = 1;
244 const IDX: usize = 1;
245}
246#[cfg(not(feature = "7z010-7z007s-clg225"))]
247impl SsPin for Pin<Mio27> {
248 const SPI: SpiId = SpiId::Spi1;
249 const GROUP: usize = 1;
250 const IDX: usize = 2;
251}
252
253impl SckPin for Pin<Mio36> {
255 const SPI: SpiId = SpiId::Spi1;
256 const GROUP: usize = 2;
257}
258impl MosiPin for Pin<Mio34> {
259 const SPI: SpiId = SpiId::Spi1;
260 const GROUP: usize = 2;
261}
262impl MisoPin for Pin<Mio35> {
263 const SPI: SpiId = SpiId::Spi1;
264 const GROUP: usize = 2;
265}
266impl SsPin for Pin<Mio37> {
267 const SPI: SpiId = SpiId::Spi1;
268 const GROUP: usize = 2;
269 const IDX: usize = 0;
270}
271impl SsPin for Pin<Mio38> {
272 const SPI: SpiId = SpiId::Spi1;
273 const GROUP: usize = 2;
274 const IDX: usize = 1;
275}
276impl SsPin for Pin<Mio39> {
277 const SPI: SpiId = SpiId::Spi1;
278 const GROUP: usize = 2;
279 const IDX: usize = 2;
280}
281
282#[cfg(not(feature = "7z010-7z007s-clg225"))]
284impl SckPin for Pin<Mio48> {
285 const SPI: SpiId = SpiId::Spi1;
286 const GROUP: usize = 3;
287}
288#[cfg(not(feature = "7z010-7z007s-clg225"))]
289impl MosiPin for Pin<Mio46> {
290 const SPI: SpiId = SpiId::Spi1;
291 const GROUP: usize = 3;
292}
293#[cfg(not(feature = "7z010-7z007s-clg225"))]
294impl MisoPin for Pin<Mio47> {
295 const SPI: SpiId = SpiId::Spi1;
296 const GROUP: usize = 3;
297}
298#[cfg(not(feature = "7z010-7z007s-clg225"))]
299impl SsPin for Pin<Mio49> {
300 const SPI: SpiId = SpiId::Spi1;
301 const GROUP: usize = 3;
302 const IDX: usize = 0;
303}
304#[cfg(not(feature = "7z010-7z007s-clg225"))]
305impl SsPin for Pin<Mio50> {
306 const SPI: SpiId = SpiId::Spi1;
307 const GROUP: usize = 3;
308 const IDX: usize = 1;
309}
310#[cfg(not(feature = "7z010-7z007s-clg225"))]
311impl SsPin for Pin<Mio51> {
312 const SPI: SpiId = SpiId::Spi1;
313 const GROUP: usize = 3;
314 const IDX: usize = 2;
315}
316
317#[derive(Debug, PartialEq, Eq, Copy, Clone)]
318pub enum ChipSelect {
319 Slave0,
320 Slave1,
321 Slave2,
322 Decoded { cs0: bool, cs1: bool, cs2: bool },
323 None,
324}
325
326impl ChipSelect {
327 pub const fn raw_reg(&self) -> u4 {
328 u4::new(match self {
329 ChipSelect::Slave0 => 0b0000,
330 ChipSelect::Slave1 => 0b0001,
331 ChipSelect::Slave2 => 0b0010,
332 ChipSelect::None => 0b1111,
333 ChipSelect::Decoded { cs0, cs1, cs2 } => {
334 (1 << 3) | (*cs0 as u8) | ((*cs1 as u8) << 1) | ((*cs2 as u8) << 2)
335 }
336 })
337 }
338
339 #[inline]
340 pub const fn cs_no_ext_decoding(&self, raw: u4) -> Option<ChipSelect> {
341 let val = raw.value();
342 if val == 0b1111 {
343 return Some(ChipSelect::None);
344 }
345 if val & 0b1 == 0 {
346 return Some(ChipSelect::Slave0);
347 } else if val & 0b11 == 0b01 {
348 return Some(ChipSelect::Slave1);
349 } else if val & 0b111 == 0b010 {
350 return Some(ChipSelect::Slave2);
351 }
352 None
353 }
354}
355
356#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
357pub enum SlaveSelectConfig {
359 ManualWithManualStart = 0b11,
361 ManualAutoStart = 0b10,
362 AutoWithManualStart = 0b01,
364 #[default]
366 AutoWithAutoStart = 0b00,
367}
368
369#[derive(Debug, Copy, Clone)]
370pub struct Config {
371 baud_div: BaudDivSel,
372 init_mode: Mode,
373 ss_config: SlaveSelectConfig,
374 with_ext_decoding: bool,
375}
376
377impl Config {
378 pub fn new(baud_div: BaudDivSel, init_mode: Mode, ss_config: SlaveSelectConfig) -> Self {
379 Self {
380 baud_div,
381 init_mode,
382 ss_config,
383 with_ext_decoding: false,
384 }
385 }
386
387 pub fn enable_external_decoding(&mut self) {
388 self.with_ext_decoding = true;
389 }
390}
391
392pub struct SpiLowLevel {
394 id: SpiId,
395 regs: zynq7000::spi::MmioSpi<'static>,
396}
397
398impl SpiLowLevel {
399 pub unsafe fn steal(id: SpiId) -> Self {
407 let regs = unsafe {
408 match id {
409 SpiId::Spi0 => zynq7000::spi::Spi::new_mmio_fixed_0(),
410 SpiId::Spi1 => zynq7000::spi::Spi::new_mmio_fixed_1(),
411 }
412 };
413 Self { id, regs }
414 }
415
416 pub unsafe fn clone(&self) -> Self {
424 Self {
425 id: self.id,
426 regs: unsafe { self.regs.clone() },
427 }
428 }
429
430 pub fn id(&self) -> SpiId {
431 self.id
432 }
433
434 #[inline]
435 pub fn disable(&mut self) {
436 self.regs.write_enable(0);
437 }
438
439 #[inline]
440 pub fn enable(&mut self) {
441 self.regs.write_enable(1);
442 }
443
444 #[inline]
454 pub fn select_hw_cs(&mut self, chip_select: ChipSelect) {
455 self.regs.modify_cr(|mut val| {
456 val.set_cs_raw(chip_select.raw_reg());
457 val
458 });
459 }
460
461 #[inline]
463 pub fn configure_mode(&mut self, mode: Mode) {
464 let (cpol, cpha) = spi_mode_const_to_cpol_cpha(mode);
465 self.regs.modify_cr(|mut val| {
466 val.set_cpha(cpha);
467 val.set_cpol(cpol);
468 val
469 });
470 }
471
472 #[inline]
474 pub fn configure_delays(&mut self, config: DelayControl) {
475 self.regs.write_delay_control(config)
476 }
477
478 pub fn reconfigure(&mut self, config: Config) {
480 self.regs.write_enable(0);
481 let (man_ss, man_start) = match config.ss_config {
482 SlaveSelectConfig::ManualWithManualStart => (true, true),
483 SlaveSelectConfig::ManualAutoStart => (true, false),
484 SlaveSelectConfig::AutoWithManualStart => (false, true),
485 SlaveSelectConfig::AutoWithAutoStart => (false, false),
486 };
487 let (cpol, cpha) = spi_mode_const_to_cpol_cpha(config.init_mode);
488
489 self.regs.write_cr(
490 zynq7000::spi::Config::builder()
491 .with_modefail_gen_en(false)
492 .with_manual_start(false)
493 .with_manual_start_enable(man_start)
494 .with_manual_cs(man_ss)
495 .with_cs_raw(ChipSelect::None.raw_reg())
496 .with_peri_sel(config.with_ext_decoding)
497 .with_baud_rate_div(config.baud_div)
498 .with_cpha(cpha)
499 .with_cpol(cpol)
500 .with_master_ern(true)
501 .build(),
502 );
503 self.regs.write_tx_trig(1);
506 self.regs.write_rx_trig(1);
508
509 self.regs.write_enable(1);
510 }
511
512 pub fn reset_and_reconfigure(&mut self, config: Config) {
516 reset(self.id());
517 self.reconfigure(config);
518 }
519
520 #[inline]
522 pub fn no_hw_cs(&mut self) {
523 self.select_hw_cs(ChipSelect::None);
524 }
525
526 #[inline(always)]
527 pub fn write_fifo_unchecked(&mut self, data: u8) {
528 self.regs.write_txd(FifoWrite::new(data));
529 }
530
531 #[inline(always)]
532 pub fn read_fifo_unchecked(&mut self) -> u8 {
533 self.regs.read_rxd().value()
534 }
535
536 #[inline]
537 pub fn issue_manual_start(&mut self) {
538 self.regs.modify_cr(|mut val| {
539 val.set_manual_start(true);
540 val
541 });
542 }
543
544 #[inline]
545 pub fn read_isr(&self) -> InterruptStatus {
546 self.regs.read_isr()
547 }
548
549 #[inline]
550 pub fn read_imr(&self) -> InterruptMask {
551 self.regs.read_imr()
552 }
553
554 #[inline]
555 pub fn read_rx_not_empty_threshold(&self) -> u32 {
556 self.regs.read_rx_trig()
557 }
558
559 #[inline]
560 pub fn set_rx_fifo_trigger(&mut self, trigger: u32) -> Result<(), InvalidTriggerError> {
561 if trigger > FIFO_DEPTH as u32 {
562 return Err(InvalidTriggerError(trigger as usize));
563 }
564 self.regs.write_rx_trig(trigger.value());
565 Ok(())
566 }
567
568 #[inline]
569 pub fn set_tx_fifo_trigger(&mut self, trigger: u32) -> Result<(), InvalidTriggerError> {
570 if trigger > FIFO_DEPTH as u32 {
571 return Err(InvalidTriggerError(trigger as usize));
572 }
573 self.regs.write_tx_trig(trigger.value());
574 Ok(())
575 }
576
577 #[inline]
580 pub fn disable_interrupts(&mut self) {
581 self.regs.write_idr(
582 InterruptControl::builder()
583 .with_tx_underflow(true)
584 .with_rx_full(true)
585 .with_rx_not_empty(true)
586 .with_tx_full(false)
587 .with_tx_trig(true)
588 .with_mode_fault(false)
589 .with_rx_ovr(true)
590 .build(),
591 );
592 }
593
594 #[inline]
597 pub fn enable_interrupts(&mut self) {
598 self.regs.write_ier(
599 InterruptControl::builder()
600 .with_tx_underflow(true)
601 .with_rx_full(true)
602 .with_rx_not_empty(true)
603 .with_tx_full(false)
604 .with_tx_trig(true)
605 .with_mode_fault(false)
606 .with_rx_ovr(true)
607 .build(),
608 );
609 }
610
611 #[inline]
614 pub fn clear_interrupts(&mut self) {
615 self.regs.write_isr(
616 InterruptStatus::builder()
617 .with_tx_underflow(true)
618 .with_rx_full(true)
619 .with_rx_not_empty(true)
620 .with_tx_full(false)
621 .with_tx_not_full(true)
622 .with_mode_fault(false)
623 .with_rx_ovr(true)
624 .build(),
625 );
626 }
627}
628
629pub struct Spi {
631 inner: SpiLowLevel,
632 sclk: Hertz,
633 config: Config,
634 outstanding_rx: bool,
635}
636
637#[derive(Debug, thiserror::Error)]
638#[error("invalid SPI ID")]
639pub struct InvalidPsSpiError;
640
641#[derive(Debug, thiserror::Error)]
642#[error("invalid trigger value {0}")]
643pub struct InvalidTriggerError(pub usize);
644
645#[derive(Debug, thiserror::Error)]
647pub enum SpiConstructionError {
648 #[error("invalid SPI ID {0}")]
649 InvalidPsSpi(#[from] InvalidPsSpiError),
650 #[error("pin invalid for SPI ID")]
652 PinInvalidForSpiId,
653 #[error("pin group missmatch")]
655 GroupMissmatch,
656 #[error("invalid pin configuration for SPI")]
657 InvalidPinConf,
658}
659
660impl Spi {
661 pub fn new_no_hw_ss<Sck: SckPin, Mosi: MosiPin, Miso: MisoPin>(
662 spi: impl PsSpi,
663 clocks: &IoClocks,
664 config: Config,
665 spi_pins: (Sck, Mosi, Miso),
666 ) -> Result<Self, SpiConstructionError> {
667 let spi_id = spi.id();
668 if spi_id.is_none() {
669 return Err(InvalidPsSpiError.into());
670 }
671 let spi_id = spi_id.unwrap();
672 if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP {
673 return Err(SpiConstructionError::GroupMissmatch);
674 }
675 if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id {
676 return Err(SpiConstructionError::PinInvalidForSpiId);
677 }
678 IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
679 IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
680 IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
681 Ok(Self::new_generic_unchecked(
682 spi_id,
683 spi.reg_block(),
684 clocks,
685 config,
686 ))
687 }
688
689 pub fn new_one_hw_cs<Sck: SckPin, Mosi: MosiPin, Miso: MisoPin, Ss: SsPin>(
690 spi: impl PsSpi,
691 clocks: &IoClocks,
692 config: Config,
693 spi_pins: (Sck, Mosi, Miso),
694 ss_pin: Ss,
695 ) -> Result<Self, SpiConstructionError> {
696 let spi_id = spi.id();
697 if spi_id.is_none() {
698 return Err(InvalidPsSpiError.into());
699 }
700 let spi_id = spi_id.unwrap();
701 if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP || Sck::GROUP != Ss::GROUP {
702 return Err(SpiConstructionError::GroupMissmatch);
703 }
704 if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id || Ss::SPI != spi_id {
705 return Err(SpiConstructionError::PinInvalidForSpiId);
706 }
707 IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
708 IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
709 IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
710 IoPeriphPin::new(ss_pin, SPI_MUX_CONF, Some(false));
711 Ok(Self::new_generic_unchecked(
712 spi_id,
713 spi.reg_block(),
714 clocks,
715 config,
716 ))
717 }
718
719 pub fn new_with_two_hw_cs<Sck: SckPin, Mosi: MosiPin, Miso: MisoPin, Ss0: SsPin, Ss1: SsPin>(
720 spi: impl PsSpi,
721 clocks: &IoClocks,
722 config: Config,
723 spi_pins: (Sck, Mosi, Miso),
724 ss_pins: (Ss0, Ss1),
725 ) -> Result<Self, SpiConstructionError> {
726 let spi_id = spi.id();
727 if spi_id.is_none() {
728 return Err(InvalidPsSpiError.into());
729 }
730 let spi_id = spi_id.unwrap();
731 if Sck::GROUP != Mosi::GROUP
732 || Sck::GROUP != Miso::GROUP
733 || Sck::GROUP != Ss0::GROUP
734 || Sck::GROUP != Ss1::GROUP
735 {
736 return Err(SpiConstructionError::GroupMissmatch);
737 }
738 if Sck::SPI != spi_id
739 || Mosi::SPI != spi_id
740 || Miso::SPI != spi_id
741 || Ss0::SPI != spi_id
742 || Ss1::SPI != spi_id
743 {
744 return Err(SpiConstructionError::PinInvalidForSpiId);
745 }
746 IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
747 IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
748 IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
749 IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false));
750 IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false));
751 Ok(Self::new_generic_unchecked(
752 spi_id,
753 spi.reg_block(),
754 clocks,
755 config,
756 ))
757 }
758
759 pub fn new_with_three_hw_cs<
760 Sck: SckPin,
761 Mosi: MosiPin,
762 Miso: MisoPin,
763 Ss0: SsPin,
764 Ss1: SsPin,
765 Ss2: SsPin,
766 >(
767 spi: impl PsSpi,
768 clocks: &IoClocks,
769 config: Config,
770 spi_pins: (Sck, Mosi, Miso),
771 ss_pins: (Ss0, Ss1, Ss2),
772 ) -> Result<Self, SpiConstructionError> {
773 let spi_id = spi.id();
774 if spi_id.is_none() {
775 return Err(InvalidPsSpiError.into());
776 }
777 let spi_id = spi_id.unwrap();
778 if Sck::GROUP != Mosi::GROUP
779 || Sck::GROUP != Miso::GROUP
780 || Sck::GROUP != Ss0::GROUP
781 || Sck::GROUP != Ss1::GROUP
782 || Sck::GROUP != Ss2::GROUP
783 {
784 return Err(SpiConstructionError::GroupMissmatch);
785 }
786 if Sck::SPI != spi_id
787 || Mosi::SPI != spi_id
788 || Miso::SPI != spi_id
789 || Ss0::SPI != spi_id
790 || Ss1::SPI != spi_id
791 || Ss2::SPI != spi_id
792 {
793 return Err(SpiConstructionError::PinInvalidForSpiId);
794 }
795 IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
796 IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
797 IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
798 IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false));
799 IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false));
800 IoPeriphPin::new(ss_pins.2, SPI_MUX_CONF, Some(false));
801 Ok(Self::new_generic_unchecked(
802 spi_id,
803 spi.reg_block(),
804 clocks,
805 config,
806 ))
807 }
808
809 pub fn new_generic_unchecked(
810 id: SpiId,
811 regs: MmioSpi<'static>,
812 clocks: &IoClocks,
813 config: Config,
814 ) -> Self {
815 let periph_sel = match id {
816 SpiId::Spi0 => crate::PeriphSelect::Spi0,
817 SpiId::Spi1 => crate::PeriphSelect::Spi1,
818 };
819 enable_amba_peripheral_clock(periph_sel);
820 let sclk = clocks.spi_clk() / config.baud_div.div_value() as u32;
821 let mut spi = Self {
822 inner: SpiLowLevel { regs, id },
823 sclk,
824 config,
825 outstanding_rx: false,
826 };
827 spi.reset_and_reconfigure();
828 spi
829 }
830
831 pub fn reconfigure(&mut self) {
833 self.inner.reconfigure(self.config);
834 }
835
836 pub fn reset_and_reconfigure(&mut self) {
840 reset(self.inner.id());
841 self.reconfigure();
842 }
843
844 #[inline]
845 pub fn issue_manual_start_for_manual_cfg(&mut self) {
846 if self.config.ss_config == SlaveSelectConfig::AutoWithManualStart
847 || self.config.ss_config == SlaveSelectConfig::ManualWithManualStart
848 {
849 self.inner.issue_manual_start();
850 }
851 }
852
853 #[inline]
855 pub const fn sclk(&self) -> Hertz {
856 self.sclk
857 }
858
859 #[inline]
861 pub const fn inner(&mut self) -> &mut SpiLowLevel {
862 &mut self.inner
863 }
864
865 #[inline]
866 pub fn regs(&mut self) -> &mut MmioSpi<'static> {
867 &mut self.inner.regs
868 }
869
870 fn initial_fifo_fill(&mut self, words: &[u8]) -> usize {
871 let write_len = core::cmp::min(FIFO_DEPTH, words.len());
872 (0..write_len).for_each(|idx| {
873 self.inner.write_fifo_unchecked(words[idx]);
874 });
875 write_len
876 }
877
878 fn prepare_generic_blocking_transfer(&mut self, words: &[u8]) -> usize {
879 self.flush().unwrap();
882 self.inner.regs.write_rx_trig(1);
884
885 let written = self.initial_fifo_fill(words);
887
888 self.issue_manual_start_for_manual_cfg();
891 written
892 }
893}
894
895impl embedded_hal::spi::ErrorType for Spi {
896 type Error = Infallible;
897}
898
899impl embedded_hal::spi::SpiBus for Spi {
900 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
901 if words.is_empty() {
902 return Ok(());
903 }
904 self.flush()?;
907 self.regs().write_rx_trig(1);
909
910 let mut write_idx = core::cmp::min(FIFO_DEPTH, words.len());
911 (0..write_idx).for_each(|_| {
913 self.inner.write_fifo_unchecked(0);
914 });
915
916 self.issue_manual_start_for_manual_cfg();
919
920 let mut read_idx = 0;
921 while read_idx < words.len() {
922 let status = self.regs().read_isr();
923 if status.rx_not_empty() {
924 words[read_idx] = self.inner.read_fifo_unchecked();
925 read_idx += 1;
926 }
927 if write_idx < words.len() && !status.tx_full() {
929 self.inner.write_fifo_unchecked(0);
930 write_idx += 1;
931 }
932 }
933
934 Ok(())
935 }
936
937 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
938 if words.is_empty() {
939 return Ok(());
940 }
941 let mut written = self.prepare_generic_blocking_transfer(words);
942 let mut read_idx = 0;
943
944 while written < words.len() {
945 let status = self.regs().read_isr();
946 if status.rx_not_empty() {
949 self.inner.read_fifo_unchecked();
950 read_idx += 1;
951 }
952 if !status.tx_full() {
953 self.inner.write_fifo_unchecked(words[written]);
954 written += 1;
955 }
956 }
957 self.regs().write_rx_trig((words.len() - read_idx) as u32);
960 self.outstanding_rx = true;
961 Ok(())
962 }
963
964 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
965 if read.is_empty() {
966 return Ok(());
967 }
968 let mut write_idx = self.prepare_generic_blocking_transfer(write);
969 let mut read_idx = 0;
970 let max_idx = core::cmp::max(write.len(), read.len());
971
972 let mut writes_finished = write_idx == max_idx;
973 let mut reads_finished = false;
974 while !writes_finished || !reads_finished {
975 let status = self.regs().read_isr();
976 if status.rx_not_empty() && !reads_finished {
977 if read_idx < read.len() {
978 read[read_idx] = self.inner.read_fifo_unchecked();
979 } else {
980 self.inner.read_fifo_unchecked();
982 }
983 read_idx += 1;
984 }
985
986 if !status.tx_full() && !writes_finished {
987 if write_idx < write.len() {
988 self.inner.write_fifo_unchecked(write[write_idx]);
989 } else {
990 self.inner.write_fifo_unchecked(0);
992 }
993 write_idx += 1;
994 }
995 writes_finished = write_idx == max_idx;
996 reads_finished = read_idx == max_idx;
997 }
998
999 Ok(())
1000 }
1001
1002 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1003 if words.is_empty() {
1004 return Ok(());
1005 }
1006 let mut write_idx = self.prepare_generic_blocking_transfer(words);
1007 let mut read_idx = 0;
1008
1009 let mut writes_finished = write_idx == words.len();
1010 let mut reads_finished = false;
1011 while !writes_finished || !reads_finished {
1012 let status = self.inner.read_isr();
1013 if status.rx_not_empty() && !reads_finished {
1014 words[read_idx] = self.inner.read_fifo_unchecked();
1015 read_idx += 1;
1016 }
1017
1018 if !status.tx_full() && !writes_finished {
1019 self.inner.write_fifo_unchecked(words[write_idx]);
1020 write_idx += 1;
1021 }
1022 writes_finished = write_idx == words.len();
1023 reads_finished = read_idx == words.len();
1024 }
1025
1026 Ok(())
1027 }
1028
1029 fn flush(&mut self) -> Result<(), Self::Error> {
1031 if !self.outstanding_rx {
1032 return Ok(());
1033 }
1034 let rx_trig = self.inner.read_rx_not_empty_threshold();
1035 while !self.inner.read_isr().rx_not_empty() {}
1036 (0..rx_trig).for_each(|_| {
1037 self.inner.read_fifo_unchecked();
1038 });
1039 self.inner.set_rx_fifo_trigger(1).unwrap();
1040 self.outstanding_rx = false;
1041 Ok(())
1042 }
1043}
1044
1045pub struct SpiWithHwCs<Delay: DelayNs> {
1046 pub spi: Spi,
1047 pub cs: ChipSelect,
1048 pub delay: Delay,
1049}
1050
1051impl<Delay: DelayNs> SpiWithHwCs<Delay> {
1052 pub fn new(spi: Spi, cs: ChipSelect, delay: Delay) -> Self {
1053 Self { spi, cs, delay }
1054 }
1055
1056 pub fn release(self) -> Spi {
1057 self.spi
1058 }
1059}
1060
1061impl<Delay: DelayNs> embedded_hal::spi::ErrorType for SpiWithHwCs<Delay> {
1062 type Error = Infallible;
1063}
1064
1065impl<Delay: DelayNs> embedded_hal::spi::SpiDevice for SpiWithHwCs<Delay> {
1066 fn transaction(
1067 &mut self,
1068 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1069 ) -> Result<(), Self::Error> {
1070 self.spi.inner.select_hw_cs(self.cs);
1071 for op in operations {
1072 match op {
1073 embedded_hal::spi::Operation::Read(items) => {
1074 self.spi.read(items)?;
1075 }
1076 embedded_hal::spi::Operation::Write(items) => {
1077 self.spi.write(items)?;
1078 }
1079 embedded_hal::spi::Operation::Transfer(read, write) => {
1080 self.spi.transfer(read, write)?;
1081 }
1082 embedded_hal::spi::Operation::TransferInPlace(items) => {
1083 self.spi.transfer_in_place(items)?;
1084 }
1085 embedded_hal::spi::Operation::DelayNs(delay) => {
1086 self.delay.delay_ns(*delay);
1087 }
1088 }
1089 }
1090 self.spi.flush()?;
1091 self.spi.inner.no_hw_cs();
1092 Ok(())
1093 }
1094}
1095
1096#[inline]
1101pub fn reset(id: SpiId) {
1102 let assert_reset = match id {
1103 SpiId::Spi0 => DualRefAndClockReset::builder()
1104 .with_periph1_ref_rst(false)
1105 .with_periph0_ref_rst(true)
1106 .with_periph1_cpu1x_rst(false)
1107 .with_periph0_cpu1x_rst(true)
1108 .build(),
1109 SpiId::Spi1 => DualRefAndClockReset::builder()
1110 .with_periph1_ref_rst(true)
1111 .with_periph0_ref_rst(false)
1112 .with_periph1_cpu1x_rst(true)
1113 .with_periph0_cpu1x_rst(false)
1114 .build(),
1115 };
1116 unsafe {
1117 Slcr::with(|regs| {
1118 regs.reset_ctrl().write_spi(assert_reset);
1119 for _ in 0..3 {
1122 cortex_ar::asm::nop();
1123 }
1124 regs.reset_ctrl().write_spi(DualRefAndClockReset::DEFAULT);
1125 });
1126 }
1127}
1128
1129pub fn calculate_largest_allowed_spi_ref_clk_divisor(clks: &Clocks) -> Option<u6> {
1138 let slcr = unsafe { Slcr::steal() };
1139 let spi_clk_ctrl = slcr.regs().clk_ctrl_shared().read_spi_clk_ctrl();
1140 let div = match spi_clk_ctrl.srcsel() {
1141 zynq7000::slcr::clocks::SrcSelIo::IoPll | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => {
1142 clks.io_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk()
1143 }
1144 zynq7000::slcr::clocks::SrcSelIo::ArmPll => {
1145 clks.arm_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk()
1146 }
1147 zynq7000::slcr::clocks::SrcSelIo::DdrPll => {
1148 clks.ddr_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk()
1149 }
1150 };
1151 if div > u6::MAX.value() as u32 {
1152 return None;
1153 }
1154
1155 Some(u6::new(div as u8))
1156}
1157
1158pub fn configure_spi_ref_clk(clks: &mut Clocks, divisor: u6) {
1159 let mut slcr = unsafe { Slcr::steal() };
1160 let spi_clk_ctrl = slcr.regs().clk_ctrl_shared().read_spi_clk_ctrl();
1161 slcr.modify(|regs| {
1162 regs.clk_ctrl().modify_spi_clk_ctrl(|mut val| {
1163 val.set_divisor(divisor);
1164 val
1165 });
1166 });
1167 let new_clk = match spi_clk_ctrl.srcsel() {
1168 zynq7000::slcr::clocks::SrcSelIo::IoPll | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => {
1169 clks.io_clocks().ref_clk() / divisor.value() as u32
1170 }
1171 zynq7000::slcr::clocks::SrcSelIo::ArmPll => {
1172 clks.arm_clocks().ref_clk() / divisor.value() as u32
1173 }
1174 zynq7000::slcr::clocks::SrcSelIo::DdrPll => {
1175 clks.ddr_clocks().ref_clk() / divisor.value() as u32
1176 }
1177 };
1178 clks.io_clocks_mut().update_spi_clk(new_clk);
1179}