aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-imxrt')
-rw-r--r--embassy-imxrt/Cargo.toml6
-rw-r--r--embassy-imxrt/src/clocks.rs2
-rw-r--r--embassy-imxrt/src/crc.rs4
-rw-r--r--embassy-imxrt/src/dma.rs6
-rw-r--r--embassy-imxrt/src/flexcomm/mod.rs19
-rw-r--r--embassy-imxrt/src/flexcomm/spi.rs1011
-rw-r--r--embassy-imxrt/src/flexcomm/uart.rs4
-rw-r--r--embassy-imxrt/src/gpio.rs2
-rw-r--r--embassy-imxrt/src/iopctl.rs2
-rw-r--r--embassy-imxrt/src/lib.rs5
-rw-r--r--embassy-imxrt/src/rng.rs4
-rw-r--r--embassy-imxrt/src/time_driver.rs4
12 files changed, 1044 insertions, 25 deletions
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index 7561640dd..81377579b 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2name = "embassy-imxrt" 2name = "embassy-imxrt"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" 6description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller"
7keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] 7keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"]
@@ -103,5 +103,5 @@ document-features = "0.2.7"
103paste = "1.0" 103paste = "1.0"
104 104
105# PACs 105# PACs
106mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } 106mimxrt685s-pac = { version = "0.5.0", optional = true, features = ["rt", "critical-section"] }
107mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } 107mimxrt633s-pac = { version = "0.5.0", optional = true, features = ["rt", "critical-section"] }
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs
index 39c3e6238..22df2686f 100644
--- a/embassy-imxrt/src/clocks.rs
+++ b/embassy-imxrt/src/clocks.rs
@@ -1,5 +1,5 @@
1//! Clock configuration for the `RT6xx` 1//! Clock configuration for the `RT6xx`
2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{AtomicU8, AtomicU32, Ordering};
3 3
4use paste::paste; 4use paste::paste;
5 5
diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs
index 24d6ba5bd..d6f0419d0 100644
--- a/embassy-imxrt/src/crc.rs
+++ b/embassy-imxrt/src/crc.rs
@@ -2,9 +2,9 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use crate::clocks::{enable_and_reset, SysconPeripheral}; 5use crate::clocks::{SysconPeripheral, enable_and_reset};
6pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; 6pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial;
7use crate::{peripherals, Peri, PeripheralType}; 7use crate::{Peri, PeripheralType, peripherals};
8 8
9/// CRC driver. 9/// CRC driver.
10pub struct Crc<'d> { 10pub struct Crc<'d> {
diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs
index e141447f3..e71a27e0e 100644
--- a/embassy-imxrt/src/dma.rs
+++ b/embassy-imxrt/src/dma.rs
@@ -2,10 +2,10 @@
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{Ordering, compiler_fence};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; 8use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma0::channel::cfg::Periphreqen; 10use pac::dma0::channel::cfg::Periphreqen;
11use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width}; 11use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width};
@@ -14,7 +14,7 @@ use crate::clocks::enable_and_reset;
14use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
15use crate::peripherals::DMA0; 15use crate::peripherals::DMA0;
16use crate::sealed::Sealed; 16use crate::sealed::Sealed;
17use crate::{interrupt, pac, peripherals, BitIter}; 17use crate::{BitIter, interrupt, pac, peripherals};
18 18
19#[cfg(feature = "rt")] 19#[cfg(feature = "rt")]
20#[interrupt] 20#[interrupt]
diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs
index 4473c9a77..ed87c7fb4 100644
--- a/embassy-imxrt/src/flexcomm/mod.rs
+++ b/embassy-imxrt/src/flexcomm/mod.rs
@@ -1,14 +1,15 @@
1//! Implements Flexcomm interface wrapper for easier usage across modules 1//! Implements Flexcomm interface wrapper for easier usage across modules
2 2
3pub mod spi;
3pub mod uart; 4pub mod uart;
4 5
5use paste::paste; 6use paste::paste;
6 7
7use crate::clocks::{enable_and_reset, SysconPeripheral}; 8use crate::clocks::{SysconPeripheral, enable_and_reset};
8use crate::peripherals::{ 9use crate::peripherals::{
9 FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, 10 FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14, FLEXCOMM15,
10}; 11};
11use crate::{pac, PeripheralType}; 12use crate::{PeripheralType, pac};
12 13
13/// clock selection option 14/// clock selection option
14#[derive(Copy, Clone, Debug)] 15#[derive(Copy, Clone, Debug)]
@@ -223,9 +224,15 @@ macro_rules! into_mode {
223 } 224 }
224} 225}
225 226
226into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7); 227into_mode!(
227into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14); 228 usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7
228into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15); 229);
230into_mode!(
231 spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14
232);
233into_mode!(
234 i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15
235);
229 236
230into_mode!( 237into_mode!(
231 i2s_transmit, 238 i2s_transmit,
diff --git a/embassy-imxrt/src/flexcomm/spi.rs b/embassy-imxrt/src/flexcomm/spi.rs
new file mode 100644
index 000000000..9dd776ac7
--- /dev/null
+++ b/embassy-imxrt/src/flexcomm/spi.rs
@@ -0,0 +1,1011 @@
1//! Serial Peripheral Interface (SPI) driver.
2
3use core::future::{Future, poll_fn};
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::{Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10pub use embedded_hal_1::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
11use paste::paste;
12
13use crate::flexcomm::Clock;
14use crate::gpio::{AnyPin, GpioPin as Pin};
15use crate::interrupt;
16use crate::interrupt::typelevel::Interrupt;
17use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate};
18use crate::pac::spi0::cfg::{Cpha, Cpol};
19
20/// Driver move trait.
21#[allow(private_bounds)]
22pub trait IoMode: sealed::Sealed {}
23
24/// Blocking mode.
25pub struct Blocking;
26impl sealed::Sealed for Blocking {}
27impl IoMode for Blocking {}
28
29/// Async mode.
30pub struct Async;
31impl sealed::Sealed for Async {}
32impl IoMode for Async {}
33
34/// Spi errors.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37#[non_exhaustive]
38pub enum Error {
39 // No errors for now.
40}
41
42/// Spi driver.
43pub struct Spi<'a, M: IoMode> {
44 info: Info,
45 _phantom: PhantomData<&'a M>,
46}
47
48impl<'a> Spi<'a, Blocking> {
49 /// Create a SPI driver in blocking mode.
50 pub fn new_blocking<T: Instance>(
51 _inner: Peri<'a, T>,
52 sck: Peri<'a, impl SckPin<T> + 'a>,
53 mosi: Peri<'a, impl MosiPin<T> + 'a>,
54 miso: Peri<'a, impl MisoPin<T> + 'a>,
55 config: Config,
56 ) -> Self {
57 sck.as_sck();
58 mosi.as_mosi();
59 miso.as_miso();
60
61 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), Some(miso.into()), config)
62 }
63
64 /// Create a TX-only SPI driver in blocking mode.
65 pub fn new_blocking_txonly<T: Instance>(
66 _inner: Peri<'a, T>,
67 sck: Peri<'a, impl SckPin<T> + 'a>,
68 mosi: Peri<'a, impl MosiPin<T> + 'a>,
69 config: Config,
70 ) -> Self {
71 sck.as_sck();
72 mosi.as_mosi();
73
74 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), None, config)
75 }
76
77 /// Create an RX-only SPI driver in blocking mode.
78 pub fn new_blocking_rxonly<T: Instance>(
79 _inner: Peri<'a, T>,
80 sck: Peri<'a, impl SckPin<T> + 'a>,
81 miso: Peri<'a, impl MisoPin<T> + 'a>,
82 config: Config,
83 ) -> Self {
84 sck.as_sck();
85 miso.as_miso();
86
87 Self::new_inner(_inner, Some(sck.into()), None, Some(miso.into()), config)
88 }
89
90 /// Create an internal-loopback SPI driver in blocking mode.
91 ///
92 /// WARNING: This is only useful for testing as it doesn't use any
93 /// external pins.
94 pub fn new_blocking_loopback<T: Instance>(_inner: Peri<'a, T>, config: Config) -> Self {
95 Self::new_inner(_inner, None, None, None, config)
96 }
97}
98
99impl<'a, M: IoMode> Spi<'a, M> {
100 /// Read data from Spi blocking execution until done.
101 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
102 critical_section::with(|_| {
103 self.info
104 .regs
105 .fifostat()
106 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
107
108 for word in data.iter_mut() {
109 // wait until we have data in the RxFIFO.
110 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
111
112 self.info
113 .regs
114 .fifowr()
115 .write(|w| unsafe { w.txdata().bits(*word as u16).len().bits(7) });
116
117 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
118 }
119 });
120
121 self.flush()
122 }
123
124 /// Write data to Spi blocking execution until done.
125 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
126 critical_section::with(|_| {
127 self.info
128 .regs
129 .fifostat()
130 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
131
132 for (i, word) in data.iter().enumerate() {
133 // wait until we have space in the TxFIFO.
134 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
135
136 self.info.regs.fifowr().write(|w| {
137 unsafe { w.txdata().bits(*word as u16).len().bits(7) }
138 .rxignore()
139 .set_bit();
140
141 if i == data.len() - 1 {
142 w.eot().set_bit();
143 }
144
145 w
146 });
147 }
148 });
149
150 self.flush()
151 }
152
153 /// Transfer data to SPI blocking execution until done.
154 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
155 let len = read.len().max(write.len());
156
157 critical_section::with(|_| {
158 self.info
159 .regs
160 .fifostat()
161 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
162
163 for i in 0..len {
164 let wb = write.get(i).copied().unwrap_or(0);
165
166 // wait until we have space in the TxFIFO.
167 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
168
169 self.info.regs.fifowr().write(|w| {
170 unsafe { w.txdata().bits(wb as u16).len().bits(7) };
171
172 if i == len - 1 {
173 w.eot().set_bit();
174 }
175
176 w
177 });
178
179 // wait until we have data in the RxFIFO.
180 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
181
182 let rb = self.info.regs.fiford().read().rxdata().bits() as u8;
183
184 if let Some(r) = read.get_mut(i) {
185 *r = rb;
186 }
187 }
188 });
189
190 self.flush()
191 }
192
193 /// Transfer data in place to SPI blocking execution until done.
194 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
195 critical_section::with(|_| {
196 self.info
197 .regs
198 .fifostat()
199 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
200
201 for word in data {
202 // wait until we have space in the TxFIFO.
203 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
204 self.info
205 .regs
206 .fifowr()
207 .write(|w| unsafe { w.txdata().bits(*word as u16) });
208
209 // wait until we have data in the RxFIFO.
210 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
211 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
212 }
213 });
214
215 self.flush()
216 }
217
218 /// Block execution until Spi is done.
219 pub fn flush(&mut self) -> Result<(), Error> {
220 let regs = self.info.regs;
221 while regs.stat().read().mstidle().bit_is_clear() {}
222 Ok(())
223 }
224}
225
226impl<'a> Spi<'a, Async> {
227 /// Create a SPI driver in async mode.
228 pub fn new_async<T: Instance>(
229 _inner: Peri<'a, T>,
230 sck: Peri<'a, impl SckPin<T> + 'a>,
231 mosi: Peri<'a, impl MosiPin<T> + 'a>,
232 miso: Peri<'a, impl MisoPin<T> + 'a>,
233 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
234 config: Config,
235 ) -> Self {
236 sck.as_sck();
237 mosi.as_mosi();
238 miso.as_miso();
239
240 T::Interrupt::unpend();
241 unsafe { T::Interrupt::enable() };
242
243 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), Some(miso.into()), config)
244 }
245
246 /// Create a TX-only SPI driver in async mode.
247 pub fn new_async_txonly<T: Instance>(
248 _inner: Peri<'a, T>,
249 sck: Peri<'a, impl SckPin<T> + 'a>,
250 mosi: Peri<'a, impl MosiPin<T> + 'a>,
251 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
252 config: Config,
253 ) -> Self {
254 sck.as_sck();
255 mosi.as_mosi();
256
257 T::Interrupt::unpend();
258 unsafe { T::Interrupt::enable() };
259
260 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), None, config)
261 }
262
263 /// Create an RX-only SPI driver in async mode.
264 pub fn new_async_rxonly<T: Instance>(
265 _inner: Peri<'a, T>,
266 sck: Peri<'a, impl SckPin<T> + 'a>,
267 miso: Peri<'a, impl MisoPin<T> + 'a>,
268 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
269 config: Config,
270 ) -> Self {
271 sck.as_sck();
272 miso.as_miso();
273
274 T::Interrupt::unpend();
275 unsafe { T::Interrupt::enable() };
276
277 Self::new_inner(_inner, Some(sck.into()), None, Some(miso.into()), config)
278 }
279
280 /// Create an internal-loopback SPI driver in async mode.
281 ///
282 /// WARNING: This is only useful for testing as it doesn't use any
283 /// external pins.
284 pub fn new_async_loopback<T: Instance>(
285 _inner: Peri<'a, T>,
286 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
287 config: Config,
288 ) -> Self {
289 T::Interrupt::unpend();
290 unsafe { T::Interrupt::enable() };
291
292 Self::new_inner(_inner, None, None, None, config)
293 }
294
295 /// Read data from Spi async execution until done.
296 pub async fn async_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
297 critical_section::with(|_| {
298 self.info
299 .regs
300 .fifostat()
301 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
302 });
303
304 for word in data.iter_mut() {
305 // wait until we have data in the RxFIFO.
306 self.wait_for(
307 |me| {
308 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
309 Poll::Ready(())
310 } else {
311 Poll::Pending
312 }
313 },
314 |me| {
315 me.info
316 .regs
317 .fifointenset()
318 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
319 },
320 )
321 .await;
322
323 self.info
324 .regs
325 .fifowr()
326 .write(|w| unsafe { w.txdata().bits(*word as u16).len().bits(7) });
327
328 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
329 }
330
331 self.async_flush().await;
332
333 Ok(())
334 }
335
336 /// Write data to Spi async execution until done.
337 pub async fn async_write(&mut self, data: &[u8]) -> Result<(), Error> {
338 critical_section::with(|_| {
339 self.info
340 .regs
341 .fifostat()
342 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
343 });
344
345 for (i, word) in data.iter().enumerate() {
346 // wait until we have space in the TxFIFO.
347 self.wait_for(
348 |me| {
349 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
350 Poll::Ready(())
351 } else {
352 Poll::Pending
353 }
354 },
355 |me| {
356 me.info
357 .regs
358 .fifointenset()
359 .write(|w| w.txlvl().set_bit().txerr().set_bit());
360 },
361 )
362 .await;
363
364 self.info.regs.fifowr().write(|w| {
365 unsafe { w.txdata().bits(*word as u16).len().bits(7) }
366 .rxignore()
367 .set_bit();
368
369 if i == data.len() - 1 {
370 w.eot().set_bit();
371 }
372
373 w
374 });
375 }
376
377 self.async_flush().await;
378
379 Ok(())
380 }
381
382 /// Transfer data to SPI async execution until done.
383 pub async fn async_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
384 let len = read.len().max(write.len());
385
386 critical_section::with(|_| {
387 self.info
388 .regs
389 .fifostat()
390 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
391 });
392
393 for i in 0..len {
394 let wb = write.get(i).copied().unwrap_or(0);
395
396 // wait until we have space in the TxFIFO.
397 self.wait_for(
398 |me| {
399 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
400 Poll::Ready(())
401 } else {
402 Poll::Pending
403 }
404 },
405 |me| {
406 me.info.regs.fifotrig().write(|w| w.txlvlena().set_bit());
407 me.info
408 .regs
409 .fifointenset()
410 .write(|w| w.txlvl().set_bit().txerr().set_bit());
411 },
412 )
413 .await;
414
415 self.info.regs.fifowr().write(|w| {
416 unsafe { w.txdata().bits(wb as u16).len().bits(7) };
417
418 if i == len - 1 {
419 w.eot().set_bit();
420 }
421
422 w
423 });
424
425 // wait until we have data in the RxFIFO.
426 self.wait_for(
427 |me| {
428 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
429 Poll::Ready(())
430 } else {
431 Poll::Pending
432 }
433 },
434 |me| {
435 me.info.regs.fifotrig().write(|w| w.rxlvlena().set_bit());
436 me.info
437 .regs
438 .fifointenset()
439 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
440 },
441 )
442 .await;
443
444 let rb = self.info.regs.fiford().read().rxdata().bits() as u8;
445
446 if let Some(r) = read.get_mut(i) {
447 *r = rb;
448 }
449 }
450
451 self.async_flush().await;
452
453 Ok(())
454 }
455
456 /// Transfer data in place to SPI async execution until done.
457 pub async fn async_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
458 critical_section::with(|_| {
459 self.info
460 .regs
461 .fifostat()
462 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
463 });
464
465 for word in data {
466 // wait until we have space in the TxFIFO.
467 self.wait_for(
468 |me| {
469 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
470 Poll::Ready(())
471 } else {
472 Poll::Pending
473 }
474 },
475 |me| {
476 me.info
477 .regs
478 .fifointenset()
479 .write(|w| w.txlvl().set_bit().txerr().set_bit());
480 },
481 )
482 .await;
483
484 self.info
485 .regs
486 .fifowr()
487 .write(|w| unsafe { w.txdata().bits(*word as u16) });
488
489 // wait until we have data in the RxFIFO.
490 self.wait_for(
491 |me| {
492 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
493 Poll::Ready(())
494 } else {
495 Poll::Pending
496 }
497 },
498 |me| {
499 me.info
500 .regs
501 .fifointenset()
502 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
503 },
504 )
505 .await;
506
507 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
508 }
509
510 self.async_flush().await;
511
512 Ok(())
513 }
514
515 /// Async flush.
516 pub fn async_flush(&mut self) -> impl Future<Output = ()> + use<'_, 'a> {
517 self.wait_for(
518 |me| {
519 if me.info.regs.stat().read().mstidle().bit_is_set() {
520 Poll::Ready(())
521 } else {
522 Poll::Pending
523 }
524 },
525 |me| {
526 me.info.regs.intenset().write(|w| w.mstidleen().set_bit());
527 },
528 )
529 }
530
531 /// Calls `f` to check if we are ready or not.
532 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
533 fn wait_for<F, U, G>(&mut self, mut f: F, mut g: G) -> impl Future<Output = U> + use<'_, 'a, F, U, G>
534 where
535 F: FnMut(&mut Self) -> Poll<U>,
536 G: FnMut(&mut Self),
537 {
538 poll_fn(move |cx| {
539 // Register waker before checking condition, to ensure that wakes/interrupts
540 // aren't lost between f() and g()
541 self.info.waker.register(cx.waker());
542 let r = f(self);
543
544 if r.is_pending() {
545 g(self);
546 }
547
548 r
549 })
550 }
551}
552
553impl<'a, M: IoMode> Spi<'a, M> {
554 fn new_inner<T: Instance>(
555 _inner: Peri<'a, T>,
556 sck: Option<Peri<'a, AnyPin>>,
557 mosi: Option<Peri<'a, AnyPin>>,
558 miso: Option<Peri<'a, AnyPin>>,
559 config: Config,
560 ) -> Self {
561 // REVISIT: allow selecting from multiple clocks.
562 let clk = Self::clock(&config);
563
564 T::enable(clk);
565 T::into_spi();
566
567 Self::apply_config(T::info().regs, &config);
568
569 let info = T::info();
570 let regs = info.regs;
571
572 critical_section::with(|_| match (sck.is_some(), mosi.is_some(), miso.is_some()) {
573 (true, true, true) => {
574 regs.fifocfg().modify(|_, w| {
575 w.enabletx()
576 .set_bit()
577 .emptytx()
578 .set_bit()
579 .enablerx()
580 .set_bit()
581 .emptyrx()
582 .set_bit()
583 });
584 }
585 (true, false, true) => {
586 regs.fifocfg().modify(|_, w| {
587 w.enabletx()
588 .set_bit()
589 .emptytx()
590 .clear_bit()
591 .enablerx()
592 .set_bit()
593 .emptyrx()
594 .set_bit()
595 });
596 }
597 (true, true, false) => {
598 regs.fifocfg().modify(|_, w| {
599 w.enabletx()
600 .set_bit()
601 .emptytx()
602 .set_bit()
603 .enablerx()
604 .clear_bit()
605 .emptyrx()
606 .set_bit()
607 });
608 }
609 (false, _, _) => {
610 regs.fifocfg().modify(|_, w| {
611 w.enabletx()
612 .set_bit()
613 .emptytx()
614 .set_bit()
615 .enablerx()
616 .set_bit()
617 .emptyrx()
618 .set_bit()
619 });
620 regs.cfg().modify(|_, w| w.loop_().enabled());
621 }
622 _ => {}
623 });
624
625 Self {
626 info,
627 _phantom: PhantomData,
628 }
629 }
630
631 fn set_config(&mut self, config: &Config) {
632 Self::apply_config(self.info.regs, config);
633 }
634
635 fn clock(config: &Config) -> Clock {
636 const SFRO_CLOCK_SPEED_HZ: u32 = 16_000_000;
637
638 if config.frequency > SFRO_CLOCK_SPEED_HZ {
639 Clock::Ffro
640 } else {
641 Clock::Sfro
642 }
643 }
644
645 fn clock_frequency(clock: Clock) -> u32 {
646 match clock {
647 Clock::Sfro => 16_000_000,
648 Clock::Ffro => 48_000_000,
649 _ => unreachable!(),
650 }
651 }
652
653 fn apply_config(regs: &'static crate::pac::spi0::RegisterBlock, config: &Config) {
654 let polarity = if config.mode.polarity == Polarity::IdleLow {
655 Cpol::Low
656 } else {
657 Cpol::High
658 };
659
660 let phase = if config.mode.phase == Phase::CaptureOnFirstTransition {
661 Cpha::Change
662 } else {
663 Cpha::Capture
664 };
665
666 let clk = Self::clock(config);
667 let div = Self::clock_frequency(clk) / config.frequency - 1;
668
669 critical_section::with(|_| {
670 // disable SPI every time we need to modify configuration.
671 regs.cfg().modify(|_, w| w.enable().disabled());
672
673 regs.cfg().modify(|_, w| {
674 w.cpha()
675 .variant(phase)
676 .cpol()
677 .variant(polarity)
678 .loop_()
679 .disabled()
680 .master()
681 .master_mode()
682 });
683
684 regs.div().write(|w| unsafe { w.divval().bits(div as u16) });
685
686 regs.cfg().modify(|_, w| w.enable().enabled());
687 });
688 }
689}
690
691/// Spi config.
692#[derive(Clone)]
693pub struct Config {
694 /// Frequency in Hertz.
695 pub frequency: u32,
696 /// SPI operating mode.
697 pub mode: Mode,
698}
699
700impl Default for Config {
701 fn default() -> Self {
702 Self {
703 frequency: 1_000_000,
704 mode: MODE_0,
705 }
706 }
707}
708
709struct Info {
710 regs: &'static crate::pac::spi0::RegisterBlock,
711 waker: &'static AtomicWaker,
712}
713
714// SAFETY: safety for Send here is the same as the other accessors to
715// unsafe blocks: it must be done from a single executor context.
716//
717// This is a temporary workaround -- a better solution might be to
718// refactor Info to no longer maintain a reference to regs, but
719// instead look up the correct register set and then perform
720// operations within an unsafe block as we do for other peripherals
721unsafe impl Send for Info {}
722
723trait SealedInstance {
724 fn info() -> Info;
725}
726
727/// Spi interrupt handler.
728pub struct InterruptHandler<T: Instance> {
729 _phantom: PhantomData<T>,
730}
731
732impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
733 unsafe fn on_interrupt() {
734 let waker = T::info().waker;
735 let stat = T::info().regs.fifointstat().read();
736
737 if stat.perint().bit_is_set() {
738 T::info().regs.intenclr().write(|w| w.mstidle().clear_bit_by_one());
739 }
740
741 if stat.txlvl().bit_is_set() {
742 T::info().regs.fifointenclr().write(|w| w.txlvl().set_bit());
743 }
744
745 if stat.txerr().bit_is_set() {
746 T::info().regs.fifointenclr().write(|w| w.txerr().set_bit());
747 }
748
749 if stat.rxlvl().bit_is_set() {
750 T::info().regs.fifointenclr().write(|w| w.rxlvl().set_bit());
751 }
752
753 if stat.rxerr().bit_is_set() {
754 T::info().regs.fifointenclr().write(|w| w.rxerr().set_bit());
755 }
756
757 waker.wake();
758 }
759}
760
761/// Spi instance trait.
762#[allow(private_bounds)]
763pub trait Instance: crate::flexcomm::IntoSpi + SealedInstance + PeripheralType + 'static + Send {
764 /// Interrupt for this Spi instance.
765 type Interrupt: interrupt::typelevel::Interrupt;
766}
767
768macro_rules! impl_instance {
769 ($($n:expr),*) => {
770 $(
771 paste!{
772 impl SealedInstance for crate::peripherals::[<FLEXCOMM $n>] {
773 #[inline]
774 fn info() -> Info {
775 static WAKER: AtomicWaker = AtomicWaker::new();
776
777 Info {
778 regs: unsafe { &*crate::pac::[<Spi $n>]::ptr() },
779 waker: &WAKER,
780 }
781 }
782 }
783
784 impl Instance for crate::peripherals::[<FLEXCOMM $n>] {
785 type Interrupt = crate::interrupt::typelevel::[<FLEXCOMM $n>];
786 }
787 }
788 )*
789 }
790}
791
792impl_instance!(0, 1, 2, 3, 4, 5, 6, 7, 14);
793
794mod sealed {
795 /// Seal a trait
796 pub trait Sealed {}
797}
798
799impl<T: Pin> sealed::Sealed for T {}
800
801/// IO configuration trait for Spi clk
802pub trait SckPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
803 /// convert the pin to appropriate function for Spi clk usage.
804 fn as_sck(&self);
805}
806
807/// IO configuration trait for Spi mosi
808pub trait MosiPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
809 /// convert the pin to appropriate function for Spi mosi usage.
810 fn as_mosi(&self);
811}
812
813/// IO configuration trait for Spi miso
814pub trait MisoPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
815 /// convert the pin to appropriate function for Spi miso usage.
816 fn as_miso(&self);
817}
818
819macro_rules! impl_pin_trait {
820 ($fcn:ident, $mode:ident, $($pin:ident, $fn:ident),*) => {
821 paste! {
822 $(
823 impl [<$mode:camel Pin>]<crate::peripherals::$fcn> for crate::peripherals::$pin {
824 fn [<as_ $mode>](&self) {
825 // UM11147 table 530 pg 518
826 self.set_function(crate::iopctl::Function::$fn)
827 .set_pull(Pull::None)
828 .enable_input_buffer()
829 .set_slew_rate(SlewRate::Standard)
830 .set_drive_strength(DriveStrength::Normal)
831 .disable_analog_multiplex()
832 .set_drive_mode(DriveMode::PushPull)
833 .set_input_inverter(Inverter::Disabled);
834 }
835 }
836 )*
837 }
838 }
839}
840
841// FLEXCOMM0
842impl_pin_trait!(FLEXCOMM0, sck, PIO0_0, F1, PIO3_0, F5);
843impl_pin_trait!(FLEXCOMM0, miso, PIO0_1, F1, PIO3_1, F5);
844impl_pin_trait!(FLEXCOMM0, mosi, PIO0_2, F1, PIO3_2, F5);
845
846// FLEXCOMM1
847impl_pin_trait!(FLEXCOMM1, sck, PIO0_7, F1, PIO7_25, F1);
848impl_pin_trait!(FLEXCOMM1, miso, PIO0_8, F1, PIO7_26, F1);
849impl_pin_trait!(FLEXCOMM1, mosi, PIO0_9, F1, PIO7_28, F1);
850
851// FLEXCOMM2
852impl_pin_trait!(FLEXCOMM2, sck, PIO0_14, F1, PIO7_29, F5);
853impl_pin_trait!(FLEXCOMM2, miso, PIO0_15, F1, PIO7_30, F5);
854impl_pin_trait!(FLEXCOMM2, mosi, PIO0_16, F1, PIO7_31, F5);
855
856// FLEXCOMM3
857impl_pin_trait!(FLEXCOMM3, sck, PIO0_21, F1);
858impl_pin_trait!(FLEXCOMM3, miso, PIO0_22, F1);
859impl_pin_trait!(FLEXCOMM3, mosi, PIO0_23, F1);
860
861// FLEXCOMM4
862impl_pin_trait!(FLEXCOMM4, sck, PIO0_28, F1);
863impl_pin_trait!(FLEXCOMM4, miso, PIO0_29, F1);
864impl_pin_trait!(FLEXCOMM4, mosi, PIO0_30, F1);
865
866// FLEXCOMM5
867impl_pin_trait!(FLEXCOMM5, sck, PIO1_3, F1, PIO3_15, F5);
868impl_pin_trait!(FLEXCOMM5, miso, PIO1_4, F1, PIO3_16, F5);
869impl_pin_trait!(FLEXCOMM5, mosi, PIO1_5, F1, PIO3_17, F5);
870
871// FLEXCOMM6
872impl_pin_trait!(FLEXCOMM6, sck, PIO3_25, F1);
873impl_pin_trait!(FLEXCOMM6, miso, PIO3_26, F1);
874impl_pin_trait!(FLEXCOMM6, mosi, PIO3_27, F1);
875
876// FLEXCOMM7
877impl_pin_trait!(FLEXCOMM7, sck, PIO4_0, F1);
878impl_pin_trait!(FLEXCOMM7, miso, PIO4_1, F1);
879impl_pin_trait!(FLEXCOMM7, mosi, PIO4_2, F1);
880
881// FLEXCOMM14
882impl_pin_trait!(FLEXCOMM14, sck, PIO1_11, F1);
883impl_pin_trait!(FLEXCOMM14, miso, PIO1_12, F1);
884impl_pin_trait!(FLEXCOMM14, mosi, PIO1_13, F1);
885
886/// Spi Tx DMA trait.
887#[allow(private_bounds)]
888pub trait TxDma<T: Instance>: crate::dma::Channel {}
889
890/// Spi Rx DMA trait.
891#[allow(private_bounds)]
892pub trait RxDma<T: Instance>: crate::dma::Channel {}
893
894macro_rules! impl_dma {
895 ($fcn:ident, $mode:ident, $dma:ident) => {
896 paste! {
897 impl [<$mode Dma>]<crate::peripherals::$fcn> for crate::peripherals::$dma {}
898 }
899 };
900}
901
902impl_dma!(FLEXCOMM0, Rx, DMA0_CH0);
903impl_dma!(FLEXCOMM0, Tx, DMA0_CH1);
904
905impl_dma!(FLEXCOMM1, Rx, DMA0_CH2);
906impl_dma!(FLEXCOMM1, Tx, DMA0_CH3);
907
908impl_dma!(FLEXCOMM2, Rx, DMA0_CH4);
909impl_dma!(FLEXCOMM2, Tx, DMA0_CH5);
910
911impl_dma!(FLEXCOMM3, Rx, DMA0_CH6);
912impl_dma!(FLEXCOMM3, Tx, DMA0_CH7);
913
914impl_dma!(FLEXCOMM4, Rx, DMA0_CH8);
915impl_dma!(FLEXCOMM4, Tx, DMA0_CH9);
916
917impl_dma!(FLEXCOMM5, Rx, DMA0_CH10);
918impl_dma!(FLEXCOMM5, Tx, DMA0_CH11);
919
920impl_dma!(FLEXCOMM6, Rx, DMA0_CH12);
921impl_dma!(FLEXCOMM6, Tx, DMA0_CH13);
922
923impl_dma!(FLEXCOMM7, Rx, DMA0_CH14);
924impl_dma!(FLEXCOMM7, Tx, DMA0_CH15);
925
926impl_dma!(FLEXCOMM14, Rx, DMA0_CH16);
927impl_dma!(FLEXCOMM14, Tx, DMA0_CH17);
928
929// ==============================
930
931impl<'d, M: IoMode> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, M> {
932 type Error = Error;
933 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
934 self.blocking_transfer_in_place(words)?;
935 Ok(words)
936 }
937}
938
939impl<'d, M: IoMode> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, M> {
940 type Error = Error;
941
942 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
943 self.blocking_write(words)
944 }
945}
946
947impl embedded_hal_1::spi::Error for Error {
948 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
949 match *self {}
950 }
951}
952
953impl<'d, M: IoMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> {
954 type Error = Error;
955}
956
957impl<'d, M: IoMode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, M> {
958 fn flush(&mut self) -> Result<(), Self::Error> {
959 self.flush()
960 }
961
962 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
963 self.blocking_read(words)
964 }
965
966 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
967 self.blocking_write(words)
968 }
969
970 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
971 self.blocking_transfer(read, write)
972 }
973
974 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
975 self.blocking_transfer_in_place(words)
976 }
977}
978
979impl<'d> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, Async> {
980 async fn flush(&mut self) -> Result<(), Self::Error> {
981 self.async_flush().await;
982
983 Ok(())
984 }
985
986 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
987 self.async_write(words).await
988 }
989
990 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
991 self.async_read(words).await
992 }
993
994 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
995 self.async_transfer(read, write).await
996 }
997
998 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
999 self.async_transfer_in_place(words).await
1000 }
1001}
1002
1003impl<'d, M: IoMode> SetConfig for Spi<'d, M> {
1004 type Config = Config;
1005 type ConfigError = ();
1006 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1007 self.set_config(config);
1008
1009 Ok(())
1010 }
1011}
diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs
index 230b30d43..2b759ba84 100644
--- a/embassy-imxrt/src/flexcomm/uart.rs
+++ b/embassy-imxrt/src/flexcomm/uart.rs
@@ -2,10 +2,10 @@
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; 5use core::sync::atomic::{AtomicU8, Ordering, compiler_fence};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_futures::select::{select, Either}; 8use embassy_futures::select::{Either, select};
9use embassy_hal_internal::drop::OnDrop; 9use embassy_hal_internal::drop::OnDrop;
10use embassy_hal_internal::{Peri, PeripheralType}; 10use embassy_hal_internal::{Peri, PeripheralType};
11use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs
index e62fde8b1..4a0608e76 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, BitIter, Peri, PeripheralType}; 16use crate::{BitIter, Peri, PeripheralType, interrupt, peripherals};
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;
diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs
index a3b8b14d6..805bf2f1b 100644
--- a/embassy-imxrt/src/iopctl.rs
+++ b/embassy-imxrt/src/iopctl.rs
@@ -2,7 +2,7 @@
2//! 2//!
3//! Also known as IO Pin Configuration (IOCON) 3//! Also known as IO Pin Configuration (IOCON)
4 4
5use crate::pac::{iopctl, Iopctl}; 5use crate::pac::{Iopctl, iopctl};
6 6
7// A generic pin of any type. 7// A generic pin of any type.
8// 8//
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index a3437c655..643dd0c8a 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -1,5 +1,6 @@
1#![no_std] 1#![no_std]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
3#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
4#![warn(missing_docs)] 5#![warn(missing_docs)]
5 6
@@ -39,7 +40,7 @@ pub use chip::interrupts::*;
39pub use chip::pac; 40pub use chip::pac;
40#[cfg(not(feature = "unstable-pac"))] 41#[cfg(not(feature = "unstable-pac"))]
41pub(crate) use chip::pac; 42pub(crate) use chip::pac;
42pub use chip::{peripherals, Peripherals}; 43pub use chip::{Peripherals, peripherals};
43pub use embassy_hal_internal::{Peri, PeripheralType}; 44pub use embassy_hal_internal::{Peri, PeripheralType};
44 45
45#[cfg(feature = "rt")] 46#[cfg(feature = "rt")]
@@ -74,7 +75,7 @@ macro_rules! bind_interrupts {
74 75
75 $( 76 $(
76 #[allow(non_snake_case)] 77 #[allow(non_snake_case)]
77 #[no_mangle] 78 #[unsafe(no_mangle)]
78 unsafe extern "C" fn $irq() { 79 unsafe extern "C" fn $irq() {
79 unsafe { 80 unsafe {
80 $( 81 $(
diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs
index 75f243df9..094418e41 100644
--- a/embassy-imxrt/src/rng.rs
+++ b/embassy-imxrt/src/rng.rs
@@ -7,9 +7,9 @@ use core::task::Poll;
7use embassy_futures::block_on; 7use embassy_futures::block_on;
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::clocks::{enable_and_reset, SysconPeripheral}; 10use crate::clocks::{SysconPeripheral, enable_and_reset};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, peripherals, Peri, PeripheralType}; 12use crate::{Peri, PeripheralType, interrupt, peripherals};
13 13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 15
diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs
index f127609c8..fbd935b70 100644
--- a/embassy-imxrt/src/time_driver.rs
+++ b/embassy-imxrt/src/time_driver.rs
@@ -1,11 +1,11 @@
1//! Time Driver. 1//! Time Driver.
2use core::cell::{Cell, RefCell}; 2use core::cell::{Cell, RefCell};
3#[cfg(feature = "time-driver-rtc")] 3#[cfg(feature = "time-driver-rtc")]
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
5 5
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::blocking_mutex::Mutex; 7use embassy_sync::blocking_mutex::Mutex;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_time_driver::Driver; 9use embassy_time_driver::Driver;
10use embassy_time_queue_utils::Queue; 10use embassy_time_queue_utils::Queue;
11 11