Skip to content

Commit 9744d12

Browse files
authored
SPI-DMA for ESP32 (#216)
* SPI-DMA for ESP32 * MSRV Fix
1 parent d78cb10 commit 9744d12

File tree

11 files changed

+1187
-598
lines changed

11 files changed

+1187
-598
lines changed

esp-hal-common/src/dma/gdma.rs

Lines changed: 48 additions & 477 deletions
Large diffs are not rendered by default.

esp-hal-common/src/dma/mod.rs

Lines changed: 510 additions & 0 deletions
Large diffs are not rendered by default.

esp-hal-common/src/dma/pdma.rs

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//! Direct Memory Access
2+
3+
use crate::{
4+
dma::pdma::private::*,
5+
system::{Peripheral, PeripheralClockControl},
6+
};
7+
8+
macro_rules! ImplSpiChannel {
9+
($num: literal) => {
10+
paste::paste! {
11+
pub struct [<Spi $num DmaChannel>] {}
12+
13+
impl RegisterAccess for [<Spi $num DmaChannel>] {
14+
fn init_channel() {
15+
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
16+
let dport = unsafe { &*crate::pac::DPORT::PTR };
17+
18+
match $num {
19+
2 => {
20+
dport
21+
.spi_dma_chan_sel
22+
.modify(|_, w| w.spi2_dma_chan_sel().variant(1));
23+
},
24+
3 => {
25+
dport
26+
.spi_dma_chan_sel
27+
.modify(|_, w| w.spi3_dma_chan_sel().variant(2));
28+
},
29+
_ => panic!("Only SPI2 and SPI3 supported"),
30+
}
31+
}
32+
33+
fn set_out_burstmode(burst_mode: bool) {
34+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
35+
spi.dma_conf
36+
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
37+
}
38+
39+
fn set_out_priority(_priority: DmaPriority) {}
40+
41+
fn clear_out_interrupts() {
42+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
43+
spi.dma_int_clr.write(|w| {
44+
w.out_done_int_clr()
45+
.set_bit()
46+
.out_eof_int_clr()
47+
.set_bit()
48+
.out_total_eof_int_clr()
49+
.set_bit()
50+
.outlink_dscr_error_int_clr()
51+
.set_bit()
52+
});
53+
}
54+
55+
fn reset_out() {
56+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
57+
spi.dma_conf.modify(|_, w| w.out_rst().set_bit());
58+
spi.dma_conf.modify(|_, w| w.out_rst().clear_bit());
59+
}
60+
61+
fn set_out_descriptors(address: u32) {
62+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
63+
spi.dma_out_link
64+
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
65+
}
66+
67+
fn has_out_descriptor_error() -> bool {
68+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
69+
spi.dma_int_raw.read().outlink_dscr_error_int_raw().bit()
70+
}
71+
72+
fn set_out_peripheral(_peripheral: u8) {
73+
// no-op
74+
}
75+
76+
fn start_out() {
77+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
78+
spi.dma_out_link.modify(|_, w| w.outlink_start().set_bit());
79+
}
80+
81+
fn is_out_done() -> bool {
82+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
83+
spi.dma_int_raw.read().out_done_int_raw().bit()
84+
}
85+
86+
fn set_in_burstmode(burst_mode: bool) {
87+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
88+
spi.dma_conf
89+
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
90+
}
91+
92+
fn set_in_priority(_priority: DmaPriority) {}
93+
94+
fn clear_in_interrupts() {
95+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
96+
spi.dma_int_clr.write(|w| {
97+
w.in_done_int_clr()
98+
.set_bit()
99+
.in_err_eof_int_clr()
100+
.set_bit()
101+
.in_suc_eof_int_clr()
102+
.set_bit()
103+
.inlink_dscr_error_int_clr()
104+
.set_bit()
105+
});
106+
}
107+
108+
fn reset_in() {
109+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
110+
spi.dma_conf.modify(|_, w| w.in_rst().set_bit());
111+
spi.dma_conf.modify(|_, w| w.in_rst().clear_bit());
112+
}
113+
114+
fn set_in_descriptors(address: u32) {
115+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
116+
spi.dma_in_link
117+
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
118+
}
119+
120+
fn has_in_descriptor_error() -> bool {
121+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
122+
spi.dma_int_raw.read().inlink_dscr_error_int_raw().bit()
123+
}
124+
125+
fn set_in_peripheral(_peripheral: u8) {
126+
// no-op
127+
}
128+
129+
fn start_in() {
130+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
131+
spi.dma_in_link.modify(|_, w| w.inlink_start().set_bit());
132+
}
133+
134+
fn is_in_done() -> bool {
135+
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
136+
spi.dma_int_raw.read().in_done_int_raw().bit()
137+
}
138+
}
139+
140+
pub struct [<Spi $num DmaChannelTxImpl>] {}
141+
142+
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {}
143+
144+
pub struct [<Spi $num DmaChannelRxImpl>] {}
145+
146+
impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {}
147+
148+
pub struct [<Spi $num DmaChannelCreator>] {}
149+
150+
impl [<Spi $num DmaChannelCreator>] {
151+
pub fn configure<'a>(
152+
self,
153+
burst_mode: bool,
154+
tx_descriptors: &'a mut [u32],
155+
rx_descriptors: &'a mut [u32],
156+
priority: DmaPriority,
157+
) -> Channel<
158+
ChannelTx<[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>,
159+
ChannelRx<[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>,
160+
[<Spi $num DmaSuitablePeripheral>],
161+
> {
162+
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
163+
tx_impl.init(burst_mode, priority);
164+
165+
let tx_channel = ChannelTx {
166+
descriptors: tx_descriptors,
167+
burst_mode,
168+
tx_impl: tx_impl,
169+
_phantom: PhantomData::default(),
170+
};
171+
172+
let mut rx_impl = [<Spi $num DmaChannelRxImpl>] {};
173+
rx_impl.init(burst_mode, priority);
174+
175+
let rx_channel = ChannelRx {
176+
descriptors: rx_descriptors,
177+
burst_mode,
178+
rx_impl: rx_impl,
179+
_phantom: PhantomData::default(),
180+
};
181+
182+
Channel {
183+
tx: tx_channel,
184+
rx: rx_channel,
185+
_phantom: PhantomData::default(),
186+
}
187+
}
188+
}
189+
}
190+
};
191+
}
192+
193+
/// Crate private implementatin details
194+
pub(crate) mod private {
195+
use crate::dma::{private::*, *};
196+
197+
pub struct Spi2DmaSuitablePeripheral {}
198+
impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
199+
impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
200+
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}
201+
202+
pub struct Spi3DmaSuitablePeripheral {}
203+
impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
204+
impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
205+
impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}
206+
207+
ImplSpiChannel!(2);
208+
ImplSpiChannel!(3);
209+
}
210+
211+
/// DMA Peripheral
212+
///
213+
/// This offers the available DMA channels.
214+
pub struct Dma {
215+
_inner: crate::system::Dma,
216+
pub spi2channel: Spi2DmaChannelCreator,
217+
pub spi3channel: Spi3DmaChannelCreator,
218+
}
219+
220+
impl Dma {
221+
/// Create a DMA instance.
222+
pub fn new(
223+
dma: crate::system::Dma,
224+
peripheral_clock_control: &mut PeripheralClockControl,
225+
) -> Dma {
226+
peripheral_clock_control.enable(Peripheral::Dma);
227+
228+
Dma {
229+
_inner: dma,
230+
spi2channel: Spi2DmaChannelCreator {},
231+
spi3channel: Spi3DmaChannelCreator {},
232+
}
233+
}
234+
}

esp-hal-common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub mod efuse;
9090
#[cfg_attr(xtensa, path = "interrupt/xtensa.rs")]
9191
pub mod interrupt;
9292

93+
#[cfg(any(esp32c3, esp32))]
9394
pub mod dma;
9495

9596
/// Enumeration of CPU cores

0 commit comments

Comments
 (0)