atsam4_hal/spi.rs
1//! SPI Implementation
2use crate::clock::{get_master_clock_frequency, Enabled, SpiClock};
3use crate::gpio::{Pa12, Pa13, Pa14, PfA};
4use crate::pac::SPI;
5use crate::pdc::*;
6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, Ordering};
8use embedded_dma::{ReadBuffer, WriteBuffer};
9use paste::paste;
10
11pub use embedded_hal::spi;
12pub use fugit::HertzU32 as Hertz;
13
14/// u8 that can convert back and forth with u16
15/// Needed for some of the register bit fields
16#[derive(Copy, Clone)]
17#[repr(transparent)]
18pub struct SpiU8(u8);
19
20impl From<u8> for SpiU8 {
21 fn from(val: u8) -> Self {
22 Self(val)
23 }
24}
25
26impl From<u16> for SpiU8 {
27 // Yes this will lose bits; however in this mode only the first 8bits are used
28 fn from(val: u16) -> Self {
29 Self(val as _)
30 }
31}
32
33impl From<SpiU16> for SpiU8 {
34 fn from(val: SpiU16) -> Self {
35 Self(val.0 as _)
36 }
37}
38
39impl From<SpiU8> for u8 {
40 fn from(val: SpiU8) -> Self {
41 val.0 as _
42 }
43}
44
45/// u16 that can convert back and forth with u8
46/// Needed for some of the register bit fields
47#[derive(Copy, Clone)]
48#[repr(transparent)]
49pub struct SpiU16(u16);
50
51impl From<u8> for SpiU16 {
52 fn from(val: u8) -> Self {
53 Self(val as _)
54 }
55}
56
57impl From<u16> for SpiU16 {
58 fn from(val: u16) -> Self {
59 Self(val)
60 }
61}
62
63impl From<SpiU8> for SpiU16 {
64 fn from(val: SpiU8) -> Self {
65 Self(val.0 as _)
66 }
67}
68
69impl From<SpiU16> for u16 {
70 fn from(val: SpiU16) -> Self {
71 val.0 as _
72 }
73}
74
75/// SPI Error
76#[derive(Clone, Copy, Debug, PartialEq, Eq, defmt::Format)]
77pub enum Error {
78 /// Overrun occurred
79 Overrun,
80 /// Underrun occurred (slave mode only)
81 Underrun,
82 /// Mode fault occurred
83 ModeFault,
84 /// SPI Disabled
85 SpiDisabled,
86 /// Invalid Chip Select
87 InvalidCs(u8),
88 /// Fixed Mode Set
89 FixedModeSet,
90 /// Variable Mode Set
91 VariableModeSet,
92 /// PCS read unexpected (data, pcs)
93 UnexpectedPcs(u16, u8),
94}
95
96/// Chip Select Active Settings
97/// This enum controls:
98/// CNSAAT -> Chip Select Not Active After Transfer
99/// CSAAT -> Chip Select Active After Transfer
100#[derive(Clone, Copy, Debug, PartialEq, Eq, defmt::Format)]
101pub enum ChipSelectActive {
102 /// csaat = 1, csnaat = 0
103 ActiveAfterTransfer,
104 /// csaat = 0, csnaat = 0
105 ActiveOnConsecutiveTransfers,
106 /// csaat = 0, csnaat = 1
107 InactiveAfterEachTransfer,
108}
109
110/// Transfer Width
111/// NOTE: Transfer Widths larger than 8-bits require using 16-bit with send/read
112#[derive(Clone, Copy, Debug, PartialEq, Eq, defmt::Format)]
113pub enum BitWidth {
114 Width8Bit = 0,
115 Width9Bit = 1,
116 Width10Bit = 2,
117 Width11Bit = 3,
118 Width12Bit = 4,
119 Width13Bit = 5,
120 Width14Bit = 6,
121 Width15Bit = 7,
122 Width16Bit = 8,
123}
124
125/// Peripheral Select Mode
126#[derive(Clone, Copy, Debug, PartialEq, Eq, defmt::Format)]
127pub enum PeripheralSelectMode {
128 /// Fixed Peripheral Select Mode (ps = 0, pcsdec = 0)
129 Fixed,
130 /// Variable Peripheral Select Mode (ps = 1, pcsdec = 0)
131 Variable,
132 /// Chip Select Decode (Variable) (ps = 1, pcsdec = 1)
133 ChipSelectDecode,
134}
135
136/// SPI Chip Select Settings
137///
138/// CPOL -> MODE
139/// NCPHA -> MODE
140/// CSNAAT -> CS not active after transfer (ignored if CSAAT = 1) => csa
141/// CSAAT -> CS active after transfer => csa
142/// BITS -> 8bit through 16bits
143/// SCBR -> Serial clock rate (SCBR = f_periph / SPCK bit rate) (0 forbidden)
144/// DLYBS -> Delay before SPCK (DLYBS x f_periph)
145/// DLYBCT -> Delay between consecutive transfers (DLYBCT x f_periph / 32)
146#[derive(Clone, PartialEq, Eq)]
147pub struct ChipSelectSettings {
148 mode: spi::Mode,
149 csa: ChipSelectActive,
150 scbr: u8,
151 dlybs: u8,
152 dlybct: u8,
153 bits: BitWidth,
154}
155
156impl ChipSelectSettings {
157 /// mode: SPI Mode
158 /// csa: Chip Select behaviour after transfer
159 /// bits: SPI bit width
160 /// baud: SPI speed in Hertz
161 /// dlybs: Cycles to delay from CS to first valid SPCK
162 /// 0 is half the SPCK clock period
163 /// Otherwise dlybs = Delay Before SPCK x f_periph
164 /// dlybct: Cycles to delay between consecutive transfers
165 /// 0 is no delay
166 /// Otherwise dlybct = Delay between consecutive transfers x f_periph / 32
167 pub fn new(
168 mode: spi::Mode,
169 csa: ChipSelectActive,
170 bits: BitWidth,
171 baud: Hertz,
172 dlybs: u8,
173 dlybct: u8,
174 ) -> ChipSelectSettings {
175 let pclk = get_master_clock_frequency();
176
177 // Calculate baud divider
178 // (f_periph + baud - 1) / baud
179 let scbr = ((pclk.raw() + baud.raw() - 1) / baud.raw()) as u8;
180 if scbr < 1 {
181 panic!("scbr must be greater than 0: {}", scbr);
182 }
183
184 ChipSelectSettings {
185 mode,
186 csa,
187 scbr,
188 dlybs,
189 dlybct,
190 bits,
191 }
192 }
193}
194
195/// SPI Master
196///
197/// Example on how to individually read/write to SPI CS channels
198/// ```
199/// use atsam4_hal::clock::{ClockController, MainClock, SlowClock};
200/// use atsam4_hal::pac::Peripherals;
201///
202/// let peripherals = Peripherals::take().unwrap();
203/// let clocks = ClockController::new(
204/// peripherals.PMC,
205/// &peripherals.SUPC,
206/// &peripherals.EFC0,
207/// MainClock::Crystal12Mhz,
208/// SlowClock::RcOscillator32Khz,
209/// );
210/// let gpio_ports = Ports::new(
211/// (
212/// peripherals.PIOA,
213/// clocks.peripheral_clocks.pio_a.into_enabled_clock(),
214/// ),
215/// (
216/// peripherals.PIOB,
217/// clocks.peripheral_clocks.pio_b.into_enabled_clock(),
218/// ),
219/// );
220/// let mut pins = Pins::new(gpio_ports, &peripherals.MATRIX)
221///
222/// // Setup SPI Master
223/// let wdrbt = false; // Wait data read before transfer enabled
224/// let llb = false; // Local loopback
225/// // Cycles to delay between consecutive transfers
226/// let dlybct = 0; // No delay
227/// // SpiU8 can be used as we're only using 8-bit SPI
228/// // SpiU16 can be used for 8 to 16-bit SPI
229/// let mut spi = SpiMaster::<SpiU8>::new(
230/// cx.device.SPI,
231/// clocks.peripheral_clocks.spi.into_enabled_clock(),
232/// pins.spi_miso,
233/// pins.spi_mosi,
234/// pins.spi_sck,
235/// spi::PeripheralSelectMode::Variable,
236/// wdrbt,
237/// llb,
238/// dlybct,
239/// );
240///
241/// // Setup CS0 channel
242/// let mode = spi::spi::MODE_3;
243/// let csa = spi::ChipSelectActive::ActiveAfterTransfer;
244/// let bits = spi::BitWidth::Width8Bit;
245/// let baud = spi::Hertz(12_000_000_u32); // 12 MHz
246/// // Cycles to delay from CS to first valid SPCK
247/// let dlybs = 0; // Half an SPCK clock period
248/// let cs_settings = spi::ChipSelectSettings::new(mode, csa, bits, baud, dlybs, dlybct);
249/// spi.cs_setup(0, cs_settings.clone()).unwrap();
250///
251/// // Enable CS0
252/// spi.cs_select(0).unwrap();
253///
254/// // Write value
255/// let val: u8 = 0x39;
256/// spi.send(val.into()).unwrap();
257///
258/// // Read value
259/// let val = match spi.read() {
260/// Ok(val) => val,
261/// _ => {}
262/// };
263/// ```
264pub struct SpiMaster<FRAMESIZE> {
265 spi: SPI,
266 clock: PhantomData<SpiClock<Enabled>>,
267 miso: PhantomData<Pa12<PfA>>,
268 mosi: PhantomData<Pa13<PfA>>,
269 spck: PhantomData<Pa14<PfA>>,
270 cs: u8,
271 lastxfer: bool,
272 framesize: PhantomData<FRAMESIZE>,
273}
274
275impl<FRAMESIZE> SpiMaster<FRAMESIZE> {
276 /// Initialize SPI as Master
277 /// PSM - Peripheral Select Mode
278 /// WDRBT - Wait Data Read Before Transfer Enabled
279 /// LLB - Local Loopback
280 /// DLYBCS - Delay between chip selects = DLYBCS / f_periph
281 #[allow(clippy::too_many_arguments)]
282 pub fn new(
283 spi: SPI,
284 _clock: SpiClock<Enabled>,
285 _miso: Pa12<PfA>,
286 _mosi: Pa13<PfA>,
287 _spck: Pa14<PfA>,
288 psm: PeripheralSelectMode,
289 wdrbt: bool,
290 llb: bool,
291 dlybcs: u8,
292 ) -> SpiMaster<FRAMESIZE> {
293 unsafe {
294 // Disable SPI
295 spi.cr.write_with_zero(|w| w.spidis().set_bit());
296
297 // Software reset SPI (this will reset SPI into Slave Mode)
298 spi.cr.write_with_zero(|w| w.swrst().set_bit());
299
300 // Enable SPI
301 spi.cr.write_with_zero(|w| w.spien().set_bit());
302
303 // Determine peripheral select mode
304 let (ps, pcsdec) = match psm {
305 PeripheralSelectMode::Fixed => (false, false),
306 PeripheralSelectMode::Variable => (true, false),
307 PeripheralSelectMode::ChipSelectDecode => (true, true),
308 };
309
310 // Clear spi protection mode register
311 // (needed before writing to SPI_MR and SPI_CSRx)
312 spi.wpmr
313 .write_with_zero(|w| w.wpkey().bits(0x535049).wpen().clear_bit());
314
315 // Setup SPI Master
316 // Master Mode
317 // Variable Peripheral Select (more flexible and less initial options to set)
318 // Mode Fault Detection Enabled
319 spi.mr.write_with_zero(|w| {
320 w.mstr()
321 .set_bit()
322 .ps()
323 .bit(ps)
324 .pcsdec()
325 .bit(pcsdec)
326 .modfdis()
327 .clear_bit()
328 .wdrbt()
329 .bit(wdrbt)
330 .llb()
331 .bit(llb)
332 .dlybcs()
333 .bits(dlybcs)
334 });
335 }
336
337 SpiMaster {
338 spi,
339 clock: PhantomData,
340 miso: PhantomData,
341 mosi: PhantomData,
342 spck: PhantomData,
343 cs: 0, // Default to NPCS0
344 lastxfer: false, // Reset to false on each call to send()
345 framesize: PhantomData,
346 }
347 }
348
349 /// Apply settings to a specific channel
350 /// Uses cs 0..3 for spi channel settings
351 /// When using pcsdec (Chip Decode Select)
352 /// csr0 -> 0..3
353 /// csr1 -> 4..7
354 /// csr2 -> 8..11
355 /// csr3 -> 12..14
356 pub fn cs_setup(&mut self, cs: u8, settings: ChipSelectSettings) -> Result<(), Error> {
357 // Lookup cs when using pcsdec
358 let cs = if self.spi.mr.read().pcsdec().bit_is_set() {
359 match cs {
360 0..=3 => 0,
361 4..=7 => 1,
362 8..=11 => 2,
363 12..=14 => 3,
364 _ => {
365 return Err(Error::InvalidCs(cs));
366 }
367 }
368
369 // Otherwise validate the cs
370 } else if cs > 3 {
371 return Err(Error::InvalidCs(cs));
372 } else {
373 cs
374 };
375
376 let cpol = match settings.mode.polarity {
377 spi::Polarity::IdleLow => false,
378 spi::Polarity::IdleHigh => true,
379 };
380 let ncpha = match settings.mode.phase {
381 spi::Phase::CaptureOnFirstTransition => true,
382 spi::Phase::CaptureOnSecondTransition => false,
383 };
384 let (csaat, csnaat) = match settings.csa {
385 ChipSelectActive::ActiveAfterTransfer => (true, false),
386 ChipSelectActive::ActiveOnConsecutiveTransfers => (false, false),
387 ChipSelectActive::InactiveAfterEachTransfer => (false, true),
388 };
389 unsafe {
390 self.spi.csr[cs as usize].write_with_zero(|w| {
391 w.cpol()
392 .bit(cpol)
393 .ncpha()
394 .bit(ncpha)
395 .csnaat()
396 .bit(csnaat)
397 .csaat()
398 .bit(csaat)
399 .bits_()
400 .bits(settings.bits as u8)
401 .scbr()
402 .bits(settings.scbr)
403 .dlybs()
404 .bits(settings.dlybs)
405 .dlybct()
406 .bits(settings.dlybct)
407 });
408 }
409
410 Ok(())
411 }
412
413 /// Select ChipSelect for next read/write FullDuplex trait functions
414 /// Works around limitations in the embedded-hal trait
415 /// Valid cs:
416 /// 0 -> 3 (as long as NPCS0..3 are configured)
417 /// 0 -> 15 (uses NPCS0..3 as the input to a 4 to 16 mux), pcsdec must be enabled
418 pub fn cs_select(&mut self, cs: u8) -> Result<(), Error> {
419 // Map cs to id
420 let pcs_id = match cs {
421 0 => 0b0000, // xxx0 => NPCS[3:0] = 1110
422 1 => 0b0001, // xx01 => NPCS[3:0] = 1101
423 2 => 0b0011, // x011 => NPCS[3:0] = 1011
424 3 => 0b0111, // 0111 => NPCS[3:0] = 0111
425 _ => 0b1111, // Forbidden
426 };
427
428 // Fixed mode
429 if self.spi.mr.read().ps().bit_is_clear() {
430 self.spi.mr.modify(|_, w| unsafe { w.pcs().bits(pcs_id) });
431
432 // Variable Mode
433 } else {
434 // Check for pcsdec
435 if self.spi.mr.read().pcsdec().bit_is_set() {
436 if cs > 15 {
437 return Err(Error::InvalidCs(cs));
438 }
439 self.cs = cs;
440 } else {
441 if cs > 3 {
442 return Err(Error::InvalidCs(cs));
443 }
444 // Map cs to id
445 self.cs = pcs_id;
446 }
447 }
448 Ok(())
449 }
450
451 /// lastxfer set
452 /// Fixed Mode
453 /// Sets lastxfer register
454 /// Variable Mode
455 /// Use to set lastxfer for the next call to send()
456 pub fn lastxfer(&mut self, lastxfer: bool) {
457 // Fixed mode
458 if self.spi.mr.read().ps().bit_is_clear() {
459 unsafe {
460 self.spi.cr.write_with_zero(|w| w.lastxfer().set_bit());
461 }
462 // Variable Mode
463 } else {
464 self.lastxfer = lastxfer;
465 }
466 }
467
468 /// Enable Receive Data Register Full (RDRF) interrupt
469 /// NOTE: Do not enable this if planning on using PDC as the PDC uses it to load the register
470 pub fn enable_rdrf_interrupt(&mut self) {
471 unsafe {
472 self.spi.ier.write_with_zero(|w| w.rdrf().set_bit());
473 }
474 }
475
476 /// Disable Receive Data Register Full (RDRF) interrupt
477 pub fn disable_rdrf_interrupt(&mut self) {
478 unsafe {
479 self.spi.idr.write_with_zero(|w| w.rdrf().set_bit());
480 }
481 }
482
483 /// Enable Transmit Data Register Empty (TDRE) interrupt
484 /// NOTE: Do not enable this if planning on using PDC as the PDC uses it to load the register
485 pub fn enable_tdre_interrupt(&mut self) {
486 unsafe {
487 self.spi.ier.write_with_zero(|w| w.tdre().set_bit());
488 }
489 }
490
491 /// Disable Transmit Data Register Empty (TDRE) interrupt
492 pub fn disable_tdre_interrupt(&mut self) {
493 unsafe {
494 self.spi.idr.write_with_zero(|w| w.tdre().set_bit());
495 }
496 }
497
498 /// Enable Mode Fault Error (MODF) interrupt
499 /// NOTE: Generally used in multi-master SPI environments
500 pub fn enable_modf_interrupt(&mut self) {
501 unsafe {
502 self.spi.ier.write_with_zero(|w| w.modf().set_bit());
503 }
504 }
505
506 /// Disable Mode Fault Error (MODF) interrupt
507 pub fn disable_modf_interrupt(&mut self) {
508 unsafe {
509 self.spi.idr.write_with_zero(|w| w.modf().set_bit());
510 }
511 }
512
513 /// Enable Overrun Error Status (OVRES) interrupt
514 pub fn enable_ovres_interrupt(&mut self) {
515 unsafe {
516 self.spi.ier.write_with_zero(|w| w.ovres().set_bit());
517 }
518 }
519
520 /// Disable Overrun Error Status (OVRES) interrupt
521 pub fn disable_ovres_interrupt(&mut self) {
522 unsafe {
523 self.spi.idr.write_with_zero(|w| w.ovres().set_bit());
524 }
525 }
526}
527
528/// Used to convert from variable pcs to cs
529/// See (33.8.4)
530/// <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11100-32-bit%20Cortex-M4-Microcontroller-SAM4S_Datasheet.pdf>
531fn variable_pcs_to_cs(pcs: u8) -> Result<u8, Error> {
532 // CS0
533 if (pcs & 0x1) == 0 {
534 Ok(0)
535 } else if (pcs & 0x2) == 0 {
536 Ok(1)
537 } else if (pcs & 0x4) == 0 {
538 Ok(2)
539 } else if (pcs & 0x8) == 0 {
540 Ok(3)
541 } else {
542 Err(Error::InvalidCs(0xF))
543 }
544}
545
546impl<FRAMESIZE> spi::FullDuplex<FRAMESIZE> for SpiMaster<FRAMESIZE>
547where
548 FRAMESIZE: Copy + From<SpiU16>,
549 SpiU16: From<FRAMESIZE> + From<SpiU8>,
550 u8: From<FRAMESIZE>,
551{
552 type Error = Error;
553
554 fn read(&mut self) -> nb::Result<FRAMESIZE, Error> {
555 let sr = self.spi.sr.read();
556 //defmt::trace!("Read: {}", sr.rdrf().bit_is_set());
557
558 // Check for errors (return error)
559 // Check for data to read (and read it)
560 // Return WouldBlock if no data available
561 Err(if sr.ovres().bit_is_set() {
562 defmt::trace!("Send overrun");
563 nb::Error::Other(Error::Overrun)
564 } else if sr.modf().bit_is_set() {
565 defmt::trace!("Mode fault");
566 nb::Error::Other(Error::ModeFault)
567 } else if sr.spiens().bit_is_clear() {
568 defmt::trace!("SPI disabled");
569 nb::Error::Other(Error::SpiDisabled)
570 } else if sr.rdrf().bit_is_set() {
571 let rdr = self.spi.rdr.read();
572
573 // In variable mode, verify pcs is what we expect
574 if self.spi.mr.read().ps().bit_is_set()
575 && variable_pcs_to_cs(rdr.pcs().bits())? != self.cs
576 {
577 nb::Error::Other(Error::UnexpectedPcs(rdr.rd().bits(), rdr.pcs().bits()))
578 } else {
579 return Ok(SpiU16(rdr.rd().bits()).into());
580 }
581 } else {
582 nb::Error::WouldBlock
583 })
584 }
585
586 fn send(&mut self, byte: FRAMESIZE) -> nb::Result<(), Error> {
587 let sr = self.spi.sr.read();
588 //let data: u8 = byte.into();
589 //defmt::trace!("Send: {} {}", data, sr.tdre().bit_is_set());
590
591 // Check for errors (return error)
592 // Make sure buffer is empty (then write if available)
593 // Return WouldBlock if buffer is full
594 Err(if sr.ovres().bit_is_set() {
595 defmt::trace!("Send overrun");
596 nb::Error::Other(Error::Overrun)
597 } else if sr.modf().bit_is_set() {
598 defmt::trace!("Send mode fault");
599 nb::Error::Other(Error::ModeFault)
600 } else if sr.spiens().bit_is_clear() {
601 defmt::trace!("Send spi disabled");
602 nb::Error::Other(Error::SpiDisabled)
603 } else if sr.tdre().bit_is_set() {
604 // Fixed Mode
605 if self.spi.mr.read().ps().bit_is_clear() {
606 self.write_fixed_data_reg(byte);
607
608 // Variable Mode
609 } else {
610 self.write_variable_data_reg(byte);
611 }
612 return Ok(());
613 } else {
614 nb::Error::WouldBlock
615 })
616 }
617}
618
619impl<FRAMESIZE> crate::hal::blocking::spi::transfer::Default<FRAMESIZE> for SpiMaster<FRAMESIZE>
620where
621 FRAMESIZE: Copy + From<SpiU16>,
622 SpiU16: From<FRAMESIZE> + From<SpiU8>,
623 u8: From<FRAMESIZE>,
624{
625}
626
627impl crate::hal::blocking::spi::Write<SpiU8> for SpiMaster<SpiU8> {
628 type Error = Error;
629
630 fn write(&mut self, words: &[SpiU8]) -> Result<(), Error> {
631 self.spi_write(words)
632 }
633}
634
635impl crate::hal::blocking::spi::Write<SpiU16> for SpiMaster<SpiU16> {
636 type Error = Error;
637
638 fn write(&mut self, words: &[SpiU16]) -> Result<(), Error> {
639 self.spi_write(words)
640 }
641}
642
643pub trait SpiReadWrite<T> {
644 fn read_data_reg(&mut self) -> T;
645 fn write_fixed_data_reg(&mut self, data: T);
646 fn write_variable_data_reg(&mut self, data: T);
647 fn spi_write(&mut self, words: &[T]) -> Result<(), Error>;
648}
649
650impl<FRAMESIZE> SpiReadWrite<FRAMESIZE> for SpiMaster<FRAMESIZE>
651where
652 FRAMESIZE: Copy + From<SpiU16>,
653 SpiU16: From<FRAMESIZE> + From<SpiU8>,
654{
655 fn read_data_reg(&mut self) -> FRAMESIZE {
656 let rdr = self.spi.rdr.read();
657 SpiU16(rdr.rd().bits()).into()
658 }
659
660 fn write_fixed_data_reg(&mut self, data: FRAMESIZE) {
661 unsafe {
662 let data: SpiU16 = data.into();
663 self.spi.tdr.write_with_zero(|w| w.td().bits(data.0));
664 }
665 }
666
667 fn write_variable_data_reg(&mut self, data: FRAMESIZE) {
668 // NOTE: Uses self.cs to write the pcs register field
669 unsafe {
670 let data: SpiU16 = data.into();
671 self.spi.tdr.write_with_zero(|w| {
672 w.td()
673 .bits(data.0)
674 .pcs()
675 .bits(self.cs)
676 .lastxfer()
677 .bit(self.lastxfer)
678 });
679 }
680 }
681
682 fn spi_write(&mut self, words: &[FRAMESIZE]) -> Result<(), Error> {
683 for word in words {
684 loop {
685 let sr = self.spi.sr.read();
686 if sr.tdre().bit_is_set() {
687 // Fixed Mode
688 if self.spi.mr.read().ps().bit_is_clear() {
689 self.write_fixed_data_reg(*word);
690
691 // Variable Mode
692 } else {
693 self.write_variable_data_reg(*word);
694 }
695 if sr.modf().bit_is_set() {
696 return Err(Error::ModeFault);
697 }
698 }
699 }
700 }
701 Ok(())
702 }
703}
704
705/// 8-bit fixed mode
706/// 8-bit data storage
707/// Any SPI settings must be done using the registers
708/// See section: 33.7.3.6
709/// <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11100-32-bit%20Cortex-M4-Microcontroller-SAM4S_Datasheet.pdf>
710///
711/// or
712///
713/// 9-16 bit fixed mode
714/// 16-bit data storage
715/// Any SPI settings must be done using the registers
716/// See section: 33.7.3.6
717/// <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11100-32-bit%20Cortex-M4-Microcontroller-SAM4S_Datasheet.pdf>
718pub struct Fixed;
719
720/// Variable mode
721/// 8-16 bit transfer sizes
722/// Can do per data word setting adjustments using the DMA stream
723/// 32-bits store:
724/// - data (8-16 bits)
725/// - pcs (CS) (4 bits)
726/// - lastxfer (1 bit)
727///
728/// Not as efficient RAM/flash wise, but fewer interrupts and polling loops are required as PDC can
729/// handle entire sequences talking to many SPI chips.
730///
731/// See section: 33.7.3.6
732/// <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11100-32-bit%20Cortex-M4-Microcontroller-SAM4S_Datasheet.pdf>
733pub struct Variable;
734
735pub struct SpiPayload<MODE, FRAMESIZE> {
736 spi: SpiMaster<FRAMESIZE>,
737 _mode: PhantomData<MODE>,
738}
739
740pub type SpiRxDma<MODE, FRAMESIZE> = RxDma<SpiPayload<MODE, FRAMESIZE>>;
741pub type SpiTxDma<MODE, FRAMESIZE> = TxDma<SpiPayload<MODE, FRAMESIZE>>;
742pub type SpiRxTxDma<MODE, FRAMESIZE> = RxTxDma<SpiPayload<MODE, FRAMESIZE>>;
743
744macro_rules! spi_pdc {
745 (
746 $Mode:ident, $Framesize:ident
747 ) => {
748 paste! {
749 impl SpiMaster<$Framesize> {
750 /// SPI with PDC, Rx only
751 pub fn with_pdc_rx(self) -> SpiRxDma<$Mode, $Framesize> {
752 let payload = SpiPayload {
753 spi: self,
754 _mode: PhantomData,
755 };
756 RxDma { payload }
757 }
758
759 /// SPI with PDC, Tx only
760 pub fn with_pdc_tx(self) -> SpiTxDma<$Mode, $Framesize> {
761 let payload = SpiPayload {
762 spi: self,
763 _mode: PhantomData,
764 };
765 TxDma { payload }
766 }
767
768 /// SPI with PDC, Rx+TX
769 /// ```
770 /// use atsam4_hal::clock::{ClockController, MainClock, SlowClock};
771 /// use atsam4_hal::pac::Peripherals;
772 ///
773 /// let peripherals = Peripherals::take().unwrap();
774 /// let clocks = ClockController::new(
775 /// peripherals.PMC,
776 /// &peripherals.SUPC,
777 /// &peripherals.EFC0,
778 /// MainClock::Crystal12Mhz,
779 /// SlowClock::RcOscillator32Khz,
780 /// );
781 /// let gpio_ports = Ports::new(
782 /// (
783 /// peripherals.PIOA,
784 /// clocks.peripheral_clocks.pio_a.into_enabled_clock(),
785 /// ),
786 /// (
787 /// peripherals.PIOB,
788 /// clocks.peripheral_clocks.pio_b.into_enabled_clock(),
789 /// ),
790 /// );
791 /// let mut pins = Pins::new(gpio_ports, &peripherals.MATRIX)
792 ///
793 /// // Setup SPI Master
794 /// let wdrbt = false; // Wait data read before transfer enabled
795 /// let llb = false; // Local loopback
796 /// // Cycles to delay between consecutive transfers
797 /// let dlybct = 0; // No delay
798 /// // SpiU8 can be used as we're only using 8-bit SPI
799 /// // SpiU16 can be used for 8 to 16-bit SPI
800 /// let mut spi = SpiMaster::<SpiU8>::new(
801 /// cx.device.SPI,
802 /// clocks.peripheral_clocks.spi.into_enabled_clock(),
803 /// pins.spi_miso,
804 /// pins.spi_mosi,
805 /// pins.spi_sck,
806 /// spi::PeripheralSelectMode::Variable,
807 /// wdrbt,
808 /// llb,
809 /// dlybct,
810 /// );
811 ///
812 /// // Setup SPI with pdc
813 /// let spi_tx_buf: [u32; 10] = [5; 10],
814 /// let spi_rx_buf: [u32; 10] = [0; 10],
815 /// let mut spi = spi.with_pdc_rxtx();
816 /// // Same as read_write() but use a smaller subset of the given buffer
817 /// let txfr = spi.read_write_len(spi_rx_buf, spi_tx_buf, 7);
818 /// let ((rx_buf, tx_buf), spi) = txfr.wait();
819 /// ```
820 pub fn with_pdc_rxtx(self) -> SpiRxTxDma<$Mode, $Framesize> {
821 let payload = SpiPayload {
822 spi: self,
823 _mode: PhantomData,
824 };
825 RxTxDma { payload }
826 }
827 }
828
829 // Setup PDC Rx/Tx functionality
830 pub type [<SpiMaster $Framesize>] = SpiMaster<$Framesize>;
831 pdc_rx! { [<SpiMaster $Framesize>]: spi, sr }
832 pdc_tx! { [<SpiMaster $Framesize>]: spi, sr }
833 pdc_rxtx! { [<SpiMaster $Framesize>]: spi }
834
835 impl Transmit for SpiTxDma<$Mode, $Framesize> {
836 type ReceivedWord = $Framesize;
837 }
838
839 impl Receive for SpiRxDma<$Mode, $Framesize> {
840 type TransmittedWord = $Framesize;
841 }
842
843 impl Receive for SpiRxTxDma<$Mode, $Framesize> {
844 type TransmittedWord = $Framesize;
845 }
846
847 impl Transmit for SpiRxTxDma<$Mode, $Framesize> {
848 type ReceivedWord = $Framesize;
849 }
850
851 impl SpiRxDma<$Mode, $Framesize> {
852 /// Reverts SpiRxDma back to SpiMaster
853 pub fn revert(mut self) -> SpiMaster<$Framesize> {
854 self.payload.spi.stop_rx_pdc();
855 self.payload.spi
856 }
857 }
858
859 impl<B> ReadDma<B, $Framesize> for SpiRxDma<$Mode, $Framesize>
860 where
861 Self: TransferPayload,
862 B: WriteBuffer<Word = $Framesize>,
863 {
864 /// Assigns the buffer, enables PDC and starts SPI transaction
865 fn read(mut self, mut buffer: B) -> Transfer<W, B, Self> {
866 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
867 // until the end of the transfer.
868 let (ptr, len) = unsafe { buffer.write_buffer() };
869 self.payload.spi.set_receive_address(ptr as u32);
870 self.payload.spi.set_receive_counter(len as u16);
871
872 compiler_fence(Ordering::Release);
873 self.start();
874
875 Transfer::w(buffer, self)
876 }
877 }
878
879 impl TransferPayload for SpiRxDma<$Mode, $Framesize> {
880 fn start(&mut self) {
881 self.payload.spi.start_rx_pdc();
882 }
883 fn stop(&mut self) {
884 self.payload.spi.stop_rx_pdc();
885 }
886 fn in_progress(&self) -> bool {
887 self.payload.spi.rx_in_progress()
888 }
889 }
890
891 impl SpiTxDma<$Mode, $Framesize> {
892 /// Reverts SpiTxDma back to SpiMaster
893 pub fn revert(mut self) -> SpiMaster<$Framesize> {
894 self.payload.spi.stop_tx_pdc();
895 self.payload.spi
896 }
897 }
898
899 impl<B> WriteDma<B, $Framesize> for SpiTxDma<$Mode, $Framesize>
900 where
901 Self: TransferPayload,
902 B: ReadBuffer<Word = $Framesize>,
903 {
904 /// Assigns the write buffer, enables PDC and starts SPI transaction
905 fn write(mut self, buffer: B) -> Transfer<R, B, Self> {
906 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
907 // until the end of the transfer.
908 let (ptr, len) = unsafe { buffer.read_buffer() };
909 self.payload.spi.set_transmit_address(ptr as u32);
910 self.payload.spi.set_transmit_counter(len as u16);
911
912 compiler_fence(Ordering::Release);
913 self.start();
914
915 Transfer::r(buffer, self)
916 }
917 }
918
919 impl TransferPayload for SpiTxDma<$Mode, $Framesize> {
920 fn start(&mut self) {
921 self.payload.spi.start_tx_pdc();
922 }
923 fn stop(&mut self) {
924 self.payload.spi.stop_tx_pdc();
925 }
926 fn in_progress(&self) -> bool {
927 self.payload.spi.tx_in_progress()
928 }
929 }
930
931 impl SpiRxTxDma<$Mode, $Framesize> {
932 /// Reverts SpiRxTxDma back to SpiMaster
933 pub fn revert(mut self) -> SpiMaster<$Framesize> {
934 self.payload.spi.stop_rxtx_pdc();
935 self.payload.spi
936 }
937 }
938
939 impl<RXB, TXB> ReadWriteDma<RXB, TXB, $Framesize> for SpiRxTxDma<$Mode, $Framesize>
940 where
941 Self: TransferPayload,
942 RXB: WriteBuffer<Word = $Framesize>,
943 TXB: ReadBuffer<Word = $Framesize>,
944 {
945 fn read_write(mut self, mut rx_buffer: RXB, tx_buffer: TXB) -> Transfer<W, (RXB, TXB), Self> {
946 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
947 // until the end of the transfer.
948 let (ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
949 self.payload.spi.set_receive_address(ptr as u32);
950 self.payload.spi.set_receive_counter(rx_len as u16);
951
952 let (ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
953 self.payload.spi.set_transmit_address(ptr as u32);
954 self.payload.spi.set_transmit_counter(tx_len as u16);
955
956 if rx_len != tx_len {
957 panic!("rx_len: {} != tx:len: {}", rx_len, tx_len);
958 }
959
960 compiler_fence(Ordering::Release);
961 self.start();
962
963 Transfer::w((rx_buffer, tx_buffer), self)
964 }
965 }
966
967 impl<RXB, TXB> ReadWriteDmaLen<RXB, TXB, $Framesize> for SpiRxTxDma<$Mode, $Framesize>
968 where
969 Self: TransferPayload,
970 RXB: WriteBuffer<Word = $Framesize>,
971 TXB: ReadBuffer<Word = $Framesize>,
972 {
973 /// Same as read_write(), but allows for a specified length
974 fn read_write_len(mut self, mut rx_buffer: RXB, rx_buf_len: usize, tx_buffer: TXB, tx_buf_len: usize) -> Transfer<W, (RXB, TXB), Self> {
975 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
976 // until the end of the transfer.
977 let (ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
978 self.payload.spi.set_receive_address(ptr as u32);
979 self.payload.spi.set_receive_counter(rx_buf_len as u16);
980 if rx_len < rx_buf_len {
981 panic!("rx_len: {} < rx_buf_len: {}", rx_len, rx_buf_len);
982 }
983
984 let (ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
985 self.payload.spi.set_transmit_address(ptr as u32);
986 self.payload.spi.set_transmit_counter(tx_buf_len as u16);
987 if tx_len < tx_buf_len {
988 panic!("tx_len: {} < tx_buf_len: {}", tx_len, tx_buf_len);
989 }
990
991 compiler_fence(Ordering::Release);
992 self.start();
993
994 Transfer::w((rx_buffer, tx_buffer), self)
995 }
996 }
997
998 impl TransferPayload for SpiRxTxDma<$Mode, $Framesize> {
999 fn start(&mut self) {
1000 self.payload.spi.start_rxtx_pdc();
1001 }
1002 fn stop(&mut self) {
1003 self.payload.spi.stop_rxtx_pdc();
1004 }
1005 fn in_progress(&self) -> bool {
1006 self.payload.spi.tx_in_progress() || self.payload.spi.rx_in_progress()
1007 }
1008 }
1009 }
1010 }
1011}
1012
1013// Setup SPI for each of the 3 different datastructures
1014spi_pdc! { Fixed, u8 }
1015spi_pdc! { Fixed, u16 }
1016spi_pdc! { Variable, u32 }