Add HIL tests of DMA & UART, and correctly set DREQ for uart DMA
This commit is contained in:
parent
b88ef03214
commit
bd27b9080f
@ -41,18 +41,38 @@ pub unsafe fn read<'a, C: Channel, W: Word>(
|
|||||||
ch: impl Peripheral<P = C> + 'a,
|
ch: impl Peripheral<P = C> + 'a,
|
||||||
from: *const W,
|
from: *const W,
|
||||||
to: &mut [W],
|
to: &mut [W],
|
||||||
|
dreq: u8,
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
let (ptr, len) = crate::dma::slice_ptr_parts_mut(to);
|
let (to_ptr, len) = crate::dma::slice_ptr_parts_mut(to);
|
||||||
copy_inner(ch, from as *const u32, ptr as *mut u32, len, W::size(), false, true)
|
copy_inner(
|
||||||
|
ch,
|
||||||
|
from as *const u32,
|
||||||
|
to_ptr as *mut u32,
|
||||||
|
len,
|
||||||
|
W::size(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
dreq,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn write<'a, C: Channel, W: Word>(
|
pub unsafe fn write<'a, C: Channel, W: Word>(
|
||||||
ch: impl Peripheral<P = C> + 'a,
|
ch: impl Peripheral<P = C> + 'a,
|
||||||
from: &[W],
|
from: &[W],
|
||||||
to: *mut W,
|
to: *mut W,
|
||||||
|
dreq: u8,
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
let (from_ptr, len) = crate::dma::slice_ptr_parts(from);
|
let (from_ptr, len) = crate::dma::slice_ptr_parts(from);
|
||||||
copy_inner(ch, from_ptr as *const u32, to as *mut u32, len, W::size(), true, false)
|
copy_inner(
|
||||||
|
ch,
|
||||||
|
from_ptr as *const u32,
|
||||||
|
to as *mut u32,
|
||||||
|
len,
|
||||||
|
W::size(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
dreq,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn copy<'a, C: Channel, W: Word>(
|
pub unsafe fn copy<'a, C: Channel, W: Word>(
|
||||||
@ -71,6 +91,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>(
|
|||||||
W::size(),
|
W::size(),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
vals::TreqSel::PERMANENT.0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +103,7 @@ fn copy_inner<'a, C: Channel>(
|
|||||||
data_size: DataSize,
|
data_size: DataSize,
|
||||||
incr_read: bool,
|
incr_read: bool,
|
||||||
incr_write: bool,
|
incr_write: bool,
|
||||||
|
dreq: u8,
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
into_ref!(ch);
|
into_ref!(ch);
|
||||||
|
|
||||||
@ -95,6 +117,9 @@ fn copy_inner<'a, C: Channel>(
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
p.ctrl_trig().write(|w| {
|
p.ctrl_trig().write(|w| {
|
||||||
|
// TODO: Add all DREQ options to pac vals::TreqSel, and use
|
||||||
|
// `set_treq:sel`
|
||||||
|
w.0 = ((dreq as u32) & 0x3f) << 15usize;
|
||||||
w.set_data_size(data_size);
|
w.set_data_size(data_size);
|
||||||
w.set_incr_read(incr_read);
|
w.set_incr_read(incr_read);
|
||||||
w.set_incr_write(incr_write);
|
w.set_incr_write(incr_write);
|
||||||
|
@ -113,7 +113,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
|||||||
|
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe { while r.uartfr().read().txff() {} }
|
unsafe { while !r.uartfr().read().txfe() {} }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
|
|||||||
});
|
});
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _)
|
crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ)
|
||||||
};
|
};
|
||||||
transfer.await;
|
transfer.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -147,6 +147,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
for b in buffer {
|
for b in buffer {
|
||||||
*b = loop {
|
*b = loop {
|
||||||
|
if r.uartfr().read().rxfe() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let dr = r.uartdr().read();
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
@ -157,7 +161,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
return Err(Error::Parity);
|
return Err(Error::Parity);
|
||||||
} else if dr.fe() {
|
} else if dr.fe() {
|
||||||
return Err(Error::Framing);
|
return Err(Error::Framing);
|
||||||
} else if dr.fe() {
|
} else {
|
||||||
break dr.data();
|
break dr.data();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -176,7 +180,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
});
|
});
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer)
|
crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ)
|
||||||
};
|
};
|
||||||
transfer.await;
|
transfer.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -282,6 +286,30 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
|
tx.io().ctrl().write(|w| w.set_funcsel(2));
|
||||||
|
rx.io().ctrl().write(|w| w.set_funcsel(2));
|
||||||
|
|
||||||
|
tx.pad_ctrl().write(|w| {
|
||||||
|
w.set_ie(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
rx.pad_ctrl().write(|w| {
|
||||||
|
w.set_ie(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(pin) = &cts {
|
||||||
|
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||||
|
pin.pad_ctrl().write(|w| {
|
||||||
|
w.set_ie(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(pin) = &rts {
|
||||||
|
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||||
|
pin.pad_ctrl().write(|w| {
|
||||||
|
w.set_ie(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let clk_base = crate::clocks::clk_peri_freq();
|
let clk_base = crate::clocks::clk_peri_freq();
|
||||||
|
|
||||||
let baud_rate_div = (8 * clk_base) / config.baudrate;
|
let baud_rate_div = (8 * clk_base) / config.baudrate;
|
||||||
@ -302,10 +330,14 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
|||||||
|
|
||||||
let (pen, eps) = match config.parity {
|
let (pen, eps) = match config.parity {
|
||||||
Parity::ParityNone => (false, false),
|
Parity::ParityNone => (false, false),
|
||||||
Parity::ParityEven => (true, true),
|
|
||||||
Parity::ParityOdd => (true, false),
|
Parity::ParityOdd => (true, false),
|
||||||
|
Parity::ParityEven => (true, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// PL011 needs a (dummy) line control register write to latch in the
|
||||||
|
// divisors. We don't want to actually change LCR contents here.
|
||||||
|
r.uartlcr_h().modify(|_| {});
|
||||||
|
|
||||||
r.uartlcr_h().write(|w| {
|
r.uartlcr_h().write(|w| {
|
||||||
w.set_wlen(config.data_bits.bits());
|
w.set_wlen(config.data_bits.bits());
|
||||||
w.set_stp2(config.stop_bits == StopBits::STOP2);
|
w.set_stp2(config.stop_bits == StopBits::STOP2);
|
||||||
@ -321,15 +353,6 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
|||||||
w.set_ctsen(cts.is_some());
|
w.set_ctsen(cts.is_some());
|
||||||
w.set_rtsen(rts.is_some());
|
w.set_rtsen(rts.is_some());
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.io().ctrl().write(|w| w.set_funcsel(2));
|
|
||||||
rx.io().ctrl().write(|w| w.set_funcsel(2));
|
|
||||||
if let Some(pin) = &cts {
|
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
|
||||||
}
|
|
||||||
if let Some(pin) = &rts {
|
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -377,6 +400,10 @@ mod eh02 {
|
|||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if r.uartfr().read().rxfe() {
|
||||||
|
return Err(nb::Error::WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
let dr = r.uartdr().read();
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
@ -387,10 +414,8 @@ mod eh02 {
|
|||||||
Err(nb::Error::Other(Error::Parity))
|
Err(nb::Error::Other(Error::Parity))
|
||||||
} else if dr.fe() {
|
} else if dr.fe() {
|
||||||
Err(nb::Error::Other(Error::Framing))
|
Err(nb::Error::Other(Error::Framing))
|
||||||
} else if dr.fe() {
|
|
||||||
Ok(dr.data())
|
|
||||||
} else {
|
} else {
|
||||||
Err(nb::Error::WouldBlock)
|
Ok(dr.data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -512,6 +537,9 @@ mod sealed {
|
|||||||
pub trait Mode {}
|
pub trait Mode {}
|
||||||
|
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
|
const TX_DREQ: u8;
|
||||||
|
const RX_DREQ: u8;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart;
|
fn regs() -> pac::uart::Uart;
|
||||||
}
|
}
|
||||||
pub trait TxPin<T: Instance> {}
|
pub trait TxPin<T: Instance> {}
|
||||||
@ -538,8 +566,11 @@ impl_mode!(Async);
|
|||||||
pub trait Instance: sealed::Instance {}
|
pub trait Instance: sealed::Instance {}
|
||||||
|
|
||||||
macro_rules! impl_instance {
|
macro_rules! impl_instance {
|
||||||
($inst:ident, $irq:ident) => {
|
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||||
impl sealed::Instance for peripherals::$inst {
|
impl sealed::Instance for peripherals::$inst {
|
||||||
|
const TX_DREQ: u8 = $tx_dreq;
|
||||||
|
const RX_DREQ: u8 = $rx_dreq;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart {
|
fn regs() -> pac::uart::Uart {
|
||||||
pac::$inst
|
pac::$inst
|
||||||
}
|
}
|
||||||
@ -548,8 +579,8 @@ macro_rules! impl_instance {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_instance!(UART0, UART0);
|
impl_instance!(UART0, UART0, 20, 21);
|
||||||
impl_instance!(UART1, UART1);
|
impl_instance!(UART1, UART1, 22, 23);
|
||||||
|
|
||||||
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
||||||
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
||||||
|
41
tests/rp/src/bin/dma_copy_async.rs
Normal file
41
tests/rp/src/bin/dma_copy_async.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::{assert_eq, *};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::dma::copy;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
// Check `u8` copy
|
||||||
|
{
|
||||||
|
let data: [u8; 2] = [0xC0, 0xDE];
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
unsafe { copy(p.DMA_CH0, &data, &mut buf).await };
|
||||||
|
assert_eq!(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check `u16` copy
|
||||||
|
{
|
||||||
|
let data: [u16; 2] = [0xC0BE, 0xDEAD];
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
unsafe { copy(p.DMA_CH1, &data, &mut buf).await };
|
||||||
|
assert_eq!(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check `u32` copy
|
||||||
|
{
|
||||||
|
let data: [u32; 2] = [0xC0BEDEAD, 0xDEADAAFF];
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
unsafe { copy(p.DMA_CH2, &data, &mut buf).await };
|
||||||
|
assert_eq!(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
32
tests/rp/src/bin/uart.rs
Normal file
32
tests/rp/src/bin/uart.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::{assert_eq, *};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::uart::{Config, Uart};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mut uart = Uart::new_blocking(uart, tx, rx, config);
|
||||||
|
|
||||||
|
// We can't send too many bytes, they have to fit in the FIFO.
|
||||||
|
// This is because we aren't sending+receiving at the same time.
|
||||||
|
|
||||||
|
let data = [0xC0, 0xDE];
|
||||||
|
uart.blocking_write(&data).unwrap();
|
||||||
|
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
uart.blocking_read(&mut buf).unwrap();
|
||||||
|
assert_eq!(buf, data);
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
32
tests/rp/src/bin/uart_dma.rs
Normal file
32
tests/rp/src/bin/uart_dma.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::{assert_eq, *};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::uart::{Config, Uart};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mut uart = Uart::new(uart, tx, rx, p.DMA_CH0, p.DMA_CH1, config);
|
||||||
|
|
||||||
|
// We can't send too many bytes, they have to fit in the FIFO.
|
||||||
|
// This is because we aren't sending+receiving at the same time.
|
||||||
|
|
||||||
|
let data = [0xC0, 0xDE];
|
||||||
|
uart.write(&data).await.unwrap();
|
||||||
|
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
uart.read(&mut buf).await.unwrap();
|
||||||
|
assert_eq!(buf, data);
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user