Add UART and DMA drivers

Both blocking and async versions are supported. Add separate examples
for each mode.
This commit is contained in:
Felipe Balbi 2025-04-10 10:39:54 -07:00
parent d1c2ce927a
commit d64ae225b3
8 changed files with 2069 additions and 21 deletions

View File

@ -10,5 +10,7 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb
The following peripherals have a HAL implementation at present
* CRC
* DMA
* GPIO
* RNG
* UART

418
embassy-imxrt/src/dma.rs Normal file
View File

@ -0,0 +1,418 @@
//! DMA driver.
use core::future::Future;
use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll};
use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use pac::dma0::channel::cfg::Periphreqen;
use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width};
use crate::clocks::enable_and_reset;
use crate::interrupt::InterruptExt;
use crate::peripherals::DMA0;
use crate::sealed::Sealed;
use crate::{interrupt, pac, peripherals, BitIter};
#[cfg(feature = "rt")]
#[interrupt]
fn DMA0() {
let reg = unsafe { crate::pac::Dma0::steal() };
if reg.intstat().read().activeerrint().bit() {
let err = reg.errint0().read().bits();
for channel in BitIter(err) {
error!("DMA error interrupt on channel {}!", channel);
reg.errint0().write(|w| unsafe { w.err().bits(1 << channel) });
CHANNEL_WAKERS[channel as usize].wake();
}
}
if reg.intstat().read().activeint().bit() {
let ia = reg.inta0().read().bits();
for channel in BitIter(ia) {
reg.inta0().write(|w| unsafe { w.ia().bits(1 << channel) });
CHANNEL_WAKERS[channel as usize].wake();
}
}
}
/// Initialize DMA controllers (DMA0 only, for now)
pub(crate) unsafe fn init() {
let sysctl0 = crate::pac::Sysctl0::steal();
let dmactl0 = crate::pac::Dma0::steal();
enable_and_reset::<DMA0>();
interrupt::DMA0.disable();
interrupt::DMA0.set_priority(interrupt::Priority::P3);
dmactl0.ctrl().modify(|_, w| w.enable().set_bit());
// Set channel descriptor SRAM base address
// Descriptor base must be 1K aligned
let descriptor_base = core::ptr::addr_of!(DESCRIPTORS.descs) as u32;
dmactl0.srambase().write(|w| w.bits(descriptor_base));
// Ensure AHB priority it highest (M4 == DMAC0)
sysctl0.ahbmatrixprior().modify(|_, w| w.m4().bits(0));
interrupt::DMA0.unpend();
interrupt::DMA0.enable();
}
/// DMA read.
///
/// SAFETY: Slice must point to a valid location reachable by DMA.
pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
let count = ((to.len() / W::size() as usize) - 1) as isize;
copy_inner(
ch,
from as *const u32,
(to as *mut u32).byte_offset(count * W::size()),
W::width(),
count,
false,
true,
true,
)
}
/// DMA write.
///
/// SAFETY: Slice must point to a valid location reachable by DMA.
pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
let count = ((from.len() / W::size() as usize) - 1) as isize;
copy_inner(
ch,
(from as *const u32).byte_offset(count * W::size()),
to as *mut u32,
W::width(),
count,
true,
false,
true,
)
}
/// DMA copy between slices.
///
/// SAFETY: Slices must point to locations reachable by DMA.
pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
let from_len = from.len();
let to_len = to.len();
assert_eq!(from_len, to_len);
let count = ((from_len / W::size() as usize) - 1) as isize;
copy_inner(
ch,
from.as_ptr().byte_offset(count * W::size()) as *const u32,
to.as_mut_ptr().byte_offset(count * W::size()) as *mut u32,
W::width(),
count,
true,
true,
false,
)
}
fn copy_inner<'a, C: Channel>(
ch: Peri<'a, C>,
from: *const u32,
to: *mut u32,
width: Width,
count: isize,
incr_read: bool,
incr_write: bool,
periph: bool,
) -> Transfer<'a, C> {
let p = ch.regs();
unsafe {
DESCRIPTORS.descs[ch.number() as usize].src = from as u32;
DESCRIPTORS.descs[ch.number() as usize].dest = to as u32;
}
compiler_fence(Ordering::SeqCst);
p.errint0().write(|w| unsafe { w.err().bits(1 << ch.number()) });
p.inta0().write(|w| unsafe { w.ia().bits(1 << ch.number()) });
p.channel(ch.number().into()).cfg().write(|w| {
unsafe { w.chpriority().bits(0) }
.periphreqen()
.variant(match periph {
false => Periphreqen::Disabled,
true => Periphreqen::Enabled,
})
.hwtrigen()
.clear_bit()
});
p.intenset0().write(|w| unsafe { w.inten().bits(1 << ch.number()) });
p.channel(ch.number().into()).xfercfg().write(|w| {
unsafe { w.xfercount().bits(count as u16) }
.cfgvalid()
.set_bit()
.clrtrig()
.set_bit()
.reload()
.clear_bit()
.setinta()
.set_bit()
.width()
.variant(width)
.srcinc()
.variant(match incr_read {
false => Srcinc::NoIncrement,
true => Srcinc::WidthX1,
// REVISIT: what about WidthX2 and WidthX4?
})
.dstinc()
.variant(match incr_write {
false => Dstinc::NoIncrement,
true => Dstinc::WidthX1,
// REVISIT: what about WidthX2 and WidthX4?
})
});
p.enableset0().write(|w| unsafe { w.ena().bits(1 << ch.number()) });
p.channel(ch.number().into())
.xfercfg()
.modify(|_, w| w.swtrig().set_bit());
compiler_fence(Ordering::SeqCst);
Transfer::new(ch)
}
/// DMA transfer driver.
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Transfer<'a, C: Channel> {
channel: Peri<'a, C>,
}
impl<'a, C: Channel> Transfer<'a, C> {
pub(crate) fn new(channel: Peri<'a, C>) -> Self {
Self { channel }
}
pub(crate) fn abort(&mut self) -> usize {
let p = self.channel.regs();
p.abort0().write(|w| w.channel(self.channel.number()).set_bit());
while p.busy0().read().bsy().bits() & (1 << self.channel.number()) != 0 {}
p.enableclr0()
.write(|w| unsafe { w.clr().bits(1 << self.channel.number()) });
let width: u8 = p
.channel(self.channel.number().into())
.xfercfg()
.read()
.width()
.variant()
.unwrap()
.into();
let count = p
.channel(self.channel.number().into())
.xfercfg()
.read()
.xfercount()
.bits()
+ 1;
usize::from(count) * usize::from(width)
}
}
impl<'a, C: Channel> Drop for Transfer<'a, C> {
fn drop(&mut self) {
self.abort();
}
}
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
impl<'a, C: Channel> Future for Transfer<'a, C> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Re-register the waker on each call to poll() because any calls to
// wake will deregister the waker.
CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
if self.channel.regs().active0().read().act().bits() & (1 << self.channel.number()) == 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
/// DMA channel descriptor
#[derive(Copy, Clone)]
#[repr(C)]
struct Descriptor {
reserved: u32,
src: u32,
dest: u32,
link: u32,
}
impl Descriptor {
const fn new() -> Self {
Self {
reserved: 0,
src: 0,
dest: 0,
link: 0,
}
}
}
#[repr(align(1024))]
struct Descriptors {
descs: [Descriptor; CHANNEL_COUNT],
}
impl Descriptors {
const fn new() -> Self {
Self {
descs: [const { Descriptor::new() }; CHANNEL_COUNT],
}
}
}
static mut DESCRIPTORS: Descriptors = Descriptors::new();
static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
pub(crate) const CHANNEL_COUNT: usize = 33;
/// DMA channel interface.
#[allow(private_bounds)]
pub trait Channel: PeripheralType + Sealed + Into<AnyChannel> + Sized + 'static {
/// Channel number.
fn number(&self) -> u8;
/// Channel registry block.
fn regs(&self) -> &'static pac::dma0::RegisterBlock {
unsafe { &*crate::pac::Dma0::ptr() }
}
}
/// DMA word.
#[allow(private_bounds)]
pub trait Word: Sealed {
/// Transfer width.
fn width() -> Width;
/// Size in bytes for the width.
fn size() -> isize;
}
impl Sealed for u8 {}
impl Word for u8 {
fn width() -> Width {
Width::Bit8
}
fn size() -> isize {
1
}
}
impl Sealed for u16 {}
impl Word for u16 {
fn width() -> Width {
Width::Bit16
}
fn size() -> isize {
2
}
}
impl Sealed for u32 {}
impl Word for u32 {
fn width() -> Width {
Width::Bit32
}
fn size() -> isize {
4
}
}
/// Type erased DMA channel.
pub struct AnyChannel {
number: u8,
}
impl_peripheral!(AnyChannel);
impl Sealed for AnyChannel {}
impl Channel for AnyChannel {
fn number(&self) -> u8 {
self.number
}
}
macro_rules! channel {
($name:ident, $num:expr) => {
impl Sealed for peripherals::$name {}
impl Channel for peripherals::$name {
fn number(&self) -> u8 {
$num
}
}
impl From<peripherals::$name> for crate::dma::AnyChannel {
fn from(val: peripherals::$name) -> Self {
Self { number: val.number() }
}
}
};
}
channel!(DMA0_CH0, 0);
channel!(DMA0_CH1, 1);
channel!(DMA0_CH2, 2);
channel!(DMA0_CH3, 3);
channel!(DMA0_CH4, 4);
channel!(DMA0_CH5, 5);
channel!(DMA0_CH6, 6);
channel!(DMA0_CH7, 7);
channel!(DMA0_CH8, 8);
channel!(DMA0_CH9, 9);
channel!(DMA0_CH10, 10);
channel!(DMA0_CH11, 11);
channel!(DMA0_CH12, 12);
channel!(DMA0_CH13, 13);
channel!(DMA0_CH14, 14);
channel!(DMA0_CH15, 15);
channel!(DMA0_CH16, 16);
channel!(DMA0_CH17, 17);
channel!(DMA0_CH18, 18);
channel!(DMA0_CH19, 19);
channel!(DMA0_CH20, 20);
channel!(DMA0_CH21, 21);
channel!(DMA0_CH22, 22);
channel!(DMA0_CH23, 23);
channel!(DMA0_CH24, 24);
channel!(DMA0_CH25, 25);
channel!(DMA0_CH26, 26);
channel!(DMA0_CH27, 27);
channel!(DMA0_CH28, 28);
channel!(DMA0_CH29, 29);
channel!(DMA0_CH30, 30);
channel!(DMA0_CH31, 31);
channel!(DMA0_CH32, 32);

View File

@ -0,0 +1,252 @@
//! Implements Flexcomm interface wrapper for easier usage across modules
pub mod uart;
use paste::paste;
use crate::clocks::{enable_and_reset, SysconPeripheral};
use crate::peripherals::{
FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7,
};
use crate::{pac, PeripheralType};
/// clock selection option
#[derive(Copy, Clone, Debug)]
pub enum Clock {
/// SFRO
Sfro,
/// FFRO
Ffro,
/// `AUDIO_PLL`
AudioPll,
/// MASTER
Master,
/// FCn_FRG with Main clock source
FcnFrgMain,
/// FCn_FRG with Pll clock source
FcnFrgPll,
/// FCn_FRG with Sfro clock source
FcnFrgSfro,
/// FCn_FRG with Ffro clock source
FcnFrgFfro,
/// disabled
None,
}
/// do not allow implementation of trait outside this mod
mod sealed {
/// trait does not get re-exported outside flexcomm mod, allowing us to safely expose only desired APIs
pub trait Sealed {}
}
/// primary low-level flexcomm interface
pub(crate) trait FlexcommLowLevel: sealed::Sealed + PeripheralType + SysconPeripheral + 'static + Send {
// fetch the flexcomm register block for direct manipulation
fn reg() -> &'static pac::flexcomm0::RegisterBlock;
// set the clock select for this flexcomm instance and remove from reset
fn enable(clk: Clock);
}
macro_rules! impl_flexcomm {
($($idx:expr),*) => {
$(
paste!{
impl sealed::Sealed for crate::peripherals::[<FLEXCOMM $idx>] {}
impl FlexcommLowLevel for crate::peripherals::[<FLEXCOMM $idx>] {
fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
// SAFETY: safe from single executor, enforce
// via peripheral reference lifetime tracking
unsafe {
&*crate::pac::[<Flexcomm $idx>]::ptr()
}
}
fn enable(clk: Clock) {
// SAFETY: safe from single executor
let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
clkctl1.flexcomm($idx).fcfclksel().write(|w| match clk {
Clock::Sfro => w.sel().sfro_clk(),
Clock::Ffro => w.sel().ffro_clk(),
Clock::AudioPll => w.sel().audio_pll_clk(),
Clock::Master => w.sel().master_clk(),
Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
Clock::None => w.sel().none(), // no clock? throw an error?
});
clkctl1.flexcomm($idx).frgclksel().write(|w| match clk {
Clock::FcnFrgMain => w.sel().main_clk(),
Clock::FcnFrgPll => w.sel().frg_pll_clk(),
Clock::FcnFrgSfro => w.sel().sfro_clk(),
Clock::FcnFrgFfro => w.sel().ffro_clk(),
_ => w.sel().none(), // not using frg ...
});
// todo: add support for frg div/mult
clkctl1
.flexcomm($idx)
.frgctl()
.write(|w|
// SAFETY: unsafe only used for .bits() call
unsafe { w.mult().bits(0) });
enable_and_reset::<[<FLEXCOMM $idx>]>();
}
}
}
)*
}
}
impl_flexcomm!(0, 1, 2, 3, 4, 5, 6, 7);
// TODO: FLEXCOMM 14 is untested. Enable SPI support on FLEXCOMM14
// Add special case FLEXCOMM14
impl sealed::Sealed for crate::peripherals::FLEXCOMM14 {}
impl FlexcommLowLevel for crate::peripherals::FLEXCOMM14 {
fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
// SAFETY: safe from single executor, enforce
// via peripheral reference lifetime tracking
unsafe { &*crate::pac::Flexcomm14::ptr() }
}
fn enable(clk: Clock) {
// SAFETY: safe from single executor
let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
clkctl1.fc14fclksel().write(|w| match clk {
Clock::Sfro => w.sel().sfro_clk(),
Clock::Ffro => w.sel().ffro_clk(),
Clock::AudioPll => w.sel().audio_pll_clk(),
Clock::Master => w.sel().master_clk(),
Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
Clock::None => w.sel().none(), // no clock? throw an error?
});
clkctl1.frg14clksel().write(|w| match clk {
Clock::FcnFrgMain => w.sel().main_clk(),
Clock::FcnFrgPll => w.sel().frg_pll_clk(),
Clock::FcnFrgSfro => w.sel().sfro_clk(),
Clock::FcnFrgFfro => w.sel().ffro_clk(),
_ => w.sel().none(), // not using frg ...
});
// todo: add support for frg div/mult
clkctl1.frg14ctl().write(|w|
// SAFETY: unsafe only used for .bits() call
unsafe { w.mult().bits(0) });
enable_and_reset::<FLEXCOMM14>();
}
}
// Add special case FLEXCOMM15
impl sealed::Sealed for crate::peripherals::FLEXCOMM15 {}
impl FlexcommLowLevel for crate::peripherals::FLEXCOMM15 {
fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
// SAFETY: safe from single executor, enforce
// via peripheral reference lifetime tracking
unsafe { &*crate::pac::Flexcomm15::ptr() }
}
fn enable(clk: Clock) {
// SAFETY: safe from single executor
let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
clkctl1.fc15fclksel().write(|w| match clk {
Clock::Sfro => w.sel().sfro_clk(),
Clock::Ffro => w.sel().ffro_clk(),
Clock::AudioPll => w.sel().audio_pll_clk(),
Clock::Master => w.sel().master_clk(),
Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
Clock::None => w.sel().none(), // no clock? throw an error?
});
clkctl1.frg15clksel().write(|w| match clk {
Clock::FcnFrgMain => w.sel().main_clk(),
Clock::FcnFrgPll => w.sel().frg_pll_clk(),
Clock::FcnFrgSfro => w.sel().sfro_clk(),
Clock::FcnFrgFfro => w.sel().ffro_clk(),
_ => w.sel().none(), // not using frg ...
});
// todo: add support for frg div/mult
clkctl1.frg15ctl().write(|w|
// SAFETY: unsafe only used for .bits() call
unsafe { w.mult().bits(0) });
enable_and_reset::<FLEXCOMM15>();
}
}
macro_rules! into_mode {
($mode:ident, $($fc:ident),*) => {
paste! {
/// Sealed Mode trait
trait [<SealedInto $mode:camel>]: FlexcommLowLevel {}
/// Select mode of operation
#[allow(private_bounds)]
pub trait [<Into $mode:camel>]: [<SealedInto $mode:camel>] {
/// Set mode of operation
fn [<into_ $mode>]() {
Self::reg().pselid().write(|w| w.persel().[<$mode>]());
}
}
}
$(
paste!{
impl [<SealedInto $mode:camel>] for crate::peripherals::$fc {}
impl [<Into $mode:camel>] for crate::peripherals::$fc {}
}
)*
}
}
into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7);
into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14);
into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15);
into_mode!(
i2s_transmit,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7
);
into_mode!(
i2s_receive,
FLEXCOMM0,
FLEXCOMM1,
FLEXCOMM2,
FLEXCOMM3,
FLEXCOMM4,
FLEXCOMM5,
FLEXCOMM6,
FLEXCOMM7
);

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ use crate::clocks::enable_and_reset;
use crate::iopctl::IopctlPin;
pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate};
use crate::sealed::Sealed;
use crate::{interrupt, peripherals, Peri, PeripheralType};
use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType};
// This should be unique per IMXRT package
const PORT_COUNT: usize = 8;
@ -63,24 +63,6 @@ fn GPIO_INTA() {
irq_handler(&GPIO_WAKERS);
}
#[cfg(feature = "rt")]
struct BitIter(u32);
#[cfg(feature = "rt")]
impl Iterator for BitIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match self.0.trailing_zeros() {
32 => None,
b => {
self.0 &= !(1 << b);
Some(b)
}
}
}
}
#[cfg(feature = "rt")]
fn irq_handler(port_wakers: &[Option<&PortWaker>]) {
let reg = unsafe { crate::pac::Gpio::steal() };

View File

@ -19,6 +19,8 @@ pub(crate) mod fmt;
pub mod clocks;
pub mod crc;
pub mod dma;
pub mod flexcomm;
pub mod gpio;
pub mod iopctl;
pub mod rng;
@ -129,14 +131,16 @@ pub fn init(config: config::Config) -> Peripherals {
// before doing anything important.
let peripherals = Peripherals::take();
#[cfg(feature = "_time-driver")]
time_driver::init(config.time_interrupt_priority);
unsafe {
if let Err(e) = clocks::init(config.clocks) {
error!("unable to initialize Clocks for reason: {:?}", e);
// Panic here?
}
dma::init();
}
#[cfg(feature = "_time-driver")]
time_driver::init(config.time_interrupt_priority);
gpio::init();
peripherals
@ -145,3 +149,21 @@ pub fn init(config: config::Config) -> Peripherals {
pub(crate) mod sealed {
pub trait Sealed {}
}
#[cfg(feature = "rt")]
struct BitIter(u32);
#[cfg(feature = "rt")]
impl Iterator for BitIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match self.0.trailing_zeros() {
32 => None,
b => {
self.0 &= !(1 << b);
Some(b)
}
}
}
}

View File

@ -0,0 +1,87 @@
#![no_std]
#![no_main]
extern crate embassy_imxrt_examples;
use defmt::info;
use embassy_executor::Spawner;
use embassy_imxrt::flexcomm::uart::{self, Async, Uart};
use embassy_imxrt::{bind_interrupts, peripherals};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
FLEXCOMM2 => uart::InterruptHandler<peripherals::FLEXCOMM2>;
FLEXCOMM4 => uart::InterruptHandler<peripherals::FLEXCOMM4>;
});
const BUFLEN: usize = 16;
#[embassy_executor::task]
async fn usart4_task(mut uart: Uart<'static, Async>) {
info!("RX Task");
loop {
let mut rx_buf = [0; BUFLEN];
uart.read(&mut rx_buf).await.unwrap();
info!("usart4: rx_buf {:02x}", rx_buf);
Timer::after_millis(10).await;
let tx_buf = [0xaa; BUFLEN];
uart.write(&tx_buf).await.unwrap();
info!("usart4: tx_buf {:02x}", tx_buf);
}
}
#[embassy_executor::task]
async fn usart2_task(mut uart: Uart<'static, Async>) {
info!("TX Task");
loop {
let tx_buf = [0x55; BUFLEN];
uart.write(&tx_buf).await.unwrap();
info!("usart2: tx_buf {:02x}", tx_buf);
Timer::after_millis(10).await;
let mut rx_buf = [0x00; BUFLEN];
uart.read(&mut rx_buf).await.unwrap();
info!("usart2: rx_buf {:02x}", rx_buf);
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_imxrt::init(Default::default());
info!("UART test start");
let usart4 = Uart::new_with_rtscts(
p.FLEXCOMM4,
p.PIO0_29,
p.PIO0_30,
p.PIO1_0,
p.PIO0_31,
Irqs,
p.DMA0_CH9,
p.DMA0_CH8,
Default::default(),
)
.unwrap();
spawner.must_spawn(usart4_task(usart4));
let usart2 = Uart::new_with_rtscts(
p.FLEXCOMM2,
p.PIO0_15,
p.PIO0_16,
p.PIO0_18,
p.PIO0_17,
Irqs,
p.DMA0_CH5,
p.DMA0_CH4,
Default::default(),
)
.unwrap();
spawner.must_spawn(usart2_task(usart2));
}

View File

@ -0,0 +1,55 @@
#![no_std]
#![no_main]
extern crate embassy_imxrt_examples;
use defmt::info;
use embassy_executor::Spawner;
use embassy_imxrt::flexcomm::uart::{Blocking, Uart, UartRx, UartTx};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task]
async fn usart4_task(mut uart: UartRx<'static, Blocking>) {
info!("RX Task");
loop {
let mut buf = [0; 8];
Timer::after_millis(10).await;
uart.blocking_read(&mut buf).unwrap();
let s = core::str::from_utf8(&buf).unwrap();
info!("Received '{}'", s);
}
}
#[embassy_executor::task]
async fn usart2_task(mut uart: UartTx<'static, Blocking>) {
info!("TX Task");
loop {
let buf = "Testing\0".as_bytes();
uart.blocking_write(buf).unwrap();
Timer::after_millis(10).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_imxrt::init(Default::default());
info!("UART test start");
let usart4 = Uart::new_blocking(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Default::default()).unwrap();
let (_, usart4) = usart4.split();
spawner.must_spawn(usart4_task(usart4));
let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap();
spawner.must_spawn(usart2_task(usart2));
}