aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt/src
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
committer1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
commit6bb3d2c0720fa082f27d3cdb70f516058497ec87 (patch)
tree5a1e255cff999b00800f203b91a759c720c973e5 /embassy-imxrt/src
parenteb685574601d98c44faed9a3534d056199b46e20 (diff)
parent92a6fd2946f2cbb15359290f68aa360953da2ff7 (diff)
Merge branch 'main' into rp2040-rtc-alarm
Diffstat (limited to 'embassy-imxrt/src')
-rw-r--r--embassy-imxrt/src/crc.rs190
-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.rs48
-rw-r--r--embassy-imxrt/src/rng.rs287
-rw-r--r--embassy-imxrt/src/time_driver.rs7
8 files changed, 2423 insertions, 29 deletions
diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs
new file mode 100644
index 000000000..24d6ba5bd
--- /dev/null
+++ b/embassy-imxrt/src/crc.rs
@@ -0,0 +1,190 @@
1//! Cyclic Redundancy Check (CRC)
2
3use core::marker::PhantomData;
4
5use crate::clocks::{enable_and_reset, SysconPeripheral};
6pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial;
7use crate::{peripherals, Peri, PeripheralType};
8
9/// CRC driver.
10pub struct Crc<'d> {
11 info: Info,
12 _config: Config,
13 _lifetime: PhantomData<&'d ()>,
14}
15
16/// CRC configuration
17pub struct Config {
18 /// Polynomial to be used
19 pub polynomial: Polynomial,
20
21 /// Reverse bit order of input?
22 pub reverse_in: bool,
23
24 /// 1's complement input?
25 pub complement_in: bool,
26
27 /// Reverse CRC bit order?
28 pub reverse_out: bool,
29
30 /// 1's complement CRC?
31 pub complement_out: bool,
32
33 /// CRC Seed
34 pub seed: u32,
35}
36
37impl Config {
38 /// Create a new CRC config.
39 #[must_use]
40 pub fn new(
41 polynomial: Polynomial,
42 reverse_in: bool,
43 complement_in: bool,
44 reverse_out: bool,
45 complement_out: bool,
46 seed: u32,
47 ) -> Self {
48 Config {
49 polynomial,
50 reverse_in,
51 complement_in,
52 reverse_out,
53 complement_out,
54 seed,
55 }
56 }
57}
58
59impl Default for Config {
60 fn default() -> Self {
61 Self {
62 polynomial: Polynomial::CrcCcitt,
63 reverse_in: false,
64 complement_in: false,
65 reverse_out: false,
66 complement_out: false,
67 seed: 0xffff,
68 }
69 }
70}
71
72impl<'d> Crc<'d> {
73 /// Instantiates new CRC peripheral and initializes to default values.
74 pub fn new<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self {
75 // enable CRC clock
76 enable_and_reset::<T>();
77
78 let mut instance = Self {
79 info: T::info(),
80 _config: config,
81 _lifetime: PhantomData,
82 };
83
84 instance.reconfigure();
85 instance
86 }
87
88 /// Reconfigured the CRC peripheral.
89 fn reconfigure(&mut self) {
90 self.info.regs.mode().write(|w| {
91 w.crc_poly()
92 .variant(self._config.polynomial)
93 .bit_rvs_wr()
94 .variant(self._config.reverse_in)
95 .cmpl_wr()
96 .variant(self._config.complement_in)
97 .bit_rvs_sum()
98 .variant(self._config.reverse_out)
99 .cmpl_sum()
100 .variant(self._config.complement_out)
101 });
102
103 // Init CRC value
104 self.info
105 .regs
106 .seed()
107 .write(|w| unsafe { w.crc_seed().bits(self._config.seed) });
108 }
109
110 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
111 pub fn feed_byte(&mut self, byte: u8) -> u32 {
112 self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) });
113
114 self.info.regs.sum().read().bits()
115 }
116
117 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
118 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
119 let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() };
120
121 for b in prefix {
122 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
123 }
124
125 for d in data {
126 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) });
127 }
128
129 for b in suffix {
130 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
131 }
132
133 self.info.regs.sum().read().bits()
134 }
135
136 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
137 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
138 self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) });
139
140 self.info.regs.sum().read().bits()
141 }
142
143 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
144 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
145 for halfword in halfwords {
146 self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) });
147 }
148
149 self.info.regs.sum().read().bits()
150 }
151
152 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
153 pub fn feed_word(&mut self, word: u32) -> u32 {
154 self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) });
155
156 self.info.regs.sum().read().bits()
157 }
158
159 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
160 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
161 for word in words {
162 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) });
163 }
164
165 self.info.regs.sum().read().bits()
166 }
167}
168
169struct Info {
170 regs: crate::pac::CrcEngine,
171}
172
173trait SealedInstance {
174 fn info() -> Info;
175}
176
177/// CRC instance trait.
178#[allow(private_bounds)]
179pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {}
180
181impl Instance for peripherals::CRC {}
182
183impl SealedInstance for peripherals::CRC {
184 fn info() -> Info {
185 // SAFETY: safe from single executor
186 Info {
187 regs: unsafe { crate::pac::CrcEngine::steal() },
188 }
189 }
190}
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 ad9f81e88..a3437c655 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -18,8 +18,12 @@ compile_error!(
18pub(crate) mod fmt; 18pub(crate) mod fmt;
19 19
20pub mod clocks; 20pub mod clocks;
21pub mod crc;
22pub mod dma;
23pub mod flexcomm;
21pub mod gpio; 24pub mod gpio;
22pub mod iopctl; 25pub mod iopctl;
26pub mod rng;
23 27
24#[cfg(feature = "_time-driver")] 28#[cfg(feature = "_time-driver")]
25pub mod time_driver; 29pub mod time_driver;
@@ -52,25 +56,31 @@ pub use crate::pac::NVIC_PRIO_BITS;
52/// ```rust,ignore 56/// ```rust,ignore
53/// use embassy_imxrt::{bind_interrupts, flexspi, peripherals}; 57/// use embassy_imxrt::{bind_interrupts, flexspi, peripherals};
54/// 58///
55/// bind_interrupts!(struct Irqs { 59/// bind_interrupts!(
56/// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>; 60/// /// Binds the FLEXSPI interrupt.
57/// }); 61/// struct Irqs {
62/// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>;
63/// }
64/// );
58/// ``` 65/// ```
59/// 66///
60// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. 67// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
61#[macro_export] 68#[macro_export]
62macro_rules! bind_interrupts { 69macro_rules! bind_interrupts {
63 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 70 ($(#[$attr:meta])* $vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
64 #[derive(Copy, Clone)] 71 #[derive(Copy, Clone)]
72 $(#[$attr])*
65 $vis struct $name; 73 $vis struct $name;
66 74
67 $( 75 $(
68 #[allow(non_snake_case)] 76 #[allow(non_snake_case)]
69 #[no_mangle] 77 #[no_mangle]
70 unsafe extern "C" fn $irq() { 78 unsafe extern "C" fn $irq() {
71 $( 79 unsafe {
72 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); 80 $(
73 )* 81 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
82 )*
83 }
74 } 84 }
75 85
76 $( 86 $(
@@ -127,14 +137,16 @@ pub fn init(config: config::Config) -> Peripherals {
127 // before doing anything important. 137 // before doing anything important.
128 let peripherals = Peripherals::take(); 138 let peripherals = Peripherals::take();
129 139
140 #[cfg(feature = "_time-driver")]
141 time_driver::init(config.time_interrupt_priority);
142
130 unsafe { 143 unsafe {
131 if let Err(e) = clocks::init(config.clocks) { 144 if let Err(e) = clocks::init(config.clocks) {
132 error!("unable to initialize Clocks for reason: {:?}", e); 145 error!("unable to initialize Clocks for reason: {:?}", e);
133 // Panic here? 146 // Panic here?
134 } 147 }
148 dma::init();
135 } 149 }
136 #[cfg(feature = "_time-driver")]
137 time_driver::init(config.time_interrupt_priority);
138 gpio::init(); 150 gpio::init();
139 151
140 peripherals 152 peripherals
@@ -143,3 +155,21 @@ pub fn init(config: config::Config) -> Peripherals {
143pub(crate) mod sealed { 155pub(crate) mod sealed {
144 pub trait Sealed {} 156 pub trait Sealed {}
145} 157}
158
159#[cfg(feature = "rt")]
160struct BitIter(u32);
161
162#[cfg(feature = "rt")]
163impl Iterator for BitIter {
164 type Item = u32;
165
166 fn next(&mut self) -> Option<Self::Item> {
167 match self.0.trailing_zeros() {
168 32 => None,
169 b => {
170 self.0 &= !(1 << b);
171 Some(b)
172 }
173 }
174 }
175}
diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs
new file mode 100644
index 000000000..75f243df9
--- /dev/null
+++ b/embassy-imxrt/src/rng.rs
@@ -0,0 +1,287 @@
1//! True Random Number Generator (TRNG)
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy_futures::block_on;
8use embassy_sync::waitqueue::AtomicWaker;
9
10use crate::clocks::{enable_and_reset, SysconPeripheral};
11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, peripherals, Peri, PeripheralType};
13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15
16/// RNG ;error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum Error {
20 /// Seed error.
21 SeedError,
22
23 /// HW Error.
24 HwError,
25
26 /// Frequency Count Fail
27 FreqCountFail,
28}
29
30/// RNG interrupt handler.
31pub struct InterruptHandler<T: Instance> {
32 _phantom: PhantomData<T>,
33}
34
35impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
36 unsafe fn on_interrupt() {
37 let regs = T::info().regs;
38 let int_status = regs.int_status().read();
39
40 if int_status.ent_val().bit_is_set()
41 || int_status.hw_err().bit_is_set()
42 || int_status.frq_ct_fail().bit_is_set()
43 {
44 regs.int_ctrl().modify(|_, w| {
45 w.ent_val()
46 .ent_val_0()
47 .hw_err()
48 .hw_err_0()
49 .frq_ct_fail()
50 .frq_ct_fail_0()
51 });
52 RNG_WAKER.wake();
53 }
54 }
55}
56
57/// RNG driver.
58pub struct Rng<'d> {
59 info: Info,
60 _lifetime: PhantomData<&'d ()>,
61}
62
63impl<'d> Rng<'d> {
64 /// Create a new RNG driver.
65 pub fn new<T: Instance>(
66 _inner: Peri<'d, T>,
67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
68 ) -> Self {
69 enable_and_reset::<T>();
70
71 let mut random = Self {
72 info: T::info(),
73 _lifetime: PhantomData,
74 };
75 random.init();
76
77 T::Interrupt::unpend();
78 unsafe { T::Interrupt::enable() };
79
80 random
81 }
82
83 /// Reset the RNG.
84 pub fn reset(&mut self) {
85 self.info.regs.mctl().write(|w| w.rst_def().set_bit().prgm().set_bit());
86 }
87
88 /// Fill the given slice with random values.
89 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
90 // We have a total of 16 words (512 bits) of entropy at our
91 // disposal. The idea here is to read all bits and copy the
92 // necessary bytes to the slice.
93 for chunk in dest.chunks_mut(64) {
94 self.async_fill_chunk(chunk).await?;
95 }
96
97 Ok(())
98 }
99
100 async fn async_fill_chunk(&mut self, chunk: &mut [u8]) -> Result<(), Error> {
101 // wait for interrupt
102 let res = poll_fn(|cx| {
103 // Check if already ready.
104 // TODO: Is this necessary? Could we just check once after
105 // the waker has been registered?
106 if self.info.regs.int_status().read().ent_val().bit_is_set() {
107 return Poll::Ready(Ok(()));
108 }
109
110 RNG_WAKER.register(cx.waker());
111
112 self.unmask_interrupts();
113
114 let mctl = self.info.regs.mctl().read();
115
116 // Check again if interrupt fired
117 if mctl.ent_val().bit_is_set() {
118 Poll::Ready(Ok(()))
119 } else if mctl.err().bit_is_set() {
120 Poll::Ready(Err(Error::HwError))
121 } else if mctl.fct_fail().bit_is_set() {
122 Poll::Ready(Err(Error::FreqCountFail))
123 } else {
124 Poll::Pending
125 }
126 })
127 .await;
128
129 let bits = self.info.regs.mctl().read();
130
131 if bits.ent_val().bit_is_set() {
132 let mut entropy = [0; 16];
133
134 for (i, item) in entropy.iter_mut().enumerate() {
135 *item = self.info.regs.ent(i).read().bits();
136 }
137
138 // Read MCTL after reading ENT15
139 let _ = self.info.regs.mctl().read();
140
141 if entropy.iter().any(|e| *e == 0) {
142 return Err(Error::SeedError);
143 }
144
145 // SAFETY: entropy is the same for input and output types in
146 // native endianness.
147 let entropy: [u8; 64] = unsafe { core::mem::transmute(entropy) };
148
149 // write bytes to chunk
150 chunk.copy_from_slice(&entropy[..chunk.len()]);
151 }
152
153 res
154 }
155
156 fn mask_interrupts(&mut self) {
157 self.info.regs.int_mask().write(|w| {
158 w.ent_val()
159 .ent_val_0()
160 .hw_err()
161 .hw_err_0()
162 .frq_ct_fail()
163 .frq_ct_fail_0()
164 });
165 }
166
167 fn unmask_interrupts(&mut self) {
168 self.info.regs.int_mask().modify(|_, w| {
169 w.ent_val()
170 .ent_val_1()
171 .hw_err()
172 .hw_err_1()
173 .frq_ct_fail()
174 .frq_ct_fail_1()
175 });
176 }
177
178 fn enable_interrupts(&mut self) {
179 self.info.regs.int_ctrl().write(|w| {
180 w.ent_val()
181 .ent_val_1()
182 .hw_err()
183 .hw_err_1()
184 .frq_ct_fail()
185 .frq_ct_fail_1()
186 });
187 }
188
189 fn init(&mut self) {
190 self.mask_interrupts();
191
192 // Switch TRNG to programming mode
193 self.info.regs.mctl().modify(|_, w| w.prgm().set_bit());
194
195 self.enable_interrupts();
196
197 // Switch TRNG to Run Mode
198 self.info
199 .regs
200 .mctl()
201 .modify(|_, w| w.trng_acc().set_bit().prgm().clear_bit());
202 }
203
204 /// Generate a random u32
205 pub fn blocking_next_u32(&mut self) -> u32 {
206 let mut bytes = [0u8; 4];
207 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
208 u32::from_ne_bytes(bytes)
209 }
210
211 /// Generate a random u64
212 pub fn blocking_next_u64(&mut self) -> u64 {
213 let mut bytes = [0u8; 8];
214 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
215 u64::from_ne_bytes(bytes)
216 }
217
218 /// Fill a slice with random bytes.
219 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
220 block_on(self.async_fill_bytes(dest)).unwrap();
221 }
222}
223
224impl<'d> rand_core_06::RngCore for Rng<'d> {
225 fn next_u32(&mut self) -> u32 {
226 self.blocking_next_u32()
227 }
228
229 fn next_u64(&mut self) -> u64 {
230 self.blocking_next_u64()
231 }
232
233 fn fill_bytes(&mut self, dest: &mut [u8]) {
234 self.blocking_fill_bytes(dest);
235 }
236
237 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
238 self.blocking_fill_bytes(dest);
239 Ok(())
240 }
241}
242
243impl<'d> rand_core_06::CryptoRng for Rng<'d> {}
244
245impl<'d> rand_core_09::RngCore for Rng<'d> {
246 fn next_u32(&mut self) -> u32 {
247 self.blocking_next_u32()
248 }
249
250 fn next_u64(&mut self) -> u64 {
251 self.blocking_next_u64()
252 }
253
254 fn fill_bytes(&mut self, dest: &mut [u8]) {
255 self.blocking_fill_bytes(dest);
256 }
257}
258
259impl<'d> rand_core_09::CryptoRng for Rng<'d> {}
260
261struct Info {
262 regs: crate::pac::Trng,
263}
264
265trait SealedInstance {
266 fn info() -> Info;
267}
268
269/// RNG instance trait.
270#[allow(private_bounds)]
271pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {
272 /// Interrupt for this RNG instance.
273 type Interrupt: interrupt::typelevel::Interrupt;
274}
275
276impl Instance for peripherals::RNG {
277 type Interrupt = crate::interrupt::typelevel::RNG;
278}
279
280impl SealedInstance for peripherals::RNG {
281 fn info() -> Info {
282 // SAFETY: safe from single executor
283 Info {
284 regs: unsafe { crate::pac::Trng::steal() },
285 }
286 }
287}
diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs
index c68679d3e..f127609c8 100644
--- a/embassy-imxrt/src/time_driver.rs
+++ b/embassy-imxrt/src/time_driver.rs
@@ -336,6 +336,10 @@ impl OsTimer {
336 let alarm = self.alarms.borrow(cs); 336 let alarm = self.alarms.borrow(cs);
337 alarm.timestamp.set(timestamp); 337 alarm.timestamp.set(timestamp);
338 338
339 // Wait until we're allowed to write to MATCH_L/MATCH_H
340 // registers
341 while os().osevent_ctrl().read().match_wr_rdy().bit_is_set() {}
342
339 let t = self.now(); 343 let t = self.now();
340 if timestamp <= t { 344 if timestamp <= t {
341 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); 345 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
@@ -366,7 +370,8 @@ impl OsTimer {
366 fn on_interrupt(&self) { 370 fn on_interrupt(&self) {
367 critical_section::with(|cs| { 371 critical_section::with(|cs| {
368 if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() { 372 if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() {
369 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); 373 os().osevent_ctrl()
374 .modify(|_, w| w.ostimer_intena().clear_bit().ostimer_intrflag().set_bit());
370 self.trigger_alarm(cs); 375 self.trigger_alarm(cs);
371 } 376 }
372 }); 377 });