pic32_hal/
dma.rs

1//! DMA Controller
2
3use crate::int::InterruptSource;
4use crate::pac::{DMAC, DMAC0, DMAC1, DMAC2, DMAC3};
5use enumflags2::{bitflags, BitFlags};
6use mips_mcu::PhysicalAddress;
7
8/// Interrupt flag or enable bits related to a specific DMA channel
9#[bitflags]
10#[derive(Copy, Clone, Debug, PartialEq)]
11#[repr(u8)]
12pub enum DmaIrq {
13    /// Channel Source Done
14    CHSD = 0x80,
15    /// Channel Source Half Empty
16    CHSH = 0x40,
17    /// Channel Destination Done
18    CHDD = 0x20,
19    /// Channel Destination Half Full
20    CHDH = 0x10,
21    /// Channel Block Transfer Complete
22    CHBC = 0x08,
23    /// Channel Cell Transfer Complete
24    CHCC = 0x04,
25    /// Channel Transfer Abort
26    CHTA = 0x02,
27    ///  Channel Address Error
28    CHER = 0x01,
29}
30
31/// indicates whether the channel shall be automatically enabled after a block
32/// transfer
33#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum XferMode {
35    OneShot,
36    Auto,
37}
38
39/// DMA Operations
40///
41/// This trait defines operations that can be carried out by a DMAChannel
42pub trait Ops {
43    /// Set source address and size of source block in bytes
44    fn set_source(&mut self, addr: PhysicalAddress, size: usize);
45
46    /// Set destination address and size of destination block in bytes
47    fn set_dest(&mut self, addr: PhysicalAddress, size: usize);
48
49    /// Set cell size, i.e. number of bytes transferred per triggering event
50    fn set_cell_size(&mut self, size: usize);
51
52    /// Set start event source for triggering a cell transfer
53    fn set_start_event(&mut self, event: Option<InterruptSource>);
54
55    /// Set event for aborting a transfer
56    fn set_abort_event(&mut self, event: Option<InterruptSource>);
57
58    /// Set data pattern that aborts a transfer
59    fn set_abort_pattern(&mut self, pattern: Option<u8>);
60
61    /// Get source pointer
62    fn source_pointer(&self) -> PhysicalAddress;
63
64    /// Get destination pointer
65    fn destination_pointer(&self) -> PhysicalAddress;
66
67    /// Enable/disable individual interrupt sources
68    ///
69    /// This function does not configure the interrupt controller.
70    fn irq_enable(&mut self, irq: BitFlags<DmaIrq>);
71
72    /// Get interrupt flags
73    fn irq_flags(&self) -> BitFlags<DmaIrq>;
74
75    /// Set interrupt flags
76    fn set_irq_flags(&mut self, flags: BitFlags<DmaIrq>);
77
78    /// Clear all interrupt flags
79    fn clear_all_irq_flags(&mut self) {
80        self.set_irq_flags(BitFlags::<DmaIrq>::default());
81    }
82
83    /// Enable DMA channel
84    ///
85    /// # Safety
86    ///
87    /// Unsafe because the DMA controller will access the memory blocks
88    /// specified as source and destination without any checks
89    unsafe fn enable(&mut self, mode: XferMode);
90
91    /// Check if a DMA channel is enabled
92    ///
93    /// Can be used to poll OneShot channels for completion.
94    fn is_enabled(&self) -> bool;
95
96    /// Disable a DMA channel
97    fn disable(&mut self);
98
99    /// Force a cell transfer
100    fn force(&mut self);
101}
102
103pub struct DmaChannel<D> {
104    ch: D,
105}
106
107macro_rules! dma {
108    ($Id:ident, $Dmac:ident) => {
109        impl Ops for DmaChannel<$Dmac> {
110            fn set_source(&mut self, addr: PhysicalAddress, size: usize) {
111                unsafe {
112                    self.ch.ssa.write(|w| w.bits(addr.address() as u32));
113                    self.ch.ssiz.write(|w| w.bits(size as u32));
114                }
115            }
116
117            fn set_dest(&mut self, addr: PhysicalAddress, size: usize) {
118                unsafe {
119                    self.ch.dsa.write(|w| w.bits(addr.address() as u32));
120                    self.ch.dsiz.write(|w| w.bits(size as u32));
121                }
122            }
123
124            fn set_cell_size(&mut self, size: usize) {
125                unsafe {
126                    self.ch.csiz.write(|w| w.bits(size as u32));
127                }
128            }
129
130            fn set_start_event(&mut self, event: Option<InterruptSource>) {
131                match event {
132                    Some(e) => {
133                        self.ch
134                            .econ
135                            .modify(|_, w| unsafe { w.chsirq().bits(e as u8).sirqen().bit(true) });
136                    }
137                    None => {
138                        self.ch.econclr.write(|w| w.sirqen().bit(true));
139                    }
140                }
141            }
142
143            fn set_abort_event(&mut self, event: Option<InterruptSource>) {
144                match event {
145                    Some(e) => {
146                        self.ch
147                            .econ
148                            .modify(|_, w| unsafe { w.chairq().bits(e as u8).airqen().bit(true) });
149                    }
150                    None => {
151                        self.ch.econclr.write(|w| w.airqen().bit(true));
152                    }
153                }
154            }
155
156            fn set_abort_pattern(&mut self, pattern: Option<u8>) {
157                match pattern {
158                    Some(p) => {
159                        self.ch.dat.write(|w| unsafe { w.dchpdat().bits(p) });
160                        self.ch.econset.write(|w| w.paten().bit(true));
161                    }
162                    None => {
163                        self.ch.econclr.write(|w| w.paten().bit(true));
164                    }
165                }
166            }
167
168            fn source_pointer(&self) -> PhysicalAddress {
169                PhysicalAddress::from_usize(self.ch.sptr.read().bits() as usize)
170            }
171
172            fn destination_pointer(&self) -> PhysicalAddress {
173                PhysicalAddress::from_usize(self.ch.dptr.read().bits() as usize)
174            }
175
176            fn irq_enable(&mut self, irq: BitFlags<DmaIrq>) {
177                self.ch
178                    .int
179                    .write(|w| unsafe { w.bits((irq.bits() as u32) << 16) });
180            }
181
182            fn irq_flags(&self) -> BitFlags<DmaIrq> {
183                let int = self.ch.int.read().bits();
184                unsafe { BitFlags::from_bits_unchecked(int as u8) }
185            }
186
187            fn set_irq_flags(&mut self, flags: BitFlags<DmaIrq>) {
188                self.ch.int.modify(|r, w| unsafe {
189                    w.bits((r.bits() & 0xffff_ff00) | flags.bits() as u32)
190                });
191            }
192
193            unsafe fn enable(&mut self, mode: XferMode) {
194                match mode {
195                    XferMode::OneShot => self.ch.contclr.write(|w| w.chaen().bit(true)),
196                    XferMode::Auto => self.ch.contset.write(|w| w.chaen().bit(true)),
197                }
198                self.ch.contset.write(|w| w.chen().bit(true));
199            }
200
201            fn is_enabled(&self) -> bool {
202                self.ch.cont.read().chen().bit()
203            }
204
205            fn disable(&mut self) {
206                self.ch.contclr.write(|w| w.chen().bit(true));
207                while self.ch.cont.read().chbusy().bit() {}
208            }
209
210            fn force(&mut self) {
211                self.ch.econset.write(|w| w.cforce().bit(true));
212            }
213        }
214
215        impl DmaChannel<$Dmac> {
216            pub fn $Id(ch: $Dmac) -> Self {
217                // make sure that the DMA controller is enabled
218                unsafe {
219                    (*DMAC::ptr()).dmaconset.write(|w| w.on().bit(true));
220                }
221                DmaChannel { ch }
222            }
223        }
224    };
225}
226
227dma!(channel0, DMAC0);
228dma!(channel1, DMAC1);
229dma!(channel2, DMAC2);
230dma!(channel3, DMAC3);