stm32f1xx_hal/
spi.rs

1/*!
2  # Serial Peripheral Interface
3  To construct the SPI instances, use the `Spi::spiX` functions.
4
5  The pin parameter is a tuple containing `(Some(sck), Some(miso), Some(mosi))` which should be configured as `(Alternate<...>, Input<...>, Alternate<...>)`.
6  As some STM32F1xx chips have 5V tolerant SPI pins, it is also possible to configure Sck and Mosi outputs as `Alternate<PushPull>`. Then
7  a simple Pull-Up to 5V can be used to use SPI on a 5V bus without a level shifter.
8
9  You can also use `None::<PA6>` or `SPI1::NoMiso` if you don't want to use the pins
10
11  ## Alternate function remapping
12
13  ## SPI1
14
15  | Function \ Remap        | 0 (default) | 1    |
16  |-------------------------|-------------|------|
17  | SCK (A-PP : I-F)        | PA5         | PB3  |
18  | MISO (I-F/PU : A-PP/OD) | PA6         | PB4  |
19  | MOSI (A-PP : I-F/PU)    | PA7         | PB5  |
20
21  ## SPI2
22
23  | Function                |      |
24  |-------------------------|------|
25  | SCK (A-PP : I-F)        | PB13 |
26  | MISO (I-F/PU : A-PP/OD) | PB14 |
27  | MOSI (A-PP : I-F/PU)    | PB15 |
28
29  ## SPI3
30
31  | Function \ Remap        | 0 (default) | 1 (conn. devices) |
32  |-------------------------|-------------|-------------------|
33  | SCK (A-PP : I-F)        | PB3         | PC10              |
34  | MISO (I-F/PU : A-PP/OD) | PB4         | PC11              |
35  | MOSI (A-PP : I-F/PU)    | PB5         | PC12              |
36
37  ## Initialisation example
38
39  ```rust
40    // Acquire the GPIOB peripheral
41    let mut gpiob = dp.GPIOB.split();
42
43    let pins = (
44        Some(gpiob.pb13.into_alternate_push_pull(&mut gpiob.crh)),
45        Some(gpiob.pb14.into_floating_input(&mut gpiob.crh)),
46        Some(gpiob.pb15.into_alternate_push_pull(&mut gpiob.crh)),
47    );
48
49    // or just
50
51    let pins = (
52        Some(gpiob.pb13),
53        Some(gpiob.pb14),
54        Some(gpiob.pb15),
55    );
56
57    let spi_mode = Mode {
58        polarity: Polarity::IdleLow,
59        phase: Phase::CaptureOnFirstTransition,
60    };
61    let spi = dp.SPI2.spi(pins, spi_mode, 100.khz(), &mut rcc);
62  ```
63*/
64
65mod hal_02;
66mod hal_1;
67
68use core::ops::{Deref, DerefMut};
69
70use crate::pac::{self, RCC};
71
72use crate::afio::{self, RInto, Rmp};
73use crate::dma::dma1;
74#[cfg(feature = "connectivity")]
75use crate::dma::dma2;
76use crate::dma::{self, Receive, RxDma, RxTxDma, Transfer, TransferPayload, Transmit, TxDma};
77use crate::gpio::{Floating, PushPull, UpMode};
78use crate::rcc::{BusClock, Enable, Rcc, Reset};
79use crate::time::Hertz;
80
81use core::sync::atomic::{self, Ordering};
82use embedded_dma::{ReadBuffer, WriteBuffer};
83
84/// Clock polarity
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub enum Polarity {
87    /// Clock signal low when idle
88    IdleLow,
89    /// Clock signal high when idle
90    IdleHigh,
91}
92
93/// Clock phase
94#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum Phase {
96    /// Data in "captured" on the first clock transition
97    CaptureOnFirstTransition,
98    /// Data in "captured" on the second clock transition
99    CaptureOnSecondTransition,
100}
101
102/// SPI mode
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub struct Mode {
105    /// Clock polarity
106    pub polarity: Polarity,
107    /// Clock phase
108    pub phase: Phase,
109}
110
111type SpiRB = pac::spi1::RegisterBlock;
112
113pub trait FrameSize: Copy + Default {
114    const DFF: bool;
115    #[doc(hidden)]
116    fn read_data(spi: &SpiRB) -> Self;
117    #[doc(hidden)]
118    fn write_data(self, spi: &SpiRB);
119}
120
121impl FrameSize for u8 {
122    const DFF: bool = false;
123    fn read_data(spi: &SpiRB) -> Self {
124        spi.dr8().read().dr().bits()
125    }
126    fn write_data(self, spi: &SpiRB) {
127        spi.dr8().write(|w| w.dr().set(self));
128    }
129}
130
131impl FrameSize for u16 {
132    const DFF: bool = true;
133    fn read_data(spi: &SpiRB) -> Self {
134        spi.dr().read().dr().bits()
135    }
136    fn write_data(self, spi: &SpiRB) {
137        spi.dr().write(|w| w.dr().set(self));
138    }
139}
140
141/// Interrupt event
142pub enum Event {
143    /// New data has been received
144    Rxne,
145    /// New data can be sent
146    Txe,
147    /// an error condition occurs(Crcerr, Overrun, ModeFault)
148    Error,
149}
150
151/// SPI error
152#[derive(Debug)]
153#[non_exhaustive]
154pub enum Error {
155    /// Overrun occurred
156    Overrun,
157    /// Mode fault occurred
158    ModeFault,
159    /// CRC error
160    Crc,
161}
162
163use core::marker::PhantomData;
164
165#[allow(non_upper_case_globals)]
166pub trait SpiExt: Sized + Instance {
167    const NoSck: Option<Self::MSck> = None;
168    const NoMiso: Option<Self::Mi<Floating>> = None;
169    const NoMosi: Option<Self::Mo> = None;
170    const NoSSck: Option<Self::SSck> = None;
171    const NoSo: Option<Self::So<PushPull>> = None;
172    const NoSi: Option<Self::Si<Floating>> = None;
173    fn spi<PULL: UpMode>(
174        self,
175        pins: (
176            Option<impl RInto<Self::MSck, 0>>,
177            Option<impl RInto<Self::Mi<PULL>, 0>>,
178            Option<impl RInto<Self::Mo, 0>>,
179        ),
180        mode: Mode,
181        freq: Hertz,
182        rcc: &mut Rcc,
183    ) -> Spi<Self, u8, PULL>;
184    fn spi_u16<PULL: UpMode>(
185        self,
186        pins: (
187            Option<impl RInto<Self::MSck, 0>>,
188            Option<impl RInto<Self::Mi<PULL>, 0>>,
189            Option<impl RInto<Self::Mo, 0>>,
190        ),
191        mode: Mode,
192        freq: Hertz,
193        rcc: &mut Rcc,
194    ) -> Spi<Self, u16, PULL> {
195        Self::spi(self, pins, mode, freq, rcc).frame_size_16bit()
196    }
197    fn spi_slave<Otype, PULL: UpMode>(
198        self,
199        pins: (
200            Option<impl RInto<Self::SSck, 0>>,
201            Option<impl RInto<Self::So<Otype>, 0>>,
202            Option<impl RInto<Self::Si<PULL>, 0>>,
203        ),
204        mode: Mode,
205        rcc: &mut RCC,
206    ) -> SpiSlave<Self, u8, Otype, PULL>;
207    fn spi_slave_u16<Otype, PULL: UpMode>(
208        self,
209        pins: (
210            Option<impl RInto<Self::SSck, 0>>,
211            Option<impl RInto<Self::So<Otype>, 0>>,
212            Option<impl RInto<Self::Si<PULL>, 0>>,
213        ),
214        mode: Mode,
215        rcc: &mut RCC,
216    ) -> SpiSlave<Self, u16, Otype, PULL> {
217        Self::spi_slave(self, pins, mode, rcc).frame_size_16bit()
218    }
219}
220
221impl<SPI: Instance> SpiExt for SPI {
222    fn spi<PULL: UpMode>(
223        self,
224        pins: (
225            Option<impl RInto<Self::MSck, 0>>,
226            Option<impl RInto<Self::Mi<PULL>, 0>>,
227            Option<impl RInto<Self::Mo, 0>>,
228        ),
229        mode: Mode,
230        freq: Hertz,
231        rcc: &mut Rcc,
232    ) -> Spi<Self, u8, PULL> {
233        Spi::new(self, pins, mode, freq, rcc)
234    }
235    fn spi_slave<Otype, PULL: UpMode>(
236        self,
237        pins: (
238            Option<impl RInto<Self::SSck, 0>>,
239            Option<impl RInto<Self::So<Otype>, 0>>,
240            Option<impl RInto<Self::Si<PULL>, 0>>,
241        ),
242        mode: Mode,
243        rcc: &mut RCC,
244    ) -> SpiSlave<Self, u8, Otype, PULL> {
245        SpiSlave::new(self, pins, mode, rcc)
246    }
247}
248
249pub struct SpiInner<SPI, W> {
250    spi: SPI,
251    _framesize: PhantomData<W>,
252}
253
254impl<SPI, W> SpiInner<SPI, W> {
255    fn new(spi: SPI) -> Self {
256        Self {
257            spi,
258            _framesize: PhantomData,
259        }
260    }
261}
262
263/// Spi in Master mode
264pub struct Spi<SPI: Instance, W, PULL = Floating> {
265    inner: SpiInner<SPI, W>,
266    #[allow(clippy::type_complexity)]
267    pins: (Option<SPI::MSck>, Option<SPI::Mi<PULL>>, Option<SPI::Mo>),
268}
269
270/// Spi in Slave mode
271pub struct SpiSlave<SPI: Instance, W, Otype = PushPull, PULL = Floating> {
272    inner: SpiInner<SPI, W>,
273    #[allow(clippy::type_complexity)]
274    pins: (
275        Option<SPI::SSck>,
276        Option<SPI::So<Otype>>,
277        Option<SPI::Si<PULL>>,
278    ),
279}
280
281impl<SPI: Instance, W, PULL> Deref for Spi<SPI, W, PULL> {
282    type Target = SpiInner<SPI, W>;
283    fn deref(&self) -> &Self::Target {
284        &self.inner
285    }
286}
287
288impl<SPI: Instance, W, PULL> DerefMut for Spi<SPI, W, PULL> {
289    fn deref_mut(&mut self) -> &mut Self::Target {
290        &mut self.inner
291    }
292}
293
294impl<SPI: Instance, W, Otype, PULL> Deref for SpiSlave<SPI, W, Otype, PULL> {
295    type Target = SpiInner<SPI, W>;
296    fn deref(&self) -> &Self::Target {
297        &self.inner
298    }
299}
300
301impl<SPI: Instance, W, Otype, PULL> DerefMut for SpiSlave<SPI, W, Otype, PULL> {
302    fn deref_mut(&mut self) -> &mut Self::Target {
303        &mut self.inner
304    }
305}
306
307/// The bit format to send the data in
308#[derive(Debug, Clone, Copy)]
309pub enum SpiBitFormat {
310    /// Least significant bit first
311    LsbFirst,
312    /// Most significant bit first
313    MsbFirst,
314}
315
316pub trait Instance:
317    crate::Sealed
318    + Deref<Target = crate::pac::spi1::RegisterBlock>
319    + Enable
320    + Reset
321    + BusClock
322    + afio::SpiCommon
323{
324}
325
326impl Instance for pac::SPI1 {}
327impl Instance for pac::SPI2 {}
328#[cfg(any(feature = "high", feature = "connectivity"))]
329impl Instance for pac::SPI3 {}
330
331impl<SPI: Instance, const R: u8> Rmp<SPI, R> {
332    pub fn spi<PULL: UpMode>(
333        self,
334        pins: (
335            Option<impl RInto<SPI::MSck, R>>,
336            Option<impl RInto<SPI::Mi<PULL>, R>>,
337            Option<impl RInto<SPI::Mo, R>>,
338        ),
339        mode: Mode,
340        freq: Hertz,
341        rcc: &mut Rcc,
342    ) -> Spi<SPI, u8, PULL> {
343        let spi = self.0;
344        // enable or reset SPI
345        SPI::enable(rcc);
346        SPI::reset(rcc);
347
348        // disable SS output
349        spi.cr2().write(|w| w.ssoe().clear_bit());
350
351        let br = match SPI::clock(&rcc.clocks) / freq {
352            0 => unreachable!(),
353            1..=2 => 0b000,
354            3..=5 => 0b001,
355            6..=11 => 0b010,
356            12..=23 => 0b011,
357            24..=47 => 0b100,
358            48..=95 => 0b101,
359            96..=191 => 0b110,
360            _ => 0b111,
361        };
362
363        let pins = (
364            pins.0.map(RInto::rinto),
365            pins.1.map(RInto::rinto),
366            pins.2.map(RInto::rinto),
367        );
368
369        spi.cr1().write(|w| {
370            // clock phase from config
371            w.cpha().bit(mode.phase == Phase::CaptureOnSecondTransition);
372            // clock polarity from config
373            w.cpol().bit(mode.polarity == Polarity::IdleHigh);
374            // mstr: master configuration
375            w.mstr().set_bit();
376            // baudrate value
377            w.br().set(br);
378            // lsbfirst: MSB first
379            w.lsbfirst().clear_bit();
380            // ssm: enable software slave management (NSS pin free for other uses)
381            w.ssm().set_bit();
382            // ssi: set nss high = master mode
383            w.ssi().set_bit();
384            // dff: 8 bit frames
385            w.dff().clear_bit();
386            // bidimode: 2-line unidirectional
387            w.bidimode().clear_bit();
388            // both TX and RX are used
389            w.rxonly().clear_bit();
390            // spe: enable the SPI bus
391            w.spe().set_bit()
392        });
393
394        Spi {
395            inner: SpiInner::new(spi),
396            pins,
397        }
398    }
399    pub fn spi_u16<PULL: UpMode>(
400        self,
401        pins: (
402            Option<impl RInto<SPI::MSck, R>>,
403            Option<impl RInto<SPI::Mi<PULL>, R>>,
404            Option<impl RInto<SPI::Mo, R>>,
405        ),
406        mode: Mode,
407        freq: Hertz,
408        rcc: &mut Rcc,
409    ) -> Spi<SPI, u16, PULL> {
410        self.spi(pins, mode, freq, rcc).frame_size_16bit()
411    }
412    pub fn spi_slave<Otype, PULL: UpMode>(
413        self,
414        pins: (
415            Option<impl RInto<SPI::SSck, R>>,
416            Option<impl RInto<SPI::So<Otype>, R>>,
417            Option<impl RInto<SPI::Si<PULL>, R>>,
418        ),
419        mode: Mode,
420        rcc: &mut RCC,
421    ) -> SpiSlave<SPI, u8, Otype, PULL> {
422        let spi = self.0;
423        // enable or reset SPI
424        SPI::enable(rcc);
425        SPI::reset(rcc);
426
427        // disable SS output
428        spi.cr2().write(|w| w.ssoe().clear_bit());
429
430        let pins = (
431            pins.0.map(RInto::rinto),
432            pins.1.map(RInto::rinto),
433            pins.2.map(RInto::rinto),
434        );
435
436        spi.cr1().write(|w| {
437            // clock phase from config
438            w.cpha().bit(mode.phase == Phase::CaptureOnSecondTransition);
439            // clock polarity from config
440            w.cpol().bit(mode.polarity == Polarity::IdleHigh);
441            // mstr: slave configuration
442            w.mstr().clear_bit();
443            // lsbfirst: MSB first
444            w.lsbfirst().clear_bit();
445            // ssm: enable software slave management (NSS pin free for other uses)
446            w.ssm().set_bit();
447            // ssi: set nss low = slave mode
448            w.ssi().clear_bit();
449            // dff: 8 bit frames
450            w.dff().clear_bit();
451            // bidimode: 2-line unidirectional
452            w.bidimode().clear_bit();
453            // both TX and RX are used
454            w.rxonly().clear_bit();
455            // spe: enable the SPI bus
456            w.spe().set_bit()
457        });
458
459        SpiSlave {
460            inner: SpiInner::new(spi),
461            pins,
462        }
463    }
464    pub fn spi_slave_u16<Otype, PULL: UpMode>(
465        self,
466        pins: (
467            Option<impl RInto<SPI::SSck, R>>,
468            Option<impl RInto<SPI::So<Otype>, R>>,
469            Option<impl RInto<SPI::Si<PULL>, R>>,
470        ),
471        mode: Mode,
472        rcc: &mut RCC,
473    ) -> SpiSlave<SPI, u16, Otype, PULL> {
474        self.spi_slave(pins, mode, rcc).frame_size_16bit()
475    }
476}
477
478impl<SPI: Instance, PULL: UpMode> Spi<SPI, u8, PULL> {
479    /**
480      Constructs an SPI instance using SPI1 in 8bit dataframe mode.
481
482      The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Alternate<PushPull>, Input<...>, Alternate<PushPull>)`.
483
484      You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
485    */
486    pub fn new<const R: u8>(
487        spi: impl Into<Rmp<SPI, R>>,
488        pins: (
489            Option<impl RInto<SPI::MSck, R>>,
490            Option<impl RInto<SPI::Mi<PULL>, R>>,
491            Option<impl RInto<SPI::Mo, R>>,
492        ),
493        mode: Mode,
494        freq: Hertz,
495        rcc: &mut Rcc,
496    ) -> Self {
497        spi.into().spi(pins, mode, freq, rcc)
498    }
499}
500
501impl<SPI: Instance, PULL> Spi<SPI, u8, PULL> {
502    #[allow(clippy::type_complexity)]
503    pub fn release(
504        self,
505    ) -> (
506        SPI,
507        (Option<SPI::MSck>, Option<SPI::Mi<PULL>>, Option<SPI::Mo>),
508    ) {
509        (self.inner.spi, self.pins)
510    }
511}
512
513impl<SPI: Instance, Otype, PULL: UpMode> SpiSlave<SPI, u8, Otype, PULL> {
514    /**
515      Constructs an SPI instance using SPI1 in 8bit dataframe mode.
516
517      The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Input<Floating>, Alternate<...>, Input<...>)`.
518
519      You can also use `NoMiso` or `NoMosi` if you don't want to use the pins
520    */
521    pub fn new<const R: u8>(
522        spi: impl Into<Rmp<SPI, R>>,
523        pins: (
524            Option<impl RInto<SPI::SSck, R>>,
525            Option<impl RInto<SPI::So<Otype>, R>>,
526            Option<impl RInto<SPI::Si<PULL>, R>>,
527        ),
528        mode: Mode,
529        rcc: &mut RCC,
530    ) -> Self {
531        spi.into().spi_slave(pins, mode, rcc)
532    }
533}
534
535impl<SPI: Instance, Otype, PULL> SpiSlave<SPI, u8, Otype, PULL> {
536    #[allow(clippy::type_complexity)]
537    pub fn release(
538        self,
539    ) -> (
540        SPI,
541        (
542            Option<SPI::SSck>,
543            Option<SPI::So<Otype>>,
544            Option<SPI::Si<PULL>>,
545        ),
546    ) {
547        (self.inner.spi, self.pins)
548    }
549}
550
551impl<SPI: Instance, W: FrameSize> SpiInner<SPI, W> {
552    // Implement write as per the "Transmit only procedure" page 712
553    // of RM0008 Rev 20. This is more than twice as fast as the
554    // default Write<> implementation (which reads and drops each
555    // received value)
556    fn spi_write(&mut self, words: &[W]) -> Result<(), Error> {
557        // Write each word when the tx buffer is empty
558        for word in words {
559            loop {
560                let sr = self.spi.sr().read();
561                if sr.txe().bit_is_set() {
562                    (*word).write_data(&self.spi);
563                    if sr.modf().bit_is_set() {
564                        return Err(Error::ModeFault);
565                    }
566                    break;
567                }
568            }
569        }
570        // Wait for final TXE
571        while !self.is_tx_empty() {}
572        // Wait for final !BSY
573        while self.is_busy() {}
574        // Clear OVR set due to dropped received values
575        let _ = W::read_data(&self.spi);
576        let _ = self.spi.sr().read();
577        Ok(())
578    }
579}
580
581impl<SPI: Instance, W> SpiInner<SPI, W> {
582    /// Select which frame format is used for data transfers
583    pub fn bit_format(&mut self, format: SpiBitFormat) {
584        self.spi
585            .cr1()
586            .modify(|_, w| w.lsbfirst().bit(matches!(format, SpiBitFormat::LsbFirst)));
587    }
588
589    /// Starts listening to the SPI by enabling the _Received data
590    /// ready to be read (RXNE)_ interrupt and _Transmit data
591    /// register empty (TXE)_ interrupt
592    pub fn listen(&mut self, event: Event) {
593        self.spi.cr2().modify(|_, w| match event {
594            Event::Rxne => w.rxneie().set_bit(),
595            Event::Txe => w.txeie().set_bit(),
596            Event::Error => w.errie().set_bit(),
597        });
598    }
599
600    /// Stops listening to the SPI by disabling the _Received data
601    /// ready to be read (RXNE)_ interrupt and _Transmit data
602    /// register empty (TXE)_ interrupt
603    pub fn unlisten(&mut self, event: Event) {
604        self.spi.cr2().modify(|_, w| match event {
605            Event::Rxne => w.rxneie().clear_bit(),
606            Event::Txe => w.txeie().clear_bit(),
607            Event::Error => w.errie().clear_bit(),
608        });
609    }
610
611    /// Returns true if the tx register is empty (and can accept data)
612    #[inline]
613    pub fn is_tx_empty(&self) -> bool {
614        self.spi.sr().read().txe().bit_is_set()
615    }
616
617    /// Returns true if the rx register is not empty (and can be read)
618    #[inline]
619    pub fn is_rx_not_empty(&self) -> bool {
620        self.spi.sr().read().rxne().bit_is_set()
621    }
622
623    /// Returns true if the transfer is in progress
624    #[inline]
625    pub fn is_busy(&self) -> bool {
626        self.spi.sr().read().bsy().bit_is_set()
627    }
628
629    /// Returns true if data are received and the previous data have not yet been read from SPI_DR.
630    #[inline]
631    pub fn is_overrun(&self) -> bool {
632        self.spi.sr().read().ovr().bit_is_set()
633    }
634}
635
636impl<SPI: Instance, PULL> Spi<SPI, u8, PULL> {
637    /// Converts from 8bit dataframe to 16bit.
638    pub fn frame_size_16bit(self) -> Spi<SPI, u16, PULL> {
639        self.spi.cr1().modify(|_, w| w.spe().clear_bit());
640        self.spi.cr1().modify(|_, w| w.dff().set_bit());
641        self.spi.cr1().modify(|_, w| w.spe().set_bit());
642        Spi {
643            inner: SpiInner::new(self.inner.spi),
644            pins: self.pins,
645        }
646    }
647}
648
649impl<SPI: Instance, Otype, PULL> SpiSlave<SPI, u8, Otype, PULL> {
650    /// Converts from 8bit dataframe to 16bit.
651    pub fn frame_size_16bit(self) -> SpiSlave<SPI, u16, Otype, PULL> {
652        self.spi.cr1().modify(|_, w| w.spe().clear_bit());
653        self.spi.cr1().modify(|_, w| w.dff().set_bit());
654        self.spi.cr1().modify(|_, w| w.spe().set_bit());
655        SpiSlave {
656            inner: SpiInner::new(self.inner.spi),
657            pins: self.pins,
658        }
659    }
660}
661
662impl<SPI: Instance, PULL> Spi<SPI, u16, PULL> {
663    /// Converts from 16bit dataframe to 8bit.
664    pub fn frame_size_8bit(self) -> Spi<SPI, u16, PULL> {
665        self.spi.cr1().modify(|_, w| w.spe().clear_bit());
666        self.spi.cr1().modify(|_, w| w.dff().clear_bit());
667        self.spi.cr1().modify(|_, w| w.spe().set_bit());
668        Spi {
669            inner: SpiInner::new(self.inner.spi),
670            pins: self.pins,
671        }
672    }
673}
674
675impl<SPI: Instance, Otype, PULL> SpiSlave<SPI, u16, Otype, PULL> {
676    /// Converts from 16bit dataframe to 8bit.
677    pub fn frame_size_8bit(self) -> SpiSlave<SPI, u8, Otype, PULL> {
678        self.spi.cr1().modify(|_, w| w.spe().clear_bit());
679        self.spi.cr1().modify(|_, w| w.dff().clear_bit());
680        self.spi.cr1().modify(|_, w| w.spe().set_bit());
681        SpiSlave {
682            inner: SpiInner::new(self.inner.spi),
683            pins: self.pins,
684        }
685    }
686}
687
688impl<SPI, W> SpiInner<SPI, W>
689where
690    SPI: Instance,
691    W: FrameSize,
692{
693    pub(crate) fn check_read(&mut self) -> nb::Result<W, Error> {
694        let sr = self.spi.sr().read();
695
696        Err(if sr.ovr().bit_is_set() {
697            Error::Overrun.into()
698        } else if sr.modf().bit_is_set() {
699            Error::ModeFault.into()
700        } else if sr.crcerr().bit_is_set() {
701            Error::Crc.into()
702        } else if sr.rxne().bit_is_set() {
703            // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
704            // reading a half-word)
705            return Ok(W::read_data(&self.spi));
706        } else {
707            nb::Error::WouldBlock
708        })
709    }
710
711    pub(crate) fn check_send(&mut self, data: W) -> nb::Result<(), Error> {
712        let sr = self.spi.sr().read();
713
714        // NOTE: Error::Overrun was deleted in #408. Need check
715        Err(if sr.modf().bit_is_set() {
716            Error::ModeFault.into()
717        } else if sr.crcerr().bit_is_set() {
718            Error::Crc.into()
719        } else if sr.txe().bit_is_set() {
720            // NOTE(write_volatile) see note above
721            data.write_data(&self.spi);
722            return Ok(());
723        } else {
724            nb::Error::WouldBlock
725        })
726    }
727
728    #[inline(always)]
729    pub fn read_nonblocking(&mut self) -> nb::Result<W, Error> {
730        // TODO: bidimode
731        self.check_read()
732    }
733
734    #[inline(always)]
735    pub fn write_nonblocking(&mut self, data: W) -> nb::Result<(), Error> {
736        // TODO: bidimode
737        self.check_send(data)
738    }
739
740    #[inline(always)]
741    pub fn write(&mut self, words: &[W]) -> Result<(), Error> {
742        self.spi_write(words)
743    }
744
745    pub fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> {
746        for word in words {
747            nb::block!(self.write_nonblocking(*word))?;
748            *word = nb::block!(self.read_nonblocking())?;
749        }
750
751        Ok(())
752    }
753
754    pub fn transfer(&mut self, buff: &mut [W], data: &[W]) -> Result<(), Error> {
755        if data.len() == buff.len() {
756            for (d, b) in data.iter().cloned().zip(buff.iter_mut()) {
757                nb::block!(self.write_nonblocking(d))?;
758                *b = nb::block!(self.read_nonblocking())?;
759            }
760        } else {
761            let mut iter_r = buff.iter_mut();
762            let mut iter_w = data.iter().cloned();
763            loop {
764                match (iter_r.next(), iter_w.next()) {
765                    (Some(r), Some(w)) => {
766                        nb::block!(self.write_nonblocking(w))?;
767                        *r = nb::block!(self.read_nonblocking())?;
768                    }
769                    (Some(r), None) => {
770                        nb::block!(self.write_nonblocking(W::default()))?;
771                        *r = nb::block!(self.read_nonblocking())?;
772                    }
773                    (None, Some(w)) => {
774                        nb::block!(self.write_nonblocking(w))?;
775                        let _ = nb::block!(self.read_nonblocking())?;
776                    }
777                    (None, None) => break,
778                }
779            }
780        }
781
782        Ok(())
783    }
784
785    pub fn flush(&mut self) -> Result<(), Error> {
786        Ok(())
787    }
788
789    pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
790        // TODO: bidimode
791        for word in words {
792            nb::block!(self.check_send(W::default()))?;
793            *word = nb::block!(self.check_read())?;
794        }
795
796        Ok(())
797    }
798}
799
800// DMA
801
802pub type SpiTxDma<SPI, CHANNEL, PULL = Floating> = TxDma<Spi<SPI, u8, PULL>, CHANNEL>;
803pub type SpiRxDma<SPI, CHANNEL, PULL = Floating> = RxDma<Spi<SPI, u8, PULL>, CHANNEL>;
804pub type SpiRxTxDma<SPI, RXCHANNEL, TXCHANNEL, PULL = Floating> =
805    RxTxDma<Spi<SPI, u8, PULL>, RXCHANNEL, TXCHANNEL>;
806
807pub type SpiSlaveTxDma<SPI, CHANNEL, Otype, PULL = Floating> =
808    TxDma<SpiSlave<SPI, u8, Otype, PULL>, CHANNEL>;
809pub type SpiSlaveRxDma<SPI, CHANNEL, Otype, PULL = Floating> =
810    RxDma<SpiSlave<SPI, u8, Otype, PULL>, CHANNEL>;
811pub type SpiSlaveRxTxDma<SPI, RXCHANNEL, TXCHANNEL, Otype, PULL = Floating> =
812    RxTxDma<SpiSlave<SPI, u8, Otype, PULL>, RXCHANNEL, TXCHANNEL>;
813
814macro_rules! spi_dma {
815    (
816        $SPIi:ty,
817        rx: $RCi:ty,
818        tx: $TCi:ty,
819        $rxdma:ident,
820        $txdma:ident,
821        $rxtxdma:ident,
822        $slaverxdma:ident,
823        $slavetxdma:ident,
824        $slaverxtxdma:ident
825    ) => {
826        pub type $rxdma<PULL = Floating> = SpiRxDma<$SPIi, $RCi, PULL>;
827        pub type $txdma<PULL = Floating> = SpiTxDma<$SPIi, $TCi, PULL>;
828        pub type $rxtxdma<PULL = Floating> = SpiRxTxDma<$SPIi, $RCi, $TCi, PULL>;
829
830        impl<PULL> Transmit for SpiTxDma<$SPIi, $TCi, PULL> {
831            type TxChannel = $TCi;
832            type ReceivedWord = u8;
833        }
834
835        impl<PULL> Receive for SpiRxDma<$SPIi, $RCi, PULL> {
836            type RxChannel = $RCi;
837            type TransmittedWord = u8;
838        }
839
840        impl<PULL> Transmit for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> {
841            type TxChannel = $TCi;
842            type ReceivedWord = u8;
843        }
844
845        impl<PULL> Receive for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> {
846            type RxChannel = $RCi;
847            type TransmittedWord = u8;
848        }
849
850        impl<PULL> Spi<$SPIi, u8, PULL> {
851            pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, $TCi, PULL> {
852                self.spi.cr2().modify(|_, w| w.txdmaen().set_bit());
853                SpiTxDma {
854                    payload: self,
855                    channel,
856                }
857            }
858            pub fn with_rx_dma(self, channel: $RCi) -> SpiRxDma<$SPIi, $RCi, PULL> {
859                self.spi.cr2().modify(|_, w| w.rxdmaen().set_bit());
860                SpiRxDma {
861                    payload: self,
862                    channel,
863                }
864            }
865            pub fn with_rx_tx_dma(
866                self,
867                rxchannel: $RCi,
868                txchannel: $TCi,
869            ) -> SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> {
870                self.spi
871                    .cr2()
872                    .modify(|_, w| w.rxdmaen().set_bit().txdmaen().set_bit());
873                SpiRxTxDma {
874                    payload: self,
875                    rxchannel,
876                    txchannel,
877                }
878            }
879        }
880
881        impl<PULL> SpiTxDma<$SPIi, $TCi, PULL> {
882            pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $TCi) {
883                let SpiTxDma { payload, channel } = self;
884                payload.spi.cr2().modify(|_, w| w.txdmaen().clear_bit());
885                (payload, channel)
886            }
887        }
888
889        impl<PULL> SpiRxDma<$SPIi, $RCi, PULL> {
890            pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $RCi) {
891                let SpiRxDma { payload, channel } = self;
892                payload.spi.cr2().modify(|_, w| w.rxdmaen().clear_bit());
893                (payload, channel)
894            }
895        }
896
897        impl<PULL> SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> {
898            pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $RCi, $TCi) {
899                let SpiRxTxDma {
900                    payload,
901                    rxchannel,
902                    txchannel,
903                } = self;
904                payload
905                    .spi
906                    .cr2()
907                    .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit());
908                (payload, rxchannel, txchannel)
909            }
910        }
911
912        impl<PULL> TransferPayload for SpiTxDma<$SPIi, $TCi, PULL> {
913            fn start(&mut self) {
914                self.channel.start();
915            }
916            fn stop(&mut self) {
917                self.channel.stop();
918            }
919        }
920
921        impl<PULL> TransferPayload for SpiRxDma<$SPIi, $RCi, PULL> {
922            fn start(&mut self) {
923                self.channel.start();
924            }
925            fn stop(&mut self) {
926                self.channel.stop();
927            }
928        }
929
930        impl<PULL> TransferPayload for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> {
931            fn start(&mut self) {
932                self.rxchannel.start();
933                self.txchannel.start();
934            }
935            fn stop(&mut self) {
936                self.txchannel.stop();
937                self.rxchannel.stop();
938            }
939        }
940
941        impl<B, PULL> crate::dma::ReadDma<B, u8> for SpiRxDma<$SPIi, $RCi, PULL>
942        where
943            B: WriteBuffer<Word = u8>,
944        {
945            fn read(mut self, mut buffer: B) -> Transfer<dma::W, B, 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, len) = unsafe { buffer.write_buffer() };
949                self.channel.set_peripheral_address(
950                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
951                    false,
952                );
953                self.channel.set_memory_address(ptr as u32, true);
954                self.channel.set_transfer_length(len);
955
956                atomic::compiler_fence(Ordering::Release);
957                self.channel.ch().cr().modify(|_, w| {
958                    // memory to memory mode disabled
959                    w.mem2mem().clear_bit();
960                    // medium channel priority level
961                    w.pl().medium();
962                    // 8-bit memory size
963                    w.msize().bits8();
964                    // 8-bit peripheral size
965                    w.psize().bits8();
966                    // circular mode disabled
967                    w.circ().clear_bit();
968                    // write to memory
969                    w.dir().clear_bit()
970                });
971                self.start();
972
973                Transfer::w(buffer, self)
974            }
975        }
976
977        impl<B, PULL> crate::dma::WriteDma<B, u8> for SpiTxDma<$SPIi, $TCi, PULL>
978        where
979            B: ReadBuffer<Word = u8>,
980        {
981            fn write(mut self, buffer: B) -> Transfer<dma::R, B, Self> {
982                // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
983                // until the end of the transfer.
984                let (ptr, len) = unsafe { buffer.read_buffer() };
985                self.channel.set_peripheral_address(
986                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
987                    false,
988                );
989                self.channel.set_memory_address(ptr as u32, true);
990                self.channel.set_transfer_length(len);
991
992                atomic::compiler_fence(Ordering::Release);
993                self.channel.ch().cr().modify(|_, w| {
994                    // memory to memory mode disabled
995                    w.mem2mem().clear_bit();
996                    // medium channel priority level
997                    w.pl().medium();
998                    // 8-bit memory size
999                    w.msize().bits8();
1000                    // 8-bit peripheral size
1001                    w.psize().bits8();
1002                    // circular mode disabled
1003                    w.circ().clear_bit();
1004                    // read from memory
1005                    w.dir().set_bit()
1006                });
1007                self.start();
1008
1009                Transfer::r(buffer, self)
1010            }
1011        }
1012
1013        impl<RXB, TXB, PULL> crate::dma::ReadWriteDma<RXB, TXB, u8>
1014            for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL>
1015        where
1016            RXB: WriteBuffer<Word = u8>,
1017            TXB: ReadBuffer<Word = u8>,
1018        {
1019            fn read_write(
1020                mut self,
1021                mut rxbuffer: RXB,
1022                txbuffer: TXB,
1023            ) -> Transfer<dma::W, (RXB, TXB), Self> {
1024                // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
1025                // until the end of the transfer.
1026                let (rxptr, rxlen) = unsafe { rxbuffer.write_buffer() };
1027                let (txptr, txlen) = unsafe { txbuffer.read_buffer() };
1028
1029                if rxlen != txlen {
1030                    panic!("receive and send buffer lengths do not match!");
1031                }
1032
1033                self.rxchannel.set_peripheral_address(
1034                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1035                    false,
1036                );
1037                self.rxchannel.set_memory_address(rxptr as u32, true);
1038                self.rxchannel.set_transfer_length(rxlen);
1039
1040                self.txchannel.set_peripheral_address(
1041                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1042                    false,
1043                );
1044                self.txchannel.set_memory_address(txptr as u32, true);
1045                self.txchannel.set_transfer_length(txlen);
1046
1047                atomic::compiler_fence(Ordering::Release);
1048                self.rxchannel.ch().cr().modify(|_, w| {
1049                    // memory to memory mode disabled
1050                    w.mem2mem().clear_bit();
1051                    // medium channel priority level
1052                    w.pl().medium();
1053                    // 8-bit memory size
1054                    w.msize().bits8();
1055                    // 8-bit peripheral size
1056                    w.psize().bits8();
1057                    // circular mode disabled
1058                    w.circ().clear_bit();
1059                    // write to memory
1060                    w.dir().clear_bit()
1061                });
1062                self.txchannel.ch().cr().modify(|_, w| {
1063                    // memory to memory mode disabled
1064                    w.mem2mem().clear_bit();
1065                    // medium channel priority level
1066                    w.pl().medium();
1067                    // 8-bit memory size
1068                    w.msize().bits8();
1069                    // 8-bit peripheral size
1070                    w.psize().bits8();
1071                    // circular mode disabled
1072                    w.circ().clear_bit();
1073                    // read from memory
1074                    w.dir().set_bit()
1075                });
1076                self.start();
1077
1078                Transfer::w((rxbuffer, txbuffer), self)
1079            }
1080        }
1081
1082        pub type $slaverxdma<Otype = PushPull, PULL = Floating> =
1083            SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL>;
1084        pub type $slavetxdma<Otype = PushPull, PULL = Floating> =
1085            SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL>;
1086        pub type $slaverxtxdma<Otype = PushPull, PULL = Floating> =
1087            SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL>;
1088
1089        impl<Otype, PULL> Transmit for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> {
1090            type TxChannel = $TCi;
1091            type ReceivedWord = u8;
1092        }
1093
1094        impl<Otype, PULL> Receive for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> {
1095            type RxChannel = $RCi;
1096            type TransmittedWord = u8;
1097        }
1098
1099        impl<Otype, PULL> Transmit for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> {
1100            type TxChannel = $TCi;
1101            type ReceivedWord = u8;
1102        }
1103
1104        impl<Otype, PULL> Receive for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> {
1105            type RxChannel = $RCi;
1106            type TransmittedWord = u8;
1107        }
1108
1109        impl<Otype, PULL> SpiSlave<$SPIi, u8, Otype, PULL> {
1110            pub fn with_tx_dma(self, channel: $TCi) -> SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> {
1111                self.spi.cr2().modify(|_, w| w.txdmaen().set_bit());
1112                SpiSlaveTxDma {
1113                    payload: self,
1114                    channel,
1115                }
1116            }
1117            pub fn with_rx_dma(self, channel: $RCi) -> SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> {
1118                self.spi.cr2().modify(|_, w| w.rxdmaen().set_bit());
1119                SpiSlaveRxDma {
1120                    payload: self,
1121                    channel,
1122                }
1123            }
1124            pub fn with_rx_tx_dma(
1125                self,
1126                rxchannel: $RCi,
1127                txchannel: $TCi,
1128            ) -> SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> {
1129                self.spi
1130                    .cr2()
1131                    .modify(|_, w| w.rxdmaen().set_bit().txdmaen().set_bit());
1132                SpiSlaveRxTxDma {
1133                    payload: self,
1134                    rxchannel,
1135                    txchannel,
1136                }
1137            }
1138        }
1139
1140        impl<Otype, PULL> SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> {
1141            pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $TCi) {
1142                let SpiSlaveTxDma { payload, channel } = self;
1143                payload.spi.cr2().modify(|_, w| w.txdmaen().clear_bit());
1144                (payload, channel)
1145            }
1146        }
1147
1148        impl<Otype, PULL> SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> {
1149            pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $RCi) {
1150                let SpiSlaveRxDma { payload, channel } = self;
1151                payload.spi.cr2().modify(|_, w| w.rxdmaen().clear_bit());
1152                (payload, channel)
1153            }
1154        }
1155
1156        impl<Otype, PULL> SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> {
1157            pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $RCi, $TCi) {
1158                let SpiSlaveRxTxDma {
1159                    payload,
1160                    rxchannel,
1161                    txchannel,
1162                } = self;
1163                payload
1164                    .spi
1165                    .cr2()
1166                    .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit());
1167                (payload, rxchannel, txchannel)
1168            }
1169        }
1170
1171        impl<Otype, PULL> TransferPayload for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> {
1172            fn start(&mut self) {
1173                self.channel.start();
1174            }
1175            fn stop(&mut self) {
1176                self.channel.stop();
1177            }
1178        }
1179
1180        impl<Otype, PULL> TransferPayload for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> {
1181            fn start(&mut self) {
1182                self.channel.start();
1183            }
1184            fn stop(&mut self) {
1185                self.channel.stop();
1186            }
1187        }
1188
1189        impl<Otype, PULL> TransferPayload for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> {
1190            fn start(&mut self) {
1191                self.rxchannel.start();
1192                self.txchannel.start();
1193            }
1194            fn stop(&mut self) {
1195                self.txchannel.stop();
1196                self.rxchannel.stop();
1197            }
1198        }
1199
1200        impl<B, Otype, PULL> crate::dma::ReadDma<B, u8> for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL>
1201        where
1202            B: WriteBuffer<Word = u8>,
1203        {
1204            fn read(mut self, mut buffer: B) -> Transfer<dma::W, B, Self> {
1205                // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
1206                // until the end of the transfer.
1207                let (ptr, len) = unsafe { buffer.write_buffer() };
1208                self.channel.set_peripheral_address(
1209                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1210                    false,
1211                );
1212                self.channel.set_memory_address(ptr as u32, true);
1213                self.channel.set_transfer_length(len);
1214
1215                atomic::compiler_fence(Ordering::Release);
1216                self.channel.ch().cr().modify(|_, w| {
1217                    // memory to memory mode disabled
1218                    w.mem2mem().clear_bit();
1219                    // medium channel priority level
1220                    w.pl().medium();
1221                    // 8-bit memory size
1222                    w.msize().bits8();
1223                    // 8-bit peripheral size
1224                    w.psize().bits8();
1225                    // circular mode disabled
1226                    w.circ().clear_bit();
1227                    // write to memory
1228                    w.dir().clear_bit()
1229                });
1230                self.start();
1231
1232                Transfer::w(buffer, self)
1233            }
1234        }
1235
1236        impl<B, Otype, PULL> crate::dma::WriteDma<B, u8> for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL>
1237        where
1238            B: ReadBuffer<Word = u8>,
1239        {
1240            fn write(mut self, buffer: B) -> Transfer<dma::R, B, Self> {
1241                // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
1242                // until the end of the transfer.
1243                let (ptr, len) = unsafe { buffer.read_buffer() };
1244                self.channel.set_peripheral_address(
1245                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1246                    false,
1247                );
1248                self.channel.set_memory_address(ptr as u32, true);
1249                self.channel.set_transfer_length(len);
1250
1251                atomic::compiler_fence(Ordering::Release);
1252                self.channel.ch().cr().modify(|_, w| {
1253                    // memory to memory mode disabled
1254                    w.mem2mem().clear_bit();
1255                    // medium channel priority level
1256                    w.pl().medium();
1257                    // 8-bit memory size
1258                    w.msize().bits8();
1259                    // 8-bit peripheral size
1260                    w.psize().bits8();
1261                    // circular mode disabled
1262                    w.circ().clear_bit();
1263                    // read from memory
1264                    w.dir().set_bit()
1265                });
1266                self.start();
1267
1268                Transfer::r(buffer, self)
1269            }
1270        }
1271
1272        impl<RXB, TXB, Otype, PULL> crate::dma::ReadWriteDma<RXB, TXB, u8>
1273            for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL>
1274        where
1275            RXB: WriteBuffer<Word = u8>,
1276            TXB: ReadBuffer<Word = u8>,
1277        {
1278            fn read_write(
1279                mut self,
1280                mut rxbuffer: RXB,
1281                txbuffer: TXB,
1282            ) -> Transfer<dma::W, (RXB, TXB), Self> {
1283                // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
1284                // until the end of the transfer.
1285                let (rxptr, rxlen) = unsafe { rxbuffer.write_buffer() };
1286                let (txptr, txlen) = unsafe { txbuffer.read_buffer() };
1287
1288                if rxlen != txlen {
1289                    panic!("receive and send buffer lengths do not match!");
1290                }
1291
1292                self.rxchannel.set_peripheral_address(
1293                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1294                    false,
1295                );
1296                self.rxchannel.set_memory_address(rxptr as u32, true);
1297                self.rxchannel.set_transfer_length(rxlen);
1298
1299                self.txchannel.set_peripheral_address(
1300                    unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 },
1301                    false,
1302                );
1303                self.txchannel.set_memory_address(txptr as u32, true);
1304                self.txchannel.set_transfer_length(txlen);
1305
1306                atomic::compiler_fence(Ordering::Release);
1307                self.rxchannel.ch().cr().modify(|_, w| {
1308                    // memory to memory mode disabled
1309                    w.mem2mem().clear_bit();
1310                    // medium channel priority level
1311                    w.pl().medium();
1312                    // 8-bit memory size
1313                    w.msize().bits8();
1314                    // 8-bit peripheral size
1315                    w.psize().bits8();
1316                    // circular mode disabled
1317                    w.circ().clear_bit();
1318                    // write to memory
1319                    w.dir().clear_bit()
1320                });
1321                self.txchannel.ch().cr().modify(|_, w| {
1322                    // memory to memory mode disabled
1323                    w.mem2mem().clear_bit();
1324                    // medium channel priority level
1325                    w.pl().medium();
1326                    // 8-bit memory size
1327                    w.msize().bits8();
1328                    // 8-bit peripheral size
1329                    w.psize().bits8();
1330                    // circular mode disabled
1331                    w.circ().clear_bit();
1332                    // read from memory
1333                    w.dir().set_bit()
1334                });
1335                self.start();
1336
1337                Transfer::w((rxbuffer, txbuffer), self)
1338            }
1339        }
1340    };
1341}
1342
1343spi_dma!(
1344    pac::SPI1,
1345    rx: dma1::C2,
1346    tx: dma1::C3,
1347    Spi1RxDma,
1348    Spi1TxDma,
1349    Spi1RxTxDma,
1350    SpiSlave1RxDma,
1351    SpiSlave1TxDma,
1352    SpiSlave1RxTxDma
1353);
1354spi_dma!(
1355    pac::SPI2,
1356    rx: dma1::C4,
1357    tx: dma1::C5,
1358    Spi2RxDma,
1359    Spi2TxDma,
1360    Spi2RxTxDma,
1361    SpiSlave2RxDma,
1362    SpiSlave2TxDma,
1363    SpiSlave2RxTxDma
1364);
1365#[cfg(feature = "connectivity")]
1366spi_dma!(
1367    pac::SPI3,
1368    rx: dma2::C1,
1369    tx: dma2::C2,
1370    Spi3RxDma,
1371    Spi3TxDma,
1372    Spi3RxTxDma,
1373    SpiSlave3RxDma,
1374    SpiSlave3TxDma,
1375    SpiSlave3RxTxDma
1376);