1use 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}