1
#![cfg_attr(docsrs, procmacros::doc_replace(
2
    "dma_channel" => {
3
        cfg(spi_master_dma_engine = "SPI_DMA") => "DMA_SPI2",
4
        cfg(spi_master_dma_engine = "AHB_GDMA") => "DMA_CH0",
5
        cfg(spi_master_dma_engine = "AXI_GDMA") => "DMA_AXI_CH0",
6
    }
7
))]
8
//! # Direct Memory Access (DMA)
9
//!
10
//! ## Overview
11
//!
12
//! The DMA driver provides an interface to efficiently transfer data between
13
//! different memory regions and peripherals within the ESP microcontroller
14
//! without involving the CPU. The DMA controller is responsible for managing
15
//! these data transfers.
16
//!
17
//! Notice, that this module is a common version of the DMA driver, `ESP32` and
18
//! `ESP32-S2` are using older `PDMA` controller, whenever other chips are using
19
//! newer `GDMA` controller.
20
//!
21
//! ## Examples
22
//!
23
//! ### Initialize and utilize DMA controller in `SPI`
24
//!
25
//! ```rust, no_run
26
//! # {before_snippet}
27
//! # use esp_hal::dma_buffers;
28
//! # use esp_hal::spi::{master::{Config, Spi}, Mode};
29
//! let sclk = peripherals.GPIO0;
30
//! let miso = peripherals.GPIO2;
31
//! let mosi = peripherals.GPIO4;
32
//! let cs = peripherals.GPIO5;
33
//!
34
//! let mut spi = Spi::new(
35
//!     peripherals.SPI2,
36
//!     Config::default()
37
//!         .with_frequency(Rate::from_khz(100))
38
//!         .with_mode(Mode::_0),
39
//! )?
40
//! .with_sck(sclk)
41
//! .with_mosi(mosi)
42
//! .with_miso(miso)
43
//! .with_cs(cs)
44
//! .with_dma(peripherals.__dma_channel__);
45
//! # {after_snippet}
46
//! ```
47
//!
48
//! ⚠️ Note: Descriptors should be sized as `(max_transfer_size + CHUNK_SIZE - 1) / CHUNK_SIZE`.
49
//! I.e., to transfer buffers of size `1..=CHUNK_SIZE`, you need 1 descriptor.
50
//!
51
//! ⚠️ Note: For chips that support DMA to/from PSRAM DMA transfers to/from PSRAM
52
//! have extra alignment requirements. The address and size of the buffer pointed to by
53
//! each descriptor must be a multiple of the cache line (block) size.
54
//!
55
//! For convenience you can use the [crate::dma_buffers] macro.
56

            
57
use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence};
58

            
59
use enumset::{EnumSet, EnumSetType};
60

            
61
pub use self::buffers::*;
62
#[cfg(dma_supports_mem2mem)]
63
pub use self::m2m::*;
64
use crate::{
65
    Async,
66
    Blocking,
67
    DriverMode,
68
    dma::aligned::DmaAlignedMut,
69
    interrupt::InterruptHandler,
70
    system::{Cpu, PeripheralGuard},
71
};
72

            
73
pub mod aligned;
74
mod buffers;
75
#[cfg(dma_supports_mem2mem)]
76
mod m2m;
77

            
78
mod engine;
79
pub use engine::*;
80

            
81
16
bitfield::bitfield! {
82
    /// DMA descriptor flags.
83
    #[derive(Clone, Copy, PartialEq, Eq)]
84
    pub struct DmaDescriptorFlags(u32);
85

            
86
    u16;
87

            
88
    /// Specifies the size of the buffer that this descriptor points to.
89
    pub size, set_size: 11, 0;
90

            
91
    /// Specifies the number of valid bytes in the buffer that this descriptor points to.
92
    ///
93
    /// This field in a transmit descriptor is written by software and indicates how many bytes can
94
    /// be read from the buffer.
95
    ///
96
    /// This field in a receive descriptor is written by hardware automatically and indicates how
97
    /// many valid bytes have been stored into the buffer.
98
    pub length, set_length: 23, 12;
99

            
100
    /// For receive descriptors, software needs to clear this bit to 0, and hardware will set it to 1 after receiving
101
    /// data containing the EOF flag.
102
    /// For transmit descriptors, software needs to set this bit to 1 as needed.
103
    /// If software configures this bit to 1 in a descriptor, the DMA will include the EOF flag in the data sent to
104
    /// the corresponding peripheral, indicating to the peripheral that this data segment marks the end of one
105
    /// transfer phase.
106
    pub suc_eof, set_suc_eof: 30;
107

            
108
    /// Specifies who is allowed to access the buffer that this descriptor points to.
109
    /// - 0: CPU can access the buffer;
110
    /// - 1: The GDMA controller can access the buffer.
111
    pub owner, set_owner: 31;
112
}
113

            
114
impl Debug for DmaDescriptorFlags {
115
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116
        f.debug_struct("DmaDescriptorFlags")
117
            .field("size", &self.size())
118
            .field("length", &self.length())
119
            .field("suc_eof", &self.suc_eof())
120
            .field("owner", &(if self.owner() { "DMA" } else { "CPU" }))
121
            .finish()
122
    }
123
}
124

            
125
#[cfg(feature = "defmt")]
126
impl defmt::Format for DmaDescriptorFlags {
127
    fn format(&self, fmt: defmt::Formatter<'_>) {
128
        defmt::write!(
129
            fmt,
130
            "DmaDescriptorFlags {{ size: {}, length: {}, suc_eof: {}, owner: {} }}",
131
            self.size(),
132
            self.length(),
133
            self.suc_eof(),
134
            if self.owner() { "DMA" } else { "CPU" }
135
        );
136
    }
137
}
138

            
139
/// A DMA transfer descriptor.
140
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
141
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142
#[cfg_attr(soc_has_axi_gdma, repr(C, align(8)))]
143
#[cfg_attr(not(soc_has_axi_gdma), repr(C, align(4)))]
144
pub struct DmaDescriptor {
145
    /// Descriptor flags.
146
    pub flags: DmaDescriptorFlags,
147

            
148
    /// Address of the buffer.
149
    pub buffer: *mut u8,
150

            
151
    /// Address of the next descriptor.
152
    /// If the current descriptor is the last one, this value is 0.
153
    /// This field can only point to internal RAM.
154
    pub next: *mut DmaDescriptor,
155
}
156

            
157
impl DmaDescriptor {
158
    /// An empty DMA descriptor used to initialize the descriptor list.
159
    pub const EMPTY: Self = Self {
160
        flags: DmaDescriptorFlags(0),
161
        buffer: core::ptr::null_mut(),
162
        next: core::ptr::null_mut(),
163
    };
164

            
165
    /// Resets the descriptor for a new receive transfer.
166
    pub fn reset_for_rx(&mut self) {
167
        // Give ownership to the DMA
168
        self.set_owner(Owner::Dma);
169

            
170
        // Clear this to allow hardware to set it when the peripheral returns an EOF
171
        // bit.
172
        self.set_suc_eof(false);
173

            
174
        // Clear this to allow hardware to set it when it's
175
        // done receiving data for this descriptor.
176
        self.set_length(0);
177
    }
178

            
179
    /// Resets the descriptor for a new transmit transfer. See
180
    /// [DmaDescriptorFlags::suc_eof] for more details on the `set_eof`
181
    /// parameter.
182
    pub fn reset_for_tx(&mut self, set_eof: bool) {
183
        // Give ownership to the DMA
184
        self.set_owner(Owner::Dma);
185

            
186
        // The `suc_eof` bit doesn't affect the transfer itself, but signals when the
187
        // hardware should trigger an interrupt request.
188
        self.set_suc_eof(set_eof);
189
    }
190

            
191
    /// Sets the size of the buffer. See [DmaDescriptorFlags::size].
192
    pub fn set_size(&mut self, len: usize) {
193
        self.flags.set_size(len as u16)
194
    }
195

            
196
    /// Sets the length of the descriptor. See [DmaDescriptorFlags::length].
197
30
    pub fn set_length(&mut self, len: usize) {
198
        self.flags.set_length(len as u16)
199
30
    }
200

            
201
    /// Returns the size of the buffer. See [DmaDescriptorFlags::size].
202
10
    pub fn size(&self) -> usize {
203
        self.flags.size() as usize
204
10
    }
205

            
206
    /// Returns the length of the descriptor. See [DmaDescriptorFlags::length].
207
    #[allow(clippy::len_without_is_empty)]
208
4
    pub fn len(&self) -> usize {
209
        self.flags.length() as usize
210
4
    }
211

            
212
    /// Sets the suc_eof bit. See [DmaDescriptorFlags::suc_eof].
213
10
    pub fn set_suc_eof(&mut self, suc_eof: bool) {
214
        self.flags.set_suc_eof(suc_eof)
215
10
    }
216

            
217
    /// Sets the owner. See [DmaDescriptorFlags::owner].
218
31
    pub fn set_owner(&mut self, owner: Owner) {
219
        let owner = match owner {
220
            Owner::Cpu => false,
221
            Owner::Dma => true,
222
        };
223
        self.flags.set_owner(owner)
224
31
    }
225

            
226
    /// Returns the owner. See [DmaDescriptorFlags::owner].
227
16
    pub fn owner(&self) -> Owner {
228
        match self.flags.owner() {
229
            false => Owner::Cpu,
230
            true => Owner::Dma,
231
        }
232
16
    }
233
}
234

            
235
// The pointers in the descriptor can be Sent.
236
// Marking this Send also allows DmaBuffer implementations to automatically be
237
// Send (where the compiler sees fit).
238
unsafe impl Send for DmaDescriptor {}
239

            
240
/// Kinds of interrupt to listen to.
241
#[derive(Debug, EnumSetType)]
242
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
243
pub enum DmaInterrupt {
244
    /// RX is done.
245
    RxDone,
246
    /// TX is done.
247
    TxDone,
248
}
249

            
250
/// Types of interrupts emitted by the TX channel.
251
196
#[derive(Debug, EnumSetType)]
252
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
253
pub enum DmaTxInterrupt {
254
    /// Triggered when all data corresponding to a linked list (including
255
    /// multiple descriptors) have been sent via transmit channel.
256
    TotalEof,
257

            
258
    /// Triggered when an error is detected in a transmit descriptor on transmit
259
    /// channel.
260
    DescriptorError,
261

            
262
    /// Triggered when EOF in a transmit descriptor is true and data
263
    /// corresponding to this descriptor have been sent via transmit
264
    /// channel.
265
    Eof,
266

            
267
    /// Triggered when all data corresponding to a transmit descriptor have been
268
    /// sent via transmit channel.
269
    Done,
270
}
271

            
272
/// Types of interrupts emitted by the RX channel.
273
475
#[derive(Debug, EnumSetType)]
274
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
275
pub enum DmaRxInterrupt {
276
    /// Triggered when the size of the buffer pointed by receive descriptors
277
    /// is smaller than the length of data to be received via receive channel.
278
    DescriptorEmpty,
279

            
280
    /// Triggered when an error is detected in a receive descriptor on receive
281
    /// channel.
282
    DescriptorError,
283

            
284
    /// Triggered when an error is detected in the data segment corresponding to
285
    /// a descriptor received via receive channel n.
286
    /// This interrupt is used only for UHCI0 peripheral (UART0 or UART1).
287
    ErrorEof,
288

            
289
    /// Triggered when the suc_eof bit in a receive descriptor is 1 and the data
290
    /// corresponding to this receive descriptor has been received via receive
291
    /// channel.
292
    SuccessfulEof,
293

            
294
    /// Triggered when all data corresponding to a receive descriptor have been
295
    /// received via receive channel.
296
    Done,
297
}
298

            
299
/// The default chunk size used for DMA transfers.
300
pub const CHUNK_SIZE: usize = 4092;
301

            
302
#[procmacros::doc_replace]
303
/// Convenience macro to create DMA buffers and descriptors.
304
///
305
/// # Examples
306
///
307
/// ```rust,no_run
308
/// # {before_snippet}
309
/// use esp_hal::dma_buffers;
310
///
311
/// // RX and TX buffers are 32000 bytes - passing only one parameter makes RX
312
/// // and TX the same size.
313
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(32000, 32000);
314
/// # {after_snippet}
315
/// ```
316
#[macro_export]
317
#[cfg(feature = "unstable")]
318
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
319
macro_rules! dma_buffers {
320
    ($rx_size:expr, $tx_size:expr) => {
321
        $crate::dma_buffers_chunk_size!($rx_size, $tx_size, $crate::dma::CHUNK_SIZE)
322
    };
323
    ($size:expr) => {
324
        $crate::dma_buffers!($size, $size)
325
    };
326
}
327

            
328
#[procmacros::doc_replace]
329
/// Convenience macro to create DMA descriptors.
330
///
331
/// # Examples
332
///
333
/// ```rust,no_run
334
/// # {before_snippet}
335
/// use esp_hal::dma_descriptors;
336
///
337
/// // Create RX and TX descriptors for transactions up to 32000 bytes - passing
338
/// // only one parameter assumes RX and TX are the same size.
339
/// let (rx_descriptors, tx_descriptors) = dma_descriptors!(32000, 32000);
340
/// # {after_snippet}
341
/// ```
342
#[macro_export]
343
#[cfg(feature = "unstable")]
344
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
345
macro_rules! dma_descriptors {
346
    ($rx_size:expr, $tx_size:expr) => {
347
        $crate::dma_descriptors_chunk_size!($rx_size, $tx_size, $crate::dma::CHUNK_SIZE)
348
    };
349

            
350
    ($size:expr) => {
351
        $crate::dma_descriptors!($size, $size)
352
    };
353
}
354

            
355
#[procmacros::doc_replace]
356
/// Convenience macro to create DMA buffers and descriptors with specific chunk
357
/// size.
358
///
359
/// # Examples
360
///
361
/// ```rust,no_run
362
/// # {before_snippet}
363
/// use esp_hal::dma_buffers_chunk_size;
364
///
365
/// // TX and RX buffers are 32000 bytes - passing only one parameter makes TX
366
/// // and RX the same size.
367
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
368
///     dma_buffers_chunk_size!(32000, 32000, 4032);
369
/// # {after_snippet}
370
/// ```
371
#[macro_export]
372
#[cfg(feature = "unstable")]
373
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
374
macro_rules! dma_buffers_chunk_size {
375
    ($rx_size:expr, $tx_size:expr, $chunk_size:expr) => {{
376
        let (rx_buf, rx_desc, tx_buf, tx_desc) =
377
            $crate::dma_buffers_impl!($rx_size, $tx_size, $chunk_size);
378
        (
379
            rx_buf.into_inner(),
380
            rx_desc.into_inner(),
381
            tx_buf.into_inner(),
382
            tx_desc.into_inner(),
383
        )
384
    }};
385

            
386
    ($size:expr, $chunk_size:expr) => {
387
        $crate::dma_buffers_chunk_size!($size, $size, $chunk_size)
388
    };
389
}
390

            
391
#[procmacros::doc_replace]
392
/// Convenience macro to create DMA descriptors with specific chunk size.
393
///
394
/// # Examples
395
///
396
/// ```rust,no_run
397
/// # {before_snippet}
398
/// use esp_hal::dma_descriptors_chunk_size;
399
///
400
/// // Create RX and TX descriptors for transactions up to 32000 bytes - passing
401
/// // only one parameter assumes RX and TX are the same size.
402
/// let (rx_descriptors, tx_descriptors) = dma_descriptors_chunk_size!(32000, 32000, 4032);
403
/// # {after_snippet}
404
/// ```
405
#[macro_export]
406
#[cfg(feature = "unstable")]
407
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
408
macro_rules! dma_descriptors_chunk_size {
409
    ($rx_size:expr, $tx_size:expr, $chunk_size:expr) => {{
410
        let (rx, tx) = $crate::dma_descriptors_impl!($rx_size, $tx_size, $chunk_size);
411
        (rx.into_inner(), tx.into_inner())
412
    }};
413

            
414
    ($size:expr, $chunk_size:expr) => {
415
        $crate::dma_descriptors_chunk_size!($size, $size, $chunk_size)
416
    };
417
}
418

            
419
#[doc(hidden)]
420
#[macro_export]
421
#[cfg(feature = "unstable")]
422
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
423
macro_rules! dma_buffers_impl {
424
    ($rx_size:expr, $tx_size:expr, $chunk_size:expr) => {{
425
        let rx = $crate::dma_buffers_impl!($rx_size, $chunk_size);
426
        let tx = $crate::dma_buffers_impl!($tx_size, $chunk_size);
427
        (rx.0, rx.1, tx.0, tx.1)
428
    }};
429

            
430
    ($size:expr, $chunk_size:expr) => {{
431
        unsafe {
432
            (
433
                {
434
                    #[allow(unused_braces)]
435
                    static mut BUFFER: $crate::dma::aligned::InternalMemory<[u8; { $size }]> =
436
                        $crate::dma::aligned::InternalMemory::new([0; $size]);
437
                    // SAFETY: The ConstStaticCell in the descriptor part ensures there will only
438
                    // be a single mutable reference to this buffer.
439
                    unsafe { BUFFER.get_mut().unsize() }
440
                },
441
                $crate::dma_descriptors_impl!($size, $chunk_size),
442
            )
443
        }
444
    }};
445

            
446
    ($size:expr) => {
447
        $crate::dma_buffers_impl!(
448
            $size,
449
            $crate::dma::BurstConfig::DEFAULT.max_compatible_chunk_size()
450
        )
451
    };
452
}
453

            
454
#[doc(hidden)]
455
#[macro_export]
456
#[cfg(feature = "unstable")]
457
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
458
macro_rules! dma_descriptors_impl {
459
    ($rx_size:expr, $tx_size:expr, $chunk_size:expr) => {{
460
        let rx = $crate::dma_descriptors_impl!($rx_size, $chunk_size);
461
        let tx = $crate::dma_descriptors_impl!($tx_size, $chunk_size);
462
        (rx, tx)
463
    }};
464

            
465
    ($size:expr, $chunk_size:expr) => {{
466
        use $crate::{
467
            __macro_implementation::static_cell::ConstStaticCell,
468
            dma::{DmaDescriptor, aligned::InternalMemory},
469
        };
470

            
471
        const __DMA_DESCRIPTOR_COUNT: usize = $crate::dma_descriptor_count!($size, $chunk_size);
472
        static DESCRIPTORS: ConstStaticCell<
473
            InternalMemory<[DmaDescriptor; __DMA_DESCRIPTOR_COUNT]>,
474
        > = ConstStaticCell::new(InternalMemory::new(
475
            [DmaDescriptor::EMPTY; __DMA_DESCRIPTOR_COUNT],
476
        ));
477

            
478
        DESCRIPTORS.take().get_mut().unsize()
479
    }};
480
}
481

            
482
#[doc(hidden)]
483
#[macro_export]
484
#[cfg(feature = "unstable")]
485
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
486
macro_rules! dma_descriptor_count {
487
    ($size:expr, $chunk_size:expr) => {{
488
        const {
489
            ::core::assert!($chunk_size <= 4095, "chunk size must be <= 4095");
490
            ::core::assert!($chunk_size > 0, "chunk size must be > 0");
491
        }
492

            
493
        // We allow 0 in the macros as a "not needed" case.
494
        if $size == 0 {
495
            0
496
        } else {
497
            $crate::dma::descriptor_count($size, $chunk_size)
498
        }
499
    }};
500
}
501

            
502
#[procmacros::doc_replace]
503
/// Convenience macro to create a DmaRxBuf from buffer size. The buffer and
504
/// descriptors are statically allocated and used to create the `DmaRxBuf`.
505
///
506
/// # Examples
507
///
508
/// ```rust,no_run
509
/// # {before_snippet}
510
/// use esp_hal::dma_rx_buffer;
511
///
512
/// let rx_buf = dma_rx_buffer!(32000)?;
513
/// # {after_snippet}
514
/// ```
515
#[macro_export]
516
#[cfg(feature = "unstable")]
517
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
518
macro_rules! dma_rx_buffer {
519
    ($rx_size:expr) => {{
520
        let (rx_buffer, rx_descriptors) = $crate::dma_buffers_impl!($rx_size);
521

            
522
        // TODO: this macro should be infallible
523
        $crate::dma::DmaRxBuf::new(rx_descriptors, rx_buffer)
524
    }};
525
}
526

            
527
#[procmacros::doc_replace]
528
/// Convenience macro to create a DmaTxBuf from buffer size. The buffer and
529
/// descriptors are statically allocated and used to create the `DmaTxBuf`.
530
///
531
/// # Examples
532
///
533
/// ```rust,no_run
534
/// # {before_snippet}
535
/// use esp_hal::dma_tx_buffer;
536
///
537
/// let tx_buf = dma_tx_buffer!(32000)?;
538
/// # {after_snippet}
539
/// ```
540
#[macro_export]
541
#[cfg(feature = "unstable")]
542
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
543
macro_rules! dma_tx_buffer {
544
    ($tx_size:expr) => {{
545
        let (tx_buffer, tx_descriptors) = $crate::dma_buffers_impl!($tx_size);
546

            
547
        // TODO: this macro should be infallible
548
        $crate::dma::DmaTxBuf::new(tx_descriptors, tx_buffer)
549
    }};
550
}
551

            
552
#[procmacros::doc_replace]
553
/// Convenience macro to create a [DmaRxStreamBuf] from buffer size and
554
/// optional chunk size (uses max if unspecified).
555
/// The buffer and descriptors are statically allocated and
556
/// used to create the [DmaRxStreamBuf].
557
///
558
/// Smaller chunk sizes are recommended for lower latency.
559
///
560
/// # Examples
561
///
562
/// ```rust,no_run
563
/// # {before_snippet}
564
/// use esp_hal::dma_rx_stream_buffer;
565
///
566
/// let buf = dma_rx_stream_buffer!(32000);
567
/// let buf = dma_rx_stream_buffer!(32000, 1000);
568
/// # {after_snippet}
569
/// ```
570
#[macro_export]
571
#[cfg(feature = "unstable")]
572
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
573
macro_rules! dma_rx_stream_buffer {
574
    ($rx_size:expr) => {
575
        $crate::dma_rx_stream_buffer!($rx_size, 4095)
576
    };
577
    ($rx_size:expr, $chunk_size:expr) => {{
578
        let (buffer, descriptors) = $crate::dma_buffers_impl!($rx_size, $chunk_size);
579

            
580
        $crate::dma::DmaRxStreamBuf::new(descriptors, buffer).unwrap()
581
    }};
582
}
583

            
584
#[procmacros::doc_replace]
585
/// Convenience macro to create a [DmaTxStreamBuf] from buffer size and
586
/// optional chunk size (uses max if unspecified).
587
/// The buffer and descriptors are statically allocated and
588
/// used to create the [DmaTxStreamBuf].
589
///
590
/// Smaller chunk sizes are recommended for lower latency.
591
///
592
/// # Examples
593
///
594
/// ```rust,no_run
595
/// # {before_snippet}
596
/// use esp_hal::dma_tx_stream_buffer;
597
///
598
/// let buf = dma_tx_stream_buffer!(32000);
599
/// let buf = dma_tx_stream_buffer!(32000, 1000);
600
/// # {after_snippet}
601
/// ```
602
#[macro_export]
603
#[cfg(feature = "unstable")]
604
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
605
macro_rules! dma_tx_stream_buffer {
606
    ($tx_size:expr) => {
607
        $crate::dma_tx_stream_buffer!($tx_size, 4095)
608
    };
609
    ($tx_size:expr, $chunk_size:expr) => {{
610
        let (buffer, descriptors) = $crate::dma_buffers_impl!($tx_size, $chunk_size);
611

            
612
        $crate::dma::DmaTxStreamBuf::new(descriptors, buffer).unwrap()
613
    }};
614
}
615

            
616
#[procmacros::doc_replace]
617
/// Convenience macro to create a [DmaLoopBuf] from a buffer size.
618
///
619
/// # Examples
620
///
621
/// ```rust,no_run
622
/// # {before_snippet}
623
/// use esp_hal::dma_loop_buffer;
624
///
625
/// let buf = dma_loop_buffer!(2000);
626
/// # {after_snippet}
627
/// ```
628
#[macro_export]
629
#[cfg(feature = "unstable")]
630
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
631
macro_rules! dma_loop_buffer {
632
    ($size:expr) => {{
633
        const {
634
            ::core::assert!($size <= 4095, "size must be <= 4095");
635
            ::core::assert!($size > 0, "size must be > 0");
636
        }
637

            
638
        let (buffer, descriptors) = $crate::dma_buffers_impl!($size, $size);
639

            
640
        $crate::dma::DmaLoopBuf::new(descriptors, buffer).unwrap()
641
    }};
642
}
643

            
644
/// DMA Errors.
645
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
646
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
647
pub enum DmaError {
648
    /// The alignment of data is invalid.
649
    InvalidAlignment(DmaAlignmentError),
650
    /// More descriptors are needed for the buffer size.
651
    OutOfDescriptors,
652
    /// DescriptorError the DMA rejected the descriptor configuration. This
653
    /// could be because the source address of the data is not in RAM. Ensure
654
    /// the source data is in a valid address space.
655
    DescriptorError,
656
    /// The available free buffer is less than the amount of data to push.
657
    Overflow,
658
    /// The given buffer is too small.
659
    BufferTooSmall,
660
    /// Descriptors or buffers are not located in a supported memory region.
661
    UnsupportedMemoryRegion,
662
    /// Invalid DMA chunk size.
663
    InvalidChunkSize,
664
}
665

            
666
impl From<DmaBufError> for DmaError {
667
    fn from(error: DmaBufError) -> Self {
668
        // FIXME: use nested errors
669
        match error {
670
            DmaBufError::InsufficientDescriptors => DmaError::OutOfDescriptors,
671
            DmaBufError::UnsupportedMemoryRegion => DmaError::UnsupportedMemoryRegion,
672
            DmaBufError::InvalidAlignment(err) => DmaError::InvalidAlignment(err),
673
            DmaBufError::InvalidChunkSize => DmaError::InvalidChunkSize,
674
            DmaBufError::BufferTooSmall => DmaError::BufferTooSmall,
675
        }
676
    }
677
}
678

            
679
/// DMA Priorities.
680
#[cfg(dma_max_priority_is_set)]
681
#[derive(Debug, Clone, Copy, PartialEq)]
682
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
683
pub enum DmaPriority {
684
    /// The lowest priority level (Priority 0).
685
    Priority0  = 0,
686
    /// Priority level 1.
687
    Priority1  = 1,
688
    /// Priority level 2.
689
    Priority2  = 2,
690
    /// Priority level 3.
691
    Priority3  = 3,
692
    /// Priority level 4.
693
    Priority4  = 4,
694
    /// Priority level 5.
695
    Priority5  = 5,
696
    /// Priority level 6.
697
    #[cfg(any(dma_max_priority = "9", dma_max_priority = "15"))]
698
    Priority6  = 6,
699
    /// Priority level 7.
700
    #[cfg(any(dma_max_priority = "9", dma_max_priority = "15"))]
701
    Priority7  = 7,
702
    /// Priority level 8.
703
    #[cfg(any(dma_max_priority = "9", dma_max_priority = "15"))]
704
    Priority8  = 8,
705
    /// Priority level 9.
706
    #[cfg(any(dma_max_priority = "9", dma_max_priority = "15"))]
707
    Priority9  = 9,
708
    /// Priority level 10.
709
    #[cfg(dma_max_priority = "15")]
710
    Priority10 = 10,
711
    /// Priority level 11.
712
    #[cfg(dma_max_priority = "15")]
713
    Priority11 = 11,
714
    /// Priority level 12.
715
    #[cfg(dma_max_priority = "15")]
716
    Priority12 = 12,
717
    /// Priority level 13.
718
    #[cfg(dma_max_priority = "15")]
719
    Priority13 = 13,
720
    /// Priority level 14.
721
    #[cfg(dma_max_priority = "15")]
722
    Priority14 = 14,
723
    /// Priority level 15.
724
    #[cfg(dma_max_priority = "15")]
725
    Priority15 = 15,
726
}
727

            
728
/// The owner bit of a DMA descriptor.
729
#[derive(PartialEq, PartialOrd)]
730
pub enum Owner {
731
    /// Owned by CPU.
732
    Cpu = 0,
733
    /// Owned by DMA.
734
    Dma = 1,
735
}
736

            
737
impl From<u32> for Owner {
738
    fn from(value: u32) -> Self {
739
        match value {
740
            0 => Owner::Cpu,
741
            _ => Owner::Dma,
742
        }
743
    }
744
}
745

            
746
/// Computes the number of descriptors required for a given buffer size with
747
/// a given chunk size.
748
pub const fn descriptor_count(buffer_size: usize, chunk_size: usize) -> usize {
749
665
    if buffer_size < chunk_size {
750
        // At least one descriptor is always required.
751
        return 1;
752
    }
753

            
754
    // TODO: we could round up to cacheline size to reduce memory waste on
755
    // soc_internal_memory_cached devices.
756
    buffer_size.div_ceil(chunk_size)
757
}
758

            
759
#[derive(Debug)]
760
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
761
struct DescriptorSet<'a> {
762
    descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
763
}
764

            
765
impl<'a> DescriptorSet<'a> {
766
    /// Creates a new `DescriptorSet` from a slice of descriptors and associates
767
    /// them with the given buffer.
768
2
    fn new(descriptors: DmaAlignedMut<'a, [DmaDescriptor]>) -> Result<Self, DmaBufError> {
769
        #[cfg(not(esp32p4))] // P4 can read descriptors from PSRAM
770
317
        if !crate::soc::is_slice_in_dram(&descriptors) {
771
            return Err(DmaBufError::UnsupportedMemoryRegion);
772
        }
773

            
774
2
        Ok(unsafe { Self::new_unchecked(descriptors.into_inner()) })
775
2
    }
776

            
777
    /// Creates a new `DescriptorSet` from a slice of descriptors and associates
778
    /// them with the given buffer.
779
    ///
780
    /// # Safety
781
    ///
782
    /// The caller must ensure that the descriptors are located in a supported
783
    /// memory region.
784
    unsafe fn new_unchecked(descriptors: &'a mut [DmaDescriptor]) -> Self {
785
        descriptors.fill(DmaDescriptor::EMPTY);
786
        Self {
787
            descriptors: unsafe { DmaAlignedMut::new_unchecked(descriptors) },
788
        }
789
    }
790

            
791
    /// Consumes the `DescriptorSet` and returns the inner slice of descriptors.
792
    fn into_inner(self) -> DmaAlignedMut<'a, [DmaDescriptor]> {
793
        self.descriptors
794
    }
795

            
796
    /// Returns a pointer to the first descriptor in the chain.
797
    fn head(&mut self) -> *mut DmaDescriptor {
798
        self.descriptors.as_mut_ptr()
799
    }
800

            
801
    /// Returns an iterator over the linked descriptors.
802
    fn linked_iter(&self) -> impl Iterator<Item = &DmaDescriptor> {
803
        let mut was_last = false;
804
        self.descriptors.iter().take_while(move |d| {
805
98
            if was_last {
806
                false
807
            } else {
808
98
                was_last = d.next.is_null();
809
                true
810
            }
811
        })
812
    }
813

            
814
    /// Returns an iterator over the linked descriptors.
815
    fn linked_iter_mut(&mut self) -> impl Iterator<Item = &mut DmaDescriptor> + use<'_> {
816
        let mut was_last = false;
817
        self.descriptors.iter_mut().take_while(move |d| {
818
            if was_last {
819
                false
820
            } else {
821
394
                was_last = d.next.is_null();
822
                true
823
            }
824
        })
825
    }
826

            
827
    /// Associates each descriptor with a chunk of the buffer.
828
    ///
829
    /// Checks the alignment and location of the buffer.
830
    ///
831
    /// See [`Self::set_up_buffer_ptrs`] for more details.
832
665
    fn link_with_buffer(
833
        &mut self,
834
        buffer: &mut [u8],
835
        chunk_size: usize,
836
    ) -> Result<(), DmaBufError> {
837
        Self::set_up_buffer_ptrs(buffer, &mut self.descriptors, chunk_size)
838
665
    }
839

            
840
    /// Prepares descriptors for transferring `len` bytes of data.
841
    ///
842
    /// See [`Self::set_up_descriptors`] for more details.
843
    fn set_length(
844
        &mut self,
845
        len: usize,
846
        chunk_size: usize,
847
        prepare: fn(&mut DmaDescriptor, usize),
848
    ) -> Result<(), DmaBufError> {
849
        Self::set_up_descriptors(&mut self.descriptors, len, chunk_size, prepare)
850
    }
851

            
852
    /// Prepares descriptors for reading `len` bytes of data.
853
    ///
854
    /// See [`Self::set_up_descriptors`] for more details.
855
    fn set_rx_length(&mut self, len: usize, chunk_size: usize) -> Result<(), DmaBufError> {
856
        self.set_length(len, chunk_size, |desc, chunk_size| {
857
            desc.set_size(chunk_size);
858
        })
859
    }
860

            
861
    /// Prepares descriptors for writing `len` bytes of data.
862
    ///
863
    /// See [`Self::set_up_descriptors`] for more details.
864
    fn set_tx_length(&mut self, len: usize, chunk_size: usize) -> Result<(), DmaBufError> {
865
        self.set_length(len, chunk_size, |desc, chunk_size| {
866
            desc.set_length(chunk_size);
867
        })
868
    }
869

            
870
    /// Returns a slice of descriptors that can cover a buffer of length `len`.
871
    fn descriptors_for_buffer_len(
872
        descriptors: &mut [DmaDescriptor],
873
        len: usize,
874
        chunk_size: usize,
875
    ) -> Result<&mut [DmaDescriptor], DmaBufError> {
876
        // First, pick enough descriptors to cover the buffer.
877
        let required_descriptors = descriptor_count(len, chunk_size);
878
652
        if descriptors.len() < required_descriptors {
879
            return Err(DmaBufError::InsufficientDescriptors);
880
        }
881
        Ok(&mut descriptors[..required_descriptors])
882
    }
883

            
884
    /// Prepares descriptors for transferring `len` bytes of data.
885
    ///
886
    /// `Prepare` means setting up the descriptor lengths and flags, as well as
887
    /// linking the descriptors into a linked list.
888
    ///
889
    /// The actual descriptor setup is done in a callback, because different
890
    /// transfer directions require different descriptor setup.
891
    fn set_up_descriptors(
892
        descriptors: &mut [DmaDescriptor],
893
        len: usize,
894
        chunk_size: usize,
895
        prepare: impl Fn(&mut DmaDescriptor, usize),
896
    ) -> Result<(), DmaBufError> {
897
        let descriptors = Self::descriptors_for_buffer_len(descriptors, len, chunk_size)?;
898

            
899
        // Link up the descriptors.
900
        let mut next = core::ptr::null_mut();
901
309
        for desc in descriptors.iter_mut().rev() {
902
393
            desc.next = next;
903
            next = desc;
904
        }
905

            
906
        // Prepare each descriptor.
907
        let mut remaining_length = len;
908
        for desc in descriptors.iter_mut() {
909
            let chunk_size = min(chunk_size, remaining_length);
910
            prepare(desc, chunk_size);
911
393
            remaining_length -= chunk_size;
912
        }
913
353
        debug_assert_eq!(remaining_length, 0);
914

            
915
        Ok(())
916
    }
917

            
918
    /// Associates each descriptor with a chunk of the buffer.
919
    ///
920
    /// Does not check the alignment and location of the buffer, because some
921
    /// callers may not have enough information currently.
922
    ///
923
    /// Does not set up descriptor lengths or states.
924
    ///
925
    /// Does not link descriptors into a linked list. This is intentional, because it is done in
926
    /// `set_up_descriptors` to support changing length without requiring buffer pointers to be set
927
    /// repeatedly.
928
    fn set_up_buffer_ptrs(
929
        buffer: &mut [u8],
930
        descriptors: &mut [DmaDescriptor],
931
        chunk_size: usize,
932
    ) -> Result<(), DmaBufError> {
933
        let descriptors = Self::descriptors_for_buffer_len(descriptors, buffer.len(), chunk_size)?;
934

            
935
        let chunks = buffer.chunks_mut(chunk_size);
936
        for (desc, chunk) in descriptors.iter_mut().zip(chunks) {
937
            desc.set_size(chunk.len());
938
739
            desc.buffer = chunk.as_mut_ptr();
939
        }
940

            
941
        Ok(())
942
    }
943
}
944

            
945
/// Blocks size for transfers to/from PSRAM.
946
#[cfg(dma_ext_mem_configurable_block_size)]
947
#[derive(Copy, Clone, Debug, PartialEq)]
948
pub enum DmaExtMemBKSize {
949
    /// External memory block size of 16 bytes.
950
    Size16 = 0,
951
    /// External memory block size of 32 bytes.
952
    Size32 = 1,
953
    /// External memory block size of 64 bytes.
954
    Size64 = 2,
955
}
956

            
957
#[cfg(dma_ext_mem_configurable_block_size)]
958
impl From<ExternalBurstConfig> for DmaExtMemBKSize {
959
    fn from(size: ExternalBurstConfig) -> Self {
960
        match size {
961
            ExternalBurstConfig::Size16 => DmaExtMemBKSize::Size16,
962
            ExternalBurstConfig::Size32 => DmaExtMemBKSize::Size32,
963
            // TODO: investigate why ext_mem_bk_size = 2 causes corruption on S2
964
            #[cfg(not(esp32s2))]
965
            ExternalBurstConfig::Size64 => DmaExtMemBKSize::Size64,
966
        }
967
    }
968
}
969

            
970
// DMA receive channel
971
#[non_exhaustive]
972
#[doc(hidden)]
973
pub struct ChannelRx<Dm, CH>
974
where
975
    Dm: DriverMode,
976
    CH: DmaRxChannel,
977
{
978
    pub(crate) rx_impl: CH,
979
    pub(crate) _phantom: PhantomData<Dm>,
980
    pub(crate) _guard: Option<PeripheralGuard>,
981
}
982

            
983
impl<CH> ChannelRx<Blocking, CH>
984
where
985
    CH: DmaRxChannel,
986
{
987
    /// Creates a new RX channel half.
988
    pub fn new(rx_impl: CH) -> Self {
989
27
        let _guard = rx_impl.enable();
990

            
991
        // clear the mem2mem mode to avoid failed DMA if this
992
        // channel was previously used for a mem2mem transfer.
993
        #[cfg(dma_supports_mem2mem)]
994
27
        rx_impl.set_mem2mem_mode(false);
995

            
996
337
        if let Some(interrupt) = rx_impl.peripheral_interrupt() {
997
            for cpu in Cpu::all() {
998
                crate::interrupt::disable(cpu, interrupt);
999
            }
        }
27
        rx_impl.set_async(false);
        Self {
            rx_impl,
            _phantom: PhantomData,
            _guard,
        }
    }
    /// Converts a blocking channel to an async channel.
5
    pub(crate) fn into_async(mut self) -> ChannelRx<Async, CH> {
5
        if let Some(handler) = self.rx_impl.async_handler() {
            self.set_interrupt_handler(handler);
        }
        self.rx_impl.set_async(true);
5
        ChannelRx {
            rx_impl: self.rx_impl,
            _phantom: PhantomData,
5
            _guard: self._guard,
        }
5
    }
    pub(crate) fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
        self.unlisten_in(EnumSet::all());
        self.clear_in(EnumSet::all());
5
        if let Some(interrupt) = self.rx_impl.peripheral_interrupt() {
            for core in Cpu::other() {
                crate::interrupt::disable(core, interrupt);
            }
            crate::interrupt::bind_handler(interrupt, handler);
        }
    }
}
impl<CH> ChannelRx<Async, CH>
where
    CH: DmaRxChannel,
{
    /// Converts an async channel into a blocking channel.
    pub(crate) fn into_blocking(self) -> ChannelRx<Blocking, CH> {
        if let Some(interrupt) = self.rx_impl.peripheral_interrupt() {
            crate::interrupt::disable(Cpu::current(), interrupt);
        }
        self.rx_impl.set_async(false);
        ChannelRx {
            rx_impl: self.rx_impl,
            _phantom: PhantomData,
            _guard: self._guard,
        }
    }
}
impl<Dm, CH> ChannelRx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaRxChannel,
{
    /// Configures the channel.
    #[cfg(dma_max_priority_is_set)]
    pub fn set_priority(&mut self, priority: DmaPriority) {
        self.rx_impl.set_priority(priority);
    }
    fn do_prepare(
        &mut self,
        preparation: Preparation,
        peri: DmaPeripheral,
    ) -> Result<(), DmaError> {
        debug!("Preparing RX transfer {:?}", preparation);
        trace!("First descriptor {:?}", unsafe { &*preparation.start });
        #[cfg(dma_can_access_psram)]
        if preparation.accesses_psram && !self.rx_impl.can_access_psram() {
            return Err(DmaError::UnsupportedMemoryRegion);
        }
        #[cfg(dma_ext_mem_configurable_block_size)]
        self.rx_impl
            .set_ext_mem_block_size(preparation.burst_transfer.external_memory.into());
41
        self.rx_impl.set_burst_mode(preparation.burst_transfer);
41
        self.rx_impl.set_descr_burst_mode(true);
41
        self.rx_impl.set_check_owner(preparation.check_owner);
        compiler_fence(core::sync::atomic::Ordering::SeqCst);
41
        self.rx_impl.clear_all();
41
        self.rx_impl.reset();
41
        self.rx_impl.set_link_addr(preparation.start as u32);
41
        self.rx_impl.set_peripheral(peri.0);
        Ok(())
    }
}
impl<Dm, CH> crate::private::Sealed for ChannelRx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaRxChannel,
{
}
#[allow(unused)]
impl<Dm, CH> ChannelRx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaRxChannel,
{
    /// Asserts that the channel is compatible with the given peripheral.
    #[allow(dead_code)]
    pub(crate) fn runtime_ensure_compatible(&self, peripheral: DmaPeripheral) {
3
        self.rx_impl.runtime_ensure_compatible(peripheral);
    }
    pub(crate) unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
        &mut self,
        peri: DmaPeripheral,
        buffer: &mut BUF,
    ) -> Result<(), DmaError> {
35
        let preparation = buffer.prepare();
        self.do_prepare(preparation, peri)
    }
    pub(crate) fn start_transfer(&mut self) -> Result<(), DmaError> {
41
        self.rx_impl.start();
        if self
            .pending_in_interrupts()
            .contains(DmaRxInterrupt::DescriptorError)
        {
            Err(DmaError::DescriptorError)
        } else {
            Ok(())
        }
    }
    pub(crate) fn stop_transfer(&mut self) {
4
        self.rx_impl.stop()
    }
    #[cfg(dma_supports_mem2mem)]
    pub(crate) fn set_mem2mem_mode(&mut self, value: bool) {
3
        self.rx_impl.set_mem2mem_mode(value);
    }
    pub(crate) fn listen_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
        self.rx_impl.listen(interrupts);
    }
    pub(crate) fn unlisten_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
        self.rx_impl.unlisten(interrupts);
    }
    pub(crate) fn is_listening_in(&self) -> EnumSet<DmaRxInterrupt> {
        self.rx_impl.is_listening()
    }
    pub(crate) fn clear_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
5
        self.rx_impl.clear(interrupts);
    }
    pub(crate) fn pending_in_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
11431104
        self.rx_impl.pending_interrupts()
    }
    pub(crate) fn is_done(&self) -> bool {
        self.pending_in_interrupts()
            .contains(DmaRxInterrupt::SuccessfulEof)
    }
    pub(crate) fn clear_interrupts(&self) {
        self.rx_impl.clear_all();
    }
    pub(crate) fn waker(&self) -> &'static crate::asynch::AtomicWaker {
5
        self.rx_impl.waker()
    }
    pub(crate) fn has_error(&self) -> bool {
        self.pending_in_interrupts()
            .contains(DmaRxInterrupt::DescriptorError)
    }
    pub(crate) fn has_dscr_empty_error(&self) -> bool {
        self.pending_in_interrupts()
            .contains(DmaRxInterrupt::DescriptorEmpty)
    }
    pub(crate) fn has_eof_error(&self) -> bool {
        self.pending_in_interrupts()
            .contains(DmaRxInterrupt::ErrorEof)
    }
}
/// DMA transmit channel.
#[doc(hidden)]
pub struct ChannelTx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaTxChannel,
{
    pub(crate) tx_impl: CH,
    pub(crate) _phantom: PhantomData<Dm>,
    pub(crate) _guard: Option<PeripheralGuard>,
}
impl<CH> ChannelTx<Blocking, CH>
where
    CH: DmaTxChannel,
{
    /// Creates a new TX channel half.
    pub fn new(tx_impl: CH) -> Self {
27
        let _guard = tx_impl.enable();
337
        if let Some(interrupt) = tx_impl.peripheral_interrupt() {
            for cpu in Cpu::all() {
                crate::interrupt::disable(cpu, interrupt);
            }
        }
27
        tx_impl.set_async(false);
        Self {
            tx_impl,
            _phantom: PhantomData,
            _guard,
        }
    }
    /// Converts a blocking channel to an async channel.
5
    pub(crate) fn into_async(mut self) -> ChannelTx<Async, CH> {
5
        if let Some(handler) = self.tx_impl.async_handler() {
            self.set_interrupt_handler(handler);
        }
        self.tx_impl.set_async(true);
5
        ChannelTx {
            tx_impl: self.tx_impl,
            _phantom: PhantomData,
5
            _guard: self._guard,
        }
5
    }
    pub(crate) fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
        self.unlisten_out(EnumSet::all());
        self.clear_out(EnumSet::all());
        if let Some(interrupt) = self.tx_impl.peripheral_interrupt() {
            for core in Cpu::other() {
                crate::interrupt::disable(core, interrupt);
            }
            crate::interrupt::bind_handler(interrupt, handler);
        }
    }
}
impl<CH> ChannelTx<Async, CH>
where
    CH: DmaTxChannel,
{
    /// Converts an async channel into a blocking channel.
    pub(crate) fn into_blocking(self) -> ChannelTx<Blocking, CH> {
        if let Some(interrupt) = self.tx_impl.peripheral_interrupt() {
            crate::interrupt::disable(Cpu::current(), interrupt);
        }
        self.tx_impl.set_async(false);
        ChannelTx {
            tx_impl: self.tx_impl,
            _phantom: PhantomData,
            _guard: self._guard,
        }
    }
}
impl<Dm, CH> ChannelTx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaTxChannel,
{
    /// Asserts that the channel is compatible with the given peripheral.
    #[allow(dead_code)]
    pub(crate) fn runtime_ensure_compatible(&self, peripheral: DmaPeripheral) {
        self.tx_impl.runtime_ensure_compatible(peripheral);
    }
    /// Configures the channel priority.
    #[cfg(dma_max_priority_is_set)]
    pub fn set_priority(&mut self, priority: DmaPriority) {
        self.tx_impl.set_priority(priority);
    }
6
    fn do_prepare(
        &mut self,
        preparation: Preparation,
        peri: DmaPeripheral,
    ) -> Result<(), DmaError> {
        debug!("Preparing TX transfer {:?}", preparation);
        trace!("First descriptor {:?}", unsafe { &*preparation.start });
        #[cfg(dma_can_access_psram)]
        if preparation.accesses_psram && !self.tx_impl.can_access_psram() {
            return Err(DmaError::UnsupportedMemoryRegion);
        }
        #[cfg(dma_ext_mem_configurable_block_size)]
        self.tx_impl
            .set_ext_mem_block_size(preparation.burst_transfer.external_memory.into());
33
        self.tx_impl.set_burst_mode(preparation.burst_transfer);
33
        self.tx_impl.set_descr_burst_mode(true);
33
        self.tx_impl.set_check_owner(preparation.check_owner);
        self.tx_impl
33
            .set_auto_write_back(preparation.auto_write_back);
        compiler_fence(core::sync::atomic::Ordering::SeqCst);
33
        self.tx_impl.clear_all();
33
        self.tx_impl.reset();
33
        self.tx_impl.set_link_addr(preparation.start as u32);
33
        self.tx_impl.set_peripheral(peri.0);
        Ok(())
    }
}
impl<Dm, CH> crate::private::Sealed for ChannelTx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaTxChannel,
{
}
#[allow(unused)]
impl<Dm, CH> ChannelTx<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaTxChannel,
{
    pub(crate) unsafe fn prepare_transfer<BUF: DmaTxBuffer>(
        &mut self,
        peri: DmaPeripheral,
        buffer: &mut BUF,
    ) -> Result<(), DmaError> {
        let preparation = buffer.prepare();
4
        self.do_prepare(preparation, peri)
    }
    pub(crate) fn start_transfer(&mut self) -> Result<(), DmaError> {
31
        self.tx_impl.start();
297
        while self.tx_impl.is_fifo_empty() && self.pending_out_interrupts().is_empty() {}
        if self
            .pending_out_interrupts()
            .contains(DmaTxInterrupt::DescriptorError)
        {
            Err(DmaError::DescriptorError)
        } else {
            Ok(())
        }
    }
    pub(crate) fn stop_transfer(&mut self) {
4
        self.tx_impl.stop()
    }
    pub(crate) fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
        self.tx_impl.listen(interrupts);
    }
    pub(crate) fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
        self.tx_impl.unlisten(interrupts);
    }
    pub(crate) fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt> {
        self.tx_impl.is_listening()
    }
    pub(crate) fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
        self.tx_impl.clear(interrupts);
    }
    pub(crate) fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
31
        self.tx_impl.pending_interrupts()
    }
    pub(crate) fn waker(&self) -> &'static crate::asynch::AtomicWaker {
        self.tx_impl.waker()
    }
    pub(crate) fn clear_interrupts(&self) {
        self.tx_impl.clear_all();
    }
    pub(crate) fn last_out_dscr_address(&self) -> usize {
        self.tx_impl.last_dscr_address()
    }
    pub(crate) fn is_done(&self) -> bool {
        self.pending_out_interrupts()
            .contains(DmaTxInterrupt::TotalEof)
    }
    pub(crate) fn has_error(&self) -> bool {
        self.pending_out_interrupts()
            .contains(DmaTxInterrupt::DescriptorError)
    }
}
/// DMA Channel.
#[non_exhaustive]
pub struct Channel<Dm, CH>
where
    Dm: DriverMode,
    CH: DmaChannel,
{
    /// RX half of the channel.
    pub rx: ChannelRx<Dm, CH::Rx>,
    /// TX half of the channel.
    pub tx: ChannelTx<Dm, CH::Tx>,
}
impl<CH> Channel<Blocking, CH>
where
    CH: DmaChannel,
{
    /// Creates a new DMA channel driver.
    #[instability::unstable]
337
    pub fn new(channel: CH) -> Self {
        let (rx, tx) = unsafe { channel.split_internal(crate::private::Internal) };
337
        Self {
            rx: ChannelRx::new(rx),
            tx: ChannelTx::new(tx),
        }
337
    }
    /// Sets the interrupt handler for RX and TX interrupts.
    ///
    /// Interrupts are not enabled at the peripheral level here.
    #[instability::unstable]
    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
        self.rx.set_interrupt_handler(handler);
        self.tx.set_interrupt_handler(handler);
    }
    /// Listens for the given interrupts.
    pub fn listen(&mut self, interrupts: impl Into<EnumSet<DmaInterrupt>>) {
        for interrupt in interrupts.into() {
            match interrupt {
                DmaInterrupt::RxDone => self.rx.listen_in(DmaRxInterrupt::Done),
                DmaInterrupt::TxDone => self.tx.listen_out(DmaTxInterrupt::Done),
            }
        }
    }
    /// Unlistens from the given interrupts.
    pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<DmaInterrupt>>) {
        for interrupt in interrupts.into() {
            match interrupt {
                DmaInterrupt::RxDone => self.rx.unlisten_in(DmaRxInterrupt::Done),
                DmaInterrupt::TxDone => self.tx.unlisten_out(DmaTxInterrupt::Done),
            }
        }
    }
    /// Returns the asserted interrupts.
    pub fn interrupts(&mut self) -> EnumSet<DmaInterrupt> {
        let mut res = EnumSet::new();
        if self.rx.is_done() {
            res.insert(DmaInterrupt::RxDone);
        }
        if self.tx.is_done() {
            res.insert(DmaInterrupt::TxDone);
        }
        res
    }
    /// Resets asserted interrupts.
    pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<DmaInterrupt>>) {
        for interrupt in interrupts.into() {
            match interrupt {
                DmaInterrupt::RxDone => self.rx.clear_in(DmaRxInterrupt::Done),
                DmaInterrupt::TxDone => self.tx.clear_out(DmaTxInterrupt::Done),
            }
        }
    }
    /// Configures the channel priorities.
    #[cfg(dma_max_priority_is_set)]
    pub fn set_priority(&mut self, priority: DmaPriority) {
        self.tx.set_priority(priority);
        self.rx.set_priority(priority);
    }
    /// Converts a blocking channel to an async channel.
    pub fn into_async(self) -> Channel<Async, CH> {
5
        Channel {
5
            rx: self.rx.into_async(),
5
            tx: self.tx.into_async(),
        }
    }
}
impl<CH, Dm> Channel<Dm, CH>
where
    CH: DmaChannel,
    Dm: DriverMode,
{
    /// Asserts that the channel is compatible with the given peripheral.
    #[instability::unstable]
    pub fn runtime_ensure_compatible(&self, peripheral: DmaPeripheral) {
        self.rx.runtime_ensure_compatible(peripheral);
    }
}
impl<CH> Channel<Async, CH>
where
    CH: DmaChannel,
{
    /// Converts an async channel to a blocking channel.
    pub fn into_blocking(self) -> Channel<Blocking, CH> {
        Channel {
            rx: self.rx.into_blocking(),
            tx: self.tx.into_blocking(),
        }
    }
}
impl<CH: DmaChannel> From<Channel<Blocking, CH>> for Channel<Async, CH> {
    fn from(channel: Channel<Blocking, CH>) -> Self {
        channel.into_async()
    }
}
impl<CH: DmaChannel> From<Channel<Async, CH>> for Channel<Blocking, CH> {
    fn from(channel: Channel<Async, CH>) -> Self {
        channel.into_blocking()
    }
}
pub(crate) mod asynch {
    use core::task::Poll;
    use enumset::enum_set;
    use super::*;
    use crate::rtc_cntl::WakeLock;
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct DmaTxFuture<'a, CH>
    where
        CH: DmaTxChannel,
    {
        pub(crate) tx: &'a mut ChannelTx<Async, CH>,
        success_interrupts: EnumSet<DmaTxInterrupt>,
        failure_interrupts: EnumSet<DmaTxInterrupt>,
        _wake_lock: WakeLock,
    }
    impl<'a, CH> DmaTxFuture<'a, CH>
    where
        CH: DmaTxChannel,
    {
        #[cfg_attr(
            not(any(i2s_driver_supported, uhci_driver_supported)),
            expect(dead_code)
        )]
        pub fn new(tx: &'a mut ChannelTx<Async, CH>) -> Self {
            Self {
                tx,
                success_interrupts: enum_set!(DmaTxInterrupt::TotalEof),
                failure_interrupts: enum_set!(DmaTxInterrupt::DescriptorError),
                _wake_lock: WakeLock::new(),
            }
        }
        #[cfg_attr(not(i2s_driver_supported), expect(dead_code))]
        pub fn new_with_config(
            tx: &'a mut ChannelTx<Async, CH>,
            success_interrupts: EnumSet<DmaTxInterrupt>,
            failure_interrupts: EnumSet<DmaTxInterrupt>,
        ) -> Self {
            Self {
                tx,
                success_interrupts,
                failure_interrupts,
                _wake_lock: WakeLock::new(),
            }
        }
    }
    impl<CH> core::future::Future for DmaTxFuture<'_, CH>
    where
        CH: DmaTxChannel,
    {
        type Output = Result<(), DmaError>;
        fn poll(
            self: core::pin::Pin<&mut Self>,
            cx: &mut core::task::Context<'_>,
        ) -> Poll<Self::Output> {
            let interrupts = self.tx.pending_out_interrupts();
            let result = if !interrupts.is_disjoint(self.failure_interrupts) {
                Err(DmaError::DescriptorError)
            } else if !interrupts.is_disjoint(self.success_interrupts) {
                Ok(())
            } else {
                // The interrupt may become pending before we register the waker and start
                // listening, but that should just trigger the interrupt handler. The only
                // constraint we have is that the waker must be registered before we start
                // listening.
                self.tx.waker().register(cx.waker());
                self.tx
                    .listen_out(self.success_interrupts | self.failure_interrupts);
                return Poll::Pending;
            };
            self.tx.clear_out(interrupts);
            Poll::Ready(result)
        }
    }
    impl<CH> Drop for DmaTxFuture<'_, CH>
    where
        CH: DmaTxChannel,
    {
        fn drop(&mut self) {
            self.tx
                .unlisten_out(self.success_interrupts | self.failure_interrupts);
        }
    }
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct DmaRxFuture<'a, CH>
    where
        CH: DmaRxChannel,
    {
        pub(crate) rx: &'a mut ChannelRx<Async, CH>,
        success_interrupts: EnumSet<DmaRxInterrupt>,
        failure_interrupts: EnumSet<DmaRxInterrupt>,
        _wake_lock: WakeLock,
    }
    impl<'a, CH> DmaRxFuture<'a, CH>
    where
        CH: DmaRxChannel,
    {
        pub fn new(rx: &'a mut ChannelRx<Async, CH>) -> Self {
            Self {
                rx,
                success_interrupts: enum_set!(DmaRxInterrupt::SuccessfulEof),
                failure_interrupts: enum_set!(
                    DmaRxInterrupt::DescriptorError
                        | DmaRxInterrupt::DescriptorEmpty
                        | DmaRxInterrupt::ErrorEof
                ),
5
                _wake_lock: WakeLock::new(),
            }
        }
        #[cfg_attr(not(i2s_driver_supported), expect(unused))]
        pub fn new_with_config(
            rx: &'a mut ChannelRx<Async, CH>,
            success_interrupts: EnumSet<DmaRxInterrupt>,
            failure_interrupts: EnumSet<DmaRxInterrupt>,
        ) -> Self {
            Self {
                rx,
                success_interrupts,
                failure_interrupts,
                _wake_lock: WakeLock::new(),
            }
        }
    }
    impl<CH> core::future::Future for DmaRxFuture<'_, CH>
    where
        CH: DmaRxChannel,
    {
        type Output = Result<(), DmaError>;
        fn poll(
            self: core::pin::Pin<&mut Self>,
            cx: &mut core::task::Context<'_>,
        ) -> Poll<Self::Output> {
5
            let interrupts = self.rx.pending_in_interrupts();
10
            let result = if !interrupts.is_disjoint(self.failure_interrupts) {
                Err(DmaError::DescriptorError)
10
            } else if !interrupts.is_disjoint(self.success_interrupts) {
                Ok(())
            } else {
                // The interrupt may become pending before we register the waker and start
                // listening, but that should just trigger the interrupt handler. The only
                // constraint we have is that the waker must be registered before we start
                // listening.
                self.rx.waker().register(cx.waker());
                self.rx
                    .listen_in(self.success_interrupts | self.failure_interrupts);
                return Poll::Pending;
            };
            self.rx.clear_in(interrupts);
            Poll::Ready(result)
        }
    }
    impl<CH> Drop for DmaRxFuture<'_, CH>
    where
        CH: DmaRxChannel,
    {
        fn drop(&mut self) {
5
            self.rx
5
                .unlisten_in(self.success_interrupts | self.failure_interrupts);
        }
    }
    pub(super) fn handle_in_interrupt<CH: DmaChannelExt>() {
        let rx = CH::rx_interrupts();
5
        if !rx.is_async() {
            return;
        }
        let pending = rx.pending_interrupts();
        let enabled = rx.is_listening();
5
        if !pending.is_disjoint(enabled) {
            rx.unlisten(EnumSet::all());
5
            rx.waker().wake()
        }
    }
    pub(super) fn handle_out_interrupt<CH: DmaChannelExt>() {
        let tx = CH::tx_interrupts();
5
        if !tx.is_async() {
            return;
        }
        let pending = tx.pending_interrupts();
        let enabled = tx.is_listening();
5
        if !pending.is_disjoint(enabled) {
            tx.unlisten(EnumSet::all());
            tx.waker().wake()
        }
    }
}