1use 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#[derive(Copy, Clone)]
16pub enum Mode {
17 Master,
19 Slave,
21}
22
23#[derive(Copy, Clone)]
25#[allow(dead_code)]
26enum Function {
27 Transmit,
29 Receive,
31 #[cfg(spi_v3)]
32 FullDuplex,
34}
35
36#[derive(Copy, Clone)]
38pub enum Standard {
39 Philips,
41 MsbFirst,
43 LsbFirst,
45 PcmLongSync,
47 PcmShortSync,
49}
50
51#[derive(Debug, PartialEq, Eq)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum Error {
55 NotATransmitter,
57 NotAReceiver,
59 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#[derive(Copy, Clone)]
98pub enum Format {
99 Data16Channel16,
101 Data16Channel32,
103 Data24Channel32,
105 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#[derive(Copy, Clone)]
133pub enum ClockPolarity {
134 IdleLow,
136 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#[non_exhaustive]
157#[derive(Copy, Clone)]
158pub struct Config {
159 pub mode: Mode,
161 pub standard: Standard,
163 pub format: Format,
165 pub clock_polarity: ClockPolarity,
167 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
183pub struct Writer<'s, 'd, W: Word>(&'s mut WritableRingBuffer<'d, W>);
185
186impl<'s, 'd, W: Word> Writer<'s, 'd, W> {
187 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
191 self.0.write_exact(data).await?;
192 Ok(())
193 }
194
195 pub fn reset(&mut self) {
199 self.0.clear();
200 }
201}
202
203pub struct Reader<'s, 'd, W: Word>(&'s mut ReadableRingBuffer<'d, W>);
205
206impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
207 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
211 self.0.read_exact(data).await?;
212 Ok(())
213 }
214
215 pub fn reset(&mut self) {
219 self.0.clear();
220 }
221}
222
223pub 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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
612fn 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)]
649fn 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}