diff options
| -rw-r--r-- | embassy-stm32/src/sai/mod.rs | 288 |
1 files changed, 228 insertions, 60 deletions
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 4ffa6e9ce..2741b790b 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 | }, |
| @@ -206,12 +206,13 @@ impl Protocol { | |||
| 206 | } | 206 | } |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | #[derive(Copy, Clone)] | 209 | #[derive(Copy, Clone, PartialEq)] |
| 210 | pub enum SyncEnable { | 210 | pub enum SyncEnable { |
| 211 | Asynchronous, | 211 | Asynchronous, |
| 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, |
| @@ -498,42 +502,127 @@ impl Config { | |||
| 498 | } | 502 | } |
| 499 | 503 | ||
| 500 | #[derive(Copy, Clone)] | 504 | #[derive(Copy, Clone)] |
| 501 | pub enum SubBlock { | 505 | enum WhichSubBlock { |
| 502 | A = 0, | 506 | A = 0, |
| 503 | B = 1, | 507 | B = 1, |
| 504 | } | 508 | } |
| 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 | ||
| 512 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 515 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 513 | fn wdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W { | 516 | fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W { |
| 514 | let ch = w.ch(sub_block as usize); | 517 | let ch = w.ch(sub_block as usize); |
| 515 | ch.dr().as_ptr() as _ | 518 | ch.dr().as_ptr() as _ |
| 516 | } | 519 | } |
| 517 | 520 | ||
| 518 | pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { | 521 | pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { |
| 519 | _peri: PeripheralRef<'d, T>, | 522 | _peri: PeripheralRef<'d, T>, |
| 520 | sd: Option<PeripheralRef<'d, AnyPin>>, | 523 | sd: Option<PeripheralRef<'d, AnyPin>>, |
| 521 | fs: Option<PeripheralRef<'d, AnyPin>>, | 524 | fs: Option<PeripheralRef<'d, AnyPin>>, |
| 522 | sck: Option<PeripheralRef<'d, AnyPin>>, | 525 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| 523 | mclk: Option<PeripheralRef<'d, AnyPin>>, | 526 | mclk: Option<PeripheralRef<'d, AnyPin>>, |
| 524 | ring_buffer: RingBuffer<'d, C, W>, | 527 | ring_buffer: RingBuffer<'d, C, W>, |
| 525 | sub_block: SubBlock, | 528 | sub_block: WhichSubBlock, |
| 526 | } | 529 | } |
| 527 | 530 | ||
| 528 | impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | 531 | pub struct SubBlockA {} |
| 529 | fn get_transmitter_af_types(mode: Mode) -> (AFType, AFType) { | 532 | pub struct SubBlockB {} |
| 533 | |||
| 534 | pub struct Sai<'d, T: Instance> { | ||
| 535 | _peri: PeripheralRef<'d, T>, | ||
| 536 | sub_block_a_peri: Option<PeripheralRef<'d, T>>, | ||
| 537 | sub_block_b_peri: Option<PeripheralRef<'d, T>>, | ||
| 538 | } | ||
| 539 | |||
| 540 | // return the type for (sd, sck) | ||
| 541 | fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { | ||
| 542 | ( | ||
| 543 | //sd is defined by tx/rx mode | ||
| 544 | match tx_rx { | ||
| 545 | TxRx::Transmitter => AFType::OutputPushPull, | ||
| 546 | TxRx::Receiver => AFType::Input, | ||
| 547 | }, | ||
| 548 | //clocks (mclk, sck and fs) are defined by master/slave | ||
| 530 | match mode { | 549 | match mode { |
| 531 | Mode::Master => (AFType::OutputPushPull, AFType::OutputPushPull), | 550 | Mode::Master => AFType::OutputPushPull, |
| 532 | Mode::Slave => (AFType::OutputPushPull, AFType::Input), | 551 | Mode::Slave => AFType::Input, |
| 552 | }, | ||
| 553 | ) | ||
| 554 | } | ||
| 555 | |||
| 556 | fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 557 | dma: impl Peripheral<P = C> + 'd, | ||
| 558 | dma_buf: &'d mut [W], | ||
| 559 | request: Request, | ||
| 560 | sub_block: WhichSubBlock, | ||
| 561 | tx_rx: TxRx, | ||
| 562 | ) -> RingBuffer<'d, C, W> { | ||
| 563 | let opts = TransferOptions { | ||
| 564 | half_transfer_ir: true, | ||
| 565 | //the new_write() and new_read() always use circular mode | ||
| 566 | ..Default::default() | ||
| 567 | }; | ||
| 568 | match tx_rx { | ||
| 569 | TxRx::Transmitter => RingBuffer::Writable(unsafe { | ||
| 570 | WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) | ||
| 571 | }), | ||
| 572 | TxRx::Receiver => RingBuffer::Readable(unsafe { | ||
| 573 | ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) | ||
| 574 | }), | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | impl<'d, T: Instance> Sai<'d, T> { | ||
| 579 | pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { | ||
| 580 | T::enable(); | ||
| 581 | T::reset(); | ||
| 582 | |||
| 583 | Self { | ||
| 584 | _peri: unsafe { peri.clone_unchecked().into_ref() }, | ||
| 585 | sub_block_a_peri: Some(unsafe { peri.clone_unchecked().into_ref() }), | ||
| 586 | sub_block_b_peri: Some(peri.into_ref()), | ||
| 533 | } | 587 | } |
| 534 | } | 588 | } |
| 535 | 589 | ||
| 536 | pub fn new_asynchronous_transmitter_with_mclk_a( | 590 | pub fn take_sub_block_a(self: &mut Self) -> Option<PeripheralRef<'d, T>> { |
| 591 | if self.sub_block_a_peri.is_some() { | ||
| 592 | self.sub_block_a_peri.take() | ||
| 593 | } else { | ||
| 594 | None | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | pub fn take_sub_block_b(self: &mut Self) -> Option<PeripheralRef<'d, T>> { | ||
| 599 | if self.sub_block_b_peri.is_some() { | ||
| 600 | self.sub_block_b_peri.take() | ||
| 601 | } else { | ||
| 602 | None | ||
| 603 | } | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | fn update_synchronous_config(config: &mut Config) { | ||
| 608 | config.mode = Mode::Slave; | ||
| 609 | config.is_sync_output = false; | ||
| 610 | |||
| 611 | #[cfg(any(sai_v1, sai_v2, sai_v3))] | ||
| 612 | { | ||
| 613 | config.sync_enable = SyncEnable::Internal; | ||
| 614 | } | ||
| 615 | |||
| 616 | #[cfg(any(sai_v4))] | ||
| 617 | { | ||
| 618 | //this must either be Internal or External | ||
| 619 | //The asynchronous sub-block on the same SAI needs to enable is_sync_output | ||
| 620 | assert!(config.sync_enable != SyncEnable::Asynchronous); | ||
| 621 | } | ||
| 622 | } | ||
| 623 | |||
| 624 | impl SubBlockA { | ||
| 625 | pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 537 | peri: impl Peripheral<P = T> + 'd, | 626 | peri: impl Peripheral<P = T> + 'd, |
| 538 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, | 627 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, |
| 539 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | 628 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, |
| @@ -542,23 +631,25 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 542 | dma: impl Peripheral<P = C> + 'd, | 631 | dma: impl Peripheral<P = C> + 'd, |
| 543 | dma_buf: &'d mut [W], | 632 | dma_buf: &'d mut [W], |
| 544 | mut config: Config, | 633 | mut config: Config, |
| 545 | ) -> Self | 634 | ) -> SubBlock<T, C, W> |
| 546 | where | 635 | where |
| 547 | C: Channel + DmaA<T>, | 636 | C: Channel + DmaA<T>, |
| 548 | { | 637 | { |
| 549 | into_ref!(mclk); | 638 | into_ref!(mclk); |
| 550 | 639 | ||
| 551 | mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull); | 640 | let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 641 | |||
| 642 | mclk.set_as_af(mclk.af_num(), ck_af_type); | ||
| 552 | mclk.set_speed(crate::gpio::Speed::VeryHigh); | 643 | mclk.set_speed(crate::gpio::Speed::VeryHigh); |
| 553 | 644 | ||
| 554 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { | 645 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { |
| 555 | config.master_clock_divider = MasterClockDivider::Div1; | 646 | config.master_clock_divider = MasterClockDivider::Div1; |
| 556 | } | 647 | } |
| 557 | 648 | ||
| 558 | Self::new_asynchronous_transmitter_a(peri, sck, sd, fs, dma, dma_buf, config) | 649 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) |
| 559 | } | 650 | } |
| 560 | 651 | ||
| 561 | pub fn new_asynchronous_transmitter_a( | 652 | pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( |
| 562 | peri: impl Peripheral<P = T> + 'd, | 653 | peri: impl Peripheral<P = T> + 'd, |
| 563 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, | 654 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, |
| 564 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | 655 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, |
| @@ -566,13 +657,13 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 566 | dma: impl Peripheral<P = C> + 'd, | 657 | dma: impl Peripheral<P = C> + 'd, |
| 567 | dma_buf: &'d mut [W], | 658 | dma_buf: &'d mut [W], |
| 568 | config: Config, | 659 | config: Config, |
| 569 | ) -> Self | 660 | ) -> SubBlock<T, C, W> |
| 570 | where | 661 | where |
| 571 | C: Channel + DmaA<T>, | 662 | C: Channel + DmaA<T>, |
| 572 | { | 663 | { |
| 573 | into_ref!(peri, dma, sck, sd, fs); | 664 | into_ref!(peri, dma, sck, sd, fs); |
| 574 | 665 | ||
| 575 | let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode); | 666 | let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 576 | sd.set_as_af(sd.af_num(), sd_af_type); | 667 | sd.set_as_af(sd.af_num(), sd_af_type); |
| 577 | sd.set_speed(crate::gpio::Speed::VeryHigh); | 668 | sd.set_speed(crate::gpio::Speed::VeryHigh); |
| 578 | 669 | ||
| @@ -581,30 +672,58 @@ 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); | 672 | fs.set_as_af(fs.af_num(), ck_af_type); |
| 582 | fs.set_speed(crate::gpio::Speed::VeryHigh); | 673 | fs.set_speed(crate::gpio::Speed::VeryHigh); |
| 583 | 674 | ||
| 675 | let sub_block = WhichSubBlock::A; | ||
| 584 | let request = dma.request(); | 676 | let request = dma.request(); |
| 585 | let opts = TransferOptions { | ||
| 586 | half_transfer_ir: true, | ||
| 587 | circular: true, | ||
| 588 | ..Default::default() | ||
| 589 | }; | ||
| 590 | 677 | ||
| 591 | let sub_block = SubBlock::A; | 678 | SubBlock::new_inner( |
| 592 | |||
| 593 | Self::new_inner( | ||
| 594 | peri, | 679 | peri, |
| 595 | sub_block, | 680 | sub_block, |
| 596 | Some(sck.map_into()), | 681 | Some(sck.map_into()), |
| 597 | None, | 682 | None, |
| 598 | Some(sd.map_into()), | 683 | Some(sd.map_into()), |
| 599 | Some(fs.map_into()), | 684 | Some(fs.map_into()), |
| 600 | RingBuffer::Writable(unsafe { | 685 | get_ring_buffer::<T, C, W>(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, | 686 | config, |
| 604 | ) | 687 | ) |
| 605 | } | 688 | } |
| 606 | 689 | ||
| 607 | pub fn new_asynchronous_transmitter_with_mclk_b( | 690 | pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( |
| 691 | peri: impl Peripheral<P = T> + 'd, | ||
| 692 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | ||
| 693 | dma: impl Peripheral<P = C> + 'd, | ||
| 694 | dma_buf: &'d mut [W], | ||
| 695 | mut config: Config, | ||
| 696 | ) -> SubBlock<T, C, W> | ||
| 697 | where | ||
| 698 | C: Channel + DmaA<T>, | ||
| 699 | { | ||
| 700 | update_synchronous_config(&mut config); | ||
| 701 | |||
| 702 | into_ref!(dma, peri, sd); | ||
| 703 | |||
| 704 | let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); | ||
| 705 | |||
| 706 | sd.set_as_af(sd.af_num(), sd_af_type); | ||
| 707 | sd.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 708 | |||
| 709 | let sub_block = WhichSubBlock::A; | ||
| 710 | let request = dma.request(); | ||
| 711 | |||
| 712 | SubBlock::new_inner( | ||
| 713 | peri, | ||
| 714 | sub_block, | ||
| 715 | None, | ||
| 716 | None, | ||
| 717 | Some(sd.map_into()), | ||
| 718 | None, | ||
| 719 | get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), | ||
| 720 | config, | ||
| 721 | ) | ||
| 722 | } | ||
| 723 | } | ||
| 724 | |||
| 725 | impl SubBlockB { | ||
| 726 | pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 608 | peri: impl Peripheral<P = T> + 'd, | 727 | peri: impl Peripheral<P = T> + 'd, |
| 609 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, | 728 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, |
| 610 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | 729 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, |
| @@ -613,23 +732,25 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 613 | dma: impl Peripheral<P = C> + 'd, | 732 | dma: impl Peripheral<P = C> + 'd, |
| 614 | dma_buf: &'d mut [W], | 733 | dma_buf: &'d mut [W], |
| 615 | mut config: Config, | 734 | mut config: Config, |
| 616 | ) -> Self | 735 | ) -> SubBlock<T, C, W> |
| 617 | where | 736 | where |
| 618 | C: Channel + DmaB<T>, | 737 | C: Channel + DmaB<T>, |
| 619 | { | 738 | { |
| 620 | into_ref!(mclk); | 739 | into_ref!(mclk); |
| 621 | 740 | ||
| 622 | mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull); | 741 | let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 742 | |||
| 743 | mclk.set_as_af(mclk.af_num(), ck_af_type); | ||
| 623 | mclk.set_speed(crate::gpio::Speed::VeryHigh); | 744 | mclk.set_speed(crate::gpio::Speed::VeryHigh); |
| 624 | 745 | ||
| 625 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { | 746 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { |
| 626 | config.master_clock_divider = MasterClockDivider::Div1; | 747 | config.master_clock_divider = MasterClockDivider::Div1; |
| 627 | } | 748 | } |
| 628 | 749 | ||
| 629 | Self::new_asynchronous_transmitter_b(peri, sck, sd, fs, dma, dma_buf, config) | 750 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) |
| 630 | } | 751 | } |
| 631 | 752 | ||
| 632 | pub fn new_asynchronous_transmitter_b( | 753 | pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( |
| 633 | peri: impl Peripheral<P = T> + 'd, | 754 | peri: impl Peripheral<P = T> + 'd, |
| 634 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, | 755 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, |
| 635 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | 756 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, |
| @@ -637,13 +758,13 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 637 | dma: impl Peripheral<P = C> + 'd, | 758 | dma: impl Peripheral<P = C> + 'd, |
| 638 | dma_buf: &'d mut [W], | 759 | dma_buf: &'d mut [W], |
| 639 | config: Config, | 760 | config: Config, |
| 640 | ) -> Self | 761 | ) -> SubBlock<T, C, W> |
| 641 | where | 762 | where |
| 642 | C: Channel + DmaB<T>, | 763 | C: Channel + DmaB<T>, |
| 643 | { | 764 | { |
| 644 | into_ref!(dma, peri, sck, sd, fs); | 765 | into_ref!(dma, peri, sck, sd, fs); |
| 645 | 766 | ||
| 646 | let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode); | 767 | let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 647 | 768 | ||
| 648 | sd.set_as_af(sd.af_num(), sd_af_type); | 769 | sd.set_as_af(sd.af_num(), sd_af_type); |
| 649 | sd.set_speed(crate::gpio::Speed::VeryHigh); | 770 | sd.set_speed(crate::gpio::Speed::VeryHigh); |
| @@ -653,28 +774,57 @@ 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); | 774 | fs.set_as_af(fs.af_num(), ck_af_type); |
| 654 | fs.set_speed(crate::gpio::Speed::VeryHigh); | 775 | fs.set_speed(crate::gpio::Speed::VeryHigh); |
| 655 | 776 | ||
| 777 | let sub_block = WhichSubBlock::B; | ||
| 656 | let request = dma.request(); | 778 | let request = dma.request(); |
| 657 | let opts = TransferOptions { | ||
| 658 | half_transfer_ir: true, | ||
| 659 | ..Default::default() | ||
| 660 | }; | ||
| 661 | |||
| 662 | let sub_block = SubBlock::B; | ||
| 663 | 779 | ||
| 664 | Self::new_inner( | 780 | SubBlock::new_inner( |
| 665 | peri, | 781 | peri, |
| 666 | sub_block, | 782 | sub_block, |
| 667 | Some(sck.map_into()), | 783 | Some(sck.map_into()), |
| 668 | None, | 784 | None, |
| 669 | Some(sd.map_into()), | 785 | Some(sd.map_into()), |
| 670 | Some(fs.map_into()), | 786 | Some(fs.map_into()), |
| 671 | RingBuffer::Writable(unsafe { | 787 | get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), |
| 672 | WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts) | 788 | config, |
| 673 | }), | 789 | ) |
| 790 | } | ||
| 791 | |||
| 792 | pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 793 | peri: impl Peripheral<P = T> + 'd, | ||
| 794 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | ||
| 795 | dma: impl Peripheral<P = C> + 'd, | ||
| 796 | dma_buf: &'d mut [W], | ||
| 797 | mut config: Config, | ||
| 798 | ) -> SubBlock<T, C, W> | ||
| 799 | where | ||
| 800 | C: Channel + DmaB<T>, | ||
| 801 | { | ||
| 802 | update_synchronous_config(&mut config); | ||
| 803 | |||
| 804 | into_ref!(dma, peri, sd); | ||
| 805 | |||
| 806 | let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); | ||
| 807 | |||
| 808 | sd.set_as_af(sd.af_num(), sd_af_type); | ||
| 809 | sd.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 810 | |||
| 811 | let sub_block = WhichSubBlock::B; | ||
| 812 | let request = dma.request(); | ||
| 813 | |||
| 814 | SubBlock::new_inner( | ||
| 815 | peri, | ||
| 816 | sub_block, | ||
| 817 | None, | ||
| 818 | None, | ||
| 819 | Some(sd.map_into()), | ||
| 820 | None, | ||
| 821 | get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), | ||
| 674 | config, | 822 | config, |
| 675 | ) | 823 | ) |
| 676 | } | 824 | } |
| 825 | } | ||
| 677 | 826 | ||
| 827 | impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | ||
| 678 | pub fn start(self: &mut Self) { | 828 | pub fn start(self: &mut Self) { |
| 679 | match self.ring_buffer { | 829 | match self.ring_buffer { |
| 680 | RingBuffer::Writable(ref mut rb) => { | 830 | RingBuffer::Writable(ref mut rb) => { |
| @@ -695,7 +845,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 695 | 845 | ||
| 696 | fn new_inner( | 846 | fn new_inner( |
| 697 | peri: impl Peripheral<P = T> + 'd, | 847 | peri: impl Peripheral<P = T> + 'd, |
| 698 | sub_block: SubBlock, | 848 | sub_block: WhichSubBlock, |
| 699 | sck: Option<PeripheralRef<'d, AnyPin>>, | 849 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| 700 | mclk: Option<PeripheralRef<'d, AnyPin>>, | 850 | mclk: Option<PeripheralRef<'d, AnyPin>>, |
| 701 | sd: Option<PeripheralRef<'d, AnyPin>>, | 851 | sd: Option<PeripheralRef<'d, AnyPin>>, |
| @@ -704,12 +854,21 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 704 | config: Config, | 854 | config: Config, |
| 705 | ) -> Self { | 855 | ) -> Self { |
| 706 | T::enable(); | 856 | T::enable(); |
| 707 | T::reset(); | 857 | |
| 858 | // can't reset here because the other sub-block might be in use | ||
| 859 | |||
| 860 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | ||
| 861 | { | ||
| 862 | let ch = T::REGS.ch(sub_block as usize); | ||
| 863 | ch.cr1().modify(|w| w.set_saien(false)); | ||
| 864 | } | ||
| 708 | 865 | ||
| 709 | #[cfg(any(sai_v4))] | 866 | #[cfg(any(sai_v4))] |
| 710 | { | 867 | { |
| 711 | // Not totally clear from the datasheet if this is right | 868 | // Not totally clear from the datasheet if this is right |
| 712 | // This is only used if using SyncEnable::External | 869 | // This is only used if using SyncEnable::External on the other SAI unit |
| 870 | // Syncing from SAIX subblock A to subblock B does not require this | ||
| 871 | // 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() { | 872 | let value: u8 = if T::REGS.as_ptr() == stm32_metapac::SAI1.as_ptr() { |
| 714 | 1 //this is SAI1, so sync with SAI2 | 873 | 1 //this is SAI1, so sync with SAI2 |
| 715 | } else { | 874 | } else { |
| @@ -721,8 +880,8 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 721 | 880 | ||
| 722 | if config.is_sync_output { | 881 | if config.is_sync_output { |
| 723 | let syncout: u8 = match sub_block { | 882 | let syncout: u8 = match sub_block { |
| 724 | SubBlock::A => 0b01, | 883 | WhichSubBlock::A => 0b01, |
| 725 | SubBlock::B => 0b10, | 884 | WhichSubBlock::B => 0b10, |
| 726 | }; | 885 | }; |
| 727 | T::REGS.gcr().modify(|w| { | 886 | T::REGS.gcr().modify(|w| { |
| 728 | w.set_syncout(syncout); | 887 | w.set_syncout(syncout); |
| @@ -735,7 +894,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); | 894 | let ch = T::REGS.ch(sub_block as usize); |
| 736 | ch.cr1().modify(|w| { | 895 | ch.cr1().modify(|w| { |
| 737 | w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { | 896 | w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { |
| 738 | TxRx::Transmiter | 897 | TxRx::Transmitter |
| 739 | } else { | 898 | } else { |
| 740 | TxRx::Receiver | 899 | TxRx::Receiver |
| 741 | })); | 900 | })); |
| @@ -770,7 +929,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 770 | w.set_fsoff(config.frame_sync_offset.fsoff()); | 929 | w.set_fsoff(config.frame_sync_offset.fsoff()); |
| 771 | w.set_fspol(config.frame_sync_polarity.fspol()); | 930 | w.set_fspol(config.frame_sync_polarity.fspol()); |
| 772 | w.set_fsdef(config.frame_sync_definition.fsdef()); | 931 | w.set_fsdef(config.frame_sync_definition.fsdef()); |
| 773 | w.set_fsall(config.frame_sync_active_level_length.0 as u8); | 932 | w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); |
| 774 | w.set_frl(config.frame_length - 1); | 933 | w.set_frl(config.frame_length - 1); |
| 775 | }); | 934 | }); |
| 776 | 935 | ||
| @@ -782,6 +941,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 782 | }); | 941 | }); |
| 783 | 942 | ||
| 784 | ch.cr1().modify(|w| w.set_saien(true)); | 943 | ch.cr1().modify(|w| w.set_saien(true)); |
| 944 | |||
| 945 | if ch.cr1().read().saien() == false { | ||
| 946 | panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)"); | ||
| 947 | } | ||
| 785 | } | 948 | } |
| 786 | 949 | ||
| 787 | Self { | 950 | Self { |
| @@ -795,6 +958,11 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 795 | } | 958 | } |
| 796 | } | 959 | } |
| 797 | 960 | ||
| 961 | pub fn reset() { | ||
| 962 | T::enable(); | ||
| 963 | T::reset(); | ||
| 964 | } | ||
| 965 | |||
| 798 | pub fn flush(&mut self) { | 966 | pub fn flush(&mut self) { |
| 799 | let ch = T::REGS.ch(self.sub_block as usize); | 967 | let ch = T::REGS.ch(self.sub_block as usize); |
| 800 | ch.cr1().modify(|w| w.set_saien(false)); | 968 | ch.cr1().modify(|w| w.set_saien(false)); |
| @@ -842,7 +1010,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { | |||
| 842 | } | 1010 | } |
| 843 | } | 1011 | } |
| 844 | 1012 | ||
| 845 | impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { | 1013 | impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { |
| 846 | fn drop(&mut self) { | 1014 | fn drop(&mut self) { |
| 847 | let ch = T::REGS.ch(self.sub_block as usize); | 1015 | let ch = T::REGS.ch(self.sub_block as usize); |
| 848 | ch.cr1().modify(|w| w.set_saien(false)); | 1016 | ch.cr1().modify(|w| w.set_saien(false)); |
| @@ -886,9 +1054,9 @@ foreach_peripheral!( | |||
| 886 | }; | 1054 | }; |
| 887 | ); | 1055 | ); |
| 888 | 1056 | ||
| 889 | impl<'d, T: Instance, C: Channel, W: word::Word> SetConfig for Sai<'d, T, C, W> { | 1057 | impl<'d, T: Instance> SetConfig for Sai<'d, T> { |
| 890 | type Config = Config; | 1058 | type Config = Config; |
| 891 | fn set_config(&mut self, config: &Self::Config) { | 1059 | fn set_config(&mut self, _config: &Self::Config) { |
| 892 | self.reconfigure(*config); | 1060 | // self.reconfigure(*config); |
| 893 | } | 1061 | } |
| 894 | } | 1062 | } |
