aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
authorEicke Hecht <[email protected]>2025-11-24 21:42:54 +0100
committerEicke Hecht <[email protected]>2025-11-24 21:42:54 +0100
commitd45376583386272bc49fecc7eed8951067f84ac8 (patch)
tree794e39ab7ebf92ca5de2e5df13dff32205b95e82 /embassy-stm32/src/timer
parenta227e61137a689ecd875c41a7efb5f2a6bb73876 (diff)
feat: Implement basic ring buffered PWM channel
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/low_level.rs2
-rw-r--r--embassy-stm32/src/timer/ringbuffered.rs151
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs35
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
3use core::mem::ManuallyDrop; 3use core::mem::ManuallyDrop;
4use core::task::Waker;
4 5
5use super::low_level::Timer; 6use super::low_level::Timer;
6use super::{Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; 7use super::{Channel, GeneralInstance4Channel};
7use crate::Peri; 8use crate::dma::ringbuffer::Error;
8use crate::dma::ringbuffer::WritableDmaRingBuffer; 9use crate::dma::WritableRingBuffer;
9use super::simple_pwm::SimplePwm;
10 10
11pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { 11pub 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
17impl<'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`].
18pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { 141pub 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.
30pub struct RingBufferedPwm<'d, T: GeneralInstance4Channel> {
31 inner: Timer<'d, T>,
32}
33
34impl<'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;
4use core::mem::ManuallyDrop; 4use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::ringbuffered::RingBufferedPwmChannel;
7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; 8use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin};
9use crate::dma::WritableRingBuffer;
8use crate::Peri; 10use crate::Peri;
11#[cfg(not(any(bdma, gpdma)))]
12use crate::dma::{Burst, FifoThreshold};
13use crate::dma::TransferOptions;
9#[cfg(gpio_v2)] 14#[cfg(gpio_v2)]
10use crate::gpio::Pull; 15use crate::gpio::Pull;
11use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 16use 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
379impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { 414impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> {