1#![macro_use]
3#![cfg_attr(gpdma, allow(unused))]
4
5use core::marker::PhantomData;
6
7use embassy_hal_internal::PeripheralType;
8
9pub use crate::dma::word;
10#[cfg(not(gpdma))]
11use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::pac::sai::{vals, Sai as Regs};
14use crate::rcc::{self, RccPeripheral};
15use crate::{peripherals, Peri};
16
17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error {
21 NotATransmitter,
23 NotAReceiver,
25 Overrun,
27}
28
29#[cfg(not(gpdma))]
30impl From<ringbuffer::Error> for Error {
31 fn from(#[allow(unused)] err: ringbuffer::Error) -> Self {
32 #[cfg(feature = "defmt")]
33 {
34 if err == ringbuffer::Error::DmaUnsynced {
35 defmt::error!("Ringbuffer broken invariants detected!");
36 }
37 }
38 Self::Overrun
39 }
40}
41
42#[derive(Copy, Clone)]
44#[allow(missing_docs)]
45pub enum Mode {
46 Master,
47 Slave,
48}
49
50impl Mode {
51 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
52 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
53 match tx_rx {
54 TxRx::Transmitter => match self {
55 Mode::Master => vals::Mode::MASTER_TX,
56 Mode::Slave => vals::Mode::SLAVE_TX,
57 },
58 TxRx::Receiver => match self {
59 Mode::Master => vals::Mode::MASTER_RX,
60 Mode::Slave => vals::Mode::SLAVE_RX,
61 },
62 }
63 }
64}
65
66#[derive(Copy, Clone)]
68#[allow(missing_docs)]
69pub enum TxRx {
70 Transmitter,
71 Receiver,
72}
73
74#[derive(Copy, Clone)]
76#[allow(missing_docs)]
77pub enum SlotSize {
78 DataSize,
79 Channel16,
81 Channel32,
83}
84
85impl SlotSize {
86 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
87 const fn slotsz(&self) -> vals::Slotsz {
88 match self {
89 SlotSize::DataSize => vals::Slotsz::DATA_SIZE,
90 SlotSize::Channel16 => vals::Slotsz::BIT16,
91 SlotSize::Channel32 => vals::Slotsz::BIT32,
92 }
93 }
94}
95
96#[derive(Copy, Clone)]
98#[allow(missing_docs)]
99pub enum DataSize {
100 Data8,
101 Data10,
102 Data16,
103 Data20,
104 Data24,
105 Data32,
106}
107
108impl DataSize {
109 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
110 const fn ds(&self) -> vals::Ds {
111 match self {
112 DataSize::Data8 => vals::Ds::BIT8,
113 DataSize::Data10 => vals::Ds::BIT10,
114 DataSize::Data16 => vals::Ds::BIT16,
115 DataSize::Data20 => vals::Ds::BIT20,
116 DataSize::Data24 => vals::Ds::BIT24,
117 DataSize::Data32 => vals::Ds::BIT32,
118 }
119 }
120}
121
122#[derive(Copy, Clone)]
124#[allow(missing_docs)]
125pub enum FifoThreshold {
126 Empty,
127 Quarter,
128 Half,
129 ThreeQuarters,
130 Full,
131}
132
133impl FifoThreshold {
134 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
135 const fn fth(&self) -> vals::Fth {
136 match self {
137 FifoThreshold::Empty => vals::Fth::EMPTY,
138 FifoThreshold::Quarter => vals::Fth::QUARTER1,
139 FifoThreshold::Half => vals::Fth::QUARTER2,
140 FifoThreshold::ThreeQuarters => vals::Fth::QUARTER3,
141 FifoThreshold::Full => vals::Fth::FULL,
142 }
143 }
144}
145
146#[derive(Copy, Clone)]
148#[allow(missing_docs)]
149pub enum MuteValue {
150 Zero,
151 LastValue,
152}
153
154impl MuteValue {
155 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
156 const fn muteval(&self) -> vals::Muteval {
157 match self {
158 MuteValue::Zero => vals::Muteval::SEND_ZERO,
159 MuteValue::LastValue => vals::Muteval::SEND_LAST,
160 }
161 }
162}
163
164#[derive(Copy, Clone)]
166#[allow(missing_docs)]
167pub enum Protocol {
168 Free,
169 Spdif,
170 Ac97,
171}
172
173impl Protocol {
174 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
175 const fn prtcfg(&self) -> vals::Prtcfg {
176 match self {
177 Protocol::Free => vals::Prtcfg::FREE,
178 Protocol::Spdif => vals::Prtcfg::SPDIF,
179 Protocol::Ac97 => vals::Prtcfg::AC97,
180 }
181 }
182}
183
184#[derive(Copy, Clone, PartialEq)]
186#[allow(missing_docs)]
187pub enum SyncInput {
188 None,
190 Internal,
192 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
194 External(SyncInputInstance),
195}
196
197impl SyncInput {
198 const fn syncen(&self) -> vals::Syncen {
199 match self {
200 SyncInput::None => vals::Syncen::ASYNCHRONOUS,
201 SyncInput::Internal => vals::Syncen::INTERNAL,
202 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
203 SyncInput::External(_) => vals::Syncen::EXTERNAL,
204 }
205 }
206}
207
208#[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
210#[derive(Copy, Clone, PartialEq)]
211#[allow(missing_docs)]
212pub enum SyncInputInstance {
213 #[cfg(peri_sai1)]
214 Sai1 = 0,
215 #[cfg(peri_sai2)]
216 Sai2 = 1,
217 #[cfg(peri_sai3)]
218 Sai3 = 2,
219 #[cfg(peri_sai4)]
220 Sai4 = 3,
221}
222
223#[derive(Copy, Clone, PartialEq)]
225#[allow(missing_docs)]
226pub enum StereoMono {
227 Stereo,
228 Mono,
229}
230
231impl StereoMono {
232 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
233 const fn mono(&self) -> vals::Mono {
234 match self {
235 StereoMono::Stereo => vals::Mono::STEREO,
236 StereoMono::Mono => vals::Mono::MONO,
237 }
238 }
239}
240
241#[derive(Copy, Clone)]
243pub enum BitOrder {
244 LsbFirst,
246 MsbFirst,
248}
249
250impl BitOrder {
251 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
252 const fn lsbfirst(&self) -> vals::Lsbfirst {
253 match self {
254 BitOrder::LsbFirst => vals::Lsbfirst::LSB_FIRST,
255 BitOrder::MsbFirst => vals::Lsbfirst::MSB_FIRST,
256 }
257 }
258}
259
260#[derive(Copy, Clone)]
262pub enum FrameSyncOffset {
263 OnFirstBit,
265 BeforeFirstBit,
267}
268
269impl FrameSyncOffset {
270 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
271 const fn fsoff(&self) -> vals::Fsoff {
272 match self {
273 FrameSyncOffset::OnFirstBit => vals::Fsoff::ON_FIRST,
274 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFORE_FIRST,
275 }
276 }
277}
278
279#[derive(Copy, Clone)]
281pub enum FrameSyncPolarity {
282 ActiveLow,
284 ActiveHigh,
286}
287
288impl FrameSyncPolarity {
289 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
290 const fn fspol(&self) -> vals::Fspol {
291 match self {
292 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLING_EDGE,
293 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISING_EDGE,
294 }
295 }
296}
297
298#[derive(Copy, Clone)]
300#[allow(missing_docs)]
301pub enum FrameSyncDefinition {
302 StartOfFrame,
303 ChannelIdentification,
304}
305
306impl FrameSyncDefinition {
307 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
308 const fn fsdef(&self) -> bool {
309 match self {
310 FrameSyncDefinition::StartOfFrame => false,
311 FrameSyncDefinition::ChannelIdentification => true,
312 }
313 }
314}
315
316#[derive(Copy, Clone)]
318#[allow(missing_docs)]
319pub enum ClockStrobe {
320 Falling,
321 Rising,
322}
323
324impl ClockStrobe {
325 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
326 const fn ckstr(&self) -> vals::Ckstr {
327 match self {
328 ClockStrobe::Falling => vals::Ckstr::FALLING_EDGE,
329 ClockStrobe::Rising => vals::Ckstr::RISING_EDGE,
330 }
331 }
332}
333
334#[derive(Copy, Clone)]
336#[allow(missing_docs)]
337pub enum ComplementFormat {
338 OnesComplement,
339 TwosComplement,
340}
341
342impl ComplementFormat {
343 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
344 const fn cpl(&self) -> vals::Cpl {
345 match self {
346 ComplementFormat::OnesComplement => vals::Cpl::ONES_COMPLEMENT,
347 ComplementFormat::TwosComplement => vals::Cpl::TWOS_COMPLEMENT,
348 }
349 }
350}
351
352#[derive(Copy, Clone)]
354#[allow(missing_docs)]
355pub enum Companding {
356 None,
357 MuLaw,
358 ALaw,
359}
360
361impl Companding {
362 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
363 const fn comp(&self) -> vals::Comp {
364 match self {
365 Companding::None => vals::Comp::NO_COMPANDING,
366 Companding::MuLaw => vals::Comp::MU_LAW,
367 Companding::ALaw => vals::Comp::ALAW,
368 }
369 }
370}
371
372#[derive(Copy, Clone)]
374#[allow(missing_docs)]
375pub enum OutputDrive {
376 OnStart,
377 Immediately,
378}
379
380impl OutputDrive {
381 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
382 const fn outdriv(&self) -> vals::Outdriv {
383 match self {
384 OutputDrive::OnStart => vals::Outdriv::ON_START,
385 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
386 }
387 }
388}
389
390#[derive(Copy, Clone, PartialEq)]
392#[allow(missing_docs)]
393#[cfg(any(sai_v1, sai_v2))]
394pub enum MasterClockDivider {
395 MasterClockDisabled,
396 Div1,
397 Div2,
398 Div4,
399 Div6,
400 Div8,
401 Div10,
402 Div12,
403 Div14,
404 Div16,
405 Div18,
406 Div20,
407 Div22,
408 Div24,
409 Div26,
410 Div28,
411 Div30,
412}
413
414#[derive(Copy, Clone, PartialEq)]
416#[allow(missing_docs)]
417#[cfg(any(sai_v1_4pdm, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
418pub enum MasterClockDivider {
419 MasterClockDisabled,
420 Div1,
421 Div2,
422 Div3,
423 Div4,
424 Div5,
425 Div6,
426 Div7,
427 Div8,
428 Div9,
429 Div10,
430 Div11,
431 Div12,
432 Div13,
433 Div14,
434 Div15,
435 Div16,
436 Div17,
437 Div18,
438 Div19,
439 Div20,
440 Div21,
441 Div22,
442 Div23,
443 Div24,
444 Div25,
445 Div26,
446 Div27,
447 Div28,
448 Div29,
449 Div30,
450 Div31,
451 Div32,
452 Div33,
453 Div34,
454 Div35,
455 Div36,
456 Div37,
457 Div38,
458 Div39,
459 Div40,
460 Div41,
461 Div42,
462 Div43,
463 Div44,
464 Div45,
465 Div46,
466 Div47,
467 Div48,
468 Div49,
469 Div50,
470 Div51,
471 Div52,
472 Div53,
473 Div54,
474 Div55,
475 Div56,
476 Div57,
477 Div58,
478 Div59,
479 Div60,
480 Div61,
481 Div62,
482 Div63,
483}
484
485impl MasterClockDivider {
486 #[cfg(any(sai_v1, sai_v2))]
487 const fn mckdiv(&self) -> u8 {
488 match self {
489 MasterClockDivider::MasterClockDisabled => 0,
490 MasterClockDivider::Div1 => 0,
491 MasterClockDivider::Div2 => 1,
492 MasterClockDivider::Div4 => 2,
493 MasterClockDivider::Div6 => 3,
494 MasterClockDivider::Div8 => 4,
495 MasterClockDivider::Div10 => 5,
496 MasterClockDivider::Div12 => 6,
497 MasterClockDivider::Div14 => 7,
498 MasterClockDivider::Div16 => 8,
499 MasterClockDivider::Div18 => 9,
500 MasterClockDivider::Div20 => 10,
501 MasterClockDivider::Div22 => 11,
502 MasterClockDivider::Div24 => 12,
503 MasterClockDivider::Div26 => 13,
504 MasterClockDivider::Div28 => 14,
505 MasterClockDivider::Div30 => 15,
506 }
507 }
508
509 #[cfg(any(sai_v1_4pdm, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
510 const fn mckdiv(&self) -> u8 {
511 match self {
512 MasterClockDivider::MasterClockDisabled => 0,
513 MasterClockDivider::Div1 => 1,
514 MasterClockDivider::Div2 => 2,
515 MasterClockDivider::Div3 => 3,
516 MasterClockDivider::Div4 => 4,
517 MasterClockDivider::Div5 => 5,
518 MasterClockDivider::Div6 => 6,
519 MasterClockDivider::Div7 => 7,
520 MasterClockDivider::Div8 => 8,
521 MasterClockDivider::Div9 => 9,
522 MasterClockDivider::Div10 => 10,
523 MasterClockDivider::Div11 => 11,
524 MasterClockDivider::Div12 => 12,
525 MasterClockDivider::Div13 => 13,
526 MasterClockDivider::Div14 => 14,
527 MasterClockDivider::Div15 => 15,
528 MasterClockDivider::Div16 => 16,
529 MasterClockDivider::Div17 => 17,
530 MasterClockDivider::Div18 => 18,
531 MasterClockDivider::Div19 => 19,
532 MasterClockDivider::Div20 => 20,
533 MasterClockDivider::Div21 => 21,
534 MasterClockDivider::Div22 => 22,
535 MasterClockDivider::Div23 => 23,
536 MasterClockDivider::Div24 => 24,
537 MasterClockDivider::Div25 => 25,
538 MasterClockDivider::Div26 => 26,
539 MasterClockDivider::Div27 => 27,
540 MasterClockDivider::Div28 => 28,
541 MasterClockDivider::Div29 => 29,
542 MasterClockDivider::Div30 => 30,
543 MasterClockDivider::Div31 => 31,
544 MasterClockDivider::Div32 => 32,
545 MasterClockDivider::Div33 => 33,
546 MasterClockDivider::Div34 => 34,
547 MasterClockDivider::Div35 => 35,
548 MasterClockDivider::Div36 => 36,
549 MasterClockDivider::Div37 => 37,
550 MasterClockDivider::Div38 => 38,
551 MasterClockDivider::Div39 => 39,
552 MasterClockDivider::Div40 => 40,
553 MasterClockDivider::Div41 => 41,
554 MasterClockDivider::Div42 => 42,
555 MasterClockDivider::Div43 => 43,
556 MasterClockDivider::Div44 => 44,
557 MasterClockDivider::Div45 => 45,
558 MasterClockDivider::Div46 => 46,
559 MasterClockDivider::Div47 => 47,
560 MasterClockDivider::Div48 => 48,
561 MasterClockDivider::Div49 => 49,
562 MasterClockDivider::Div50 => 50,
563 MasterClockDivider::Div51 => 51,
564 MasterClockDivider::Div52 => 52,
565 MasterClockDivider::Div53 => 53,
566 MasterClockDivider::Div54 => 54,
567 MasterClockDivider::Div55 => 55,
568 MasterClockDivider::Div56 => 56,
569 MasterClockDivider::Div57 => 57,
570 MasterClockDivider::Div58 => 58,
571 MasterClockDivider::Div59 => 59,
572 MasterClockDivider::Div60 => 60,
573 MasterClockDivider::Div61 => 61,
574 MasterClockDivider::Div62 => 62,
575 MasterClockDivider::Div63 => 63,
576 }
577 }
578}
579
580#[allow(missing_docs)]
582#[non_exhaustive]
583#[derive(Copy, Clone)]
584pub struct Config {
585 pub mode: Mode,
586 pub tx_rx: TxRx,
587 pub sync_input: SyncInput,
588 pub sync_output: bool,
589 pub protocol: Protocol,
590 pub slot_size: SlotSize,
591 pub slot_count: word::U4,
592 pub slot_enable: u16,
593 pub first_bit_offset: word::U5,
594 pub data_size: DataSize,
595 pub stereo_mono: StereoMono,
596 pub bit_order: BitOrder,
597 pub frame_sync_offset: FrameSyncOffset,
598 pub frame_sync_polarity: FrameSyncPolarity,
599 pub frame_sync_active_level_length: word::U7,
600 pub frame_sync_definition: FrameSyncDefinition,
601 pub frame_length: u8,
602 pub clock_strobe: ClockStrobe,
603 pub output_drive: OutputDrive,
604 pub master_clock_divider: MasterClockDivider,
605 pub nodiv: bool,
606 pub is_high_impedance_on_inactive_slot: bool,
607 pub fifo_threshold: FifoThreshold,
608 pub companding: Companding,
609 pub complement_format: ComplementFormat,
610 pub mute_value: MuteValue,
611 pub mute_detection_counter: word::U5,
612}
613
614impl Default for Config {
615 fn default() -> Self {
616 Self {
617 mode: Mode::Master,
618 tx_rx: TxRx::Transmitter,
619 sync_output: false,
620 sync_input: SyncInput::None,
621 protocol: Protocol::Free,
622 slot_size: SlotSize::DataSize,
623 slot_count: word::U4(2),
624 first_bit_offset: word::U5(0),
625 slot_enable: 0b11,
626 data_size: DataSize::Data16,
627 stereo_mono: StereoMono::Stereo,
628 bit_order: BitOrder::LsbFirst,
629 frame_sync_offset: FrameSyncOffset::BeforeFirstBit,
630 frame_sync_polarity: FrameSyncPolarity::ActiveLow,
631 frame_sync_active_level_length: word::U7(16),
632 frame_sync_definition: FrameSyncDefinition::ChannelIdentification,
633 frame_length: 32,
634 master_clock_divider: MasterClockDivider::MasterClockDisabled,
635 nodiv: false,
636 clock_strobe: ClockStrobe::Rising,
637 output_drive: OutputDrive::Immediately,
638 is_high_impedance_on_inactive_slot: false,
639 fifo_threshold: FifoThreshold::ThreeQuarters,
640 companding: Companding::None,
641 complement_format: ComplementFormat::TwosComplement,
642 mute_value: MuteValue::Zero,
643 mute_detection_counter: word::U5(4),
644 }
645 }
646}
647
648impl Config {
649 pub fn new() -> Self {
651 return Default::default();
652 }
653}
654
655#[cfg(not(gpdma))]
656enum RingBuffer<'d, W: word::Word> {
657 Writable(WritableRingBuffer<'d, W>),
658 Readable(ReadableRingBuffer<'d, W>),
659}
660
661fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
662 let ch = w.ch(sub_block as usize);
663 ch.dr().as_ptr() as _
664}
665
666fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) {
668 (
669 match tx_rx {
671 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh),
672 TxRx::Receiver => AfType::input(Pull::Down), },
674 match mode {
676 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh),
677 Mode::Slave => AfType::input(Pull::Down), },
679 )
680}
681
682#[cfg(not(gpdma))]
683fn get_ring_buffer<'d, T: Instance, W: word::Word>(
684 dma: Peri<'d, impl Channel>,
685 dma_buf: &'d mut [W],
686 request: Request,
687 sub_block: WhichSubBlock,
688 tx_rx: TxRx,
689) -> RingBuffer<'d, W> {
690 let opts = TransferOptions {
691 half_transfer_ir: true,
692 ..Default::default()
694 };
695 match tx_rx {
696 TxRx::Transmitter => RingBuffer::Writable(unsafe {
697 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
698 }),
699 TxRx::Receiver => RingBuffer::Readable(unsafe {
700 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
701 }),
702 }
703}
704
705fn update_synchronous_config(config: &mut Config) {
706 config.mode = Mode::Slave;
707 config.sync_output = false;
708
709 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2))]
710 {
711 config.sync_input = SyncInput::Internal;
712 }
713
714 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
715 {
716 assert!(config.sync_input != SyncInput::None);
719 }
720}
721
722pub struct SubBlock<'d, T: Instance, S: SubBlockInstance> {
724 peri: Peri<'d, T>,
725 _phantom: PhantomData<S>,
726}
727
728pub fn split_subblocks<'d, T: Instance>(peri: Peri<'d, T>) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
732 rcc::enable_and_reset::<T>();
733
734 (
735 SubBlock {
736 peri: unsafe { peri.clone_unchecked() },
737 _phantom: PhantomData,
738 },
739 SubBlock {
740 peri,
741 _phantom: PhantomData,
742 },
743 )
744}
745
746pub struct Sai<'d, T: Instance, W: word::Word> {
748 _peri: Peri<'d, T>,
749 sd: Option<Peri<'d, AnyPin>>,
750 fs: Option<Peri<'d, AnyPin>>,
751 sck: Option<Peri<'d, AnyPin>>,
752 mclk: Option<Peri<'d, AnyPin>>,
753 #[cfg(gpdma)]
754 ring_buffer: PhantomData<W>,
755 #[cfg(not(gpdma))]
756 ring_buffer: RingBuffer<'d, W>,
757 sub_block: WhichSubBlock,
758}
759
760#[cfg(not(gpdma))]
761impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
762 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>(
766 peri: SubBlock<'d, T, S>,
767 sck: Peri<'d, impl SckPin<T, S>>,
768 sd: Peri<'d, impl SdPin<T, S>>,
769 fs: Peri<'d, impl FsPin<T, S>>,
770 mclk: Peri<'d, impl MclkPin<T, S>>,
771 dma: Peri<'d, impl Channel + Dma<T, S>>,
772 dma_buf: &'d mut [W],
773 mut config: Config,
774 ) -> Self {
775 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
776 mclk.set_as_af(mclk.af_num(), ck_af_type);
777
778 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
779 config.master_clock_divider = MasterClockDivider::Div1;
780 }
781
782 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
783 }
784
785 pub fn new_asynchronous<S: SubBlockInstance>(
789 peri: SubBlock<'d, T, S>,
790 sck: Peri<'d, impl SckPin<T, S>>,
791 sd: Peri<'d, impl SdPin<T, S>>,
792 fs: Peri<'d, impl FsPin<T, S>>,
793 dma: Peri<'d, impl Channel + Dma<T, S>>,
794 dma_buf: &'d mut [W],
795 config: Config,
796 ) -> Self {
797 let peri = peri.peri;
798
799 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
800 sd.set_as_af(sd.af_num(), sd_af_type);
801 sck.set_as_af(sck.af_num(), ck_af_type);
802 fs.set_as_af(fs.af_num(), ck_af_type);
803
804 let sub_block = S::WHICH;
805 let request = dma.request();
806
807 Self::new_inner(
808 peri,
809 sub_block,
810 Some(sck.into()),
811 None,
812 Some(sd.into()),
813 Some(fs.into()),
814 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
815 config,
816 )
817 }
818
819 pub fn new_synchronous<S: SubBlockInstance>(
823 peri: SubBlock<'d, T, S>,
824 sd: Peri<'d, impl SdPin<T, S>>,
825 dma: Peri<'d, impl Channel + Dma<T, S>>,
826 dma_buf: &'d mut [W],
827 mut config: Config,
828 ) -> Self {
829 update_synchronous_config(&mut config);
830
831 let peri = peri.peri;
832
833 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
834 sd.set_as_af(sd.af_num(), sd_af_type);
835
836 let sub_block = S::WHICH;
837 let request = dma.request();
838
839 Self::new_inner(
840 peri,
841 sub_block,
842 None,
843 None,
844 Some(sd.into()),
845 None,
846 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
847 config,
848 )
849 }
850
851 fn new_inner(
852 peri: Peri<'d, T>,
853 sub_block: WhichSubBlock,
854 sck: Option<Peri<'d, AnyPin>>,
855 mclk: Option<Peri<'d, AnyPin>>,
856 sd: Option<Peri<'d, AnyPin>>,
857 fs: Option<Peri<'d, AnyPin>>,
858 ring_buffer: RingBuffer<'d, W>,
859 config: Config,
860 ) -> Self {
861 let ch = T::REGS.ch(sub_block as usize);
862
863 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
864 {
865 ch.cr1().modify(|w| w.set_saien(false));
866 }
867
868 ch.cr2().modify(|w| w.set_fflush(true));
869
870 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
871 {
872 if let SyncInput::External(i) = config.sync_input {
873 T::REGS.gcr().modify(|w| {
874 w.set_syncin(i as u8);
875 });
876 }
877
878 if config.sync_output {
879 let syncout: u8 = match sub_block {
880 WhichSubBlock::A => 0b01,
881 WhichSubBlock::B => 0b10,
882 };
883 T::REGS.gcr().modify(|w| {
884 w.set_syncout(syncout);
885 });
886 }
887 }
888
889 #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
890 {
891 ch.cr1().modify(|w| {
892 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
893 TxRx::Transmitter
894 } else {
895 TxRx::Receiver
896 }));
897 w.set_prtcfg(config.protocol.prtcfg());
898 w.set_ds(config.data_size.ds());
899 w.set_lsbfirst(config.bit_order.lsbfirst());
900 w.set_ckstr(config.clock_strobe.ckstr());
901 w.set_syncen(config.sync_input.syncen());
902 w.set_mono(config.stereo_mono.mono());
903 w.set_outdriv(config.output_drive.outdriv());
904 w.set_mckdiv(config.master_clock_divider.mckdiv().into());
905 w.set_nodiv(config.nodiv);
906 w.set_dmaen(true);
907 });
908
909 ch.cr2().modify(|w| {
910 w.set_fth(config.fifo_threshold.fth());
911 w.set_comp(config.companding.comp());
912 w.set_cpl(config.complement_format.cpl());
913 w.set_muteval(config.mute_value.muteval());
914 w.set_mutecnt(config.mute_detection_counter.0 as u8);
915 w.set_tris(config.is_high_impedance_on_inactive_slot);
916 });
917
918 ch.frcr().modify(|w| {
919 w.set_fsoff(config.frame_sync_offset.fsoff());
920 w.set_fspol(config.frame_sync_polarity.fspol());
921 w.set_fsdef(config.frame_sync_definition.fsdef());
922 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
923 w.set_frl(config.frame_length - 1);
924 });
925
926 ch.slotr().modify(|w| {
927 w.set_nbslot(config.slot_count.0 as u8 - 1);
928 w.set_slotsz(config.slot_size.slotsz());
929 w.set_fboff(config.first_bit_offset.0 as u8);
930 w.set_sloten(vals::Sloten::from_bits(config.slot_enable as u16));
931 });
932
933 ch.cr1().modify(|w| w.set_saien(true));
934
935 if ch.cr1().read().saien() == false {
936 panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)");
937 }
938 }
939
940 Self {
941 _peri: peri,
942 sub_block,
943 sck,
944 mclk,
945 sd,
946 fs,
947 ring_buffer,
948 }
949 }
950
951 pub fn start(&mut self) -> Result<(), Error> {
955 match self.ring_buffer {
956 RingBuffer::Writable(_) => Err(Error::NotAReceiver),
957 RingBuffer::Readable(ref mut rb) => {
958 rb.start();
959 Ok(())
960 }
961 }
962 }
963
964 fn is_transmitter(ring_buffer: &RingBuffer<W>) -> bool {
965 match ring_buffer {
966 RingBuffer::Writable(_) => true,
967 _ => false,
968 }
969 }
970
971 pub fn reset() {
973 rcc::enable_and_reset::<T>();
974 }
975
976 pub fn set_mute(&mut self, value: bool) {
978 let ch = T::REGS.ch(self.sub_block as usize);
979 ch.cr2().modify(|w| w.set_mute(value));
980 }
981
982 pub fn is_muted(&self) -> Result<bool, Error> {
986 match &self.ring_buffer {
987 RingBuffer::Readable(_) => {
988 let ch = T::REGS.ch(self.sub_block as usize);
989 let mute_state = ch.sr().read().mutedet();
990 ch.clrfr().write(|w| w.set_cmutedet(true));
991 Ok(mute_state)
992 }
993 _ => Err(Error::NotAReceiver),
994 }
995 }
996
997 pub async fn wait_write_error(&mut self) -> Result<(), Error> {
1004 match &mut self.ring_buffer {
1005 RingBuffer::Writable(buffer) => {
1006 buffer.wait_write_error().await?;
1007 Ok(())
1008 }
1009 _ => return Err(Error::NotATransmitter),
1010 }
1011 }
1012
1013 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
1023 match &mut self.ring_buffer {
1024 RingBuffer::Writable(buffer) => {
1025 if buffer.is_running() {
1026 buffer.write_exact(data).await?;
1027 } else {
1028 buffer.write_immediate(data)?;
1029 buffer.start();
1030 }
1031 Ok(())
1032 }
1033 _ => return Err(Error::NotATransmitter),
1034 }
1035 }
1036
1037 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
1044 match &mut self.ring_buffer {
1045 RingBuffer::Readable(buffer) => {
1046 buffer.read_exact(data).await?;
1047 Ok(())
1048 }
1049 _ => Err(Error::NotAReceiver),
1050 }
1051 }
1052}
1053
1054impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> {
1055 fn drop(&mut self) {
1056 let ch = T::REGS.ch(self.sub_block as usize);
1057 ch.cr1().modify(|w| w.set_saien(false));
1058 ch.cr2().modify(|w| w.set_fflush(true));
1059 self.fs.as_ref().map(|x| x.set_as_disconnected());
1060 self.sd.as_ref().map(|x| x.set_as_disconnected());
1061 self.sck.as_ref().map(|x| x.set_as_disconnected());
1062 self.mclk.as_ref().map(|x| x.set_as_disconnected());
1063 }
1064}
1065
1066trait SealedInstance {
1067 const REGS: Regs;
1068}
1069
1070#[derive(Copy, Clone)]
1071enum WhichSubBlock {
1072 A = 0,
1073 B = 1,
1074}
1075
1076trait SealedSubBlock {
1077 const WHICH: WhichSubBlock;
1078}
1079
1080#[allow(private_bounds)]
1082pub trait SubBlockInstance: SealedSubBlock {}
1083
1084pub enum A {}
1086impl SealedSubBlock for A {
1087 const WHICH: WhichSubBlock = WhichSubBlock::A;
1088}
1089impl SubBlockInstance for A {}
1090
1091pub enum B {}
1093impl SealedSubBlock for B {
1094 const WHICH: WhichSubBlock = WhichSubBlock::B;
1095}
1096impl SubBlockInstance for B {}
1097
1098#[allow(private_bounds)]
1100pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
1101
1102pin_trait!(SckPin, Instance, SubBlockInstance);
1103pin_trait!(FsPin, Instance, SubBlockInstance);
1104pin_trait!(SdPin, Instance, SubBlockInstance);
1105pin_trait!(MclkPin, Instance, SubBlockInstance);
1106
1107dma_trait!(Dma, Instance, SubBlockInstance);
1108
1109foreach_peripheral!(
1110 (sai, $inst:ident) => {
1111 impl SealedInstance for peripherals::$inst {
1112 const REGS: Regs = crate::pac::$inst;
1113 }
1114
1115 impl Instance for peripherals::$inst {}
1116 };
1117);