1use 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#[derive(Copy, Clone)]
15pub enum Mode {
16 Master,
18 Slave,
20}
21
22#[derive(Copy, Clone)]
24#[allow(dead_code)]
25enum Function {
26 Transmit,
28 Receive,
30 #[cfg(spi_v3)]
31 FullDuplex,
33}
34
35#[derive(Copy, Clone)]
37pub enum Standard {
38 Philips,
40 MsbFirst,
42 LsbFirst,
44 PcmLongSync,
46 PcmShortSync,
48}
49
50#[derive(Debug, PartialEq, Eq)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum Error {
54 NotATransmitter,
56 NotAReceiver,
58 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#[derive(Copy, Clone)]
97pub enum Format {
98 Data16Channel16,
100 Data16Channel32,
102 Data24Channel32,
104 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#[derive(Copy, Clone)]
132pub enum ClockPolarity {
133 IdleLow,
135 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#[non_exhaustive]
156#[derive(Copy, Clone)]
157pub struct Config {
158 pub frequency: Hertz,
160 pub gpio_speed: Speed,
162 pub mode: Mode,
164 pub standard: Standard,
166 pub format: Format,
168 pub clock_polarity: ClockPolarity,
170 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
188pub struct Writer<'s, 'd, W: Word>(&'s mut WritableRingBuffer<'d, W>);
190
191impl<'s, 'd, W: Word> Writer<'s, 'd, W> {
192 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
196 self.0.write_exact(data).await?;
197 Ok(())
198 }
199
200 pub fn reset(&mut self) {
204 self.0.clear();
205 }
206}
207
208pub struct Reader<'s, 'd, W: Word>(&'s mut ReadableRingBuffer<'d, W>);
210
211impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
212 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
216 self.0.read_exact(data).await?;
217 Ok(())
218 }
219
220 pub fn reset(&mut self) {
224 self.0.clear();
225 }
226}
227
228pub 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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
606fn 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)]
643fn 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}