diff options
| author | xoviat <[email protected]> | 2025-12-01 08:39:32 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-12-01 08:39:32 -0600 |
| commit | b466ba29d2857815e5b25af7d8ab82d5b7e05e30 (patch) | |
| tree | 36b0439a19e9b3649f89d72db6226b77ae4ec0fc /embassy-stm32/src/timer | |
| parent | edb14f8c0966e1d22f396cbd631e5835a9a5104b (diff) | |
timer: allow 16 bit dma buffers for 32 bit timers.
Diffstat (limited to 'embassy-stm32/src/timer')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 20 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/ringbuffered.rs | 27 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 24 |
4 files changed, 49 insertions, 40 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 996759060..b9434d37b 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -8,6 +8,7 @@ use super::low_level::{CountingMode, OutputPolarity, Timer}; | |||
| 8 | use super::simple_pwm::PwmPin; | 8 | use super::simple_pwm::PwmPin; |
| 9 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; | 9 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; |
| 10 | use crate::Peri; | 10 | use crate::Peri; |
| 11 | use crate::dma::word::Word; | ||
| 11 | use crate::gpio::{AnyPin, OutputType}; | 12 | use crate::gpio::{AnyPin, OutputType}; |
| 12 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 13 | use crate::timer::TimerChannel; | 14 | use crate::timer::TimerChannel; |
| @@ -220,8 +221,14 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 220 | /// | 221 | /// |
| 221 | /// Note: | 222 | /// Note: |
| 222 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 223 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 223 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[T::Word]) { | 224 | pub async fn waveform_up<W: Word + Into<T::Word>>( |
| 225 | &mut self, | ||
| 226 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 227 | channel: Channel, | ||
| 228 | duty: &[W], | ||
| 229 | ) { | ||
| 224 | self.inner.enable_channel(channel, true); | 230 | self.inner.enable_channel(channel, true); |
| 231 | self.inner.set_compare_value(channel, 0.into()); | ||
| 225 | self.inner.enable_update_dma(true); | 232 | self.inner.enable_update_dma(true); |
| 226 | self.inner.setup_update_dma(dma, channel, duty).await; | 233 | self.inner.setup_update_dma(dma, channel, duty).await; |
| 227 | self.inner.enable_update_dma(false); | 234 | self.inner.enable_update_dma(false); |
| @@ -256,18 +263,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 256 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 263 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 257 | /// switch this timer by using `time-driver-timX` feature. | 264 | /// switch this timer by using `time-driver-timX` feature. |
| 258 | /// | 265 | /// |
| 259 | pub async fn waveform_up_multi_channel( | 266 | pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>( |
| 260 | &mut self, | 267 | &mut self, |
| 261 | dma: Peri<'_, impl super::UpDma<T>>, | 268 | dma: Peri<'_, impl super::UpDma<T>>, |
| 262 | starting_channel: Channel, | 269 | starting_channel: Channel, |
| 263 | ending_channel: Channel, | 270 | ending_channel: Channel, |
| 264 | duty: &[T::Word], | 271 | duty: &[W], |
| 265 | ) { | 272 | ) { |
| 266 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 273 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| 267 | .iter() | 274 | .iter() |
| 268 | .filter(|ch| ch.index() >= starting_channel.index()) | 275 | .filter(|ch| ch.index() >= starting_channel.index()) |
| 269 | .filter(|ch| ch.index() <= ending_channel.index()) | 276 | .filter(|ch| ch.index() <= ending_channel.index()) |
| 270 | .for_each(|ch| self.inner.enable_channel(*ch, true)); | 277 | .for_each(|ch| { |
| 278 | self.inner.enable_channel(*ch, true); | ||
| 279 | self.inner.set_compare_value(*ch, 0.into()); | ||
| 280 | }); | ||
| 271 | self.inner.enable_update_dma(true); | 281 | self.inner.enable_update_dma(true); |
| 272 | self.inner | 282 | self.inner |
| 273 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) | 283 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 73a81bff1..1af66aec1 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -628,12 +628,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | /// Setup a ring buffer for the channel | 630 | /// Setup a ring buffer for the channel |
| 631 | pub fn setup_ring_buffer<'a>( | 631 | pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>>( |
| 632 | &mut self, | 632 | &mut self, |
| 633 | dma: Peri<'a, impl super::UpDma<T>>, | 633 | dma: Peri<'a, impl super::UpDma<T>>, |
| 634 | channel: Channel, | 634 | channel: Channel, |
| 635 | dma_buf: &'a mut [T::Word], | 635 | dma_buf: &'a mut [W], |
| 636 | ) -> WritableRingBuffer<'a, T::Word> { | 636 | ) -> WritableRingBuffer<'a, W> { |
| 637 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 637 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 638 | let req = dma.request(); | 638 | let req = dma.request(); |
| 639 | 639 | ||
| @@ -653,7 +653,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 653 | WritableRingBuffer::new( | 653 | WritableRingBuffer::new( |
| 654 | dma, | 654 | dma, |
| 655 | req, | 655 | req, |
| 656 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut T::Word, | 656 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W, |
| 657 | dma_buf, | 657 | dma_buf, |
| 658 | dma_transfer_option, | 658 | dma_transfer_option, |
| 659 | ) | 659 | ) |
| @@ -664,11 +664,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 664 | /// | 664 | /// |
| 665 | /// Note: | 665 | /// Note: |
| 666 | /// 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. |
| 667 | pub fn setup_update_dma<'a>( | 667 | pub fn setup_update_dma<'a, W: Word + Into<T::Word>>( |
| 668 | &mut self, | 668 | &mut self, |
| 669 | dma: Peri<'a, impl super::UpDma<T>>, | 669 | dma: Peri<'a, impl super::UpDma<T>>, |
| 670 | channel: Channel, | 670 | channel: Channel, |
| 671 | duty: &'a [T::Word], | 671 | duty: &'a [W], |
| 672 | ) -> Transfer<'a> { | 672 | ) -> Transfer<'a> { |
| 673 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 673 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 674 | let req = dma.request(); | 674 | let req = dma.request(); |
| @@ -690,7 +690,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 690 | dma, | 690 | dma, |
| 691 | req, | 691 | req, |
| 692 | duty, | 692 | duty, |
| 693 | self.regs_gp16().ccr(channel.index()).as_ptr() as *mut T::Word, | 693 | self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W, |
| 694 | dma_transfer_option, | 694 | dma_transfer_option, |
| 695 | ) | 695 | ) |
| 696 | } | 696 | } |
| @@ -725,12 +725,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 725 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 725 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 726 | /// switch this timer by using `time-driver-timX` feature. | 726 | /// switch this timer by using `time-driver-timX` feature. |
| 727 | /// | 727 | /// |
| 728 | pub fn setup_update_dma_burst<'a>( | 728 | pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>( |
| 729 | &mut self, | 729 | &mut self, |
| 730 | dma: Peri<'a, impl super::UpDma<T>>, | 730 | dma: Peri<'a, impl super::UpDma<T>>, |
| 731 | starting_channel: Channel, | 731 | starting_channel: Channel, |
| 732 | ending_channel: Channel, | 732 | ending_channel: Channel, |
| 733 | duty: &'a [T::Word], | 733 | duty: &'a [W], |
| 734 | ) -> Transfer<'a> { | 734 | ) -> Transfer<'a> { |
| 735 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; | 735 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; |
| 736 | let start_ch_index = starting_channel.index(); | 736 | let start_ch_index = starting_channel.index(); |
| @@ -766,7 +766,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 766 | dma, | 766 | dma, |
| 767 | req, | 767 | req, |
| 768 | duty, | 768 | duty, |
| 769 | self.regs_gp16().dmar().as_ptr() as *mut T::Word, | 769 | self.regs_gp16().dmar().as_ptr() as *mut W, |
| 770 | dma_transfer_option, | 770 | dma_transfer_option, |
| 771 | ) | 771 | ) |
| 772 | } | 772 | } |
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs index f5a4328d1..fbb6b19ea 100644 --- a/embassy-stm32/src/timer/ringbuffered.rs +++ b/embassy-stm32/src/timer/ringbuffered.rs | |||
| @@ -7,6 +7,7 @@ use super::low_level::Timer; | |||
| 7 | use super::{Channel, GeneralInstance4Channel}; | 7 | use super::{Channel, GeneralInstance4Channel}; |
| 8 | use crate::dma::WritableRingBuffer; | 8 | use crate::dma::WritableRingBuffer; |
| 9 | use crate::dma::ringbuffer::Error; | 9 | use crate::dma::ringbuffer::Error; |
| 10 | use crate::dma::word::Word; | ||
| 10 | 11 | ||
| 11 | /// A PWM channel that uses a DMA ring buffer for continuous waveform generation. | 12 | /// A PWM channel that uses a DMA ring buffer for continuous waveform generation. |
| 12 | /// | 13 | /// |
| @@ -23,17 +24,17 @@ use crate::dma::ringbuffer::Error; | |||
| 23 | /// channel.start(); // Start DMA transfer | 24 | /// channel.start(); // Start DMA transfer |
| 24 | /// channel.write(&[100, 200, 300]).ok(); // Update duty cycles | 25 | /// channel.write(&[100, 200, 300]).ok(); // Update duty cycles |
| 25 | /// ``` | 26 | /// ``` |
| 26 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { | 27 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> { |
| 27 | timer: ManuallyDrop<Timer<'d, T>>, | 28 | timer: ManuallyDrop<Timer<'d, T>>, |
| 28 | ring_buf: WritableRingBuffer<'d, T::Word>, | 29 | ring_buf: WritableRingBuffer<'d, W>, |
| 29 | channel: Channel, | 30 | channel: Channel, |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | 33 | impl<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> RingBufferedPwmChannel<'d, T, W> { |
| 33 | pub(crate) fn new( | 34 | pub(crate) fn new( |
| 34 | timer: ManuallyDrop<Timer<'d, T>>, | 35 | timer: ManuallyDrop<Timer<'d, T>>, |
| 35 | channel: Channel, | 36 | channel: Channel, |
| 36 | ring_buf: WritableRingBuffer<'d, T::Word>, | 37 | ring_buf: WritableRingBuffer<'d, W>, |
| 37 | ) -> Self { | 38 | ) -> Self { |
| 38 | Self { | 39 | Self { |
| 39 | timer, | 40 | timer, |
| @@ -55,18 +56,18 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | |||
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. | 58 | /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. |
| 58 | pub fn write_immediate(&mut self, buf: &[T::Word]) -> Result<(usize, usize), Error> { | 59 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 59 | self.ring_buf.write_immediate(buf) | 60 | self.ring_buf.write_immediate(buf) |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | /// Write elements from the ring buffer | 63 | /// Write elements from the ring buffer |
| 63 | /// Return a tuple of the length written and the length remaining in the buffer | 64 | /// Return a tuple of the length written and the length remaining in the buffer |
| 64 | pub fn write(&mut self, buf: &[T::Word]) -> Result<(usize, usize), Error> { | 65 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 65 | self.ring_buf.write(buf) | 66 | self.ring_buf.write(buf) |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | /// Write an exact number of elements to the ringbuffer. | 69 | /// Write an exact number of elements to the ringbuffer. |
| 69 | pub async fn write_exact(&mut self, buffer: &[T::Word]) -> Result<usize, Error> { | 70 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> { |
| 70 | self.ring_buf.write_exact(buffer).await | 71 | self.ring_buf.write_exact(buffer).await |
| 71 | } | 72 | } |
| 72 | 73 | ||
| @@ -155,15 +156,3 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | |||
| 155 | self.timer.set_output_compare_mode(self.channel, mode); | 156 | self.timer.set_output_compare_mode(self.channel, mode); |
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | |||
| 159 | /// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. | ||
| 160 | pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { | ||
| 161 | /// Channel 1 | ||
| 162 | pub ch1: RingBufferedPwmChannel<'d, T>, | ||
| 163 | /// Channel 2 | ||
| 164 | pub ch2: RingBufferedPwmChannel<'d, T>, | ||
| 165 | /// Channel 3 | ||
| 166 | pub ch3: RingBufferedPwmChannel<'d, T>, | ||
| 167 | /// Channel 4 | ||
| 168 | pub ch4: RingBufferedPwmChannel<'d, T>, | ||
| 169 | } | ||
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 466c56db2..3f37ffcd9 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -7,6 +7,7 @@ use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; | |||
| 7 | use super::ringbuffered::RingBufferedPwmChannel; | 7 | use super::ringbuffered::RingBufferedPwmChannel; |
| 8 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; | 8 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; |
| 9 | use crate::Peri; | 9 | use crate::Peri; |
| 10 | use crate::dma::word::Word; | ||
| 10 | #[cfg(gpio_v2)] | 11 | #[cfg(gpio_v2)] |
| 11 | use crate::gpio::Pull; | 12 | use crate::gpio::Pull; |
| 12 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 13 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| @@ -171,11 +172,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { | |||
| 171 | /// | 172 | /// |
| 172 | /// # Panics | 173 | /// # Panics |
| 173 | /// Panics if `dma_buf` is empty or longer than 65535 elements. | 174 | /// Panics if `dma_buf` is empty or longer than 65535 elements. |
| 174 | pub fn into_ring_buffered_channel( | 175 | pub fn into_ring_buffered_channel<W: Word + Into<T::Word>>( |
| 175 | mut self, | 176 | mut self, |
| 176 | tx_dma: Peri<'d, impl super::UpDma<T>>, | 177 | tx_dma: Peri<'d, impl super::UpDma<T>>, |
| 177 | dma_buf: &'d mut [T::Word], | 178 | dma_buf: &'d mut [W], |
| 178 | ) -> RingBufferedPwmChannel<'d, T> { | 179 | ) -> RingBufferedPwmChannel<'d, T, W> { |
| 179 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 180 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| 180 | 181 | ||
| 181 | self.timer.enable_update_dma(true); | 182 | self.timer.enable_update_dma(true); |
| @@ -344,8 +345,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 344 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. | 345 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. |
| 345 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 346 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 346 | /// switch this timer by using `time-driver-timX` feature. | 347 | /// switch this timer by using `time-driver-timX` feature. |
| 347 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[T::Word]) { | 348 | pub async fn waveform_up<W: Word + Into<T::Word>>( |
| 349 | &mut self, | ||
| 350 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 351 | channel: Channel, | ||
| 352 | duty: &[W], | ||
| 353 | ) { | ||
| 348 | self.inner.enable_channel(channel, true); | 354 | self.inner.enable_channel(channel, true); |
| 355 | self.inner.set_compare_value(channel, 0.into()); | ||
| 349 | self.inner.enable_update_dma(true); | 356 | self.inner.enable_update_dma(true); |
| 350 | self.inner.setup_update_dma(dma, channel, duty).await; | 357 | self.inner.setup_update_dma(dma, channel, duty).await; |
| 351 | self.inner.enable_update_dma(false); | 358 | self.inner.enable_update_dma(false); |
| @@ -380,18 +387,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 380 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 387 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 381 | /// switch this timer by using `time-driver-timX` feature. | 388 | /// switch this timer by using `time-driver-timX` feature. |
| 382 | /// | 389 | /// |
| 383 | pub async fn waveform_up_multi_channel( | 390 | pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>( |
| 384 | &mut self, | 391 | &mut self, |
| 385 | dma: Peri<'_, impl super::UpDma<T>>, | 392 | dma: Peri<'_, impl super::UpDma<T>>, |
| 386 | starting_channel: Channel, | 393 | starting_channel: Channel, |
| 387 | ending_channel: Channel, | 394 | ending_channel: Channel, |
| 388 | duty: &[T::Word], | 395 | duty: &[W], |
| 389 | ) { | 396 | ) { |
| 390 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 397 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| 391 | .iter() | 398 | .iter() |
| 392 | .filter(|ch| ch.index() >= starting_channel.index()) | 399 | .filter(|ch| ch.index() >= starting_channel.index()) |
| 393 | .filter(|ch| ch.index() <= ending_channel.index()) | 400 | .filter(|ch| ch.index() <= ending_channel.index()) |
| 394 | .for_each(|ch| self.inner.enable_channel(*ch, true)); | 401 | .for_each(|ch| { |
| 402 | self.inner.enable_channel(*ch, true); | ||
| 403 | self.inner.set_compare_value(*ch, 0.into()); | ||
| 404 | }); | ||
| 395 | self.inner.enable_update_dma(true); | 405 | self.inner.enable_update_dma(true); |
| 396 | self.inner | 406 | self.inner |
| 397 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) | 407 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
