embassy_stm32/
i2s.rs

1//! Inter-IC Sound (I2S)
2
3use embassy_futures::join::join;
4use embassy_hal_internal::into_ref;
5use stm32_metapac::spi::vals;
6
7use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9use crate::mode::Async;
10use crate::spi::{Config as SpiConfig, RegsExt as _, *};
11use crate::time::Hertz;
12use crate::{Peripheral, PeripheralRef};
13
14/// I2S mode
15#[derive(Copy, Clone)]
16pub enum Mode {
17    /// Master mode
18    Master,
19    /// Slave mode
20    Slave,
21}
22
23/// I2S function
24#[derive(Copy, Clone)]
25#[allow(dead_code)]
26enum Function {
27    /// Transmit audio data
28    Transmit,
29    /// Receive audio data
30    Receive,
31    #[cfg(spi_v3)]
32    /// Transmit and Receive audio data
33    FullDuplex,
34}
35
36/// I2C standard
37#[derive(Copy, Clone)]
38pub enum Standard {
39    /// Philips
40    Philips,
41    /// Most significant bit first.
42    MsbFirst,
43    /// Least significant bit first.
44    LsbFirst,
45    /// PCM with long sync.
46    PcmLongSync,
47    /// PCM with short sync.
48    PcmShortSync,
49}
50
51/// SAI error
52#[derive(Debug, PartialEq, Eq)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum Error {
55    /// `write` called on a SAI in receive mode.
56    NotATransmitter,
57    /// `read` called on a SAI in transmit mode.
58    NotAReceiver,
59    /// Overrun
60    Overrun,
61}
62
63impl From<ringbuffer::Error> for Error {
64    fn from(#[allow(unused)] err: ringbuffer::Error) -> Self {
65        #[cfg(feature = "defmt")]
66        {
67            if err == ringbuffer::Error::DmaUnsynced {
68                defmt::error!("Ringbuffer broken invariants detected!");
69            }
70        }
71        Self::Overrun
72    }
73}
74
75impl Standard {
76    #[cfg(any(spi_v1, spi_v3, spi_f1))]
77    const fn i2sstd(&self) -> vals::I2sstd {
78        match self {
79            Standard::Philips => vals::I2sstd::PHILIPS,
80            Standard::MsbFirst => vals::I2sstd::MSB,
81            Standard::LsbFirst => vals::I2sstd::LSB,
82            Standard::PcmLongSync => vals::I2sstd::PCM,
83            Standard::PcmShortSync => vals::I2sstd::PCM,
84        }
85    }
86
87    #[cfg(any(spi_v1, spi_v3, spi_f1))]
88    const fn pcmsync(&self) -> vals::Pcmsync {
89        match self {
90            Standard::PcmLongSync => vals::Pcmsync::LONG,
91            _ => vals::Pcmsync::SHORT,
92        }
93    }
94}
95
96/// I2S data format.
97#[derive(Copy, Clone)]
98pub enum Format {
99    /// 16 bit data length on 16 bit wide channel
100    Data16Channel16,
101    /// 16 bit data length on 32 bit wide channel
102    Data16Channel32,
103    /// 24 bit data length on 32 bit wide channel
104    Data24Channel32,
105    /// 32 bit data length on 32 bit wide channel
106    Data32Channel32,
107}
108
109impl Format {
110    #[cfg(any(spi_v1, spi_v3, spi_f1))]
111    const fn datlen(&self) -> vals::Datlen {
112        match self {
113            Format::Data16Channel16 => vals::Datlen::BITS16,
114            Format::Data16Channel32 => vals::Datlen::BITS16,
115            Format::Data24Channel32 => vals::Datlen::BITS24,
116            Format::Data32Channel32 => vals::Datlen::BITS32,
117        }
118    }
119
120    #[cfg(any(spi_v1, spi_v3, spi_f1))]
121    const fn chlen(&self) -> vals::Chlen {
122        match self {
123            Format::Data16Channel16 => vals::Chlen::BITS16,
124            Format::Data16Channel32 => vals::Chlen::BITS32,
125            Format::Data24Channel32 => vals::Chlen::BITS32,
126            Format::Data32Channel32 => vals::Chlen::BITS32,
127        }
128    }
129}
130
131/// Clock polarity
132#[derive(Copy, Clone)]
133pub enum ClockPolarity {
134    /// Low on idle.
135    IdleLow,
136    /// High on idle.
137    IdleHigh,
138}
139
140impl ClockPolarity {
141    #[cfg(any(spi_v1, spi_v3, spi_f1))]
142    const fn ckpol(&self) -> vals::Ckpol {
143        match self {
144            ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH,
145            ClockPolarity::IdleLow => vals::Ckpol::IDLE_LOW,
146        }
147    }
148}
149
150/// [`I2S`] configuration.
151///
152///  - `MS`: `Master` or `Slave`
153///  - `TR`: `Transmit` or `Receive`
154///  - `STD`: I2S standard, eg `Philips`
155///  - `FMT`: Frame Format marker, eg `Data16Channel16`
156#[non_exhaustive]
157#[derive(Copy, Clone)]
158pub struct Config {
159    /// Mode
160    pub mode: Mode,
161    /// Which I2S standard to use.
162    pub standard: Standard,
163    /// Data format.
164    pub format: Format,
165    /// Clock polarity.
166    pub clock_polarity: ClockPolarity,
167    /// True to enable master clock output from this instance.
168    pub master_clock: bool,
169}
170
171impl Default for Config {
172    fn default() -> Self {
173        Self {
174            mode: Mode::Master,
175            standard: Standard::Philips,
176            format: Format::Data16Channel16,
177            clock_polarity: ClockPolarity::IdleLow,
178            master_clock: true,
179        }
180    }
181}
182
183/// I2S driver writer. Useful for moving write functionality across tasks.
184pub struct Writer<'s, 'd, W: Word>(&'s mut WritableRingBuffer<'d, W>);
185
186impl<'s, 'd, W: Word> Writer<'s, 'd, W> {
187    /// Write data to the I2S ringbuffer.
188    /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background.
189    /// If thfre’s no space in the buffer, this waits until there is.
190    pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
191        self.0.write_exact(data).await?;
192        Ok(())
193    }
194
195    /// Reset the ring buffer to its initial state.
196    /// Can be used to recover from overrun.
197    /// The ringbuffer will always auto-reset on Overrun in any case.
198    pub fn reset(&mut self) {
199        self.0.clear();
200    }
201}
202
203/// I2S driver reader. Useful for moving read functionality across tasks.
204pub struct Reader<'s, 'd, W: Word>(&'s mut ReadableRingBuffer<'d, W>);
205
206impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
207    /// Read data from the I2S ringbuffer.
208    /// SAI is always receiving data in the background. This function pops already-received data from the buffer.
209    /// If there’s less than data.len() data in the buffer, this waits until there is.
210    pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
211        self.0.read_exact(data).await?;
212        Ok(())
213    }
214
215    /// Reset the ring buffer to its initial state.
216    /// Can be used to prevent overrun.
217    /// The ringbuffer will always auto-reset on Overrun in any case.
218    pub fn reset(&mut self) {
219        self.0.clear();
220    }
221}
222
223/// I2S driver.
224pub struct I2S<'d, W: Word> {
225    #[allow(dead_code)]
226    mode: Mode,
227    spi: Spi<'d, Async>,
228    txsd: Option<PeripheralRef<'d, AnyPin>>,
229    rxsd: Option<PeripheralRef<'d, AnyPin>>,
230    ws: Option<PeripheralRef<'d, AnyPin>>,
231    ck: Option<PeripheralRef<'d, AnyPin>>,
232    mck: Option<PeripheralRef<'d, AnyPin>>,
233    tx_ring_buffer: Option<WritableRingBuffer<'d, W>>,
234    rx_ring_buffer: Option<ReadableRingBuffer<'d, W>>,
235}
236
237impl<'d, W: Word> I2S<'d, W> {
238    /// Create a transmitter driver.
239    pub fn new_txonly<T: Instance>(
240        peri: impl Peripheral<P = T> + 'd,
241        sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
242        ws: impl Peripheral<P = impl WsPin<T>> + 'd,
243        ck: impl Peripheral<P = impl CkPin<T>> + 'd,
244        mck: impl Peripheral<P = impl MckPin<T>> + 'd,
245        txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
246        txdma_buf: &'d mut [W],
247        freq: Hertz,
248        config: Config,
249    ) -> Self {
250        Self::new_inner(
251            peri,
252            new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
253            None,
254            ws,
255            ck,
256            new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
257            new_dma!(txdma).map(|d| (d, txdma_buf)),
258            None,
259            freq,
260            config,
261            Function::Transmit,
262        )
263    }
264
265    /// Create a transmitter driver without a master clock pin.
266    pub fn new_txonly_nomck<T: Instance>(
267        peri: impl Peripheral<P = T> + 'd,
268        sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
269        ws: impl Peripheral<P = impl WsPin<T>> + 'd,
270        ck: impl Peripheral<P = impl CkPin<T>> + 'd,
271        txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
272        txdma_buf: &'d mut [W],
273        freq: Hertz,
274        config: Config,
275    ) -> Self {
276        Self::new_inner(
277            peri,
278            new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
279            None,
280            ws,
281            ck,
282            None,
283            new_dma!(txdma).map(|d| (d, txdma_buf)),
284            None,
285            freq,
286            config,
287            Function::Transmit,
288        )
289    }
290
291    /// Create a receiver driver.
292    pub fn new_rxonly<T: Instance>(
293        peri: impl Peripheral<P = T> + 'd,
294        sd: impl Peripheral<P = impl MisoPin<T>> + 'd,
295        ws: impl Peripheral<P = impl WsPin<T>> + 'd,
296        ck: impl Peripheral<P = impl CkPin<T>> + 'd,
297        mck: impl Peripheral<P = impl MckPin<T>> + 'd,
298        rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
299        rxdma_buf: &'d mut [W],
300        freq: Hertz,
301        config: Config,
302    ) -> Self {
303        Self::new_inner(
304            peri,
305            None,
306            new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
307            ws,
308            ck,
309            new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
310            None,
311            new_dma!(rxdma).map(|d| (d, rxdma_buf)),
312            freq,
313            config,
314            Function::Receive,
315        )
316    }
317
318    #[cfg(spi_v3)]
319    /// Create a full duplex driver.
320    pub fn new_full_duplex<T: Instance>(
321        peri: impl Peripheral<P = T> + 'd,
322        txsd: impl Peripheral<P = impl MosiPin<T>> + 'd,
323        rxsd: impl Peripheral<P = impl MisoPin<T>> + 'd,
324        ws: impl Peripheral<P = impl WsPin<T>> + 'd,
325        ck: impl Peripheral<P = impl CkPin<T>> + 'd,
326        mck: impl Peripheral<P = impl MckPin<T>> + 'd,
327        txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
328        txdma_buf: &'d mut [W],
329        rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
330        rxdma_buf: &'d mut [W],
331        freq: Hertz,
332        config: Config,
333    ) -> Self {
334        Self::new_inner(
335            peri,
336            new_pin!(txsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
337            new_pin!(rxsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
338            ws,
339            ck,
340            new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
341            new_dma!(txdma).map(|d| (d, txdma_buf)),
342            new_dma!(rxdma).map(|d| (d, rxdma_buf)),
343            freq,
344            config,
345            Function::FullDuplex,
346        )
347    }
348
349    /// Start I2S driver.
350    pub fn start(&mut self) {
351        self.spi.info.regs.cr1().modify(|w| {
352            w.set_spe(false);
353        });
354        self.spi.set_word_size(W::CONFIG);
355        if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
356            tx_ring_buffer.start();
357
358            set_txdmaen(self.spi.info.regs, true);
359        }
360        if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
361            rx_ring_buffer.start();
362            // SPIv3 clears rxfifo on SPE=0
363            #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
364            flush_rx_fifo(self.spi.info.regs);
365
366            set_rxdmaen(self.spi.info.regs, true);
367        }
368        self.spi.info.regs.cr1().modify(|w| {
369            w.set_spe(true);
370        });
371        #[cfg(any(spi_v3, spi_v4, spi_v5))]
372        self.spi.info.regs.cr1().modify(|w| {
373            w.set_cstart(true);
374        });
375    }
376
377    /// Reset the ring buffer to its initial state.
378    /// Can be used to recover from overrun.
379    pub fn clear(&mut self) {
380        if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
381            rx_ring_buffer.clear();
382        }
383        if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
384            tx_ring_buffer.clear();
385        }
386    }
387
388    /// Stop I2S driver.
389    pub async fn stop(&mut self) {
390        let regs = self.spi.info.regs;
391
392        let tx_f = async {
393            if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
394                tx_ring_buffer.stop().await;
395
396                set_txdmaen(regs, false);
397            }
398        };
399
400        let rx_f = async {
401            if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
402                rx_ring_buffer.stop().await;
403
404                set_rxdmaen(regs, false);
405            }
406        };
407
408        join(rx_f, tx_f).await;
409
410        #[cfg(any(spi_v3, spi_v4, spi_v5))]
411        {
412            if let Mode::Master = self.mode {
413                regs.cr1().modify(|w| {
414                    w.set_csusp(true);
415                });
416
417                while regs.cr1().read().cstart() {}
418            }
419        }
420
421        regs.cr1().modify(|w| {
422            w.set_spe(false);
423        });
424
425        self.clear();
426    }
427
428    /// Split the driver into a Reader/Writer pair.
429    /// Useful for splitting the reader/writer functionality across tasks or
430    /// for calling the read/write methods in parallel.
431    pub fn split<'s>(&'s mut self) -> Result<(Reader<'s, 'd, W>, Writer<'s, 'd, W>), Error> {
432        match (&mut self.rx_ring_buffer, &mut self.tx_ring_buffer) {
433            (None, _) => Err(Error::NotAReceiver),
434            (_, None) => Err(Error::NotATransmitter),
435            (Some(rx_ring), Some(tx_ring)) => Ok((Reader(rx_ring), Writer(tx_ring))),
436        }
437    }
438
439    /// Read data from the I2S ringbuffer.
440    /// SAI is always receiving data in the background. This function pops already-received data from the buffer.
441    /// If there’s less than data.len() data in the buffer, this waits until there is.
442    pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
443        match &mut self.rx_ring_buffer {
444            Some(ring) => Reader(ring).read(data).await,
445            _ => Err(Error::NotAReceiver),
446        }
447    }
448
449    /// Write data to the I2S ringbuffer.
450    /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background.
451    /// If thfre’s no space in the buffer, this waits until there is.
452    pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
453        match &mut self.tx_ring_buffer {
454            Some(ring) => Writer(ring).write(data).await,
455            _ => Err(Error::NotATransmitter),
456        }
457    }
458
459    /// Write data directly to the raw I2S ringbuffer.
460    /// This can be used to fill the buffer before starting the DMA transfer.
461    pub async fn write_immediate(&mut self, data: &[W]) -> Result<(usize, usize), Error> {
462        match &mut self.tx_ring_buffer {
463            Some(ring) => Ok(ring.write_immediate(data)?),
464            _ => return Err(Error::NotATransmitter),
465        }
466    }
467
468    fn new_inner<T: Instance>(
469        peri: impl Peripheral<P = T> + 'd,
470        txsd: Option<PeripheralRef<'d, AnyPin>>,
471        rxsd: Option<PeripheralRef<'d, AnyPin>>,
472        ws: impl Peripheral<P = impl WsPin<T>> + 'd,
473        ck: impl Peripheral<P = impl CkPin<T>> + 'd,
474        mck: Option<PeripheralRef<'d, AnyPin>>,
475        txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
476        rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
477        freq: Hertz,
478        config: Config,
479        function: Function,
480    ) -> Self {
481        into_ref!(ws, ck);
482
483        ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
484        ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
485
486        let spi = Spi::new_internal(peri, None, None, {
487            let mut config = SpiConfig::default();
488            config.frequency = freq;
489            config
490        });
491
492        let regs = T::info().regs;
493
494        #[cfg(all(rcc_f4, not(stm32f410)))]
495        let pclk = unsafe { crate::rcc::get_freqs() }.plli2s1_r.to_hertz().unwrap();
496        #[cfg(not(all(rcc_f4, not(stm32f410))))]
497        let pclk = T::frequency();
498
499        let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
500
501        #[cfg(any(spi_v1, spi_v3, spi_f1))]
502        {
503            #[cfg(spi_v3)]
504            {
505                regs.cr1().modify(|w| w.set_spe(false));
506
507                reset_incompatible_bitfields::<T>();
508            }
509
510            use stm32_metapac::spi::vals::{I2scfg, Odd};
511
512            // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud
513            // rate to reach the proper audio sample frequency. The ODD bit in the
514            // SPI_I2SPR/SPI_I2SCFGR register also has to be defined.
515
516            // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
517            // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to
518            // the external DAC/ADC audio component (the I2SDIV and ODD values should be
519            // computed depending on the state of the MCK output, for more details refer to
520            // Section 28.4.4: Clock generator).
521
522            // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the
523            // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the
524            // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit.
525            // Select also the I2S master mode and direction (Transmitter or Receiver) through the
526            // I2SCFG[1:0] bits in the SPI_I2SCFGR register.
527
528            // 4. If needed, select all the potential interruption sources and the DMA capabilities by
529            // writing the SPI_CR2 register.
530
531            // 5. The I2SE bit in SPI_I2SCFGR register must be set.
532
533            let clk_reg = {
534                #[cfg(any(spi_v1, spi_f1))]
535                {
536                    regs.i2spr()
537                }
538                #[cfg(spi_v3)]
539                {
540                    regs.i2scfgr()
541                }
542            };
543
544            clk_reg.modify(|w| {
545                w.set_i2sdiv(div);
546                w.set_odd(match odd {
547                    true => Odd::ODD,
548                    false => Odd::EVEN,
549                });
550
551                w.set_mckoe(config.master_clock);
552            });
553
554            regs.i2scfgr().modify(|w| {
555                w.set_ckpol(config.clock_polarity.ckpol());
556
557                w.set_i2smod(true);
558
559                w.set_i2sstd(config.standard.i2sstd());
560                w.set_pcmsync(config.standard.pcmsync());
561
562                w.set_datlen(config.format.datlen());
563                w.set_chlen(config.format.chlen());
564
565                w.set_i2scfg(match (config.mode, function) {
566                    (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX,
567                    (Mode::Master, Function::Receive) => I2scfg::MASTER_RX,
568                    #[cfg(spi_v3)]
569                    (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX,
570                    (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX,
571                    (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX,
572                    #[cfg(spi_v3)]
573                    (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX,
574                });
575
576                #[cfg(any(spi_v1, spi_f1))]
577                w.set_i2se(true);
578            });
579
580            let mut opts = TransferOptions::default();
581            opts.half_transfer_ir = true;
582
583            Self {
584                mode: config.mode,
585                spi,
586                txsd: txsd.map(|w| w.map_into()),
587                rxsd: rxsd.map(|w| w.map_into()),
588                ws: Some(ws.map_into()),
589                ck: Some(ck.map_into()),
590                mck: mck.map(|w| w.map_into()),
591                tx_ring_buffer: txdma.map(|(ch, buf)| unsafe {
592                    WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts)
593                }),
594                rx_ring_buffer: rxdma.map(|(ch, buf)| unsafe {
595                    ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts)
596                }),
597            }
598        }
599    }
600}
601
602impl<'d, W: Word> Drop for I2S<'d, W> {
603    fn drop(&mut self) {
604        self.txsd.as_ref().map(|x| x.set_as_disconnected());
605        self.rxsd.as_ref().map(|x| x.set_as_disconnected());
606        self.ws.as_ref().map(|x| x.set_as_disconnected());
607        self.ck.as_ref().map(|x| x.set_as_disconnected());
608        self.mck.as_ref().map(|x| x.set_as_disconnected());
609    }
610}
611
612// Note, calculation details:
613// Fs = i2s_clock / [256 * ((2 * div) + odd)] when master clock is enabled
614// Fs = i2s_clock / [(channel_length * 2) * ((2 * div) + odd)]` when master clock is disabled
615// channel_length is 16 or 32
616//
617// can be rewritten as
618// Fs = i2s_clock / (coef * division)
619// where coef is a constant equal to 256, 64 or 32 depending channel length and master clock
620// and where division = (2 * div) + odd
621//
622// Equation can be rewritten as
623// division = i2s_clock/ (coef * Fs)
624//
625// note: division = (2 * div) + odd = (div << 1) + odd
626// in other word, from bits point of view, division[8:1] = div[7:0] and division[0] = odd
627fn compute_baud_rate(i2s_clock: Hertz, request_freq: Hertz, mclk: bool, data_format: Format) -> (bool, u8) {
628    let coef = if mclk {
629        256
630    } else if let Format::Data16Channel16 = data_format {
631        32
632    } else {
633        64
634    };
635
636    let (n, d) = (i2s_clock.0, coef * request_freq.0);
637    let division = (n + (d >> 1)) / d;
638
639    if division < 4 {
640        (false, 2)
641    } else if division > 511 {
642        (true, 255)
643    } else {
644        ((division & 1) == 1, (division >> 1) as u8)
645    }
646}
647
648#[cfg(spi_v3)]
649// The STM32H7 reference manual specifies that any incompatible bitfields should be reset
650// to their reset values while operating in I2S mode.
651fn reset_incompatible_bitfields<T: Instance>() {
652    let regs = T::info().regs;
653    regs.cr1().modify(|w| {
654        let iolock = w.iolock();
655        let csusp = w.csusp();
656        let spe = w.cstart();
657        let cstart = w.cstart();
658        w.0 = 0;
659        w.set_iolock(iolock);
660        w.set_csusp(csusp);
661        w.set_spe(spe);
662        w.set_cstart(cstart);
663    });
664
665    regs.cr2().write(|w| w.0 = 0);
666
667    regs.cfg1().modify(|w| {
668        let txdmaen = w.txdmaen();
669        let rxdmaen = w.rxdmaen();
670        let fthlv = w.fthlv();
671        w.0 = 0;
672        w.set_txdmaen(txdmaen);
673        w.set_rxdmaen(rxdmaen);
674        w.set_fthlv(fthlv);
675    });
676
677    regs.cfg2().modify(|w| {
678        let afcntr = w.afcntr();
679        let lsbfirst = w.lsbfirst();
680        let ioswp = w.ioswp();
681        w.0 = 0;
682        w.set_afcntr(afcntr);
683        w.set_lsbfirst(lsbfirst);
684        w.set_ioswp(ioswp);
685    });
686
687    regs.ier().modify(|w| {
688        let tifreie = w.tifreie();
689        let ovrie = w.ovrie();
690        let udrie = w.udrie();
691        let txpie = w.txpie();
692        let rxpie = w.rxpie();
693
694        w.0 = 0;
695
696        w.set_tifreie(tifreie);
697        w.set_ovrie(ovrie);
698        w.set_udrie(udrie);
699        w.set_txpie(txpie);
700        w.set_rxpie(rxpie);
701    });
702
703    regs.ifcr().write(|w| {
704        w.set_suspc(true);
705        w.set_tifrec(true);
706        w.set_ovrc(true);
707        w.set_udrc(true);
708    });
709
710    regs.crcpoly().write(|w| w.0 = 0x107);
711    regs.txcrc().write(|w| w.0 = 0);
712    regs.rxcrc().write(|w| w.0 = 0);
713    regs.udrdr().write(|w| w.0 = 0);
714}