aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/dma/bdma.rs2
-rw-r--r--embassy-stm32/src/dma/dma.rs118
-rw-r--r--embassy-stm32/src/dma/mod.rs7
3 files changed, 92 insertions, 35 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index c86999bea..528e49f42 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -139,7 +139,7 @@ unsafe fn _get_remaining_transfers(dma: pac::bdma::Dma, ch: u8) -> u16 {
139} 139}
140 140
141/// Sets the waker for the specified DMA channel 141/// Sets the waker for the specified DMA channel
142unsafe fn _set_waker(dma: pac::bdma::Dma, state_number: u8, waker: &Waker) { 142unsafe fn _set_waker(_dma: pac::bdma::Dma, state_number: u8, waker: &Waker) {
143 let n = state_number as usize; 143 let n = state_number as usize;
144 STATE.ch_wakers[n].register(waker); 144 STATE.ch_wakers[n].register(waker);
145} 145}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 672e632f8..257f21a73 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -53,10 +53,7 @@ pub(crate) unsafe fn do_transfer(
53 // Reset status 53 // Reset status
54 let isrn = channel_number as usize / 4; 54 let isrn = channel_number as usize / 4;
55 let isrbit = channel_number as usize % 4; 55 let isrbit = channel_number as usize % 4;
56 dma.ifcr(isrn).write(|w| { 56 _reset_status(&dma, isrn, isrbit);
57 w.set_tcif(isrbit, true);
58 w.set_teif(isrbit, true);
59 });
60 57
61 let ch = dma.st(channel_number as _); 58 let ch = dma.st(channel_number as _);
62 59
@@ -64,37 +61,23 @@ pub(crate) unsafe fn do_transfer(
64 _stop(&dma, channel_number); 61 _stop(&dma, channel_number);
65 }); 62 });
66 63
67 #[cfg(dmamux)]
68 super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
69
70 // "Preceding reads and writes cannot be moved past subsequent writes." 64 // "Preceding reads and writes cannot be moved past subsequent writes."
71 fence(Ordering::Release); 65 fence(Ordering::Release);
72 66
73 unsafe { 67 // Actually start the transaction
74 ch.par().write_value(peri_addr as u32); 68 _start_transfer(
75 ch.m0ar().write_value(mem_addr as u32); 69 request,
76 ch.ndtr().write_value(regs::Ndtr(mem_len as _)); 70 dir,
77 ch.cr().write(|w| { 71 peri_addr,
78 w.set_dir(dir); 72 mem_addr,
79 w.set_msize(vals::Size::BITS8); 73 mem_len,
80 w.set_psize(vals::Size::BITS8); 74 incr_mem,
81 if incr_mem { 75 ch,
82 w.set_minc(vals::Inc::INCREMENTED); 76 #[cfg(dmamux)]
83 } else { 77 dmamux_regs,
84 w.set_minc(vals::Inc::FIXED); 78 #[cfg(dmamux)]
85 } 79 dmamux_ch_num,
86 w.set_pinc(vals::Inc::FIXED); 80 );
87 w.set_teie(true);
88 w.set_tcie(true);
89 #[cfg(dma_v1)]
90 w.set_trbuff(true);
91
92 #[cfg(dma_v2)]
93 w.set_chsel(request);
94
95 w.set_en(true);
96 });
97 }
98 81
99 async move { 82 async move {
100 let res = poll_fn(|cx| { 83 let res = poll_fn(|cx| {
@@ -118,6 +101,55 @@ pub(crate) unsafe fn do_transfer(
118 } 101 }
119} 102}
120 103
104unsafe fn _reset_status(dma: &crate::pac::dma::Dma, isrn: usize, isrbit: usize) {
105 dma.ifcr(isrn).write(|w| {
106 w.set_tcif(isrbit, true);
107 w.set_teif(isrbit, true);
108 });
109}
110
111unsafe fn _start_transfer(
112 request: Request,
113 dir: vals::Dir,
114 peri_addr: *const u8,
115 mem_addr: *mut u8,
116 mem_len: usize,
117 incr_mem: bool,
118 ch: crate::pac::dma::St,
119 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
120 #[cfg(dmamux)] dmamux_ch_num: u8,
121) {
122 #[cfg(dmamux)]
123 super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
124
125 // "Preceding reads and writes cannot be moved past subsequent writes."
126 fence(Ordering::Release);
127
128 ch.par().write_value(peri_addr as u32);
129 ch.m0ar().write_value(mem_addr as u32);
130 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
131 ch.cr().write(|w| {
132 w.set_dir(dir);
133 w.set_msize(vals::Size::BITS8);
134 w.set_psize(vals::Size::BITS8);
135 if incr_mem {
136 w.set_minc(vals::Inc::INCREMENTED);
137 } else {
138 w.set_minc(vals::Inc::FIXED);
139 }
140 w.set_pinc(vals::Inc::FIXED);
141 w.set_teie(true);
142 w.set_tcie(true);
143 #[cfg(dma_v1)]
144 w.set_trbuff(true);
145
146 #[cfg(dma_v2)]
147 w.set_chsel(request);
148
149 w.set_en(true);
150 });
151}
152
121/// Stops the DMA channel. 153/// Stops the DMA channel.
122unsafe fn _stop(dma: &pac::dma::Dma, ch: u8) { 154unsafe fn _stop(dma: &pac::dma::Dma, ch: u8) {
123 // get a handle on the channel itself 155 // get a handle on the channel itself
@@ -152,7 +184,7 @@ unsafe fn _get_remaining_transfers(dma: &pac::dma::Dma, ch: u8) -> u16 {
152} 184}
153 185
154/// Sets the waker for the specified DMA channel 186/// Sets the waker for the specified DMA channel
155unsafe fn _set_waker(dma: &pac::dma::Dma, state_number: u8, waker: &Waker) { 187unsafe fn _set_waker(_dma: &pac::dma::Dma, state_number: u8, waker: &Waker) {
156 let n = state_number as usize; 188 let n = state_number as usize;
157 STATE.ch_wakers[n].register(waker); 189 STATE.ch_wakers[n].register(waker);
158} 190}
@@ -295,6 +327,26 @@ pac::dma_channels! {
295 fn set_waker<'a>(&'a mut self, waker: &'a Waker) { 327 fn set_waker<'a>(&'a mut self, waker: &'a Waker) {
296 unsafe {_set_waker(&crate::pac::$dma_peri, $channel_num, waker )} 328 unsafe {_set_waker(&crate::pac::$dma_peri, $channel_num, waker )}
297 } 329 }
330 fn start<'a>(&'a mut self, request: Request, buf: &'a [u8], dst: *mut u8){
331 unsafe {
332 let isrn = $channel_num as usize / 4;
333 let isrbit = $channel_num as usize % 4;
334 _reset_status(&crate::pac::$dma_peri, isrn, isrbit);
335 _start_transfer(
336 request,
337 vals::Dir::MEMORYTOPERIPHERAL,
338 dst,
339 buf.as_ptr() as *mut u8,
340 buf.len(),
341 true,
342 crate::pac::$dma_peri.st($channel_num as _),
343 #[cfg(dmamux)]
344 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
345 #[cfg(dmamux)]
346 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
347 )
348 }
349 }
298 } 350 }
299 }; 351 };
300} 352}
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index aa2da1fa9..48b229c2e 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -52,11 +52,16 @@ pub trait Channel: sealed::Channel {
52 dst: *mut u8, 52 dst: *mut u8,
53 ) -> Self::WriteFuture<'a>; 53 ) -> Self::WriteFuture<'a>;
54 54
55 /// Stops this channel.
55 fn stop<'a>(&'a mut self); 56 fn stop<'a>(&'a mut self);
56 57 /// Returns whether this channel is active or stopped.
57 fn is_stopped<'a>(&self) -> bool; 58 fn is_stopped<'a>(&self) -> bool;
59 /// Returns the total number of remaining transfers .
58 fn remaining_transfers<'a>(&'a mut self) -> u16; 60 fn remaining_transfers<'a>(&'a mut self) -> u16;
61 /// Sets the waker that is called when this channel completes/
59 fn set_waker(&mut self, waker: &Waker); 62 fn set_waker(&mut self, waker: &Waker);
63 /// Starts this channel.
64 fn start<'a>(&'a mut self, request: Request, buf: &'a [u8], dst: *mut u8);
60} 65}
61 66
62pub struct NoDma; 67pub struct NoDma;