embassy_stm32/
i2s.rs

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