aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer/ringbuffered.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer/ringbuffered.rs')
-rw-r--r--embassy-stm32/src/timer/ringbuffered.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs
new file mode 100644
index 000000000..fbb6b19ea
--- /dev/null
+++ b/embassy-stm32/src/timer/ringbuffered.rs
@@ -0,0 +1,158 @@
1//! RingBuffered PWM driver.
2
3use core::mem::ManuallyDrop;
4use core::task::Waker;
5
6use super::low_level::Timer;
7use super::{Channel, GeneralInstance4Channel};
8use crate::dma::WritableRingBuffer;
9use crate::dma::ringbuffer::Error;
10use crate::dma::word::Word;
11
12/// A PWM channel that uses a DMA ring buffer for continuous waveform generation.
13///
14/// This allows you to continuously update PWM duty cycles via DMA without blocking the CPU.
15/// The ring buffer enables smooth, uninterrupted waveform generation by automatically cycling
16/// through duty cycle values stored in memory.
17///
18/// You can write new duty cycle values to the ring buffer while it's running, enabling
19/// dynamic waveform generation for applications like motor control, LED dimming, or audio output.
20///
21/// # Example
22/// ```ignore
23/// let mut channel = pwm.ch1().into_ring_buffered_channel(dma_ch, &mut buffer);
24/// channel.start(); // Start DMA transfer
25/// channel.write(&[100, 200, 300]).ok(); // Update duty cycles
26/// ```
27pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> {
28 timer: ManuallyDrop<Timer<'d, T>>,
29 ring_buf: WritableRingBuffer<'d, W>,
30 channel: Channel,
31}
32
33impl<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> RingBufferedPwmChannel<'d, T, W> {
34 pub(crate) fn new(
35 timer: ManuallyDrop<Timer<'d, T>>,
36 channel: Channel,
37 ring_buf: WritableRingBuffer<'d, W>,
38 ) -> Self {
39 Self {
40 timer,
41 ring_buf,
42 channel,
43 }
44 }
45
46 /// Start the ring buffer operation.
47 ///
48 /// You must call this after creating it for it to work.
49 pub fn start(&mut self) {
50 self.ring_buf.start()
51 }
52
53 /// Clear all data in the ring buffer.
54 pub fn clear(&mut self) {
55 self.ring_buf.clear()
56 }
57
58 /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer.
59 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
60 self.ring_buf.write_immediate(buf)
61 }
62
63 /// Write elements from the ring buffer
64 /// Return a tuple of the length written and the length remaining in the buffer
65 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
66 self.ring_buf.write(buf)
67 }
68
69 /// Write an exact number of elements to the ringbuffer.
70 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
71 self.ring_buf.write_exact(buffer).await
72 }
73
74 /// Wait for any ring buffer write error.
75 pub async fn wait_write_error(&mut self) -> Result<usize, Error> {
76 self.ring_buf.wait_write_error().await
77 }
78
79 /// The current length of the ringbuffer
80 pub fn len(&mut self) -> Result<usize, Error> {
81 self.ring_buf.len()
82 }
83
84 /// The capacity of the ringbuffer
85 pub const fn capacity(&self) -> usize {
86 self.ring_buf.capacity()
87 }
88
89 /// Set a waker to be woken when at least one byte is send.
90 pub fn set_waker(&mut self, waker: &Waker) {
91 self.ring_buf.set_waker(waker)
92 }
93
94 /// Request the DMA to reset. The configuration for this channel will not be preserved.
95 ///
96 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
97 pub fn request_reset(&mut self) {
98 self.ring_buf.request_reset()
99 }
100
101 /// Request the transfer to pause, keeping the existing configuration for this channel.
102 /// To restart the transfer, call [`start`](Self::start) again.
103 ///
104 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
105 pub fn request_pause(&mut self) {
106 self.ring_buf.request_pause()
107 }
108
109 /// Return whether DMA is still running.
110 ///
111 /// If this returns false, it can be because either the transfer finished, or it was requested to stop early with request_stop.
112 pub fn is_running(&mut self) -> bool {
113 self.ring_buf.is_running()
114 }
115
116 /// Stop the DMA transfer and await until the buffer is empty.
117 ///
118 /// This disables the DMA transfer's circular mode so that the transfer stops when all available data has been written.
119 ///
120 /// This is designed to be used with streaming output data such as the I2S/SAI or DAC.
121 pub async fn stop(&mut self) {
122 self.ring_buf.stop().await
123 }
124
125 /// Enable the given channel.
126 pub fn enable(&mut self) {
127 self.timer.enable_channel(self.channel, true);
128 }
129
130 /// Disable the given channel.
131 pub fn disable(&mut self) {
132 self.timer.enable_channel(self.channel, false);
133 }
134
135 /// Check whether given channel is enabled
136 pub fn is_enabled(&self) -> bool {
137 self.timer.get_channel_enable_state(self.channel)
138 }
139
140 /// Get max duty value.
141 ///
142 /// This value depends on the configured frequency and the timer's clock rate from RCC.
143 pub fn max_duty_cycle(&self) -> u16 {
144 let max: u32 = self.timer.get_max_compare_value().into();
145 assert!(max < u16::MAX as u32);
146 max as u16 + 1
147 }
148
149 /// Set the output polarity for a given channel.
150 pub fn set_polarity(&mut self, polarity: super::low_level::OutputPolarity) {
151 self.timer.set_output_polarity(self.channel, polarity);
152 }
153
154 /// Set the output compare mode for a given channel.
155 pub fn set_output_compare_mode(&mut self, mode: super::low_level::OutputCompareMode) {
156 self.timer.set_output_compare_mode(self.channel, mode);
157 }
158}