1#![macro_use]
3#![cfg_attr(gpdma, allow(unused))]
4
5use core::marker::PhantomData;
6
7use embassy_hal_internal::{into_ref, PeripheralRef};
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, Peripheral};
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_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_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_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_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_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_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_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_v4_2pdm, sai_v4_4pdm))]
203 SyncInput::External(_) => vals::Syncen::EXTERNAL,
204 }
205 }
206}
207
208#[cfg(any(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_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_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_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_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_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_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_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_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_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_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_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 is_high_impedance_on_inactive_slot: bool,
606 pub fifo_threshold: FifoThreshold,
607 pub companding: Companding,
608 pub complement_format: ComplementFormat,
609 pub mute_value: MuteValue,
610 pub mute_detection_counter: word::U5,
611}
612
613impl Default for Config {
614 fn default() -> Self {
615 Self {
616 mode: Mode::Master,
617 tx_rx: TxRx::Transmitter,
618 sync_output: false,
619 sync_input: SyncInput::None,
620 protocol: Protocol::Free,
621 slot_size: SlotSize::DataSize,
622 slot_count: word::U4(2),
623 first_bit_offset: word::U5(0),
624 slot_enable: 0b11,
625 data_size: DataSize::Data16,
626 stereo_mono: StereoMono::Stereo,
627 bit_order: BitOrder::LsbFirst,
628 frame_sync_offset: FrameSyncOffset::BeforeFirstBit,
629 frame_sync_polarity: FrameSyncPolarity::ActiveLow,
630 frame_sync_active_level_length: word::U7(16),
631 frame_sync_definition: FrameSyncDefinition::ChannelIdentification,
632 frame_length: 32,
633 master_clock_divider: MasterClockDivider::MasterClockDisabled,
634 clock_strobe: ClockStrobe::Rising,
635 output_drive: OutputDrive::Immediately,
636 is_high_impedance_on_inactive_slot: false,
637 fifo_threshold: FifoThreshold::ThreeQuarters,
638 companding: Companding::None,
639 complement_format: ComplementFormat::TwosComplement,
640 mute_value: MuteValue::Zero,
641 mute_detection_counter: word::U5(4),
642 }
643 }
644}
645
646impl Config {
647 pub fn new() -> Self {
649 return Default::default();
650 }
651}
652
653#[cfg(not(gpdma))]
654enum RingBuffer<'d, W: word::Word> {
655 Writable(WritableRingBuffer<'d, W>),
656 Readable(ReadableRingBuffer<'d, W>),
657}
658
659fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
660 let ch = w.ch(sub_block as usize);
661 ch.dr().as_ptr() as _
662}
663
664fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) {
666 (
667 match tx_rx {
669 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh),
670 TxRx::Receiver => AfType::input(Pull::Down), },
672 match mode {
674 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh),
675 Mode::Slave => AfType::input(Pull::Down), },
677 )
678}
679
680#[cfg(not(gpdma))]
681fn get_ring_buffer<'d, T: Instance, W: word::Word>(
682 dma: impl Peripheral<P = impl Channel> + 'd,
683 dma_buf: &'d mut [W],
684 request: Request,
685 sub_block: WhichSubBlock,
686 tx_rx: TxRx,
687) -> RingBuffer<'d, W> {
688 let opts = TransferOptions {
689 half_transfer_ir: true,
690 ..Default::default()
692 };
693 match tx_rx {
694 TxRx::Transmitter => RingBuffer::Writable(unsafe {
695 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
696 }),
697 TxRx::Receiver => RingBuffer::Readable(unsafe {
698 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
699 }),
700 }
701}
702
703fn update_synchronous_config(config: &mut Config) {
704 config.mode = Mode::Slave;
705 config.sync_output = false;
706
707 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))]
708 {
709 config.sync_input = SyncInput::Internal;
710 }
711
712 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
713 {
714 assert!(config.sync_input != SyncInput::None);
717 }
718}
719
720pub struct SubBlock<'d, T, S: SubBlockInstance> {
722 peri: PeripheralRef<'d, T>,
723 _phantom: PhantomData<S>,
724}
725
726pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
730 into_ref!(peri);
731 rcc::enable_and_reset::<T>();
732
733 (
734 SubBlock {
735 peri: unsafe { peri.clone_unchecked() },
736 _phantom: PhantomData,
737 },
738 SubBlock {
739 peri,
740 _phantom: PhantomData,
741 },
742 )
743}
744
745pub struct Sai<'d, T: Instance, W: word::Word> {
747 _peri: PeripheralRef<'d, T>,
748 sd: Option<PeripheralRef<'d, AnyPin>>,
749 fs: Option<PeripheralRef<'d, AnyPin>>,
750 sck: Option<PeripheralRef<'d, AnyPin>>,
751 mclk: Option<PeripheralRef<'d, AnyPin>>,
752 #[cfg(gpdma)]
753 ring_buffer: PhantomData<W>,
754 #[cfg(not(gpdma))]
755 ring_buffer: RingBuffer<'d, W>,
756 sub_block: WhichSubBlock,
757}
758
759#[cfg(not(gpdma))]
760impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
761 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>(
765 peri: SubBlock<'d, T, S>,
766 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
767 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
768 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
769 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd,
770 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
771 dma_buf: &'d mut [W],
772 mut config: Config,
773 ) -> Self {
774 into_ref!(mclk);
775
776 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
777 mclk.set_as_af(mclk.af_num(), ck_af_type);
778
779 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
780 config.master_clock_divider = MasterClockDivider::Div1;
781 }
782
783 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
784 }
785
786 pub fn new_asynchronous<S: SubBlockInstance>(
790 peri: SubBlock<'d, T, S>,
791 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
792 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
793 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
794 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
795 dma_buf: &'d mut [W],
796 config: Config,
797 ) -> Self {
798 let peri = peri.peri;
799 into_ref!(peri, dma, sck, sd, fs);
800
801 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
802 sd.set_as_af(sd.af_num(), sd_af_type);
803 sck.set_as_af(sck.af_num(), ck_af_type);
804 fs.set_as_af(fs.af_num(), ck_af_type);
805
806 let sub_block = S::WHICH;
807 let request = dma.request();
808
809 Self::new_inner(
810 peri,
811 sub_block,
812 Some(sck.map_into()),
813 None,
814 Some(sd.map_into()),
815 Some(fs.map_into()),
816 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
817 config,
818 )
819 }
820
821 pub fn new_synchronous<S: SubBlockInstance>(
825 peri: SubBlock<'d, T, S>,
826 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
827 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
828 dma_buf: &'d mut [W],
829 mut config: Config,
830 ) -> Self {
831 update_synchronous_config(&mut config);
832
833 let peri = peri.peri;
834 into_ref!(dma, peri, sd);
835
836 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
837 sd.set_as_af(sd.af_num(), sd_af_type);
838
839 let sub_block = S::WHICH;
840 let request = dma.request();
841
842 Self::new_inner(
843 peri,
844 sub_block,
845 None,
846 None,
847 Some(sd.map_into()),
848 None,
849 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
850 config,
851 )
852 }
853
854 fn new_inner(
855 peri: impl Peripheral<P = T> + 'd,
856 sub_block: WhichSubBlock,
857 sck: Option<PeripheralRef<'d, AnyPin>>,
858 mclk: Option<PeripheralRef<'d, AnyPin>>,
859 sd: Option<PeripheralRef<'d, AnyPin>>,
860 fs: Option<PeripheralRef<'d, AnyPin>>,
861 ring_buffer: RingBuffer<'d, W>,
862 config: Config,
863 ) -> Self {
864 let ch = T::REGS.ch(sub_block as usize);
865
866 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
867 {
868 ch.cr1().modify(|w| w.set_saien(false));
869 }
870
871 ch.cr2().modify(|w| w.set_fflush(true));
872
873 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
874 {
875 if let SyncInput::External(i) = config.sync_input {
876 T::REGS.gcr().modify(|w| {
877 w.set_syncin(i as u8);
878 });
879 }
880
881 if config.sync_output {
882 let syncout: u8 = match sub_block {
883 WhichSubBlock::A => 0b01,
884 WhichSubBlock::B => 0b10,
885 };
886 T::REGS.gcr().modify(|w| {
887 w.set_syncout(syncout);
888 });
889 }
890 }
891
892 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
893 {
894 ch.cr1().modify(|w| {
895 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
896 TxRx::Transmitter
897 } else {
898 TxRx::Receiver
899 }));
900 w.set_prtcfg(config.protocol.prtcfg());
901 w.set_ds(config.data_size.ds());
902 w.set_lsbfirst(config.bit_order.lsbfirst());
903 w.set_ckstr(config.clock_strobe.ckstr());
904 w.set_syncen(config.sync_input.syncen());
905 w.set_mono(config.stereo_mono.mono());
906 w.set_outdriv(config.output_drive.outdriv());
907 w.set_mckdiv(config.master_clock_divider.mckdiv());
908 w.set_nodiv(
909 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
910 vals::Nodiv::NO_DIV
911 } else {
912 vals::Nodiv::MASTER_CLOCK
913 },
914 );
915 w.set_dmaen(true);
916 });
917
918 ch.cr2().modify(|w| {
919 w.set_fth(config.fifo_threshold.fth());
920 w.set_comp(config.companding.comp());
921 w.set_cpl(config.complement_format.cpl());
922 w.set_muteval(config.mute_value.muteval());
923 w.set_mutecnt(config.mute_detection_counter.0 as u8);
924 w.set_tris(config.is_high_impedance_on_inactive_slot);
925 });
926
927 ch.frcr().modify(|w| {
928 w.set_fsoff(config.frame_sync_offset.fsoff());
929 w.set_fspol(config.frame_sync_polarity.fspol());
930 w.set_fsdef(config.frame_sync_definition.fsdef());
931 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
932 w.set_frl(config.frame_length - 1);
933 });
934
935 ch.slotr().modify(|w| {
936 w.set_nbslot(config.slot_count.0 as u8 - 1);
937 w.set_slotsz(config.slot_size.slotsz());
938 w.set_fboff(config.first_bit_offset.0 as u8);
939 w.set_sloten(vals::Sloten(config.slot_enable as u16));
940 });
941
942 ch.cr1().modify(|w| w.set_saien(true));
943
944 if ch.cr1().read().saien() == false {
945 panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)");
946 }
947 }
948
949 Self {
950 _peri: peri.into_ref(),
951 sub_block,
952 sck,
953 mclk,
954 sd,
955 fs,
956 ring_buffer,
957 }
958 }
959
960 pub fn start(&mut self) -> Result<(), Error> {
964 match self.ring_buffer {
965 RingBuffer::Writable(_) => Err(Error::NotAReceiver),
966 RingBuffer::Readable(ref mut rb) => {
967 rb.start();
968 Ok(())
969 }
970 }
971 }
972
973 fn is_transmitter(ring_buffer: &RingBuffer<W>) -> bool {
974 match ring_buffer {
975 RingBuffer::Writable(_) => true,
976 _ => false,
977 }
978 }
979
980 pub fn reset() {
982 rcc::enable_and_reset::<T>();
983 }
984
985 pub fn set_mute(&mut self, value: bool) {
987 let ch = T::REGS.ch(self.sub_block as usize);
988 ch.cr2().modify(|w| w.set_mute(value));
989 }
990
991 pub fn is_muted(&self) -> Result<bool, Error> {
995 match &self.ring_buffer {
996 RingBuffer::Readable(_) => {
997 let ch = T::REGS.ch(self.sub_block as usize);
998 let mute_state = ch.sr().read().mutedet();
999 ch.clrfr().write(|w| w.set_cmutedet(true));
1000 Ok(mute_state)
1001 }
1002 _ => Err(Error::NotAReceiver),
1003 }
1004 }
1005
1006 pub async fn wait_write_error(&mut self) -> Result<(), Error> {
1013 match &mut self.ring_buffer {
1014 RingBuffer::Writable(buffer) => {
1015 buffer.wait_write_error().await?;
1016 Ok(())
1017 }
1018 _ => return Err(Error::NotATransmitter),
1019 }
1020 }
1021
1022 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
1032 match &mut self.ring_buffer {
1033 RingBuffer::Writable(buffer) => {
1034 if buffer.is_running() {
1035 buffer.write_exact(data).await?;
1036 } else {
1037 buffer.write_immediate(data)?;
1038 buffer.start();
1039 }
1040 Ok(())
1041 }
1042 _ => return Err(Error::NotATransmitter),
1043 }
1044 }
1045
1046 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
1053 match &mut self.ring_buffer {
1054 RingBuffer::Readable(buffer) => {
1055 buffer.read_exact(data).await?;
1056 Ok(())
1057 }
1058 _ => Err(Error::NotAReceiver),
1059 }
1060 }
1061}
1062
1063impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> {
1064 fn drop(&mut self) {
1065 let ch = T::REGS.ch(self.sub_block as usize);
1066 ch.cr1().modify(|w| w.set_saien(false));
1067 ch.cr2().modify(|w| w.set_fflush(true));
1068 self.fs.as_ref().map(|x| x.set_as_disconnected());
1069 self.sd.as_ref().map(|x| x.set_as_disconnected());
1070 self.sck.as_ref().map(|x| x.set_as_disconnected());
1071 self.mclk.as_ref().map(|x| x.set_as_disconnected());
1072 }
1073}
1074
1075trait SealedInstance {
1076 const REGS: Regs;
1077}
1078
1079#[derive(Copy, Clone)]
1080enum WhichSubBlock {
1081 A = 0,
1082 B = 1,
1083}
1084
1085trait SealedSubBlock {
1086 const WHICH: WhichSubBlock;
1087}
1088
1089#[allow(private_bounds)]
1091pub trait SubBlockInstance: SealedSubBlock {}
1092
1093pub enum A {}
1095impl SealedSubBlock for A {
1096 const WHICH: WhichSubBlock = WhichSubBlock::A;
1097}
1098impl SubBlockInstance for A {}
1099
1100pub enum B {}
1102impl SealedSubBlock for B {
1103 const WHICH: WhichSubBlock = WhichSubBlock::B;
1104}
1105impl SubBlockInstance for B {}
1106
1107#[allow(private_bounds)]
1109pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
1110
1111pin_trait!(SckPin, Instance, SubBlockInstance);
1112pin_trait!(FsPin, Instance, SubBlockInstance);
1113pin_trait!(SdPin, Instance, SubBlockInstance);
1114pin_trait!(MclkPin, Instance, SubBlockInstance);
1115
1116dma_trait!(Dma, Instance, SubBlockInstance);
1117
1118foreach_peripheral!(
1119 (sai, $inst:ident) => {
1120 impl SealedInstance for peripherals::$inst {
1121 const REGS: Regs = crate::pac::$inst;
1122 }
1123
1124 impl Instance for peripherals::$inst {}
1125 };
1126);