diff options
| author | Tyler Gilbert <[email protected]> | 2023-09-30 19:43:44 -0500 |
|---|---|---|
| committer | Tyler Gilbert <[email protected]> | 2023-09-30 19:43:44 -0500 |
| commit | d1f4511cd14e851b0fa8c54d45131095ee8edbe0 (patch) | |
| tree | e00088d20991f9634ab71e0bcc1814109f071ab1 | |
| parent | fa8d5da4a5c5270a66d4bdf59aa215c32b14ad43 (diff) | |
Issue #1986 update the SAI driver with receiver capability
| -rw-r--r-- | embassy-stm32/src/sai/mod.rs | 216 |
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; | |||
| 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 5 | 5 | ||
| 6 | pub use crate::dma::word; | 6 | pub use crate::dma::word; |
| 7 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; | 7 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; |
| 8 | use crate::gpio::sealed::{AFType, Pin as _}; | 8 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 9 | use crate::gpio::AnyPin; | 9 | use crate::gpio::AnyPin; |
| 10 | use crate::pac::sai::{vals, Sai as Regs}; | 10 | use 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)] |
| 51 | enum TxRx { | 51 | pub 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)] |
| 426 | pub struct Config { | 428 | pub 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 | ||
| 506 | enum RingBuffer<'d, C: Channel, W: word::Word> { | 510 | enum 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))] | ||
| 522 | fn 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 | |||
| 518 | pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { | 527 | pub 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 | ||
| 528 | impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | 537 | impl<'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)); |
