diff options
| author | xoviat <[email protected]> | 2025-11-25 15:20:54 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-25 15:20:54 +0000 |
| commit | 1f9c436afe6b0bcb306803d916e28df9e910479c (patch) | |
| tree | e2227fbac5f2c404130c444cd1b31a4c53b3b31e | |
| parent | 9e82cdc023cf001bd628ad68a712a41f8045455d (diff) | |
| parent | 2612f07f549fa0b9d8565ef760814d5f7ebea785 (diff) | |
Merge pull request #4944 from xoviat/timer
stm32: remove waveform method
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 174 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 17 |
4 files changed, 60 insertions, 149 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 6140b3238..949ea03b5 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - change: remove waveform timer method | ||
| 10 | - change: low power: store stop mode for dma channels | 11 | - change: low power: store stop mode for dma channels |
| 11 | - fix: Fixed ADC4 enable() for WBA | 12 | - fix: Fixed ADC4 enable() for WBA |
| 12 | - feat: allow use of anyadcchannel for adc4 | 13 | - feat: allow use of anyadcchannel for adc4 |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 6d4c70dff..77f19a37b 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -220,9 +220,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 220 | /// | 220 | /// |
| 221 | /// Note: | 221 | /// Note: |
| 222 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 222 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 223 | #[inline(always)] | ||
| 224 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 223 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { |
| 225 | self.inner.waveform_up(dma, channel, duty).await | 224 | self.inner.enable_channel(channel, true); |
| 225 | self.inner.enable_update_dma(true); | ||
| 226 | self.inner.setup_update_dma(dma, channel, duty).await; | ||
| 227 | self.inner.enable_update_dma(false); | ||
| 226 | } | 228 | } |
| 227 | 229 | ||
| 228 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. | 230 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. |
| @@ -254,7 +256,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 254 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 256 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 255 | /// switch this timer by using `time-driver-timX` feature. | 257 | /// switch this timer by using `time-driver-timX` feature. |
| 256 | /// | 258 | /// |
| 257 | #[inline(always)] | ||
| 258 | pub async fn waveform_up_multi_channel( | 259 | pub async fn waveform_up_multi_channel( |
| 259 | &mut self, | 260 | &mut self, |
| 260 | dma: Peri<'_, impl super::UpDma<T>>, | 261 | dma: Peri<'_, impl super::UpDma<T>>, |
| @@ -262,15 +263,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 262 | ending_channel: Channel, | 263 | ending_channel: Channel, |
| 263 | duty: &[u16], | 264 | duty: &[u16], |
| 264 | ) { | 265 | ) { |
| 266 | self.inner.enable_update_dma(true); | ||
| 265 | self.inner | 267 | self.inner |
| 266 | .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) | 268 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
| 267 | .await; | 269 | .await; |
| 268 | } | 270 | self.inner.enable_update_dma(false); |
| 269 | |||
| 270 | /// Generate a sequence of PWM waveform | ||
| 271 | #[inline(always)] | ||
| 272 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | ||
| 273 | self.inner.waveform(dma, duty).await; | ||
| 274 | } | 271 | } |
| 275 | } | 272 | } |
| 276 | 273 | ||
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index f0105ece8..f986c8dab 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -13,9 +13,10 @@ use embassy_hal_internal::Peri; | |||
| 13 | pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; | 13 | pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; |
| 14 | 14 | ||
| 15 | use super::*; | 15 | use super::*; |
| 16 | use crate::dma::Transfer; | ||
| 16 | use crate::pac::timer::vals; | 17 | use crate::pac::timer::vals; |
| 18 | use crate::rcc; | ||
| 17 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| 18 | use crate::{dma, rcc}; | ||
| 19 | 20 | ||
| 20 | /// Input capture mode. | 21 | /// Input capture mode. |
| 21 | #[derive(Clone, Copy)] | 22 | #[derive(Clone, Copy)] |
| @@ -663,25 +664,51 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 663 | /// | 664 | /// |
| 664 | /// Note: | 665 | /// Note: |
| 665 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 666 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 666 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 667 | pub fn setup_update_dma<'a>( |
| 668 | &mut self, | ||
| 669 | dma: Peri<'a, impl super::UpDma<T>>, | ||
| 670 | channel: Channel, | ||
| 671 | duty: &'a [u16], | ||
| 672 | ) -> Transfer<'a> { | ||
| 667 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 673 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 668 | let req = dma.request(); | 674 | let req = dma.request(); |
| 669 | 675 | ||
| 670 | let original_update_dma_state = self.get_update_dma_state(); | 676 | unsafe { |
| 677 | #[cfg(not(any(bdma, gpdma)))] | ||
| 678 | use crate::dma::{Burst, FifoThreshold}; | ||
| 679 | use crate::dma::{Transfer, TransferOptions}; | ||
| 671 | 680 | ||
| 672 | if !original_update_dma_state { | 681 | let dma_transfer_option = TransferOptions { |
| 673 | self.enable_update_dma(true); | 682 | #[cfg(not(any(bdma, gpdma)))] |
| 674 | } | 683 | fifo_threshold: Some(FifoThreshold::Full), |
| 684 | #[cfg(not(any(bdma, gpdma)))] | ||
| 685 | mburst: Burst::Incr8, | ||
| 686 | ..Default::default() | ||
| 687 | }; | ||
| 675 | 688 | ||
| 676 | self.waveform_helper(dma, req, channel, duty).await; | 689 | match self.bits() { |
| 690 | TimerBits::Bits16 => Transfer::new_write( | ||
| 691 | dma, | ||
| 692 | req, | ||
| 693 | duty, | ||
| 694 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 695 | dma_transfer_option, | ||
| 696 | ), | ||
| 697 | #[cfg(not(any(stm32l0)))] | ||
| 698 | TimerBits::Bits32 => { | ||
| 699 | #[cfg(not(any(bdma, gpdma)))] | ||
| 700 | panic!("unsupported timer bits"); | ||
| 677 | 701 | ||
| 678 | // Since DMA is closed before timer update event trigger DMA is turn off, | 702 | #[cfg(any(bdma, gpdma))] |
| 679 | // this can almost always trigger a DMA FIFO error. | 703 | Transfer::new_write( |
| 680 | // | 704 | dma, |
| 681 | // optional TODO: | 705 | req, |
| 682 | // clean FEIF after disable UDE | 706 | duty, |
| 683 | if !original_update_dma_state { | 707 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, |
| 684 | self.enable_update_dma(false); | 708 | dma_transfer_option, |
| 709 | ) | ||
| 710 | } | ||
| 711 | } | ||
| 685 | } | 712 | } |
| 686 | } | 713 | } |
| 687 | 714 | ||
| @@ -714,13 +741,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 714 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 741 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 715 | /// switch this timer by using `time-driver-timX` feature. | 742 | /// switch this timer by using `time-driver-timX` feature. |
| 716 | /// | 743 | /// |
| 717 | pub async fn waveform_up_multi_channel( | 744 | pub fn setup_update_dma_burst<'a>( |
| 718 | &mut self, | 745 | &mut self, |
| 719 | dma: Peri<'_, impl super::UpDma<T>>, | 746 | dma: Peri<'a, impl super::UpDma<T>>, |
| 720 | starting_channel: Channel, | 747 | starting_channel: Channel, |
| 721 | ending_channel: Channel, | 748 | ending_channel: Channel, |
| 722 | duty: &[u16], | 749 | duty: &'a [u16], |
| 723 | ) { | 750 | ) -> Transfer<'a> { |
| 724 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; | 751 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; |
| 725 | let start_ch_index = starting_channel.index(); | 752 | let start_ch_index = starting_channel.index(); |
| 726 | let end_ch_index = ending_channel.index(); | 753 | let end_ch_index = ending_channel.index(); |
| @@ -738,11 +765,6 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 738 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 765 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 739 | let req = dma.request(); | 766 | let req = dma.request(); |
| 740 | 767 | ||
| 741 | let original_update_dma_state = self.get_update_dma_state(); | ||
| 742 | if !original_update_dma_state { | ||
| 743 | self.enable_update_dma(true); | ||
| 744 | } | ||
| 745 | |||
| 746 | unsafe { | 768 | unsafe { |
| 747 | #[cfg(not(any(bdma, gpdma)))] | 769 | #[cfg(not(any(bdma, gpdma)))] |
| 748 | use crate::dma::{Burst, FifoThreshold}; | 770 | use crate::dma::{Burst, FifoThreshold}; |
| @@ -763,113 +785,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 763 | self.regs_gp16().dmar().as_ptr() as *mut u16, | 785 | self.regs_gp16().dmar().as_ptr() as *mut u16, |
| 764 | dma_transfer_option, | 786 | dma_transfer_option, |
| 765 | ) | 787 | ) |
| 766 | .await | ||
| 767 | }; | ||
| 768 | |||
| 769 | if !original_update_dma_state { | ||
| 770 | self.enable_update_dma(false); | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | /// Generate a sequence of PWM waveform | ||
| 775 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | ||
| 776 | use crate::pac::timer::vals::Ccds; | ||
| 777 | |||
| 778 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 779 | let req = dma.request(); | ||
| 780 | |||
| 781 | let cc_channel = C::CHANNEL; | ||
| 782 | |||
| 783 | let original_cc_dma_on_update = self.get_cc_dma_selection() == Ccds::ON_UPDATE; | ||
| 784 | let original_cc_dma_enabled = self.get_cc_dma_enable_state(cc_channel); | ||
| 785 | |||
| 786 | // redirect CC DMA request onto Update Event | ||
| 787 | if !original_cc_dma_on_update { | ||
| 788 | self.set_cc_dma_selection(Ccds::ON_UPDATE) | ||
| 789 | } | 788 | } |
| 790 | |||
| 791 | if !original_cc_dma_enabled { | ||
| 792 | self.set_cc_dma_enable_state(cc_channel, true); | ||
| 793 | } | ||
| 794 | |||
| 795 | self.waveform_helper(dma, req, cc_channel, duty).await; | ||
| 796 | |||
| 797 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, | ||
| 798 | // this can almost always trigger a DMA FIFO error. | ||
| 799 | // | ||
| 800 | // optional TODO: | ||
| 801 | // clean FEIF after disable UDE | ||
| 802 | if !original_cc_dma_enabled { | ||
| 803 | self.set_cc_dma_enable_state(cc_channel, false); | ||
| 804 | } | ||
| 805 | |||
| 806 | if !original_cc_dma_on_update { | ||
| 807 | self.set_cc_dma_selection(Ccds::ON_COMPARE) | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | async fn waveform_helper( | ||
| 812 | &mut self, | ||
| 813 | dma: Peri<'_, impl dma::Channel>, | ||
| 814 | req: dma::Request, | ||
| 815 | channel: Channel, | ||
| 816 | duty: &[u16], | ||
| 817 | ) { | ||
| 818 | let original_duty_state = self.get_compare_value(channel); | ||
| 819 | let original_enable_state = self.get_channel_enable_state(channel); | ||
| 820 | |||
| 821 | if !original_enable_state { | ||
| 822 | self.enable_channel(channel, true); | ||
| 823 | } | ||
| 824 | |||
| 825 | unsafe { | ||
| 826 | #[cfg(not(any(bdma, gpdma)))] | ||
| 827 | use crate::dma::{Burst, FifoThreshold}; | ||
| 828 | use crate::dma::{Transfer, TransferOptions}; | ||
| 829 | |||
| 830 | let dma_transfer_option = TransferOptions { | ||
| 831 | #[cfg(not(any(bdma, gpdma)))] | ||
| 832 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 833 | #[cfg(not(any(bdma, gpdma)))] | ||
| 834 | mburst: Burst::Incr8, | ||
| 835 | ..Default::default() | ||
| 836 | }; | ||
| 837 | |||
| 838 | match self.bits() { | ||
| 839 | TimerBits::Bits16 => { | ||
| 840 | Transfer::new_write( | ||
| 841 | dma, | ||
| 842 | req, | ||
| 843 | duty, | ||
| 844 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 845 | dma_transfer_option, | ||
| 846 | ) | ||
| 847 | .await | ||
| 848 | } | ||
| 849 | #[cfg(not(any(stm32l0)))] | ||
| 850 | TimerBits::Bits32 => { | ||
| 851 | #[cfg(not(any(bdma, gpdma)))] | ||
| 852 | panic!("unsupported timer bits"); | ||
| 853 | |||
| 854 | #[cfg(any(bdma, gpdma))] | ||
| 855 | Transfer::new_write( | ||
| 856 | dma, | ||
| 857 | req, | ||
| 858 | duty, | ||
| 859 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, | ||
| 860 | dma_transfer_option, | ||
| 861 | ) | ||
| 862 | .await | ||
| 863 | } | ||
| 864 | }; | ||
| 865 | }; | ||
| 866 | |||
| 867 | // restore output compare state | ||
| 868 | if !original_enable_state { | ||
| 869 | self.enable_channel(channel, false); | ||
| 870 | } | ||
| 871 | |||
| 872 | self.set_compare_value(channel, original_duty_state); | ||
| 873 | } | 789 | } |
| 874 | 790 | ||
| 875 | /// Get capture value for a channel. | 791 | /// Get capture value for a channel. |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 6c9ef17e0..eb1b66358 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -316,9 +316,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 316 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. | 316 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. |
| 317 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 317 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 318 | /// switch this timer by using `time-driver-timX` feature. | 318 | /// switch this timer by using `time-driver-timX` feature. |
| 319 | #[inline(always)] | ||
| 320 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 319 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { |
| 321 | self.inner.waveform_up(dma, channel, duty).await; | 320 | self.inner.enable_channel(channel, true); |
| 321 | self.inner.enable_update_dma(true); | ||
| 322 | self.inner.setup_update_dma(dma, channel, duty).await; | ||
| 323 | self.inner.enable_update_dma(false); | ||
| 322 | } | 324 | } |
| 323 | 325 | ||
| 324 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. | 326 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. |
| @@ -350,7 +352,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 350 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 352 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 351 | /// switch this timer by using `time-driver-timX` feature. | 353 | /// switch this timer by using `time-driver-timX` feature. |
| 352 | /// | 354 | /// |
| 353 | #[inline(always)] | ||
| 354 | pub async fn waveform_up_multi_channel( | 355 | pub async fn waveform_up_multi_channel( |
| 355 | &mut self, | 356 | &mut self, |
| 356 | dma: Peri<'_, impl super::UpDma<T>>, | 357 | dma: Peri<'_, impl super::UpDma<T>>, |
| @@ -358,15 +359,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 358 | ending_channel: Channel, | 359 | ending_channel: Channel, |
| 359 | duty: &[u16], | 360 | duty: &[u16], |
| 360 | ) { | 361 | ) { |
| 362 | self.inner.enable_update_dma(true); | ||
| 361 | self.inner | 363 | self.inner |
| 362 | .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) | 364 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
| 363 | .await; | 365 | .await; |
| 364 | } | 366 | self.inner.enable_update_dma(false); |
| 365 | |||
| 366 | /// Generate a sequence of PWM waveform | ||
| 367 | #[inline(always)] | ||
| 368 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | ||
| 369 | self.inner.waveform(dma, duty).await; | ||
| 370 | } | 367 | } |
| 371 | } | 368 | } |
| 372 | 369 | ||
