diff options
| author | Eicke Hecht <[email protected]> | 2025-11-24 21:42:54 +0100 |
|---|---|---|
| committer | Eicke Hecht <[email protected]> | 2025-11-24 21:42:54 +0100 |
| commit | d45376583386272bc49fecc7eed8951067f84ac8 (patch) | |
| tree | 794e39ab7ebf92ca5de2e5df13dff32205b95e82 /embassy-stm32/src/timer | |
| parent | a227e61137a689ecd875c41a7efb5f2a6bb73876 (diff) | |
feat: Implement basic ring buffered PWM channel
Diffstat (limited to 'embassy-stm32/src/timer')
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/ringbuffered.rs | 151 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 35 |
3 files changed, 163 insertions, 25 deletions
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 307d614bf..2cee5f1f5 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -813,8 +813,6 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 813 | 813 | ||
| 814 | pub async fn waveform_continuous<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | 814 | pub async fn waveform_continuous<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { |
| 815 | 815 | ||
| 816 | #[cfg(any(bdma, gpdma))] | ||
| 817 | panic!("unsupported DMA"); | ||
| 818 | 816 | ||
| 819 | use crate::pac::timer::vals::Ccds; | 817 | use crate::pac::timer::vals::Ccds; |
| 820 | 818 | ||
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs index d20c5d532..bb602f8a7 100644 --- a/embassy-stm32/src/timer/ringbuffered.rs +++ b/embassy-stm32/src/timer/ringbuffered.rs | |||
| @@ -1,19 +1,142 @@ | |||
| 1 | //! RingBuffered PWM driver. | 1 | //! RingBuffered PWM driver. |
| 2 | 2 | ||
| 3 | use core::mem::ManuallyDrop; | 3 | use core::mem::ManuallyDrop; |
| 4 | use core::task::Waker; | ||
| 4 | 5 | ||
| 5 | use super::low_level::Timer; | 6 | use super::low_level::Timer; |
| 6 | use super::{Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; | 7 | use super::{Channel, GeneralInstance4Channel}; |
| 7 | use crate::Peri; | 8 | use crate::dma::ringbuffer::Error; |
| 8 | use crate::dma::ringbuffer::WritableDmaRingBuffer; | 9 | use crate::dma::WritableRingBuffer; |
| 9 | use super::simple_pwm::SimplePwm; | ||
| 10 | 10 | ||
| 11 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { | 11 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { |
| 12 | timer: ManuallyDrop<Timer<'d, T>>, | 12 | timer: ManuallyDrop<Timer<'d, T>>, |
| 13 | ring_buf: WritableDmaRingBuffer<'d, u8>, | 13 | ring_buf: WritableRingBuffer<'d, u16>, |
| 14 | channel: Channel, | 14 | channel: Channel, |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | ||
| 18 | pub(crate) fn new(timer: ManuallyDrop<Timer<'d, T>>, channel: Channel, ring_buf: WritableRingBuffer<'d, u16>) -> Self { | ||
| 19 | Self { | ||
| 20 | timer, | ||
| 21 | ring_buf, | ||
| 22 | channel, | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Start the ring buffer operation. | ||
| 27 | /// | ||
| 28 | /// You must call this after creating it for it to work. | ||
| 29 | pub fn start(&mut self) { | ||
| 30 | self.ring_buf.start() | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Clear all data in the ring buffer. | ||
| 34 | pub fn clear(&mut self) { | ||
| 35 | self.ring_buf.clear() | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. | ||
| 39 | pub fn write_immediate(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { | ||
| 40 | self.ring_buf.write_immediate(buf) | ||
| 41 | } | ||
| 42 | |||
| 43 | /// Write elements from the ring buffer | ||
| 44 | /// Return a tuple of the length written and the length remaining in the buffer | ||
| 45 | pub fn write(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { | ||
| 46 | self.ring_buf.write(buf) | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Write an exact number of elements to the ringbuffer. | ||
| 50 | pub async fn write_exact(&mut self, buffer: &[u16]) -> Result<usize, Error> { | ||
| 51 | self.ring_buf.write_exact(buffer).await | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Wait for any ring buffer write error. | ||
| 55 | pub async fn wait_write_error(&mut self) -> Result<usize, Error> { | ||
| 56 | self.ring_buf.wait_write_error().await | ||
| 57 | } | ||
| 58 | |||
| 59 | /// The current length of the ringbuffer | ||
| 60 | pub fn len(&mut self) -> Result<usize, Error> { | ||
| 61 | self.ring_buf.len() | ||
| 62 | } | ||
| 63 | |||
| 64 | /// The capacity of the ringbuffer | ||
| 65 | pub const fn capacity(&self) -> usize { | ||
| 66 | self.ring_buf.capacity() | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Set a waker to be woken when at least one byte is send. | ||
| 70 | pub fn set_waker(&mut self, waker: &Waker) { | ||
| 71 | self.ring_buf.set_waker(waker) | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Request the DMA to reset. The configuration for this channel will not be preserved. | ||
| 75 | /// | ||
| 76 | /// This doesn't immediately stop the transfer, you have to wait until is_running returns false. | ||
| 77 | pub fn request_reset(&mut self) { | ||
| 78 | self.ring_buf.request_reset() | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Request the transfer to pause, keeping the existing configuration for this channel. | ||
| 82 | /// To restart the transfer, call [`start`](Self::start) again. | ||
| 83 | /// | ||
| 84 | /// This doesn't immediately stop the transfer, you have to wait until is_running returns false. | ||
| 85 | pub fn request_pause(&mut self) { | ||
| 86 | self.ring_buf.request_pause() | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Return whether DMA is still running. | ||
| 90 | /// | ||
| 91 | /// If this returns false, it can be because either the transfer finished, or it was requested to stop early with request_stop. | ||
| 92 | pub fn is_running(&mut self) -> bool { | ||
| 93 | self.ring_buf.is_running() | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Stop the DMA transfer and await until the buffer is empty. | ||
| 97 | /// | ||
| 98 | /// This disables the DMA transfer's circular mode so that the transfer stops when all available data has been written. | ||
| 99 | /// | ||
| 100 | /// This is designed to be used with streaming output data such as the I2S/SAI or DAC. | ||
| 101 | pub async fn stop(&mut self) { | ||
| 102 | self.ring_buf.stop().await | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Enable the given channel. | ||
| 106 | pub fn enable(&mut self) { | ||
| 107 | self.timer.enable_channel(self.channel, true); | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Disable the given channel. | ||
| 111 | pub fn disable(&mut self) { | ||
| 112 | self.timer.enable_channel(self.channel, false); | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Check whether given channel is enabled | ||
| 116 | pub fn is_enabled(&self) -> bool { | ||
| 117 | self.timer.get_channel_enable_state(self.channel) | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Get max duty value. | ||
| 121 | /// | ||
| 122 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 123 | pub fn max_duty_cycle(&self) -> u16 { | ||
| 124 | let max = self.timer.get_max_compare_value(); | ||
| 125 | assert!(max < u16::MAX as u32); | ||
| 126 | max as u16 + 1 | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Set the output polarity for a given channel. | ||
| 130 | pub fn set_polarity(&mut self, polarity: super::low_level::OutputPolarity) { | ||
| 131 | self.timer.set_output_polarity(self.channel, polarity); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Set the output compare mode for a given channel. | ||
| 135 | pub fn set_output_compare_mode(&mut self, mode: super::low_level::OutputCompareMode) { | ||
| 136 | self.timer.set_output_compare_mode(self.channel, mode); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 17 | /// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. | 140 | /// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. |
| 18 | pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { | 141 | pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { |
| 19 | /// Channel 1 | 142 | /// Channel 1 |
| @@ -26,22 +149,4 @@ pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { | |||
| 26 | pub ch4: RingBufferedPwmChannel<'d, T>, | 149 | pub ch4: RingBufferedPwmChannel<'d, T>, |
| 27 | } | 150 | } |
| 28 | 151 | ||
| 29 | /// Simple PWM driver. | ||
| 30 | pub struct RingBufferedPwm<'d, T: GeneralInstance4Channel> { | ||
| 31 | inner: Timer<'d, T>, | ||
| 32 | } | ||
| 33 | |||
| 34 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | ||
| 35 | pub fn into_ring_buffered_channel<C: TimerChannel>(mut self, tx_dma: Peri<'_, impl super::Dma<T, C>>, dma_buf: &'d mut [u8]) -> RingBufferedPwmChannel<'d> { | ||
| 36 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | ||
| 37 | let ring_buf = WritableDmaRingBuffer::new(dma_buf); | ||
| 38 | let channel = C::CHANNEL; | ||
| 39 | RingBufferedPwmChannel { | ||
| 40 | timer: unsafe { self.inner.clone_unchecked() }, | ||
| 41 | channel, | ||
| 42 | ring_buf | ||
| 43 | } | ||
| 44 | 152 | ||
| 45 | // let ring_buf = WriteableRingBuffer::new(); | ||
| 46 | } | ||
| 47 | } | ||
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 56d00ea59..53e0345ea 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -4,8 +4,13 @@ use core::marker::PhantomData; | |||
| 4 | use core::mem::ManuallyDrop; | 4 | use core::mem::ManuallyDrop; |
| 5 | 5 | ||
| 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; | 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; |
| 7 | use super::ringbuffered::RingBufferedPwmChannel; | ||
| 7 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; | 8 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; |
| 9 | use crate::dma::WritableRingBuffer; | ||
| 8 | use crate::Peri; | 10 | use crate::Peri; |
| 11 | #[cfg(not(any(bdma, gpdma)))] | ||
| 12 | use crate::dma::{Burst, FifoThreshold}; | ||
| 13 | use crate::dma::TransferOptions; | ||
| 9 | #[cfg(gpio_v2)] | 14 | #[cfg(gpio_v2)] |
| 10 | use crate::gpio::Pull; | 15 | use crate::gpio::Pull; |
| 11 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 16 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| @@ -374,6 +379,36 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 374 | pub async fn waveform_continuous<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | 379 | pub async fn waveform_continuous<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { |
| 375 | self.inner.waveform_continuous(dma, duty).await; | 380 | self.inner.waveform_continuous(dma, duty).await; |
| 376 | } | 381 | } |
| 382 | pub fn into_ring_buffered_channel<C: TimerChannel>(self, tx_dma: Peri<'d, impl super::Dma<T, C>>, dma_buf: &'d mut [u16]) -> RingBufferedPwmChannel<'d, T> { | ||
| 383 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | ||
| 384 | |||
| 385 | let channel = C::CHANNEL; | ||
| 386 | let request = tx_dma.request(); | ||
| 387 | |||
| 388 | let opts = TransferOptions { | ||
| 389 | #[cfg(not(any(bdma, gpdma)))] | ||
| 390 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 391 | #[cfg(not(any(bdma, gpdma)))] | ||
| 392 | mburst: Burst::Incr8, | ||
| 393 | ..Default::default() | ||
| 394 | }; | ||
| 395 | |||
| 396 | let ring_buf = unsafe { | ||
| 397 | WritableRingBuffer::new( | ||
| 398 | tx_dma, | ||
| 399 | request, | ||
| 400 | self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 401 | dma_buf, | ||
| 402 | opts, | ||
| 403 | ) | ||
| 404 | }; | ||
| 405 | |||
| 406 | RingBufferedPwmChannel::new( | ||
| 407 | unsafe { self.inner.clone_unchecked() }, | ||
| 408 | channel, | ||
| 409 | ring_buf | ||
| 410 | ) | ||
| 411 | } | ||
| 377 | } | 412 | } |
| 378 | 413 | ||
| 379 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { | 414 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { |
