aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/pages/imxrt.adoc2
-rw-r--r--embassy-imxrt/src/dma.rs418
-rw-r--r--embassy-imxrt/src/flexcomm/mod.rs252
-rw-r--r--embassy-imxrt/src/flexcomm/uart.rs1230
-rw-r--r--embassy-imxrt/src/gpio.rs20
-rw-r--r--embassy-imxrt/src/lib.rs26
-rw-r--r--examples/mimxrt6/src/bin/uart-async.rs87
-rw-r--r--examples/mimxrt6/src/bin/uart.rs55
8 files changed, 2069 insertions, 21 deletions
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc
index bbd65e494..87867e1e0 100644
--- a/docs/pages/imxrt.adoc
+++ b/docs/pages/imxrt.adoc
@@ -10,5 +10,7 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb
10The following peripherals have a HAL implementation at present 10The following peripherals have a HAL implementation at present
11 11
12* CRC 12* CRC
13* DMA
13* GPIO 14* GPIO
14* RNG 15* RNG
16* UART
diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs
new file mode 100644
index 000000000..e141447f3
--- /dev/null
+++ b/embassy-imxrt/src/dma.rs
@@ -0,0 +1,418 @@
1//! DMA driver.
2
3use core::future::Future;
4use core::pin::Pin;
5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma0::channel::cfg::Periphreqen;
11use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width};
12
13use crate::clocks::enable_and_reset;
14use crate::interrupt::InterruptExt;
15use crate::peripherals::DMA0;
16use crate::sealed::Sealed;
17use crate::{interrupt, pac, peripherals, BitIter};
18
19#[cfg(feature = "rt")]
20#[interrupt]
21fn DMA0() {
22 let reg = unsafe { crate::pac::Dma0::steal() };
23
24 if reg.intstat().read().activeerrint().bit() {
25 let err = reg.errint0().read().bits();
26
27 for channel in BitIter(err) {
28 error!("DMA error interrupt on channel {}!", channel);
29 reg.errint0().write(|w| unsafe { w.err().bits(1 << channel) });
30 CHANNEL_WAKERS[channel as usize].wake();
31 }
32 }
33
34 if reg.intstat().read().activeint().bit() {
35 let ia = reg.inta0().read().bits();
36
37 for channel in BitIter(ia) {
38 reg.inta0().write(|w| unsafe { w.ia().bits(1 << channel) });
39 CHANNEL_WAKERS[channel as usize].wake();
40 }
41 }
42}
43
44/// Initialize DMA controllers (DMA0 only, for now)
45pub(crate) unsafe fn init() {
46 let sysctl0 = crate::pac::Sysctl0::steal();
47 let dmactl0 = crate::pac::Dma0::steal();
48
49 enable_and_reset::<DMA0>();
50
51 interrupt::DMA0.disable();
52 interrupt::DMA0.set_priority(interrupt::Priority::P3);
53
54 dmactl0.ctrl().modify(|_, w| w.enable().set_bit());
55
56 // Set channel descriptor SRAM base address
57 // Descriptor base must be 1K aligned
58 let descriptor_base = core::ptr::addr_of!(DESCRIPTORS.descs) as u32;
59 dmactl0.srambase().write(|w| w.bits(descriptor_base));
60
61 // Ensure AHB priority it highest (M4 == DMAC0)
62 sysctl0.ahbmatrixprior().modify(|_, w| w.m4().bits(0));
63
64 interrupt::DMA0.unpend();
65 interrupt::DMA0.enable();
66}
67
68/// DMA read.
69///
70/// SAFETY: Slice must point to a valid location reachable by DMA.
71pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
72 let count = ((to.len() / W::size() as usize) - 1) as isize;
73
74 copy_inner(
75 ch,
76 from as *const u32,
77 (to as *mut u32).byte_offset(count * W::size()),
78 W::width(),
79 count,
80 false,
81 true,
82 true,
83 )
84}
85
86/// DMA write.
87///
88/// SAFETY: Slice must point to a valid location reachable by DMA.
89pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
90 let count = ((from.len() / W::size() as usize) - 1) as isize;
91
92 copy_inner(
93 ch,
94 (from as *const u32).byte_offset(count * W::size()),
95 to as *mut u32,
96 W::width(),
97 count,
98 true,
99 false,
100 true,
101 )
102}
103
104/// DMA copy between slices.
105///
106/// SAFETY: Slices must point to locations reachable by DMA.
107pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
108 let from_len = from.len();
109 let to_len = to.len();
110 assert_eq!(from_len, to_len);
111
112 let count = ((from_len / W::size() as usize) - 1) as isize;
113
114 copy_inner(
115 ch,
116 from.as_ptr().byte_offset(count * W::size()) as *const u32,
117 to.as_mut_ptr().byte_offset(count * W::size()) as *mut u32,
118 W::width(),
119 count,
120 true,
121 true,
122 false,
123 )
124}
125
126fn copy_inner<'a, C: Channel>(
127 ch: Peri<'a, C>,
128 from: *const u32,
129 to: *mut u32,
130 width: Width,
131 count: isize,
132 incr_read: bool,
133 incr_write: bool,
134 periph: bool,
135) -> Transfer<'a, C> {
136 let p = ch.regs();
137
138 unsafe {
139 DESCRIPTORS.descs[ch.number() as usize].src = from as u32;
140 DESCRIPTORS.descs[ch.number() as usize].dest = to as u32;
141 }
142
143 compiler_fence(Ordering::SeqCst);
144
145 p.errint0().write(|w| unsafe { w.err().bits(1 << ch.number()) });
146 p.inta0().write(|w| unsafe { w.ia().bits(1 << ch.number()) });
147
148 p.channel(ch.number().into()).cfg().write(|w| {
149 unsafe { w.chpriority().bits(0) }
150 .periphreqen()
151 .variant(match periph {
152 false => Periphreqen::Disabled,
153 true => Periphreqen::Enabled,
154 })
155 .hwtrigen()
156 .clear_bit()
157 });
158
159 p.intenset0().write(|w| unsafe { w.inten().bits(1 << ch.number()) });
160
161 p.channel(ch.number().into()).xfercfg().write(|w| {
162 unsafe { w.xfercount().bits(count as u16) }
163 .cfgvalid()
164 .set_bit()
165 .clrtrig()
166 .set_bit()
167 .reload()
168 .clear_bit()
169 .setinta()
170 .set_bit()
171 .width()
172 .variant(width)
173 .srcinc()
174 .variant(match incr_read {
175 false => Srcinc::NoIncrement,
176 true => Srcinc::WidthX1,
177 // REVISIT: what about WidthX2 and WidthX4?
178 })
179 .dstinc()
180 .variant(match incr_write {
181 false => Dstinc::NoIncrement,
182 true => Dstinc::WidthX1,
183 // REVISIT: what about WidthX2 and WidthX4?
184 })
185 });
186
187 p.enableset0().write(|w| unsafe { w.ena().bits(1 << ch.number()) });
188
189 p.channel(ch.number().into())
190 .xfercfg()
191 .modify(|_, w| w.swtrig().set_bit());
192
193 compiler_fence(Ordering::SeqCst);
194
195 Transfer::new(ch)
196}
197
198/// DMA transfer driver.
199#[must_use = "futures do nothing unless you `.await` or poll them"]
200pub struct Transfer<'a, C: Channel> {
201 channel: Peri<'a, C>,
202}
203
204impl<'a, C: Channel> Transfer<'a, C> {
205 pub(crate) fn new(channel: Peri<'a, C>) -> Self {
206 Self { channel }
207 }
208
209 pub(crate) fn abort(&mut self) -> usize {
210 let p = self.channel.regs();
211
212 p.abort0().write(|w| w.channel(self.channel.number()).set_bit());
213 while p.busy0().read().bsy().bits() & (1 << self.channel.number()) != 0 {}
214
215 p.enableclr0()
216 .write(|w| unsafe { w.clr().bits(1 << self.channel.number()) });
217
218 let width: u8 = p
219 .channel(self.channel.number().into())
220 .xfercfg()
221 .read()
222 .width()
223 .variant()
224 .unwrap()
225 .into();
226
227 let count = p
228 .channel(self.channel.number().into())
229 .xfercfg()
230 .read()
231 .xfercount()
232 .bits()
233 + 1;
234
235 usize::from(count) * usize::from(width)
236 }
237}
238
239impl<'a, C: Channel> Drop for Transfer<'a, C> {
240 fn drop(&mut self) {
241 self.abort();
242 }
243}
244
245impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
246impl<'a, C: Channel> Future for Transfer<'a, C> {
247 type Output = ();
248
249 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
250 // Re-register the waker on each call to poll() because any calls to
251 // wake will deregister the waker.
252 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
253
254 if self.channel.regs().active0().read().act().bits() & (1 << self.channel.number()) == 0 {
255 Poll::Ready(())
256 } else {
257 Poll::Pending
258 }
259 }
260}
261
262/// DMA channel descriptor
263#[derive(Copy, Clone)]
264#[repr(C)]
265struct Descriptor {
266 reserved: u32,
267 src: u32,
268 dest: u32,
269 link: u32,
270}
271
272impl Descriptor {
273 const fn new() -> Self {
274 Self {
275 reserved: 0,
276 src: 0,
277 dest: 0,
278 link: 0,
279 }
280 }
281}
282
283#[repr(align(1024))]
284struct Descriptors {
285 descs: [Descriptor; CHANNEL_COUNT],
286}
287
288impl Descriptors {
289 const fn new() -> Self {
290 Self {
291 descs: [const { Descriptor::new() }; CHANNEL_COUNT],
292 }
293 }
294}
295
296static mut DESCRIPTORS: Descriptors = Descriptors::new();
297static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
298pub(crate) const CHANNEL_COUNT: usize = 33;
299
300/// DMA channel interface.
301#[allow(private_bounds)]
302pub trait Channel: PeripheralType + Sealed + Into<AnyChannel> + Sized + 'static {
303 /// Channel number.
304 fn number(&self) -> u8;
305
306 /// Channel registry block.
307 fn regs(&self) -> &'static pac::dma0::RegisterBlock {
308 unsafe { &*crate::pac::Dma0::ptr() }
309 }
310}
311
312/// DMA word.
313#[allow(private_bounds)]
314pub trait Word: Sealed {
315 /// Transfer width.
316 fn width() -> Width;
317
318 /// Size in bytes for the width.
319 fn size() -> isize;
320}
321
322impl Sealed for u8 {}
323impl Word for u8 {
324 fn width() -> Width {
325 Width::Bit8
326 }
327
328 fn size() -> isize {
329 1
330 }
331}
332
333impl Sealed for u16 {}
334impl Word for u16 {
335 fn width() -> Width {
336 Width::Bit16
337 }
338
339 fn size() -> isize {
340 2
341 }
342}
343
344impl Sealed for u32 {}
345impl Word for u32 {
346 fn width() -> Width {
347 Width::Bit32
348 }
349
350 fn size() -> isize {
351 4
352 }
353}
354
355/// Type erased DMA channel.
356pub struct AnyChannel {
357 number: u8,
358}
359
360impl_peripheral!(AnyChannel);
361
362impl Sealed for AnyChannel {}
363impl Channel for AnyChannel {
364 fn number(&self) -> u8 {
365 self.number
366 }
367}
368
369macro_rules! channel {
370 ($name:ident, $num:expr) => {
371 impl Sealed for peripherals::$name {}
372 impl Channel for peripherals::$name {
373 fn number(&self) -> u8 {
374 $num
375 }
376 }
377
378 impl From<peripherals::$name> for crate::dma::AnyChannel {
379 fn from(val: peripherals::$name) -> Self {
380 Self { number: val.number() }
381 }
382 }
383 };
384}
385
386channel!(DMA0_CH0, 0);
387channel!(DMA0_CH1, 1);
388channel!(DMA0_CH2, 2);
389channel!(DMA0_CH3, 3);
390channel!(DMA0_CH4, 4);
391channel!(DMA0_CH5, 5);
392channel!(DMA0_CH6, 6);
393channel!(DMA0_CH7, 7);
394channel!(DMA0_CH8, 8);
395channel!(DMA0_CH9, 9);
396channel!(DMA0_CH10, 10);
397channel!(DMA0_CH11, 11);
398channel!(DMA0_CH12, 12);
399channel!(DMA0_CH13, 13);
400channel!(DMA0_CH14, 14);
401channel!(DMA0_CH15, 15);
402channel!(DMA0_CH16, 16);
403channel!(DMA0_CH17, 17);
404channel!(DMA0_CH18, 18);
405channel!(DMA0_CH19, 19);
406channel!(DMA0_CH20, 20);
407channel!(DMA0_CH21, 21);
408channel!(DMA0_CH22, 22);
409channel!(DMA0_CH23, 23);
410channel!(DMA0_CH24, 24);
411channel!(DMA0_CH25, 25);
412channel!(DMA0_CH26, 26);
413channel!(DMA0_CH27, 27);
414channel!(DMA0_CH28, 28);
415channel!(DMA0_CH29, 29);
416channel!(DMA0_CH30, 30);
417channel!(DMA0_CH31, 31);
418channel!(DMA0_CH32, 32);
diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs
new file mode 100644
index 000000000..4473c9a77
--- /dev/null
+++ b/embassy-imxrt/src/flexcomm/mod.rs
@@ -0,0 +1,252 @@
1//! Implements Flexcomm interface wrapper for easier usage across modules
2
3pub mod uart;
4
5use paste::paste;
6
7use crate::clocks::{enable_and_reset, SysconPeripheral};
8use crate::peripherals::{
9 FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7,
10};
11use crate::{pac, PeripheralType};
12
13/// clock selection option
14#[derive(Copy, Clone, Debug)]
15pub enum Clock {
16 /// SFRO
17 Sfro,
18
19 /// FFRO
20 Ffro,
21
22 /// `AUDIO_PLL`
23 AudioPll,
24
25 /// MASTER
26 Master,
27
28 /// FCn_FRG with Main clock source
29 FcnFrgMain,
30
31 /// FCn_FRG with Pll clock source
32 FcnFrgPll,
33
34 /// FCn_FRG with Sfro clock source
35 FcnFrgSfro,
36
37 /// FCn_FRG with Ffro clock source
38 FcnFrgFfro,
39
40 /// disabled
41 None,
42}
43
44/// do not allow implementation of trait outside this mod
45mod sealed {
46 /// trait does not get re-exported outside flexcomm mod, allowing us to safely expose only desired APIs
47 pub trait Sealed {}
48}
49
50/// primary low-level flexcomm interface
51pub(crate) trait FlexcommLowLevel: sealed::Sealed + PeripheralType + SysconPeripheral + 'static + Send {
52 // fetch the flexcomm register block for direct manipulation
53 fn reg() -> &'static pac::flexcomm0::RegisterBlock;
54
55 // set the clock select for this flexcomm instance and remove from reset
56 fn enable(clk: Clock);
57}
58
59macro_rules! impl_flexcomm {
60 ($($idx:expr),*) => {
61 $(
62 paste!{
63 impl sealed::Sealed for crate::peripherals::[<FLEXCOMM $idx>] {}
64
65 impl FlexcommLowLevel for crate::peripherals::[<FLEXCOMM $idx>] {
66 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
67 // SAFETY: safe from single executor, enforce
68 // via peripheral reference lifetime tracking
69 unsafe {
70 &*crate::pac::[<Flexcomm $idx>]::ptr()
71 }
72 }
73
74 fn enable(clk: Clock) {
75 // SAFETY: safe from single executor
76 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
77
78 clkctl1.flexcomm($idx).fcfclksel().write(|w| match clk {
79 Clock::Sfro => w.sel().sfro_clk(),
80 Clock::Ffro => w.sel().ffro_clk(),
81 Clock::AudioPll => w.sel().audio_pll_clk(),
82 Clock::Master => w.sel().master_clk(),
83 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
84 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
85 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
86 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
87 Clock::None => w.sel().none(), // no clock? throw an error?
88 });
89
90 clkctl1.flexcomm($idx).frgclksel().write(|w| match clk {
91 Clock::FcnFrgMain => w.sel().main_clk(),
92 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
93 Clock::FcnFrgSfro => w.sel().sfro_clk(),
94 Clock::FcnFrgFfro => w.sel().ffro_clk(),
95 _ => w.sel().none(), // not using frg ...
96 });
97
98 // todo: add support for frg div/mult
99 clkctl1
100 .flexcomm($idx)
101 .frgctl()
102 .write(|w|
103 // SAFETY: unsafe only used for .bits() call
104 unsafe { w.mult().bits(0) });
105
106 enable_and_reset::<[<FLEXCOMM $idx>]>();
107 }
108 }
109 }
110 )*
111 }
112}
113
114impl_flexcomm!(0, 1, 2, 3, 4, 5, 6, 7);
115
116// TODO: FLEXCOMM 14 is untested. Enable SPI support on FLEXCOMM14
117// Add special case FLEXCOMM14
118impl sealed::Sealed for crate::peripherals::FLEXCOMM14 {}
119
120impl FlexcommLowLevel for crate::peripherals::FLEXCOMM14 {
121 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
122 // SAFETY: safe from single executor, enforce
123 // via peripheral reference lifetime tracking
124 unsafe { &*crate::pac::Flexcomm14::ptr() }
125 }
126
127 fn enable(clk: Clock) {
128 // SAFETY: safe from single executor
129 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
130
131 clkctl1.fc14fclksel().write(|w| match clk {
132 Clock::Sfro => w.sel().sfro_clk(),
133 Clock::Ffro => w.sel().ffro_clk(),
134 Clock::AudioPll => w.sel().audio_pll_clk(),
135 Clock::Master => w.sel().master_clk(),
136 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
137 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
138 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
139 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
140 Clock::None => w.sel().none(), // no clock? throw an error?
141 });
142
143 clkctl1.frg14clksel().write(|w| match clk {
144 Clock::FcnFrgMain => w.sel().main_clk(),
145 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
146 Clock::FcnFrgSfro => w.sel().sfro_clk(),
147 Clock::FcnFrgFfro => w.sel().ffro_clk(),
148 _ => w.sel().none(), // not using frg ...
149 });
150
151 // todo: add support for frg div/mult
152 clkctl1.frg14ctl().write(|w|
153 // SAFETY: unsafe only used for .bits() call
154 unsafe { w.mult().bits(0) });
155
156 enable_and_reset::<FLEXCOMM14>();
157 }
158}
159
160// Add special case FLEXCOMM15
161impl sealed::Sealed for crate::peripherals::FLEXCOMM15 {}
162
163impl FlexcommLowLevel for crate::peripherals::FLEXCOMM15 {
164 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
165 // SAFETY: safe from single executor, enforce
166 // via peripheral reference lifetime tracking
167 unsafe { &*crate::pac::Flexcomm15::ptr() }
168 }
169
170 fn enable(clk: Clock) {
171 // SAFETY: safe from single executor
172 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
173
174 clkctl1.fc15fclksel().write(|w| match clk {
175 Clock::Sfro => w.sel().sfro_clk(),
176 Clock::Ffro => w.sel().ffro_clk(),
177 Clock::AudioPll => w.sel().audio_pll_clk(),
178 Clock::Master => w.sel().master_clk(),
179 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
180 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
181 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
182 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
183 Clock::None => w.sel().none(), // no clock? throw an error?
184 });
185 clkctl1.frg15clksel().write(|w| match clk {
186 Clock::FcnFrgMain => w.sel().main_clk(),
187 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
188 Clock::FcnFrgSfro => w.sel().sfro_clk(),
189 Clock::FcnFrgFfro => w.sel().ffro_clk(),
190 _ => w.sel().none(), // not using frg ...
191 });
192 // todo: add support for frg div/mult
193 clkctl1.frg15ctl().write(|w|
194 // SAFETY: unsafe only used for .bits() call
195 unsafe { w.mult().bits(0) });
196
197 enable_and_reset::<FLEXCOMM15>();
198 }
199}
200
201macro_rules! into_mode {
202 ($mode:ident, $($fc:ident),*) => {
203 paste! {
204 /// Sealed Mode trait
205 trait [<SealedInto $mode:camel>]: FlexcommLowLevel {}
206
207 /// Select mode of operation
208 #[allow(private_bounds)]
209 pub trait [<Into $mode:camel>]: [<SealedInto $mode:camel>] {
210 /// Set mode of operation
211 fn [<into_ $mode>]() {
212 Self::reg().pselid().write(|w| w.persel().[<$mode>]());
213 }
214 }
215 }
216
217 $(
218 paste!{
219 impl [<SealedInto $mode:camel>] for crate::peripherals::$fc {}
220 impl [<Into $mode:camel>] for crate::peripherals::$fc {}
221 }
222 )*
223 }
224}
225
226into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7);
227into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14);
228into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15);
229
230into_mode!(
231 i2s_transmit,
232 FLEXCOMM0,
233 FLEXCOMM1,
234 FLEXCOMM2,
235 FLEXCOMM3,
236 FLEXCOMM4,
237 FLEXCOMM5,
238 FLEXCOMM6,
239 FLEXCOMM7
240);
241
242into_mode!(
243 i2s_receive,
244 FLEXCOMM0,
245 FLEXCOMM1,
246 FLEXCOMM2,
247 FLEXCOMM3,
248 FLEXCOMM4,
249 FLEXCOMM5,
250 FLEXCOMM6,
251 FLEXCOMM7
252);
diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs
new file mode 100644
index 000000000..230b30d43
--- /dev/null
+++ b/embassy-imxrt/src/flexcomm/uart.rs
@@ -0,0 +1,1230 @@
1//! Universal Asynchronous Receiver Transmitter (UART) driver.
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, AtomicU8, Ordering};
6use core::task::Poll;
7
8use embassy_futures::select::{select, Either};
9use embassy_hal_internal::drop::OnDrop;
10use embassy_hal_internal::{Peri, PeripheralType};
11use embassy_sync::waitqueue::AtomicWaker;
12use paste::paste;
13
14use crate::dma::AnyChannel;
15use crate::flexcomm::Clock;
16use crate::gpio::{AnyPin, GpioPin as Pin};
17use crate::interrupt::typelevel::Interrupt;
18use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate};
19use crate::pac::usart0::cfg::{Clkpol, Datalen, Loop, Paritysel as Parity, Stoplen, Syncen, Syncmst};
20use crate::pac::usart0::ctl::Cc;
21use crate::sealed::Sealed;
22use crate::{dma, interrupt};
23
24/// Driver move trait.
25#[allow(private_bounds)]
26pub trait Mode: Sealed {}
27
28/// Blocking mode.
29pub struct Blocking;
30impl Sealed for Blocking {}
31impl Mode for Blocking {}
32
33/// Async mode.
34pub struct Async;
35impl Sealed for Async {}
36impl Mode for Async {}
37
38/// Uart driver.
39pub struct Uart<'a, M: Mode> {
40 tx: UartTx<'a, M>,
41 rx: UartRx<'a, M>,
42}
43
44/// Uart TX driver.
45pub struct UartTx<'a, M: Mode> {
46 info: Info,
47 tx_dma: Option<Peri<'a, AnyChannel>>,
48 _phantom: PhantomData<(&'a (), M)>,
49}
50
51/// Uart RX driver.
52pub struct UartRx<'a, M: Mode> {
53 info: Info,
54 rx_dma: Option<Peri<'a, AnyChannel>>,
55 _phantom: PhantomData<(&'a (), M)>,
56}
57
58/// UART config
59#[derive(Clone, Copy)]
60pub struct Config {
61 /// Baudrate of the Uart
62 pub baudrate: u32,
63 /// data length
64 pub data_bits: Datalen,
65 /// Parity
66 pub parity: Parity,
67 /// Stop bits
68 pub stop_bits: Stoplen,
69 /// Polarity of the clock
70 pub clock_polarity: Clkpol,
71 /// Sync/ Async operation selection
72 pub operation: Syncen,
73 /// Sync master/slave mode selection (only applicable in sync mode)
74 pub sync_mode_master_select: Syncmst,
75 /// USART continuous Clock generation enable in synchronous master mode.
76 pub continuous_clock: Cc,
77 /// Normal/ loopback mode
78 pub loopback_mode: Loop,
79 /// Clock type
80 pub clock: Clock,
81}
82
83impl Default for Config {
84 /// Default configuration for single channel sampling.
85 fn default() -> Self {
86 Self {
87 baudrate: 115_200,
88 data_bits: Datalen::Bit8,
89 parity: Parity::NoParity,
90 stop_bits: Stoplen::Bit1,
91 clock_polarity: Clkpol::FallingEdge,
92 operation: Syncen::AsynchronousMode,
93 sync_mode_master_select: Syncmst::Slave,
94 continuous_clock: Cc::ClockOnCharacter,
95 loopback_mode: Loop::Normal,
96 clock: crate::flexcomm::Clock::Sfro,
97 }
98 }
99}
100
101/// Uart Errors
102#[derive(Debug, Copy, Clone, Eq, PartialEq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104pub enum Error {
105 /// Read error
106 Read,
107
108 /// Buffer overflow
109 Overrun,
110
111 /// Noise error
112 Noise,
113
114 /// Framing error
115 Framing,
116
117 /// Parity error
118 Parity,
119
120 /// Failure
121 Fail,
122
123 /// Invalid argument
124 InvalidArgument,
125
126 /// Uart baud rate cannot be supported with the given clock
127 UnsupportedBaudrate,
128
129 /// RX FIFO Empty
130 RxFifoEmpty,
131
132 /// TX FIFO Full
133 TxFifoFull,
134
135 /// TX Busy
136 TxBusy,
137}
138/// shorthand for -> `Result<T>`
139pub type Result<T> = core::result::Result<T, Error>;
140
141impl<'a, M: Mode> UartTx<'a, M> {
142 fn new_inner<T: Instance>(tx_dma: Option<Peri<'a, AnyChannel>>) -> Self {
143 let uarttx = Self {
144 info: T::info(),
145 tx_dma,
146 _phantom: PhantomData,
147 };
148 uarttx.info.refcnt.fetch_add(1, Ordering::Relaxed);
149 uarttx
150 }
151}
152
153impl<'a, M: Mode> Drop for UartTx<'a, M> {
154 fn drop(&mut self) {
155 if self.info.refcnt.fetch_sub(1, Ordering::Relaxed) == 1 {
156 while self.info.regs.stat().read().txidle().bit_is_clear() {}
157
158 self.info.regs.fifointenclr().modify(|_, w| {
159 w.txerr()
160 .set_bit()
161 .rxerr()
162 .set_bit()
163 .txlvl()
164 .set_bit()
165 .rxlvl()
166 .set_bit()
167 });
168
169 self.info
170 .regs
171 .fifocfg()
172 .modify(|_, w| w.dmatx().clear_bit().dmarx().clear_bit());
173
174 self.info.regs.cfg().modify(|_, w| w.enable().disabled());
175 }
176 }
177}
178
179impl<'a> UartTx<'a, Blocking> {
180 /// Create a new UART which can only send data
181 /// Unidirectional Uart - Tx only
182 pub fn new_blocking<T: Instance>(_inner: Peri<'a, T>, tx: Peri<'a, impl TxPin<T>>, config: Config) -> Result<Self> {
183 tx.as_tx();
184
185 let _tx = tx.into();
186 Uart::<Blocking>::init::<T>(Some(_tx), None, None, None, config)?;
187
188 Ok(Self::new_inner::<T>(None))
189 }
190
191 fn write_byte_internal(&mut self, byte: u8) -> Result<()> {
192 // SAFETY: unsafe only used for .bits()
193 self.info
194 .regs
195 .fifowr()
196 .write(|w| unsafe { w.txdata().bits(u16::from(byte)) });
197
198 Ok(())
199 }
200
201 fn blocking_write_byte(&mut self, byte: u8) -> Result<()> {
202 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
203
204 // Prevent the compiler from reordering write_byte_internal()
205 // before the loop above.
206 compiler_fence(Ordering::Release);
207
208 self.write_byte_internal(byte)
209 }
210
211 fn write_byte(&mut self, byte: u8) -> Result<()> {
212 if self.info.regs.fifostat().read().txnotfull().bit_is_clear() {
213 Err(Error::TxFifoFull)
214 } else {
215 self.write_byte_internal(byte)
216 }
217 }
218
219 /// Transmit the provided buffer blocking execution until done.
220 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> {
221 for x in buf {
222 self.blocking_write_byte(*x)?;
223 }
224
225 Ok(())
226 }
227
228 /// Transmit the provided buffer. Non-blocking version, bails out
229 /// if it would block.
230 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
231 for x in buf {
232 self.write_byte(*x)?;
233 }
234
235 Ok(())
236 }
237
238 /// Flush UART TX blocking execution until done.
239 pub fn blocking_flush(&mut self) -> Result<()> {
240 while self.info.regs.stat().read().txidle().bit_is_clear() {}
241 Ok(())
242 }
243
244 /// Flush UART TX.
245 pub fn flush(&mut self) -> Result<()> {
246 if self.info.regs.stat().read().txidle().bit_is_clear() {
247 Err(Error::TxBusy)
248 } else {
249 Ok(())
250 }
251 }
252}
253
254impl<'a, M: Mode> UartRx<'a, M> {
255 fn new_inner<T: Instance>(rx_dma: Option<Peri<'a, AnyChannel>>) -> Self {
256 let uartrx = Self {
257 info: T::info(),
258 rx_dma,
259 _phantom: PhantomData,
260 };
261 uartrx.info.refcnt.fetch_add(1, Ordering::Relaxed);
262 uartrx
263 }
264}
265
266impl<'a, M: Mode> Drop for UartRx<'a, M> {
267 fn drop(&mut self) {
268 if self.info.refcnt.fetch_sub(1, Ordering::Relaxed) == 1 {
269 while self.info.regs.stat().read().rxidle().bit_is_clear() {}
270
271 self.info.regs.fifointenclr().modify(|_, w| {
272 w.txerr()
273 .set_bit()
274 .rxerr()
275 .set_bit()
276 .txlvl()
277 .set_bit()
278 .rxlvl()
279 .set_bit()
280 });
281
282 self.info
283 .regs
284 .fifocfg()
285 .modify(|_, w| w.dmatx().clear_bit().dmarx().clear_bit());
286
287 self.info.regs.cfg().modify(|_, w| w.enable().disabled());
288 }
289 }
290}
291
292impl<'a> UartRx<'a, Blocking> {
293 /// Create a new blocking UART which can only receive data
294 pub fn new_blocking<T: Instance>(_inner: Peri<'a, T>, rx: Peri<'a, impl RxPin<T>>, config: Config) -> Result<Self> {
295 rx.as_rx();
296
297 let _rx = rx.into();
298 Uart::<Blocking>::init::<T>(None, Some(_rx), None, None, config)?;
299
300 Ok(Self::new_inner::<T>(None))
301 }
302}
303
304impl UartRx<'_, Blocking> {
305 fn read_byte_internal(&mut self) -> Result<u8> {
306 if self.info.regs.fifostat().read().rxerr().bit_is_set() {
307 self.info.regs.fifocfg().modify(|_, w| w.emptyrx().set_bit());
308 self.info.regs.fifostat().modify(|_, w| w.rxerr().set_bit());
309 Err(Error::Read)
310 } else if self.info.regs.stat().read().parityerrint().bit_is_set() {
311 self.info.regs.stat().modify(|_, w| w.parityerrint().clear_bit_by_one());
312 Err(Error::Parity)
313 } else if self.info.regs.stat().read().framerrint().bit_is_set() {
314 self.info.regs.stat().modify(|_, w| w.framerrint().clear_bit_by_one());
315 Err(Error::Framing)
316 } else if self.info.regs.stat().read().rxnoiseint().bit_is_set() {
317 self.info.regs.stat().modify(|_, w| w.rxnoiseint().clear_bit_by_one());
318 Err(Error::Noise)
319 } else {
320 let byte = self.info.regs.fiford().read().rxdata().bits() as u8;
321 Ok(byte)
322 }
323 }
324
325 fn read_byte(&mut self) -> Result<u8> {
326 if self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {
327 Err(Error::RxFifoEmpty)
328 } else {
329 self.read_byte_internal()
330 }
331 }
332
333 fn blocking_read_byte(&mut self) -> Result<u8> {
334 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
335
336 // Prevent the compiler from reordering read_byte_internal()
337 // before the loop above.
338 compiler_fence(Ordering::Acquire);
339
340 self.read_byte_internal()
341 }
342
343 /// Read from UART RX. Non-blocking version, bails out if it would
344 /// block.
345 pub fn read(&mut self, buf: &mut [u8]) -> Result<()> {
346 for b in buf.iter_mut() {
347 *b = self.read_byte()?;
348 }
349
350 Ok(())
351 }
352
353 /// Read from UART RX blocking execution until done.
354 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> {
355 for b in buf.iter_mut() {
356 *b = self.blocking_read_byte()?;
357 }
358
359 Ok(())
360 }
361}
362
363impl<'a, M: Mode> Uart<'a, M> {
364 fn init<T: Instance>(
365 tx: Option<Peri<'a, AnyPin>>,
366 rx: Option<Peri<'a, AnyPin>>,
367 rts: Option<Peri<'a, AnyPin>>,
368 cts: Option<Peri<'a, AnyPin>>,
369 config: Config,
370 ) -> Result<()> {
371 T::enable(config.clock);
372 T::into_usart();
373
374 let regs = T::info().regs;
375
376 if tx.is_some() {
377 regs.fifocfg().modify(|_, w| w.emptytx().set_bit().enabletx().enabled());
378
379 // clear FIFO error
380 regs.fifostat().write(|w| w.txerr().set_bit());
381 }
382
383 if rx.is_some() {
384 regs.fifocfg().modify(|_, w| w.emptyrx().set_bit().enablerx().enabled());
385
386 // clear FIFO error
387 regs.fifostat().write(|w| w.rxerr().set_bit());
388 }
389
390 if rts.is_some() && cts.is_some() {
391 regs.cfg().modify(|_, w| w.ctsen().enabled());
392 }
393
394 Self::set_baudrate_inner::<T>(config.baudrate, config.clock)?;
395 Self::set_uart_config::<T>(config);
396
397 Ok(())
398 }
399
400 fn get_fc_freq(clock: Clock) -> Result<u32> {
401 match clock {
402 Clock::Sfro => Ok(16_000_000),
403 Clock::Ffro => Ok(48_000_000),
404 // We only support Sfro and Ffro now.
405 _ => Err(Error::InvalidArgument),
406 }
407 }
408
409 fn set_baudrate_inner<T: Instance>(baudrate: u32, clock: Clock) -> Result<()> {
410 // Get source clock frequency according to clock type.
411 let source_clock_hz = Self::get_fc_freq(clock)?;
412
413 if baudrate == 0 {
414 return Err(Error::InvalidArgument);
415 }
416
417 let regs = T::info().regs;
418
419 // If synchronous master mode is enabled, only configure the BRG value.
420 if regs.cfg().read().syncen().is_synchronous_mode() {
421 // Master
422 if regs.cfg().read().syncmst().is_master() {
423 // Calculate the BRG value
424 let brgval = (source_clock_hz / baudrate) - 1;
425
426 // SAFETY: unsafe only used for .bits()
427 regs.brg().write(|w| unsafe { w.brgval().bits(brgval as u16) });
428 }
429 } else {
430 // Smaller values of OSR can make the sampling position within a
431 // data bit less accurate and may potentially cause more noise
432 // errors or incorrect data.
433 let (_, osr, brg) = (8..16).rev().fold(
434 (u32::MAX, u32::MAX, u32::MAX),
435 |(best_diff, best_osr, best_brg), osrval| {
436 // Compare source_clock_hz agaist with ((osrval + 1) * baudrate) to make sure
437 // (source_clock_hz / ((osrval + 1) * baudrate)) is not less than 0.
438 if source_clock_hz < ((osrval + 1) * baudrate) {
439 (best_diff, best_osr, best_brg)
440 } else {
441 let brgval = (source_clock_hz / ((osrval + 1) * baudrate)) - 1;
442 // We know brgval will not be less than 0 now, it should have already been a valid u32 value,
443 // then compare it agaist with 65535.
444 if brgval > 65535 {
445 (best_diff, best_osr, best_brg)
446 } else {
447 // Calculate the baud rate based on the BRG value
448 let candidate = source_clock_hz / ((osrval + 1) * (brgval + 1));
449
450 // Calculate the difference between the
451 // current baud rate and the desired baud rate
452 let diff = (candidate as i32 - baudrate as i32).unsigned_abs();
453
454 // Check if the current calculated difference is the best so far
455 if diff < best_diff {
456 (diff, osrval, brgval)
457 } else {
458 (best_diff, best_osr, best_brg)
459 }
460 }
461 }
462 },
463 );
464
465 // Value over range
466 if brg > 65535 {
467 return Err(Error::UnsupportedBaudrate);
468 }
469
470 // SAFETY: unsafe only used for .bits()
471 regs.osr().write(|w| unsafe { w.osrval().bits(osr as u8) });
472
473 // SAFETY: unsafe only used for .bits()
474 regs.brg().write(|w| unsafe { w.brgval().bits(brg as u16) });
475 }
476
477 Ok(())
478 }
479
480 fn set_uart_config<T: Instance>(config: Config) {
481 let regs = T::info().regs;
482
483 regs.cfg().modify(|_, w| w.enable().disabled());
484
485 regs.cfg().modify(|_, w| {
486 w.datalen()
487 .variant(config.data_bits)
488 .stoplen()
489 .variant(config.stop_bits)
490 .paritysel()
491 .variant(config.parity)
492 .loop_()
493 .variant(config.loopback_mode)
494 .syncen()
495 .variant(config.operation)
496 .clkpol()
497 .variant(config.clock_polarity)
498 });
499
500 regs.cfg().modify(|_, w| w.enable().enabled());
501 }
502
503 /// Split the Uart into a transmitter and receiver, which is particularly
504 /// useful when having two tasks correlating to transmitting and receiving.
505 pub fn split(self) -> (UartTx<'a, M>, UartRx<'a, M>) {
506 (self.tx, self.rx)
507 }
508
509 /// Split the Uart into a transmitter and receiver by mutable reference,
510 /// which is particularly useful when having two tasks correlating to
511 /// transmitting and receiving.
512 pub fn split_ref(&mut self) -> (&mut UartTx<'a, M>, &mut UartRx<'a, M>) {
513 (&mut self.tx, &mut self.rx)
514 }
515}
516
517impl<'a> Uart<'a, Blocking> {
518 /// Create a new blocking UART
519 pub fn new_blocking<T: Instance>(
520 _inner: Peri<'a, T>,
521 tx: Peri<'a, impl TxPin<T>>,
522 rx: Peri<'a, impl RxPin<T>>,
523 config: Config,
524 ) -> Result<Self> {
525 tx.as_tx();
526 rx.as_rx();
527
528 let tx = tx.into();
529 let rx = rx.into();
530
531 Self::init::<T>(Some(tx), Some(rx), None, None, config)?;
532
533 Ok(Self {
534 tx: UartTx::new_inner::<T>(None),
535 rx: UartRx::new_inner::<T>(None),
536 })
537 }
538
539 /// Read from UART RX blocking execution until done.
540 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> {
541 self.rx.blocking_read(buf)
542 }
543
544 /// Read from UART RX. Non-blocking version, bails out if it would
545 /// block.
546 pub fn read(&mut self, buf: &mut [u8]) -> Result<()> {
547 self.rx.read(buf)
548 }
549
550 /// Transmit the provided buffer blocking execution until done.
551 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> {
552 self.tx.blocking_write(buf)
553 }
554
555 /// Transmit the provided buffer. Non-blocking version, bails out
556 /// if it would block.
557 pub fn write(&mut self, buf: &[u8]) -> Result<()> {
558 self.tx.write(buf)
559 }
560
561 /// Flush UART TX blocking execution until done.
562 pub fn blocking_flush(&mut self) -> Result<()> {
563 self.tx.blocking_flush()
564 }
565
566 /// Flush UART TX.
567 pub fn flush(&mut self) -> Result<()> {
568 self.tx.flush()
569 }
570}
571
572impl<'a> UartTx<'a, Async> {
573 /// Create a new DMA enabled UART which can only send data
574 pub fn new_async<T: Instance>(
575 _inner: Peri<'a, T>,
576 tx: Peri<'a, impl TxPin<T>>,
577 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
578 tx_dma: Peri<'a, impl TxDma<T>>,
579 config: Config,
580 ) -> Result<Self> {
581 tx.as_tx();
582
583 let _tx = tx.into();
584 Uart::<Async>::init::<T>(Some(_tx), None, None, None, config)?;
585
586 T::Interrupt::unpend();
587 unsafe { T::Interrupt::enable() };
588
589 Ok(Self::new_inner::<T>(Some(tx_dma.into())))
590 }
591
592 /// Transmit the provided buffer asynchronously.
593 pub async fn write(&mut self, buf: &[u8]) -> Result<()> {
594 let regs = self.info.regs;
595
596 // Disable DMA on completion/cancellation
597 let _dma_guard = OnDrop::new(|| {
598 regs.fifocfg().modify(|_, w| w.dmatx().disabled());
599 });
600
601 for chunk in buf.chunks(1024) {
602 regs.fifocfg().modify(|_, w| w.dmatx().enabled());
603
604 let ch = self.tx_dma.as_mut().unwrap().reborrow();
605 let transfer = unsafe { dma::write(ch, chunk, regs.fifowr().as_ptr() as *mut u8) };
606
607 let res = select(
608 transfer,
609 poll_fn(|cx| {
610 UART_WAKERS[self.info.index].register(cx.waker());
611
612 self.info.regs.intenset().write(|w| {
613 w.framerren()
614 .set_bit()
615 .parityerren()
616 .set_bit()
617 .rxnoiseen()
618 .set_bit()
619 .aberren()
620 .set_bit()
621 });
622
623 let stat = self.info.regs.stat().read();
624
625 self.info.regs.stat().write(|w| {
626 w.framerrint()
627 .clear_bit_by_one()
628 .parityerrint()
629 .clear_bit_by_one()
630 .rxnoiseint()
631 .clear_bit_by_one()
632 .aberr()
633 .clear_bit_by_one()
634 });
635
636 if stat.framerrint().bit_is_set() {
637 Poll::Ready(Err(Error::Framing))
638 } else if stat.parityerrint().bit_is_set() {
639 Poll::Ready(Err(Error::Parity))
640 } else if stat.rxnoiseint().bit_is_set() {
641 Poll::Ready(Err(Error::Noise))
642 } else if stat.aberr().bit_is_set() {
643 Poll::Ready(Err(Error::Fail))
644 } else {
645 Poll::Pending
646 }
647 }),
648 )
649 .await;
650
651 match res {
652 Either::First(()) | Either::Second(Ok(())) => (),
653 Either::Second(e) => return e,
654 }
655 }
656
657 Ok(())
658 }
659
660 /// Flush UART TX asynchronously.
661 pub async fn flush(&mut self) -> Result<()> {
662 self.wait_on(
663 |me| {
664 if me.info.regs.stat().read().txidle().bit_is_set() {
665 Poll::Ready(Ok(()))
666 } else {
667 Poll::Pending
668 }
669 },
670 |me| {
671 me.info.regs.intenset().write(|w| w.txidleen().set_bit());
672 },
673 )
674 .await
675 }
676
677 /// Calls `f` to check if we are ready or not.
678 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
679 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
680 where
681 F: FnMut(&mut Self) -> Poll<U>,
682 G: FnMut(&mut Self),
683 {
684 poll_fn(|cx| {
685 // Register waker before checking condition, to ensure that wakes/interrupts
686 // aren't lost between f() and g()
687 UART_WAKERS[self.info.index].register(cx.waker());
688 let r = f(self);
689
690 if r.is_pending() {
691 g(self);
692 }
693
694 r
695 })
696 .await
697 }
698}
699
700impl<'a> UartRx<'a, Async> {
701 /// Create a new DMA enabled UART which can only receive data
702 pub fn new_async<T: Instance>(
703 _inner: Peri<'a, T>,
704 rx: Peri<'a, impl RxPin<T>>,
705 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
706 rx_dma: Peri<'a, impl RxDma<T>>,
707 config: Config,
708 ) -> Result<Self> {
709 rx.as_rx();
710
711 let _rx = rx.into();
712 Uart::<Async>::init::<T>(None, Some(_rx), None, None, config)?;
713
714 T::Interrupt::unpend();
715 unsafe { T::Interrupt::enable() };
716
717 Ok(Self::new_inner::<T>(Some(rx_dma.into())))
718 }
719
720 /// Read from UART RX asynchronously.
721 pub async fn read(&mut self, buf: &mut [u8]) -> Result<()> {
722 let regs = self.info.regs;
723
724 // Disable DMA on completion/cancellation
725 let _dma_guard = OnDrop::new(|| {
726 regs.fifocfg().modify(|_, w| w.dmarx().disabled());
727 });
728
729 for chunk in buf.chunks_mut(1024) {
730 regs.fifocfg().modify(|_, w| w.dmarx().enabled());
731
732 let ch = self.rx_dma.as_mut().unwrap().reborrow();
733 let transfer = unsafe { dma::read(ch, regs.fiford().as_ptr() as *const u8, chunk) };
734
735 let res = select(
736 transfer,
737 poll_fn(|cx| {
738 UART_WAKERS[self.info.index].register(cx.waker());
739
740 self.info.regs.intenset().write(|w| {
741 w.framerren()
742 .set_bit()
743 .parityerren()
744 .set_bit()
745 .rxnoiseen()
746 .set_bit()
747 .aberren()
748 .set_bit()
749 });
750
751 let stat = self.info.regs.stat().read();
752
753 self.info.regs.stat().write(|w| {
754 w.framerrint()
755 .clear_bit_by_one()
756 .parityerrint()
757 .clear_bit_by_one()
758 .rxnoiseint()
759 .clear_bit_by_one()
760 .aberr()
761 .clear_bit_by_one()
762 });
763
764 if stat.framerrint().bit_is_set() {
765 Poll::Ready(Err(Error::Framing))
766 } else if stat.parityerrint().bit_is_set() {
767 Poll::Ready(Err(Error::Parity))
768 } else if stat.rxnoiseint().bit_is_set() {
769 Poll::Ready(Err(Error::Noise))
770 } else if stat.aberr().bit_is_set() {
771 Poll::Ready(Err(Error::Fail))
772 } else {
773 Poll::Pending
774 }
775 }),
776 )
777 .await;
778
779 match res {
780 Either::First(()) | Either::Second(Ok(())) => (),
781 Either::Second(e) => return e,
782 }
783 }
784
785 Ok(())
786 }
787}
788
789impl<'a> Uart<'a, Async> {
790 /// Create a new DMA enabled UART
791 pub fn new_async<T: Instance>(
792 _inner: Peri<'a, T>,
793 tx: Peri<'a, impl TxPin<T>>,
794 rx: Peri<'a, impl RxPin<T>>,
795 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
796 tx_dma: Peri<'a, impl TxDma<T>>,
797 rx_dma: Peri<'a, impl RxDma<T>>,
798 config: Config,
799 ) -> Result<Self> {
800 tx.as_tx();
801 rx.as_rx();
802
803 let tx = tx.into();
804 let rx = rx.into();
805
806 T::Interrupt::unpend();
807 unsafe { T::Interrupt::enable() };
808
809 Self::init::<T>(Some(tx), Some(rx), None, None, config)?;
810
811 Ok(Self {
812 tx: UartTx::new_inner::<T>(Some(tx_dma.into())),
813 rx: UartRx::new_inner::<T>(Some(rx_dma.into())),
814 })
815 }
816
817 /// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
818 pub fn new_with_rtscts<T: Instance>(
819 _inner: Peri<'a, T>,
820 tx: Peri<'a, impl TxPin<T>>,
821 rx: Peri<'a, impl RxPin<T>>,
822 rts: Peri<'a, impl RtsPin<T>>,
823 cts: Peri<'a, impl CtsPin<T>>,
824 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
825 tx_dma: Peri<'a, impl TxDma<T>>,
826 rx_dma: Peri<'a, impl RxDma<T>>,
827 config: Config,
828 ) -> Result<Self> {
829 tx.as_tx();
830 rx.as_rx();
831 rts.as_rts();
832 cts.as_cts();
833
834 let tx = tx.into();
835 let rx = rx.into();
836 let rts = rts.into();
837 let cts = cts.into();
838
839 Self::init::<T>(Some(tx), Some(rx), Some(rts), Some(cts), config)?;
840
841 Ok(Self {
842 tx: UartTx::new_inner::<T>(Some(tx_dma.into())),
843 rx: UartRx::new_inner::<T>(Some(rx_dma.into())),
844 })
845 }
846
847 /// Read from UART RX.
848 pub async fn read(&mut self, buf: &mut [u8]) -> Result<()> {
849 self.rx.read(buf).await
850 }
851
852 /// Transmit the provided buffer.
853 pub async fn write(&mut self, buf: &[u8]) -> Result<()> {
854 self.tx.write(buf).await
855 }
856
857 /// Flush UART TX.
858 pub async fn flush(&mut self) -> Result<()> {
859 self.tx.flush().await
860 }
861}
862
863impl embedded_hal_02::serial::Read<u8> for UartRx<'_, Blocking> {
864 type Error = Error;
865
866 fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> {
867 let mut buf = [0; 1];
868
869 match self.read(&mut buf) {
870 Ok(_) => Ok(buf[0]),
871 Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock),
872 Err(e) => Err(nb::Error::Other(e)),
873 }
874 }
875}
876
877impl embedded_hal_02::serial::Write<u8> for UartTx<'_, Blocking> {
878 type Error = Error;
879
880 fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> {
881 match self.write(&[word]) {
882 Ok(_) => Ok(()),
883 Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock),
884 Err(e) => Err(nb::Error::Other(e)),
885 }
886 }
887
888 fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> {
889 match self.flush() {
890 Ok(_) => Ok(()),
891 Err(Error::TxBusy) => Err(nb::Error::WouldBlock),
892 Err(e) => Err(nb::Error::Other(e)),
893 }
894 }
895}
896
897impl embedded_hal_02::blocking::serial::Write<u8> for UartTx<'_, Blocking> {
898 type Error = Error;
899
900 fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> {
901 self.blocking_write(buffer)
902 }
903
904 fn bflush(&mut self) -> core::result::Result<(), Self::Error> {
905 self.blocking_flush()
906 }
907}
908
909impl embedded_hal_02::serial::Read<u8> for Uart<'_, Blocking> {
910 type Error = Error;
911
912 fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> {
913 embedded_hal_02::serial::Read::read(&mut self.rx)
914 }
915}
916
917impl embedded_hal_02::serial::Write<u8> for Uart<'_, Blocking> {
918 type Error = Error;
919
920 fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> {
921 embedded_hal_02::serial::Write::write(&mut self.tx, word)
922 }
923
924 fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> {
925 embedded_hal_02::serial::Write::flush(&mut self.tx)
926 }
927}
928
929impl embedded_hal_02::blocking::serial::Write<u8> for Uart<'_, Blocking> {
930 type Error = Error;
931
932 fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> {
933 self.blocking_write(buffer)
934 }
935
936 fn bflush(&mut self) -> core::result::Result<(), Self::Error> {
937 self.blocking_flush()
938 }
939}
940
941impl embedded_hal_nb::serial::Error for Error {
942 fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
943 match *self {
944 Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
945 Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
946 Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
947 Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise,
948 _ => embedded_hal_nb::serial::ErrorKind::Other,
949 }
950 }
951}
952
953impl embedded_hal_nb::serial::ErrorType for UartRx<'_, Blocking> {
954 type Error = Error;
955}
956
957impl embedded_hal_nb::serial::ErrorType for UartTx<'_, Blocking> {
958 type Error = Error;
959}
960
961impl embedded_hal_nb::serial::ErrorType for Uart<'_, Blocking> {
962 type Error = Error;
963}
964
965impl embedded_hal_nb::serial::Read for UartRx<'_, Blocking> {
966 fn read(&mut self) -> nb::Result<u8, Self::Error> {
967 let mut buf = [0; 1];
968
969 match self.read(&mut buf) {
970 Ok(_) => Ok(buf[0]),
971 Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock),
972 Err(e) => Err(nb::Error::Other(e)),
973 }
974 }
975}
976
977impl embedded_hal_nb::serial::Write for UartTx<'_, Blocking> {
978 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
979 match self.write(&[word]) {
980 Ok(_) => Ok(()),
981 Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock),
982 Err(e) => Err(nb::Error::Other(e)),
983 }
984 }
985
986 fn flush(&mut self) -> nb::Result<(), Self::Error> {
987 match self.flush() {
988 Ok(_) => Ok(()),
989 Err(Error::TxBusy) => Err(nb::Error::WouldBlock),
990 Err(e) => Err(nb::Error::Other(e)),
991 }
992 }
993}
994
995impl embedded_hal_nb::serial::Read for Uart<'_, Blocking> {
996 fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> {
997 embedded_hal_02::serial::Read::read(&mut self.rx)
998 }
999}
1000
1001impl embedded_hal_nb::serial::Write for Uart<'_, Blocking> {
1002 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1003 self.blocking_write(&[char]).map_err(nb::Error::Other)
1004 }
1005
1006 fn flush(&mut self) -> nb::Result<(), Self::Error> {
1007 self.blocking_flush().map_err(nb::Error::Other)
1008 }
1009}
1010
1011struct Info {
1012 regs: &'static crate::pac::usart0::RegisterBlock,
1013 index: usize,
1014 refcnt: AtomicU8,
1015}
1016
1017trait SealedInstance {
1018 fn info() -> Info;
1019 fn index() -> usize;
1020}
1021
1022/// UART interrupt handler.
1023pub struct InterruptHandler<T: Instance> {
1024 _phantom: PhantomData<T>,
1025}
1026
1027const UART_COUNT: usize = 8;
1028static UART_WAKERS: [AtomicWaker; UART_COUNT] = [const { AtomicWaker::new() }; UART_COUNT];
1029
1030impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
1031 unsafe fn on_interrupt() {
1032 let waker = &UART_WAKERS[T::index()];
1033 let regs = T::info().regs;
1034 let stat = regs.intstat().read();
1035
1036 if stat.txidle().bit_is_set()
1037 || stat.framerrint().bit_is_set()
1038 || stat.parityerrint().bit_is_set()
1039 || stat.rxnoiseint().bit_is_set()
1040 || stat.aberrint().bit_is_set()
1041 {
1042 regs.intenclr().write(|w| {
1043 w.txidleclr()
1044 .set_bit()
1045 .framerrclr()
1046 .set_bit()
1047 .parityerrclr()
1048 .set_bit()
1049 .rxnoiseclr()
1050 .set_bit()
1051 .aberrclr()
1052 .set_bit()
1053 });
1054 }
1055
1056 waker.wake();
1057 }
1058}
1059
1060/// UART instance trait.
1061#[allow(private_bounds)]
1062pub trait Instance: crate::flexcomm::IntoUsart + SealedInstance + PeripheralType + 'static + Send {
1063 /// Interrupt for this UART instance.
1064 type Interrupt: interrupt::typelevel::Interrupt;
1065}
1066
1067macro_rules! impl_instance {
1068 ($($n:expr),*) => {
1069 $(
1070 paste!{
1071 impl SealedInstance for crate::peripherals::[<FLEXCOMM $n>] {
1072 fn info() -> Info {
1073 Info {
1074 regs: unsafe { &*crate::pac::[<Usart $n>]::ptr() },
1075 index: $n,
1076 refcnt: AtomicU8::new(0),
1077 }
1078 }
1079
1080 #[inline]
1081 fn index() -> usize {
1082 $n
1083 }
1084 }
1085
1086 impl Instance for crate::peripherals::[<FLEXCOMM $n>] {
1087 type Interrupt = crate::interrupt::typelevel::[<FLEXCOMM $n>];
1088 }
1089 }
1090 )*
1091 };
1092}
1093
1094impl_instance!(0, 1, 2, 3, 4, 5, 6, 7);
1095
1096impl<T: Pin> Sealed for T {}
1097
1098/// io configuration trait for Uart Tx configuration
1099pub trait TxPin<T: Instance>: Pin + Sealed + PeripheralType {
1100 /// convert the pin to appropriate function for Uart Tx usage
1101 fn as_tx(&self);
1102}
1103
1104/// io configuration trait for Uart Rx configuration
1105pub trait RxPin<T: Instance>: Pin + Sealed + PeripheralType {
1106 /// convert the pin to appropriate function for Uart Rx usage
1107 fn as_rx(&self);
1108}
1109
1110/// io configuration trait for Uart Cts
1111pub trait CtsPin<T: Instance>: Pin + Sealed + PeripheralType {
1112 /// convert the pin to appropriate function for Uart Cts usage
1113 fn as_cts(&self);
1114}
1115
1116/// io configuration trait for Uart Rts
1117pub trait RtsPin<T: Instance>: Pin + Sealed + PeripheralType {
1118 /// convert the pin to appropriate function for Uart Rts usage
1119 fn as_rts(&self);
1120}
1121
1122macro_rules! impl_pin_trait {
1123 ($fcn:ident, $mode:ident, $($pin:ident, $fn:ident),*) => {
1124 paste! {
1125 $(
1126 impl [<$mode:camel Pin>]<crate::peripherals::$fcn> for crate::peripherals::$pin {
1127 fn [<as_ $mode>](&self) {
1128 // UM11147 table 507 pg 495
1129 self.set_function(crate::iopctl::Function::$fn)
1130 .set_pull(Pull::None)
1131 .enable_input_buffer()
1132 .set_slew_rate(SlewRate::Standard)
1133 .set_drive_strength(DriveStrength::Normal)
1134 .disable_analog_multiplex()
1135 .set_drive_mode(DriveMode::PushPull)
1136 .set_input_inverter(Inverter::Disabled);
1137 }
1138 }
1139 )*
1140 }
1141 };
1142}
1143
1144// FLEXCOMM0
1145impl_pin_trait!(FLEXCOMM0, tx, PIO0_1, F1, PIO3_1, F5);
1146impl_pin_trait!(FLEXCOMM0, rx, PIO0_2, F1, PIO3_2, F5);
1147impl_pin_trait!(FLEXCOMM0, cts, PIO0_3, F1, PIO3_3, F5);
1148impl_pin_trait!(FLEXCOMM0, rts, PIO0_4, F1, PIO3_4, F5);
1149
1150// FLEXCOMM1
1151impl_pin_trait!(FLEXCOMM1, tx, PIO0_8, F1, PIO7_26, F1);
1152impl_pin_trait!(FLEXCOMM1, rx, PIO0_9, F1, PIO7_27, F1);
1153impl_pin_trait!(FLEXCOMM1, cts, PIO0_10, F1, PIO7_28, F1);
1154impl_pin_trait!(FLEXCOMM1, rts, PIO0_11, F1, PIO7_29, F1);
1155
1156// FLEXCOMM2
1157impl_pin_trait!(FLEXCOMM2, tx, PIO0_15, F1, PIO7_30, F5);
1158impl_pin_trait!(FLEXCOMM2, rx, PIO0_16, F1, PIO7_31, F5);
1159impl_pin_trait!(FLEXCOMM2, cts, PIO0_17, F1, PIO4_8, F5);
1160impl_pin_trait!(FLEXCOMM2, rts, PIO0_18, F1);
1161
1162// FLEXCOMM3
1163impl_pin_trait!(FLEXCOMM3, tx, PIO0_22, F1);
1164impl_pin_trait!(FLEXCOMM3, rx, PIO0_23, F1);
1165impl_pin_trait!(FLEXCOMM3, cts, PIO0_24, F1);
1166impl_pin_trait!(FLEXCOMM3, rts, PIO0_25, F1);
1167
1168// FLEXCOMM4
1169impl_pin_trait!(FLEXCOMM4, tx, PIO0_29, F1);
1170impl_pin_trait!(FLEXCOMM4, rx, PIO0_30, F1);
1171impl_pin_trait!(FLEXCOMM4, cts, PIO0_31, F1);
1172impl_pin_trait!(FLEXCOMM4, rts, PIO1_0, F1);
1173
1174// FLEXCOMM5
1175impl_pin_trait!(FLEXCOMM5, tx, PIO1_4, F1, PIO3_16, F5);
1176impl_pin_trait!(FLEXCOMM5, rx, PIO1_5, F1, PIO3_17, F5);
1177impl_pin_trait!(FLEXCOMM5, cts, PIO1_6, F1, PIO3_18, F5);
1178impl_pin_trait!(FLEXCOMM5, rts, PIO1_7, F1, PIO3_23, F5);
1179
1180// FLEXCOMM6
1181impl_pin_trait!(FLEXCOMM6, tx, PIO3_26, F1);
1182impl_pin_trait!(FLEXCOMM6, rx, PIO3_27, F1);
1183impl_pin_trait!(FLEXCOMM6, cts, PIO3_28, F1);
1184impl_pin_trait!(FLEXCOMM6, rts, PIO3_29, F1);
1185
1186// FLEXCOMM7
1187impl_pin_trait!(FLEXCOMM7, tx, PIO4_1, F1);
1188impl_pin_trait!(FLEXCOMM7, rx, PIO4_2, F1);
1189impl_pin_trait!(FLEXCOMM7, cts, PIO4_3, F1);
1190impl_pin_trait!(FLEXCOMM7, rts, PIO4_4, F1);
1191
1192/// UART Tx DMA trait.
1193#[allow(private_bounds)]
1194pub trait TxDma<T: Instance>: crate::dma::Channel {}
1195
1196/// UART Rx DMA trait.
1197#[allow(private_bounds)]
1198pub trait RxDma<T: Instance>: crate::dma::Channel {}
1199
1200macro_rules! impl_dma {
1201 ($fcn:ident, $mode:ident, $dma:ident) => {
1202 paste! {
1203 impl [<$mode Dma>]<crate::peripherals::$fcn> for crate::peripherals::$dma {}
1204 }
1205 };
1206}
1207
1208impl_dma!(FLEXCOMM0, Rx, DMA0_CH0);
1209impl_dma!(FLEXCOMM0, Tx, DMA0_CH1);
1210
1211impl_dma!(FLEXCOMM1, Rx, DMA0_CH2);
1212impl_dma!(FLEXCOMM1, Tx, DMA0_CH3);
1213
1214impl_dma!(FLEXCOMM2, Rx, DMA0_CH4);
1215impl_dma!(FLEXCOMM2, Tx, DMA0_CH5);
1216
1217impl_dma!(FLEXCOMM3, Rx, DMA0_CH6);
1218impl_dma!(FLEXCOMM3, Tx, DMA0_CH7);
1219
1220impl_dma!(FLEXCOMM4, Rx, DMA0_CH8);
1221impl_dma!(FLEXCOMM4, Tx, DMA0_CH9);
1222
1223impl_dma!(FLEXCOMM5, Rx, DMA0_CH10);
1224impl_dma!(FLEXCOMM5, Tx, DMA0_CH11);
1225
1226impl_dma!(FLEXCOMM6, Rx, DMA0_CH12);
1227impl_dma!(FLEXCOMM6, Tx, DMA0_CH13);
1228
1229impl_dma!(FLEXCOMM7, Rx, DMA0_CH14);
1230impl_dma!(FLEXCOMM7, Tx, DMA0_CH15);
diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs
index 6883c4ee0..e62fde8b1 100644
--- a/embassy-imxrt/src/gpio.rs
+++ b/embassy-imxrt/src/gpio.rs
@@ -13,7 +13,7 @@ use crate::clocks::enable_and_reset;
13use crate::iopctl::IopctlPin; 13use crate::iopctl::IopctlPin;
14pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; 14pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate};
15use crate::sealed::Sealed; 15use crate::sealed::Sealed;
16use crate::{interrupt, peripherals, Peri, PeripheralType}; 16use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType};
17 17
18// This should be unique per IMXRT package 18// This should be unique per IMXRT package
19const PORT_COUNT: usize = 8; 19const PORT_COUNT: usize = 8;
@@ -64,24 +64,6 @@ fn GPIO_INTA() {
64} 64}
65 65
66#[cfg(feature = "rt")] 66#[cfg(feature = "rt")]
67struct BitIter(u32);
68
69#[cfg(feature = "rt")]
70impl Iterator for BitIter {
71 type Item = u32;
72
73 fn next(&mut self) -> Option<Self::Item> {
74 match self.0.trailing_zeros() {
75 32 => None,
76 b => {
77 self.0 &= !(1 << b);
78 Some(b)
79 }
80 }
81 }
82}
83
84#[cfg(feature = "rt")]
85fn irq_handler(port_wakers: &[Option<&PortWaker>]) { 67fn irq_handler(port_wakers: &[Option<&PortWaker>]) {
86 let reg = unsafe { crate::pac::Gpio::steal() }; 68 let reg = unsafe { crate::pac::Gpio::steal() };
87 69
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index b1183d8fc..ad0d9e21c 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -19,6 +19,8 @@ pub(crate) mod fmt;
19 19
20pub mod clocks; 20pub mod clocks;
21pub mod crc; 21pub mod crc;
22pub mod dma;
23pub mod flexcomm;
22pub mod gpio; 24pub mod gpio;
23pub mod iopctl; 25pub mod iopctl;
24pub mod rng; 26pub mod rng;
@@ -129,14 +131,16 @@ pub fn init(config: config::Config) -> Peripherals {
129 // before doing anything important. 131 // before doing anything important.
130 let peripherals = Peripherals::take(); 132 let peripherals = Peripherals::take();
131 133
134 #[cfg(feature = "_time-driver")]
135 time_driver::init(config.time_interrupt_priority);
136
132 unsafe { 137 unsafe {
133 if let Err(e) = clocks::init(config.clocks) { 138 if let Err(e) = clocks::init(config.clocks) {
134 error!("unable to initialize Clocks for reason: {:?}", e); 139 error!("unable to initialize Clocks for reason: {:?}", e);
135 // Panic here? 140 // Panic here?
136 } 141 }
142 dma::init();
137 } 143 }
138 #[cfg(feature = "_time-driver")]
139 time_driver::init(config.time_interrupt_priority);
140 gpio::init(); 144 gpio::init();
141 145
142 peripherals 146 peripherals
@@ -145,3 +149,21 @@ pub fn init(config: config::Config) -> Peripherals {
145pub(crate) mod sealed { 149pub(crate) mod sealed {
146 pub trait Sealed {} 150 pub trait Sealed {}
147} 151}
152
153#[cfg(feature = "rt")]
154struct BitIter(u32);
155
156#[cfg(feature = "rt")]
157impl Iterator for BitIter {
158 type Item = u32;
159
160 fn next(&mut self) -> Option<Self::Item> {
161 match self.0.trailing_zeros() {
162 32 => None,
163 b => {
164 self.0 &= !(1 << b);
165 Some(b)
166 }
167 }
168 }
169}
diff --git a/examples/mimxrt6/src/bin/uart-async.rs b/examples/mimxrt6/src/bin/uart-async.rs
new file mode 100644
index 000000000..58e31f379
--- /dev/null
+++ b/examples/mimxrt6/src/bin/uart-async.rs
@@ -0,0 +1,87 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::flexcomm::uart::{self, Async, Uart};
9use embassy_imxrt::{bind_interrupts, peripherals};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 FLEXCOMM2 => uart::InterruptHandler<peripherals::FLEXCOMM2>;
15 FLEXCOMM4 => uart::InterruptHandler<peripherals::FLEXCOMM4>;
16});
17
18const BUFLEN: usize = 16;
19
20#[embassy_executor::task]
21async fn usart4_task(mut uart: Uart<'static, Async>) {
22 info!("RX Task");
23
24 loop {
25 let mut rx_buf = [0; BUFLEN];
26 uart.read(&mut rx_buf).await.unwrap();
27 info!("usart4: rx_buf {:02x}", rx_buf);
28
29 Timer::after_millis(10).await;
30
31 let tx_buf = [0xaa; BUFLEN];
32 uart.write(&tx_buf).await.unwrap();
33 info!("usart4: tx_buf {:02x}", tx_buf);
34 }
35}
36
37#[embassy_executor::task]
38async fn usart2_task(mut uart: Uart<'static, Async>) {
39 info!("TX Task");
40
41 loop {
42 let tx_buf = [0x55; BUFLEN];
43 uart.write(&tx_buf).await.unwrap();
44 info!("usart2: tx_buf {:02x}", tx_buf);
45
46 Timer::after_millis(10).await;
47
48 let mut rx_buf = [0x00; BUFLEN];
49 uart.read(&mut rx_buf).await.unwrap();
50 info!("usart2: rx_buf {:02x}", rx_buf);
51 }
52}
53
54#[embassy_executor::main]
55async fn main(spawner: Spawner) {
56 let p = embassy_imxrt::init(Default::default());
57
58 info!("UART test start");
59
60 let usart4 = Uart::new_with_rtscts(
61 p.FLEXCOMM4,
62 p.PIO0_29,
63 p.PIO0_30,
64 p.PIO1_0,
65 p.PIO0_31,
66 Irqs,
67 p.DMA0_CH9,
68 p.DMA0_CH8,
69 Default::default(),
70 )
71 .unwrap();
72 spawner.must_spawn(usart4_task(usart4));
73
74 let usart2 = Uart::new_with_rtscts(
75 p.FLEXCOMM2,
76 p.PIO0_15,
77 p.PIO0_16,
78 p.PIO0_18,
79 p.PIO0_17,
80 Irqs,
81 p.DMA0_CH5,
82 p.DMA0_CH4,
83 Default::default(),
84 )
85 .unwrap();
86 spawner.must_spawn(usart2_task(usart2));
87}
diff --git a/examples/mimxrt6/src/bin/uart.rs b/examples/mimxrt6/src/bin/uart.rs
new file mode 100644
index 000000000..d6a75f85d
--- /dev/null
+++ b/examples/mimxrt6/src/bin/uart.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::flexcomm::uart::{Blocking, Uart, UartRx, UartTx};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn usart4_task(mut uart: UartRx<'static, Blocking>) {
14 info!("RX Task");
15
16 loop {
17 let mut buf = [0; 8];
18
19 Timer::after_millis(10).await;
20
21 uart.blocking_read(&mut buf).unwrap();
22
23 let s = core::str::from_utf8(&buf).unwrap();
24
25 info!("Received '{}'", s);
26 }
27}
28
29#[embassy_executor::task]
30async fn usart2_task(mut uart: UartTx<'static, Blocking>) {
31 info!("TX Task");
32
33 loop {
34 let buf = "Testing\0".as_bytes();
35
36 uart.blocking_write(buf).unwrap();
37
38 Timer::after_millis(10).await;
39 }
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_imxrt::init(Default::default());
45
46 info!("UART test start");
47
48 let usart4 = Uart::new_blocking(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Default::default()).unwrap();
49
50 let (_, usart4) = usart4.split();
51 spawner.must_spawn(usart4_task(usart4));
52
53 let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap();
54 spawner.must_spawn(usart2_task(usart2));
55}