aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuliDi <[email protected]>2023-06-24 13:10:59 +0200
committerJuliDi <[email protected]>2023-06-24 13:10:59 +0200
commit388d3e273d3d003e6a058b4bad9e2517dd33d626 (patch)
treeb2b7830bc138d0a611125abe13f7afd4c8842525
parent915f79c974ace037e914397b42eb9d2448bd5ca3 (diff)
first attempt at fixing the 2nd channel problem
-rw-r--r--embassy-stm32/src/dac/mod.rs366
1 files changed, 224 insertions, 142 deletions
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 5b39758bf..e87292b86 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,5 +1,7 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::marker::PhantomData;
4
3use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
4 6
5use crate::dma::{Transfer, TransferOptions}; 7use crate::dma::{Transfer, TransferOptions};
@@ -108,166 +110,108 @@ pub enum ValueArray<'a> {
108 Bit12Right(&'a [u16]), 110 Bit12Right(&'a [u16]),
109} 111}
110 112
111pub struct Dac<'d, T: Instance, Tx> { 113pub trait DacChannel<T: Instance, Tx> {
112 ch1: bool, 114 const CHANNEL: Channel;
113 ch2: bool,
114 txdma: PeripheralRef<'d, Tx>,
115 _peri: PeripheralRef<'d, T>,
116}
117
118impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
119 pub fn new_ch1(
120 peri: impl Peripheral<P = T> + 'd,
121 txdma: impl Peripheral<P = Tx> + 'd,
122 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
123 ) -> Self {
124 into_ref!(peri);
125 Self::new_inner(peri, true, false, txdma)
126 }
127
128 pub fn new_ch2(
129 peri: impl Peripheral<P = T> + 'd,
130 txdma: impl Peripheral<P = Tx> + 'd,
131 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
132 ) -> Self {
133 into_ref!(peri);
134 Self::new_inner(peri, false, true, txdma)
135 }
136
137 pub fn new_ch1_and_ch2(
138 peri: impl Peripheral<P = T> + 'd,
139 txdma: impl Peripheral<P = Tx> + 'd,
140 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
141 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
142 ) -> Self {
143 into_ref!(peri);
144 Self::new_inner(peri, true, true, txdma)
145 }
146
147 /// Perform initialisation steps for the DAC
148 fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral<P = Tx> + 'd) -> Self {
149 into_ref!(txdma);
150 T::enable();
151 T::reset();
152
153 let mut dac = Self {
154 ch1,
155 ch2,
156 txdma,
157 _peri: peri,
158 };
159
160 // Configure each activated channel. All results can be `unwrap`ed since they
161 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
162 if ch1 {
163 dac.set_channel_mode(Channel::Ch1, 0).unwrap();
164 dac.enable_channel(Channel::Ch1).unwrap();
165 dac.set_trigger_enable(Channel::Ch1, true).unwrap();
166 }
167 if ch2 {
168 dac.set_channel_mode(Channel::Ch2, 0).unwrap();
169 dac.enable_channel(Channel::Ch2).unwrap();
170 dac.set_trigger_enable(Channel::Ch2, true).unwrap();
171 }
172
173 dac
174 }
175
176 /// Check the channel is configured
177 fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> {
178 if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) {
179 Err(Error::UnconfiguredChannel)
180 } else {
181 Ok(())
182 }
183 }
184 115
185 /// Enable trigger of the given channel 116 /// Enable trigger of the given channel
186 fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { 117 fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
187 self.check_channel_configured(ch)?;
188 T::regs().cr().modify(|reg| { 118 T::regs().cr().modify(|reg| {
189 reg.set_ten(ch.index(), on); 119 reg.set_ten(Self::CHANNEL.index(), on);
190 }); 120 });
191 Ok(()) 121 Ok(())
192 } 122 }
193 123
194 /// Set mode register of the given channel 124 /// Set mode register of the given channel
195 fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> { 125 fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
196 self.check_channel_configured(ch)?;
197 T::regs().mcr().modify(|reg| { 126 T::regs().mcr().modify(|reg| {
198 reg.set_mode(ch.index(), val); 127 reg.set_mode(Self::CHANNEL.index(), val);
199 }); 128 });
200 Ok(()) 129 Ok(())
201 } 130 }
202 131
203 /// Set enable register of the given channel 132 /// Set enable register of the given channel
204 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { 133 fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
205 self.check_channel_configured(ch)?;
206 T::regs().cr().modify(|reg| { 134 T::regs().cr().modify(|reg| {
207 reg.set_en(ch.index(), on); 135 reg.set_en(Self::CHANNEL.index(), on);
208 }); 136 });
209 Ok(()) 137 Ok(())
210 } 138 }
211 139
212 /// Enable the DAC channel `ch` 140 /// Enable the DAC channel `ch`
213 pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> { 141 fn enable_channel(&mut self) -> Result<(), Error> {
214 self.set_channel_enable(ch, true) 142 self.set_channel_enable(true)
215 } 143 }
216 144
217 /// Disable the DAC channel `ch` 145 /// Disable the DAC channel `ch`
218 pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> { 146 fn disable_channel(&mut self) -> Result<(), Error> {
219 self.set_channel_enable(ch, false) 147 self.set_channel_enable(false)
220 }
221
222 /// Select a new trigger for CH1 (disables the channel)
223 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
224 self.check_channel_configured(Channel::Ch1)?;
225 unwrap!(self.disable_channel(Channel::Ch1));
226 T::regs().cr().modify(|reg| {
227 reg.set_tsel1(trigger.tsel());
228 });
229 Ok(())
230 }
231
232 /// Select a new trigger for CH2 (disables the channel)
233 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
234 self.check_channel_configured(Channel::Ch2)?;
235 unwrap!(self.disable_channel(Channel::Ch2));
236 T::regs().cr().modify(|reg| {
237 reg.set_tsel2(trigger.tsel());
238 });
239 Ok(())
240 } 148 }
241 149
242 /// Perform a software trigger on `ch` 150 /// Perform a software trigger on `ch`
243 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { 151 fn trigger(&mut self) -> Result<(), Error> {
244 self.check_channel_configured(ch)?;
245 T::regs().swtrigr().write(|reg| { 152 T::regs().swtrigr().write(|reg| {
246 reg.set_swtrig(ch.index(), true); 153 reg.set_swtrig(Self::CHANNEL.index(), true);
247 }); 154 });
248 Ok(()) 155 Ok(())
249 } 156 }
250 157
251 /// Perform a software trigger on all channels
252 pub fn trigger_all(&mut self) {
253 T::regs().swtrigr().write(|reg| {
254 reg.set_swtrig(Channel::Ch1.index(), true);
255 reg.set_swtrig(Channel::Ch2.index(), true);
256 });
257 }
258
259 /// Set a value to be output by the DAC on trigger. 158 /// Set a value to be output by the DAC on trigger.
260 /// 159 ///
261 /// The `value` is written to the corresponding "data holding register" 160 /// The `value` is written to the corresponding "data holding register"
262 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { 161 fn set(&mut self, value: Value) -> Result<(), Error> {
263 self.check_channel_configured(ch)?;
264 match value { 162 match value {
265 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), 163 Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
266 Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), 164 Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
267 Value::Bit12Right(v) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), 165 Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
268 } 166 }
269 Ok(()) 167 Ok(())
270 } 168 }
169}
170
171pub struct Dac<'d, T: Instance, Tx> {
172 ch1: DacCh1<'d, T, Tx>,
173 ch2: DacCh2<'d, T, Tx>,
174}
175
176pub struct DacCh1<'d, T: Instance, Tx> {
177 _peri: PeripheralRef<'d, T>,
178 dma: PeripheralRef<'d, Tx>,
179}
180
181pub struct DacCh2<'d, T: Instance, Tx> {
182 phantom: PhantomData<&'d mut T>,
183 dma: PeripheralRef<'d, Tx>,
184}
185
186impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
187 /// Perform initialisation steps for the DAC
188 pub fn new(
189 peri: impl Peripheral<P = T> + 'd,
190 dma: impl Peripheral<P = Tx> + 'd,
191 _pin: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
192 ) -> Self {
193 into_ref!(peri, dma);
194 T::enable();
195 T::reset();
196
197 let mut dac = Self { _peri: peri, dma };
198
199 // Configure each activated channel. All results can be `unwrap`ed since they
200 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
201 dac.set_channel_mode(0).unwrap();
202 dac.enable_channel().unwrap();
203 dac.set_trigger_enable(true).unwrap();
204
205 dac
206 }
207 /// Select a new trigger for CH1 (disables the channel)
208 pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
209 unwrap!(self.disable_channel());
210 T::regs().cr().modify(|reg| {
211 reg.set_tsel1(trigger.tsel());
212 });
213 Ok(())
214 }
271 215
272 /// Write `data` to the DAC CH1 via DMA. 216 /// Write `data` to the DAC CH1 via DMA.
273 /// 217 ///
@@ -276,36 +220,127 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
276 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. 220 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
277 /// 221 ///
278 /// **Important:** Channel 1 has to be configured for the DAC instance! 222 /// **Important:** Channel 1 has to be configured for the DAC instance!
279 pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> 223 async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
280 where 224 where
281 Tx: Dma<T>, 225 Tx: Dma<T>,
282 { 226 {
283 self.check_channel_configured(Channel::Ch1)?; 227 let channel = Channel::Ch1.index();
284 self.write_inner(data, circular, Channel::Ch1).await 228 debug!("Writing to channel {}", channel);
229
230 // Enable DAC and DMA
231 T::regs().cr().modify(|w| {
232 w.set_en(channel, true);
233 w.set_dmaen(channel, true);
234 });
235
236 let tx_request = self.dma.request();
237 let dma_channel = &self.dma;
238
239 // Initiate the correct type of DMA transfer depending on what data is passed
240 let tx_f = match data {
241 ValueArray::Bit8(buf) => unsafe {
242 Transfer::new_write(
243 dma_channel,
244 tx_request,
245 buf,
246 T::regs().dhr8r(channel).as_ptr() as *mut u8,
247 TransferOptions {
248 circular,
249 half_transfer_ir: false,
250 complete_transfer_ir: !circular,
251 },
252 )
253 },
254 ValueArray::Bit12Left(buf) => unsafe {
255 Transfer::new_write(
256 dma_channel,
257 tx_request,
258 buf,
259 T::regs().dhr12l(channel).as_ptr() as *mut u16,
260 TransferOptions {
261 circular,
262 half_transfer_ir: false,
263 complete_transfer_ir: !circular,
264 },
265 )
266 },
267 ValueArray::Bit12Right(buf) => unsafe {
268 Transfer::new_write(
269 dma_channel,
270 tx_request,
271 buf,
272 T::regs().dhr12r(channel).as_ptr() as *mut u16,
273 TransferOptions {
274 circular,
275 half_transfer_ir: false,
276 complete_transfer_ir: !circular,
277 },
278 )
279 },
280 };
281
282 tx_f.await;
283
284 // finish dma
285 // TODO: Do we need to check any status registers here?
286 T::regs().cr().modify(|w| {
287 // Disable the DAC peripheral
288 w.set_en(channel, false);
289 // Disable the DMA. TODO: Is this necessary?
290 w.set_dmaen(channel, false);
291 });
292
293 Ok(())
285 } 294 }
295}
286 296
287 /// Write `data` to the DAC CH2 via DMA. 297impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
298 /// Perform initialisation steps for the DAC
299 pub fn new_ch2(
300 peri: impl Peripheral<P = T> + 'd,
301 dma: impl Peripheral<P = Tx> + 'd,
302 _pin: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
303 ) -> Self {
304 into_ref!(peri, dma);
305 T::enable();
306 T::reset();
307
308 let mut dac = Self {
309 phantom: PhantomData,
310 dma,
311 };
312
313 // Configure each activated channel. All results can be `unwrap`ed since they
314 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
315 dac.set_channel_mode(0).unwrap();
316 dac.enable_channel().unwrap();
317 dac.set_trigger_enable(true).unwrap();
318
319 dac
320 }
321
322 /// Select a new trigger for CH1 (disables the channel)
323 pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
324 unwrap!(self.disable_channel());
325 T::regs().cr().modify(|reg| {
326 reg.set_tsel2(trigger.tsel());
327 });
328 Ok(())
329 }
330
331 /// Write `data` to the DAC CH1 via DMA.
288 /// 332 ///
289 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. 333 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
290 /// This will configure a circular DMA transfer that periodically outputs the `data`. 334 /// This will configure a circular DMA transfer that periodically outputs the `data`.
291 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. 335 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
292 /// 336 ///
293 /// **Important:** Channel 2 has to be configured for the DAC instance! 337 /// **Important:** Channel 1 has to be configured for the DAC instance!
294 pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> 338 async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
295 where
296 Tx: Dma<T>,
297 {
298 self.check_channel_configured(Channel::Ch2)?;
299 self.write_inner(data, circular, Channel::Ch2).await
300 }
301
302 /// Performs the dma write for the given channel.
303 /// TODO: Should self be &mut?
304 async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error>
305 where 339 where
306 Tx: Dma<T>, 340 Tx: Dma<T>,
307 { 341 {
308 let channel = channel.index(); 342 let channel = Channel::Ch2.index();
343 debug!("Writing to channel {}", channel);
309 344
310 // Enable DAC and DMA 345 // Enable DAC and DMA
311 T::regs().cr().modify(|w| { 346 T::regs().cr().modify(|w| {
@@ -313,11 +348,11 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
313 w.set_dmaen(channel, true); 348 w.set_dmaen(channel, true);
314 }); 349 });
315 350
316 let tx_request = self.txdma.request(); 351 let tx_request = self.dma.request();
317 let dma_channel = &self.txdma; 352 let dma_channel = &self.dma;
318 353
319 // Initiate the correct type of DMA transfer depending on what data is passed 354 // Initiate the correct type of DMA transfer depending on what data is passed
320 let tx_f = match data_ch1 { 355 let tx_f = match data {
321 ValueArray::Bit8(buf) => unsafe { 356 ValueArray::Bit8(buf) => unsafe {
322 Transfer::new_write( 357 Transfer::new_write(
323 dma_channel, 358 dma_channel,
@@ -374,6 +409,53 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
374 } 409 }
375} 410}
376 411
412impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
413 pub fn new(
414 peri: impl Peripheral<P = T> + 'd,
415 dma_ch1: impl Peripheral<P = Tx> + 'd,
416 dma_ch2: impl Peripheral<P = Tx> + 'd,
417 _pin_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
418 _pin_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
419 ) -> Self {
420 into_ref!(peri, dma_ch1, dma_ch2);
421 T::enable();
422 T::reset();
423
424 let mut dac_ch1 = DacCh1 {
425 _peri: peri,
426 dma: dma_ch1,
427 };
428
429 let mut dac_ch2 = DacCh2 {
430 phantom: PhantomData,
431 dma: dma_ch2,
432 };
433
434 // Configure each activated channel. All results can be `unwrap`ed since they
435 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
436 dac_ch1.set_channel_mode(0).unwrap();
437 dac_ch1.enable_channel().unwrap();
438 dac_ch1.set_trigger_enable(true).unwrap();
439
440 dac_ch1.set_channel_mode(0).unwrap();
441 dac_ch1.enable_channel().unwrap();
442 dac_ch1.set_trigger_enable(true).unwrap();
443
444 Self {
445 ch1: dac_ch1,
446 ch2: dac_ch2,
447 }
448 }
449}
450
451impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
452 const CHANNEL: Channel = Channel::Ch1;
453}
454
455impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
456 const CHANNEL: Channel = Channel::Ch2;
457}
458
377pub(crate) mod sealed { 459pub(crate) mod sealed {
378 pub trait Instance { 460 pub trait Instance {
379 fn regs() -> &'static crate::pac::dac::Dac; 461 fn regs() -> &'static crate::pac::dac::Dac;