aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Gilbert <[email protected]>2023-09-30 19:43:44 -0500
committerTyler Gilbert <[email protected]>2023-09-30 19:43:44 -0500
commitd1f4511cd14e851b0fa8c54d45131095ee8edbe0 (patch)
treee00088d20991f9634ab71e0bcc1814109f071ab1
parentfa8d5da4a5c5270a66d4bdf59aa215c32b14ad43 (diff)
Issue #1986 update the SAI driver with receiver capability
-rw-r--r--embassy-stm32/src/sai/mod.rs216
1 files changed, 174 insertions, 42 deletions
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 4ffa6e9ce..a89c132c3 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -4,7 +4,7 @@ use embassy_embedded_hal::SetConfig;
4use embassy_hal_internal::{into_ref, PeripheralRef}; 4use embassy_hal_internal::{into_ref, PeripheralRef};
5 5
6pub use crate::dma::word; 6pub use crate::dma::word;
7use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; 7use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
8use crate::gpio::sealed::{AFType, Pin as _}; 8use crate::gpio::sealed::{AFType, Pin as _};
9use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
10use crate::pac::sai::{vals, Sai as Regs}; 10use crate::pac::sai::{vals, Sai as Regs};
@@ -48,8 +48,8 @@ pub enum Mode {
48} 48}
49 49
50#[derive(Copy, Clone)] 50#[derive(Copy, Clone)]
51enum TxRx { 51pub enum TxRx {
52 Transmiter, 52 Transmitter,
53 Receiver, 53 Receiver,
54} 54}
55 55
@@ -57,7 +57,7 @@ impl Mode {
57 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 57 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
58 const fn mode(&self, tx_rx: TxRx) -> vals::Mode { 58 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
59 match tx_rx { 59 match tx_rx {
60 TxRx::Transmiter => match self { 60 TxRx::Transmitter => match self {
61 Mode::Master => vals::Mode::MASTERTX, 61 Mode::Master => vals::Mode::MASTERTX,
62 Mode::Slave => vals::Mode::SLAVETX, 62 Mode::Slave => vals::Mode::SLAVETX,
63 }, 63 },
@@ -212,6 +212,7 @@ pub enum SyncEnable {
212 /// Syncs with the other A/B sub-block within the SAI unit 212 /// Syncs with the other A/B sub-block within the SAI unit
213 Internal, 213 Internal,
214 /// Syncs with a sub-block in the other SAI unit - use set_sync_output() and set_sync_input() 214 /// Syncs with a sub-block in the other SAI unit - use set_sync_output() and set_sync_input()
215 #[cfg(any(sai_v4))]
215 External, 216 External,
216} 217}
217 218
@@ -221,6 +222,7 @@ impl SyncEnable {
221 match self { 222 match self {
222 SyncEnable::Asynchronous => vals::Syncen::ASYNCHRONOUS, 223 SyncEnable::Asynchronous => vals::Syncen::ASYNCHRONOUS,
223 SyncEnable::Internal => vals::Syncen::INTERNAL, 224 SyncEnable::Internal => vals::Syncen::INTERNAL,
225 #[cfg(any(sai_v4))]
224 SyncEnable::External => vals::Syncen::EXTERNAL, 226 SyncEnable::External => vals::Syncen::EXTERNAL,
225 } 227 }
226 } 228 }
@@ -425,6 +427,7 @@ impl MasterClockDivider {
425#[derive(Copy, Clone)] 427#[derive(Copy, Clone)]
426pub struct Config { 428pub struct Config {
427 pub mode: Mode, 429 pub mode: Mode,
430 pub tx_rx: TxRx,
428 pub sync_enable: SyncEnable, 431 pub sync_enable: SyncEnable,
429 pub is_sync_output: bool, 432 pub is_sync_output: bool,
430 pub protocol: Protocol, 433 pub protocol: Protocol,
@@ -455,6 +458,7 @@ impl Default for Config {
455 fn default() -> Self { 458 fn default() -> Self {
456 Self { 459 Self {
457 mode: Mode::Master, 460 mode: Mode::Master,
461 tx_rx: TxRx::Transmitter,
458 is_sync_output: false, 462 is_sync_output: false,
459 sync_enable: SyncEnable::Asynchronous, 463 sync_enable: SyncEnable::Asynchronous,
460 protocol: Protocol::Free, 464 protocol: Protocol::Free,
@@ -505,7 +509,6 @@ pub enum SubBlock {
505 509
506enum RingBuffer<'d, C: Channel, W: word::Word> { 510enum RingBuffer<'d, C: Channel, W: word::Word> {
507 Writable(WritableRingBuffer<'d, C, W>), 511 Writable(WritableRingBuffer<'d, C, W>),
508 #[allow(dead_code)] // remove this after implementing new_* functions for receiver
509 Readable(ReadableRingBuffer<'d, C, W>), 512 Readable(ReadableRingBuffer<'d, C, W>),
510} 513}
511 514
@@ -515,6 +518,12 @@ fn wdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W {
515 ch.dr().as_ptr() as _ 518 ch.dr().as_ptr() as _
516} 519}
517 520
521#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
522fn rdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W {
523 let ch = w.ch(sub_block as usize);
524 ch.dr().as_ptr() as _
525}
526
518pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { 527pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
519 _peri: PeripheralRef<'d, T>, 528 _peri: PeripheralRef<'d, T>,
520 sd: Option<PeripheralRef<'d, AnyPin>>, 529 sd: Option<PeripheralRef<'d, AnyPin>>,
@@ -526,14 +535,45 @@ pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
526} 535}
527 536
528impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { 537impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
529 fn get_transmitter_af_types(mode: Mode) -> (AFType, AFType) { 538 // return the type for (sd, sck)
530 match mode { 539 fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
531 Mode::Master => (AFType::OutputPushPull, AFType::OutputPushPull), 540 (
532 Mode::Slave => (AFType::OutputPushPull, AFType::Input), 541 //sd is defined by tx/rx mode
542 match tx_rx {
543 TxRx::Transmitter => AFType::OutputPushPull,
544 TxRx::Receiver => AFType::Input,
545 },
546 //clocks (mclk, sck and fs) are defined by master/slave
547 match mode {
548 Mode::Master => AFType::OutputPushPull,
549 Mode::Slave => AFType::Input,
550 },
551 )
552 }
553
554 fn get_ring_buffer(
555 dma: impl Peripheral<P = C> + 'd,
556 dma_buf: &'d mut [W],
557 request: Request,
558 sub_block: SubBlock,
559 tx_rx: TxRx,
560 ) -> RingBuffer<'d, C, W> {
561 let opts = TransferOptions {
562 half_transfer_ir: true,
563 //the new_write() and new_read() always use circular mode
564 ..Default::default()
565 };
566 match tx_rx {
567 TxRx::Transmitter => RingBuffer::Writable(unsafe {
568 WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
569 }),
570 TxRx::Receiver => RingBuffer::Readable(unsafe {
571 ReadableRingBuffer::new_read(dma, request, rdr(T::REGS, sub_block), dma_buf, opts)
572 }),
533 } 573 }
534 } 574 }
535 575
536 pub fn new_asynchronous_transmitter_with_mclk_a( 576 pub fn new_asynchronous_block_a_with_mclk(
537 peri: impl Peripheral<P = T> + 'd, 577 peri: impl Peripheral<P = T> + 'd,
538 sck: impl Peripheral<P = impl SckAPin<T>> + 'd, 578 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
539 sd: impl Peripheral<P = impl SdAPin<T>> + 'd, 579 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
@@ -548,17 +588,19 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
548 { 588 {
549 into_ref!(mclk); 589 into_ref!(mclk);
550 590
551 mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull); 591 let (_sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
592
593 mclk.set_as_af(mclk.af_num(), ck_af_type);
552 mclk.set_speed(crate::gpio::Speed::VeryHigh); 594 mclk.set_speed(crate::gpio::Speed::VeryHigh);
553 595
554 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { 596 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
555 config.master_clock_divider = MasterClockDivider::Div1; 597 config.master_clock_divider = MasterClockDivider::Div1;
556 } 598 }
557 599
558 Self::new_asynchronous_transmitter_a(peri, sck, sd, fs, dma, dma_buf, config) 600 Self::new_asynchronous_block_a(peri, sck, sd, fs, dma, dma_buf, config)
559 } 601 }
560 602
561 pub fn new_asynchronous_transmitter_a( 603 pub fn new_asynchronous_block_a(
562 peri: impl Peripheral<P = T> + 'd, 604 peri: impl Peripheral<P = T> + 'd,
563 sck: impl Peripheral<P = impl SckAPin<T>> + 'd, 605 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
564 sd: impl Peripheral<P = impl SdAPin<T>> + 'd, 606 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
@@ -572,7 +614,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
572 { 614 {
573 into_ref!(peri, dma, sck, sd, fs); 615 into_ref!(peri, dma, sck, sd, fs);
574 616
575 let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode); 617 let (sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
576 sd.set_as_af(sd.af_num(), sd_af_type); 618 sd.set_as_af(sd.af_num(), sd_af_type);
577 sd.set_speed(crate::gpio::Speed::VeryHigh); 619 sd.set_speed(crate::gpio::Speed::VeryHigh);
578 620
@@ -581,14 +623,8 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
581 fs.set_as_af(fs.af_num(), ck_af_type); 623 fs.set_as_af(fs.af_num(), ck_af_type);
582 fs.set_speed(crate::gpio::Speed::VeryHigh); 624 fs.set_speed(crate::gpio::Speed::VeryHigh);
583 625
584 let request = dma.request();
585 let opts = TransferOptions {
586 half_transfer_ir: true,
587 circular: true,
588 ..Default::default()
589 };
590
591 let sub_block = SubBlock::A; 626 let sub_block = SubBlock::A;
627 let request = dma.request();
592 628
593 Self::new_inner( 629 Self::new_inner(
594 peri, 630 peri,
@@ -597,14 +633,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
597 None, 633 None,
598 Some(sd.map_into()), 634 Some(sd.map_into()),
599 Some(fs.map_into()), 635 Some(fs.map_into()),
600 RingBuffer::Writable(unsafe { 636 Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
601 WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
602 }),
603 config, 637 config,
604 ) 638 )
605 } 639 }
606 640
607 pub fn new_asynchronous_transmitter_with_mclk_b( 641 pub fn new_asynchronous_block_b_with_mclk(
608 peri: impl Peripheral<P = T> + 'd, 642 peri: impl Peripheral<P = T> + 'd,
609 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 643 sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
610 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 644 sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
@@ -619,17 +653,19 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
619 { 653 {
620 into_ref!(mclk); 654 into_ref!(mclk);
621 655
622 mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull); 656 let (_sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
657
658 mclk.set_as_af(mclk.af_num(), ck_af_type);
623 mclk.set_speed(crate::gpio::Speed::VeryHigh); 659 mclk.set_speed(crate::gpio::Speed::VeryHigh);
624 660
625 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { 661 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
626 config.master_clock_divider = MasterClockDivider::Div1; 662 config.master_clock_divider = MasterClockDivider::Div1;
627 } 663 }
628 664
629 Self::new_asynchronous_transmitter_b(peri, sck, sd, fs, dma, dma_buf, config) 665 Self::new_asynchronous_block_b(peri, sck, sd, fs, dma, dma_buf, config)
630 } 666 }
631 667
632 pub fn new_asynchronous_transmitter_b( 668 pub fn new_asynchronous_block_b(
633 peri: impl Peripheral<P = T> + 'd, 669 peri: impl Peripheral<P = T> + 'd,
634 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 670 sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
635 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 671 sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
@@ -643,7 +679,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
643 { 679 {
644 into_ref!(dma, peri, sck, sd, fs); 680 into_ref!(dma, peri, sck, sd, fs);
645 681
646 let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode); 682 let (sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
647 683
648 sd.set_as_af(sd.af_num(), sd_af_type); 684 sd.set_as_af(sd.af_num(), sd_af_type);
649 sd.set_speed(crate::gpio::Speed::VeryHigh); 685 sd.set_speed(crate::gpio::Speed::VeryHigh);
@@ -653,13 +689,8 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
653 fs.set_as_af(fs.af_num(), ck_af_type); 689 fs.set_as_af(fs.af_num(), ck_af_type);
654 fs.set_speed(crate::gpio::Speed::VeryHigh); 690 fs.set_speed(crate::gpio::Speed::VeryHigh);
655 691
656 let request = dma.request();
657 let opts = TransferOptions {
658 half_transfer_ir: true,
659 ..Default::default()
660 };
661
662 let sub_block = SubBlock::B; 692 let sub_block = SubBlock::B;
693 let request = dma.request();
663 694
664 Self::new_inner( 695 Self::new_inner(
665 peri, 696 peri,
@@ -668,9 +699,92 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
668 None, 699 None,
669 Some(sd.map_into()), 700 Some(sd.map_into()),
670 Some(fs.map_into()), 701 Some(fs.map_into()),
671 RingBuffer::Writable(unsafe { 702 Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
672 WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts) 703 config,
673 }), 704 )
705 }
706
707 fn update_synchronous_config(config: &mut Config) {
708 config.mode = Mode::Slave;
709 config.is_sync_output = false;
710
711 #[cfg(any(sai_v1, sai_v2, sai_v3))]
712 {
713 config.sync_enable = SyncEnable::Internal;
714 }
715
716 #[cfg(any(sai_v4))]
717 {
718 //this must either be Internal or External
719 //The asynchronous sub-block on the same SAI needs to enable is_sync_output
720 assert!(config.sync_enable != SyncEnable::Asynchronous);
721 }
722 }
723
724 pub fn new_synchronous_block_a(
725 peri: impl Peripheral<P = T> + 'd,
726 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
727 dma: impl Peripheral<P = C> + 'd,
728 dma_buf: &'d mut [W],
729 mut config: Config,
730 ) -> Self
731 where
732 C: Channel + DmaA<T>,
733 {
734 Self::update_synchronous_config(&mut config);
735
736 into_ref!(dma, peri, sd);
737
738 let (sd_af_type, _ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
739
740 sd.set_as_af(sd.af_num(), sd_af_type);
741 sd.set_speed(crate::gpio::Speed::VeryHigh);
742
743 let sub_block = SubBlock::A;
744 let request = dma.request();
745
746 Self::new_inner(
747 peri,
748 sub_block,
749 None,
750 None,
751 Some(sd.map_into()),
752 None,
753 Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
754 config,
755 )
756 }
757
758 pub fn new_synchronous_block_b(
759 peri: impl Peripheral<P = T> + 'd,
760 sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
761 dma: impl Peripheral<P = C> + 'd,
762 dma_buf: &'d mut [W],
763 mut config: Config,
764 ) -> Self
765 where
766 C: Channel + DmaB<T>,
767 {
768 Self::update_synchronous_config(&mut config);
769
770 into_ref!(dma, peri, sd);
771
772 let (sd_af_type, _ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
773
774 sd.set_as_af(sd.af_num(), sd_af_type);
775 sd.set_speed(crate::gpio::Speed::VeryHigh);
776
777 let sub_block = SubBlock::B;
778 let request = dma.request();
779
780 Self::new_inner(
781 peri,
782 sub_block,
783 None,
784 None,
785 Some(sd.map_into()),
786 None,
787 Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
674 config, 788 config,
675 ) 789 )
676 } 790 }
@@ -704,12 +818,21 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
704 config: Config, 818 config: Config,
705 ) -> Self { 819 ) -> Self {
706 T::enable(); 820 T::enable();
707 T::reset(); 821
822 // can't reset here because the other sub-block might be in use
823
824 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
825 {
826 let ch = T::REGS.ch(sub_block as usize);
827 ch.cr1().modify(|w| w.set_saien(false));
828 }
708 829
709 #[cfg(any(sai_v4))] 830 #[cfg(any(sai_v4))]
710 { 831 {
711 // Not totally clear from the datasheet if this is right 832 // Not totally clear from the datasheet if this is right
712 // This is only used if using SyncEnable::External 833 // This is only used if using SyncEnable::External on the other SAI unit
834 // Syncing from SAIX subblock A to subblock B does not require this
835 // Only syncing from SAI1 subblock A/B to SAI2 subblock A/B
713 let value: u8 = if T::REGS.as_ptr() == stm32_metapac::SAI1.as_ptr() { 836 let value: u8 = if T::REGS.as_ptr() == stm32_metapac::SAI1.as_ptr() {
714 1 //this is SAI1, so sync with SAI2 837 1 //this is SAI1, so sync with SAI2
715 } else { 838 } else {
@@ -735,7 +858,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
735 let ch = T::REGS.ch(sub_block as usize); 858 let ch = T::REGS.ch(sub_block as usize);
736 ch.cr1().modify(|w| { 859 ch.cr1().modify(|w| {
737 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { 860 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
738 TxRx::Transmiter 861 TxRx::Transmitter
739 } else { 862 } else {
740 TxRx::Receiver 863 TxRx::Receiver
741 })); 864 }));
@@ -770,7 +893,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
770 w.set_fsoff(config.frame_sync_offset.fsoff()); 893 w.set_fsoff(config.frame_sync_offset.fsoff());
771 w.set_fspol(config.frame_sync_polarity.fspol()); 894 w.set_fspol(config.frame_sync_polarity.fspol());
772 w.set_fsdef(config.frame_sync_definition.fsdef()); 895 w.set_fsdef(config.frame_sync_definition.fsdef());
773 w.set_fsall(config.frame_sync_active_level_length.0 as u8); 896 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
774 w.set_frl(config.frame_length - 1); 897 w.set_frl(config.frame_length - 1);
775 }); 898 });
776 899
@@ -782,6 +905,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
782 }); 905 });
783 906
784 ch.cr1().modify(|w| w.set_saien(true)); 907 ch.cr1().modify(|w| w.set_saien(true));
908
909 if ch.cr1().read().saien() == false {
910 panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)");
911 }
785 } 912 }
786 913
787 Self { 914 Self {
@@ -795,6 +922,11 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
795 } 922 }
796 } 923 }
797 924
925 pub fn reset() {
926 T::enable();
927 T::reset();
928 }
929
798 pub fn flush(&mut self) { 930 pub fn flush(&mut self) {
799 let ch = T::REGS.ch(self.sub_block as usize); 931 let ch = T::REGS.ch(self.sub_block as usize);
800 ch.cr1().modify(|w| w.set_saien(false)); 932 ch.cr1().modify(|w| w.set_saien(false));