1use core::marker::PhantomData;
3
4use embassy_embedded_hal::SetConfig;
5use embassy_futures::join::join;
6use embassy_hal_internal::{Peri, PeripheralType};
7pub use embedded_hal_02::spi::{Phase, Polarity};
8
9use crate::dma::{AnyChannel, Channel};
10use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
11use crate::{pac, peripherals};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[non_exhaustive]
17pub enum Error {
18 }
20
21#[non_exhaustive]
23#[derive(Clone)]
24pub struct Config {
25 pub frequency: u32,
27 pub phase: Phase,
29 pub polarity: Polarity,
31}
32
33impl Default for Config {
34 fn default() -> Self {
35 Self {
36 frequency: 1_000_000,
37 phase: Phase::CaptureOnFirstTransition,
38 polarity: Polarity::IdleLow,
39 }
40 }
41}
42
43pub struct Spi<'d, T: Instance, M: Mode> {
45 inner: Peri<'d, T>,
46 tx_dma: Option<Peri<'d, AnyChannel>>,
47 rx_dma: Option<Peri<'d, AnyChannel>>,
48 phantom: PhantomData<(&'d mut T, M)>,
49}
50
51fn div_roundup(a: u32, b: u32) -> u32 {
52 (a + b - 1) / b
53}
54
55fn calc_prescs(freq: u32) -> (u8, u8) {
56 let clk_peri = crate::clocks::clk_peri_freq();
57
58 let ratio = div_roundup(clk_peri, freq * 2);
64 if ratio > 127 * 256 {
65 panic!("Requested too low SPI frequency");
66 }
67
68 let presc = div_roundup(ratio, 256);
69 let postdiv = if presc == 1 { ratio } else { div_roundup(ratio, presc) };
70
71 ((presc * 2) as u8, (postdiv - 1) as u8)
72}
73
74impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
75 fn new_inner(
76 inner: Peri<'d, T>,
77 clk: Option<Peri<'d, AnyPin>>,
78 mosi: Option<Peri<'d, AnyPin>>,
79 miso: Option<Peri<'d, AnyPin>>,
80 cs: Option<Peri<'d, AnyPin>>,
81 tx_dma: Option<Peri<'d, AnyChannel>>,
82 rx_dma: Option<Peri<'d, AnyChannel>>,
83 config: Config,
84 ) -> Self {
85 Self::apply_config(&inner, &config);
86
87 let p = inner.regs();
88
89 p.dmacr().write(|reg| {
91 reg.set_rxdmae(true);
92 reg.set_txdmae(true);
93 });
94
95 p.cr1().write(|w| w.set_sse(true));
97
98 if let Some(pin) = &clk {
99 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
100 pin.pad_ctrl().write(|w| {
101 #[cfg(feature = "_rp235x")]
102 w.set_iso(false);
103 w.set_schmitt(true);
104 w.set_slewfast(false);
105 w.set_ie(true);
106 w.set_od(false);
107 w.set_pue(false);
108 w.set_pde(false);
109 });
110 }
111 if let Some(pin) = &mosi {
112 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
113 pin.pad_ctrl().write(|w| {
114 #[cfg(feature = "_rp235x")]
115 w.set_iso(false);
116 w.set_schmitt(true);
117 w.set_slewfast(false);
118 w.set_ie(true);
119 w.set_od(false);
120 w.set_pue(false);
121 w.set_pde(false);
122 });
123 }
124 if let Some(pin) = &miso {
125 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
126 pin.pad_ctrl().write(|w| {
127 #[cfg(feature = "_rp235x")]
128 w.set_iso(false);
129 w.set_schmitt(true);
130 w.set_slewfast(false);
131 w.set_ie(true);
132 w.set_od(false);
133 w.set_pue(false);
134 w.set_pde(false);
135 });
136 }
137 if let Some(pin) = &cs {
138 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
139 pin.pad_ctrl().write(|w| {
140 #[cfg(feature = "_rp235x")]
141 w.set_iso(false);
142 w.set_schmitt(true);
143 w.set_slewfast(false);
144 w.set_ie(true);
145 w.set_od(false);
146 w.set_pue(false);
147 w.set_pde(false);
148 });
149 }
150 Self {
151 inner,
152 tx_dma,
153 rx_dma,
154 phantom: PhantomData,
155 }
156 }
157
158 fn apply_config(inner: &Peri<'d, T>, config: &Config) {
163 let p = inner.regs();
164 let (presc, postdiv) = calc_prescs(config.frequency);
165
166 p.cpsr().write(|w| w.set_cpsdvsr(presc));
167 p.cr0().write(|w| {
168 w.set_dss(0b0111); w.set_spo(config.polarity == Polarity::IdleHigh);
170 w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
171 w.set_scr(postdiv);
172 });
173 }
174
175 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
177 let p = self.inner.regs();
178 for &b in data {
179 while !p.sr().read().tnf() {}
180 p.dr().write(|w| w.set_data(b as _));
181 while !p.sr().read().rne() {}
182 let _ = p.dr().read();
183 }
184 self.flush()?;
185 Ok(())
186 }
187
188 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
190 let p = self.inner.regs();
191 for b in data {
192 while !p.sr().read().tnf() {}
193 p.dr().write(|w| w.set_data(*b as _));
194 while !p.sr().read().rne() {}
195 *b = p.dr().read().data() as u8;
196 }
197 self.flush()?;
198 Ok(())
199 }
200
201 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
203 let p = self.inner.regs();
204 for b in data {
205 while !p.sr().read().tnf() {}
206 p.dr().write(|w| w.set_data(0));
207 while !p.sr().read().rne() {}
208 *b = p.dr().read().data() as u8;
209 }
210 self.flush()?;
211 Ok(())
212 }
213
214 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
216 let p = self.inner.regs();
217 let len = read.len().max(write.len());
218 for i in 0..len {
219 let wb = write.get(i).copied().unwrap_or(0);
220 while !p.sr().read().tnf() {}
221 p.dr().write(|w| w.set_data(wb as _));
222 while !p.sr().read().rne() {}
223 let rb = p.dr().read().data() as u8;
224 if let Some(r) = read.get_mut(i) {
225 *r = rb;
226 }
227 }
228 self.flush()?;
229 Ok(())
230 }
231
232 pub fn flush(&mut self) -> Result<(), Error> {
234 let p = self.inner.regs();
235 while p.sr().read().bsy() {}
236 Ok(())
237 }
238
239 pub fn set_frequency(&mut self, freq: u32) {
241 let (presc, postdiv) = calc_prescs(freq);
242 let p = self.inner.regs();
243 p.cr1().write(|w| w.set_sse(false));
245
246 p.cpsr().write(|w| w.set_cpsdvsr(presc));
248 p.cr0().modify(|w| {
249 w.set_scr(postdiv);
250 });
251
252 p.cr1().write(|w| w.set_sse(true));
254 }
255
256 pub fn set_config(&mut self, config: &Config) {
258 let p = self.inner.regs();
259
260 p.cr1().write(|w| w.set_sse(false));
262
263 Self::apply_config(&self.inner, config);
265
266 p.cr1().write(|w| w.set_sse(true));
268 }
269}
270
271impl<'d, T: Instance> Spi<'d, T, Blocking> {
272 pub fn new_blocking(
274 inner: Peri<'d, T>,
275 clk: Peri<'d, impl ClkPin<T> + 'd>,
276 mosi: Peri<'d, impl MosiPin<T> + 'd>,
277 miso: Peri<'d, impl MisoPin<T> + 'd>,
278 config: Config,
279 ) -> Self {
280 Self::new_inner(
281 inner,
282 Some(clk.into()),
283 Some(mosi.into()),
284 Some(miso.into()),
285 None,
286 None,
287 None,
288 config,
289 )
290 }
291
292 pub fn new_blocking_txonly(
294 inner: Peri<'d, T>,
295 clk: Peri<'d, impl ClkPin<T> + 'd>,
296 mosi: Peri<'d, impl MosiPin<T> + 'd>,
297 config: Config,
298 ) -> Self {
299 Self::new_inner(
300 inner,
301 Some(clk.into()),
302 Some(mosi.into()),
303 None,
304 None,
305 None,
306 None,
307 config,
308 )
309 }
310
311 pub fn new_blocking_rxonly(
313 inner: Peri<'d, T>,
314 clk: Peri<'d, impl ClkPin<T> + 'd>,
315 miso: Peri<'d, impl MisoPin<T> + 'd>,
316 config: Config,
317 ) -> Self {
318 Self::new_inner(
319 inner,
320 Some(clk.into()),
321 None,
322 Some(miso.into()),
323 None,
324 None,
325 None,
326 config,
327 )
328 }
329}
330
331impl<'d, T: Instance> Spi<'d, T, Async> {
332 pub fn new(
334 inner: Peri<'d, T>,
335 clk: Peri<'d, impl ClkPin<T> + 'd>,
336 mosi: Peri<'d, impl MosiPin<T> + 'd>,
337 miso: Peri<'d, impl MisoPin<T> + 'd>,
338 tx_dma: Peri<'d, impl Channel>,
339 rx_dma: Peri<'d, impl Channel>,
340 config: Config,
341 ) -> Self {
342 Self::new_inner(
343 inner,
344 Some(clk.into()),
345 Some(mosi.into()),
346 Some(miso.into()),
347 None,
348 Some(tx_dma.into()),
349 Some(rx_dma.into()),
350 config,
351 )
352 }
353
354 pub fn new_txonly(
356 inner: Peri<'d, T>,
357 clk: Peri<'d, impl ClkPin<T> + 'd>,
358 mosi: Peri<'d, impl MosiPin<T> + 'd>,
359 tx_dma: Peri<'d, impl Channel>,
360 config: Config,
361 ) -> Self {
362 Self::new_inner(
363 inner,
364 Some(clk.into()),
365 Some(mosi.into()),
366 None,
367 None,
368 Some(tx_dma.into()),
369 None,
370 config,
371 )
372 }
373
374 pub fn new_rxonly(
376 inner: Peri<'d, T>,
377 clk: Peri<'d, impl ClkPin<T> + 'd>,
378 miso: Peri<'d, impl MisoPin<T> + 'd>,
379 tx_dma: Peri<'d, impl Channel>,
380 rx_dma: Peri<'d, impl Channel>,
381 config: Config,
382 ) -> Self {
383 Self::new_inner(
384 inner,
385 Some(clk.into()),
386 None,
387 Some(miso.into()),
388 None,
389 Some(tx_dma.into()),
390 Some(rx_dma.into()),
391 config,
392 )
393 }
394
395 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
397 let tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
398 let tx_transfer = unsafe {
399 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
402 };
403 tx_transfer.await;
404
405 let p = self.inner.regs();
406 while p.sr().read().bsy() {}
407
408 while p.sr().read().rne() {
410 let _: u16 = p.dr().read().data();
411 }
412 p.icr().write(|w| w.set_roric(true));
414
415 Ok(())
416 }
417
418 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
420 let rx_ch = self.rx_dma.as_mut().unwrap().reborrow();
423 let rx_transfer = unsafe {
424 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
427 };
428
429 let tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
430 let tx_transfer = unsafe {
431 crate::dma::write_repeated(
434 tx_ch,
435 self.inner.regs().dr().as_ptr() as *mut u8,
436 buffer.len(),
437 T::TX_DREQ,
438 )
439 };
440 join(tx_transfer, rx_transfer).await;
441 Ok(())
442 }
443
444 pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> {
446 self.transfer_inner(rx_buffer, tx_buffer).await
447 }
448
449 pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
451 self.transfer_inner(words, words).await
452 }
453
454 async fn transfer_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
455 let rx_ch = self.rx_dma.as_mut().unwrap().reborrow();
458 let rx_transfer = unsafe {
459 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx, T::RX_DREQ)
462 };
463
464 let mut tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
465 let tx_transfer = async {
468 let p = self.inner.regs();
469 unsafe {
470 crate::dma::write(tx_ch.reborrow(), tx, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
471
472 if rx.len() > tx.len() {
473 let write_bytes_len = rx.len() - tx.len();
474 crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
477 }
478 }
479 };
480 join(tx_transfer, rx_transfer).await;
481
482 if tx.len() > rx.len() {
484 let p = self.inner.regs();
485 while p.sr().read().bsy() {}
486
487 while p.sr().read().rne() {
489 let _: u16 = p.dr().read().data();
490 }
491 p.icr().write(|w| w.set_roric(true));
493 }
494
495 Ok(())
496 }
497}
498
499trait SealedMode {}
500
501trait SealedInstance {
502 const TX_DREQ: pac::dma::vals::TreqSel;
503 const RX_DREQ: pac::dma::vals::TreqSel;
504
505 fn regs(&self) -> pac::spi::Spi;
506}
507
508#[allow(private_bounds)]
510pub trait Mode: SealedMode {}
511
512#[allow(private_bounds)]
514pub trait Instance: SealedInstance + PeripheralType {}
515
516macro_rules! impl_instance {
517 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
518 impl SealedInstance for peripherals::$type {
519 const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
520 const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
521
522 fn regs(&self) -> pac::spi::Spi {
523 pac::$type
524 }
525 }
526 impl Instance for peripherals::$type {}
527 };
528}
529
530impl_instance!(
531 SPI0,
532 Spi0,
533 pac::dma::vals::TreqSel::SPI0_TX,
534 pac::dma::vals::TreqSel::SPI0_RX
535);
536impl_instance!(
537 SPI1,
538 Spi1,
539 pac::dma::vals::TreqSel::SPI1_TX,
540 pac::dma::vals::TreqSel::SPI1_RX
541);
542
543pub trait ClkPin<T: Instance>: GpioPin {}
545pub trait CsPin<T: Instance>: GpioPin {}
547pub trait MosiPin<T: Instance>: GpioPin {}
549pub trait MisoPin<T: Instance>: GpioPin {}
551
552macro_rules! impl_pin {
553 ($pin:ident, $instance:ident, $function:ident) => {
554 impl $function<peripherals::$instance> for peripherals::$pin {}
555 };
556}
557
558impl_pin!(PIN_0, SPI0, MisoPin);
559impl_pin!(PIN_1, SPI0, CsPin);
560impl_pin!(PIN_2, SPI0, ClkPin);
561impl_pin!(PIN_3, SPI0, MosiPin);
562impl_pin!(PIN_4, SPI0, MisoPin);
563impl_pin!(PIN_5, SPI0, CsPin);
564impl_pin!(PIN_6, SPI0, ClkPin);
565impl_pin!(PIN_7, SPI0, MosiPin);
566impl_pin!(PIN_8, SPI1, MisoPin);
567impl_pin!(PIN_9, SPI1, CsPin);
568impl_pin!(PIN_10, SPI1, ClkPin);
569impl_pin!(PIN_11, SPI1, MosiPin);
570impl_pin!(PIN_12, SPI1, MisoPin);
571impl_pin!(PIN_13, SPI1, CsPin);
572impl_pin!(PIN_14, SPI1, ClkPin);
573impl_pin!(PIN_15, SPI1, MosiPin);
574impl_pin!(PIN_16, SPI0, MisoPin);
575impl_pin!(PIN_17, SPI0, CsPin);
576impl_pin!(PIN_18, SPI0, ClkPin);
577impl_pin!(PIN_19, SPI0, MosiPin);
578impl_pin!(PIN_20, SPI0, MisoPin);
579impl_pin!(PIN_21, SPI0, CsPin);
580impl_pin!(PIN_22, SPI0, ClkPin);
581impl_pin!(PIN_23, SPI0, MosiPin);
582impl_pin!(PIN_24, SPI1, MisoPin);
583impl_pin!(PIN_25, SPI1, CsPin);
584impl_pin!(PIN_26, SPI1, ClkPin);
585impl_pin!(PIN_27, SPI1, MosiPin);
586impl_pin!(PIN_28, SPI1, MisoPin);
587impl_pin!(PIN_29, SPI1, CsPin);
588#[cfg(feature = "rp235xb")]
589impl_pin!(PIN_30, SPI1, ClkPin);
590#[cfg(feature = "rp235xb")]
591impl_pin!(PIN_31, SPI1, MosiPin);
592#[cfg(feature = "rp235xb")]
593impl_pin!(PIN_32, SPI0, MisoPin);
594#[cfg(feature = "rp235xb")]
595impl_pin!(PIN_33, SPI0, CsPin);
596#[cfg(feature = "rp235xb")]
597impl_pin!(PIN_34, SPI0, ClkPin);
598#[cfg(feature = "rp235xb")]
599impl_pin!(PIN_35, SPI0, MosiPin);
600#[cfg(feature = "rp235xb")]
601impl_pin!(PIN_36, SPI0, MisoPin);
602#[cfg(feature = "rp235xb")]
603impl_pin!(PIN_37, SPI0, CsPin);
604#[cfg(feature = "rp235xb")]
605impl_pin!(PIN_38, SPI0, ClkPin);
606#[cfg(feature = "rp235xb")]
607impl_pin!(PIN_39, SPI0, MosiPin);
608#[cfg(feature = "rp235xb")]
609impl_pin!(PIN_40, SPI1, MisoPin);
610#[cfg(feature = "rp235xb")]
611impl_pin!(PIN_41, SPI1, CsPin);
612#[cfg(feature = "rp235xb")]
613impl_pin!(PIN_42, SPI1, ClkPin);
614#[cfg(feature = "rp235xb")]
615impl_pin!(PIN_43, SPI1, MosiPin);
616#[cfg(feature = "rp235xb")]
617impl_pin!(PIN_44, SPI1, MisoPin);
618#[cfg(feature = "rp235xb")]
619impl_pin!(PIN_45, SPI1, CsPin);
620#[cfg(feature = "rp235xb")]
621impl_pin!(PIN_46, SPI1, ClkPin);
622#[cfg(feature = "rp235xb")]
623impl_pin!(PIN_47, SPI1, MosiPin);
624
625macro_rules! impl_mode {
626 ($name:ident) => {
627 impl SealedMode for $name {}
628 impl Mode for $name {}
629 };
630}
631
632pub struct Blocking;
634pub struct Async;
636
637impl_mode!(Blocking);
638impl_mode!(Async);
639
640impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, T, M> {
643 type Error = Error;
644 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
645 self.blocking_transfer_in_place(words)?;
646 Ok(words)
647 }
648}
649
650impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, T, M> {
651 type Error = Error;
652
653 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
654 self.blocking_write(words)
655 }
656}
657
658impl embedded_hal_1::spi::Error for Error {
659 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
660 match *self {}
661 }
662}
663
664impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
665 type Error = Error;
666}
667
668impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
669 fn flush(&mut self) -> Result<(), Self::Error> {
670 Ok(())
671 }
672
673 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
674 self.blocking_transfer(words, &[])
675 }
676
677 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
678 self.blocking_write(words)
679 }
680
681 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
682 self.blocking_transfer(read, write)
683 }
684
685 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
686 self.blocking_transfer_in_place(words)
687 }
688}
689
690impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
691 async fn flush(&mut self) -> Result<(), Self::Error> {
692 Ok(())
693 }
694
695 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
696 self.write(words).await
697 }
698
699 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
700 self.read(words).await
701 }
702
703 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
704 self.transfer(read, write).await
705 }
706
707 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
708 self.transfer_in_place(words).await
709 }
710}
711
712impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
713 type Config = Config;
714 type ConfigError = ();
715 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
716 self.set_config(config);
717
718 Ok(())
719 }
720}