stm32l4xx_hal/spi.rs
1//! Serial Peripheral Interface (SPI) bus
2//!
3//! The PACs and SVDs are not set up granularity enough to handle all peripheral configurations.
4//! SPI2 is enabled for stm32l4x2 feature at a HAL level even though some variants do and some
5//! don't have it (L432xx and L442xx don't, L452xx does). Users of this MCU variant that
6//! don't have it shouldn't attempt to use it. Relevant info is on user-manual level.
7
8use core::ptr;
9use core::sync::atomic;
10use core::sync::atomic::Ordering;
11
12#[cfg(not(any(feature = "stm32l433", feature = "stm32l443",)))]
13use crate::dma::dma2;
14use crate::dma::{self, dma1, TransferPayload};
15use crate::dmamux::{DmaInput, DmaMux};
16use crate::gpio::{Alternate, PushPull};
17use crate::hal::spi::{FullDuplex, Mode, Phase, Polarity};
18use crate::rcc::{Clocks, Enable, RccBus, Reset};
19use crate::time::Hertz;
20
21use embedded_dma::{StaticReadBuffer, StaticWriteBuffer};
22
23/// SPI error
24#[non_exhaustive]
25#[derive(Debug)]
26pub enum Error {
27 /// Overrun occurred
28 Overrun,
29 /// Mode fault occurred
30 ModeFault,
31 /// CRC error
32 Crc,
33}
34
35#[doc(hidden)]
36mod private {
37 pub trait Sealed {}
38}
39
40/// SCK pin. This trait is sealed and cannot be implemented.
41pub trait SckPin<SPI>: private::Sealed {}
42/// MISO pin. This trait is sealed and cannot be implemented.
43pub trait MisoPin<SPI>: private::Sealed {}
44/// MOSI pin. This trait is sealed and cannot be implemented.
45pub trait MosiPin<SPI>: private::Sealed {}
46
47macro_rules! pins {
48 ($spi:ident, $af:literal, SCK: [$($sck:ident),*], MISO: [$($miso:ident),*], MOSI: [$($mosi:ident),*]) => {
49 $(
50 impl private::Sealed for $sck<Alternate<PushPull, $af>> {}
51 impl SckPin<$spi> for $sck<Alternate<PushPull, $af>> {}
52 )*
53 $(
54 impl private::Sealed for $miso<Alternate<PushPull, $af>> {}
55 impl MisoPin<$spi> for $miso<Alternate<PushPull, $af>> {}
56 )*
57 $(
58 impl private::Sealed for $mosi<Alternate<PushPull, $af>> {}
59 impl MosiPin<$spi> for $mosi<Alternate<PushPull, $af>> {}
60 )*
61 }
62}
63
64/// SPI peripheral operating in full duplex master mode
65pub struct Spi<SPI, PINS> {
66 spi: SPI,
67 pins: PINS,
68}
69
70macro_rules! hal {
71 ($($SPIX:ident: ($spiX:ident, $spiX_slave:ident, $pclkX:ident),)+) => {
72 $(
73 impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
74 /// Configures the SPI peripheral to operate in full duplex master mode
75 #[allow(unused_unsafe)] // Necessary for stm32l4r9
76 pub fn $spiX(
77 spi: $SPIX,
78 pins: (SCK, MISO, MOSI),
79 mode: Mode,
80 freq: Hertz,
81 clocks: Clocks,
82 apb2: &mut <$SPIX as RccBus>::Bus,
83 ) -> Self
84 where
85 SCK: SckPin<$SPIX>,
86 MISO: MisoPin<$SPIX>,
87 MOSI: MosiPin<$SPIX>,
88 {
89 // enable or reset $SPIX
90 <$SPIX>::enable(apb2);
91 <$SPIX>::reset(apb2);
92
93 // FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
94 // 8-bit
95 // DS: 8-bit data size
96 // SSOE: Slave Select output disabled
97 spi.cr2
98 .write(|w| unsafe {
99 w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit()
100 });
101
102 let br = Self::compute_baud_rate(clocks.$pclkX(), freq);
103
104 // CPHA: phase
105 // CPOL: polarity
106 // MSTR: master mode
107 // BR: 1 MHz
108 // SPE: SPI disabled
109 // LSBFIRST: MSB first
110 // SSM: enable software slave management (NSS pin free for other uses)
111 // SSI: set nss high = master mode
112 // CRCEN: hardware CRC calculation disabled
113 // BIDIMODE: 2 line unidirectional (full duplex)
114 spi.cr1.write(|w| unsafe {
115 w.cpha()
116 .bit(mode.phase == Phase::CaptureOnSecondTransition)
117 .cpol()
118 .bit(mode.polarity == Polarity::IdleHigh)
119 .mstr()
120 .set_bit()
121 .br()
122 .bits(br)
123 .spe()
124 .set_bit()
125 .lsbfirst()
126 .clear_bit()
127 .ssi()
128 .set_bit()
129 .ssm()
130 .set_bit()
131 .crcen()
132 .clear_bit()
133 .bidimode()
134 .clear_bit()
135 });
136
137 Spi { spi, pins }
138 }
139
140 pub fn $spiX_slave(spi: $SPIX, pins: (SCK, MISO, MOSI), mode: Mode, apb2: &mut <$SPIX as RccBus>::Bus) -> Self
141 where
142 SCK: SckPin<$SPIX>,
143 MISO: MisoPin<$SPIX>,
144 MOSI: MosiPin<$SPIX>,
145 {
146 // enable or reset $SPIX
147 <$SPIX>::enable(apb2);
148 <$SPIX>::reset(apb2);
149
150 // CPOL: polarity
151 // CPHA: phase
152 // BIDIMODE: 2 line unidirectional (full duplex)
153 // LSBFIRST: MSB first
154 // CRCEN: hardware CRC calculation disabled
155 // MSTR: master mode
156 // SSM: disable software slave management (NSS pin not free for other uses)
157 // SPE: SPI disabled
158 spi.cr1.write(|w| {
159 w.cpol()
160 .bit(mode.polarity == Polarity::IdleHigh)
161 .cpha()
162 .bit(mode.phase == Phase::CaptureOnSecondTransition)
163 .bidimode()
164 .clear_bit()
165 .lsbfirst()
166 .clear_bit()
167 .crcen()
168 .clear_bit()
169 .ssm()
170 .clear_bit()
171 .mstr()
172 .clear_bit()
173 });
174
175 // DS: 8-bit data size
176 // FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
177 // 8-bit
178 spi.cr2
179 .write(|w| unsafe { w.ds().bits(0b111).frxth().set_bit() });
180
181 // SPE: SPI enabled
182 spi.cr1.write(|w| w.spe().set_bit());
183
184 Spi { spi, pins }
185 }
186
187 pub fn clear_overrun(&mut self) {
188 self.spi.dr.read().dr();
189 self.spi.sr.read().ovr();
190 }
191
192 /// Change the baud rate of the SPI
193 #[allow(unused_unsafe)] // Necessary for stm32l4r9
194 pub fn reclock(&mut self, freq: Hertz, clocks: Clocks) {
195 self.spi.cr1.modify(|_, w| w.spe().clear_bit());
196 self.spi.cr1.modify(|_, w| unsafe {
197 w.br().bits(Self::compute_baud_rate(clocks.$pclkX(), freq));
198 w.spe().set_bit()
199 });
200 }
201
202 fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> u8 {
203 match clocks / freq {
204 0 => unreachable!(),
205 1..=2 => 0b000,
206 3..=5 => 0b001,
207 6..=11 => 0b010,
208 12..=23 => 0b011,
209 24..=39 => 0b100,
210 40..=95 => 0b101,
211 96..=191 => 0b110,
212 _ => 0b111,
213 }
214 }
215
216 /// Releases the SPI peripheral and associated pins
217 pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
218 (self.spi, self.pins)
219 }
220 }
221
222 impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
223 type Error = Error;
224
225 fn read(&mut self) -> nb::Result<u8, Error> {
226 let sr = self.spi.sr.read();
227
228 Err(if sr.ovr().bit_is_set() {
229 nb::Error::Other(Error::Overrun)
230 } else if sr.modf().bit_is_set() {
231 nb::Error::Other(Error::ModeFault)
232 } else if sr.crcerr().bit_is_set() {
233 nb::Error::Other(Error::Crc)
234 } else if sr.rxne().bit_is_set() {
235 // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
236 // reading a half-word)
237 return Ok(unsafe {
238 ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
239 });
240 } else {
241 nb::Error::WouldBlock
242 })
243 }
244
245 fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
246 let sr = self.spi.sr.read();
247
248 Err(if sr.ovr().bit_is_set() {
249 nb::Error::Other(Error::Overrun)
250 } else if sr.modf().bit_is_set() {
251 nb::Error::Other(Error::ModeFault)
252 } else if sr.crcerr().bit_is_set() {
253 nb::Error::Other(Error::Crc)
254 } else if sr.txe().bit_is_set() {
255 // NOTE(write_volatile) see note above
256 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
257 return Ok(());
258 } else {
259 nb::Error::WouldBlock
260 })
261 }
262 }
263
264 impl<PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
265
266 impl<PINS> crate::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
267 )+
268 }
269}
270
271use crate::gpio::gpiod::*;
272#[cfg(any(
273 // feature = "stm32l471", // missing PAC support for Port G
274 feature = "stm32l475",
275 feature = "stm32l476",
276 feature = "stm32l485",
277 feature = "stm32l486",
278 feature = "stm32l496",
279 feature = "stm32l4a6",
280 // feature = "stm32l4p5",
281 // feature = "stm32l4q5",
282 // feature = "stm32l4r5",
283 // feature = "stm32l4s5",
284 // feature = "stm32l4r7",
285 // feature = "stm32l4s7",
286 feature = "stm32l4r9",
287 feature = "stm32l4s9",
288))]
289use crate::gpio::gpiog::*;
290use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpioe::*};
291
292use crate::stm32::SPI1;
293hal! {
294 SPI1: (spi1, spi1_slave, pclk2),
295}
296
297pins!(SPI1, 5,
298 SCK: [PA5, PB3, PE13],
299 MISO: [PA6, PB4, PE14],
300 MOSI: [PA7, PB5, PE15]);
301
302#[cfg(any(
303 // feature = "stm32l471", // missing PAC support for Port G
304 feature = "stm32l475",
305 feature = "stm32l476",
306 feature = "stm32l485",
307 feature = "stm32l486",
308 feature = "stm32l496",
309 feature = "stm32l4a6",
310 // feature = "stm32l4p5",
311 // feature = "stm32l4q5",
312 // feature = "stm32l4r5",
313 // feature = "stm32l4s5",
314 // feature = "stm32l4r7",
315 // feature = "stm32l4s7",
316 feature = "stm32l4r9",
317 feature = "stm32l4s9",
318))]
319pins!(SPI1, 5, SCK: [PG2], MISO: [PG3], MOSI: [PG4]);
320
321#[cfg(not(any(feature = "stm32l433", feature = "stm32l443",)))]
322use crate::stm32::SPI3;
323
324#[cfg(not(any(feature = "stm32l433", feature = "stm32l443",)))]
325hal! {
326 SPI3: (spi3, spi3_slave, pclk1),
327}
328
329#[cfg(not(any(feature = "stm32l433", feature = "stm32l443",)))]
330pins!(SPI3, 6,
331 SCK: [PB3, PC10],
332 MISO: [PB4, PC11],
333 MOSI: [PB5, PC12]);
334
335#[cfg(any(
336 // feature = "stm32l471", // missing PAC support for Port G
337 feature = "stm32l475",
338 feature = "stm32l476",
339 feature = "stm32l485",
340 feature = "stm32l486",
341 feature = "stm32l496",
342 feature = "stm32l4a6",
343 // feature = "stm32l4p5",
344 // feature = "stm32l4q5",
345 // feature = "stm32l4r5",
346 // feature = "stm32l4s5",
347 // feature = "stm32l4r7",
348 // feature = "stm32l4s7",
349 feature = "stm32l4r9",
350 feature = "stm32l4s9",
351))]
352pins!(SPI3, 6, SCK: [PG9], MISO: [PG10], MOSI: [PG11]);
353
354use crate::stm32::SPI2;
355
356hal! {
357 SPI2: (spi2, spi2_slave, pclk1),
358}
359
360pins!(SPI2, 5,
361 SCK: [PB13, PB10, PD1],
362 MISO: [PB14, PC2, PD3],
363 MOSI: [PB15, PC3, PD4]);
364
365pub struct SpiPayload<SPI, PINS> {
366 spi: Spi<SPI, PINS>,
367}
368
369pub type SpiRxDma<SPI, PINS, CHANNEL> = dma::RxDma<SpiPayload<SPI, PINS>, CHANNEL>;
370
371pub type SpiTxDma<SPI, PINS, CHANNEL> = dma::TxDma<SpiPayload<SPI, PINS>, CHANNEL>;
372
373pub type SpiRxTxDma<SPI, PINS, RXCH, TXCH> = dma::RxTxDma<SpiPayload<SPI, PINS>, RXCH, TXCH>;
374
375macro_rules! spi_dma {
376 ($SPIX:ident, $RX_CH:path, $RX_CHSEL:path, $TX_CH:path, $TX_CHSEL:path) => {
377 impl<PINS> dma::Receive for SpiRxDma<$SPIX, PINS, $RX_CH> {
378 type RxChannel = $RX_CH;
379 type TransmittedWord = u8;
380 }
381
382 impl<PINS> dma::Transmit for SpiTxDma<$SPIX, PINS, $TX_CH> {
383 type TxChannel = $TX_CH;
384 type ReceivedWord = u8;
385 }
386
387 impl<PINS> dma::ReceiveTransmit for SpiRxTxDma<$SPIX, PINS, $RX_CH, $TX_CH> {
388 type RxChannel = $RX_CH;
389 type TxChannel = $TX_CH;
390 type TransferedWord = u8;
391 }
392
393 impl<PINS> Spi<$SPIX, PINS> {
394 pub fn with_rx_dma(self, mut channel: $RX_CH) -> SpiRxDma<$SPIX, PINS, $RX_CH> {
395 let payload = SpiPayload { spi: self };
396
397 // Perform one-time setup actions to keep the work minimal when using the driver.
398
399 channel.set_peripheral_address(
400 unsafe { &(*$SPIX::ptr()).dr as *const _ as u32 },
401 false,
402 );
403 channel.set_request_line($RX_CHSEL).unwrap();
404 channel.ccr().modify(|_, w| {
405 w
406 // memory to memory mode disabled
407 .mem2mem()
408 .clear_bit()
409 // medium channel priority level
410 .pl()
411 .medium()
412 // 8-bit memory size
413 .msize()
414 .bits8()
415 // 8-bit peripheral size
416 .psize()
417 .bits8()
418 // circular mode disabled
419 .circ()
420 .clear_bit()
421 // write to memory
422 .dir()
423 .clear_bit()
424 });
425
426 SpiRxDma { payload, channel }
427 }
428
429 pub fn with_tx_dma(self, mut channel: $TX_CH) -> SpiTxDma<$SPIX, PINS, $TX_CH> {
430 let payload = SpiPayload { spi: self };
431
432 // Perform one-time setup actions to keep the work minimal when using the driver.
433
434 channel.set_peripheral_address(
435 unsafe { &(*$SPIX::ptr()).dr as *const _ as u32 },
436 false,
437 );
438 channel.set_request_line($TX_CHSEL).unwrap();
439 channel.ccr().modify(|_, w| {
440 w
441 // memory to memory mode disabled
442 .mem2mem()
443 .clear_bit()
444 // medium channel priority level
445 .pl()
446 .medium()
447 // 8-bit memory size
448 .msize()
449 .bits8()
450 // 8-bit peripheral size
451 .psize()
452 .bits8()
453 // circular mode disabled
454 .circ()
455 .clear_bit()
456 // write to peripheral
457 .dir()
458 .set_bit()
459 });
460
461 SpiTxDma { payload, channel }
462 }
463
464 pub fn with_rxtx_dma(
465 self,
466 mut rx_channel: $RX_CH,
467 mut tx_channel: $TX_CH,
468 ) -> SpiRxTxDma<$SPIX, PINS, $RX_CH, $TX_CH> {
469 let payload = SpiPayload { spi: self };
470
471 // Perform one-time setup actions to keep the work minimal when using the driver.
472
473 //
474 // Setup RX channel
475 //
476 rx_channel.set_peripheral_address(
477 unsafe { &(*$SPIX::ptr()).dr as *const _ as u32 },
478 false,
479 );
480 rx_channel.set_request_line($RX_CHSEL).unwrap();
481
482 rx_channel.ccr().modify(|_, w| {
483 w
484 // memory to memory mode disabled
485 .mem2mem()
486 .clear_bit()
487 // medium channel priority level
488 .pl()
489 .medium()
490 // 8-bit memory size
491 .msize()
492 .bits8()
493 // 8-bit peripheral size
494 .psize()
495 .bits8()
496 // circular mode disabled
497 .circ()
498 .clear_bit()
499 // write to memory
500 .dir()
501 .clear_bit()
502 });
503
504 //
505 // Setup TX channel
506 //
507 tx_channel.set_peripheral_address(
508 unsafe { &(*$SPIX::ptr()).dr as *const _ as u32 },
509 false,
510 );
511 tx_channel.set_request_line($TX_CHSEL).unwrap();
512
513 tx_channel.ccr().modify(|_, w| {
514 w
515 // memory to memory mode disabled
516 .mem2mem()
517 .clear_bit()
518 // medium channel priority level
519 .pl()
520 .medium()
521 // 8-bit memory size
522 .msize()
523 .bits8()
524 // 8-bit peripheral size
525 .psize()
526 .bits8()
527 // circular mode disabled
528 .circ()
529 .clear_bit()
530 // write to peripheral
531 .dir()
532 .set_bit()
533 });
534
535 SpiRxTxDma {
536 payload,
537 rx_channel,
538 tx_channel,
539 }
540 }
541 }
542
543 impl<PINS> SpiRxDma<$SPIX, PINS, $RX_CH> {
544 pub fn split(mut self) -> (Spi<$SPIX, PINS>, $RX_CH) {
545 self.stop();
546 (self.payload.spi, self.channel)
547 }
548 }
549
550 impl<PINS> SpiTxDma<$SPIX, PINS, $TX_CH> {
551 pub fn split(mut self) -> (Spi<$SPIX, PINS>, $TX_CH) {
552 self.stop();
553 (self.payload.spi, self.channel)
554 }
555 }
556
557 impl<PINS> SpiRxTxDma<$SPIX, PINS, $RX_CH, $TX_CH> {
558 pub fn split(mut self) -> (Spi<$SPIX, PINS>, $RX_CH, $TX_CH) {
559 self.stop();
560 (self.payload.spi, self.rx_channel, self.tx_channel)
561 }
562 }
563
564 impl<PINS> dma::TransferPayload for SpiRxDma<$SPIX, PINS, $RX_CH> {
565 fn start(&mut self) {
566 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
567 // DMA (direct memory addressing)".
568 // It is mandatory to follow these steps in order:
569 //
570 // 0. SPI disabled during setup.
571 // 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CR2 register, if DMA Rx is used.
572 // 2. Enable DMA streams for Tx and Rx in DMA registers, if the streams are used.
573 // 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CR2 register, if DMA Tx is used.
574 // 4. Enable the SPI by setting the SPE bit.
575 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 0.
576 self.payload
577 .spi
578 .spi
579 .cr2
580 .modify(|_, w| w.rxdmaen().set_bit()); // 1.
581 self.channel.start(); // 2.
582 self.payload.spi.spi.cr1.modify(|_, w| w.spe().set_bit()); // 4.
583 }
584
585 fn stop(&mut self) {
586 // Stop DMA channels in accordance with RM 40.4.9, subheading "Communication using
587 // DMA (direct memory addressing)".
588 // It is mandatory to follow these steps in order:
589 //
590 // 1. Disable DMA streams for Tx and Rx in the DMA registers, if the streams are used.
591 // 2. Disable the SPI by following the SPI disable procedure.
592 // 3. Disable DMA Tx and Rx buffers by clearing the TXDMAEN and RXDMAEN bits in the
593 // SPI_CR2 register, if DMA Tx and/or DMA Rx are used.
594 self.channel.stop(); // 1.
595 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 2.
596 self.payload
597 .spi
598 .spi
599 .cr2
600 .modify(|_, w| w.rxdmaen().clear_bit()); // 3.
601 }
602 }
603
604 impl<PINS> dma::TransferPayload for SpiTxDma<$SPIX, PINS, $TX_CH> {
605 fn start(&mut self) {
606 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
607 // DMA (direct memory addressing)".
608 // It is mandatory to follow these steps in order:
609 //
610 // 0. SPI disabled during setup.
611 // 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CR2 register, if DMA Rx is used.
612 // 2. Enable DMA streams for Tx and Rx in DMA registers, if the streams are used.
613 // 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CR2 register, if DMA Tx is used.
614 // 4. Enable the SPI by setting the SPE bit.
615 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 0.
616 self.channel.start(); // 2.
617 self.payload
618 .spi
619 .spi
620 .cr2
621 .modify(|_, w| w.txdmaen().set_bit()); // 3.
622 self.payload.spi.spi.cr1.modify(|_, w| w.spe().set_bit()); // 4.
623 }
624
625 fn stop(&mut self) {
626 // Stop DMA channels in accordance with RM 40.4.9, subheading "Communication using
627 // DMA (direct memory addressing)".
628 // It is mandatory to follow these steps in order:
629 //
630 // 1. Disable DMA streams for Tx and Rx in the DMA registers, if the streams are used.
631 // 2. Disable the SPI by following the SPI disable procedure.
632 // 3. Disable DMA Tx and Rx buffers by clearing the TXDMAEN and RXDMAEN bits in the
633 // SPI_CR2 register, if DMA Tx and/or DMA Rx are used.
634 self.channel.stop(); // 1.
635 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 2.
636 self.payload
637 .spi
638 .spi
639 .cr2
640 .modify(|_, w| w.txdmaen().clear_bit()); // 3.
641 }
642 }
643
644 impl<PINS> dma::TransferPayload for SpiRxTxDma<$SPIX, PINS, $RX_CH, $TX_CH> {
645 fn start(&mut self) {
646 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
647 // DMA (direct memory addressing)".
648 // It is mandatory to follow these steps in order:
649 //
650 // 0. SPI disabled during setup.
651 // 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CR2 register, if DMA Rx is used.
652 // 2. Enable DMA streams for Tx and Rx in DMA registers, if the streams are used.
653 // 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CR2 register, if DMA Tx is used.
654 // 4. Enable the SPI by setting the SPE bit.
655 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 0.
656 self.payload
657 .spi
658 .spi
659 .cr2
660 .modify(|_, w| w.rxdmaen().set_bit()); // 1.
661 self.rx_channel.start(); // 2.
662 self.tx_channel.start(); // 2.
663 self.payload
664 .spi
665 .spi
666 .cr2
667 .modify(|_, w| w.txdmaen().set_bit()); // 3.
668 self.payload.spi.spi.cr1.modify(|_, w| w.spe().set_bit()); // 4.
669 }
670
671 fn stop(&mut self) {
672 // Stop DMA channels in accordance with RM 40.4.9, subheading "Communication using
673 // DMA (direct memory addressing)".
674 // It is mandatory to follow these steps in order:
675 //
676 // 1. Disable DMA streams for Tx and Rx in the DMA registers, if the streams are used.
677 // 2. Disable the SPI by following the SPI disable procedure.
678 // 3. Disable DMA Tx and Rx buffers by clearing the TXDMAEN and RXDMAEN bits in the
679 // SPI_CR2 register, if DMA Tx and/or DMA Rx are used.
680 self.tx_channel.stop(); // 1.
681 self.rx_channel.stop(); // 1.
682 self.payload.spi.spi.cr1.modify(|_, w| w.spe().clear_bit()); // 2.
683 self.payload
684 .spi
685 .spi
686 .cr2
687 .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit()); // 3.
688 }
689 }
690
691 impl<B, PINS> dma::ReadDma<B, u8> for SpiRxDma<$SPIX, PINS, $RX_CH>
692 where
693 B: StaticWriteBuffer<Word = u8>,
694 {
695 fn read(mut self, mut buffer: B) -> dma::Transfer<dma::W, B, Self> {
696 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
697 // DMA (direct memory addressing)"
698
699 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
700 // until the end of the transfer.
701 let (ptr, len) = unsafe { buffer.static_write_buffer() };
702
703 // Setup RX channel addresses and length
704 self.channel.set_memory_address(ptr as u32, true);
705 self.channel.set_transfer_length(len as u16);
706
707 // Fences and start
708 atomic::compiler_fence(Ordering::Release);
709 self.start();
710
711 dma::Transfer::w(buffer, self)
712 }
713 }
714
715 impl<B, PINS> dma::WriteDma<B, u8> for SpiTxDma<$SPIX, PINS, $TX_CH>
716 where
717 B: StaticReadBuffer<Word = u8>,
718 {
719 fn write(mut self, buffer: B) -> dma::Transfer<dma::R, B, Self> {
720 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
721 // DMA (direct memory addressing)"
722
723 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
724 // until the end of the transfer.
725 let (ptr, len) = unsafe { buffer.static_read_buffer() };
726
727 // Setup TX channel addresses and length
728 self.channel.set_memory_address(ptr as u32, true);
729 self.channel.set_transfer_length(len as u16);
730
731 // Fences and start
732 atomic::compiler_fence(Ordering::Release);
733 self.start();
734
735 dma::Transfer::r(buffer, self)
736 }
737 }
738
739 impl<B, PINS> dma::TransferDma<B, u8> for SpiRxTxDma<$SPIX, PINS, $RX_CH, $TX_CH>
740 where
741 B: StaticWriteBuffer<Word = u8>,
742 {
743 fn transfer(mut self, mut buffer: B) -> dma::Transfer<dma::RW, B, Self> {
744 // Setup DMA channels in accordance with RM 40.4.9, subheading "Communication using
745 // DMA (direct memory addressing)"
746
747 // Transfer: we use the same buffer for RX and TX
748
749 // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
750 // until the end of the transfer.
751 let (ptr, len) = unsafe { buffer.static_write_buffer() };
752
753 // Setup RX channel addresses and length
754 self.rx_channel.set_memory_address(ptr as u32, true);
755 self.rx_channel.set_transfer_length(len as u16);
756
757 // Setup TX channel addresses and length
758 self.tx_channel.set_memory_address(ptr as u32, true);
759 self.tx_channel.set_transfer_length(len as u16);
760
761 // Fences and start
762 atomic::compiler_fence(Ordering::Release);
763 self.start();
764
765 dma::Transfer::rw(buffer, self)
766 }
767 }
768 };
769}
770
771spi_dma!(SPI1, dma1::C2, DmaInput::Spi1Rx, dma1::C3, DmaInput::Spi1Tx);
772#[cfg(not(any(
773 feature = "stm32l412",
774 feature = "stm32l422",
775 feature = "stm32l432",
776 feature = "stm32l442",
777 feature = "stm32l452",
778 feature = "stm32l462",
779)))]
780spi_dma!(SPI2, dma1::C4, DmaInput::Spi2Rx, dma1::C5, DmaInput::Spi2Tx);
781// spi_dma!(SPI1, dma2::C3, c3s, map4, dma2::C4, c4s, map4);
782#[cfg(not(any(feature = "stm32l433", feature = "stm32l443",)))]
783spi_dma!(SPI3, dma2::C1, DmaInput::Spi3Rx, dma2::C2, DmaInput::Spi3Tx);