1pub use crate::ll_api::DmaChannel;
2use crate::ll_api::{ll_cmd::*, DmaCtrl, DmaFlags};
3
4pub trait DmaDataSize: PartialOrd {}
5
6impl DmaDataSize for i8 {}
7impl DmaDataSize for i16 {}
8impl DmaDataSize for i32 {}
9impl DmaDataSize for u8 {}
10impl DmaDataSize for u16 {}
11impl DmaDataSize for u32 {}
12
13pub struct Config<'a, ST, DT> {
14 pub src: DmaSrc<'a, ST>,
15 pub dst: DmaDst<'a, DT>,
16 pub dir: DmaDir,
17 pub circular: bool,
18}
19
20#[derive(Debug, PartialEq, Eq)]
21pub enum DmaSrc<'a, T> {
22 Ref(&'a [T]),
23 Addr(usize),
24}
25
26#[derive(Debug, PartialEq, Eq)]
27pub enum DmaDst<'a, T> {
28 Ref(&'a mut [T]),
29 Addr(usize),
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum DmaDir {
34 M2M,
36 P2M,
38 M2P,
40}
41
42impl<'a, ST, DT> Config<'a, ST, DT> {
43 pub const fn new(
44 src: DmaSrc<'a, ST>,
45 dst: DmaDst<'a, DT>,
46 dir: DmaDir,
47 circular: bool,
48 ) -> Self {
49 Self {
50 src,
51 dst,
52 dir,
53 circular,
54 }
55 }
56
57 pub fn set_src(&mut self, src: DmaSrc<'a, ST>) {
58 self.src = src
59 }
60
61 pub fn set_dst(&mut self, dst: DmaDst<'a, DT>) {
62 self.dst = dst
63 }
64
65 pub fn set_dir(&mut self, dir: DmaDir) {
66 self.dir = dir
67 }
68
69 pub fn set_circular(&mut self, circular: bool) {
70 self.circular = circular
71 }
72
73 pub fn build(&self) -> Result<DmaParam, i32> {
74 let mut src_inc = false;
75 let mut dst_inc = false;
76 let (src_addr, src_buff_size) = match self.src {
77 DmaSrc::Ref(buff) => {
78 let addr = buff.as_ptr() as usize;
79 let size = buff.len();
80 src_inc = true;
81 (addr, size)
82 }
83 DmaSrc::Addr(addr) => (addr, 0),
84 };
85
86 let (dst_addr, dst_buff_size) = match &self.dst {
87 DmaDst::Ref(buff) => {
88 let addr = (*buff).as_ptr() as usize;
89 let size = buff.len();
90 dst_inc = true;
91 (addr, size)
92 }
93 DmaDst::Addr(addr) => (*addr, 0),
94 };
95
96 let src_data_size = match core::mem::size_of::<ST>() {
97 1 => DmaFlags::SrcByte,
98 2 => DmaFlags::SrcHalfWord,
99 4 => DmaFlags::SrcWord,
100 _ => return Err(-100),
101 };
102
103 let dst_data_size = match core::mem::size_of::<DT>() {
104 1 => DmaFlags::DstByte,
105 2 => DmaFlags::DstHalfWord,
106 4 => DmaFlags::DstWord,
107 _ => return Err(-200),
108 };
109
110 let dir = match self.dir {
111 DmaDir::M2M => DmaFlags::MemToMem,
112 DmaDir::P2M => DmaFlags::PeriphToMem,
113 DmaDir::M2P => DmaFlags::MemToPeriph,
114 };
115
116 let circular = if self.circular {
117 DmaFlags::CircularOn
118 } else {
119 DmaFlags::None
120 };
121
122 let inc = match (src_inc, dst_inc) {
123 (true, true) => DmaFlags::BothInc,
124 (true, false) => DmaFlags::SrcInc,
125 (false, true) => DmaFlags::DstInc,
126 (false, false) => DmaFlags::None,
127 };
128
129 let flags =
130 src_data_size as u32 | dst_data_size as u32 | dir as u32 | inc as u32 | circular as u32;
131
132 Ok(DmaParam {
133 src_addr,
134 src_buff_size,
135 dst_addr,
136 dst_buff_size,
137 flags,
138 })
139 }
140}
141
142pub struct DmaParam {
143 src_addr: usize,
144 src_buff_size: usize,
145 dst_addr: usize,
146 dst_buff_size: usize,
147 flags: u32,
148}
149
150#[derive(Clone, Debug)]
151pub struct Dma {
152 ch: DmaChannel,
153}
154
155impl Dma {
156 pub fn new(ch: DmaChannel) -> Self {
157 Dma { ch }
158 }
159
160 pub fn init<ST, DT>(&self, config: &Config<ST, DT>, extra: Option<u32>) -> Result<(), i32> {
161 let extra_flags = if let Some(extra) = extra { extra } else { 0 };
162 let param = config.build()?;
163 let result = ll_invoke_inner!(
164 INVOKE_ID_DMA_INIT,
165 self.ch,
166 param.src_addr,
167 param.src_buff_size,
168 param.dst_addr,
169 param.dst_buff_size,
170 param.flags,
171 extra_flags
172 );
173 if result == 0 {
174 Ok(())
175 } else {
176 Err(result)
177 }
178 }
179
180 pub fn start(&self) -> Result<(), i32> {
181 let result = ll_invoke_inner!(INVOKE_ID_DMA_CTRL, self.ch, DmaCtrl::Start);
182 if result == 0 {
183 Ok(())
184 } else {
185 Err(result)
186 }
187 }
188
189 pub fn stop(&self) -> Result<(), i32> {
190 let result = ll_invoke_inner!(INVOKE_ID_DMA_CTRL, self.ch, DmaCtrl::Stop);
191 if result == 0 {
192 Ok(())
193 } else {
194 Err(result)
195 }
196 }
197
198 pub fn wait(&self) -> Result<(), i32> {
199 let result = ll_invoke_inner!(INVOKE_ID_DMA_CTRL, self.ch, DmaCtrl::Wait);
200 if result == 0 {
201 Ok(())
202 } else {
203 Err(result)
204 }
205 }
206}
207
208impl Drop for Dma {
209 fn drop(&mut self) {
210 ll_invoke_inner!(INVOKE_ID_DMA_DEINIT, self.ch);
211 }
212}