aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/sai/mod.rs888
1 files changed, 888 insertions, 0 deletions
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
new file mode 100644
index 000000000..1fcee226d
--- /dev/null
+++ b/embassy-stm32/src/sai/mod.rs
@@ -0,0 +1,888 @@
1#![macro_use]
2
3use embassy_embedded_hal::SetConfig;
4use embassy_hal_internal::{into_ref, PeripheralRef};
5
6use crate::dma::{Channel, ReadableRingBuffer, TransferOptions, WritableRingBuffer};
7use crate::gpio::sealed::{AFType, Pin as _};
8use crate::gpio::AnyPin;
9use crate::pac::sai::{vals, Sai as Regs};
10use crate::rcc::RccPeripheral;
11use crate::time::Hertz;
12use crate::{peripherals, Peripheral};
13
14pub use crate::dma::word;
15
16#[derive(Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error {
19 NotATransmitter,
20 NotAReceiver,
21}
22
23#[derive(Copy, Clone)]
24pub enum SyncBlock {
25 None,
26 Sai1BlockA,
27 Sai1BlockB,
28 Sai2BlockA,
29 Sai2BlockB,
30}
31
32#[derive(Copy, Clone)]
33pub enum SyncIn {
34 None,
35 ChannelZero,
36 ChannelOne,
37}
38
39#[derive(Copy, Clone)]
40pub enum Mode {
41 Master,
42 Slave,
43}
44
45#[derive(Copy, Clone)]
46enum TxRx {
47 Transmiter,
48 Receiver,
49}
50
51impl Mode {
52 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
53 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
54 match tx_rx {
55 TxRx::Transmiter => match self {
56 Mode::Master => vals::Mode::MASTERTX,
57 Mode::Slave => vals::Mode::SLAVETX,
58 },
59 TxRx::Receiver => match self {
60 Mode::Master => vals::Mode::MASTERRX,
61 Mode::Slave => vals::Mode::SLAVERX,
62 },
63 }
64 }
65}
66
67#[derive(Copy, Clone)]
68pub enum SlotSize {
69 DataSize,
70 /// 16 bit data length on 16 bit wide channel
71 Channel16,
72 /// 16 bit data length on 32 bit wide channel
73 Channel32,
74}
75
76impl SlotSize {
77 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
78 pub const fn slotsz(&self) -> vals::Slotsz {
79 match self {
80 SlotSize::DataSize => vals::Slotsz::DATASIZE,
81 SlotSize::Channel16 => vals::Slotsz::BIT16,
82 SlotSize::Channel32 => vals::Slotsz::BIT32,
83 }
84 }
85}
86
87#[derive(Copy, Clone)]
88pub enum DataSize {
89 Data8,
90 Data10,
91 Data16,
92 Data20,
93 Data24,
94 Data32,
95}
96
97impl DataSize {
98 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
99 pub const fn ds(&self) -> vals::Ds {
100 match self {
101 DataSize::Data8 => vals::Ds::BIT8,
102 DataSize::Data10 => vals::Ds::BIT10,
103 DataSize::Data16 => vals::Ds::BIT16,
104 DataSize::Data20 => vals::Ds::BIT20,
105 DataSize::Data24 => vals::Ds::BIT24,
106 DataSize::Data32 => vals::Ds::BIT32,
107 }
108 }
109}
110
111#[derive(Copy, Clone)]
112pub enum FifoThreshold {
113 Empty,
114 Quarter,
115 Half,
116 ThreeQuarters,
117 Full,
118}
119
120impl FifoThreshold {
121 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
122 pub const fn fth(&self) -> vals::Fth {
123 match self {
124 FifoThreshold::Empty => vals::Fth::EMPTY,
125 FifoThreshold::Quarter => vals::Fth::QUARTER1,
126 FifoThreshold::Half => vals::Fth::QUARTER2,
127 FifoThreshold::ThreeQuarters => vals::Fth::QUARTER3,
128 FifoThreshold::Full => vals::Fth::FULL,
129 }
130 }
131}
132
133#[derive(Copy, Clone)]
134pub enum FifoLevel {
135 Empty,
136 FirstQuarter,
137 SecondQuarter,
138 ThirdQuarter,
139 FourthQuarter,
140 Full,
141}
142
143#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
144impl From<vals::Flvl> for FifoLevel {
145 fn from(flvl: vals::Flvl) -> Self {
146 match flvl {
147 vals::Flvl::EMPTY => FifoLevel::Empty,
148 vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter,
149 vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter,
150 vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter,
151 vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter,
152 vals::Flvl::FULL => FifoLevel::Full,
153 _ => FifoLevel::Empty,
154 }
155 }
156}
157
158#[derive(Copy, Clone)]
159pub enum MuteDetection {
160 NoMute,
161 Mute,
162}
163
164#[derive(Copy, Clone)]
165pub enum MuteValue {
166 Zero,
167 LastValue,
168}
169
170impl MuteValue {
171 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
172 pub const fn muteval(&self) -> vals::Muteval {
173 match self {
174 MuteValue::Zero => vals::Muteval::SENDZERO,
175 MuteValue::LastValue => vals::Muteval::SENDLAST,
176 }
177 }
178}
179
180#[derive(Copy, Clone)]
181pub enum OverUnderStatus {
182 NoError,
183 OverUnderRunDetected,
184}
185
186#[derive(Copy, Clone)]
187pub enum Protocol {
188 Free,
189 Spdif,
190 Ac97,
191}
192
193impl Protocol {
194 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
195 pub const fn prtcfg(&self) -> vals::Prtcfg {
196 match self {
197 Protocol::Free => vals::Prtcfg::FREE,
198 Protocol::Spdif => vals::Prtcfg::SPDIF,
199 Protocol::Ac97 => vals::Prtcfg::AC97,
200 }
201 }
202}
203
204#[derive(Copy, Clone)]
205pub enum SyncEnable {
206 Asynchronous,
207 /// Syncs with the other A/B sub-block within the SAI unit
208 Internal,
209 /// Syncs with a sub-block in the other SAI unit - use set_sync_output() and set_sync_input()
210 External,
211}
212
213impl SyncEnable {
214 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
215 pub const fn syncen(&self) -> vals::Syncen {
216 match self {
217 SyncEnable::Asynchronous => vals::Syncen::ASYNCHRONOUS,
218 SyncEnable::Internal => vals::Syncen::INTERNAL,
219 SyncEnable::External => vals::Syncen::EXTERNAL,
220 }
221 }
222}
223
224#[derive(Copy, Clone, PartialEq)]
225pub enum StereoMono {
226 Stereo,
227 Mono,
228}
229
230impl StereoMono {
231 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
232 pub const fn mono(&self) -> vals::Mono {
233 match self {
234 StereoMono::Stereo => vals::Mono::STEREO,
235 StereoMono::Mono => vals::Mono::MONO,
236 }
237 }
238}
239
240#[derive(Copy, Clone)]
241pub enum BitOrder {
242 LsbFirst,
243 MsbFirst,
244}
245
246impl BitOrder {
247 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
248 pub const fn lsbfirst(&self) -> vals::Lsbfirst {
249 match self {
250 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
251 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
252 }
253 }
254}
255
256#[derive(Copy, Clone)]
257pub enum FrameSyncOffset {
258 /// This is used in modes other than standard I2S phillips mode
259 OnFirstBit,
260 /// This is used in standard I2S phillips mode
261 BeforeFirstBit,
262}
263
264impl FrameSyncOffset {
265 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
266 pub const fn fsoff(&self) -> vals::Fsoff {
267 match self {
268 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
269 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST,
270 }
271 }
272}
273
274#[derive(Copy, Clone)]
275pub enum FrameSyncPolarity {
276 ActiveLow,
277 ActiveHigh,
278}
279
280impl FrameSyncPolarity {
281 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
282 pub const fn fspol(&self) -> vals::Fspol {
283 match self {
284 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
285 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE,
286 }
287 }
288}
289
290#[derive(Copy, Clone)]
291pub enum FrameSyncDefinition {
292 StartOfFrame,
293 ChannelIdentification,
294}
295
296impl FrameSyncDefinition {
297 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
298 pub const fn fsdef(&self) -> bool {
299 match self {
300 FrameSyncDefinition::StartOfFrame => false,
301 FrameSyncDefinition::ChannelIdentification => true,
302 }
303 }
304}
305
306#[derive(Copy, Clone)]
307pub enum ClockStrobe {
308 Falling,
309 Rising,
310}
311
312impl ClockStrobe {
313 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
314 pub const fn ckstr(&self) -> vals::Ckstr {
315 match self {
316 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
317 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE,
318 }
319 }
320}
321
322#[derive(Copy, Clone)]
323pub enum ComplementFormat {
324 OnesComplement,
325 TwosComplement,
326}
327
328impl ComplementFormat {
329 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
330 pub const fn cpl(&self) -> vals::Cpl {
331 match self {
332 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
333 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT,
334 }
335 }
336}
337
338#[derive(Copy, Clone)]
339pub enum Companding {
340 None,
341 MuLaw,
342 ALaw,
343}
344
345impl Companding {
346 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
347 pub const fn comp(&self) -> vals::Comp {
348 match self {
349 Companding::None => vals::Comp::NOCOMPANDING,
350 Companding::MuLaw => vals::Comp::MULAW,
351 Companding::ALaw => vals::Comp::ALAW,
352 }
353 }
354}
355
356#[derive(Copy, Clone)]
357pub enum OutputDrive {
358 OnStart,
359 Immediately,
360}
361
362impl OutputDrive {
363 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
364 pub const fn outdriv(&self) -> vals::Outdriv {
365 match self {
366 OutputDrive::OnStart => vals::Outdriv::ONSTART,
367 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
368 }
369 }
370}
371
372#[derive(Copy, Clone, PartialEq)]
373pub enum MasterClockDivider {
374 MasterClockDisabled,
375 Div1,
376 Div2,
377 Div4,
378 Div6,
379 Div8,
380 Div10,
381 Div12,
382 Div14,
383 Div16,
384 Div18,
385 Div20,
386 Div22,
387 Div24,
388 Div26,
389 Div28,
390 Div30,
391}
392
393impl MasterClockDivider {
394 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
395 pub const fn mckdiv(&self) -> u8 {
396 match self {
397 MasterClockDivider::MasterClockDisabled => 0,
398 MasterClockDivider::Div1 => 0,
399 MasterClockDivider::Div2 => 1,
400 MasterClockDivider::Div4 => 2,
401 MasterClockDivider::Div6 => 3,
402 MasterClockDivider::Div8 => 4,
403 MasterClockDivider::Div10 => 5,
404 MasterClockDivider::Div12 => 6,
405 MasterClockDivider::Div14 => 7,
406 MasterClockDivider::Div16 => 8,
407 MasterClockDivider::Div18 => 9,
408 MasterClockDivider::Div20 => 10,
409 MasterClockDivider::Div22 => 11,
410 MasterClockDivider::Div24 => 12,
411 MasterClockDivider::Div26 => 13,
412 MasterClockDivider::Div28 => 14,
413 MasterClockDivider::Div30 => 15,
414 }
415 }
416}
417
418/// [`SAI`] configuration.
419#[non_exhaustive]
420#[derive(Copy, Clone)]
421pub struct Config {
422 pub mode: Mode,
423 pub sync_enable: SyncEnable,
424 pub is_sync_output: bool,
425 pub protocol: Protocol,
426 pub slot_size: SlotSize,
427 pub slot_count: word::U4,
428 pub slot_enable: u16,
429 pub first_bit_offset: word::U5,
430 pub data_size: DataSize,
431 pub stereo_mono: StereoMono,
432 pub bit_order: BitOrder,
433 pub frame_sync_offset: FrameSyncOffset,
434 pub frame_sync_polarity: FrameSyncPolarity,
435 pub frame_sync_active_level_length: word::U7,
436 pub frame_sync_definition: FrameSyncDefinition,
437 pub frame_length: u8,
438 pub clock_strobe: ClockStrobe,
439 pub output_drive: OutputDrive,
440 pub master_clock_divider: MasterClockDivider,
441 pub is_high_impedenane_on_inactive_slot: bool,
442 pub fifo_threshold: FifoThreshold,
443 pub companding: Companding,
444 pub complement_format: ComplementFormat,
445 pub mute_value: MuteValue,
446 pub mute_detection_counter: word::U5,
447}
448
449impl Default for Config {
450 fn default() -> Self {
451 Self {
452 mode: Mode::Master,
453 is_sync_output: false,
454 sync_enable: SyncEnable::Asynchronous,
455 protocol: Protocol::Free,
456 slot_size: SlotSize::DataSize,
457 slot_count: word::U4(2),
458 first_bit_offset: word::U5(0),
459 slot_enable: 0b11,
460 data_size: DataSize::Data16,
461 stereo_mono: StereoMono::Stereo,
462 bit_order: BitOrder::LsbFirst,
463 frame_sync_offset: FrameSyncOffset::BeforeFirstBit,
464 frame_sync_polarity: FrameSyncPolarity::ActiveLow,
465 frame_sync_active_level_length: word::U7(16),
466 frame_sync_definition: FrameSyncDefinition::ChannelIdentification,
467 frame_length: 32,
468 master_clock_divider: MasterClockDivider::MasterClockDisabled,
469 clock_strobe: ClockStrobe::Rising,
470 output_drive: OutputDrive::Immediately,
471 is_high_impedenane_on_inactive_slot: false,
472 fifo_threshold: FifoThreshold::ThreeQuarters,
473 companding: Companding::None,
474 complement_format: ComplementFormat::TwosComplement,
475 mute_value: MuteValue::Zero,
476 mute_detection_counter: word::U5(4),
477 }
478 }
479}
480
481impl Config {
482 pub fn new_i2s() -> Self {
483 return Default::default();
484 }
485
486 pub fn new_msb_first() -> Self {
487 Self {
488 bit_order: BitOrder::MsbFirst,
489 frame_sync_offset: FrameSyncOffset::OnFirstBit,
490 ..Default::default()
491 }
492 }
493}
494
495#[derive(Copy, Clone)]
496pub enum SubBlock {
497 A = 0,
498 B = 1,
499}
500
501enum RingBuffer<'d, C: Channel, W: word::Word> {
502 Writable(WritableRingBuffer<'d, C, W>),
503 Readable(ReadableRingBuffer<'d, C, W>),
504}
505
506#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
507fn wdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W {
508 let ch = w.ch(sub_block as usize);
509 ch.dr().as_ptr() as _
510}
511
512pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
513 _peri: PeripheralRef<'d, T>,
514 sd: Option<PeripheralRef<'d, AnyPin>>,
515 fs: Option<PeripheralRef<'d, AnyPin>>,
516 sck: Option<PeripheralRef<'d, AnyPin>>,
517 mclk: Option<PeripheralRef<'d, AnyPin>>,
518 ring_buffer: RingBuffer<'d, C, W>,
519 sub_block: SubBlock,
520}
521
522impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
523 fn get_transmitter_af_types(mode: Mode) -> (AFType, AFType) {
524 match mode {
525 Mode::Master => (AFType::OutputPushPull, AFType::OutputPushPull),
526 Mode::Slave => (AFType::OutputPushPull, AFType::Input),
527 }
528 }
529
530 pub fn new_asynchronous_transmitter_with_mclk_a(
531 peri: impl Peripheral<P = T> + 'd,
532 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
533 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
534 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
535 mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
536 dma: impl Peripheral<P = C> + 'd,
537 dma_buf: &'d mut [W],
538 mut config: Config,
539 ) -> Self
540 where
541 C: Channel + DmaA<T>,
542 {
543 into_ref!(mclk);
544
545 mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull);
546 mclk.set_speed(crate::gpio::Speed::VeryHigh);
547
548 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
549 config.master_clock_divider = MasterClockDivider::Div1;
550 }
551
552 Self::new_asynchronous_transmitter_a(peri, sck, sd, fs, dma, dma_buf, config)
553 }
554
555 pub fn new_asynchronous_transmitter_a(
556 peri: impl Peripheral<P = T> + 'd,
557 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
558 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
559 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
560 dma: impl Peripheral<P = C> + 'd,
561 dma_buf: &'d mut [W],
562 config: Config,
563 ) -> Self
564 where
565 C: Channel + DmaA<T>,
566 {
567 into_ref!(peri, dma, sck, sd, fs);
568
569 let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode);
570 sd.set_as_af(sd.af_num(), sd_af_type);
571 sd.set_speed(crate::gpio::Speed::VeryHigh);
572
573 sck.set_as_af(sck.af_num(), ck_af_type);
574 sck.set_speed(crate::gpio::Speed::VeryHigh);
575 fs.set_as_af(fs.af_num(), ck_af_type);
576 fs.set_speed(crate::gpio::Speed::VeryHigh);
577
578 let request = dma.request();
579 let opts = TransferOptions {
580 half_transfer_ir: true,
581 circular: true,
582 ..Default::default()
583 };
584
585 let sub_block = SubBlock::A;
586
587 Self::new_inner(
588 peri,
589 sub_block,
590 Some(sck.map_into()),
591 None,
592 Some(sd.map_into()),
593 Some(fs.map_into()),
594 RingBuffer::Writable(unsafe {
595 WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
596 }),
597 config,
598 )
599 }
600
601 pub fn new_asynchronous_transmitter_with_mclk_b(
602 peri: impl Peripheral<P = T> + 'd,
603 sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
604 sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
605 fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
606 mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd,
607 dma: impl Peripheral<P = C> + 'd,
608 dma_buf: &'d mut [W],
609 mut config: Config,
610 ) -> Self
611 where
612 C: Channel + DmaB<T>,
613 {
614 into_ref!(mclk);
615
616 mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull);
617 mclk.set_speed(crate::gpio::Speed::VeryHigh);
618
619 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
620 config.master_clock_divider = MasterClockDivider::Div1;
621 }
622
623 Self::new_asynchronous_transmitter_b(peri, sck, sd, fs, dma, dma_buf, config)
624 }
625
626 pub fn new_asynchronous_transmitter_b(
627 peri: impl Peripheral<P = T> + 'd,
628 sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
629 sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
630 fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
631 dma: impl Peripheral<P = C> + 'd,
632 dma_buf: &'d mut [W],
633 config: Config,
634 ) -> Self
635 where
636 C: Channel + DmaB<T>,
637 {
638 into_ref!(dma, peri, sck, sd, fs);
639
640 let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode);
641
642 sd.set_as_af(sd.af_num(), sd_af_type);
643 sd.set_speed(crate::gpio::Speed::VeryHigh);
644
645 sck.set_as_af(sck.af_num(), ck_af_type);
646 sck.set_speed(crate::gpio::Speed::VeryHigh);
647 fs.set_as_af(fs.af_num(), ck_af_type);
648 fs.set_speed(crate::gpio::Speed::VeryHigh);
649
650 let request = dma.request();
651 let opts = TransferOptions {
652 half_transfer_ir: true,
653 ..Default::default()
654 };
655
656 let sub_block = SubBlock::B;
657
658 Self::new_inner(
659 peri,
660 sub_block,
661 Some(sck.map_into()),
662 None,
663 Some(sd.map_into()),
664 Some(fs.map_into()),
665 RingBuffer::Writable(unsafe {
666 WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
667 }),
668 config,
669 )
670 }
671
672 pub fn start(self: &mut Self) {
673 match self.ring_buffer {
674 RingBuffer::Writable(ref mut rb) => {
675 rb.start();
676 }
677 RingBuffer::Readable(ref mut rb) => {
678 rb.start();
679 }
680 }
681 }
682
683 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
684 match ring_buffer {
685 RingBuffer::Writable(_) => true,
686 _ => false,
687 }
688 }
689
690 fn new_inner(
691 peri: impl Peripheral<P = T> + 'd,
692 sub_block: SubBlock,
693 sck: Option<PeripheralRef<'d, AnyPin>>,
694 mclk: Option<PeripheralRef<'d, AnyPin>>,
695 sd: Option<PeripheralRef<'d, AnyPin>>,
696 fs: Option<PeripheralRef<'d, AnyPin>>,
697 ring_buffer: RingBuffer<'d, C, W>,
698 config: Config,
699 ) -> Self {
700 T::enable();
701 T::reset();
702
703 #[cfg(any(sai_v4))]
704 {
705 /// Not totally clear from the datasheet if this is right
706 /// This is only used if using SyncEnable::External
707 let value: u8 = if T::REGS.as_ptr() == stm32_metapac::SAI1.as_ptr() {
708 1 //this is SAI1, so sync with SAI2
709 } else {
710 0 //this is SAI2, so sync with SAI1
711 };
712 T::REGS.gcr().modify(|w| {
713 w.set_syncin(value);
714 });
715
716 if config.is_sync_output {
717 let syncout: u8 = match sub_block {
718 SubBlock::A => 0b01,
719 SubBlock::B => 0b10,
720 };
721 T::REGS.gcr().modify(|w| {
722 w.set_syncout(syncout);
723 });
724 }
725 }
726
727 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
728 {
729 let ch = T::REGS.ch(sub_block as usize);
730 ch.cr1().modify(|w| {
731 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
732 TxRx::Transmiter
733 } else {
734 TxRx::Receiver
735 }));
736 w.set_prtcfg(config.protocol.prtcfg());
737 w.set_ds(config.data_size.ds());
738 w.set_lsbfirst(config.bit_order.lsbfirst());
739 w.set_ckstr(config.clock_strobe.ckstr());
740 w.set_syncen(config.sync_enable.syncen());
741 w.set_mono(config.stereo_mono.mono());
742 w.set_outdriv(config.output_drive.outdriv());
743 w.set_mckdiv(config.master_clock_divider.mckdiv());
744 w.set_nodiv(
745 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
746 vals::Nodiv::NODIV
747 } else {
748 vals::Nodiv::MASTERCLOCK
749 },
750 );
751 w.set_dmaen(true);
752 });
753
754 ch.cr2().modify(|w| {
755 w.set_fth(config.fifo_threshold.fth());
756 w.set_comp(config.companding.comp());
757 w.set_cpl(config.complement_format.cpl());
758 w.set_muteval(config.mute_value.muteval());
759 w.set_mutecnt(config.mute_detection_counter.0 as u8);
760 w.set_tris(config.is_high_impedenane_on_inactive_slot);
761 });
762
763 ch.frcr().modify(|w| {
764 w.set_fsoff(config.frame_sync_offset.fsoff());
765 w.set_fspol(config.frame_sync_polarity.fspol());
766 w.set_fsdef(config.frame_sync_definition.fsdef());
767 w.set_fsall(config.frame_sync_active_level_length.0 as u8);
768 w.set_frl(config.frame_length - 1);
769 });
770
771 ch.slotr().modify(|w| {
772 w.set_nbslot(config.slot_count.0 as u8 - 1);
773 w.set_slotsz(config.slot_size.slotsz());
774 w.set_fboff(config.first_bit_offset.0 as u8);
775 w.set_sloten(vals::Sloten(config.slot_enable as u16));
776 });
777
778 ch.cr1().modify(|w| w.set_saien(true));
779 }
780
781 Self {
782 _peri: peri.into_ref(),
783 sub_block,
784 sck,
785 mclk,
786 sd,
787 fs,
788 ring_buffer,
789 }
790 }
791
792 fn flush(&mut self) {
793 let ch = T::REGS.ch(self.sub_block as usize);
794 ch.cr1().modify(|w| w.set_saien(false));
795 #[cfg(any(sai_v1, sai_v2))]
796 {
797 ch.cr2().modify(|w| w.set_fflush(vals::Fflush::FLUSH));
798 }
799 #[cfg(any(sai_v3, sai_v4))]
800 {
801 ch.cr2().modify(|w| w.set_fflush(true));
802 }
803 ch.cr1().modify(|w| w.set_saien(true));
804 }
805
806 fn set_mute(&mut self, value: bool) {
807 let ch = T::REGS.ch(self.sub_block as usize);
808 ch.cr2().modify(|w| w.set_mute(value));
809 }
810
811 /// Reconfigures it with the supplied config.
812 pub fn reconfigure(&mut self, config: Config) {}
813
814 pub fn get_current_config(&self) -> Config {
815 Config::default()
816 }
817
818 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
819 match &mut self.ring_buffer {
820 RingBuffer::Writable(buffer) => {
821 buffer.write_exact(data).await;
822 Ok(())
823 }
824 _ => return Err(Error::NotATransmitter),
825 }
826 }
827
828 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
829 match &mut self.ring_buffer {
830 RingBuffer::Readable(buffer) => {
831 buffer.read_exact(data).await;
832 Ok(())
833 }
834 _ => Err(Error::NotAReceiver),
835 }
836 }
837}
838
839impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> {
840 fn drop(&mut self) {
841 let ch = T::REGS.ch(self.sub_block as usize);
842 ch.cr1().modify(|w| w.set_saien(false));
843 self.fs.as_ref().map(|x| x.set_as_disconnected());
844 self.sd.as_ref().map(|x| x.set_as_disconnected());
845 self.sck.as_ref().map(|x| x.set_as_disconnected());
846 self.mclk.as_ref().map(|x| x.set_as_disconnected());
847 }
848}
849
850pub(crate) mod sealed {
851 use super::*;
852
853 pub trait Instance {
854 const REGS: Regs;
855 }
856}
857
858pub trait Word: word::Word {}
859
860pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
861pin_trait!(SckAPin, Instance);
862pin_trait!(SckBPin, Instance);
863pin_trait!(FsAPin, Instance);
864pin_trait!(FsBPin, Instance);
865pin_trait!(SdAPin, Instance);
866pin_trait!(SdBPin, Instance);
867pin_trait!(MclkAPin, Instance);
868pin_trait!(MclkBPin, Instance);
869
870dma_trait!(DmaA, Instance);
871dma_trait!(DmaB, Instance);
872
873foreach_peripheral!(
874 (sai, $inst:ident) => {
875 impl sealed::Instance for peripherals::$inst {
876 const REGS: Regs = crate::pac::$inst;
877 }
878
879 impl Instance for peripherals::$inst {}
880 };
881);
882
883impl<'d, T: Instance, C: Channel, W: word::Word> SetConfig for Sai<'d, T, C, W> {
884 type Config = Config;
885 fn set_config(&mut self, config: &Self::Config) {
886 self.reconfigure(*config);
887 }
888}