embedded_c_sdk_bind_hal/
dma.rs

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    /// Memory to memory direction
35    M2M,
36    /// Peripheral to memory direction
37    P2M,
38    /// Memory to peripheral direction
39    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}