esp-hal/hil-test/tests/parl_io.rs

369 lines
12 KiB
Rust

//! PARL_IO test
//% CHIPS: esp32c6 esp32h2
//% FEATURES: unstable
#![no_std]
#![no_main]
#[cfg(not(esp32h2))]
use esp_hal::parl_io::{RxSixteenBits, TxSixteenBits};
use esp_hal::{
dma::{DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::{AnyPin, Pin},
parl_io::{
BitPackOrder,
ClkOutPin,
EnableMode,
ParlIo,
RxClkInPin,
RxConfig,
RxEightBits,
RxFourBits,
RxOneBit,
RxPinConfigWithValidPin,
RxTwoBits,
SampleEdge,
TxConfig,
TxEightBits,
TxFourBits,
TxOneBit,
TxPinConfigWithValidPin,
TxTwoBits,
},
peripherals::{DMA_CH0, PARL_IO},
time::Rate,
};
use hil_test as _;
struct Context {
parl_io: PARL_IO<'static>,
dma_channel: DMA_CH0<'static>,
clock_pin: AnyPin<'static>,
valid_pin: AnyPin<'static>,
data_pins: [AnyPin<'static>; 8],
#[cfg(esp32c6)]
extra_data_pins: [AnyPin<'static>; 7],
}
#[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,
#[cfg(esp32h2)]
clock_pin: peripherals.GPIO13.degrade(),
#[cfg(esp32h2)]
valid_pin: peripherals.GPIO24.degrade(),
#[cfg(esp32c6)]
clock_pin: peripherals.GPIO16.degrade(),
#[cfg(esp32c6)]
valid_pin: peripherals.GPIO17.degrade(),
data_pins: [
peripherals.GPIO2.degrade(),
peripherals.GPIO4.degrade(),
peripherals.GPIO10.degrade(),
peripherals.GPIO11.degrade(),
peripherals.GPIO14.degrade(),
peripherals.GPIO23.degrade(),
peripherals.GPIO0.degrade(),
peripherals.GPIO1.degrade(),
],
#[cfg(esp32c6)]
extra_data_pins: [
peripherals.GPIO18.degrade(),
peripherals.GPIO19.degrade(),
peripherals.GPIO20.degrade(),
peripherals.GPIO22.degrade(),
peripherals.GPIO8.degrade(),
peripherals.GPIO9.degrade(),
peripherals.GPIO15.degrade(),
],
}
}
#[test]
fn test_parl_io_rx_can_read_tx_in_1_bit_mode(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) = unsafe { ctx.clock_pin.split() };
let (valid_rx, valid_tx) = unsafe { ctx.valid_pin.split() };
let [(d0_rx, d0_tx), ..] = ctx.data_pins.map(|pin| unsafe { pin.split() });
let tx_pins = TxOneBit::new(d0_tx);
let rx_pins = RxOneBit::new(d0_rx);
let tx_pins = TxPinConfigWithValidPin::new(tx_pins, valid_tx);
let rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
let clock_out_pin = ClkOutPin::new(clock_tx);
let clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
let pio = ParlIo::new(ctx.parl_io, ctx.dma_channel).unwrap();
let pio_tx = pio
.tx
.with_config(
tx_pins,
clock_out_pin,
TxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_sample_edge(SampleEdge::Invert)
.with_bit_order(BitPackOrder::Lsb),
)
.unwrap();
let pio_rx = pio
.rx
.with_config(
rx_pins,
clock_in_pin,
RxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_bit_order(BitPackOrder::Lsb),
)
.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());
}
#[test]
fn test_parl_io_rx_can_read_tx_in_2_bit_mode(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) = unsafe { ctx.clock_pin.split() };
let (valid_rx, valid_tx) = unsafe { ctx.valid_pin.split() };
let [(d0_rx, d0_tx), (d1_rx, d1_tx), ..] = ctx.data_pins.map(|pin| unsafe { pin.split() });
let tx_pins = TxTwoBits::new(d0_tx, d1_tx);
let rx_pins = RxTwoBits::new(d0_rx, d1_rx);
let tx_pins = TxPinConfigWithValidPin::new(tx_pins, valid_tx);
let rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
let clock_out_pin = ClkOutPin::new(clock_tx);
let clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
let pio = ParlIo::new(ctx.parl_io, ctx.dma_channel).unwrap();
let pio_tx = pio
.tx
.with_config(
tx_pins,
clock_out_pin,
TxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_sample_edge(SampleEdge::Invert)
.with_bit_order(BitPackOrder::Lsb),
)
.unwrap();
let pio_rx = pio
.rx
.with_config(
rx_pins,
clock_in_pin,
RxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_bit_order(BitPackOrder::Lsb),
)
.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());
}
#[test]
fn test_parl_io_rx_can_read_tx_in_4_bit_mode(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) = unsafe { ctx.clock_pin.split() };
let (valid_rx, valid_tx) = unsafe { 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| unsafe { 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 rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
let clock_out_pin = ClkOutPin::new(clock_tx);
let clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
let pio = ParlIo::new(ctx.parl_io, ctx.dma_channel).unwrap();
let pio_tx = pio
.tx
.with_config(
tx_pins,
clock_out_pin,
TxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_sample_edge(SampleEdge::Invert)
.with_bit_order(BitPackOrder::Lsb),
)
.unwrap();
let pio_rx = pio
.rx
.with_config(
rx_pins,
clock_in_pin,
RxConfig::default()
.with_frequency(Rate::from_mhz(40))
.with_bit_order(BitPackOrder::Lsb),
)
.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());
}
// This test is disabled on the H2 because in 8-bit mode, there's no external
// enable pin to indicate when data is valid. The C6 has the same issue in
// 16-bit mode. The test would have to be written differently for it to work
// reliably. See https://github.com/esp-rs/esp-hal/pull/3339.
#[cfg(not(esp32h2))]
#[test]
fn test_parl_io_rx_can_read_tx_in_8_bit_mode(ctx: Context) {
const BUFFER_SIZE: usize = 250;
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) = unsafe { ctx.clock_pin.split() };
let (valid_rx, valid_tx) = unsafe { ctx.valid_pin.split() };
let [
(d0_rx, d0_tx),
(d1_rx, d1_tx),
(d2_rx, d2_tx),
(d3_rx, d3_tx),
(d4_rx, d4_tx),
(d5_rx, d5_tx),
(d6_rx, d6_tx),
(d7_rx, d7_tx),
] = ctx.data_pins.map(|pin| unsafe { pin.split() });
let tx_pins = TxEightBits::new(d0_tx, d1_tx, d2_tx, d3_tx, d4_tx, d5_tx, d6_tx, d7_tx);
let rx_pins = RxEightBits::new(d0_rx, d1_rx, d2_rx, d3_rx, d4_rx, d5_rx, d6_rx, d7_rx);
let tx_pins = TxPinConfigWithValidPin::new(tx_pins, valid_tx);
let rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
let clock_out_pin = ClkOutPin::new(clock_tx);
let clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
let pio = ParlIo::new(ctx.parl_io, ctx.dma_channel).unwrap();
let pio_tx = pio
.tx
.with_config(
tx_pins,
clock_out_pin,
TxConfig::default()
.with_frequency(Rate::from_khz(100))
.with_sample_edge(SampleEdge::Invert)
.with_bit_order(BitPackOrder::Msb),
)
.unwrap();
let pio_rx = pio
.rx
.with_config(
rx_pins,
clock_in_pin,
RxConfig::default()
.with_frequency(Rate::from_khz(100))
.with_bit_order(BitPackOrder::Msb),
)
.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());
}
}