mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-01 14:20:44 +00:00
Migrate PARL_IO driver to newer DMA API (#3033)
* Migrate PARL_IO driver to newer DMA API * Register waker when necessary * Basic HIL test * fmt * oops * return resources on error * Invert sampling edge * Attempt manual formatting --------- Co-authored-by: Dominic Fischer <git@dominicfischer.me>
This commit is contained in:
parent
8ba212c717
commit
fe53061931
@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `Rng` and `Trng` now implement `Peripheral<P = Self>` (#2992)
|
||||
- SPI, UART, I2C: `with_<pin>` functions of peripheral drivers now disconnect the previously assigned pins from the peripheral. (#3012)
|
||||
- SPI, UART, I2C: Dropping a driver now disconnects pins from their peripherals. (#3012)
|
||||
- Migrate PARL_IO driver to DMA move API (#3033)
|
||||
- `Async` drivers are no longer `Send` (#2980)
|
||||
- GPIO drivers now take configuration structs (#2990, #3029)
|
||||
- `flip-link` feature is now a config option (`ESP_HAL_CONFIG_FLIP_LINK`) (#3001)
|
||||
|
@ -174,6 +174,35 @@ config/config.toml
|
||||
+ ESP_HAL_CONFIG_PSRAM_MODE = "octal"
|
||||
```
|
||||
|
||||
## PARL_IO changes
|
||||
Parallel IO now uses the newer DMA Move API.
|
||||
|
||||
Changes on the TX side
|
||||
```diff
|
||||
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
|
||||
+ let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||
|
||||
- let transfer = parl_io_tx.write_dma(&tx_buffer).unwrap();
|
||||
- transfer.wait().unwrap();
|
||||
+ let transfer = parl_io_tx.write(dma_tx_buf.len(), dma_tx_buf).unwrap();
|
||||
+ (result, parl_io_tx, dma_tx_buf) = transfer.wait();
|
||||
+ result.unwrap();
|
||||
```
|
||||
|
||||
Changes on the RX side
|
||||
```diff
|
||||
let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
|
||||
+ let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
|
||||
- let transfer = parl_io_rx.read_dma(&mut rx_buffer).unwrap();
|
||||
- transfer.wait().unwrap();
|
||||
+ let transfer = parl_io_rx.read(Some(dma_rx_buf.len()), dma_rx_buf).unwrap();
|
||||
+ (_, parl_io_rx, dma_rx_buf) = transfer.wait();
|
||||
```
|
||||
|
||||
On the RX side, the `EofMode` is now decided at transfer time, rather than config time.
|
||||
- `EofMode::ByteLen` -> `Some(<number of bytes to receive>)`
|
||||
- `EofMode::EnableSignal` -> `None`
|
||||
|
||||
## GPIO changes
|
||||
|
||||
GPIO drivers now take configuration structs.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -115,6 +115,10 @@ harness = false
|
||||
name = "spi_slave"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "parl_io"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "parl_io_tx"
|
||||
harness = false
|
||||
|
121
hil-test/tests/parl_io.rs
Normal file
121
hil-test/tests/parl_io.rs
Normal file
@ -0,0 +1,121 @@
|
||||
//! PARL_IO test
|
||||
|
||||
//% CHIPS: esp32c6 esp32h2
|
||||
//% FEATURES: unstable
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp_hal::{
|
||||
dma::{DmaChannel0, DmaRxBuf, DmaTxBuf},
|
||||
dma_buffers,
|
||||
gpio::{AnyPin, Pin},
|
||||
parl_io::{
|
||||
BitPackOrder,
|
||||
ClkOutPin,
|
||||
EnableMode,
|
||||
ParlIoFullDuplex,
|
||||
RxClkInPin,
|
||||
RxFourBits,
|
||||
RxPinConfigWithValidPin,
|
||||
SampleEdge,
|
||||
TxFourBits,
|
||||
TxPinConfigWithValidPin,
|
||||
},
|
||||
peripherals::PARL_IO,
|
||||
time::RateExtU32,
|
||||
};
|
||||
use hil_test as _;
|
||||
|
||||
struct Context {
|
||||
parl_io: PARL_IO,
|
||||
dma_channel: DmaChannel0,
|
||||
clock_pin: AnyPin,
|
||||
valid_pin: AnyPin,
|
||||
data_pins: [AnyPin; 4],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests(default_timeout = 3)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context {
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
let dma_channel = peripherals.DMA_CH0;
|
||||
|
||||
let parl_io = peripherals.PARL_IO;
|
||||
|
||||
Context {
|
||||
parl_io,
|
||||
dma_channel,
|
||||
clock_pin: peripherals.GPIO11.degrade(),
|
||||
valid_pin: peripherals.GPIO10.degrade(),
|
||||
data_pins: [
|
||||
peripherals.GPIO1.degrade(),
|
||||
peripherals.GPIO0.degrade(),
|
||||
peripherals.GPIO14.degrade(),
|
||||
peripherals.GPIO23.degrade(),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parl_io_rx_can_read_tx(ctx: Context) {
|
||||
const BUFFER_SIZE: usize = 64;
|
||||
|
||||
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(BUFFER_SIZE);
|
||||
let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
|
||||
let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||
|
||||
let (clock_rx, clock_tx) = ctx.clock_pin.split();
|
||||
let (valid_rx, valid_tx) = ctx.valid_pin.split();
|
||||
let [(d0_rx, d0_tx), (d1_rx, d1_tx), (d2_rx, d2_tx), (d3_rx, d3_tx)] =
|
||||
ctx.data_pins.map(|pin| pin.split());
|
||||
|
||||
let tx_pins = TxFourBits::new(d0_tx, d1_tx, d2_tx, d3_tx);
|
||||
let rx_pins = RxFourBits::new(d0_rx, d1_rx, d2_rx, d3_rx);
|
||||
|
||||
let tx_pins = TxPinConfigWithValidPin::new(tx_pins, valid_tx);
|
||||
let mut rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
|
||||
|
||||
let clock_out_pin = ClkOutPin::new(clock_tx);
|
||||
let mut clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
|
||||
|
||||
let pio = ParlIoFullDuplex::new(ctx.parl_io, ctx.dma_channel, 40.MHz()).unwrap();
|
||||
|
||||
let pio_tx = pio
|
||||
.tx
|
||||
.with_config(
|
||||
tx_pins,
|
||||
clock_out_pin,
|
||||
0,
|
||||
SampleEdge::Invert,
|
||||
BitPackOrder::Lsb,
|
||||
)
|
||||
.unwrap();
|
||||
let pio_rx = pio
|
||||
.rx
|
||||
.with_config(&mut rx_pins, &mut clock_in_pin, BitPackOrder::Lsb, None)
|
||||
.unwrap();
|
||||
|
||||
for (i, b) in dma_tx_buf.as_mut_slice().iter_mut().enumerate() {
|
||||
*b = i as u8;
|
||||
}
|
||||
|
||||
let rx_transfer = pio_rx
|
||||
.read(Some(dma_rx_buf.len()), dma_rx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
let tx_transfer = pio_tx
|
||||
.write(dma_tx_buf.len(), dma_tx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
(_, _, dma_tx_buf) = tx_transfer.wait();
|
||||
(_, _, dma_rx_buf) = rx_transfer.wait();
|
||||
|
||||
assert_eq!(dma_rx_buf.as_slice(), dma_tx_buf.as_slice());
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@
|
||||
#[cfg(esp32c6)]
|
||||
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
|
||||
use esp_hal::{
|
||||
dma::DmaChannel0,
|
||||
dma::{DmaChannel0, DmaTxBuf},
|
||||
dma_tx_buffer,
|
||||
gpio::{
|
||||
interconnect::{InputSignal, OutputSignal},
|
||||
NoPin,
|
||||
@ -78,8 +79,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parl_io_tx_16bit_valid_clock_count(ctx: Context) {
|
||||
const BUFFER_SIZE: usize = 64;
|
||||
let tx_buffer = [0u16; BUFFER_SIZE];
|
||||
let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
|
||||
|
||||
let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(2 * BUFFER_SIZE).unwrap();
|
||||
|
||||
let pins = TxSixteenBits::new(
|
||||
NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin,
|
||||
@ -88,8 +89,7 @@ mod tests {
|
||||
let mut pins = TxPinConfigIncludingValidPin::new(pins);
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio =
|
||||
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz()).unwrap();
|
||||
|
||||
let mut pio = pio
|
||||
.tx
|
||||
@ -102,7 +102,7 @@ mod tests {
|
||||
)
|
||||
.unwrap(); // TODO: handle error
|
||||
|
||||
// use a PCNT unit to count the negitive clock edges only when valid is high
|
||||
// use a PCNT unit to count the negative clock edges only when valid is high
|
||||
let clock_unit = ctx.pcnt_unit;
|
||||
clock_unit.channel0.set_edge_signal(ctx.clock_loopback);
|
||||
clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback);
|
||||
@ -115,8 +115,11 @@ mod tests {
|
||||
|
||||
for _ in 0..100 {
|
||||
clock_unit.clear();
|
||||
let xfer = pio.write_dma(&tx_buffer).unwrap();
|
||||
xfer.wait().unwrap();
|
||||
let xfer = pio
|
||||
.write(dma_tx_buf.len(), dma_tx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
(_, pio, dma_tx_buf) = xfer.wait();
|
||||
info!("clock count: {}", clock_unit.value());
|
||||
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
|
||||
}
|
||||
@ -125,8 +128,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parl_io_tx_8bit_valid_clock_count(ctx: Context) {
|
||||
const BUFFER_SIZE: usize = 64;
|
||||
let tx_buffer = [0u8; BUFFER_SIZE];
|
||||
let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
|
||||
let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(BUFFER_SIZE).unwrap();
|
||||
|
||||
let pins = TxEightBits::new(
|
||||
NoPin,
|
||||
@ -149,8 +151,7 @@ mod tests {
|
||||
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio =
|
||||
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz()).unwrap();
|
||||
|
||||
let mut pio = pio
|
||||
.tx
|
||||
@ -176,8 +177,11 @@ mod tests {
|
||||
|
||||
for _ in 0..100 {
|
||||
clock_unit.clear();
|
||||
let xfer = pio.write_dma(&tx_buffer).unwrap();
|
||||
xfer.wait().unwrap();
|
||||
let xfer = pio
|
||||
.write(dma_tx_buf.len(), dma_tx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
(_, pio, dma_tx_buf) = xfer.wait();
|
||||
info!("clock count: {}", clock_unit.value());
|
||||
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
|
||||
}
|
||||
|
@ -9,7 +9,8 @@
|
||||
#[cfg(esp32c6)]
|
||||
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
|
||||
use esp_hal::{
|
||||
dma::DmaChannel0,
|
||||
dma::{DmaChannel0, DmaTxBuf},
|
||||
dma_tx_buffer,
|
||||
gpio::{
|
||||
interconnect::{InputSignal, OutputSignal},
|
||||
NoPin,
|
||||
@ -78,8 +79,7 @@ mod tests {
|
||||
#[test]
|
||||
async fn test_parl_io_tx_async_16bit_valid_clock_count(ctx: Context) {
|
||||
const BUFFER_SIZE: usize = 64;
|
||||
let tx_buffer = [0u16; BUFFER_SIZE];
|
||||
let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
|
||||
let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(2 * BUFFER_SIZE).unwrap();
|
||||
|
||||
let pins = TxSixteenBits::new(
|
||||
NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin,
|
||||
@ -88,7 +88,7 @@ mod tests {
|
||||
let mut pins = TxPinConfigIncludingValidPin::new(pins);
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
@ -116,7 +116,12 @@ mod tests {
|
||||
|
||||
for _ in 0..100 {
|
||||
clock_unit.clear();
|
||||
pio.write_dma_async(&tx_buffer).await.unwrap();
|
||||
let mut xfer = pio
|
||||
.write(dma_tx_buf.len(), dma_tx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
xfer.wait_for_done().await;
|
||||
(_, pio, dma_tx_buf) = xfer.wait();
|
||||
info!("clock count: {}", clock_unit.value());
|
||||
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
|
||||
}
|
||||
@ -125,8 +130,8 @@ mod tests {
|
||||
#[test]
|
||||
async fn test_parl_io_tx_async_8bit_valid_clock_count(ctx: Context) {
|
||||
const BUFFER_SIZE: usize = 64;
|
||||
let tx_buffer = [0u8; BUFFER_SIZE];
|
||||
let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
|
||||
|
||||
let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(BUFFER_SIZE).unwrap();
|
||||
|
||||
let pins = TxEightBits::new(
|
||||
NoPin,
|
||||
@ -149,7 +154,7 @@ mod tests {
|
||||
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
@ -178,7 +183,12 @@ mod tests {
|
||||
|
||||
for _ in 0..100 {
|
||||
clock_unit.clear();
|
||||
pio.write_dma_async(&tx_buffer).await.unwrap();
|
||||
let mut xfer = pio
|
||||
.write(dma_tx_buf.len(), dma_tx_buf)
|
||||
.map_err(|e| e.0)
|
||||
.unwrap();
|
||||
xfer.wait_for_done().await;
|
||||
(_, pio, dma_tx_buf) = xfer.wait();
|
||||
info!("clock count: {}", clock_unit.value());
|
||||
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user