|
1 | 1 | //! Use the DMA Controller to perform transfers using the SERCOM peripheral
|
2 | 2 | //!
|
3 |
| -//! See the [`mod@uart`], [`mod@i2c`] and [`mod@spi`] modules for the |
4 |
| -//! corresponding DMA transfer implementations. |
| 3 | +//! See the [`uart`], [`i2c`](crate::sercom::i2c) and |
| 4 | +//! [`spi`](crate::sercom::spi) modules for the corresponding DMA transfer |
| 5 | +//! implementations. |
5 | 6 |
|
6 | 7 | use core::{marker::PhantomData, ops::Range};
|
7 | 8 |
|
8 | 9 | use atsamd_hal_macros::hal_macro_helper;
|
9 | 10 |
|
10 |
| -use crate::{ |
11 |
| - dmac::{ |
12 |
| - self, Beat, Buffer, Transfer, TriggerAction, |
13 |
| - channel::{AnyChannel, Busy, Channel, InterruptFlags, Ready}, |
14 |
| - sram::DmacDescriptor, |
15 |
| - transfer::BufferPair, |
16 |
| - }, |
17 |
| - sercom::{ |
18 |
| - Sercom, |
19 |
| - i2c::{self, I2c}, |
20 |
| - spi::{self, Spi}, |
21 |
| - uart::{self, Uart}, |
22 |
| - }, |
| 11 | +use crate::dmac::{ |
| 12 | + self, Beat, Buffer, Transfer, TriggerAction, |
| 13 | + channel::{AnyChannel, Busy, Channel, InterruptFlags, Ready}, |
| 14 | + sram::DmacDescriptor, |
| 15 | + transfer::BufferPair, |
| 16 | +}; |
| 17 | +use crate::sercom::{ |
| 18 | + Sercom, |
| 19 | + uart::{self, Uart}, |
23 | 20 | };
|
24 | 21 |
|
25 | 22 | /// Wrapper type over an `&[T]` that can be used as a source buffer for DMA
|
@@ -142,172 +139,6 @@ unsafe impl<T: Beat> Buffer for SercomPtr<T> {
|
142 | 139 | }
|
143 | 140 | }
|
144 | 141 |
|
145 |
| -//============================================================================= |
146 |
| -// I2C DMA transfers |
147 |
| -//============================================================================= |
148 |
| - |
149 |
| -/// Token type representing an [`I2c`] for which the bus is |
150 |
| -/// ready to start a transaction. |
151 |
| -/// |
152 |
| -/// For use with [`send_with_dma`](super::i2c::I2c::send_with_dma) and |
153 |
| -/// [`receive_with_dma`](super::i2c::I2c::send_with_dma). |
154 |
| -#[deprecated( |
155 |
| - since = "0.19.0", |
156 |
| - note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
157 |
| -)] |
158 |
| -pub struct I2cBusReady; |
159 |
| - |
160 |
| -unsafe impl<C: i2c::AnyConfig> Buffer for I2c<C> { |
161 |
| - type Beat = i2c::Word; |
162 |
| - |
163 |
| - #[inline] |
164 |
| - fn dma_ptr(&mut self) -> *mut Self::Beat { |
165 |
| - self.data_ptr() |
166 |
| - } |
167 |
| - |
168 |
| - #[inline] |
169 |
| - fn incrementing(&self) -> bool { |
170 |
| - false |
171 |
| - } |
172 |
| - |
173 |
| - #[inline] |
174 |
| - fn buffer_len(&self) -> usize { |
175 |
| - 1 |
176 |
| - } |
177 |
| -} |
178 |
| - |
179 |
| -impl<C: i2c::AnyConfig> I2c<C> { |
180 |
| - /// Initialize the bus to start receiving with DMA. |
181 |
| - /// |
182 |
| - /// In reality, this function only checks whether or not the I2C bus is |
183 |
| - /// ready to accept a new transaction. A call to [`init_dma_transfer`] |
184 |
| - /// should immediately be followed by a call to [`send_with_dma`] or |
185 |
| - /// [`receive_with_dma`]. |
186 |
| - /// |
187 |
| - /// ```no_run |
188 |
| - /// # fn init_transfer<A: i2c::AnyConfig, C: AnyChannel<dmac::Ready>>(i2c: I2c<A>, chan0: C, buf_src: &'static mut [u8]){ |
189 |
| - /// // Assume `i2c` is a fully configured `I2c`, and `chan0` a fully configured `dmac::Channel`. |
190 |
| - /// let token = i2c.init_dma_transfer()?; |
191 |
| - /// i2c.send_with_dma(ADDRESS, token, buf_src, chan0); |
192 |
| - /// # } |
193 |
| - /// ``` |
194 |
| - /// |
195 |
| - /// [`init_dma_transfer`]: super::i2c::I2c::init_dma_transfer |
196 |
| - /// [`send_with_dma`]: super::i2c::I2c::send_with_dma |
197 |
| - /// [`receive_with_dma`]: super::i2c::I2c::receive_with_dma |
198 |
| - #[deprecated( |
199 |
| - since = "0.19.0", |
200 |
| - note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
201 |
| - )] |
202 |
| - #[allow(deprecated)] |
203 |
| - pub fn init_dma_transfer(&mut self) -> Result<I2cBusReady, super::i2c::Error> { |
204 |
| - self.check_bus_status()?; |
205 |
| - Ok(I2cBusReady) |
206 |
| - } |
207 |
| - |
208 |
| - /// Transform an [`I2c`] into a DMA [`Transfer`]) and |
209 |
| - /// start receiving into the provided buffer. The buffer length must be 255 |
210 |
| - /// bytes or shorter. |
211 |
| - /// |
212 |
| - /// It is recommended that you check for errors after the transfer is |
213 |
| - /// complete by calling [`read_status`](I2c::read_status). |
214 |
| - #[deprecated( |
215 |
| - since = "0.19.0", |
216 |
| - note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
217 |
| - )] |
218 |
| - #[allow(deprecated)] |
219 |
| - #[hal_macro_helper] |
220 |
| - pub fn receive_with_dma<Ch, B>( |
221 |
| - self, |
222 |
| - address: u8, |
223 |
| - _ready_token: I2cBusReady, |
224 |
| - buf: B, |
225 |
| - mut channel: Ch, |
226 |
| - ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>> |
227 |
| - where |
228 |
| - Ch: AnyChannel<Status = Ready>, |
229 |
| - B: Buffer<Beat = i2c::Word> + 'static, |
230 |
| - { |
231 |
| - let len = buf.buffer_len(); |
232 |
| - assert!(len > 0 && len <= 255); |
233 |
| - |
234 |
| - channel |
235 |
| - .as_mut() |
236 |
| - .enable_interrupts(InterruptFlags::new().with_tcmpl(true)); |
237 |
| - |
238 |
| - #[hal_cfg("sercom0-d5x")] |
239 |
| - let trigger_action = TriggerAction::Burst; |
240 |
| - |
241 |
| - #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] |
242 |
| - let trigger_action = TriggerAction::Beat; |
243 |
| - |
244 |
| - // SAFETY: This is safe because the of the `'static` bound check |
245 |
| - // for `B`, and the fact that the buffer length of an `I2c` is always 1. |
246 |
| - let xfer = unsafe { dmac::Transfer::new_unchecked(channel, self, buf, false) }; |
247 |
| - let mut xfer = xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action); |
248 |
| - |
249 |
| - // SAFETY: we borrow the source from under a `Busy` transfer. While the type |
250 |
| - // system believes the transfer is running, we haven't enabled it in the |
251 |
| - // I2C peripheral yet, and so a trigger won't happen until we call |
252 |
| - // `start_dma_read`. |
253 |
| - unsafe { xfer.borrow_source().start_dma_read(address, len as u8) }; |
254 |
| - xfer |
255 |
| - } |
256 |
| - |
257 |
| - /// Transform an [`I2c`] into a DMA [`Transfer`]) and |
258 |
| - /// start sending the provided buffer. The buffer length must be 255 bytes |
259 |
| - /// or shorter. |
260 |
| - /// |
261 |
| - /// It is recommended that you check for errors after the transfer is |
262 |
| - /// complete by calling [`read_status`](I2c::read_status). |
263 |
| - #[inline] |
264 |
| - #[hal_macro_helper] |
265 |
| - #[deprecated( |
266 |
| - since = "0.19.0", |
267 |
| - note = "Use `I2c::with_dma_chahnnel` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
268 |
| - )] |
269 |
| - #[allow(deprecated)] |
270 |
| - pub fn send_with_dma<Ch, B>( |
271 |
| - self, |
272 |
| - address: u8, |
273 |
| - _ready_token: I2cBusReady, |
274 |
| - buf: B, |
275 |
| - mut channel: Ch, |
276 |
| - ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>> |
277 |
| - where |
278 |
| - Ch: AnyChannel<Status = Ready>, |
279 |
| - B: Buffer<Beat = i2c::Word> + 'static, |
280 |
| - { |
281 |
| - let len = buf.buffer_len(); |
282 |
| - assert!(len > 0 && len <= 255); |
283 |
| - |
284 |
| - channel |
285 |
| - .as_mut() |
286 |
| - .enable_interrupts(InterruptFlags::new().with_tcmpl(true)); |
287 |
| - |
288 |
| - #[hal_cfg("sercom0-d5x")] |
289 |
| - let trigger_action = TriggerAction::Burst; |
290 |
| - |
291 |
| - #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] |
292 |
| - let trigger_action = TriggerAction::Beat; |
293 |
| - |
294 |
| - // SAFETY: This is safe because the of the `'static` bound check |
295 |
| - // for `B`, and the fact that the buffer length of an `I2c` is always 1. |
296 |
| - let xfer = unsafe { dmac::Transfer::new_unchecked(channel, buf, self, false) }; |
297 |
| - let mut xfer = xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action); |
298 |
| - |
299 |
| - // SAFETY: we borrow the source from under a `Busy` transfer. While the type |
300 |
| - // system believes the transfer is running, we haven't enabled it in the |
301 |
| - // I2C peripheral yet, and so a trigger won't happen until we call |
302 |
| - // `start_dma_write`. |
303 |
| - unsafe { |
304 |
| - xfer.borrow_destination() |
305 |
| - .start_dma_write(address, len as u8) |
306 |
| - }; |
307 |
| - xfer |
308 |
| - } |
309 |
| -} |
310 |
| - |
311 | 142 | //=============================================================================
|
312 | 143 | // UART DMA transfers
|
313 | 144 | //=============================================================================
|
@@ -348,7 +179,7 @@ where
|
348 | 179 | /// buffer. If you'd rather use DMA with the blocking
|
349 | 180 | /// [`embedded_io::Read`](crate::embedded_io::Read) trait, and avoid having
|
350 | 181 | /// to use static buffers,
|
351 |
| - /// use[`Uart::with_rx_channel`](Self::with_tx_channel) instead. |
| 182 | + /// use [`Uart::with_rx_channel`](Self::with_tx_channel) instead. |
352 | 183 | #[inline]
|
353 | 184 | #[hal_macro_helper]
|
354 | 185 | pub fn receive_with_dma<Ch, B>(
|
@@ -419,116 +250,6 @@ where
|
419 | 250 | }
|
420 | 251 | }
|
421 | 252 |
|
422 |
| -//============================================================================= |
423 |
| -// SPI DMA transfers |
424 |
| -//============================================================================= |
425 |
| - |
426 |
| -unsafe impl<C, A> Buffer for Spi<C, A> |
427 |
| -where |
428 |
| - C: spi::ValidConfig, |
429 |
| - C::OpMode: spi::MasterMode, |
430 |
| - C::Size: spi::AtomicSize<Word = C::Word>, |
431 |
| - C::Word: Beat, |
432 |
| - A: spi::Capability, |
433 |
| -{ |
434 |
| - type Beat = C::Word; |
435 |
| - |
436 |
| - #[inline] |
437 |
| - fn dma_ptr(&mut self) -> *mut Self::Beat { |
438 |
| - self.data_ptr() |
439 |
| - } |
440 |
| - |
441 |
| - #[inline] |
442 |
| - fn incrementing(&self) -> bool { |
443 |
| - false |
444 |
| - } |
445 |
| - |
446 |
| - #[inline] |
447 |
| - fn buffer_len(&self) -> usize { |
448 |
| - 1 |
449 |
| - } |
450 |
| -} |
451 |
| - |
452 |
| -impl<C, A> Spi<C, A> |
453 |
| -where |
454 |
| - C: spi::ValidConfig, |
455 |
| - A: spi::Transmit, |
456 |
| - Self: Buffer<Beat = C::Word>, |
457 |
| -{ |
458 |
| - /// Transform an [`Spi`] into a DMA [`Transfer`]) and |
459 |
| - /// start a send transaction. |
460 |
| - #[inline] |
461 |
| - #[hal_macro_helper] |
462 |
| - #[deprecated( |
463 |
| - since = "0.19.0", |
464 |
| - note = "Use `Spi::with_dma_channels` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
465 |
| - )] |
466 |
| - pub fn send_with_dma<Ch, B>( |
467 |
| - self, |
468 |
| - buf: B, |
469 |
| - mut channel: Ch, |
470 |
| - ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>> |
471 |
| - where |
472 |
| - Ch: AnyChannel<Status = Ready>, |
473 |
| - B: Buffer<Beat = C::Word> + 'static, |
474 |
| - { |
475 |
| - channel |
476 |
| - .as_mut() |
477 |
| - .enable_interrupts(InterruptFlags::new().with_tcmpl(true)); |
478 |
| - |
479 |
| - #[hal_cfg("sercom0-d5x")] |
480 |
| - let trigger_action = TriggerAction::Burst; |
481 |
| - |
482 |
| - #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] |
483 |
| - let trigger_action = TriggerAction::Beat; |
484 |
| - |
485 |
| - // SAFETY: This is safe because the of the `'static` bound check |
486 |
| - // for `B`, and the fact that the buffer length of an `Spi` is always 1. |
487 |
| - let xfer = unsafe { Transfer::new_unchecked(channel, buf, self, false) }; |
488 |
| - xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action) |
489 |
| - } |
490 |
| -} |
491 |
| - |
492 |
| -impl<C, A> Spi<C, A> |
493 |
| -where |
494 |
| - C: spi::ValidConfig, |
495 |
| - A: spi::Receive, |
496 |
| - Self: Buffer<Beat = C::Word>, |
497 |
| -{ |
498 |
| - /// Transform an [`Spi`] into a DMA [`Transfer`]) and |
499 |
| - /// start a receive transaction. |
500 |
| - #[inline] |
501 |
| - #[hal_macro_helper] |
502 |
| - #[deprecated( |
503 |
| - since = "0.19.0", |
504 |
| - note = "Use `Spi::with_dma_channels` instead. You will have access to DMA-enabled `embedded-hal` implementations." |
505 |
| - )] |
506 |
| - pub fn receive_with_dma<Ch, B>( |
507 |
| - self, |
508 |
| - buf: B, |
509 |
| - mut channel: Ch, |
510 |
| - ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>> |
511 |
| - where |
512 |
| - Ch: AnyChannel<Status = Ready>, |
513 |
| - B: Buffer<Beat = C::Word> + 'static, |
514 |
| - { |
515 |
| - channel |
516 |
| - .as_mut() |
517 |
| - .enable_interrupts(InterruptFlags::new().with_tcmpl(true)); |
518 |
| - |
519 |
| - #[hal_cfg("sercom0-d5x")] |
520 |
| - let trigger_action = TriggerAction::Burst; |
521 |
| - |
522 |
| - #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] |
523 |
| - let trigger_action = TriggerAction::Beat; |
524 |
| - |
525 |
| - // SAFETY: This is safe because the of the `'static` bound check |
526 |
| - // for `B`, and the fact that the buffer length of an `Spi` is always 1. |
527 |
| - let xfer = unsafe { Transfer::new_unchecked(channel, self, buf, false) }; |
528 |
| - xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action) |
529 |
| - } |
530 |
| -} |
531 |
| - |
532 | 253 | /// Perform a SERCOM DMA read with a provided [`Buffer`]
|
533 | 254 | ///
|
534 | 255 | /// # Safety
|
|
0 commit comments