mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
369 lines
12 KiB
Rust
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());
|
|
}
|
|
}
|