stm32f1_hal/
dma.rs

1//! # Direct Memory Access
2
3pub use crate::common::dma::*;
4pub type DmaPriority = pac::dma1::ch::cr::PL;
5
6use crate::{Steal, common::wrap_trait::*, pac, rcc::Rcc};
7
8pub trait DmaInit {
9    type Channels;
10
11    fn split(self, rcc: &mut Rcc) -> Self::Channels;
12}
13
14macro_rules! dma {
15    ($DMAX:ty: ($dmaX:ident, {
16        $($CX:ident: ($ch: literal),)+
17    }),) => {
18        pub mod $dmaX {
19            use super::*;
20
21            #[non_exhaustive]
22            #[allow(clippy::manual_non_exhaustive)]
23            pub struct Channels((), $(pub $CX),+);
24
25            $(
26                pub type $CX = super::Ch<$DMAX, $ch>;
27            )+
28
29            impl DmaInit for $DMAX {
30                type Channels = Channels;
31
32                fn split(self, rcc: &mut Rcc) -> Channels {
33                    rcc.enable(&self);
34
35                    // reset the DMA control registers (stops all on-going transfers)
36                    $(
37                        self.ch($ch).cr().reset();
38                    )+
39
40                    Channels((), $(Ch::<$DMAX, $ch>{ dma: unsafe { self.steal() }}),+)
41                }
42            }
43        }
44    }
45}
46
47dma! {
48    pac::DMA1: (dma1, {
49        C1: (0),
50        C2: (1),
51        C3: (2),
52        C4: (3),
53        C5: (4),
54        C6: (5),
55        C7: (6),
56    }),
57}
58
59dma! {
60    pac::DMA2: (dma2, {
61        C1: (0),
62        C2: (1),
63        C3: (2),
64        C4: (3),
65        C5: (4),
66    }),
67}
68
69wrap_trait_deref! {
70    (pac::DMA1, pac::DMA2,),
71    pub trait RegisterBlock {
72        fn isr(&self) -> &pac::dma1::ISR;
73        fn ifcr(&self) -> &pac::dma1::IFCR;
74        fn ch(&self, n: usize) -> &pac::dma1::CH;
75    }
76}
77
78// DMA Channel ----------------------------------------------------------------
79
80pub struct Ch<DMA, const C: u8> {
81    dma: DMA,
82}
83
84impl<DMA, const C: u8> Ch<DMA, C>
85where
86    DMA: RegisterBlock,
87{
88    #[inline]
89    pub fn set_priority(&mut self, priority: DmaPriority) {
90        self.ch().cr().modify(|_, w| w.pl().variant(priority));
91    }
92
93    #[inline(always)]
94    fn ch(&self) -> &pac::dma1::CH {
95        self.dma.ch(C as usize)
96    }
97}
98
99impl<DMA, const C: u8> Steal for Ch<DMA, C>
100where
101    DMA: RegisterBlock + Steal,
102{
103    unsafe fn steal(&self) -> Self {
104        unsafe {
105            Self {
106                dma: self.dma.steal(),
107            }
108        }
109    }
110}
111
112impl<DMA, const C: u8> DmaChannel for Ch<DMA, C>
113where
114    DMA: RegisterBlock,
115{
116    #[inline]
117    fn start(&mut self) {
118        self.dma.ifcr().write(|w| w.cgif(C).set_bit());
119        self.ch().cr().modify(|_, w| w.en().set_bit());
120    }
121
122    #[inline]
123    fn stop(&mut self) {
124        self.ch().cr().modify(|_, w| w.en().clear_bit());
125        self.dma.ifcr().write(|w| w.cgif(C).set_bit());
126        self.set_transfer_length(0);
127    }
128
129    #[inline]
130    fn set_peripheral_address<T: Sized>(
131        &mut self,
132        address: usize,
133        mem_to_periph: bool,
134        increase: bool,
135        circular: bool,
136    ) {
137        self.ch()
138            .par()
139            .write(|w| unsafe { w.pa().bits(address as u32) });
140        self.ch().cr().modify(|_, w| {
141            w.mem2mem()
142                .clear_bit()
143                .pinc()
144                .bit(increase)
145                .circ()
146                .bit(circular)
147                .dir()
148                .bit(mem_to_periph);
149
150            match core::mem::size_of::<T>() {
151                2 => {
152                    w.msize().bits16();
153                    w.psize().bits16()
154                }
155                4 => {
156                    w.msize().bits32();
157                    w.psize().bits32()
158                }
159                _ => {
160                    w.msize().bits8();
161                    w.psize().bits8()
162                }
163            }
164        });
165    }
166
167    #[inline(always)]
168    fn set_memory_address(&mut self, address: usize, increase: bool) {
169        self.ch()
170            .mar()
171            .write(|w| unsafe { w.ma().bits(address as u32) });
172        self.ch().cr().modify(|_, w| w.minc().bit(increase));
173    }
174
175    #[inline(always)]
176    fn set_transfer_length(&mut self, len: usize) {
177        self.ch()
178            .ndtr()
179            .write(|w| w.ndt().set(u16::try_from(len).unwrap()));
180    }
181
182    #[inline]
183    fn set_memory_to_memory<T: Sized>(&mut self, _src_addr: usize, _dst_addr: usize, _len: usize) {
184        todo!()
185    }
186
187    #[inline]
188    fn get_unprocessed_len(&self) -> usize {
189        self.ch().ndtr().read().bits() as usize
190    }
191
192    #[inline]
193    fn in_progress(&self) -> bool {
194        self.get_unprocessed_len() != 0 && self.dma.isr().read().tcif(C).bit_is_clear()
195    }
196
197    #[inline]
198    fn set_interrupt(&mut self, event: DmaEvent, enable: bool) {
199        match event {
200            DmaEvent::HalfTransfer => self.ch().cr().modify(|_, w| w.htie().bit(enable)),
201            DmaEvent::TransferComplete => self.ch().cr().modify(|_, w| w.tcie().bit(enable)),
202        };
203    }
204
205    #[inline]
206    fn is_interrupted(&mut self, event: DmaEvent) -> bool {
207        match event {
208            DmaEvent::TransferComplete => {
209                if self.dma.isr().read().tcif(C).bit_is_set() {
210                    self.dma.ifcr().write(|w| w.ctcif(C).set_bit());
211                    true
212                } else {
213                    false
214                }
215            }
216            DmaEvent::HalfTransfer => {
217                if self.dma.isr().read().htif(C).bit_is_set() {
218                    self.dma.ifcr().write(|w| w.chtif(C).set_bit());
219                    true
220                } else {
221                    false
222                }
223            }
224        }
225    }
226}
227
228pub trait DmaBindTx<U>: DmaChannel {}
229pub trait DmaBindRx<U>: DmaChannel {}
230
231// table
232// Do NOT manually modify the code.
233// It's generated by scripts/generate_dma_table.py from scripts/table/stm32f1_dma_table.csv
234
235impl DmaBindTx<pac::USART3> for dma1::C2 {}
236impl DmaBindRx<pac::USART3> for dma1::C3 {}
237impl DmaBindTx<pac::USART1> for dma1::C4 {}
238impl DmaBindRx<pac::USART1> for dma1::C5 {}
239impl DmaBindRx<pac::USART2> for dma1::C6 {}
240impl DmaBindTx<pac::USART2> for dma1::C7 {}
241impl DmaBindRx<pac::UART4> for dma2::C3 {}
242impl DmaBindTx<pac::UART4> for dma2::C5 {}
243
244impl DmaBindRx<pac::SPI1> for dma1::C2 {}
245impl DmaBindTx<pac::SPI1> for dma1::C3 {}
246impl DmaBindRx<pac::SPI2> for dma1::C4 {}
247impl DmaBindTx<pac::SPI2> for dma1::C5 {}
248impl DmaBindRx<pac::SPI3> for dma2::C1 {}
249impl DmaBindTx<pac::SPI3> for dma2::C2 {}
250
251impl DmaBindTx<pac::I2C2> for dma1::C4 {}
252impl DmaBindRx<pac::I2C2> for dma1::C5 {}
253impl DmaBindTx<pac::I2C1> for dma1::C6 {}
254impl DmaBindRx<pac::I2C1> for dma1::C7 {}