Skip to content

Commit

Permalink
SPI-DMA for ESP32 (#216)
Browse files Browse the repository at this point in the history
* SPI-DMA for ESP32

* MSRV Fix
  • Loading branch information
bjoernQ authored Oct 20, 2022
1 parent d78cb10 commit 9744d12
Show file tree
Hide file tree
Showing 11 changed files with 1,187 additions and 598 deletions.
525 changes: 48 additions & 477 deletions esp-hal-common/src/dma/gdma.rs

Large diffs are not rendered by default.

510 changes: 510 additions & 0 deletions esp-hal-common/src/dma/mod.rs

Large diffs are not rendered by default.

234 changes: 234 additions & 0 deletions esp-hal-common/src/dma/pdma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
//! Direct Memory Access

use crate::{
dma::pdma::private::*,
system::{Peripheral, PeripheralClockControl},
};

macro_rules! ImplSpiChannel {
($num: literal) => {
paste::paste! {
pub struct [<Spi $num DmaChannel>] {}

impl RegisterAccess for [<Spi $num DmaChannel>] {
fn init_channel() {
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
let dport = unsafe { &*crate::pac::DPORT::PTR };

match $num {
2 => {
dport
.spi_dma_chan_sel
.modify(|_, w| w.spi2_dma_chan_sel().variant(1));
},
3 => {
dport
.spi_dma_chan_sel
.modify(|_, w| w.spi3_dma_chan_sel().variant(2));
},
_ => panic!("Only SPI2 and SPI3 supported"),
}
}

fn set_out_burstmode(burst_mode: bool) {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_conf
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
}

fn set_out_priority(_priority: DmaPriority) {}

fn clear_out_interrupts() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_clr.write(|w| {
w.out_done_int_clr()
.set_bit()
.out_eof_int_clr()
.set_bit()
.out_total_eof_int_clr()
.set_bit()
.outlink_dscr_error_int_clr()
.set_bit()
});
}

fn reset_out() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_conf.modify(|_, w| w.out_rst().set_bit());
spi.dma_conf.modify(|_, w| w.out_rst().clear_bit());
}

fn set_out_descriptors(address: u32) {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_out_link
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}

fn has_out_descriptor_error() -> bool {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().outlink_dscr_error_int_raw().bit()
}

fn set_out_peripheral(_peripheral: u8) {
// no-op
}

fn start_out() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_out_link.modify(|_, w| w.outlink_start().set_bit());
}

fn is_out_done() -> bool {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().out_done_int_raw().bit()
}

fn set_in_burstmode(burst_mode: bool) {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_conf
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}

fn set_in_priority(_priority: DmaPriority) {}

fn clear_in_interrupts() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_clr.write(|w| {
w.in_done_int_clr()
.set_bit()
.in_err_eof_int_clr()
.set_bit()
.in_suc_eof_int_clr()
.set_bit()
.inlink_dscr_error_int_clr()
.set_bit()
});
}

fn reset_in() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_conf.modify(|_, w| w.in_rst().set_bit());
spi.dma_conf.modify(|_, w| w.in_rst().clear_bit());
}

fn set_in_descriptors(address: u32) {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_in_link
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}

fn has_in_descriptor_error() -> bool {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().inlink_dscr_error_int_raw().bit()
}

fn set_in_peripheral(_peripheral: u8) {
// no-op
}

fn start_in() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_in_link.modify(|_, w| w.inlink_start().set_bit());
}

fn is_in_done() -> bool {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().in_done_int_raw().bit()
}
}

pub struct [<Spi $num DmaChannelTxImpl>] {}

impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {}

pub struct [<Spi $num DmaChannelRxImpl>] {}

impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {}

pub struct [<Spi $num DmaChannelCreator>] {}

impl [<Spi $num DmaChannelCreator>] {
pub fn configure<'a>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32],
priority: DmaPriority,
) -> Channel<
ChannelTx<[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>,
ChannelRx<[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>,
[<Spi $num DmaSuitablePeripheral>],
> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);

let tx_channel = ChannelTx {
descriptors: tx_descriptors,
burst_mode,
tx_impl: tx_impl,
_phantom: PhantomData::default(),
};

let mut rx_impl = [<Spi $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);

let rx_channel = ChannelRx {
descriptors: rx_descriptors,
burst_mode,
rx_impl: rx_impl,
_phantom: PhantomData::default(),
};

Channel {
tx: tx_channel,
rx: rx_channel,
_phantom: PhantomData::default(),
}
}
}
}
};
}

/// Crate private implementatin details
pub(crate) mod private {
use crate::dma::{private::*, *};

pub struct Spi2DmaSuitablePeripheral {}
impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}

pub struct Spi3DmaSuitablePeripheral {}
impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}

ImplSpiChannel!(2);
ImplSpiChannel!(3);
}

/// DMA Peripheral
///
/// This offers the available DMA channels.
pub struct Dma {
_inner: crate::system::Dma,
pub spi2channel: Spi2DmaChannelCreator,
pub spi3channel: Spi3DmaChannelCreator,
}

impl Dma {
/// Create a DMA instance.
pub fn new(
dma: crate::system::Dma,
peripheral_clock_control: &mut PeripheralClockControl,
) -> Dma {
peripheral_clock_control.enable(Peripheral::Dma);

Dma {
_inner: dma,
spi2channel: Spi2DmaChannelCreator {},
spi3channel: Spi3DmaChannelCreator {},
}
}
}
1 change: 1 addition & 0 deletions esp-hal-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub mod efuse;
#[cfg_attr(xtensa, path = "interrupt/xtensa.rs")]
pub mod interrupt;

#[cfg(any(esp32c3, esp32))]
pub mod dma;

/// Enumeration of CPU cores
Expand Down
Loading

0 comments on commit 9744d12

Please sign in to comment.