embassy_stm32/spi/
mod.rs

1//! Serial Peripheral Interface (SPI)
2#![macro_use]
3
4use core::marker::PhantomData;
5use core::ptr;
6
7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join;
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
10
11use crate::dma::{word, ChannelAndRequest};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::mode::{Async, Blocking, Mode as PeriMode};
14use crate::pac::spi::{regs, vals, Spi as Regs};
15use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::time::Hertz;
17use crate::Peri;
18
19/// SPI error.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub enum Error {
23    /// Invalid framing.
24    Framing,
25    /// CRC error (only if hardware CRC checking is enabled).
26    Crc,
27    /// Mode fault
28    ModeFault,
29    /// Overrun.
30    Overrun,
31}
32
33impl core::fmt::Display for Error {
34    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35        let message = match self {
36            Self::Framing => "Invalid Framing",
37            Self::Crc => "Hardware CRC Check Failed",
38            Self::ModeFault => "Mode Fault",
39            Self::Overrun => "Buffer Overrun",
40        };
41
42        write!(f, "{}", message)
43    }
44}
45
46impl core::error::Error for Error {}
47
48/// SPI bit order
49#[derive(Copy, Clone)]
50pub enum BitOrder {
51    /// Least significant bit first.
52    LsbFirst,
53    /// Most significant bit first.
54    MsbFirst,
55}
56
57/// SPI configuration.
58#[non_exhaustive]
59#[derive(Copy, Clone)]
60pub struct Config {
61    /// SPI mode.
62    pub mode: Mode,
63    /// Bit order.
64    pub bit_order: BitOrder,
65    /// Clock frequency.
66    pub frequency: Hertz,
67    /// Enable internal pullup on MISO.
68    ///
69    /// There are some ICs that require a pull-up on the MISO pin for some applications.
70    /// If you  are unsure, you probably don't need this.
71    pub miso_pull: Pull,
72    /// signal rise/fall speed (slew rate) - defaults to `Medium`.
73    /// Increase for high SPI speeds. Change to `Low` to reduce ringing.
74    pub gpio_speed: Speed,
75}
76
77impl Default for Config {
78    fn default() -> Self {
79        Self {
80            mode: MODE_0,
81            bit_order: BitOrder::MsbFirst,
82            frequency: Hertz(1_000_000),
83            miso_pull: Pull::None,
84            gpio_speed: Speed::VeryHigh,
85        }
86    }
87}
88
89impl Config {
90    fn raw_phase(&self) -> vals::Cpha {
91        match self.mode.phase {
92            Phase::CaptureOnSecondTransition => vals::Cpha::SECOND_EDGE,
93            Phase::CaptureOnFirstTransition => vals::Cpha::FIRST_EDGE,
94        }
95    }
96
97    fn raw_polarity(&self) -> vals::Cpol {
98        match self.mode.polarity {
99            Polarity::IdleHigh => vals::Cpol::IDLE_HIGH,
100            Polarity::IdleLow => vals::Cpol::IDLE_LOW,
101        }
102    }
103
104    fn raw_byte_order(&self) -> vals::Lsbfirst {
105        match self.bit_order {
106            BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
107            BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
108        }
109    }
110
111    #[cfg(gpio_v1)]
112    fn sck_af(&self) -> AfType {
113        AfType::output(OutputType::PushPull, self.gpio_speed)
114    }
115
116    #[cfg(gpio_v2)]
117    fn sck_af(&self) -> AfType {
118        AfType::output_pull(
119            OutputType::PushPull,
120            self.gpio_speed,
121            match self.mode.polarity {
122                Polarity::IdleLow => Pull::Down,
123                Polarity::IdleHigh => Pull::Up,
124            },
125        )
126    }
127}
128/// SPI driver.
129pub struct Spi<'d, M: PeriMode> {
130    pub(crate) info: &'static Info,
131    kernel_clock: Hertz,
132    sck: Option<Peri<'d, AnyPin>>,
133    mosi: Option<Peri<'d, AnyPin>>,
134    miso: Option<Peri<'d, AnyPin>>,
135    tx_dma: Option<ChannelAndRequest<'d>>,
136    rx_dma: Option<ChannelAndRequest<'d>>,
137    _phantom: PhantomData<M>,
138    current_word_size: word_impl::Config,
139    gpio_speed: Speed,
140}
141
142impl<'d, M: PeriMode> Spi<'d, M> {
143    fn new_inner<T: Instance>(
144        _peri: Peri<'d, T>,
145        sck: Option<Peri<'d, AnyPin>>,
146        mosi: Option<Peri<'d, AnyPin>>,
147        miso: Option<Peri<'d, AnyPin>>,
148        tx_dma: Option<ChannelAndRequest<'d>>,
149        rx_dma: Option<ChannelAndRequest<'d>>,
150        config: Config,
151    ) -> Self {
152        let mut this = Self {
153            info: T::info(),
154            kernel_clock: T::frequency(),
155            sck,
156            mosi,
157            miso,
158            tx_dma,
159            rx_dma,
160            current_word_size: <u8 as SealedWord>::CONFIG,
161            _phantom: PhantomData,
162            gpio_speed: config.gpio_speed,
163        };
164        this.enable_and_init(config);
165        this
166    }
167
168    fn enable_and_init(&mut self, config: Config) {
169        let br = compute_baud_rate(self.kernel_clock, config.frequency);
170        let cpha = config.raw_phase();
171        let cpol = config.raw_polarity();
172        let lsbfirst = config.raw_byte_order();
173
174        self.info.rcc.enable_and_reset();
175
176        let regs = self.info.regs;
177        #[cfg(any(spi_v1, spi_f1))]
178        {
179            regs.cr2().modify(|w| {
180                w.set_ssoe(false);
181            });
182            regs.cr1().modify(|w| {
183                w.set_cpha(cpha);
184                w.set_cpol(cpol);
185
186                w.set_mstr(vals::Mstr::MASTER);
187                w.set_br(br);
188                w.set_spe(true);
189                w.set_lsbfirst(lsbfirst);
190                w.set_ssi(true);
191                w.set_ssm(true);
192                w.set_crcen(false);
193                w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194                // we're doing "fake rxonly", by actually writing one
195                // byte to TXDR for each byte we want to receive. if we
196                // set OUTPUTDISABLED here, this hangs.
197                w.set_rxonly(vals::Rxonly::FULL_DUPLEX);
198                w.set_dff(<u8 as SealedWord>::CONFIG)
199            });
200        }
201        #[cfg(spi_v2)]
202        {
203            regs.cr2().modify(|w| {
204                let (ds, frxth) = <u8 as SealedWord>::CONFIG;
205                w.set_frxth(frxth);
206                w.set_ds(ds);
207                w.set_ssoe(false);
208            });
209            regs.cr1().modify(|w| {
210                w.set_cpha(cpha);
211                w.set_cpol(cpol);
212
213                w.set_mstr(vals::Mstr::MASTER);
214                w.set_br(br);
215                w.set_lsbfirst(lsbfirst);
216                w.set_ssi(true);
217                w.set_ssm(true);
218                w.set_crcen(false);
219                w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220                w.set_spe(true);
221            });
222        }
223        #[cfg(any(spi_v3, spi_v4, spi_v5))]
224        {
225            regs.ifcr().write(|w| w.0 = 0xffff_ffff);
226            regs.cfg2().modify(|w| {
227                //w.set_ssoe(true);
228                w.set_ssoe(false);
229                w.set_cpha(cpha);
230                w.set_cpol(cpol);
231                w.set_lsbfirst(lsbfirst);
232                w.set_ssm(true);
233                w.set_master(vals::Master::MASTER);
234                w.set_comm(vals::Comm::FULL_DUPLEX);
235                w.set_ssom(vals::Ssom::ASSERTED);
236                w.set_midi(0);
237                w.set_mssi(0);
238                w.set_afcntr(true);
239                w.set_ssiop(vals::Ssiop::ACTIVE_HIGH);
240            });
241            regs.cfg1().modify(|w| {
242                w.set_crcen(false);
243                w.set_mbr(br);
244                w.set_dsize(<u8 as SealedWord>::CONFIG);
245                w.set_fthlv(vals::Fthlv::ONE_FRAME);
246            });
247            regs.cr2().modify(|w| {
248                w.set_tsize(0);
249            });
250            regs.cr1().modify(|w| {
251                w.set_ssi(false);
252                w.set_spe(true);
253            });
254        }
255    }
256
257    /// Reconfigures it with the supplied config.
258    pub fn set_config(&mut self, config: &Config) -> Result<(), ()> {
259        let cpha = config.raw_phase();
260        let cpol = config.raw_polarity();
261
262        let lsbfirst = config.raw_byte_order();
263
264        let br = compute_baud_rate(self.kernel_clock, config.frequency);
265
266        #[cfg(gpio_v2)]
267        {
268            self.gpio_speed = config.gpio_speed;
269            if let Some(sck) = self.sck.as_ref() {
270                sck.set_speed(config.gpio_speed);
271            }
272            if let Some(mosi) = self.mosi.as_ref() {
273                mosi.set_speed(config.gpio_speed);
274            }
275        }
276
277        #[cfg(any(spi_v1, spi_f1, spi_v2))]
278        self.info.regs.cr1().modify(|w| {
279            w.set_cpha(cpha);
280            w.set_cpol(cpol);
281            w.set_br(br);
282            w.set_lsbfirst(lsbfirst);
283        });
284
285        #[cfg(any(spi_v3, spi_v4, spi_v5))]
286        {
287            self.info.regs.cr1().modify(|w| {
288                w.set_spe(false);
289            });
290
291            self.info.regs.cfg2().modify(|w| {
292                w.set_cpha(cpha);
293                w.set_cpol(cpol);
294                w.set_lsbfirst(lsbfirst);
295            });
296            self.info.regs.cfg1().modify(|w| {
297                w.set_mbr(br);
298            });
299
300            self.info.regs.cr1().modify(|w| {
301                w.set_spe(true);
302            });
303        }
304        Ok(())
305    }
306
307    /// Get current SPI configuration.
308    pub fn get_current_config(&self) -> Config {
309        #[cfg(any(spi_v1, spi_f1, spi_v2))]
310        let cfg = self.info.regs.cr1().read();
311        #[cfg(any(spi_v3, spi_v4, spi_v5))]
312        let cfg = self.info.regs.cfg2().read();
313        #[cfg(any(spi_v3, spi_v4, spi_v5))]
314        let cfg1 = self.info.regs.cfg1().read();
315
316        let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW {
317            Polarity::IdleLow
318        } else {
319            Polarity::IdleHigh
320        };
321        let phase = if cfg.cpha() == vals::Cpha::FIRST_EDGE {
322            Phase::CaptureOnFirstTransition
323        } else {
324            Phase::CaptureOnSecondTransition
325        };
326
327        let bit_order = if cfg.lsbfirst() == vals::Lsbfirst::LSBFIRST {
328            BitOrder::LsbFirst
329        } else {
330            BitOrder::MsbFirst
331        };
332
333        let miso_pull = match &self.miso {
334            None => Pull::None,
335            Some(pin) => pin.pull(),
336        };
337
338        #[cfg(any(spi_v1, spi_f1, spi_v2))]
339        let br = cfg.br();
340        #[cfg(any(spi_v3, spi_v4, spi_v5))]
341        let br = cfg1.mbr();
342
343        let frequency = compute_frequency(self.kernel_clock, br);
344
345        Config {
346            mode: Mode { polarity, phase },
347            bit_order,
348            frequency,
349            miso_pull,
350            gpio_speed: self.gpio_speed,
351        }
352    }
353
354    pub(crate) fn set_word_size(&mut self, word_size: word_impl::Config) {
355        if self.current_word_size == word_size {
356            return;
357        }
358
359        self.info.regs.cr1().modify(|w| {
360            w.set_spe(false);
361        });
362
363        #[cfg(any(spi_v1, spi_f1))]
364        self.info.regs.cr1().modify(|reg| {
365            reg.set_dff(word_size);
366        });
367        #[cfg(spi_v2)]
368        self.info.regs.cr2().modify(|w| {
369            w.set_frxth(word_size.1);
370            w.set_ds(word_size.0);
371        });
372        #[cfg(any(spi_v3, spi_v4, spi_v5))]
373        self.info.regs.cfg1().modify(|w| {
374            w.set_dsize(word_size);
375        });
376
377        self.current_word_size = word_size;
378    }
379
380    /// Blocking write.
381    pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
382        // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
383        #[cfg(any(spi_v3, spi_v4, spi_v5))]
384        self.info.regs.cr1().modify(|w| w.set_spe(false));
385        self.set_word_size(W::CONFIG);
386        self.info.regs.cr1().modify(|w| w.set_spe(true));
387        flush_rx_fifo(self.info.regs);
388        for word in words.iter() {
389            // this cannot use `transfer_word` because on SPIv2 and higher,
390            // the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
391            // This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`.
392            // See https://github.com/embassy-rs/embassy/issues/2902
393            // This is not documented as an errata by ST, and I've been unable to find anything online...
394            #[cfg(not(any(spi_v1, spi_f1)))]
395            write_word(self.info.regs, *word)?;
396
397            // if we're doing tx only, after writing the last byte to FIFO we have to wait
398            // until it's actually sent. On SPIv1 you're supposed to use the BSY flag for this
399            // but apparently it's broken, it clears too soon. Workaround is to wait for RXNE:
400            // when it gets set you know the transfer is done, even if you don't care about rx.
401            // Luckily this doesn't affect SPIv2+.
402            // See http://efton.sk/STM32/gotcha/g68.html
403            // ST doesn't seem to document this in errata sheets (?)
404            #[cfg(any(spi_v1, spi_f1))]
405            transfer_word(self.info.regs, *word)?;
406        }
407
408        // wait until last word is transmitted. (except on v1, see above)
409        #[cfg(not(any(spi_v1, spi_f1, spi_v2)))]
410        while !self.info.regs.sr().read().txc() {}
411        #[cfg(spi_v2)]
412        while self.info.regs.sr().read().bsy() {}
413
414        Ok(())
415    }
416
417    /// Blocking read.
418    pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
419        // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
420        #[cfg(any(spi_v3, spi_v4, spi_v5))]
421        self.info.regs.cr1().modify(|w| w.set_spe(false));
422        self.set_word_size(W::CONFIG);
423        self.info.regs.cr1().modify(|w| w.set_spe(true));
424        flush_rx_fifo(self.info.regs);
425        for word in words.iter_mut() {
426            *word = transfer_word(self.info.regs, W::default())?;
427        }
428        Ok(())
429    }
430
431    /// Blocking in-place bidirectional transfer.
432    ///
433    /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
434    pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
435        // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
436        #[cfg(any(spi_v3, spi_v4, spi_v5))]
437        self.info.regs.cr1().modify(|w| w.set_spe(false));
438        self.set_word_size(W::CONFIG);
439        self.info.regs.cr1().modify(|w| w.set_spe(true));
440        flush_rx_fifo(self.info.regs);
441        for word in words.iter_mut() {
442            *word = transfer_word(self.info.regs, *word)?;
443        }
444        Ok(())
445    }
446
447    /// Blocking bidirectional transfer.
448    ///
449    /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
450    ///
451    /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
452    /// If `write` is shorter it is padded with zero bytes.
453    pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
454        // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
455        #[cfg(any(spi_v3, spi_v4, spi_v5))]
456        self.info.regs.cr1().modify(|w| w.set_spe(false));
457        self.set_word_size(W::CONFIG);
458        self.info.regs.cr1().modify(|w| w.set_spe(true));
459        flush_rx_fifo(self.info.regs);
460        let len = read.len().max(write.len());
461        for i in 0..len {
462            let wb = write.get(i).copied().unwrap_or_default();
463            let rb = transfer_word(self.info.regs, wb)?;
464            if let Some(r) = read.get_mut(i) {
465                *r = rb;
466            }
467        }
468        Ok(())
469    }
470}
471
472impl<'d> Spi<'d, Blocking> {
473    /// Create a new blocking SPI driver.
474    pub fn new_blocking<T: Instance>(
475        peri: Peri<'d, T>,
476        sck: Peri<'d, impl SckPin<T>>,
477        mosi: Peri<'d, impl MosiPin<T>>,
478        miso: Peri<'d, impl MisoPin<T>>,
479        config: Config,
480    ) -> Self {
481        Self::new_inner(
482            peri,
483            new_pin!(sck, config.sck_af()),
484            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
485            new_pin!(miso, AfType::input(config.miso_pull)),
486            None,
487            None,
488            config,
489        )
490    }
491
492    /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
493    pub fn new_blocking_rxonly<T: Instance>(
494        peri: Peri<'d, T>,
495        sck: Peri<'d, impl SckPin<T>>,
496        miso: Peri<'d, impl MisoPin<T>>,
497        config: Config,
498    ) -> Self {
499        Self::new_inner(
500            peri,
501            new_pin!(sck, config.sck_af()),
502            None,
503            new_pin!(miso, AfType::input(config.miso_pull)),
504            None,
505            None,
506            config,
507        )
508    }
509
510    /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
511    pub fn new_blocking_txonly<T: Instance>(
512        peri: Peri<'d, T>,
513        sck: Peri<'d, impl SckPin<T>>,
514        mosi: Peri<'d, impl MosiPin<T>>,
515        config: Config,
516    ) -> Self {
517        Self::new_inner(
518            peri,
519            new_pin!(sck, config.sck_af()),
520            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
521            None,
522            None,
523            None,
524            config,
525        )
526    }
527
528    /// Create a new SPI driver, in TX-only mode, without SCK pin.
529    ///
530    /// This can be useful for bit-banging non-SPI protocols.
531    pub fn new_blocking_txonly_nosck<T: Instance>(
532        peri: Peri<'d, T>,
533        mosi: Peri<'d, impl MosiPin<T>>,
534        config: Config,
535    ) -> Self {
536        Self::new_inner(
537            peri,
538            None,
539            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
540            None,
541            None,
542            None,
543            config,
544        )
545    }
546}
547
548impl<'d> Spi<'d, Async> {
549    /// Create a new SPI driver.
550    pub fn new<T: Instance>(
551        peri: Peri<'d, T>,
552        sck: Peri<'d, impl SckPin<T>>,
553        mosi: Peri<'d, impl MosiPin<T>>,
554        miso: Peri<'d, impl MisoPin<T>>,
555        tx_dma: Peri<'d, impl TxDma<T>>,
556        rx_dma: Peri<'d, impl RxDma<T>>,
557        config: Config,
558    ) -> Self {
559        Self::new_inner(
560            peri,
561            new_pin!(sck, config.sck_af()),
562            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563            new_pin!(miso, AfType::input(config.miso_pull)),
564            new_dma!(tx_dma),
565            new_dma!(rx_dma),
566            config,
567        )
568    }
569
570    /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
571    pub fn new_rxonly<T: Instance>(
572        peri: Peri<'d, T>,
573        sck: Peri<'d, impl SckPin<T>>,
574        miso: Peri<'d, impl MisoPin<T>>,
575        #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: Peri<'d, impl TxDma<T>>,
576        rx_dma: Peri<'d, impl RxDma<T>>,
577        config: Config,
578    ) -> Self {
579        Self::new_inner(
580            peri,
581            new_pin!(sck, config.sck_af()),
582            None,
583            new_pin!(miso, AfType::input(config.miso_pull)),
584            #[cfg(any(spi_v1, spi_f1, spi_v2))]
585            new_dma!(tx_dma),
586            #[cfg(any(spi_v3, spi_v4, spi_v5))]
587            None,
588            new_dma!(rx_dma),
589            config,
590        )
591    }
592
593    /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
594    pub fn new_txonly<T: Instance>(
595        peri: Peri<'d, T>,
596        sck: Peri<'d, impl SckPin<T>>,
597        mosi: Peri<'d, impl MosiPin<T>>,
598        tx_dma: Peri<'d, impl TxDma<T>>,
599        config: Config,
600    ) -> Self {
601        Self::new_inner(
602            peri,
603            new_pin!(sck, config.sck_af()),
604            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605            None,
606            new_dma!(tx_dma),
607            None,
608            config,
609        )
610    }
611
612    /// Create a new SPI driver, in TX-only mode, without SCK pin.
613    ///
614    /// This can be useful for bit-banging non-SPI protocols.
615    pub fn new_txonly_nosck<T: Instance>(
616        peri: Peri<'d, T>,
617        mosi: Peri<'d, impl MosiPin<T>>,
618        tx_dma: Peri<'d, impl TxDma<T>>,
619        config: Config,
620    ) -> Self {
621        Self::new_inner(
622            peri,
623            None,
624            new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625            None,
626            new_dma!(tx_dma),
627            None,
628            config,
629        )
630    }
631
632    #[cfg(stm32wl)]
633    /// Useful for on chip peripherals like SUBGHZ which are hardwired.
634    pub fn new_subghz<T: Instance>(
635        peri: Peri<'d, T>,
636        tx_dma: Peri<'d, impl TxDma<T>>,
637        rx_dma: Peri<'d, impl RxDma<T>>,
638    ) -> Self {
639        // see RM0453 rev 1 section 7.2.13 page 291
640        // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
641        // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
642        let pclk3_freq = <crate::peripherals::SUBGHZSPI as SealedRccPeripheral>::frequency().0;
643        let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
644        let mut config = Config::default();
645        config.mode = MODE_0;
646        config.bit_order = BitOrder::MsbFirst;
647        config.frequency = freq;
648
649        Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650    }
651
652    #[allow(dead_code)]
653    pub(crate) fn new_internal<T: Instance>(
654        peri: Peri<'d, T>,
655        tx_dma: Option<ChannelAndRequest<'d>>,
656        rx_dma: Option<ChannelAndRequest<'d>>,
657        config: Config,
658    ) -> Self {
659        Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
660    }
661
662    /// SPI write, using DMA.
663    pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664        if data.is_empty() {
665            return Ok(());
666        }
667
668        self.info.regs.cr1().modify(|w| {
669            w.set_spe(false);
670        });
671        self.set_word_size(W::CONFIG);
672
673        let tx_dst = self.info.regs.tx_ptr();
674        let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
675
676        set_txdmaen(self.info.regs, true);
677        self.info.regs.cr1().modify(|w| {
678            w.set_spe(true);
679        });
680        #[cfg(any(spi_v3, spi_v4, spi_v5))]
681        self.info.regs.cr1().modify(|w| {
682            w.set_cstart(true);
683        });
684
685        tx_f.await;
686
687        finish_dma(self.info.regs);
688
689        Ok(())
690    }
691
692    /// SPI read, using DMA.
693    #[cfg(any(spi_v3, spi_v4, spi_v5))]
694    pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
695        if data.is_empty() {
696            return Ok(());
697        }
698
699        let regs = self.info.regs;
700
701        regs.cr1().modify(|w| {
702            w.set_spe(false);
703        });
704
705        self.set_word_size(W::CONFIG);
706
707        let comm = regs.cfg2().modify(|w| {
708            let prev = w.comm();
709            w.set_comm(vals::Comm::RECEIVER);
710            prev
711        });
712
713        #[cfg(spi_v3)]
714        let i2scfg = regs.i2scfgr().modify(|w| {
715            w.i2smod().then(|| {
716                let prev = w.i2scfg();
717                w.set_i2scfg(match prev {
718                    vals::I2scfg::SLAVE_RX | vals::I2scfg::SLAVE_FULL_DUPLEX => vals::I2scfg::SLAVE_RX,
719                    vals::I2scfg::MASTER_RX | vals::I2scfg::MASTER_FULL_DUPLEX => vals::I2scfg::MASTER_RX,
720                    _ => panic!("unsupported configuration"),
721                });
722                prev
723            })
724        });
725
726        let rx_src = regs.rx_ptr();
727
728        for mut chunk in data.chunks_mut(u16::max_value().into()) {
729            set_rxdmaen(regs, true);
730
731            let tsize = chunk.len();
732
733            let transfer = unsafe {
734                self.rx_dma
735                    .as_mut()
736                    .unwrap()
737                    .read(rx_src, &mut chunk, Default::default())
738            };
739
740            regs.cr2().modify(|w| {
741                w.set_tsize(tsize as u16);
742            });
743
744            regs.cr1().modify(|w| {
745                w.set_spe(true);
746            });
747
748            regs.cr1().modify(|w| {
749                w.set_cstart(true);
750            });
751
752            transfer.await;
753
754            finish_dma(regs);
755        }
756
757        regs.cr1().modify(|w| {
758            w.set_spe(false);
759        });
760
761        regs.cfg2().modify(|w| {
762            w.set_comm(comm);
763        });
764
765        regs.cr2().modify(|w| {
766            w.set_tsize(0);
767        });
768
769        #[cfg(spi_v3)]
770        if let Some(i2scfg) = i2scfg {
771            regs.i2scfgr().modify(|w| {
772                w.set_i2scfg(i2scfg);
773            });
774        }
775
776        Ok(())
777    }
778
779    /// SPI read, using DMA.
780    #[cfg(any(spi_v1, spi_f1, spi_v2))]
781    pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
782        if data.is_empty() {
783            return Ok(());
784        }
785
786        self.info.regs.cr1().modify(|w| {
787            w.set_spe(false);
788        });
789
790        self.set_word_size(W::CONFIG);
791
792        // SPIv3 clears rxfifo on SPE=0
793        #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
794        flush_rx_fifo(self.info.regs);
795
796        set_rxdmaen(self.info.regs, true);
797
798        let clock_byte_count = data.len();
799
800        let rx_src = self.info.regs.rx_ptr();
801        let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
802
803        let tx_dst = self.info.regs.tx_ptr();
804        let clock_byte = W::default();
805        let tx_f = unsafe {
806            self.tx_dma
807                .as_mut()
808                .unwrap()
809                .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
810        };
811
812        set_txdmaen(self.info.regs, true);
813        self.info.regs.cr1().modify(|w| {
814            w.set_spe(true);
815        });
816        #[cfg(any(spi_v3, spi_v4, spi_v5))]
817        self.info.regs.cr1().modify(|w| {
818            w.set_cstart(true);
819        });
820
821        join(tx_f, rx_f).await;
822
823        finish_dma(self.info.regs);
824
825        Ok(())
826    }
827
828    async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
829        assert_eq!(read.len(), write.len());
830        if read.len() == 0 {
831            return Ok(());
832        }
833
834        self.info.regs.cr1().modify(|w| {
835            w.set_spe(false);
836        });
837
838        self.set_word_size(W::CONFIG);
839
840        // SPIv3 clears rxfifo on SPE=0
841        #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
842        flush_rx_fifo(self.info.regs);
843
844        set_rxdmaen(self.info.regs, true);
845
846        let rx_src = self.info.regs.rx_ptr::<W>();
847        let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
848
849        let tx_dst: *mut W = self.info.regs.tx_ptr();
850        let tx_f = unsafe {
851            self.tx_dma
852                .as_mut()
853                .unwrap()
854                .write_raw(write, tx_dst, Default::default())
855        };
856
857        set_txdmaen(self.info.regs, true);
858        self.info.regs.cr1().modify(|w| {
859            w.set_spe(true);
860        });
861        #[cfg(any(spi_v3, spi_v4, spi_v5))]
862        self.info.regs.cr1().modify(|w| {
863            w.set_cstart(true);
864        });
865
866        join(tx_f, rx_f).await;
867
868        finish_dma(self.info.regs);
869
870        Ok(())
871    }
872
873    /// Bidirectional transfer, using DMA.
874    ///
875    /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
876    ///
877    /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
878    /// If `write` is shorter it is padded with zero bytes.
879    pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
880        self.transfer_inner(read, write).await
881    }
882
883    /// In-place bidirectional transfer, using DMA.
884    ///
885    /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
886    pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
887        self.transfer_inner(data, data).await
888    }
889}
890
891impl<'d, M: PeriMode> Drop for Spi<'d, M> {
892    fn drop(&mut self) {
893        self.sck.as_ref().map(|x| x.set_as_disconnected());
894        self.mosi.as_ref().map(|x| x.set_as_disconnected());
895        self.miso.as_ref().map(|x| x.set_as_disconnected());
896
897        self.info.rcc.disable();
898    }
899}
900
901#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
902use vals::Br;
903#[cfg(any(spi_v3, spi_v4, spi_v5))]
904use vals::Mbr as Br;
905
906fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br {
907    let val = match kernel_clock.0 / freq.0 {
908        0 => panic!("You are trying to reach a frequency higher than the clock"),
909        1..=2 => 0b000,
910        3..=5 => 0b001,
911        6..=11 => 0b010,
912        12..=23 => 0b011,
913        24..=39 => 0b100,
914        40..=95 => 0b101,
915        96..=191 => 0b110,
916        _ => 0b111,
917    };
918
919    Br::from_bits(val)
920}
921
922fn compute_frequency(kernel_clock: Hertz, br: Br) -> Hertz {
923    let div: u16 = match br {
924        Br::DIV2 => 2,
925        Br::DIV4 => 4,
926        Br::DIV8 => 8,
927        Br::DIV16 => 16,
928        Br::DIV32 => 32,
929        Br::DIV64 => 64,
930        Br::DIV128 => 128,
931        Br::DIV256 => 256,
932    };
933
934    kernel_clock / div
935}
936
937pub(crate) trait RegsExt {
938    fn tx_ptr<W>(&self) -> *mut W;
939    fn rx_ptr<W>(&self) -> *mut W;
940}
941
942impl RegsExt for Regs {
943    fn tx_ptr<W>(&self) -> *mut W {
944        #[cfg(any(spi_v1, spi_f1))]
945        let dr = self.dr();
946        #[cfg(spi_v2)]
947        let dr = self.dr16();
948        #[cfg(any(spi_v3, spi_v4, spi_v5))]
949        let dr = self.txdr32();
950        dr.as_ptr() as *mut W
951    }
952
953    fn rx_ptr<W>(&self) -> *mut W {
954        #[cfg(any(spi_v1, spi_f1))]
955        let dr = self.dr();
956        #[cfg(spi_v2)]
957        let dr = self.dr16();
958        #[cfg(any(spi_v3, spi_v4, spi_v5))]
959        let dr = self.rxdr32();
960        dr.as_ptr() as *mut W
961    }
962}
963
964fn check_error_flags(sr: regs::Sr, ovr: bool) -> Result<(), Error> {
965    if sr.ovr() && ovr {
966        return Err(Error::Overrun);
967    }
968    #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))]
969    if sr.fre() {
970        return Err(Error::Framing);
971    }
972    #[cfg(any(spi_v3, spi_v4, spi_v5))]
973    if sr.tifre() {
974        return Err(Error::Framing);
975    }
976    if sr.modf() {
977        return Err(Error::ModeFault);
978    }
979    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
980    if sr.crcerr() {
981        return Err(Error::Crc);
982    }
983    #[cfg(any(spi_v3, spi_v4, spi_v5))]
984    if sr.crce() {
985        return Err(Error::Crc);
986    }
987
988    Ok(())
989}
990
991fn spin_until_tx_ready(regs: Regs, ovr: bool) -> Result<(), Error> {
992    loop {
993        let sr = regs.sr().read();
994
995        check_error_flags(sr, ovr)?;
996
997        #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
998        if sr.txe() {
999            return Ok(());
1000        }
1001        #[cfg(any(spi_v3, spi_v4, spi_v5))]
1002        if sr.txp() {
1003            return Ok(());
1004        }
1005    }
1006}
1007
1008fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
1009    loop {
1010        let sr = regs.sr().read();
1011
1012        check_error_flags(sr, true)?;
1013
1014        #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1015        if sr.rxne() {
1016            return Ok(());
1017        }
1018        #[cfg(any(spi_v3, spi_v4, spi_v5))]
1019        if sr.rxp() {
1020            return Ok(());
1021        }
1022    }
1023}
1024
1025pub(crate) fn flush_rx_fifo(regs: Regs) {
1026    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1027    while regs.sr().read().rxne() {
1028        #[cfg(not(spi_v2))]
1029        let _ = regs.dr().read();
1030        #[cfg(spi_v2)]
1031        let _ = regs.dr16().read();
1032    }
1033    #[cfg(any(spi_v3, spi_v4, spi_v5))]
1034    while regs.sr().read().rxp() {
1035        let _ = regs.rxdr32().read();
1036    }
1037}
1038
1039pub(crate) fn set_txdmaen(regs: Regs, val: bool) {
1040    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1041    regs.cr2().modify(|reg| {
1042        reg.set_txdmaen(val);
1043    });
1044    #[cfg(any(spi_v3, spi_v4, spi_v5))]
1045    regs.cfg1().modify(|reg| {
1046        reg.set_txdmaen(val);
1047    });
1048}
1049
1050pub(crate) fn set_rxdmaen(regs: Regs, val: bool) {
1051    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1052    regs.cr2().modify(|reg| {
1053        reg.set_rxdmaen(val);
1054    });
1055    #[cfg(any(spi_v3, spi_v4, spi_v5))]
1056    regs.cfg1().modify(|reg| {
1057        reg.set_rxdmaen(val);
1058    });
1059}
1060
1061fn finish_dma(regs: Regs) {
1062    #[cfg(spi_v2)]
1063    while regs.sr().read().ftlvl().to_bits() > 0 {}
1064
1065    #[cfg(any(spi_v3, spi_v4, spi_v5))]
1066    {
1067        if regs.cr2().read().tsize() == 0 {
1068            while !regs.sr().read().txc() {}
1069        } else {
1070            while !regs.sr().read().eot() {}
1071        }
1072    }
1073    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1074    while regs.sr().read().bsy() {}
1075
1076    // Disable the spi peripheral
1077    regs.cr1().modify(|w| {
1078        w.set_spe(false);
1079    });
1080
1081    // The peripheral automatically disables the DMA stream on completion without error,
1082    // but it does not clear the RXDMAEN/TXDMAEN flag in CR2.
1083    #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1084    regs.cr2().modify(|reg| {
1085        reg.set_txdmaen(false);
1086        reg.set_rxdmaen(false);
1087    });
1088    #[cfg(any(spi_v3, spi_v4, spi_v5))]
1089    regs.cfg1().modify(|reg| {
1090        reg.set_txdmaen(false);
1091        reg.set_rxdmaen(false);
1092    });
1093}
1094
1095fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
1096    spin_until_tx_ready(regs, true)?;
1097
1098    unsafe {
1099        ptr::write_volatile(regs.tx_ptr(), tx_word);
1100
1101        #[cfg(any(spi_v3, spi_v4, spi_v5))]
1102        regs.cr1().modify(|reg| reg.set_cstart(true));
1103    }
1104
1105    spin_until_rx_ready(regs)?;
1106
1107    let rx_word = unsafe { ptr::read_volatile(regs.rx_ptr()) };
1108    Ok(rx_word)
1109}
1110
1111#[allow(unused)] // unused in SPIv1
1112fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1113    // for write, we intentionally ignore the rx fifo, which will cause
1114    // overrun errors that we have to ignore.
1115    spin_until_tx_ready(regs, false)?;
1116
1117    unsafe {
1118        ptr::write_volatile(regs.tx_ptr(), tx_word);
1119
1120        #[cfg(any(spi_v3, spi_v4, spi_v5))]
1121        regs.cr1().modify(|reg| reg.set_cstart(true));
1122    }
1123    Ok(())
1124}
1125
1126// Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking {
1129    ($w:ident) => {
1130        impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> {
1131            type Error = Error;
1132
1133            fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
1134                self.blocking_write(words)
1135            }
1136        }
1137
1138        impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> {
1139            type Error = Error;
1140
1141            fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
1142                self.blocking_transfer_in_place(words)?;
1143                Ok(words)
1144            }
1145        }
1146    };
1147}
1148
1149impl_blocking!(u8);
1150impl_blocking!(u16);
1151
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> {
1153    type Error = Error;
1154}
1155
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> {
1157    fn flush(&mut self) -> Result<(), Self::Error> {
1158        Ok(())
1159    }
1160
1161    fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
1162        self.blocking_read(words)
1163    }
1164
1165    fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
1166        self.blocking_write(words)
1167    }
1168
1169    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
1170        self.blocking_transfer(read, write)
1171    }
1172
1173    fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
1174        self.blocking_transfer_in_place(words)
1175    }
1176}
1177
1178impl embedded_hal_1::spi::Error for Error {
1179    fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
1180        match *self {
1181            Self::Framing => embedded_hal_1::spi::ErrorKind::FrameFormat,
1182            Self::Crc => embedded_hal_1::spi::ErrorKind::Other,
1183            Self::ModeFault => embedded_hal_1::spi::ErrorKind::ModeFault,
1184            Self::Overrun => embedded_hal_1::spi::ErrorKind::Overrun,
1185        }
1186    }
1187}
1188
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> {
1190    async fn flush(&mut self) -> Result<(), Self::Error> {
1191        Ok(())
1192    }
1193
1194    async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
1195        self.write(words).await
1196    }
1197
1198    async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
1199        self.read(words).await
1200    }
1201
1202    async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
1203        self.transfer(read, write).await
1204    }
1205
1206    async fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
1207        self.transfer_in_place(words).await
1208    }
1209}
1210
1211pub(crate) trait SealedWord {
1212    const CONFIG: word_impl::Config;
1213}
1214
1215/// Word sizes usable for SPI.
1216#[allow(private_bounds)]
1217pub trait Word: word::Word + SealedWord + Default {}
1218
1219macro_rules! impl_word {
1220    ($T:ty, $config:expr) => {
1221        impl SealedWord for $T {
1222            const CONFIG: Config = $config;
1223        }
1224        impl Word for $T {}
1225    };
1226}
1227
1228#[cfg(any(spi_v1, spi_f1))]
1229mod word_impl {
1230    use super::*;
1231
1232    pub type Config = vals::Dff;
1233
1234    impl_word!(u8, vals::Dff::BITS8);
1235    impl_word!(u16, vals::Dff::BITS16);
1236}
1237
1238#[cfg(spi_v2)]
1239mod word_impl {
1240    use super::*;
1241
1242    pub type Config = (vals::Ds, vals::Frxth);
1243
1244    impl_word!(word::U4, (vals::Ds::BITS4, vals::Frxth::QUARTER));
1245    impl_word!(word::U5, (vals::Ds::BITS5, vals::Frxth::QUARTER));
1246    impl_word!(word::U6, (vals::Ds::BITS6, vals::Frxth::QUARTER));
1247    impl_word!(word::U7, (vals::Ds::BITS7, vals::Frxth::QUARTER));
1248    impl_word!(u8, (vals::Ds::BITS8, vals::Frxth::QUARTER));
1249    impl_word!(word::U9, (vals::Ds::BITS9, vals::Frxth::HALF));
1250    impl_word!(word::U10, (vals::Ds::BITS10, vals::Frxth::HALF));
1251    impl_word!(word::U11, (vals::Ds::BITS11, vals::Frxth::HALF));
1252    impl_word!(word::U12, (vals::Ds::BITS12, vals::Frxth::HALF));
1253    impl_word!(word::U13, (vals::Ds::BITS13, vals::Frxth::HALF));
1254    impl_word!(word::U14, (vals::Ds::BITS14, vals::Frxth::HALF));
1255    impl_word!(word::U15, (vals::Ds::BITS15, vals::Frxth::HALF));
1256    impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF));
1257}
1258
1259#[cfg(any(spi_v3, spi_v4, spi_v5))]
1260mod word_impl {
1261    use super::*;
1262
1263    pub type Config = u8;
1264
1265    impl_word!(word::U4, 4 - 1);
1266    impl_word!(word::U5, 5 - 1);
1267    impl_word!(word::U6, 6 - 1);
1268    impl_word!(word::U7, 7 - 1);
1269    impl_word!(u8, 8 - 1);
1270    impl_word!(word::U9, 9 - 1);
1271    impl_word!(word::U10, 10 - 1);
1272    impl_word!(word::U11, 11 - 1);
1273    impl_word!(word::U12, 12 - 1);
1274    impl_word!(word::U13, 13 - 1);
1275    impl_word!(word::U14, 14 - 1);
1276    impl_word!(word::U15, 15 - 1);
1277    impl_word!(u16, 16 - 1);
1278    impl_word!(word::U17, 17 - 1);
1279    impl_word!(word::U18, 18 - 1);
1280    impl_word!(word::U19, 19 - 1);
1281    impl_word!(word::U20, 20 - 1);
1282    impl_word!(word::U21, 21 - 1);
1283    impl_word!(word::U22, 22 - 1);
1284    impl_word!(word::U23, 23 - 1);
1285    impl_word!(word::U24, 24 - 1);
1286    impl_word!(word::U25, 25 - 1);
1287    impl_word!(word::U26, 26 - 1);
1288    impl_word!(word::U27, 27 - 1);
1289    impl_word!(word::U28, 28 - 1);
1290    impl_word!(word::U29, 29 - 1);
1291    impl_word!(word::U30, 30 - 1);
1292    impl_word!(word::U31, 31 - 1);
1293    impl_word!(u32, 32 - 1);
1294}
1295
1296pub(crate) struct Info {
1297    pub(crate) regs: Regs,
1298    pub(crate) rcc: RccInfo,
1299}
1300
1301struct State {}
1302
1303impl State {
1304    #[allow(unused)]
1305    const fn new() -> Self {
1306        Self {}
1307    }
1308}
1309
1310peri_trait!();
1311
1312pin_trait!(SckPin, Instance);
1313pin_trait!(MosiPin, Instance);
1314pin_trait!(MisoPin, Instance);
1315pin_trait!(CsPin, Instance);
1316pin_trait!(MckPin, Instance);
1317pin_trait!(CkPin, Instance);
1318pin_trait!(WsPin, Instance);
1319dma_trait!(RxDma, Instance);
1320dma_trait!(TxDma, Instance);
1321
1322foreach_peripheral!(
1323    (spi, $inst:ident) => {
1324        peri_trait_impl!($inst, Info {
1325            regs: crate::pac::$inst,
1326            rcc: crate::peripherals::$inst::RCC_INFO,
1327        });
1328    };
1329);
1330
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> {
1332    type Config = Config;
1333    type ConfigError = ();
1334    fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1335        self.set_config(config)
1336    }
1337}