forked from esp-rs/esp-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspi_full_duplex_dma_async.rs
172 lines (139 loc) · 5.73 KB
/
spi_full_duplex_dma_async.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! SPI Full Duplex DMA Test
//!
//! Folowing pins are used:
//! SCLK GPIO0
//! MOSI GPIO3
//! MISO GPIO6
//! CS GPIO8
//!
//! PCNT GPIO2
//! OUTPUT GPIO5 (helper to keep MISO LOW)
//!
//! The idea of using PCNT (input) here is to connect MOSI to it and count the
//! edges of whatever SPI writes (in this test case 3 pos edges).
//!
//! Connect PCNT (GPIO2) and MOSI (GPIO3) and MISO (GPIO6) and GPIO5 pins.
//% CHIPS: esp32 esp32c6 esp32h2 esp32s3
#![no_std]
#![no_main]
use embedded_hal_async::spi::SpiBus;
use esp_hal::{
clock::ClockControl,
dma::{Dma, DmaPriority},
dma_buffers,
gpio::{Io, Level, Output, Pull},
pcnt::{
channel::{EdgeMode, PcntInputConfig, PcntSource},
Pcnt,
},
peripherals::Peripherals,
prelude::*,
spi::{master::Spi, SpiMode},
system::SystemControl,
};
use hil_test as _;
#[cfg(test)]
#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())]
mod tests {
use defmt::assert_eq;
use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
use super::*;
#[test]
#[timeout(3)]
async fn test_async_dma_read_dma_write_pcnt() {
const DMA_BUFFER_SIZE: usize = 5;
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let pcnt = Pcnt::new(peripherals.PCNT);
let sclk = io.pins.gpio0;
let mosi_mirror = io.pins.gpio2;
let mosi = io.pins.gpio3;
let miso = io.pins.gpio6;
let cs = io.pins.gpio8;
let mut out_pin = Output::new(io.pins.gpio5, Level::Low);
out_pin.set_low();
assert_eq!(out_pin.is_set_low(), true);
let dma = Dma::new(peripherals.DMA);
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
let dma_channel = dma.spi2channel;
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
let dma_channel = dma.channel0;
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
.with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
.with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0))
.with_buffers(dma_tx_buf, dma_rx_buf);
let unit = pcnt.unit0;
unit.channel0.set_edge_signal(PcntSource::from_pin(
mosi_mirror,
PcntInputConfig { pull: Pull::Down },
));
unit.channel0
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
let mut receive = [0; DMA_BUFFER_SIZE];
// Fill the buffer where each byte has 3 pos edges.
let transmit = [0b0110_1010; DMA_BUFFER_SIZE];
assert_eq!(out_pin.is_set_low(), true);
for i in 1..4 {
receive.copy_from_slice(&[5, 5, 5, 5, 5]);
SpiBus::read(&mut spi, &mut receive).await.unwrap();
assert_eq!(receive, [0, 0, 0, 0, 0]);
SpiBus::write(&mut spi, &transmit).await.unwrap();
assert_eq!(unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _);
}
}
#[test]
#[timeout(3)]
async fn test_async_dma_read_dma_transfer_pcnt() {
const DMA_BUFFER_SIZE: usize = 5;
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let pcnt = Pcnt::new(peripherals.PCNT);
let sclk = io.pins.gpio0;
let mosi_mirror = io.pins.gpio2;
let mosi = io.pins.gpio3;
let miso = io.pins.gpio6;
let cs = io.pins.gpio8;
let mut out_pin = Output::new(io.pins.gpio5, Level::High);
out_pin.set_low();
assert_eq!(out_pin.is_set_low(), true);
let dma = Dma::new(peripherals.DMA);
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
let dma_channel = dma.spi2channel;
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
let dma_channel = dma.channel0;
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
.with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
.with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0))
.with_buffers(dma_tx_buf, dma_rx_buf);
let unit = pcnt.unit0;
unit.channel0.set_edge_signal(PcntSource::from_pin(
mosi_mirror,
PcntInputConfig { pull: Pull::Down },
));
unit.channel0
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
let mut receive = [0; DMA_BUFFER_SIZE];
// Fill the buffer where each byte has 3 pos edges.
let transmit = [0b0110_1010; DMA_BUFFER_SIZE];
assert_eq!(out_pin.is_set_low(), true);
for i in 1..4 {
receive.copy_from_slice(&[5, 5, 5, 5, 5]);
SpiBus::read(&mut spi, &mut receive).await.unwrap();
assert_eq!(receive, [0, 0, 0, 0, 0]);
SpiBus::transfer(&mut spi, &mut receive, &transmit)
.await
.unwrap();
assert_eq!(unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _);
}
}
}