diff options
| -rw-r--r-- | docs/pages/imxrt.adoc | 2 | ||||
| -rw-r--r-- | embassy-imxrt/src/dma.rs | 418 | ||||
| -rw-r--r-- | embassy-imxrt/src/flexcomm/mod.rs | 252 | ||||
| -rw-r--r-- | embassy-imxrt/src/flexcomm/uart.rs | 1230 | ||||
| -rw-r--r-- | embassy-imxrt/src/gpio.rs | 20 | ||||
| -rw-r--r-- | embassy-imxrt/src/lib.rs | 26 | ||||
| -rw-r--r-- | examples/mimxrt6/src/bin/uart-async.rs | 87 | ||||
| -rw-r--r-- | examples/mimxrt6/src/bin/uart.rs | 55 |
8 files changed, 2069 insertions, 21 deletions
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc index bbd65e494..87867e1e0 100644 --- a/docs/pages/imxrt.adoc +++ b/docs/pages/imxrt.adoc | |||
| @@ -10,5 +10,7 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb | |||
| 10 | The following peripherals have a HAL implementation at present | 10 | The following peripherals have a HAL implementation at present |
| 11 | 11 | ||
| 12 | * CRC | 12 | * CRC |
| 13 | * DMA | ||
| 13 | * GPIO | 14 | * GPIO |
| 14 | * RNG | 15 | * RNG |
| 16 | * UART | ||
diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs new file mode 100644 index 000000000..e141447f3 --- /dev/null +++ b/embassy-imxrt/src/dma.rs | |||
| @@ -0,0 +1,418 @@ | |||
| 1 | //! DMA driver. | ||
| 2 | |||
| 3 | use core::future::Future; | ||
| 4 | use core::pin::Pin; | ||
| 5 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 6 | use core::task::{Context, Poll}; | ||
| 7 | |||
| 8 | use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | use pac::dma0::channel::cfg::Periphreqen; | ||
| 11 | use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width}; | ||
| 12 | |||
| 13 | use crate::clocks::enable_and_reset; | ||
| 14 | use crate::interrupt::InterruptExt; | ||
| 15 | use crate::peripherals::DMA0; | ||
| 16 | use crate::sealed::Sealed; | ||
| 17 | use crate::{interrupt, pac, peripherals, BitIter}; | ||
| 18 | |||
| 19 | #[cfg(feature = "rt")] | ||
| 20 | #[interrupt] | ||
| 21 | fn 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) | ||
| 45 | pub(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. | ||
| 71 | pub 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. | ||
| 89 | pub 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. | ||
| 107 | pub 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 | |||
| 126 | fn 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"] | ||
| 200 | pub struct Transfer<'a, C: Channel> { | ||
| 201 | channel: Peri<'a, C>, | ||
| 202 | } | ||
| 203 | |||
| 204 | impl<'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 | |||
| 239 | impl<'a, C: Channel> Drop for Transfer<'a, C> { | ||
| 240 | fn drop(&mut self) { | ||
| 241 | self.abort(); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} | ||
| 246 | impl<'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)] | ||
| 265 | struct Descriptor { | ||
| 266 | reserved: u32, | ||
| 267 | src: u32, | ||
| 268 | dest: u32, | ||
| 269 | link: u32, | ||
| 270 | } | ||
| 271 | |||
| 272 | impl 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))] | ||
| 284 | struct Descriptors { | ||
| 285 | descs: [Descriptor; CHANNEL_COUNT], | ||
| 286 | } | ||
| 287 | |||
| 288 | impl Descriptors { | ||
| 289 | const fn new() -> Self { | ||
| 290 | Self { | ||
| 291 | descs: [const { Descriptor::new() }; CHANNEL_COUNT], | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | static mut DESCRIPTORS: Descriptors = Descriptors::new(); | ||
| 297 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; | ||
| 298 | pub(crate) const CHANNEL_COUNT: usize = 33; | ||
| 299 | |||
| 300 | /// DMA channel interface. | ||
| 301 | #[allow(private_bounds)] | ||
| 302 | pub 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)] | ||
| 314 | pub trait Word: Sealed { | ||
| 315 | /// Transfer width. | ||
| 316 | fn width() -> Width; | ||
| 317 | |||
| 318 | /// Size in bytes for the width. | ||
| 319 | fn size() -> isize; | ||
| 320 | } | ||
| 321 | |||
| 322 | impl Sealed for u8 {} | ||
| 323 | impl Word for u8 { | ||
| 324 | fn width() -> Width { | ||
| 325 | Width::Bit8 | ||
| 326 | } | ||
| 327 | |||
| 328 | fn size() -> isize { | ||
| 329 | 1 | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | impl Sealed for u16 {} | ||
| 334 | impl Word for u16 { | ||
| 335 | fn width() -> Width { | ||
| 336 | Width::Bit16 | ||
| 337 | } | ||
| 338 | |||
| 339 | fn size() -> isize { | ||
| 340 | 2 | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | impl Sealed for u32 {} | ||
| 345 | impl 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. | ||
| 356 | pub struct AnyChannel { | ||
| 357 | number: u8, | ||
| 358 | } | ||
| 359 | |||
| 360 | impl_peripheral!(AnyChannel); | ||
| 361 | |||
| 362 | impl Sealed for AnyChannel {} | ||
| 363 | impl Channel for AnyChannel { | ||
| 364 | fn number(&self) -> u8 { | ||
| 365 | self.number | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | macro_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 | |||
| 386 | channel!(DMA0_CH0, 0); | ||
| 387 | channel!(DMA0_CH1, 1); | ||
| 388 | channel!(DMA0_CH2, 2); | ||
| 389 | channel!(DMA0_CH3, 3); | ||
| 390 | channel!(DMA0_CH4, 4); | ||
| 391 | channel!(DMA0_CH5, 5); | ||
| 392 | channel!(DMA0_CH6, 6); | ||
| 393 | channel!(DMA0_CH7, 7); | ||
| 394 | channel!(DMA0_CH8, 8); | ||
| 395 | channel!(DMA0_CH9, 9); | ||
| 396 | channel!(DMA0_CH10, 10); | ||
| 397 | channel!(DMA0_CH11, 11); | ||
| 398 | channel!(DMA0_CH12, 12); | ||
| 399 | channel!(DMA0_CH13, 13); | ||
| 400 | channel!(DMA0_CH14, 14); | ||
| 401 | channel!(DMA0_CH15, 15); | ||
| 402 | channel!(DMA0_CH16, 16); | ||
| 403 | channel!(DMA0_CH17, 17); | ||
| 404 | channel!(DMA0_CH18, 18); | ||
| 405 | channel!(DMA0_CH19, 19); | ||
| 406 | channel!(DMA0_CH20, 20); | ||
| 407 | channel!(DMA0_CH21, 21); | ||
| 408 | channel!(DMA0_CH22, 22); | ||
| 409 | channel!(DMA0_CH23, 23); | ||
| 410 | channel!(DMA0_CH24, 24); | ||
| 411 | channel!(DMA0_CH25, 25); | ||
| 412 | channel!(DMA0_CH26, 26); | ||
| 413 | channel!(DMA0_CH27, 27); | ||
| 414 | channel!(DMA0_CH28, 28); | ||
| 415 | channel!(DMA0_CH29, 29); | ||
| 416 | channel!(DMA0_CH30, 30); | ||
| 417 | channel!(DMA0_CH31, 31); | ||
| 418 | channel!(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 | |||
| 3 | pub mod uart; | ||
| 4 | |||
| 5 | use paste::paste; | ||
| 6 | |||
| 7 | use crate::clocks::{enable_and_reset, SysconPeripheral}; | ||
| 8 | use crate::peripherals::{ | ||
| 9 | FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, | ||
| 10 | }; | ||
| 11 | use crate::{pac, PeripheralType}; | ||
| 12 | |||
| 13 | /// clock selection option | ||
| 14 | #[derive(Copy, Clone, Debug)] | ||
| 15 | pub 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 | ||
| 45 | mod 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 | ||
| 51 | pub(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 | |||
| 59 | macro_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 | |||
| 114 | impl_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 | ||
| 118 | impl sealed::Sealed for crate::peripherals::FLEXCOMM14 {} | ||
| 119 | |||
| 120 | impl 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 | ||
| 161 | impl sealed::Sealed for crate::peripherals::FLEXCOMM15 {} | ||
| 162 | |||
| 163 | impl 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 | |||
| 201 | macro_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 | |||
| 226 | into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7); | ||
| 227 | into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14); | ||
| 228 | into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15); | ||
| 229 | |||
| 230 | into_mode!( | ||
| 231 | i2s_transmit, | ||
| 232 | FLEXCOMM0, | ||
| 233 | FLEXCOMM1, | ||
| 234 | FLEXCOMM2, | ||
| 235 | FLEXCOMM3, | ||
| 236 | FLEXCOMM4, | ||
| 237 | FLEXCOMM5, | ||
| 238 | FLEXCOMM6, | ||
| 239 | FLEXCOMM7 | ||
| 240 | ); | ||
| 241 | |||
| 242 | into_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 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::marker::PhantomData; | ||
| 5 | use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; | ||
| 6 | use core::task::Poll; | ||
| 7 | |||
| 8 | use embassy_futures::select::{select, Either}; | ||
| 9 | use embassy_hal_internal::drop::OnDrop; | ||
| 10 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | use paste::paste; | ||
| 13 | |||
| 14 | use crate::dma::AnyChannel; | ||
| 15 | use crate::flexcomm::Clock; | ||
| 16 | use crate::gpio::{AnyPin, GpioPin as Pin}; | ||
| 17 | use crate::interrupt::typelevel::Interrupt; | ||
| 18 | use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate}; | ||
| 19 | use crate::pac::usart0::cfg::{Clkpol, Datalen, Loop, Paritysel as Parity, Stoplen, Syncen, Syncmst}; | ||
| 20 | use crate::pac::usart0::ctl::Cc; | ||
| 21 | use crate::sealed::Sealed; | ||
| 22 | use crate::{dma, interrupt}; | ||
| 23 | |||
| 24 | /// Driver move trait. | ||
| 25 | #[allow(private_bounds)] | ||
| 26 | pub trait Mode: Sealed {} | ||
| 27 | |||
| 28 | /// Blocking mode. | ||
| 29 | pub struct Blocking; | ||
| 30 | impl Sealed for Blocking {} | ||
| 31 | impl Mode for Blocking {} | ||
| 32 | |||
| 33 | /// Async mode. | ||
| 34 | pub struct Async; | ||
| 35 | impl Sealed for Async {} | ||
| 36 | impl Mode for Async {} | ||
| 37 | |||
| 38 | /// Uart driver. | ||
| 39 | pub struct Uart<'a, M: Mode> { | ||
| 40 | tx: UartTx<'a, M>, | ||
| 41 | rx: UartRx<'a, M>, | ||
| 42 | } | ||
| 43 | |||
| 44 | /// Uart TX driver. | ||
| 45 | pub 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. | ||
| 52 | pub 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)] | ||
| 60 | pub 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 | |||
| 83 | impl 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))] | ||
| 104 | pub 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>` | ||
| 139 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 140 | |||
| 141 | impl<'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 | |||
| 153 | impl<'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 | |||
| 179 | impl<'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 | |||
| 254 | impl<'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 | |||
| 266 | impl<'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 | |||
| 292 | impl<'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 | |||
| 304 | impl 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 | |||
| 363 | impl<'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 | |||
| 517 | impl<'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 | |||
| 572 | impl<'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 | |||
| 700 | impl<'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 | |||
| 789 | impl<'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 | |||
| 863 | impl 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 | |||
| 877 | impl 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 | |||
| 897 | impl 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 | |||
| 909 | impl 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 | |||
| 917 | impl 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 | |||
| 929 | impl 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 | |||
| 941 | impl 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 | |||
| 953 | impl embedded_hal_nb::serial::ErrorType for UartRx<'_, Blocking> { | ||
| 954 | type Error = Error; | ||
| 955 | } | ||
| 956 | |||
| 957 | impl embedded_hal_nb::serial::ErrorType for UartTx<'_, Blocking> { | ||
| 958 | type Error = Error; | ||
| 959 | } | ||
| 960 | |||
| 961 | impl embedded_hal_nb::serial::ErrorType for Uart<'_, Blocking> { | ||
| 962 | type Error = Error; | ||
| 963 | } | ||
| 964 | |||
| 965 | impl 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 | |||
| 977 | impl 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 | |||
| 995 | impl 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 | |||
| 1001 | impl 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 | |||
| 1011 | struct Info { | ||
| 1012 | regs: &'static crate::pac::usart0::RegisterBlock, | ||
| 1013 | index: usize, | ||
| 1014 | refcnt: AtomicU8, | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | trait SealedInstance { | ||
| 1018 | fn info() -> Info; | ||
| 1019 | fn index() -> usize; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /// UART interrupt handler. | ||
| 1023 | pub struct InterruptHandler<T: Instance> { | ||
| 1024 | _phantom: PhantomData<T>, | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | const UART_COUNT: usize = 8; | ||
| 1028 | static UART_WAKERS: [AtomicWaker; UART_COUNT] = [const { AtomicWaker::new() }; UART_COUNT]; | ||
| 1029 | |||
| 1030 | impl<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)] | ||
| 1062 | pub trait Instance: crate::flexcomm::IntoUsart + SealedInstance + PeripheralType + 'static + Send { | ||
| 1063 | /// Interrupt for this UART instance. | ||
| 1064 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | macro_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 | |||
| 1094 | impl_instance!(0, 1, 2, 3, 4, 5, 6, 7); | ||
| 1095 | |||
| 1096 | impl<T: Pin> Sealed for T {} | ||
| 1097 | |||
| 1098 | /// io configuration trait for Uart Tx configuration | ||
| 1099 | pub 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 | ||
| 1105 | pub 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 | ||
| 1111 | pub 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 | ||
| 1117 | pub 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 | |||
| 1122 | macro_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 | ||
| 1145 | impl_pin_trait!(FLEXCOMM0, tx, PIO0_1, F1, PIO3_1, F5); | ||
| 1146 | impl_pin_trait!(FLEXCOMM0, rx, PIO0_2, F1, PIO3_2, F5); | ||
| 1147 | impl_pin_trait!(FLEXCOMM0, cts, PIO0_3, F1, PIO3_3, F5); | ||
| 1148 | impl_pin_trait!(FLEXCOMM0, rts, PIO0_4, F1, PIO3_4, F5); | ||
| 1149 | |||
| 1150 | // FLEXCOMM1 | ||
| 1151 | impl_pin_trait!(FLEXCOMM1, tx, PIO0_8, F1, PIO7_26, F1); | ||
| 1152 | impl_pin_trait!(FLEXCOMM1, rx, PIO0_9, F1, PIO7_27, F1); | ||
| 1153 | impl_pin_trait!(FLEXCOMM1, cts, PIO0_10, F1, PIO7_28, F1); | ||
| 1154 | impl_pin_trait!(FLEXCOMM1, rts, PIO0_11, F1, PIO7_29, F1); | ||
| 1155 | |||
| 1156 | // FLEXCOMM2 | ||
| 1157 | impl_pin_trait!(FLEXCOMM2, tx, PIO0_15, F1, PIO7_30, F5); | ||
| 1158 | impl_pin_trait!(FLEXCOMM2, rx, PIO0_16, F1, PIO7_31, F5); | ||
| 1159 | impl_pin_trait!(FLEXCOMM2, cts, PIO0_17, F1, PIO4_8, F5); | ||
| 1160 | impl_pin_trait!(FLEXCOMM2, rts, PIO0_18, F1); | ||
| 1161 | |||
| 1162 | // FLEXCOMM3 | ||
| 1163 | impl_pin_trait!(FLEXCOMM3, tx, PIO0_22, F1); | ||
| 1164 | impl_pin_trait!(FLEXCOMM3, rx, PIO0_23, F1); | ||
| 1165 | impl_pin_trait!(FLEXCOMM3, cts, PIO0_24, F1); | ||
| 1166 | impl_pin_trait!(FLEXCOMM3, rts, PIO0_25, F1); | ||
| 1167 | |||
| 1168 | // FLEXCOMM4 | ||
| 1169 | impl_pin_trait!(FLEXCOMM4, tx, PIO0_29, F1); | ||
| 1170 | impl_pin_trait!(FLEXCOMM4, rx, PIO0_30, F1); | ||
| 1171 | impl_pin_trait!(FLEXCOMM4, cts, PIO0_31, F1); | ||
| 1172 | impl_pin_trait!(FLEXCOMM4, rts, PIO1_0, F1); | ||
| 1173 | |||
| 1174 | // FLEXCOMM5 | ||
| 1175 | impl_pin_trait!(FLEXCOMM5, tx, PIO1_4, F1, PIO3_16, F5); | ||
| 1176 | impl_pin_trait!(FLEXCOMM5, rx, PIO1_5, F1, PIO3_17, F5); | ||
| 1177 | impl_pin_trait!(FLEXCOMM5, cts, PIO1_6, F1, PIO3_18, F5); | ||
| 1178 | impl_pin_trait!(FLEXCOMM5, rts, PIO1_7, F1, PIO3_23, F5); | ||
| 1179 | |||
| 1180 | // FLEXCOMM6 | ||
| 1181 | impl_pin_trait!(FLEXCOMM6, tx, PIO3_26, F1); | ||
| 1182 | impl_pin_trait!(FLEXCOMM6, rx, PIO3_27, F1); | ||
| 1183 | impl_pin_trait!(FLEXCOMM6, cts, PIO3_28, F1); | ||
| 1184 | impl_pin_trait!(FLEXCOMM6, rts, PIO3_29, F1); | ||
| 1185 | |||
| 1186 | // FLEXCOMM7 | ||
| 1187 | impl_pin_trait!(FLEXCOMM7, tx, PIO4_1, F1); | ||
| 1188 | impl_pin_trait!(FLEXCOMM7, rx, PIO4_2, F1); | ||
| 1189 | impl_pin_trait!(FLEXCOMM7, cts, PIO4_3, F1); | ||
| 1190 | impl_pin_trait!(FLEXCOMM7, rts, PIO4_4, F1); | ||
| 1191 | |||
| 1192 | /// UART Tx DMA trait. | ||
| 1193 | #[allow(private_bounds)] | ||
| 1194 | pub trait TxDma<T: Instance>: crate::dma::Channel {} | ||
| 1195 | |||
| 1196 | /// UART Rx DMA trait. | ||
| 1197 | #[allow(private_bounds)] | ||
| 1198 | pub trait RxDma<T: Instance>: crate::dma::Channel {} | ||
| 1199 | |||
| 1200 | macro_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 | |||
| 1208 | impl_dma!(FLEXCOMM0, Rx, DMA0_CH0); | ||
| 1209 | impl_dma!(FLEXCOMM0, Tx, DMA0_CH1); | ||
| 1210 | |||
| 1211 | impl_dma!(FLEXCOMM1, Rx, DMA0_CH2); | ||
| 1212 | impl_dma!(FLEXCOMM1, Tx, DMA0_CH3); | ||
| 1213 | |||
| 1214 | impl_dma!(FLEXCOMM2, Rx, DMA0_CH4); | ||
| 1215 | impl_dma!(FLEXCOMM2, Tx, DMA0_CH5); | ||
| 1216 | |||
| 1217 | impl_dma!(FLEXCOMM3, Rx, DMA0_CH6); | ||
| 1218 | impl_dma!(FLEXCOMM3, Tx, DMA0_CH7); | ||
| 1219 | |||
| 1220 | impl_dma!(FLEXCOMM4, Rx, DMA0_CH8); | ||
| 1221 | impl_dma!(FLEXCOMM4, Tx, DMA0_CH9); | ||
| 1222 | |||
| 1223 | impl_dma!(FLEXCOMM5, Rx, DMA0_CH10); | ||
| 1224 | impl_dma!(FLEXCOMM5, Tx, DMA0_CH11); | ||
| 1225 | |||
| 1226 | impl_dma!(FLEXCOMM6, Rx, DMA0_CH12); | ||
| 1227 | impl_dma!(FLEXCOMM6, Tx, DMA0_CH13); | ||
| 1228 | |||
| 1229 | impl_dma!(FLEXCOMM7, Rx, DMA0_CH14); | ||
| 1230 | impl_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; | |||
| 13 | use crate::iopctl::IopctlPin; | 13 | use crate::iopctl::IopctlPin; |
| 14 | pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; | 14 | pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; |
| 15 | use crate::sealed::Sealed; | 15 | use crate::sealed::Sealed; |
| 16 | use crate::{interrupt, peripherals, Peri, PeripheralType}; | 16 | use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType}; |
| 17 | 17 | ||
| 18 | // This should be unique per IMXRT package | 18 | // This should be unique per IMXRT package |
| 19 | const PORT_COUNT: usize = 8; | 19 | const PORT_COUNT: usize = 8; |
| @@ -64,24 +64,6 @@ fn GPIO_INTA() { | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | #[cfg(feature = "rt")] | 66 | #[cfg(feature = "rt")] |
| 67 | struct BitIter(u32); | ||
| 68 | |||
| 69 | #[cfg(feature = "rt")] | ||
| 70 | impl 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")] | ||
| 85 | fn irq_handler(port_wakers: &[Option<&PortWaker>]) { | 67 | fn irq_handler(port_wakers: &[Option<&PortWaker>]) { |
| 86 | let reg = unsafe { crate::pac::Gpio::steal() }; | 68 | let reg = unsafe { crate::pac::Gpio::steal() }; |
| 87 | 69 | ||
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index b1183d8fc..ad0d9e21c 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs | |||
| @@ -19,6 +19,8 @@ pub(crate) mod fmt; | |||
| 19 | 19 | ||
| 20 | pub mod clocks; | 20 | pub mod clocks; |
| 21 | pub mod crc; | 21 | pub mod crc; |
| 22 | pub mod dma; | ||
| 23 | pub mod flexcomm; | ||
| 22 | pub mod gpio; | 24 | pub mod gpio; |
| 23 | pub mod iopctl; | 25 | pub mod iopctl; |
| 24 | pub mod rng; | 26 | pub mod rng; |
| @@ -129,14 +131,16 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 129 | // before doing anything important. | 131 | // before doing anything important. |
| 130 | let peripherals = Peripherals::take(); | 132 | let peripherals = Peripherals::take(); |
| 131 | 133 | ||
| 134 | #[cfg(feature = "_time-driver")] | ||
| 135 | time_driver::init(config.time_interrupt_priority); | ||
| 136 | |||
| 132 | unsafe { | 137 | unsafe { |
| 133 | if let Err(e) = clocks::init(config.clocks) { | 138 | if let Err(e) = clocks::init(config.clocks) { |
| 134 | error!("unable to initialize Clocks for reason: {:?}", e); | 139 | error!("unable to initialize Clocks for reason: {:?}", e); |
| 135 | // Panic here? | 140 | // Panic here? |
| 136 | } | 141 | } |
| 142 | dma::init(); | ||
| 137 | } | 143 | } |
| 138 | #[cfg(feature = "_time-driver")] | ||
| 139 | time_driver::init(config.time_interrupt_priority); | ||
| 140 | gpio::init(); | 144 | gpio::init(); |
| 141 | 145 | ||
| 142 | peripherals | 146 | peripherals |
| @@ -145,3 +149,21 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 145 | pub(crate) mod sealed { | 149 | pub(crate) mod sealed { |
| 146 | pub trait Sealed {} | 150 | pub trait Sealed {} |
| 147 | } | 151 | } |
| 152 | |||
| 153 | #[cfg(feature = "rt")] | ||
| 154 | struct BitIter(u32); | ||
| 155 | |||
| 156 | #[cfg(feature = "rt")] | ||
| 157 | impl Iterator for BitIter { | ||
| 158 | type Item = u32; | ||
| 159 | |||
| 160 | fn next(&mut self) -> Option<Self::Item> { | ||
| 161 | match self.0.trailing_zeros() { | ||
| 162 | 32 => None, | ||
| 163 | b => { | ||
| 164 | self.0 &= !(1 << b); | ||
| 165 | Some(b) | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
diff --git a/examples/mimxrt6/src/bin/uart-async.rs b/examples/mimxrt6/src/bin/uart-async.rs new file mode 100644 index 000000000..58e31f379 --- /dev/null +++ b/examples/mimxrt6/src/bin/uart-async.rs | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | extern crate embassy_imxrt_examples; | ||
| 5 | |||
| 6 | use defmt::info; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_imxrt::flexcomm::uart::{self, Async, Uart}; | ||
| 9 | use embassy_imxrt::{bind_interrupts, peripherals}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | FLEXCOMM2 => uart::InterruptHandler<peripherals::FLEXCOMM2>; | ||
| 15 | FLEXCOMM4 => uart::InterruptHandler<peripherals::FLEXCOMM4>; | ||
| 16 | }); | ||
| 17 | |||
| 18 | const BUFLEN: usize = 16; | ||
| 19 | |||
| 20 | #[embassy_executor::task] | ||
| 21 | async fn usart4_task(mut uart: Uart<'static, Async>) { | ||
| 22 | info!("RX Task"); | ||
| 23 | |||
| 24 | loop { | ||
| 25 | let mut rx_buf = [0; BUFLEN]; | ||
| 26 | uart.read(&mut rx_buf).await.unwrap(); | ||
| 27 | info!("usart4: rx_buf {:02x}", rx_buf); | ||
| 28 | |||
| 29 | Timer::after_millis(10).await; | ||
| 30 | |||
| 31 | let tx_buf = [0xaa; BUFLEN]; | ||
| 32 | uart.write(&tx_buf).await.unwrap(); | ||
| 33 | info!("usart4: tx_buf {:02x}", tx_buf); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::task] | ||
| 38 | async fn usart2_task(mut uart: Uart<'static, Async>) { | ||
| 39 | info!("TX Task"); | ||
| 40 | |||
| 41 | loop { | ||
| 42 | let tx_buf = [0x55; BUFLEN]; | ||
| 43 | uart.write(&tx_buf).await.unwrap(); | ||
| 44 | info!("usart2: tx_buf {:02x}", tx_buf); | ||
| 45 | |||
| 46 | Timer::after_millis(10).await; | ||
| 47 | |||
| 48 | let mut rx_buf = [0x00; BUFLEN]; | ||
| 49 | uart.read(&mut rx_buf).await.unwrap(); | ||
| 50 | info!("usart2: rx_buf {:02x}", rx_buf); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | #[embassy_executor::main] | ||
| 55 | async fn main(spawner: Spawner) { | ||
| 56 | let p = embassy_imxrt::init(Default::default()); | ||
| 57 | |||
| 58 | info!("UART test start"); | ||
| 59 | |||
| 60 | let usart4 = Uart::new_with_rtscts( | ||
| 61 | p.FLEXCOMM4, | ||
| 62 | p.PIO0_29, | ||
| 63 | p.PIO0_30, | ||
| 64 | p.PIO1_0, | ||
| 65 | p.PIO0_31, | ||
| 66 | Irqs, | ||
| 67 | p.DMA0_CH9, | ||
| 68 | p.DMA0_CH8, | ||
| 69 | Default::default(), | ||
| 70 | ) | ||
| 71 | .unwrap(); | ||
| 72 | spawner.must_spawn(usart4_task(usart4)); | ||
| 73 | |||
| 74 | let usart2 = Uart::new_with_rtscts( | ||
| 75 | p.FLEXCOMM2, | ||
| 76 | p.PIO0_15, | ||
| 77 | p.PIO0_16, | ||
| 78 | p.PIO0_18, | ||
| 79 | p.PIO0_17, | ||
| 80 | Irqs, | ||
| 81 | p.DMA0_CH5, | ||
| 82 | p.DMA0_CH4, | ||
| 83 | Default::default(), | ||
| 84 | ) | ||
| 85 | .unwrap(); | ||
| 86 | spawner.must_spawn(usart2_task(usart2)); | ||
| 87 | } | ||
diff --git a/examples/mimxrt6/src/bin/uart.rs b/examples/mimxrt6/src/bin/uart.rs new file mode 100644 index 000000000..d6a75f85d --- /dev/null +++ b/examples/mimxrt6/src/bin/uart.rs | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | extern crate embassy_imxrt_examples; | ||
| 5 | |||
| 6 | use defmt::info; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_imxrt::flexcomm::uart::{Blocking, Uart, UartRx, UartTx}; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::task] | ||
| 13 | async fn usart4_task(mut uart: UartRx<'static, Blocking>) { | ||
| 14 | info!("RX Task"); | ||
| 15 | |||
| 16 | loop { | ||
| 17 | let mut buf = [0; 8]; | ||
| 18 | |||
| 19 | Timer::after_millis(10).await; | ||
| 20 | |||
| 21 | uart.blocking_read(&mut buf).unwrap(); | ||
| 22 | |||
| 23 | let s = core::str::from_utf8(&buf).unwrap(); | ||
| 24 | |||
| 25 | info!("Received '{}'", s); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | #[embassy_executor::task] | ||
| 30 | async fn usart2_task(mut uart: UartTx<'static, Blocking>) { | ||
| 31 | info!("TX Task"); | ||
| 32 | |||
| 33 | loop { | ||
| 34 | let buf = "Testing\0".as_bytes(); | ||
| 35 | |||
| 36 | uart.blocking_write(buf).unwrap(); | ||
| 37 | |||
| 38 | Timer::after_millis(10).await; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(spawner: Spawner) { | ||
| 44 | let p = embassy_imxrt::init(Default::default()); | ||
| 45 | |||
| 46 | info!("UART test start"); | ||
| 47 | |||
| 48 | let usart4 = Uart::new_blocking(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Default::default()).unwrap(); | ||
| 49 | |||
| 50 | let (_, usart4) = usart4.split(); | ||
| 51 | spawner.must_spawn(usart4_task(usart4)); | ||
| 52 | |||
| 53 | let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap(); | ||
| 54 | spawner.must_spawn(usart2_task(usart2)); | ||
| 55 | } | ||
