1use core::ops::Deref;
23
24use crate::gpio::alt::SaiChannel;
25use crate::pac::RCC;
26#[cfg(feature = "sai2")]
27use crate::pac::SAI2;
28#[cfg(any(
29 feature = "gpio-f413",
30 feature = "gpio-f469",
31 feature = "stm32f429",
32 feature = "stm32f439"
33))]
34use crate::pac::{sai, SAI as SAI1};
35#[cfg(any(feature = "stm32f427", feature = "stm32f437", feature = "stm32f446"))]
36use crate::pac::{sai1 as sai, SAI1};
37use crate::rcc;
38use crate::time::Hertz;
39
40pub use sai::ch::{cr1::DS as WordSize, slotr::SLOTSZ as SlotSize};
41
42fn word_size(ws: WordSize) -> u8 {
43 match ws {
44 WordSize::Bit8 => 8,
45 WordSize::Bit10 => 10,
46 WordSize::Bit16 => 16,
47 WordSize::Bit20 => 20,
48 WordSize::Bit24 => 24,
49 WordSize::Bit32 => 32,
50 }
51}
52
53fn slot_size(sz: SlotSize, ws: u8) -> u8 {
54 match sz {
55 SlotSize::DataSize => ws,
56 SlotSize::Bit16 => 16,
57 SlotSize::Bit32 => 32,
58 }
59}
60
61#[derive(Clone, Copy)]
63pub struct Protocol {
64 pub sync: Synchronization,
66 pub word_size: WordSize,
70 pub slot_size: SlotSize,
79 pub num_slots: u8,
83}
84
85#[derive(Clone, Copy)]
87pub enum Synchronization {
88 I2S,
96 MSBJustified,
101 LSBJustified,
107 PCMShortFrame,
111 PCMLongFrame,
116}
117
118pub struct SAICH<SAI, const C: bool> {
120 sai: SAI,
121}
122
123impl<SAI: Instance, const C: bool> SAICH<SAI, C> {
124 fn ch(&self) -> &sai::CH {
125 self.sai.ch(usize::from(C))
126 }
127}
128
129pub type SAIA<SAI> = SAICH<SAI, false>;
131
132pub type SAIB<SAI> = SAICH<SAI, true>;
134
135impl<SAI> crate::Sealed for SAIA<SAI> {}
136
137pub struct Asynchronous;
141
142pub struct AsyncMaster<Ch: SaiChannel> {
144 #[allow(unused)]
146 pins: (Option<Ch::Mclk>, Ch::Fs, Ch::Sck, Ch::Sd),
147}
148
149impl<Ch: SaiChannel> AsyncMaster<Ch> {
150 fn new(
151 pins: (
152 Option<impl Into<Ch::Mclk>>,
153 impl Into<Ch::Fs>,
154 impl Into<Ch::Sck>,
155 impl Into<Ch::Sd>,
156 ),
157 ) -> Self {
158 Self {
159 pins: (
160 pins.0.map(Into::into),
161 pins.1.into(),
162 pins.2.into(),
163 pins.3.into(),
164 ),
165 }
166 }
167}
168
169pub struct AsyncSlave<Ch: SaiChannel> {
171 #[allow(unused)]
173 pins: (Option<Ch::Mclk>, Ch::Fs, Ch::Sck, Ch::Sd),
174}
175
176impl<Ch: SaiChannel> AsyncSlave<Ch> {
177 fn new(
178 pins: (
179 Option<impl Into<Ch::Mclk>>,
180 impl Into<Ch::Fs>,
181 impl Into<Ch::Sck>,
182 impl Into<Ch::Sd>,
183 ),
184 ) -> Self {
185 Self {
186 pins: (
187 pins.0.map(Into::into),
188 pins.1.into(),
189 pins.2.into(),
190 pins.3.into(),
191 ),
192 }
193 }
194}
195
196pub struct Synchronous;
200
201pub struct SyncSlave<Ch: SaiChannel> {
203 #[allow(unused)]
205 sd: Ch::Sd,
206}
207
208impl<Ch: SaiChannel> SyncSlave<Ch> {
209 fn new(sd: impl Into<Ch::Sd>) -> Self {
210 Self { sd: sd.into() }
211 }
212}
213
214pub struct NoDir;
216
217pub struct Receive;
219
220pub struct Transmit;
222
223pub trait Instance:
224 crate::Sealed
225 + crate::Ptr<RB = sai::RegisterBlock>
226 + crate::Steal
227 + Deref<Target = Self::RB>
228 + rcc::Enable
229 + rcc::Reset
230 + rcc::BusClock
231{
232}
233
234impl<SAI: Instance, const C: bool> SAICH<SAI, C> {
235 fn new(sai: SAI) -> Self {
236 Self { sai }
237 }
238 fn new_steal() -> Self {
239 Self {
240 sai: unsafe { SAI::steal() },
241 }
242 }
243}
244
245macro_rules! sai_impl {
246 ($SAI:ty, $sai:ident, $SAIA:ident, $SAIB:ident) => {
247 pub type $SAIA = SAIA<$SAI>;
248 pub type $SAIB = SAIB<$SAI>;
249
250 impl Instance for $SAI {}
251 };
252}
253
254sai_impl!(SAI1, sai1, SAI1A, SAI1B);
255#[cfg(feature = "sai2")]
256sai_impl!(SAI2, sai2, SAI2A, SAI2B);
257
258impl<SAI, const C: bool> Deref for SAICH<SAI, C>
259where
260 SAI: Instance,
261{
262 type Target = sai::CH;
263
264 fn deref(&self) -> &Self::Target {
265 self.ch()
266 }
267}
268
269pub trait ChannelClocks {
270 fn get_clk_frequency(clocks: &rcc::Clocks) -> Option<Hertz>;
271}
272
273pub trait Channel: ChannelClocks {
274 fn set_master_tx(&self);
275 fn set_master_rx(&self);
276 fn set_slave_tx(&self);
277 fn set_slave_rx(&self);
278
279 fn is_slave(&self) -> bool;
280 fn set_clock_gen(&self, sample_freq: Hertz, clocks: &rcc::Clocks);
281 fn set_protocol(&self, protocol: Protocol, tx: bool);
282
283 fn start(&self);
284 fn stop(&self);
285
286 fn fifo_full(&self) -> bool;
287 fn fifo_empty(&self) -> bool;
288
289 fn write(&self, word: u32);
290 fn read(&self) -> u32;
291
292 }
297
298#[cfg(not(feature = "sai2"))]
299impl<SAI, const C: bool> ChannelClocks for SAICH<SAI, C> {
300 fn get_clk_frequency(clocks: &rcc::Clocks) -> Option<Hertz> {
301 if C {
302 clocks.saib_clk()
303 } else {
304 clocks.saia_clk()
305 }
306 }
307}
308
309#[cfg(feature = "sai2")]
310impl<const C: bool> ChannelClocks for SAICH<SAI1, C> {
311 fn get_clk_frequency(clocks: &rcc::Clocks) -> Option<Hertz> {
312 clocks.sai1_clk()
313 }
314}
315
316#[cfg(feature = "sai2")]
317impl<const C: bool> ChannelClocks for SAICH<SAI2, C> {
318 fn get_clk_frequency(clocks: &rcc::Clocks) -> Option<Hertz> {
319 clocks.sai2_clk()
320 }
321}
322
323impl<Ch> Channel for Ch
324where
325 Ch: Deref<Target = sai::CH> + ChannelClocks,
326{
327 fn set_master_tx(&self) {
328 self.cr1().modify(|_, w| w.mode().master_tx());
329 }
330
331 fn set_master_rx(&self) {
332 self.cr1().modify(|_, w| w.mode().master_rx());
333 }
334
335 fn set_slave_tx(&self) {
336 self.cr1().modify(|_, w| w.mode().slave_tx());
337 }
338
339 fn set_slave_rx(&self) {
340 self.cr1().modify(|_, w| w.mode().slave_rx());
341 }
342
343 fn is_slave(&self) -> bool {
344 let mode = self.cr1().read().mode();
345 mode.is_slave_tx() || mode.is_slave_rx()
346 }
347
348 fn set_clock_gen(&self, sample_freq: Hertz, clocks: &rcc::Clocks) {
349 let mclk = sample_freq.raw() * 256;
350 let sai_clock = Self::get_clk_frequency(clocks)
351 .expect("no SAI clock available")
352 .raw();
353 if (sai_clock + (mclk >> 1)) / mclk == 1 {
354 self.cr1().modify(|_, w| unsafe { w.mckdiv().bits(0) });
355 } else {
356 let best_divider = (sai_clock + mclk) / (mclk << 1);
357 assert!(best_divider < 16);
358 self.cr1()
359 .modify(|_, w| unsafe { w.mckdiv().bits(best_divider as u8) });
360 }
361 }
362
363 fn set_protocol(&self, protocol: Protocol, tx: bool) {
364 let pcm = match protocol.sync {
367 Synchronization::I2S => false,
368 Synchronization::MSBJustified => false,
369 Synchronization::LSBJustified => false,
370 Synchronization::PCMLongFrame => true,
371 Synchronization::PCMShortFrame => true,
372 };
373 if !pcm && protocol.num_slots != 2 {
374 panic!("only stereo I2S supported");
375 }
376 assert!(protocol.num_slots > 0);
377 let word_size = word_size(protocol.word_size);
378 let slot_size = slot_size(protocol.slot_size, word_size);
379 assert!(slot_size >= word_size, "slot size smaller than word size");
380 self.cr1().modify(|_, w| {
381 w.ds().variant(protocol.word_size);
382 if (pcm && tx) || (!pcm && !tx) {
383 w.ckstr().rising_edge()
384 } else {
385 w.ckstr().falling_edge()
386 }
387 });
388 self.frcr().modify(|_, w| {
389 match protocol.sync {
390 Synchronization::PCMShortFrame => w.fsoff().before_first(),
391 _ => w.fsoff().on_first(),
392 };
393 if pcm {
394 w.fspol().rising_edge();
395 w.fsdef().clear_bit();
396 unsafe {
397 match protocol.sync {
399 Synchronization::PCMShortFrame => w.fsall().bits(0),
400 Synchronization::PCMLongFrame => w.fsall().bits(12),
401 _ => unreachable!(),
402 };
403 w.frl().bits((slot_size * protocol.num_slots) - 1);
404 }
405 } else {
406 w.fspol().falling_edge();
407 w.fsdef().set_bit();
408 unsafe {
409 w.fsall().bits(slot_size - 1);
410 w.frl().bits((slot_size << 1) - 1);
411 }
412 }
413 w
414 });
415 self.slotr().modify(|_, w| unsafe {
416 if pcm {
417 w.sloten().bits((1 << protocol.num_slots as u32) - 1);
418 w.nbslot().bits(protocol.num_slots - 1);
419 } else {
420 w.sloten().bits(0x3);
421 w.nbslot().bits(1);
422 }
423 w.slotsz().variant(protocol.slot_size);
424 match protocol.sync {
425 Synchronization::LSBJustified => w.fboff().bits(slot_size - word_size),
426 _ => w.fboff().bits(0),
427 };
428 w
429 });
430 }
431
432 fn start(&self) {
433 self.clrfr().write(|w| {
434 w.clfsdet().set_bit();
435 w.cafsdet().set_bit();
436 w.ccnrdy().set_bit();
437 w.cwckcfg().set_bit();
438 w.cmutedet().set_bit();
439 w.covrudr().set_bit();
440 w
441 });
442 self.cr2().modify(|_, w| w.fflush().flush());
443 self.cr1().modify(|_, w| w.saien().enabled());
444 }
445
446 fn stop(&self) {
447 self.cr1().modify(|_, w| w.saien().disabled());
448 while self.cr1().read().saien().bit_is_set() {}
449 }
450
451 fn fifo_full(&self) -> bool {
452 let sr = self.sr().read();
454 sr.flvl().is_full() || sr.flvl().is_quarter4()
455 }
456 fn fifo_empty(&self) -> bool {
457 let sr = self.sr().read();
459 sr.flvl().is_empty() || sr.flvl().is_quarter1()
460 }
461
462 fn write(&self, word: u32) {
463 self.dr().write(|w| unsafe { w.data().bits(word) });
464 }
465 fn read(&self) -> u32 {
466 self.dr().read().data().bits()
467 }
468}
469
470pub struct SubBlock<Channel, Config, Direction = NoDir> {
472 channel: Channel,
473 #[allow(unused)]
474 config: Config,
475 #[allow(unused)]
476 direction: Direction,
477}
478
479pub trait SAIExt
484where
485 Self: Instance,
486{
487 fn split(
489 self,
490 rcc: &mut RCC,
491 ) -> (
492 SubBlock<SAIA<Self>, Asynchronous>,
493 SubBlock<SAIB<Self>, Asynchronous>,
494 )
495 where
496 Self: Sized;
497
498 fn split_sync_a(
501 self,
502 rcc: &mut RCC,
503 ) -> (
504 SubBlock<SAIA<Self>, Synchronous>,
505 SubBlock<SAIB<Self>, Asynchronous>,
506 )
507 where
508 Self: Sized;
509
510 fn split_sync_b(
513 self,
514 rcc: &mut RCC,
515 ) -> (
516 SubBlock<SAIA<Self>, Asynchronous>,
517 SubBlock<SAIB<Self>, Synchronous>,
518 )
519 where
520 Self: Sized;
521
522 }
527
528impl<SAI> SAIExt for SAI
529where
530 SAI: Instance,
531{
532 fn split(
533 self,
534 rcc: &mut RCC,
535 ) -> (
536 SubBlock<SAIA<Self>, Asynchronous>,
537 SubBlock<SAIB<Self>, Asynchronous>,
538 )
539 where
540 Self: Sized,
541 {
542 SAI::enable(rcc);
543 SAI::reset(rcc);
544 (
545 SubBlock {
546 channel: SAIA::new(self),
547 config: Asynchronous,
548 direction: NoDir,
549 },
550 SubBlock {
551 channel: SAIB::new_steal(),
552 config: Asynchronous,
553 direction: NoDir,
554 },
555 )
556 }
557
558 fn split_sync_a(
559 self,
560 rcc: &mut RCC,
561 ) -> (
562 SubBlock<SAIA<Self>, Synchronous>,
563 SubBlock<SAIB<Self>, Asynchronous>,
564 )
565 where
566 Self: Sized,
567 {
568 SAI::enable(rcc);
569 SAI::reset(rcc);
570 (
571 SubBlock {
572 channel: SAIA::new(self),
573 config: Synchronous,
574 direction: NoDir,
575 },
576 SubBlock {
577 channel: SAIB::new_steal(),
578 config: Asynchronous,
579 direction: NoDir,
580 },
581 )
582 }
583
584 fn split_sync_b(
585 self,
586 rcc: &mut RCC,
587 ) -> (
588 SubBlock<SAIA<Self>, Asynchronous>,
589 SubBlock<SAIB<Self>, Synchronous>,
590 )
591 where
592 Self: Sized,
593 {
594 SAI::enable(rcc);
595 SAI::reset(rcc);
596 (
597 SubBlock {
598 channel: SAIA::new(self),
599 config: Asynchronous,
600 direction: NoDir,
601 },
602 SubBlock {
603 channel: SAIB::new_steal(),
604 config: Synchronous,
605 direction: NoDir,
606 },
607 )
608 }
609
610 }
614
615impl<Ch> SubBlock<Ch, Asynchronous>
616where
617 Ch: Channel + SaiChannel,
618{
619 pub fn master_rx(
621 self,
622 pins: (
623 Option<impl Into<Ch::Mclk>>,
624 impl Into<Ch::Fs>,
625 impl Into<Ch::Sck>,
626 impl Into<Ch::Sd>,
627 ),
628 protocol: Protocol,
629 sample_freq: impl Into<Hertz>,
630 clocks: &rcc::Clocks,
631 ) -> SubBlock<Ch, AsyncMaster<Ch>, Receive> {
632 self.channel.set_clock_gen(sample_freq.into(), clocks);
633 self.channel.set_master_rx();
634 self.channel.set_protocol(protocol, false);
635
636 SubBlock {
637 channel: self.channel,
638 config: AsyncMaster::new(pins),
639 direction: Receive,
640 }
641 }
642
643 pub fn master_tx(
645 self,
646 pins: (
647 Option<impl Into<Ch::Mclk>>,
648 impl Into<Ch::Fs>,
649 impl Into<Ch::Sck>,
650 impl Into<Ch::Sd>,
651 ),
652 protocol: Protocol,
653 sample_freq: impl Into<Hertz>,
654 clocks: &rcc::Clocks,
655 ) -> SubBlock<Ch, AsyncMaster<Ch>, Transmit> {
656 self.channel.set_clock_gen(sample_freq.into(), clocks);
657 self.channel.set_master_tx();
658 self.channel.set_protocol(protocol, true);
659
660 SubBlock {
661 channel: self.channel,
662 config: AsyncMaster::new(pins),
663 direction: Transmit,
664 }
665 }
666
667 pub fn slave_rx(
669 self,
670 pins: (
671 Option<impl Into<Ch::Mclk>>,
672 impl Into<Ch::Fs>,
673 impl Into<Ch::Sck>,
674 impl Into<Ch::Sd>,
675 ),
676 protocol: Protocol,
677 ) -> SubBlock<Ch, AsyncSlave<Ch>, Receive> {
678 self.channel.set_slave_rx();
679 self.channel.set_protocol(protocol, false);
680
681 SubBlock {
682 channel: self.channel,
683 config: AsyncSlave::new(pins),
684 direction: Receive,
685 }
686 }
687
688 pub fn slave_tx(
690 self,
691 pins: (
692 Option<impl Into<Ch::Mclk>>,
693 impl Into<Ch::Fs>,
694 impl Into<Ch::Sck>,
695 impl Into<Ch::Sd>,
696 ),
697 protocol: Protocol,
698 ) -> SubBlock<Ch, AsyncSlave<Ch>, Transmit> {
699 self.channel.set_slave_tx();
700 self.channel.set_protocol(protocol, true);
701
702 SubBlock {
703 channel: self.channel,
704 config: AsyncSlave::new(pins),
705 direction: Transmit,
706 }
707 }
708}
709
710impl<Ch> SubBlock<Ch, Synchronous>
711where
712 Ch: Channel + SaiChannel,
713{
714 pub fn slave_rx(
716 self,
717 sd: impl Into<Ch::Sd>,
718 protocol: Protocol,
719 ) -> SubBlock<Ch, SyncSlave<Ch>, Receive> {
720 self.channel.set_slave_rx();
721 self.channel.set_protocol(protocol, false);
722
723 SubBlock {
724 channel: self.channel,
725 config: SyncSlave::new(sd),
726 direction: Receive,
727 }
728 }
729
730 pub fn slave_tx(
732 self,
733 sd: impl Into<Ch::Sd>,
734 protocol: Protocol,
735 ) -> SubBlock<Ch, SyncSlave<Ch>, Transmit> {
736 self.channel.set_slave_tx();
737 self.channel.set_protocol(protocol, true);
738
739 SubBlock {
740 channel: self.channel,
741 config: SyncSlave::new(sd),
742 direction: Transmit,
743 }
744 }
745}
746
747impl<Ch, Config> SubBlock<Ch, Config, Receive>
748where
749 Ch: Channel,
750{
751 pub fn start(&mut self) {
752 self.channel.start();
753 }
754
755 pub fn stop(&mut self) {
756 self.channel.stop();
757 }
758
759 pub fn try_read(&mut self) -> nb::Result<(u32, u32), ()> {
762 if !self.channel.fifo_empty() {
763 Ok((self.channel.read(), self.channel.read()))
765 } else {
766 Err(nb::Error::WouldBlock)
767 }
768 }
769}
770
771impl<Ch, Config> SubBlock<Ch, Config, Transmit>
772where
773 Ch: Channel,
774{
775 pub fn start(&mut self) {
776 self.channel.start();
777 }
778
779 pub fn stop(&mut self) {
780 self.channel.stop();
781 }
782
783 pub fn try_send(&mut self, left: u32, right: u32) -> nb::Result<(), ()> {
786 if !self.channel.fifo_full() {
787 self.channel.write(left);
789 self.channel.write(right);
790 Ok(())
791 } else {
792 Err(nb::Error::WouldBlock)
793 }
794 }
795}
796
797pub struct Duplex<Ch1, Config1, Ch2, Config2> {
799 rx: SubBlock<Ch1, Config1, Receive>,
800 tx: SubBlock<Ch2, Config2, Transmit>,
801}
802
803impl<Ch1, Config1, Ch2, Config2> Duplex<Ch1, Config1, Ch2, Config2>
804where
805 Ch1: Channel,
806 Ch2: Channel,
807{
808 pub fn new(rx: SubBlock<Ch1, Config1, Receive>, tx: SubBlock<Ch2, Config2, Transmit>) -> Self {
810 Self { rx, tx }
811 }
812
813 pub fn start(&mut self) {
814 if self.rx.channel.is_slave() {
817 self.rx.start();
818 }
819 if self.tx.channel.is_slave() {
820 self.tx.start();
821 }
822 if !self.rx.channel.is_slave() {
823 self.rx.start();
824 }
825 if !self.tx.channel.is_slave() {
826 self.tx.start();
827 }
828 }
829
830 pub fn stop(&mut self) {
831 self.rx.stop();
832 self.tx.stop();
833 }
834
835 pub fn try_read(&mut self) -> nb::Result<(u32, u32), ()> {
836 self.rx.try_read()
837 }
838
839 pub fn try_send(&mut self, left: u32, right: u32) -> nb::Result<(), ()> {
840 self.tx.try_send(left, right)
841 }
842
843 }
845
846unsafe impl<SAI: Instance, const C: bool> crate::dma::traits::PeriAddress for SAICH<SAI, C> {
847 #[inline(always)]
848 fn address(&self) -> u32 {
849 self.ch().dr().as_ptr() as u32
850 }
851
852 type MemSize = u32;
853}