aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/dac/mod.rs267
-rw-r--r--embassy-stm32/src/dma/dma.rs26
3 files changed, 178 insertions, 119 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index f7a25743c..7fa4fae45 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -699,8 +699,8 @@ fn main() {
699 // SDMMCv1 uses the same channel for both directions, so just implement for RX 699 // SDMMCv1 uses the same channel for both directions, so just implement for RX
700 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 700 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
701 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 701 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
702 (("dac", "CH1"), quote!(crate::dac::Dma)), 702 (("dac", "CH1"), quote!(crate::dac::DmaCh1)),
703 (("dac", "CH2"), quote!(crate::dac::Dma)), 703 (("dac", "CH2"), quote!(crate::dac::DmaCh2)),
704 ] 704 ]
705 .into(); 705 .into();
706 706
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index d95674ff0..6ead00e15 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -171,13 +171,6 @@ pub trait DacChannel<T: Instance, Tx> {
171 } 171 }
172 Ok(()) 172 Ok(())
173 } 173 }
174
175 /// Write `data` to the DAC channel via DMA.
176 ///
177 /// `circular` sets the DMA to circular mode.
178 async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
179 where
180 Tx: Dma<T>;
181} 174}
182 175
183/// Hold two DAC channels 176/// Hold two DAC channels
@@ -244,6 +237,81 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
244 }); 237 });
245 Ok(()) 238 Ok(())
246 } 239 }
240
241 /// Write `data` to the DAC CH1 via DMA.
242 ///
243 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
244 /// This will configure a circular DMA transfer that periodically outputs the `data`.
245 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
246 ///
247 /// **Important:** Channel 1 has to be configured for the DAC instance!
248 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
249 where
250 Tx: DmaCh1<T>,
251 {
252 let channel = Channel::Ch1.index();
253 debug!("Writing to channel {}", channel);
254
255 // Enable DAC and DMA
256 T::regs().cr().modify(|w| {
257 w.set_en(channel, true);
258 w.set_dmaen(channel, true);
259 });
260
261 let tx_request = self.dma.request();
262 let dma_channel = &self.dma;
263
264 let tx_options = TransferOptions {
265 circular,
266 half_transfer_ir: false,
267 complete_transfer_ir: !circular,
268 ..Default::default()
269 };
270
271 // Initiate the correct type of DMA transfer depending on what data is passed
272 let tx_f = match data {
273 ValueArray::Bit8(buf) => unsafe {
274 Transfer::new_write(
275 dma_channel,
276 tx_request,
277 buf,
278 T::regs().dhr8r(channel).as_ptr() as *mut u8,
279 tx_options,
280 )
281 },
282 ValueArray::Bit12Left(buf) => unsafe {
283 Transfer::new_write(
284 dma_channel,
285 tx_request,
286 buf,
287 T::regs().dhr12l(channel).as_ptr() as *mut u16,
288 tx_options,
289 )
290 },
291 ValueArray::Bit12Right(buf) => unsafe {
292 Transfer::new_write(
293 dma_channel,
294 tx_request,
295 buf,
296 T::regs().dhr12r(channel).as_ptr() as *mut u16,
297 tx_options,
298 )
299 },
300 };
301
302 tx_f.await;
303
304 // finish dma
305 // TODO: Do we need to check any status registers here?
306 T::regs().cr().modify(|w| {
307 // Disable the DAC peripheral
308 w.set_en(channel, false);
309 // Disable the DMA. TODO: Is this necessary?
310 w.set_dmaen(channel, false);
311 });
312
313 Ok(())
314 }
247} 315}
248 316
249impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { 317impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
@@ -279,6 +347,81 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
279 }); 347 });
280 Ok(()) 348 Ok(())
281 } 349 }
350
351 /// Write `data` to the DAC CH2 via DMA.
352 ///
353 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
354 /// This will configure a circular DMA transfer that periodically outputs the `data`.
355 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
356 ///
357 /// **Important:** Channel 2 has to be configured for the DAC instance!
358 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
359 where
360 Tx: DmaCh2<T>,
361 {
362 let channel = Channel::Ch2.index();
363 debug!("Writing to channel {}", channel);
364
365 // Enable DAC and DMA
366 T::regs().cr().modify(|w| {
367 w.set_en(channel, true);
368 w.set_dmaen(channel, true);
369 });
370
371 let tx_request = self.dma.request();
372 let dma_channel = &self.dma;
373
374 let tx_options = TransferOptions {
375 circular,
376 half_transfer_ir: false,
377 complete_transfer_ir: !circular,
378 ..Default::default()
379 };
380
381 // Initiate the correct type of DMA transfer depending on what data is passed
382 let tx_f = match data {
383 ValueArray::Bit8(buf) => unsafe {
384 Transfer::new_write(
385 dma_channel,
386 tx_request,
387 buf,
388 T::regs().dhr8r(channel).as_ptr() as *mut u8,
389 tx_options,
390 )
391 },
392 ValueArray::Bit12Left(buf) => unsafe {
393 Transfer::new_write(
394 dma_channel,
395 tx_request,
396 buf,
397 T::regs().dhr12l(channel).as_ptr() as *mut u16,
398 tx_options,
399 )
400 },
401 ValueArray::Bit12Right(buf) => unsafe {
402 Transfer::new_write(
403 dma_channel,
404 tx_request,
405 buf,
406 T::regs().dhr12r(channel).as_ptr() as *mut u16,
407 tx_options,
408 )
409 },
410 };
411
412 tx_f.await;
413
414 // finish dma
415 // TODO: Do we need to check any status registers here?
416 T::regs().cr().modify(|w| {
417 // Disable the DAC peripheral
418 w.set_en(channel, false);
419 // Disable the DMA. TODO: Is this necessary?
420 w.set_dmaen(channel, false);
421 });
422
423 Ok(())
424 }
282} 425}
283 426
284impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { 427impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
@@ -350,117 +493,10 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
350 493
351impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> { 494impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
352 const CHANNEL: Channel = Channel::Ch1; 495 const CHANNEL: Channel = Channel::Ch1;
353
354 /// Write `data` to the DAC CH1 via DMA.
355 ///
356 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
357 /// This will configure a circular DMA transfer that periodically outputs the `data`.
358 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
359 ///
360 /// **Important:** Channel 1 has to be configured for the DAC instance!
361 async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
362 where
363 Tx: Dma<T>,
364 {
365 write_inner(Self::CHANNEL, &self.dma, data, circular).await
366 }
367} 496}
368 497
369impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> { 498impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
370 const CHANNEL: Channel = Channel::Ch2; 499 const CHANNEL: Channel = Channel::Ch2;
371
372 /// Write `data` to the DAC CH2 via DMA.
373 ///
374 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
375 /// This will configure a circular DMA transfer that periodically outputs the `data`.
376 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
377 ///
378 /// **Important:** Channel 2 has to be configured for the DAC instance!
379 async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
380 where
381 Tx: Dma<T>,
382 {
383 write_inner(Self::CHANNEL, &self.dma, data, circular).await
384 }
385}
386
387/// Shared utility function to perform the actual DMA config and write.
388async fn write_inner<T: Instance, Tx>(
389 ch: Channel,
390 dma: &PeripheralRef<'_, Tx>,
391 data: ValueArray<'_>,
392 circular: bool,
393) -> Result<(), Error>
394where
395 Tx: Dma<T>,
396{
397 let channel = ch.index();
398 debug!("Writing to channel {}", channel);
399
400 // Enable DAC and DMA
401 T::regs().cr().modify(|w| {
402 w.set_en(channel, true);
403 w.set_dmaen(channel, true);
404 });
405
406 let tx_request = dma.request();
407 let dma_channel = dma;
408
409 // Initiate the correct type of DMA transfer depending on what data is passed
410 let tx_f = match data {
411 ValueArray::Bit8(buf) => unsafe {
412 Transfer::new_write(
413 dma_channel,
414 tx_request,
415 buf,
416 T::regs().dhr8r(channel).as_ptr() as *mut u8,
417 TransferOptions {
418 circular,
419 half_transfer_ir: false,
420 complete_transfer_ir: !circular,
421 },
422 )
423 },
424 ValueArray::Bit12Left(buf) => unsafe {
425 Transfer::new_write(
426 dma_channel,
427 tx_request,
428 buf,
429 T::regs().dhr12l(channel).as_ptr() as *mut u16,
430 TransferOptions {
431 circular,
432 half_transfer_ir: false,
433 complete_transfer_ir: !circular,
434 },
435 )
436 },
437 ValueArray::Bit12Right(buf) => unsafe {
438 Transfer::new_write(
439 dma_channel,
440 tx_request,
441 buf,
442 T::regs().dhr12r(channel).as_ptr() as *mut u16,
443 TransferOptions {
444 circular,
445 half_transfer_ir: false,
446 complete_transfer_ir: !circular,
447 },
448 )
449 },
450 };
451
452 tx_f.await;
453
454 // finish dma
455 // TODO: Do we need to check any status registers here?
456 T::regs().cr().modify(|w| {
457 // Disable the DAC peripheral
458 w.set_en(channel, false);
459 // Disable the DMA. TODO: Is this necessary?
460 w.set_dmaen(channel, false);
461 });
462
463 Ok(())
464} 500}
465 501
466pub(crate) mod sealed { 502pub(crate) mod sealed {
@@ -470,7 +506,8 @@ pub(crate) mod sealed {
470} 506}
471 507
472pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 508pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
473dma_trait!(Dma, Instance); 509dma_trait!(DmaCh1, Instance);
510dma_trait!(DmaCh2, Instance);
474 511
475/// Marks a pin that can be used with the DAC 512/// Marks a pin that can be used with the DAC
476pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} 513pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 8abe541d3..a5f828948 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -29,6 +29,12 @@ pub struct TransferOptions {
29 pub flow_ctrl: FlowControl, 29 pub flow_ctrl: FlowControl,
30 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. 30 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
31 pub fifo_threshold: Option<FifoThreshold>, 31 pub fifo_threshold: Option<FifoThreshold>,
32 /// Enable circular DMA
33 pub circular: bool,
34 /// Enable half transfer interrupt
35 pub half_transfer_ir: bool,
36 /// Enable transfer complete interrupt
37 pub complete_transfer_ir: bool,
32} 38}
33 39
34impl Default for TransferOptions { 40impl Default for TransferOptions {
@@ -38,6 +44,9 @@ impl Default for TransferOptions {
38 mburst: Burst::Single, 44 mburst: Burst::Single,
39 flow_ctrl: FlowControl::Dma, 45 flow_ctrl: FlowControl::Dma,
40 fifo_threshold: None, 46 fifo_threshold: None,
47 circular: false,
48 half_transfer_ir: false,
49 complete_transfer_ir: true,
41 } 50 }
42 } 51 }
43} 52}
@@ -366,13 +375,20 @@ impl<'a, C: Channel> Transfer<'a, C> {
366 }); 375 });
367 w.set_pinc(vals::Inc::FIXED); 376 w.set_pinc(vals::Inc::FIXED);
368 w.set_teie(true); 377 w.set_teie(true);
369 w.set_tcie(true); 378 w.set_tcie(options.complete_transfer_ir);
379 w.set_htie(options.half_transfer_ir);
370 #[cfg(dma_v1)] 380 #[cfg(dma_v1)]
371 w.set_trbuff(true); 381 w.set_trbuff(true);
372 382
373 #[cfg(dma_v2)] 383 #[cfg(dma_v2)]
374 w.set_chsel(_request); 384 w.set_chsel(_request);
375 385
386 if options.circular {
387 w.set_circ(vals::Circ::ENABLED);
388 debug!("Setting circular mode");
389 } else {
390 w.set_circ(vals::Circ::DISABLED);
391 }
376 w.set_pburst(options.pburst.into()); 392 w.set_pburst(options.pburst.into());
377 w.set_mburst(options.mburst.into()); 393 w.set_mburst(options.mburst.into());
378 w.set_pfctrl(options.flow_ctrl.into()); 394 w.set_pfctrl(options.flow_ctrl.into());
@@ -404,8 +420,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
404 } 420 }
405 421
406 pub fn is_running(&mut self) -> bool { 422 pub fn is_running(&mut self) -> bool {
423 //let ch = self.channel.regs().st(self.channel.num());
424 //ch.cr().read().en()
425
407 let ch = self.channel.regs().st(self.channel.num()); 426 let ch = self.channel.regs().st(self.channel.num());
408 ch.cr().read().en() 427 let en = ch.cr().read().en();
428 let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
429 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
430 en && (circular || !tcif)
409 } 431 }
410 432
411 /// Gets the total remaining transfers for the channel 433 /// Gets the total remaining transfers for the channel