1use crate::peripherals::{Dma, Sdma};
27use core::marker::PhantomData;
28
29pub trait DmaInstance {
33 fn ptr() -> *const ws63_pac::dma::RegisterBlock;
35
36 const CHANNEL_BASE: u8;
42}
43
44pub struct Dma0;
46impl DmaInstance for Dma0 {
47 fn ptr() -> *const ws63_pac::dma::RegisterBlock {
48 Dma::ptr()
49 }
50 const CHANNEL_BASE: u8 = 0;
51}
52
53pub struct Sdma0;
55impl DmaInstance for Sdma0 {
56 fn ptr() -> *const ws63_pac::dma::RegisterBlock {
57 Sdma::ptr()
58 }
59 const CHANNEL_BASE: u8 = 8;
60}
61
62#[inline]
65fn physical_channel_index(base: u8, channel: u8) -> usize {
66 assert!(channel >= base && channel < base + 4, "DMA channel out of range for this controller");
67 (channel - base) as usize
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum TransferWidth {
75 Width8 = 0,
77 Width16 = 1,
79 Width32 = 2,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum BurstSize {
86 Beats1 = 0,
88 Beats4 = 1,
90 Beats8 = 2,
92 Beats16 = 3,
94 Beats32 = 4,
96 Beats64 = 5,
98 Beats128 = 6,
100 Beats256 = 7,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum FlowControl {
107 MemToMem = 0,
109 MemToPeripheral = 1,
111 PeripheralToMem = 2,
113 PeripheralToPeripheral = 3,
115}
116
117#[derive(Debug, Clone, Copy)]
119pub struct DmaChannelConfig {
120 pub src_peripheral: u8,
122 pub dst_peripheral: u8,
124 pub flow_control: FlowControl,
126 pub src_width: TransferWidth,
128 pub dst_width: TransferWidth,
130 pub src_burst: BurstSize,
132 pub dst_burst: BurstSize,
134 pub src_inc: bool,
136 pub dst_inc: bool,
138 pub transfer_int: bool,
140 pub error_int: bool,
142 pub bus_lock: bool,
144}
145
146impl Default for DmaChannelConfig {
147 fn default() -> Self {
148 Self {
149 src_peripheral: 0,
150 dst_peripheral: 0,
151 flow_control: FlowControl::MemToMem,
152 src_width: TransferWidth::Width32,
153 dst_width: TransferWidth::Width32,
154 src_burst: BurstSize::Beats1,
155 dst_burst: BurstSize::Beats1,
156 src_inc: true,
157 dst_inc: true,
158 transfer_int: false,
159 error_int: false,
160 bus_lock: false,
161 }
162 }
163}
164
165pub struct DmaDriver<'d, T: DmaInstance> {
169 _instance: PhantomData<&'d T>,
170}
171
172impl<'d, T: DmaInstance> DmaDriver<'d, T> {
173 pub fn new(_dma: impl Into<PhantomData<&'d T>>) -> Self {
175 Self { _instance: PhantomData }
176 }
177
178 fn regs() -> &'static ws63_pac::dma::RegisterBlock {
179 unsafe { &*T::ptr() }
181 }
182
183 #[inline]
186 fn physical_channel(channel: u8) -> usize {
187 physical_channel_index(T::CHANNEL_BASE, channel)
188 }
189
190 pub fn enable_controller(&mut self) {
192 let r = Self::regs();
193 unsafe {
194 r.dmac_config().write(|w| w.bits(0x01));
195 }
196 }
197
198 pub fn disable_controller(&mut self) {
200 unsafe {
201 Self::regs().dmac_config().write(|w| w.bits(0));
202 }
203 }
204
205 pub fn configure_channel(
213 &mut self,
214 channel: u8,
215 src_addr: u32,
216 dst_addr: u32,
217 transfer_size: u16,
218 config: &DmaChannelConfig,
219 ) {
220 let ch = Self::physical_channel(channel);
221 let r = Self::regs();
222
223 unsafe {
225 r.dmac_chn_config_0(ch).write(|w| w.bits(0));
226 }
227
228 unsafe {
230 r.dmac_s_addr_0(ch).write(|w| w.bits(src_addr));
231 }
232
233 unsafe {
235 r.dmac_d_addr_0(ch).write(|w| w.bits(dst_addr));
236 }
237
238 unsafe {
240 r.dmac_lli_0(ch).write(|w| w.bits(0));
241 }
242
243 let mut control: u32 = 0;
245 control |= (transfer_size as u32) & 0xFFF; control |= ((config.src_burst as u32) & 0x07) << 12; control |= ((config.dst_burst as u32) & 0x07) << 15; control |= ((config.src_width as u32) & 0x07) << 18; control |= ((config.dst_width as u32) & 0x07) << 21; control |= 0 << 24; control |= 0 << 25; if config.src_inc {
253 control |= 1 << 26;
254 }
255 if config.dst_inc {
256 control |= 1 << 27;
257 }
258 control |= 0 << 28; if config.transfer_int {
260 control |= 1 << 31;
261 }
262
263 unsafe {
264 r.dmac_chn_control_0(ch).write(|w| w.bits(control));
265 }
266
267 let mut ch_cfg: u32 = 0;
269 ch_cfg |= 0x01; ch_cfg |= ((config.src_peripheral as u32) & 0x0F) << 1; ch_cfg |= ((config.dst_peripheral as u32) & 0x0F) << 5; ch_cfg |= ((config.flow_control as u32) & 0x07) << 9; if config.error_int {
274 ch_cfg |= 1 << 12; }
276 if config.transfer_int {
277 ch_cfg |= 1 << 13; }
279 if config.bus_lock {
280 ch_cfg |= 1 << 14; }
282
283 unsafe {
284 r.dmac_chn_config_0(ch).write(|w| w.bits(ch_cfg));
285 }
286 }
287
288 pub fn enable_channel(&mut self, channel: u8) {
290 let ch = Self::physical_channel(channel);
291 let r = Self::regs();
292 let cfg = r.dmac_chn_config_0(ch).read().bits();
293 unsafe {
294 r.dmac_chn_config_0(ch).write(|w| w.bits(cfg | 0x01));
295 }
296 }
297
298 pub fn disable_channel(&mut self, channel: u8) {
300 let ch = Self::physical_channel(channel);
301 let r = Self::regs();
302 let cfg = r.dmac_chn_config_0(ch).read().bits();
303 unsafe {
304 r.dmac_chn_config_0(ch).write(|w| w.bits(cfg & !0x01));
305 }
306 }
307
308 pub fn channel_enabled(&self, channel: u8) -> bool {
310 let ch = Self::physical_channel(channel);
311 let mask = 1u32 << ch;
312 Self::regs().dmac_en_chns().read().bits() & mask != 0
313 }
314
315 pub fn channel_active(&self, channel: u8) -> bool {
317 let ch = Self::physical_channel(channel);
318 Self::regs().dmac_chn_config_0(ch).read().bits() & (1 << 15) != 0
319 }
320
321 pub fn halt_channel(&mut self, channel: u8) {
323 let ch = Self::physical_channel(channel);
324 let r = Self::regs();
325 let cfg = r.dmac_chn_config_0(ch).read().bits();
326 unsafe {
327 r.dmac_chn_config_0(ch).write(|w| w.bits(cfg | (1 << 16)));
328 }
329 }
330
331 pub fn resume_channel(&mut self, channel: u8) {
333 let ch = Self::physical_channel(channel);
334 let r = Self::regs();
335 let cfg = r.dmac_chn_config_0(ch).read().bits();
336 unsafe {
337 r.dmac_chn_config_0(ch).write(|w| w.bits(cfg & !(1 << 16)));
338 }
339 }
340
341 pub fn burst_request(&mut self, channel: u8) {
343 let ch = Self::physical_channel(channel);
344 unsafe {
345 Self::regs().dmac_burst_req().write(|w| w.bits(1 << ch));
346 }
347 }
348
349 pub fn single_request(&mut self, channel: u8) {
351 let ch = Self::physical_channel(channel);
352 unsafe {
353 Self::regs().dmac_single_req().write(|w| w.bits(1 << ch));
354 }
355 }
356
357 pub fn raw_interrupt_status(&self) -> (u8, u8) {
364 let sts = Self::regs().dmac_ori_int_st().read().bits();
365 ((sts & 0xFF) as u8, ((sts >> 8) & 0xFF) as u8)
366 }
367
368 pub fn interrupt_status(&self) -> (u8, u8) {
374 let sts = Self::regs().dmac_int_st().read().bits();
375 ((sts & 0xFF) as u8, ((sts >> 16) & 0xFF) as u8)
376 }
377
378 pub fn clear_transfer_interrupt(&mut self, channel: u8) {
380 let ch = Self::physical_channel(channel);
381 unsafe {
382 Self::regs().dmac_int_clr().write(|w| w.bits(1 << ch));
383 }
384 }
385
386 pub fn clear_error_interrupt(&mut self, channel: u8) {
388 let ch = Self::physical_channel(channel);
389 unsafe {
390 Self::regs().dmac_int_clr().write(|w| w.bits(1 << (ch + 8)));
391 }
392 }
393
394 pub fn set_sync(&mut self, sync_mask: u16) {
399 unsafe {
400 Self::regs().dmac_sync().write(|w| w.bits(sync_mask as u32));
401 }
402 }
403}
404
405impl<'d> DmaDriver<'d, Dma0> {
408 pub fn new_dma(_dma: Dma<'d>) -> Self {
410 Self { _instance: PhantomData }
411 }
412}
413
414#[derive(Debug, Clone, Copy, PartialEq, Eq)]
429#[repr(u8)]
430pub enum DmaPeripheral {
431 Tie0 = 0,
433 Uart0Tx = 1,
435 Uart0Rx = 2,
437 Uart1Tx = 3,
439 Uart1Rx = 4,
441 Uart2Tx = 5,
443 Uart2Rx = 6,
445 Spi0Tx = 7,
447 Spi0Rx = 8,
449 I2sTx = 11,
451 I2sRx = 12,
453 Spi1Tx = 13,
455 Spi1Rx = 14,
457}
458
459impl DmaPeripheral {
460 pub const fn request_id(self) -> u8 {
463 self as u8
464 }
465}
466
467#[derive(Debug, Clone, Copy, PartialEq, Eq)]
469pub enum DmaDirection {
470 Tx,
472 Rx,
474}
475
476impl DmaChannelConfig {
477 pub fn mem_to_peripheral(mut self, peri: DmaPeripheral) -> Self {
481 self.flow_control = FlowControl::MemToPeripheral;
482 self.dst_peripheral = peri.request_id();
483 self.dst_inc = false;
484 self
485 }
486
487 pub fn peripheral_to_mem(mut self, peri: DmaPeripheral) -> Self {
491 self.flow_control = FlowControl::PeripheralToMem;
492 self.src_peripheral = peri.request_id();
493 self.src_inc = false;
494 self
495 }
496}
497
498impl<'d> DmaDriver<'d, Sdma0> {
505 pub fn new_sdma(_sdma: Sdma<'d>) -> Self {
507 Self { _instance: PhantomData }
508 }
509}
510
511#[cfg(test)]
514mod tests {
515 use super::*;
516
517 #[test]
518 fn test_dma_direction_tx_rx_distinct() {
519 assert_ne!(DmaDirection::Tx as u8, DmaDirection::Rx as u8);
521 }
522
523 #[test]
527 fn test_dma_peripheral_spi_handshaking_ids() {
528 assert_eq!(DmaPeripheral::Spi0Tx.request_id(), 7);
530 assert_eq!(DmaPeripheral::Spi0Rx.request_id(), 8);
531 assert_eq!(DmaPeripheral::Spi1Tx.request_id(), 13);
532 assert_eq!(DmaPeripheral::Spi1Rx.request_id(), 14);
533 }
534
535 #[test]
536 fn test_dma_peripheral_uart_handshaking_ids() {
537 assert_eq!(DmaPeripheral::Uart0Tx.request_id(), 1);
539 assert_eq!(DmaPeripheral::Uart0Rx.request_id(), 2);
540 assert_eq!(DmaPeripheral::Uart1Tx.request_id(), 3);
541 assert_eq!(DmaPeripheral::Uart1Rx.request_id(), 4);
542 assert_eq!(DmaPeripheral::Uart2Tx.request_id(), 5);
543 assert_eq!(DmaPeripheral::Uart2Rx.request_id(), 6);
544 }
545
546 #[test]
547 fn test_dma_peripheral_i2s_handshaking_ids() {
548 assert_eq!(DmaPeripheral::I2sTx.request_id(), 11);
549 assert_eq!(DmaPeripheral::I2sRx.request_id(), 12);
550 }
551
552 #[test]
553 fn test_dma_peripheral_ids_fit_4bit_field() {
554 for p in [
556 DmaPeripheral::Uart0Tx,
557 DmaPeripheral::Uart2Rx,
558 DmaPeripheral::Spi0Tx,
559 DmaPeripheral::Spi1Rx,
560 DmaPeripheral::I2sTx,
561 DmaPeripheral::I2sRx,
562 ] {
563 assert!(p.request_id() <= 0x0F, "{:?} id {} > 4 bits", p, p.request_id());
564 }
565 }
566
567 #[test]
568 fn test_dma_channel_config_peripheral_wiring() {
569 let tx = DmaChannelConfig::default().mem_to_peripheral(DmaPeripheral::Spi0Tx);
572 assert_eq!(tx.flow_control, FlowControl::MemToPeripheral);
573 assert_eq!(tx.dst_peripheral, 7);
574 assert!(!tx.dst_inc);
575
576 let rx = DmaChannelConfig::default().peripheral_to_mem(DmaPeripheral::Uart1Rx);
577 assert_eq!(rx.flow_control, FlowControl::PeripheralToMem);
578 assert_eq!(rx.src_peripheral, 4);
579 assert!(!rx.src_inc);
580 }
581
582 #[test]
583 fn test_channel_base_consts() {
584 assert_eq!(Dma0::CHANNEL_BASE, 0);
586 assert_eq!(Sdma0::CHANNEL_BASE, 8);
587 }
588
589 #[test]
590 fn test_mdma_logical_to_physical() {
591 for ch in 0u8..4 {
593 assert_eq!(physical_channel_index(Dma0::CHANNEL_BASE, ch), ch as usize);
594 }
595 }
596
597 #[test]
598 fn test_sdma_logical_to_physical() {
599 assert_eq!(physical_channel_index(Sdma0::CHANNEL_BASE, 8), 0);
602 assert_eq!(physical_channel_index(Sdma0::CHANNEL_BASE, 9), 1);
603 assert_eq!(physical_channel_index(Sdma0::CHANNEL_BASE, 10), 2);
604 assert_eq!(physical_channel_index(Sdma0::CHANNEL_BASE, 11), 3);
605 }
606
607 #[test]
608 #[should_panic(expected = "out of range")]
609 fn test_mdma_channel_4_panics() {
610 physical_channel_index(Dma0::CHANNEL_BASE, 4);
612 }
613
614 #[test]
615 #[should_panic(expected = "out of range")]
616 fn test_sdma_channel_7_panics() {
617 physical_channel_index(Sdma0::CHANNEL_BASE, 7);
620 }
621
622 #[test]
623 #[should_panic(expected = "out of range")]
624 fn test_sdma_channel_12_panics() {
625 physical_channel_index(Sdma0::CHANNEL_BASE, 12);
627 }
628}
629
630#[cfg(feature = "async")]
632mod asynch_impl {
633 use super::{Dma0, DmaDriver};
634 use crate::asynch::IrqSignal;
635 use crate::interrupt::{self, Interrupt};
636 use core::future::Future;
637 use core::pin::Pin;
638 use core::task::{Context, Poll};
639
640 static DMA_SIGNAL: IrqSignal = IrqSignal::new();
641
642 pub fn on_interrupt() {
644 DMA_SIGNAL.signal();
645 interrupt::clear_pending(Interrupt::DMA_INT);
646 }
647
648 struct DmaDoneFuture;
649 impl Future for DmaDoneFuture {
650 type Output = ();
651 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
652 if DMA_SIGNAL.take_fired() {
653 Poll::Ready(())
654 } else {
655 DMA_SIGNAL.register(cx.waker());
656 Poll::Pending
657 }
658 }
659 }
660
661 impl DmaDriver<'_, Dma0> {
662 pub async fn wait_transfer_done(&mut self, channel: u8) {
666 let bit = 1u8 << channel; if self.raw_interrupt_status().0 & bit == 0 {
668 DMA_SIGNAL.reset();
669 unsafe { interrupt::enable(Interrupt::DMA_INT) };
671 if self.raw_interrupt_status().0 & bit == 0 {
672 DmaDoneFuture.await;
673 }
674 }
675 self.clear_transfer_interrupt(channel);
676 }
677 }
678}
679
680#[cfg(feature = "async")]
681pub use asynch_impl::on_interrupt;