Skip to main content

hal_mik32/
dma.rs

1//! Direct memory access controller.
2
3use core::marker::PhantomData;
4use core::sync::atomic::{Ordering, fence};
5
6use mik32_pac::{Dma as DmaPeripheral, Peripherals};
7
8pub use channel::Id as ChannelId;
9
10pub struct Dma {
11    peripheral: DmaPeripheral,
12}
13
14pub struct Channels {
15    pub channel1: Channel1,
16    pub channel2: Channel2,
17    pub channel3: Channel3,
18    pub channel4: Channel4,
19}
20
21pub type Channel1 = Channel<channel::Ch1>;
22pub type Channel2 = Channel<channel::Ch2>;
23pub type Channel3 = Channel<channel::Ch3>;
24pub type Channel4 = Channel<channel::Ch4>;
25
26pub mod channel {
27    mod sealed {
28        pub trait Sealed {}
29    }
30
31    pub trait Id: sealed::Sealed {
32        const INDEX: u8;
33    }
34
35    pub enum Ch1 {}
36    pub enum Ch2 {}
37    pub enum Ch3 {}
38    pub enum Ch4 {}
39
40    impl sealed::Sealed for Ch1 {}
41    impl sealed::Sealed for Ch2 {}
42    impl sealed::Sealed for Ch3 {}
43    impl sealed::Sealed for Ch4 {}
44
45    impl Id for Ch1 {
46        const INDEX: u8 = 0;
47    }
48
49    impl Id for Ch2 {
50        const INDEX: u8 = 1;
51    }
52
53    impl Id for Ch3 {
54        const INDEX: u8 = 2;
55    }
56
57    impl Id for Ch4 {
58        const INDEX: u8 = 3;
59    }
60}
61
62pub struct Channel<CHANNEL: ChannelId> {
63    _private: PhantomData<*mut CHANNEL>,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub enum Error {
68    EmptyBuffer,
69    TransferTooLong,
70    Timeout,
71    Bus,
72    InvalidChannel,
73}
74
75impl Dma {
76    pub fn new(peripheral: DmaPeripheral) -> Self {
77        let p = unsafe { Peripherals::steal() };
78        p.pm.clk_ahb_set().modify(|_, w| w.dma().enable());
79        Self { peripheral }
80    }
81
82    pub fn split(self) -> Channels {
83        let _ = self.peripheral;
84        Channels {
85            channel1: Channel::new(),
86            channel2: Channel::new(),
87            channel3: Channel::new(),
88            channel4: Channel::new(),
89        }
90    }
91}
92
93impl<CHANNEL: ChannelId> Channel<CHANNEL> {
94    const fn new() -> Self {
95        Self {
96            _private: PhantomData,
97        }
98    }
99
100    pub fn is_ready(&self) -> bool {
101        let dma = unsafe { &*DmaPeripheral::ptr() };
102        dma.status().read().channel_ready().bits() & (1 << CHANNEL::INDEX) != 0
103    }
104
105    pub fn stop(&mut self) {
106        unsafe { channel_register(CHANNEL::INDEX, 3).write_volatile(0) };
107        fence(Ordering::SeqCst);
108    }
109
110    pub(crate) fn transfer(
111        &mut self,
112        source: *const u8,
113        destination: *mut u8,
114        length: usize,
115        config: u32,
116        timeout: u32,
117    ) -> Result<(), Error> {
118        self.start(source, destination, length, config)?;
119
120        for _ in 0..timeout {
121            if self.poll()? {
122                return Ok(());
123            }
124            core::hint::spin_loop();
125        }
126
127        self.stop();
128        fence(Ordering::Acquire);
129        Err(Error::Timeout)
130    }
131
132    pub(crate) fn start(
133        &mut self,
134        source: *const u8,
135        destination: *mut u8,
136        length: usize,
137        config: u32,
138    ) -> Result<(), Error> {
139        if length == 0 {
140            return Err(Error::EmptyBuffer);
141        }
142        if length > u32::MAX as usize {
143            return Err(Error::TransferTooLong);
144        }
145
146        self.stop();
147        fence(Ordering::Release);
148        unsafe {
149            channel_register(CHANNEL::INDEX, 0).write_volatile(destination as usize as u32);
150            channel_register(CHANNEL::INDEX, 1).write_volatile(source as usize as u32);
151            channel_register(CHANNEL::INDEX, 2).write_volatile(length as u32 - 1);
152            channel_register(CHANNEL::INDEX, 3).write_volatile(config | 1);
153        }
154
155        Ok(())
156    }
157
158    pub(crate) fn poll(&mut self) -> Result<bool, Error> {
159        let dma = unsafe { &*DmaPeripheral::ptr() };
160        let status = dma.status().read();
161        if status.bits() & (1 << (8 + CHANNEL::INDEX)) != 0 {
162            self.stop();
163            fence(Ordering::Acquire);
164            return Err(Error::Bus);
165        }
166
167        let ready = status.channel_ready().bits() & (1 << CHANNEL::INDEX) != 0;
168        if ready {
169            fence(Ordering::Acquire);
170        }
171        Ok(ready)
172    }
173}
174
175#[inline(always)]
176unsafe fn channel_register(channel: u8, register: u8) -> *mut u32 {
177    unsafe { (DmaPeripheral::ptr() as *mut u32).add(channel as usize * 4 + register as usize) }
178}