Skip to main content

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 }