@@ -10,7 +10,11 @@ use crate::{
10
10
stm32:: { self , dma1:: ch:: cr} ,
11
11
} ;
12
12
use cast:: u16;
13
- use core:: sync:: atomic:: { self , Ordering } ;
13
+ use core:: {
14
+ mem:: { self , MaybeUninit } ,
15
+ ops:: { Deref , DerefMut } ,
16
+ sync:: atomic:: { self , Ordering } ,
17
+ } ;
14
18
use stable_deref_trait:: StableDeref ;
15
19
16
20
/// Extension trait to split a DMA peripheral into independent channels
@@ -29,15 +33,46 @@ pub struct Transfer<B, C: Channel, T> {
29
33
}
30
34
31
35
impl < B , C : Channel , T > Transfer < B , C , T > {
32
- /// Start a DMA transfer.
33
- ///
36
+ /// Start a DMA write transfer.
37
+ pub fn start_write ( mut buffer : B , mut channel : C , target : T ) -> Self
38
+ where
39
+ B : WriteBuffer + ' static ,
40
+ T : Target < C > ,
41
+ {
42
+ let ( ptr, len) = buffer. write_buffer ( ) ;
43
+
44
+ channel. set_memory_address ( ptr as u32 , Increment :: Enable ) ;
45
+ channel. set_transfer_length ( len) ;
46
+ channel. set_word_size :: < B :: Word > ( ) ;
47
+ channel. set_direction ( Direction :: FromPeripheral ) ;
48
+
49
+ unsafe { Self :: start ( buffer, channel, target) }
50
+ }
51
+
52
+ /// Start a DMA read transfer.
53
+ pub fn start_read ( buffer : B , mut channel : C , target : T ) -> Self
54
+ where
55
+ B : ReadBuffer + ' static ,
56
+ T : Target < C > ,
57
+ {
58
+ let ( ptr, len) = buffer. read_buffer ( ) ;
59
+
60
+ channel. set_memory_address ( ptr as u32 , Increment :: Enable ) ;
61
+ channel. set_transfer_length ( len) ;
62
+ channel. set_word_size :: < B :: Word > ( ) ;
63
+ channel. set_direction ( Direction :: FromMemory ) ;
64
+
65
+ unsafe { Self :: start ( buffer, channel, target) }
66
+ }
67
+
34
68
/// # Safety
35
69
///
36
- /// Callers must ensure that the DMA channel is configured correctly for
37
- /// the given target and buffer.
38
- pub unsafe fn start ( buffer : B , mut channel : C , target : T ) -> Self
70
+ /// Callers must ensure that:
71
+ ///
72
+ /// - the given buffer will be valid for the duration of the transfer
73
+ /// - the DMA channel is configured correctly for the given target and buffer
74
+ unsafe fn start ( buffer : B , mut channel : C , target : T ) -> Self
39
75
where
40
- B : StableDeref + ' static ,
41
76
T : Target < C > ,
42
77
{
43
78
assert ! ( !channel. is_enabled( ) ) ;
@@ -100,6 +135,211 @@ impl<B, C: Channel, T> TransferInner<B, C, T> {
100
135
}
101
136
}
102
137
138
+ /// Trait for buffers that can be given to DMA for reading.
139
+ ///
140
+ /// # Safety
141
+ ///
142
+ /// The implementing type must be safe to use for DMA reads. This means:
143
+ ///
144
+ /// - It must be a pointer that references the actual buffer.
145
+ /// - The requirements documented on `read_buffer` must be fulfilled.
146
+ pub unsafe trait ReadBuffer {
147
+ type Word ;
148
+
149
+ /// Provide a buffer usable for DMA reads.
150
+ ///
151
+ /// The return value is:
152
+ ///
153
+ /// - pointer to the start of the buffer
154
+ /// - buffer size in words
155
+ ///
156
+ /// # Safety
157
+ ///
158
+ /// - This function must always return the same values, if called multiple
159
+ /// times.
160
+ /// - The memory specified by the returned pointer and size must not be
161
+ /// freed as long as `self` is not dropped.
162
+ fn read_buffer ( & self ) -> ( * const Self :: Word , usize ) ;
163
+ }
164
+
165
+ /// Trait for buffers that can be given to DMA for writing.
166
+ ///
167
+ /// # Safety
168
+ ///
169
+ /// The implementing type must be safe to use for DMA writes. This means:
170
+ ///
171
+ /// - It must be a pointer that references the actual buffer.
172
+ /// - `Target` must be a type that is valid for any possible byte pattern.
173
+ /// - The requirements documented on `write_buffer` must be fulfilled.
174
+ pub unsafe trait WriteBuffer {
175
+ type Word ;
176
+
177
+ /// Provide a buffer usable for DMA writes.
178
+ ///
179
+ /// The return value is:
180
+ ///
181
+ /// - pointer to the start of the buffer
182
+ /// - buffer size in words
183
+ ///
184
+ /// # Safety
185
+ ///
186
+ /// - This function must always return the same values, if called multiple
187
+ /// times.
188
+ /// - The memory specified by the returned pointer and size must not be
189
+ /// freed as long as `self` is not dropped.
190
+ fn write_buffer ( & mut self ) -> ( * mut Self :: Word , usize ) ;
191
+ }
192
+
193
+ // Blanked implementations for common DMA buffer types.
194
+
195
+ unsafe impl < B , T > ReadBuffer for B
196
+ where
197
+ B : Deref < Target = T > + StableDeref ,
198
+ T : ReadTarget + ?Sized ,
199
+ {
200
+ type Word = T :: Word ;
201
+
202
+ fn read_buffer ( & self ) -> ( * const Self :: Word , usize ) {
203
+ self . as_read_buffer ( )
204
+ }
205
+ }
206
+
207
+ unsafe impl < B , T > WriteBuffer for B
208
+ where
209
+ B : DerefMut < Target = T > + StableDeref ,
210
+ T : WriteTarget + ?Sized ,
211
+ {
212
+ type Word = T :: Word ;
213
+
214
+ fn write_buffer ( & mut self ) -> ( * mut Self :: Word , usize ) {
215
+ self . as_write_buffer ( )
216
+ }
217
+ }
218
+
219
+ /// Trait for DMA word types used by the blanket DMA buffer impls.
220
+ ///
221
+ /// # Safety
222
+ ///
223
+ /// Types that implement this trait must be valid for every possible byte
224
+ /// pattern. This is to ensure that, whatever DMA writes into the buffer,
225
+ /// we won't get UB due to invalid values.
226
+ pub unsafe trait Word { }
227
+
228
+ unsafe impl Word for u8 { }
229
+ unsafe impl Word for u16 { }
230
+ unsafe impl Word for u32 { }
231
+
232
+ /// Trait for `Deref` targets used by the blanket `DmaReadBuffer` impl.
233
+ ///
234
+ /// This trait exists solely to work around
235
+ /// https://github.com/rust-lang/rust/issues/20400.
236
+ ///
237
+ /// # Safety
238
+ ///
239
+ /// - `as_read_buffer` must adhere to the safety requirements
240
+ /// documented for `DmaReadBuffer::dma_read_buffer`.
241
+ pub unsafe trait ReadTarget {
242
+ type Word : Word ;
243
+
244
+ fn as_read_buffer ( & self ) -> ( * const Self :: Word , usize ) {
245
+ let ptr = self as * const _ as * const Self :: Word ;
246
+ let len = mem:: size_of_val ( self ) / mem:: size_of :: < Self :: Word > ( ) ;
247
+ ( ptr, len)
248
+ }
249
+ }
250
+
251
+ /// Trait for `DerefMut` targets used by the blanket `DmaWriteBuffer` impl.
252
+ ///
253
+ /// This trait exists solely to work around
254
+ /// https://github.com/rust-lang/rust/issues/20400.
255
+ ///
256
+ /// # Safety
257
+ ///
258
+ /// - `as_write_buffer` must adhere to the safety requirements
259
+ /// documented for `DmaWriteBuffer::dma_write_buffer`.
260
+ pub unsafe trait WriteTarget {
261
+ type Word : Word ;
262
+
263
+ fn as_write_buffer ( & mut self ) -> ( * mut Self :: Word , usize ) {
264
+ let ptr = self as * mut _ as * mut Self :: Word ;
265
+ let len = mem:: size_of_val ( self ) / mem:: size_of :: < Self :: Word > ( ) ;
266
+ ( ptr, len)
267
+ }
268
+ }
269
+
270
+ unsafe impl < W : Word > ReadTarget for W {
271
+ type Word = W ;
272
+ }
273
+
274
+ unsafe impl < W : Word > WriteTarget for W {
275
+ type Word = W ;
276
+ }
277
+
278
+ unsafe impl < T : ReadTarget > ReadTarget for [ T ] {
279
+ type Word = T :: Word ;
280
+ }
281
+
282
+ unsafe impl < T : WriteTarget > WriteTarget for [ T ] {
283
+ type Word = T :: Word ;
284
+ }
285
+
286
+ macro_rules! dma_target_array_impls {
287
+ ( $( $i: expr, ) + ) => {
288
+ $(
289
+ unsafe impl <T : ReadTarget > ReadTarget for [ T ; $i] {
290
+ type Word = T :: Word ;
291
+ }
292
+
293
+ unsafe impl <T : WriteTarget > WriteTarget for [ T ; $i] {
294
+ type Word = T :: Word ;
295
+ }
296
+ ) +
297
+ } ;
298
+ }
299
+
300
+ #[ rustfmt:: skip]
301
+ dma_target_array_impls ! (
302
+ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,
303
+ 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 ,
304
+ 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 ,
305
+ 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 ,
306
+ 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 ,
307
+ 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 ,
308
+ 60 , 61 , 62 , 63 , 64 , 65 , 66 , 67 , 68 , 69 ,
309
+ 70 , 71 , 72 , 73 , 74 , 75 , 76 , 77 , 78 , 79 ,
310
+ 80 , 81 , 82 , 83 , 84 , 85 , 86 , 87 , 88 , 89 ,
311
+ 90 , 91 , 92 , 93 , 94 , 95 , 96 , 97 , 98 , 99 ,
312
+ 100 , 101 , 102 , 103 , 104 , 105 , 106 , 107 , 108 , 109 ,
313
+ 110 , 111 , 112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 ,
314
+ 120 , 121 , 122 , 123 , 124 , 125 , 126 , 127 , 128 , 129 ,
315
+ 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 , 138 , 139 ,
316
+ 140 , 141 , 142 , 143 , 144 , 145 , 146 , 147 , 148 , 149 ,
317
+ 150 , 151 , 152 , 153 , 154 , 155 , 156 , 157 , 158 , 159 ,
318
+ 160 , 161 , 162 , 163 , 164 , 165 , 166 , 167 , 168 , 169 ,
319
+ 170 , 171 , 172 , 173 , 174 , 175 , 176 , 177 , 178 , 179 ,
320
+ 180 , 181 , 182 , 183 , 184 , 185 , 186 , 187 , 188 , 189 ,
321
+ 190 , 191 , 192 , 193 , 194 , 195 , 196 , 197 , 198 , 199 ,
322
+ 200 , 201 , 202 , 203 , 204 , 205 , 206 , 207 , 208 , 209 ,
323
+ 210 , 211 , 212 , 213 , 214 , 215 , 216 , 217 , 218 , 219 ,
324
+ 220 , 221 , 222 , 223 , 224 , 225 , 226 , 227 , 228 , 229 ,
325
+ 230 , 231 , 232 , 233 , 234 , 235 , 236 , 237 , 238 , 239 ,
326
+ 240 , 241 , 242 , 243 , 244 , 245 , 246 , 247 , 248 , 249 ,
327
+ 250 , 251 , 252 , 253 , 254 , 255 , 256 ,
328
+
329
+ 1 << 9 ,
330
+ 1 << 10 ,
331
+ 1 << 11 ,
332
+ 1 << 12 ,
333
+ 1 << 13 ,
334
+ 1 << 14 ,
335
+ 1 << 15 ,
336
+ 1 << 16 ,
337
+ ) ;
338
+
339
+ unsafe impl < T : WriteTarget > WriteTarget for MaybeUninit < T > {
340
+ type Word = T :: Word ;
341
+ }
342
+
103
343
/// DMA address increment mode
104
344
pub enum Increment {
105
345
/// Enable increment
@@ -117,26 +357,6 @@ impl From<Increment> for cr::PINC_A {
117
357
}
118
358
}
119
359
120
- /// DMA word size
121
- pub enum WordSize {
122
- /// 8 bits
123
- Bits8 ,
124
- /// 16 bits
125
- Bits16 ,
126
- /// 32 bits
127
- Bits32 ,
128
- }
129
-
130
- impl From < WordSize > for cr:: PSIZE_A {
131
- fn from ( size : WordSize ) -> Self {
132
- match size {
133
- WordSize :: Bits8 => cr:: PSIZE_A :: BITS8 ,
134
- WordSize :: Bits16 => cr:: PSIZE_A :: BITS16 ,
135
- WordSize :: Bits32 => cr:: PSIZE_A :: BITS32 ,
136
- }
137
- }
138
- }
139
-
140
360
/// Channel priority level
141
361
pub enum Priority {
142
362
/// Low
@@ -251,8 +471,16 @@ pub trait Channel: private::Channel {
251
471
}
252
472
253
473
/// Set the word size
254
- fn set_word_size ( & mut self , size : WordSize ) {
255
- let psize = size. into ( ) ;
474
+ fn set_word_size < W > ( & mut self ) {
475
+ use cr:: PSIZE_A :: * ;
476
+
477
+ let psize = match mem:: size_of :: < W > ( ) {
478
+ 1 => BITS8 ,
479
+ 2 => BITS16 ,
480
+ 4 => BITS32 ,
481
+ s => panic ! ( "unsupported word size: {}" , s) ,
482
+ } ;
483
+
256
484
self . ch ( ) . cr . modify ( |_, w| {
257
485
w. psize ( ) . variant ( psize) ;
258
486
w. msize ( ) . variant ( psize)
0 commit comments