aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authori509VCB <[email protected]>2025-09-13 17:47:26 +0000
committerGitHub <[email protected]>2025-09-13 17:47:26 +0000
commitbe794533d3929e316c65b4296de47292ae0eae67 (patch)
tree7b2288be6594573ced05c9a82cb8f258ea0dbf1a
parentabcf0ff2e17e698322c2b92238a53e2d4de328f8 (diff)
parent547a52103b3c30506dc981fa89faa6c12765e97a (diff)
Merge pull request #4647 from WyliodrinEmbeddedIoT/embassy-dev
lpc55: move to nxp-pac
-rw-r--r--embassy-nxp/CHANGELOG.md2
-rw-r--r--embassy-nxp/Cargo.toml13
-rw-r--r--embassy-nxp/src/chips/lpc55.rs2
-rw-r--r--embassy-nxp/src/gpio.rs2
-rw-r--r--embassy-nxp/src/gpio/lpc55.rs360
-rw-r--r--embassy-nxp/src/lib.rs10
-rw-r--r--embassy-nxp/src/pint.rs97
-rw-r--r--embassy-nxp/src/time_driver/rtc.rs76
-rw-r--r--embassy-nxp/src/usart.rs3
-rw-r--r--embassy-nxp/src/usart/lpc55.rs884
-rw-r--r--examples/lpc55s69/Cargo.toml2
11 files changed, 462 insertions, 989 deletions
diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md
index 7042ad14c..ab97c4185 100644
--- a/embassy-nxp/CHANGELOG.md
+++ b/embassy-nxp/CHANGELOG.md
@@ -7,5 +7,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10- Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac`
11- First release with changelog. 11- First release with changelog.
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index ab0bfbfd7..455915f29 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[package.metadata.embassy] 8[package.metadata.embassy]
9build = [ 9build = [
10 {target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55"]}, 10 {target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55-core0"]},
11 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1011", "rt", "time-driver-pit"]}, 11 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1011", "rt", "time-driver-pit"]},
12 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1062", "rt", "time-driver-pit"]}, 12 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1062", "rt", "time-driver-pit"]},
13] 13]
@@ -18,7 +18,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nxp/s
18features = ["defmt", "unstable-pac" ] # TODO: Add time-driver-any, as both lpc55 and mimxrt1xxx use different drivers. 18features = ["defmt", "unstable-pac" ] # TODO: Add time-driver-any, as both lpc55 and mimxrt1xxx use different drivers.
19 19
20flavors = [ 20flavors = [
21 { regex_feature = "lpc55", target = "thumbv8m.main-none-eabihf" }, 21 { regex_feature = "lpc55-core0", target = "thumbv8m.main-none-eabihf" },
22 { regex_feature = "mimxrt.*", target = "thumbv7em-none-eabihf" }, 22 { regex_feature = "mimxrt.*", target = "thumbv7em-none-eabihf" },
23] 23]
24 24
@@ -36,21 +36,20 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut
36embedded-io = "0.6.1" 36embedded-io = "0.6.1"
37embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 37embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
38## Chip dependencies 38## Chip dependencies
39lpc55-pac = { version = "0.5.0", optional = true } 39nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"}
40nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
41 40
42imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } 41imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
43 42
44[build-dependencies] 43[build-dependencies]
45cfg_aliases = "0.2.1" 44cfg_aliases = "0.2.1"
46nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true } 45nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true }
47proc-macro2 = "1.0.95" 46proc-macro2 = "1.0.95"
48quote = "1.0.15" 47quote = "1.0.15"
49 48
50[features] 49[features]
51default = ["rt"] 50default = ["rt"]
52# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily). 51# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
53rt = ["lpc55-pac?/rt", "nxp-pac?/rt"] 52rt = ["nxp-pac?/rt"]
54 53
55## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 54## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
56defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"] 55defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
@@ -79,6 +78,6 @@ _rt1xxx = []
79_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"] 78_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
80 79
81#! ### Chip selection features 80#! ### Chip selection features
82lpc55 = ["dep:lpc55-pac"] 81lpc55-core0 = ["nxp-pac/lpc55s69_cm33_core0"]
83mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"] 82mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
84mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"] 83mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]
diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs
index e168ced00..711bff3e7 100644
--- a/embassy-nxp/src/chips/lpc55.rs
+++ b/embassy-nxp/src/chips/lpc55.rs
@@ -1,4 +1,4 @@
1pub use lpc55_pac as pac; 1pub use nxp_pac as pac;
2 2
3embassy_hal_internal::peripherals! { 3embassy_hal_internal::peripherals! {
4 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other 4 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
index 3049cc12d..717b38d96 100644
--- a/embassy-nxp/src/gpio.rs
+++ b/embassy-nxp/src/gpio.rs
@@ -1,7 +1,7 @@
1//! General purpose input/output (GPIO) driver. 1//! General purpose input/output (GPIO) driver.
2#![macro_use] 2#![macro_use]
3 3
4#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")] 4#[cfg_attr(feature = "lpc55-core0", path = "./gpio/lpc55.rs")]
5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")] 5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
6mod inner; 6mod inner;
7pub use inner::*; 7pub use inner::*;
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs
index 8f407bb3a..36ea99d21 100644
--- a/embassy-nxp/src/gpio/lpc55.rs
+++ b/embassy-nxp/src/gpio/lpc55.rs
@@ -1,12 +1,17 @@
1use embassy_hal_internal::{impl_peripheral, PeripheralType}; 1use embassy_hal_internal::{impl_peripheral, PeripheralType};
2 2
3use crate::pac::iocon::vals::{PioDigimode, PioMode};
4use crate::pac::{GPIO, IOCON, SYSCON};
3use crate::{peripherals, Peri}; 5use crate::{peripherals, Peri};
4 6
5pub(crate) fn init() { 7pub(crate) fn init() {
6 // Enable clocks for GPIO, PINT, and IOCON 8 // Enable clocks for GPIO, PINT, and IOCON
7 syscon_reg() 9 SYSCON.ahbclkctrl0().modify(|w| {
8 .ahbclkctrl0 10 w.set_gpio0(true);
9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable()); 11 w.set_gpio1(true);
12 w.set_mux(true);
13 w.set_iocon(true);
14 });
10 info!("GPIO initialized"); 15 info!("GPIO initialized");
11} 16}
12 17
@@ -59,21 +64,24 @@ impl<'d> Output<'d> {
59 } 64 }
60 65
61 pub fn set_high(&mut self) { 66 pub fn set_high(&mut self) {
62 gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 67 GPIO.set(self.pin.pin_bank() as usize)
68 .write(|w| w.set_setp(self.pin.bit()));
63 } 69 }
64 70
65 pub fn set_low(&mut self) { 71 pub fn set_low(&mut self) {
66 gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 72 GPIO.clr(self.pin.pin_bank() as usize)
73 .write(|w| w.set_clrp(self.pin.bit()));
67 } 74 }
68 75
69 pub fn toggle(&mut self) { 76 pub fn toggle(&mut self) {
70 gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 77 GPIO.not(self.pin.pin_bank() as usize)
78 .write(|w| w.set_notp(self.pin.bit()));
71 } 79 }
72 80
73 /// Get the current output level of the pin. Note that the value returned by this function is 81 /// Get the current output level of the pin. Note that the value returned by this function is
74 /// the voltage level reported by the pin, not the value set by the output driver. 82 /// the voltage level reported by the pin, not the value set by the output driver.
75 pub fn level(&self) -> Level { 83 pub fn level(&self) -> Level {
76 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); 84 let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
77 if bits & self.pin.bit() != 0 { 85 if bits & self.pin.bit() != 0 {
78 Level::High 86 Level::High
79 } else { 87 } else {
@@ -101,18 +109,18 @@ impl<'d> Input<'d> {
101 109
102 /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. 110 /// Set the pull configuration for the pin. To disable the pull, use [Pull::None].
103 pub fn set_pull(&mut self, pull: Pull) { 111 pub fn set_pull(&mut self, pull: Pull) {
104 match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), { 112 match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), {
105 register.modify(|_, w| match pull { 113 register.modify(|w| match pull {
106 Pull::None => w.mode().inactive(), 114 Pull::None => w.set_mode(PioMode::INACTIVE),
107 Pull::Up => w.mode().pull_up(), 115 Pull::Up => w.set_mode(PioMode::PULL_UP),
108 Pull::Down => w.mode().pull_down(), 116 Pull::Down => w.set_mode(PioMode::PULL_DOWN),
109 }); 117 });
110 }); 118 });
111 } 119 }
112 120
113 /// Get the current input level of the pin. 121 /// Get the current input level of the pin.
114 pub fn read(&self) -> Level { 122 pub fn read(&self) -> Level {
115 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); 123 let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
116 if bits & self.pin.bit() != 0 { 124 if bits & self.pin.bit() != 0 {
117 Level::High 125 Level::High
118 } else { 126 } else {
@@ -188,8 +196,8 @@ impl<'d> Flex<'d> {
188 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default 196 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
189 /// setting for pins is (usually) non-digital. 197 /// setting for pins is (usually) non-digital.
190 fn set_as_digital(&mut self) { 198 fn set_as_digital(&mut self) {
191 match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), { 199 match_iocon!(register, self.pin_bank(), self.pin_number(), {
192 register.modify(|_, w| w.digimode().digital()); 200 register.modify(|w| w.set_digimode(PioDigimode::DIGITAL));
193 }); 201 });
194 } 202 }
195 203
@@ -197,12 +205,14 @@ impl<'d> Flex<'d> {
197 /// function handles itself. 205 /// function handles itself.
198 pub fn set_as_output(&mut self) { 206 pub fn set_as_output(&mut self) {
199 self.set_as_digital(); 207 self.set_as_digital();
200 gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) }) 208 GPIO.dirset(self.pin.pin_bank() as usize)
209 .write(|w| w.set_dirsetp(self.bit()))
201 } 210 }
202 211
203 pub fn set_as_input(&mut self) { 212 pub fn set_as_input(&mut self) {
204 self.set_as_digital(); 213 self.set_as_digital();
205 gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) }) 214 GPIO.dirclr(self.pin.pin_bank() as usize)
215 .write(|w| w.set_dirclrp(self.bit()))
206 } 216 }
207} 217}
208 218
@@ -262,52 +272,6 @@ impl SealedPin for AnyPin {
262 } 272 }
263} 273}
264 274
265/// Get the GPIO register block. This is used to configure all GPIO pins.
266///
267/// # Safety
268/// Due to the type system of peripherals, access to the settings of a single pin is possible only
269/// by a single thread at a time. Read/Write operations on a single registers are NOT atomic. You
270/// must ensure that the GPIO registers are not accessed concurrently by multiple threads.
271pub(crate) fn gpio_reg() -> &'static lpc55_pac::gpio::RegisterBlock {
272 unsafe { &*lpc55_pac::GPIO::ptr() }
273}
274
275/// Get the IOCON register block.
276///
277/// # Safety
278/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
279/// registers are not accessed concurrently by multiple threads.
280pub(crate) fn iocon_reg() -> &'static lpc55_pac::iocon::RegisterBlock {
281 unsafe { &*lpc55_pac::IOCON::ptr() }
282}
283
284/// Get the INPUTMUX register block.
285///
286/// # Safety
287/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
288/// registers are not accessed concurrently by multiple threads.
289pub(crate) fn inputmux_reg() -> &'static lpc55_pac::inputmux::RegisterBlock {
290 unsafe { &*lpc55_pac::INPUTMUX::ptr() }
291}
292
293/// Get the SYSCON register block.
294///
295/// # Safety
296/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
297/// registers are not accessed concurrently by multiple threads.
298pub(crate) fn syscon_reg() -> &'static lpc55_pac::syscon::RegisterBlock {
299 unsafe { &*lpc55_pac::SYSCON::ptr() }
300}
301
302/// Get the PINT register block.
303///
304/// # Safety
305/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
306/// registers are not accessed concurrently by multiple threads.
307pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
308 unsafe { &*lpc55_pac::PINT::ptr() }
309}
310
311/// Match the pin bank and number of a pin to the corresponding IOCON register. 275/// Match the pin bank and number of a pin to the corresponding IOCON register.
312/// 276///
313/// # Example 277/// # Example
@@ -316,270 +280,26 @@ pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
316/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; 280/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon};
317/// 281///
318/// // Make pin PIO1_6 digital and set it to pull-down mode. 282/// // Make pin PIO1_6 digital and set it to pull-down mode.
319/// match_iocon!(register, iocon_reg(), Bank::Bank1, 6, { 283/// match_iocon!(register, Bank::Bank1, 6, {
320/// register.modify(|_, w| w.mode().pull_down().digimode().digital()); 284/// register.modify(|w|{
285/// w.set_mode(PioMode::PULL_DOWN);
286/// w.set_digimode(PioDigimode::DIGITAL);
287///
288/// }
321/// }); 289/// });
322/// ``` 290/// ```
323macro_rules! match_iocon { 291macro_rules! match_iocon {
324 ($register:ident, $iocon_register:expr, $pin_bank:expr, $pin_number:expr, $action:expr) => { 292 ($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => {
325 match ($pin_bank, $pin_number) { 293 match $pin_bank {
326 (Bank::Bank0, 0) => { 294 Bank::Bank0 => {
327 let $register = &($iocon_register).pio0_0; 295 let $register = IOCON.pio0($pin_number as usize);
328 $action;
329 }
330 (Bank::Bank0, 1) => {
331 let $register = &($iocon_register).pio0_1;
332 $action;
333 }
334 (Bank::Bank0, 2) => {
335 let $register = &($iocon_register).pio0_2;
336 $action;
337 }
338 (Bank::Bank0, 3) => {
339 let $register = &($iocon_register).pio0_3;
340 $action;
341 }
342 (Bank::Bank0, 4) => {
343 let $register = &($iocon_register).pio0_4;
344 $action;
345 }
346 (Bank::Bank0, 5) => {
347 let $register = &($iocon_register).pio0_5;
348 $action;
349 }
350 (Bank::Bank0, 6) => {
351 let $register = &($iocon_register).pio0_6;
352 $action;
353 }
354 (Bank::Bank0, 7) => {
355 let $register = &($iocon_register).pio0_7;
356 $action;
357 }
358 (Bank::Bank0, 8) => {
359 let $register = &($iocon_register).pio0_8;
360 $action;
361 }
362 (Bank::Bank0, 9) => {
363 let $register = &($iocon_register).pio0_9;
364 $action;
365 }
366 (Bank::Bank0, 10) => {
367 let $register = &($iocon_register).pio0_10;
368 $action; 296 $action;
369 } 297 }
370 (Bank::Bank0, 11) => { 298
371 let $register = &($iocon_register).pio0_11; 299 Bank::Bank1 => {
372 $action; 300 let $register = IOCON.pio1($pin_number as usize);
373 }
374 (Bank::Bank0, 12) => {
375 let $register = &($iocon_register).pio0_12;
376 $action;
377 }
378 (Bank::Bank0, 13) => {
379 let $register = &($iocon_register).pio0_13;
380 $action;
381 }
382 (Bank::Bank0, 14) => {
383 let $register = &($iocon_register).pio0_14;
384 $action;
385 }
386 (Bank::Bank0, 15) => {
387 let $register = &($iocon_register).pio0_15;
388 $action;
389 }
390 (Bank::Bank0, 16) => {
391 let $register = &($iocon_register).pio0_16;
392 $action;
393 }
394 (Bank::Bank0, 17) => {
395 let $register = &($iocon_register).pio0_17;
396 $action;
397 }
398 (Bank::Bank0, 18) => {
399 let $register = &($iocon_register).pio0_18;
400 $action;
401 }
402 (Bank::Bank0, 19) => {
403 let $register = &($iocon_register).pio0_19;
404 $action;
405 }
406 (Bank::Bank0, 20) => {
407 let $register = &($iocon_register).pio0_20;
408 $action;
409 }
410 (Bank::Bank0, 21) => {
411 let $register = &($iocon_register).pio0_21;
412 $action;
413 }
414 (Bank::Bank0, 22) => {
415 let $register = &($iocon_register).pio0_22;
416 $action;
417 }
418 (Bank::Bank0, 23) => {
419 let $register = &($iocon_register).pio0_23;
420 $action;
421 }
422 (Bank::Bank0, 24) => {
423 let $register = &($iocon_register).pio0_24;
424 $action;
425 }
426 (Bank::Bank0, 25) => {
427 let $register = &($iocon_register).pio0_25;
428 $action;
429 }
430 (Bank::Bank0, 26) => {
431 let $register = &($iocon_register).pio0_26;
432 $action;
433 }
434 (Bank::Bank0, 27) => {
435 let $register = &($iocon_register).pio0_27;
436 $action;
437 }
438 (Bank::Bank0, 28) => {
439 let $register = &($iocon_register).pio0_28;
440 $action;
441 }
442 (Bank::Bank0, 29) => {
443 let $register = &($iocon_register).pio0_29;
444 $action;
445 }
446 (Bank::Bank0, 30) => {
447 let $register = &($iocon_register).pio0_30;
448 $action;
449 }
450 (Bank::Bank0, 31) => {
451 let $register = &($iocon_register).pio0_31;
452 $action;
453 }
454 (Bank::Bank1, 0) => {
455 let $register = &($iocon_register).pio1_0;
456 $action;
457 }
458 (Bank::Bank1, 1) => {
459 let $register = &($iocon_register).pio1_1;
460 $action;
461 }
462 (Bank::Bank1, 2) => {
463 let $register = &($iocon_register).pio1_2;
464 $action;
465 }
466 (Bank::Bank1, 3) => {
467 let $register = &($iocon_register).pio1_3;
468 $action;
469 }
470 (Bank::Bank1, 4) => {
471 let $register = &($iocon_register).pio1_4;
472 $action;
473 }
474 (Bank::Bank1, 5) => {
475 let $register = &($iocon_register).pio1_5;
476 $action;
477 }
478 (Bank::Bank1, 6) => {
479 let $register = &($iocon_register).pio1_6;
480 $action;
481 }
482 (Bank::Bank1, 7) => {
483 let $register = &($iocon_register).pio1_7;
484 $action;
485 }
486 (Bank::Bank1, 8) => {
487 let $register = &($iocon_register).pio1_8;
488 $action;
489 }
490 (Bank::Bank1, 9) => {
491 let $register = &($iocon_register).pio1_9;
492 $action;
493 }
494 (Bank::Bank1, 10) => {
495 let $register = &($iocon_register).pio1_10;
496 $action;
497 }
498 (Bank::Bank1, 11) => {
499 let $register = &($iocon_register).pio1_11;
500 $action;
501 }
502 (Bank::Bank1, 12) => {
503 let $register = &($iocon_register).pio1_12;
504 $action;
505 }
506 (Bank::Bank1, 13) => {
507 let $register = &($iocon_register).pio1_13;
508 $action;
509 }
510 (Bank::Bank1, 14) => {
511 let $register = &($iocon_register).pio1_14;
512 $action;
513 }
514 (Bank::Bank1, 15) => {
515 let $register = &($iocon_register).pio1_15;
516 $action;
517 }
518 (Bank::Bank1, 16) => {
519 let $register = &($iocon_register).pio1_16;
520 $action;
521 }
522 (Bank::Bank1, 17) => {
523 let $register = &($iocon_register).pio1_17;
524 $action;
525 }
526 (Bank::Bank1, 18) => {
527 let $register = &($iocon_register).pio1_18;
528 $action;
529 }
530 (Bank::Bank1, 19) => {
531 let $register = &($iocon_register).pio1_19;
532 $action;
533 }
534 (Bank::Bank1, 20) => {
535 let $register = &($iocon_register).pio1_20;
536 $action;
537 }
538 (Bank::Bank1, 21) => {
539 let $register = &($iocon_register).pio1_21;
540 $action;
541 }
542 (Bank::Bank1, 22) => {
543 let $register = &($iocon_register).pio1_22;
544 $action;
545 }
546 (Bank::Bank1, 23) => {
547 let $register = &($iocon_register).pio1_23;
548 $action;
549 }
550 (Bank::Bank1, 24) => {
551 let $register = &($iocon_register).pio1_24;
552 $action;
553 }
554 (Bank::Bank1, 25) => {
555 let $register = &($iocon_register).pio1_25;
556 $action;
557 }
558 (Bank::Bank1, 26) => {
559 let $register = &($iocon_register).pio1_26;
560 $action;
561 }
562 (Bank::Bank1, 27) => {
563 let $register = &($iocon_register).pio1_27;
564 $action;
565 }
566 (Bank::Bank1, 28) => {
567 let $register = &($iocon_register).pio1_28;
568 $action;
569 }
570 (Bank::Bank1, 29) => {
571 let $register = &($iocon_register).pio1_29;
572 $action;
573 }
574 (Bank::Bank1, 30) => {
575 let $register = &($iocon_register).pio1_30;
576 $action;
577 }
578 (Bank::Bank1, 31) => {
579 let $register = &($iocon_register).pio1_31;
580 $action; 301 $action;
581 } 302 }
582 _ => unreachable!(),
583 } 303 }
584 }; 304 };
585} 305}
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
index 3fcb14b7e..74142a10b 100644
--- a/embassy-nxp/src/lib.rs
+++ b/embassy-nxp/src/lib.rs
@@ -4,9 +4,9 @@
4pub(crate) mod fmt; 4pub(crate) mod fmt;
5 5
6pub mod gpio; 6pub mod gpio;
7#[cfg(feature = "lpc55")] 7#[cfg(feature = "lpc55-core0")]
8pub mod pint; 8pub mod pint;
9#[cfg(feature = "lpc55")] 9#[cfg(feature = "lpc55-core0")]
10pub mod usart; 10pub mod usart;
11 11
12#[cfg(feature = "_time_driver")] 12#[cfg(feature = "_time_driver")]
@@ -15,7 +15,7 @@ pub mod usart;
15mod time_driver; 15mod time_driver;
16 16
17// This mod MUST go last, so that it sees all the `impl_foo!` macros 17// This mod MUST go last, so that it sees all the `impl_foo!` macros
18#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")] 18#[cfg_attr(feature = "lpc55-core0", path = "chips/lpc55.rs")]
19#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")] 19#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
20#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] 20#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
21mod chip; 21mod chip;
@@ -83,10 +83,10 @@ pub fn init(_config: config::Config) -> Peripherals {
83 pac::CCM.ccgr6().modify(|v| v.set_cg0(1)); 83 pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
84 } 84 }
85 85
86 #[cfg(any(feature = "lpc55", rt1xxx))] 86 #[cfg(any(feature = "lpc55-core0", rt1xxx))]
87 gpio::init(); 87 gpio::init();
88 88
89 #[cfg(feature = "lpc55")] 89 #[cfg(feature = "lpc55-core0")]
90 pint::init(); 90 pint::init();
91 91
92 #[cfg(feature = "_time_driver")] 92 #[cfg(feature = "_time_driver")]
diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs
index ff414b4e6..e594aaa6a 100644
--- a/embassy-nxp/src/pint.rs
+++ b/embassy-nxp/src/pint.rs
@@ -5,10 +5,11 @@ use core::pin::Pin as FuturePin;
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use critical_section::Mutex; 7use critical_section::Mutex;
8use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9 10
10use crate::gpio::{self, inputmux_reg, pint_reg, syscon_reg, AnyPin, Level, SealedPin}; 11use crate::gpio::{self, AnyPin, Level, SealedPin};
11use crate::pac::interrupt; 12use crate::pac::{interrupt, INPUTMUX, PINT, SYSCON};
12use crate::Peri; 13use crate::Peri;
13 14
14struct PinInterrupt { 15struct PinInterrupt {
@@ -88,18 +89,18 @@ enum InterruptOn {
88} 89}
89 90
90pub(crate) fn init() { 91pub(crate) fn init() {
91 syscon_reg().ahbclkctrl0.modify(|_, w| w.pint().enable()); 92 SYSCON.ahbclkctrl0().modify(|w| w.set_pint(true));
92 93
93 // Enable interrupts 94 // Enable interrupts
94 unsafe { 95 unsafe {
95 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT0); 96 interrupt::PIN_INT0.enable();
96 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT1); 97 interrupt::PIN_INT1.enable();
97 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT2); 98 interrupt::PIN_INT2.enable();
98 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT3); 99 interrupt::PIN_INT3.enable();
99 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT4); 100 interrupt::PIN_INT4.enable();
100 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT5); 101 interrupt::PIN_INT5.enable();
101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6); 102 interrupt::PIN_INT6.enable();
102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7); 103 interrupt::PIN_INT7.enable();
103 }; 104 };
104 105
105 info!("Pin interrupts initialized"); 106 info!("Pin interrupts initialized");
@@ -119,24 +120,19 @@ impl<'d> InputFuture<'d> {
119 let interrupt_number = next_available_interrupt()?; 120 let interrupt_number = next_available_interrupt()?;
120 121
121 // Clear interrupt, just in case 122 // Clear interrupt, just in case
122 pint_reg() 123 PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
123 .rise 124 PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
124 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
125 pint_reg()
126 .fall
127 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
128 125
129 // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number) 126 // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number)
130 inputmux_reg().pintsel[interrupt_number] 127 INPUTMUX
131 .write(|w| unsafe { w.intpin().bits(32 * pin.pin_bank() as u8 + pin.pin_number()) }); 128 .pintsel(interrupt_number as usize)
129 .write(|w| w.set_intpin(32 * pin.pin_bank() as u8 + pin.pin_number()));
132 130
133 match interrupt_on { 131 match interrupt_on {
134 InterruptOn::Level(level) => { 132 InterruptOn::Level(level) => {
135 // Set pin interrupt register to edge sensitive or level sensitive 133 // Set pin interrupt register to edge sensitive or level sensitive
136 // 0 = edge sensitive, 1 = level sensitive 134 // 0 = edge sensitive, 1 = level sensitive
137 pint_reg() 135 PINT.isel().modify(|w| w.set_pmode(w.pmode() | (1 << interrupt_number)));
138 .isel
139 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << interrupt_number)) });
140 136
141 // Enable level interrupt. 137 // Enable level interrupt.
142 // 138 //
@@ -144,63 +140,44 @@ impl<'d> InputFuture<'d> {
144 // is activated. 140 // is activated.
145 141
146 // 0 = no-op, 1 = enable 142 // 0 = no-op, 1 = enable
147 pint_reg() 143 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
148 .sienr
149 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
150 144
151 // Set active level 145 // Set active level
152 match level { 146 match level {
153 Level::Low => { 147 Level::Low => {
154 // 0 = no-op, 1 = select LOW 148 // 0 = no-op, 1 = select LOW
155 pint_reg() 149 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
156 .cienf
157 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
158 } 150 }
159 Level::High => { 151 Level::High => {
160 // 0 = no-op, 1 = select HIGH 152 // 0 = no-op, 1 = select HIGH
161 pint_reg() 153 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
162 .sienf
163 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
164 } 154 }
165 } 155 }
166 } 156 }
167 InterruptOn::Edge(edge) => { 157 InterruptOn::Edge(edge) => {
168 // Set pin interrupt register to edge sensitive or level sensitive 158 // Set pin interrupt register to edge sensitive or level sensitive
169 // 0 = edge sensitive, 1 = level sensitive 159 // 0 = edge sensitive, 1 = level sensitive
170 pint_reg() 160 PINT.isel()
171 .isel 161 .modify(|w| w.set_pmode(w.pmode() & !(1 << interrupt_number)));
172 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << interrupt_number)) });
173 162
174 // Enable rising/falling edge detection 163 // Enable rising/falling edge detection
175 match edge { 164 match edge {
176 Edge::Rising => { 165 Edge::Rising => {
177 // 0 = no-op, 1 = enable rising edge 166 // 0 = no-op, 1 = enable rising edge
178 pint_reg() 167 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
179 .sienr
180 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
181 // 0 = no-op, 1 = disable falling edge 168 // 0 = no-op, 1 = disable falling edge
182 pint_reg() 169 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
183 .cienf
184 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
185 } 170 }
186 Edge::Falling => { 171 Edge::Falling => {
187 // 0 = no-op, 1 = enable falling edge 172 // 0 = no-op, 1 = enable falling edge
188 pint_reg() 173 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
189 .sienf
190 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
191 // 0 = no-op, 1 = disable rising edge 174 // 0 = no-op, 1 = disable rising edge
192 pint_reg() 175 PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
193 .cienr
194 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
195 } 176 }
196 Edge::Both => { 177 Edge::Both => {
197 // 0 = no-op, 1 = enable 178 // 0 = no-op, 1 = enable
198 pint_reg() 179 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
199 .sienr 180 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
200 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
201 pint_reg()
202 .sienf
203 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
204 } 181 }
205 } 182 }
206 } 183 }
@@ -239,12 +216,8 @@ impl<'d> Drop for InputFuture<'d> {
239 216
240 // Disable pin interrupt 217 // Disable pin interrupt
241 // 0 = no-op, 1 = disable 218 // 0 = no-op, 1 = disable
242 pint_reg() 219 PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
243 .cienr 220 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
244 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
245 pint_reg()
246 .cienf
247 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
248 221
249 critical_section::with(|cs| { 222 critical_section::with(|cs| {
250 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); 223 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
@@ -277,12 +250,8 @@ impl<'d> Future for InputFuture<'d> {
277} 250}
278 251
279fn handle_interrupt(interrupt_number: usize) { 252fn handle_interrupt(interrupt_number: usize) {
280 pint_reg() 253 PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
281 .rise 254 PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
282 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
283 pint_reg()
284 .fall
285 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
286 255
287 critical_section::with(|cs| { 256 critical_section::with(|cs| {
288 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); 257 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
diff --git a/embassy-nxp/src/time_driver/rtc.rs b/embassy-nxp/src/time_driver/rtc.rs
index 94272e9c2..fb6de6a5e 100644
--- a/embassy-nxp/src/time_driver/rtc.rs
+++ b/embassy-nxp/src/time_driver/rtc.rs
@@ -6,7 +6,9 @@ use embassy_hal_internal::interrupt::{InterruptExt, Priority};
6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
7use embassy_time_driver::{time_driver_impl, Driver}; 7use embassy_time_driver::{time_driver_impl, Driver};
8use embassy_time_queue_utils::Queue; 8use embassy_time_queue_utils::Queue;
9use lpc55_pac::{interrupt, PMC, RTC, SYSCON}; 9
10use crate::pac::{interrupt, pmc, rtc, PMC, RTC, SYSCON};
11
10struct AlarmState { 12struct AlarmState {
11 timestamp: Cell<u64>, 13 timestamp: Cell<u64>,
12} 14}
@@ -32,33 +34,32 @@ time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
32}); 34});
33impl RtcDriver { 35impl RtcDriver {
34 fn init(&'static self) { 36 fn init(&'static self) {
35 let syscon = unsafe { &*SYSCON::ptr() }; 37 let syscon = SYSCON;
36 let pmc = unsafe { &*PMC::ptr() }; 38 let pmc = PMC;
37 let rtc = unsafe { &*RTC::ptr() }; 39 let rtc = RTC;
38 40
39 syscon.ahbclkctrl0.modify(|_, w| w.rtc().enable()); 41 syscon.ahbclkctrl0().modify(|w| w.set_rtc(true));
40 42
41 // By default the RTC enters software reset. If for some reason it is 43 // By default the RTC enters software reset. If for some reason it is
42 // not in reset, we enter and them promptly leave.q 44 // not in reset, we enter and them promptly leave.q
43 rtc.ctrl.modify(|_, w| w.swreset().set_bit()); 45 rtc.ctrl().modify(|w| w.set_swreset(true));
44 rtc.ctrl.modify(|_, w| w.swreset().clear_bit()); 46 rtc.ctrl().modify(|w| w.set_swreset(false));
45 47
46 // Select clock source - either XTAL or FRO 48 // Select clock source - either XTAL or FRO
47 // pmc.rtcosc32k.write(|w| w.sel().xtal32k()); 49 // pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::XTAL32K));
48 pmc.rtcosc32k.write(|w| w.sel().fro32k()); 50 pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::FRO32K));
49 51
50 // Start the RTC peripheral 52 // Start the RTC peripheral
51 rtc.ctrl.modify(|_, w| w.rtc_osc_pd().power_up()); 53 rtc.ctrl().modify(|w| w.set_rtc_osc_pd(rtc::vals::RtcOscPd::POWER_UP));
52
53 // rtc.ctrl.modify(|_, w| w.rtc_en().clear_bit()); // EXTRA
54 54
55 //reset/clear(?) counter 55 //reset/clear(?) counter
56 rtc.count.reset(); 56 rtc.count().modify(|w| w.set_val(0));
57 //en rtc main counter 57 //en rtc main counter
58 rtc.ctrl.modify(|_, w| w.rtc_en().set_bit()); 58 rtc.ctrl().modify(|w| w.set_rtc_en(true));
59 rtc.ctrl.modify(|_, w| w.rtc1khz_en().set_bit()); 59 rtc.ctrl().modify(|w| w.set_rtc1khz_en(true));
60 // subsec counter enable 60 // subsec counter enable
61 rtc.ctrl.modify(|_, w| w.rtc_subsec_ena().set_bit()); 61 rtc.ctrl()
62 .modify(|w| w.set_rtc_subsec_ena(rtc::vals::RtcSubsecEna::POWER_UP));
62 63
63 // enable irq 64 // enable irq
64 unsafe { 65 unsafe {
@@ -68,7 +69,7 @@ impl RtcDriver {
68 } 69 }
69 70
70 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 71 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
71 let rtc = unsafe { &*RTC::ptr() }; 72 let rtc = RTC;
72 let alarm = &self.alarms.borrow(cs); 73 let alarm = &self.alarms.borrow(cs);
73 alarm.timestamp.set(timestamp); 74 alarm.timestamp.set(timestamp);
74 let now = self.now(); 75 let now = self.now();
@@ -83,33 +84,38 @@ impl RtcDriver {
83 let sec = (diff / 32768) as u32; 84 let sec = (diff / 32768) as u32;
84 let subsec = (diff % 32768) as u32; 85 let subsec = (diff % 32768) as u32;
85 86
86 let current_sec = rtc.count.read().val().bits(); 87 let current_sec = rtc.count().read().val();
87 let target_sec = current_sec.wrapping_add(sec as u32); 88 let target_sec = current_sec.wrapping_add(sec as u32);
88 89
89 rtc.match_.write(|w| unsafe { w.matval().bits(target_sec) }); 90 rtc.match_().write(|w| w.set_matval(target_sec));
90 rtc.wake.write(|w| unsafe { 91 rtc.wake().write(|w| {
91 let ms = (subsec * 1000) / 32768; 92 let ms = (subsec * 1000) / 32768;
92 w.val().bits(ms as u16) 93 w.set_val(ms as u16)
93 }); 94 });
95
94 if subsec > 0 { 96 if subsec > 0 {
95 let ms = (subsec * 1000) / 32768; 97 let ms = (subsec * 1000) / 32768;
96 rtc.wake.write(|w| unsafe { w.val().bits(ms as u16) }); 98 rtc.wake().write(|w| w.set_val(ms as u16));
97 } 99 }
98 rtc.ctrl.modify(|_, w| w.alarm1hz().clear_bit().wake1khz().clear_bit()); 100
101 rtc.ctrl().modify(|w| {
102 w.set_alarm1hz(false);
103 w.set_wake1khz(rtc::vals::Wake1khz::RUN)
104 });
99 true 105 true
100 } 106 }
101 107
102 fn on_interrupt(&self) { 108 fn on_interrupt(&self) {
103 critical_section::with(|cs| { 109 critical_section::with(|cs| {
104 let rtc = unsafe { &*RTC::ptr() }; 110 let rtc = RTC;
105 let flags = rtc.ctrl.read(); 111 let flags = rtc.ctrl().read();
106 if flags.alarm1hz().bit_is_clear() { 112 if flags.alarm1hz() == false {
107 rtc.ctrl.modify(|_, w| w.alarm1hz().set_bit()); 113 rtc.ctrl().modify(|w| w.set_alarm1hz(true));
108 self.trigger_alarm(cs); 114 self.trigger_alarm(cs);
109 } 115 }
110 116
111 if flags.wake1khz().bit_is_clear() { 117 if flags.wake1khz() == rtc::vals::Wake1khz::RUN {
112 rtc.ctrl.modify(|_, w| w.wake1khz().set_bit()); 118 rtc.ctrl().modify(|w| w.set_wake1khz(rtc::vals::Wake1khz::TIMEOUT));
113 self.trigger_alarm(cs); 119 self.trigger_alarm(cs);
114 } 120 }
115 }); 121 });
@@ -135,13 +141,13 @@ impl RtcDriver {
135 141
136impl Driver for RtcDriver { 142impl Driver for RtcDriver {
137 fn now(&self) -> u64 { 143 fn now(&self) -> u64 {
138 let rtc = unsafe { &*RTC::ptr() }; 144 let rtc = RTC;
139 145
140 loop { 146 loop {
141 let sec1 = rtc.count.read().val().bits() as u64; 147 let sec1 = rtc.count().read().val() as u64;
142 let sub1 = rtc.subsec.read().subsec().bits() as u64; 148 let sub1 = rtc.subsec().read().subsec() as u64;
143 let sec2 = rtc.count.read().val().bits() as u64; 149 let sec2 = rtc.count().read().val() as u64;
144 let sub2 = rtc.subsec.read().subsec().bits() as u64; 150 let sub2 = rtc.subsec().read().subsec() as u64;
145 151
146 if sec1 == sec2 && sub1 == sub2 { 152 if sec1 == sec2 && sub1 == sub2 {
147 return sec1 * 32768 + sub1; 153 return sec1 * 32768 + sub1;
@@ -162,7 +168,7 @@ impl Driver for RtcDriver {
162 }) 168 })
163 } 169 }
164} 170}
165#[cortex_m_rt::interrupt] 171#[interrupt]
166fn RTC() { 172fn RTC() {
167 DRIVER.on_interrupt(); 173 DRIVER.on_interrupt();
168} 174}
diff --git a/embassy-nxp/src/usart.rs b/embassy-nxp/src/usart.rs
index 009c251e2..1d8886f24 100644
--- a/embassy-nxp/src/usart.rs
+++ b/embassy-nxp/src/usart.rs
@@ -1,6 +1,5 @@
1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. 1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver.
2#![macro_use]
3 2
4#[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")] 3#[cfg_attr(feature = "lpc55-core0", path = "./usart/lpc55.rs")]
5mod inner; 4mod inner;
6pub use inner::*; 5pub use inner::*;
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
index 3f7456a2e..428b80c4b 100644
--- a/embassy-nxp/src/usart/lpc55.rs
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -2,9 +2,12 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::{Peri, PeripheralType}; 3use embassy_hal_internal::{Peri, PeripheralType};
4use embedded_io::{self, ErrorKind}; 4use embedded_io::{self, ErrorKind};
5pub use sealed::SealedInstance;
6 5
7use crate::gpio::AnyPin; 6use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin};
7use crate::pac::flexcomm::Flexcomm as FlexcommReg;
8use crate::pac::iocon::vals::PioFunc;
9use crate::pac::usart::Usart as UsartReg;
10use crate::pac::*;
8use crate::{Blocking, Mode}; 11use crate::{Blocking, Mode};
9 12
10/// Serial error 13/// Serial error
@@ -47,16 +50,6 @@ pub enum DataBits {
47 DataBits9, 50 DataBits9,
48} 51}
49 52
50impl DataBits {
51 fn bits(&self) -> u8 {
52 match self {
53 Self::DataBits7 => 0b00,
54 Self::DataBits8 => 0b01,
55 Self::DataBits9 => 0b10,
56 }
57 }
58}
59
60/// Parity bit. 53/// Parity bit.
61#[derive(Clone, Copy, PartialEq, Eq, Debug)] 54#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62pub enum Parity { 55pub enum Parity {
@@ -68,16 +61,6 @@ pub enum Parity {
68 ParityOdd, 61 ParityOdd,
69} 62}
70 63
71impl Parity {
72 fn bits(&self) -> u8 {
73 match self {
74 Self::ParityNone => 0b00,
75 Self::ParityEven => 0b10,
76 Self::ParityOdd => 0b11,
77 }
78 }
79}
80
81/// Stop bits. 64/// Stop bits.
82#[derive(Clone, Copy, PartialEq, Eq, Debug)] 65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
83pub enum StopBits { 66pub enum StopBits {
@@ -87,15 +70,6 @@ pub enum StopBits {
87 Stop2, 70 Stop2,
88} 71}
89 72
90impl StopBits {
91 fn bits(&self) -> bool {
92 return match self {
93 Self::Stop1 => false,
94 Self::Stop2 => true,
95 };
96 }
97}
98
99/// UART config. 73/// UART config.
100#[non_exhaustive] 74#[non_exhaustive]
101#[derive(Clone, Debug)] 75#[derive(Clone, Debug)]
@@ -117,7 +91,7 @@ pub struct Config {
117impl Default for Config { 91impl Default for Config {
118 fn default() -> Self { 92 fn default() -> Self {
119 Self { 93 Self {
120 baudrate: 9600, 94 baudrate: 115200,
121 data_bits: DataBits::DataBits8, 95 data_bits: DataBits::DataBits8,
122 stop_bits: StopBits::Stop1, 96 stop_bits: StopBits::Stop1,
123 parity: Parity::ParityNone, 97 parity: Parity::ParityNone,
@@ -131,59 +105,72 @@ impl Default for Config {
131/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time 105/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time
132/// T: the peripheral instance type allowing usage of peripheral specific registers 106/// T: the peripheral instance type allowing usage of peripheral specific registers
133/// M: the operating mode of USART peripheral 107/// M: the operating mode of USART peripheral
134pub struct Usart<'d, T: Instance, M: Mode> { 108pub struct Usart<'d, M: Mode> {
135 tx: UsartTx<'d, T, M>, 109 tx: UsartTx<'d, M>,
136 rx: UsartRx<'d, T, M>, 110 rx: UsartRx<'d, M>,
137} 111}
138 112
139pub struct UsartTx<'d, T: Instance, M: Mode> { 113pub struct UsartTx<'d, M: Mode> {
140 phantom: PhantomData<(&'d (), T, M)>, 114 info: &'static Info,
115 phantom: PhantomData<(&'d (), M)>,
141} 116}
142 117
143pub struct UsartRx<'d, T: Instance, M: Mode> { 118pub struct UsartRx<'d, M: Mode> {
144 phantom: PhantomData<(&'d (), T, M)>, 119 info: &'static Info,
120 phantom: PhantomData<(&'d (), M)>,
145} 121}
146 122
147impl<'d, T: Instance, M: Mode> UsartTx<'d, T, M> { 123impl<'d, M: Mode> UsartTx<'d, M> {
148 pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 124 pub fn new<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
149 Usart::<T, M>::init(Some(tx.into()), None, config); 125 Usart::<M>::init::<T>(Some(tx.into()), None, config);
150 Self::new_inner() 126 Self::new_inner(T::info())
151 } 127 }
152 128
153 #[inline] 129 #[inline]
154 fn new_inner() -> Self { 130 fn new_inner(info: &'static Info) -> Self {
155 Self { phantom: PhantomData } 131 Self {
132 info,
133 phantom: PhantomData,
134 }
156 } 135 }
157 136
158 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 137 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
159 T::blocking_write(buffer) 138 for &b in buffer {
139 while !(self.info.usart_reg.fifostat().read().txnotfull()) {}
140 self.info.usart_reg.fifowr().write(|w| w.set_txdata(b as u16));
141 }
142 Ok(())
160 } 143 }
161 144
162 pub fn blocking_flush(&mut self) -> Result<(), Error> { 145 pub fn blocking_flush(&mut self) -> Result<(), Error> {
163 T::blocking_flush() 146 while !(self.info.usart_reg.fifostat().read().txempty()) {}
147 Ok(())
164 } 148 }
165 149
166 pub fn tx_busy(&self) -> bool { 150 pub fn tx_busy(&self) -> bool {
167 T::tx_busy() 151 !(self.info.usart_reg.fifostat().read().txempty())
168 } 152 }
169} 153}
170 154
171impl<'d, T: Instance> UsartTx<'d, T, Blocking> { 155impl<'d> UsartTx<'d, Blocking> {
172 pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 156 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
173 Usart::<T, Blocking>::init(Some(tx.into()), None, config); 157 Usart::<Blocking>::init::<T>(Some(tx.into()), None, config);
174 Self::new_inner() 158 Self::new_inner(T::info())
175 } 159 }
176} 160}
177 161
178impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> { 162impl<'d, M: Mode> UsartRx<'d, M> {
179 pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 163 pub fn new<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
180 Usart::<T, M>::init(None, Some(rx.into()), config); 164 Usart::<M>::init::<T>(None, Some(rx.into()), config);
181 Self::new_inner() 165 Self::new_inner(T::info())
182 } 166 }
183 167
184 #[inline] 168 #[inline]
185 fn new_inner() -> Self { 169 fn new_inner(info: &'static Info) -> Self {
186 Self { phantom: PhantomData } 170 Self {
171 info,
172 phantom: PhantomData,
173 }
187 } 174 }
188 175
189 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 176 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
@@ -201,19 +188,35 @@ impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> {
201 /// - Ok(n) -> read n bytes 188 /// - Ok(n) -> read n bytes
202 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte 189 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte
203 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { 190 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
204 T::drain_fifo(buffer) 191 for (i, b) in buffer.iter_mut().enumerate() {
192 while !(self.info.usart_reg.fifostat().read().rxnotempty()) {}
193 if self.info.usart_reg.fifostat().read().rxerr() {
194 return Err((i, Error::Overrun));
195 } else if self.info.usart_reg.fifordnopop().read().parityerr() {
196 return Err((i, Error::Parity));
197 } else if self.info.usart_reg.fifordnopop().read().framerr() {
198 return Err((i, Error::Framing));
199 } else if self.info.usart_reg.fifordnopop().read().rxnoise() {
200 return Err((i, Error::Noise));
201 } else if self.info.usart_reg.intstat().read().deltarxbrk() {
202 return Err((i, Error::Break));
203 }
204 let dr = self.info.usart_reg.fiford().read().rxdata() as u8;
205 *b = dr;
206 }
207 Ok(buffer.len())
205 } 208 }
206} 209}
207 210
208impl<'d, T: Instance> UsartRx<'d, T, Blocking> { 211impl<'d> UsartRx<'d, Blocking> {
209 pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 212 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
210 Usart::<T, Blocking>::init(None, Some(rx.into()), config); 213 Usart::<Blocking>::init::<T>(None, Some(rx.into()), config);
211 Self::new_inner() 214 Self::new_inner(T::info())
212 } 215 }
213} 216}
214 217
215impl<'d, T: Instance> Usart<'d, T, Blocking> { 218impl<'d> Usart<'d, Blocking> {
216 pub fn new_blocking( 219 pub fn new_blocking<T: Instance>(
217 usart: Peri<'d, T>, 220 usart: Peri<'d, T>,
218 tx: Peri<'d, impl TxPin<T>>, 221 tx: Peri<'d, impl TxPin<T>>,
219 rx: Peri<'d, impl RxPin<T>>, 222 rx: Peri<'d, impl RxPin<T>>,
@@ -223,29 +226,70 @@ impl<'d, T: Instance> Usart<'d, T, Blocking> {
223 } 226 }
224} 227}
225 228
226impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 229impl<'d, M: Mode> Usart<'d, M> {
227 fn new_inner(_usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, config: Config) -> Self { 230 fn new_inner<T: Instance>(
228 Self::init(Some(tx.reborrow()), Some(rx.reborrow()), config); 231 _usart: Peri<'d, T>,
232 mut tx: Peri<'d, AnyPin>,
233 mut rx: Peri<'d, AnyPin>,
234 config: Config,
235 ) -> Self {
236 Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config);
229 Self { 237 Self {
230 tx: UsartTx::new_inner(), 238 tx: UsartTx::new_inner(T::info()),
231 rx: UsartRx::new_inner(), 239 rx: UsartRx::new_inner(T::info()),
232 } 240 }
233 } 241 }
234 242
235 fn init(_tx: Option<Peri<'_, AnyPin>>, _rx: Option<Peri<'_, AnyPin>>, config: Config) { 243 fn init<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>, config: Config) {
236 T::enable_clock(); 244 Self::configure_flexcomm(T::info().fc_reg, T::instance_number());
237 T::reset_flexcomm(); 245 Self::configure_clock::<T>(&config);
238 let source_clock: u32 = T::select_clock(config.baudrate); 246 Self::pin_config::<T>(tx, rx);
239 T::configure_flexcomm(); 247 Self::configure_usart(T::info(), &config);
240 T::tx_pin_config();
241 T::rx_pin_config();
242 Self::set_baudrate(source_clock, config.baudrate);
243 T::configure_usart(config);
244 T::disable_dma();
245 T::enable_usart();
246 } 248 }
247 249
248 fn set_baudrate(source_clock: u32, baudrate: u32) { 250 fn configure_clock<T: Instance>(config: &Config) {
251 // Select source clock
252
253 // Adaptive clock choice based on baud rate
254 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
255 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
256 // and fractional divider (fractional rate divider).
257
258 // By default, oversampling rate is 16 which is an industry standard.
259 // That means 16 clocks are used to deliver the byte to recipient.
260 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
261
262 // Minimum and maximum values were computed taking these formulas into account:
263 // For minimum value, MULT = 0, BRGVAL = 0
264 // For maximum value, MULT = 255, BRGVAL = 255
265 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
266 // By default, OSRVAL = 15 (see above)
267 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
268 let source_clock = match config.baudrate {
269 750_001..=6_000_000 => {
270 SYSCON
271 .fcclksel(T::instance_number())
272 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X3)); // 96 MHz
273 96_000_000
274 }
275 1501..=750_000 => {
276 SYSCON
277 .fcclksel(T::instance_number())
278 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); // 12 MHz
279 12_000_000
280 }
281 121..=1500 => {
282 SYSCON
283 .fcclksel(T::instance_number())
284 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X4)); // 1 MHz
285 1_000_000
286 }
287 _ => {
288 panic!("{} baudrate is not permitted in this mode", config.baudrate);
289 }
290 };
291 // Calculate MULT and BRG values based on baudrate
292
249 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) 293 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
250 // and fractional divider (fractional rate divider). 294 // and fractional divider (fractional rate divider).
251 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 295 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15
@@ -274,14 +318,167 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
274 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. 318 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate.
275 // The deduced formulas are written below. 319 // The deduced formulas are written below.
276 320
277 let brg_value = (source_clock / (16 * baudrate)).min(255); 321 let brg_value = (source_clock / (16 * config.baudrate)).min(255);
278 let raw_clock = source_clock / (16 * brg_value); 322 let raw_clock = source_clock / (16 * brg_value);
279 let mult_value = ((raw_clock * 256 / baudrate) - 256).min(255); 323 let mult_value = ((raw_clock * 256 / config.baudrate) - 256).min(255);
280 T::set_baudrate(mult_value as u8, brg_value as u8); 324
325 // Write values to the registers
326
327 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV)
328 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
329 // to yield a denominator vale of 256. All other values are not supported
330 SYSCON.flexfrgctrl(T::instance_number()).modify(|w| {
331 w.set_div(0xFF);
332 w.set_mult(mult_value as u8);
333 });
334
335 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
336 // By default, oversampling is 16x, i.e. OSRVAL = 15
337
338 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
339 // asynchronous data. This is the number of BRG clocks used for one data bit. The
340 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
341 // oversample clock. There is no oversampling in synchronous modes.
342 T::info()
343 .usart_reg
344 .brg()
345 .modify(|w| w.set_brgval((brg_value - 1) as u16));
346 }
347
348 fn pin_config<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>) {
349 if let Some(tx_pin) = tx {
350 match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), {
351 register.modify(|w| {
352 w.set_func(T::tx_pin_func());
353 w.set_mode(iocon::vals::PioMode::INACTIVE);
354 w.set_slew(iocon::vals::PioSlew::STANDARD);
355 w.set_invert(false);
356 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
357 w.set_od(iocon::vals::PioOd::NORMAL);
358 });
359 })
360 }
361
362 if let Some(rx_pin) = rx {
363 match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), {
364 register.modify(|w| {
365 w.set_func(T::rx_pin_func());
366 w.set_mode(iocon::vals::PioMode::INACTIVE);
367 w.set_slew(iocon::vals::PioSlew::STANDARD);
368 w.set_invert(false);
369 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
370 w.set_od(iocon::vals::PioOd::NORMAL);
371 });
372 })
373 };
374 }
375
376 fn configure_flexcomm(flexcomm_register: crate::pac::flexcomm::Flexcomm, instance_number: usize) {
377 critical_section::with(|_cs| {
378 if !(SYSCON.ahbclkctrl0().read().iocon()) {
379 SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true));
380 }
381 });
382 critical_section::with(|_cs| {
383 if !(SYSCON.ahbclkctrl1().read().fc(instance_number)) {
384 SYSCON.ahbclkctrl1().modify(|w| w.set_fc(instance_number, true));
385 }
386 });
387 SYSCON
388 .presetctrl1()
389 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::ASSERTED));
390 SYSCON
391 .presetctrl1()
392 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED));
393 flexcomm_register
394 .pselid()
395 .modify(|w| w.set_persel(flexcomm::vals::Persel::USART));
396 }
397
398 fn configure_usart(info: &'static Info, config: &Config) {
399 let registers = info.usart_reg;
400 // See section 34.6.1
401 registers.cfg().modify(|w| {
402 // LIN break mode enable
403 // Disabled. Break detect and generate is configured for normal operation.
404 w.set_linmode(false);
405 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
406 //input pin, or from the USART’s own RTS if loopback mode is enabled.
407 // No flow control. The transmitter does not receive any automatic flow control signal.
408 w.set_ctsen(false);
409 // Selects synchronous or asynchronous operation.
410 w.set_syncen(usart::vals::Syncen::ASYNCHRONOUS_MODE);
411 // Selects the clock polarity and sampling edge of received data in synchronous mode.
412 w.set_clkpol(usart::vals::Clkpol::RISING_EDGE);
413 // Synchronous mode Master select.
414 // When synchronous mode is enabled, the USART is a master.
415 w.set_syncmst(usart::vals::Syncmst::MASTER);
416 // Selects data loopback mode
417 w.set_loop_(usart::vals::Loop::NORMAL);
418 // Output Enable Turnaround time enable for RS-485 operation.
419 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
420 // the last stop bit of a transmission.
421 w.set_oeta(false);
422 // Output enable select.
423 // Standard. The RTS signal is used as the standard flow control function.
424 w.set_oesel(usart::vals::Oesel::STANDARD);
425 // Automatic address matching enable.
426 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
427 // software. This provides the possibility of versatile addressing (e.g. respond to more
428 // than one address)
429 w.set_autoaddr(false);
430 // Output enable polarity.
431 // Low. If selected by OESEL, the output enable is active low.
432 w.set_oepol(usart::vals::Oepol::LOW);
433 });
434
435 // Configurations based on the config written by a user
436 registers.cfg().modify(|w| {
437 w.set_datalen(match config.data_bits {
438 DataBits::DataBits7 => usart::vals::Datalen::BIT_7,
439 DataBits::DataBits8 => usart::vals::Datalen::BIT_8,
440 DataBits::DataBits9 => usart::vals::Datalen::BIT_9,
441 });
442 w.set_paritysel(match config.parity {
443 Parity::ParityNone => usart::vals::Paritysel::NO_PARITY,
444 Parity::ParityEven => usart::vals::Paritysel::EVEN_PARITY,
445 Parity::ParityOdd => usart::vals::Paritysel::ODD_PARITY,
446 });
447 w.set_stoplen(match config.stop_bits {
448 StopBits::Stop1 => usart::vals::Stoplen::BIT_1,
449 StopBits::Stop2 => usart::vals::Stoplen::BITS_2,
450 });
451 w.set_rxpol(match config.invert_rx {
452 false => usart::vals::Rxpol::STANDARD,
453 true => usart::vals::Rxpol::INVERTED,
454 });
455 w.set_txpol(match config.invert_tx {
456 false => usart::vals::Txpol::STANDARD,
457 true => usart::vals::Txpol::INVERTED,
458 });
459 });
460
461 // DMA-related settings
462 registers.fifocfg().modify(|w| {
463 w.set_dmatx(false);
464 w.set_dmatx(false);
465 });
466
467 // Enabling USART
468 registers.fifocfg().modify(|w| {
469 w.set_enabletx(true);
470 w.set_enablerx(true);
471 });
472 registers.cfg().modify(|w| w.set_enable(true));
473
474 // Drain RX FIFO in case it still has some unrelevant data
475 while registers.fifostat().read().rxnotempty() {
476 let _ = registers.fiford().read().0;
477 }
281 } 478 }
282} 479}
283 480
284impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 481impl<'d, M: Mode> Usart<'d, M> {
285 /// Transmit the provided buffer blocking execution until done. 482 /// Transmit the provided buffer blocking execution until done.
286 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 483 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
287 self.tx.blocking_write(buffer) 484 self.tx.blocking_write(buffer)
@@ -304,19 +501,19 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
304 501
305 /// Split the Usart into a transmitter and receiver, which is particularly 502 /// Split the Usart into a transmitter and receiver, which is particularly
306 /// useful when having two tasks correlating to transmitting and receiving. 503 /// useful when having two tasks correlating to transmitting and receiving.
307 pub fn split(self) -> (UsartTx<'d, T, M>, UsartRx<'d, T, M>) { 504 pub fn split(self) -> (UsartTx<'d, M>, UsartRx<'d, M>) {
308 (self.tx, self.rx) 505 (self.tx, self.rx)
309 } 506 }
310 507
311 /// Split the Usart into a transmitter and receiver by mutable reference, 508 /// Split the Usart into a transmitter and receiver by mutable reference,
312 /// which is particularly useful when having two tasks correlating to 509 /// which is particularly useful when having two tasks correlating to
313 /// transmitting and receiving. 510 /// transmitting and receiving.
314 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, T, M>, &mut UsartRx<'d, T, M>) { 511 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, M>, &mut UsartRx<'d, M>) {
315 (&mut self.tx, &mut self.rx) 512 (&mut self.tx, &mut self.rx)
316 } 513 }
317} 514}
318 515
319impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, T, M> { 516impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> {
320 type Error = Error; 517 type Error = Error;
321 518
322 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 519 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -328,7 +525,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
328 } 525 }
329} 526}
330 527
331impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, T, M> { 528impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, M> {
332 type Error = Error; 529 type Error = Error;
333 530
334 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 531 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -340,11 +537,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
340 } 537 }
341} 538}
342 539
343impl<'d, T: Instance> embedded_io::ErrorType for UsartTx<'d, T, Blocking> { 540impl<'d> embedded_io::ErrorType for UsartTx<'d, Blocking> {
344 type Error = Error; 541 type Error = Error;
345} 542}
346 543
347impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> { 544impl<'d> embedded_io::Write for UsartTx<'d, Blocking> {
348 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 545 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
349 self.blocking_write(buf).map(|_| buf.len()) 546 self.blocking_write(buf).map(|_| buf.len())
350 } 547 }
@@ -354,21 +551,21 @@ impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> {
354 } 551 }
355} 552}
356 553
357impl<'d, T: Instance> embedded_io::ErrorType for UsartRx<'d, T, Blocking> { 554impl<'d> embedded_io::ErrorType for UsartRx<'d, Blocking> {
358 type Error = Error; 555 type Error = Error;
359} 556}
360 557
361impl<'d, T: Instance> embedded_io::Read for UsartRx<'d, T, Blocking> { 558impl<'d> embedded_io::Read for UsartRx<'d, Blocking> {
362 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 559 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
363 self.blocking_read(buf).map(|_| buf.len()) 560 self.blocking_read(buf).map(|_| buf.len())
364 } 561 }
365} 562}
366 563
367impl<'d, T: Instance> embedded_io::ErrorType for Usart<'d, T, Blocking> { 564impl<'d> embedded_io::ErrorType for Usart<'d, Blocking> {
368 type Error = Error; 565 type Error = Error;
369} 566}
370 567
371impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> { 568impl<'d> embedded_io::Write for Usart<'d, Blocking> {
372 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 569 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
373 self.blocking_write(buf).map(|_| buf.len()) 570 self.blocking_write(buf).map(|_| buf.len())
374 } 571 }
@@ -378,468 +575,69 @@ impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> {
378 } 575 }
379} 576}
380 577
381impl<'d, T: Instance> embedded_io::Read for Usart<'d, T, Blocking> { 578impl<'d> embedded_io::Read for Usart<'d, Blocking> {
382 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 579 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
383 self.blocking_read(buf).map(|_| buf.len()) 580 self.blocking_read(buf).map(|_| buf.len())
384 } 581 }
385} 582}
386 583
387type UsartRegBlock = crate::pac::usart0::RegisterBlock; 584struct Info {
388 585 usart_reg: UsartReg,
389mod sealed { 586 fc_reg: FlexcommReg,
390 use crate::usart::inner::UsartRegBlock; 587}
391 use crate::usart::{Config, Error};
392 pub trait SealedInstance {
393 fn usart_reg() -> &'static UsartRegBlock;
394 fn enable_clock();
395 fn select_clock(baudrate: u32) -> u32;
396 fn configure_flexcomm();
397 fn set_baudrate(mult_value: u8, brg_value: u8);
398 fn reset_flexcomm();
399 fn tx_pin_config();
400 fn rx_pin_config();
401
402 fn configure_usart(config: Config) {
403 // See section 34.6.1
404 Self::usart_reg().cfg.modify(|_, w| {
405 // LIN break mode enable
406 w.linmode()
407 // Disabled. Break detect and generate is configured for normal operation.
408 .disabled()
409 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
410 //input pin, or from the USART’s own RTS if loopback mode is enabled.
411 .ctsen()
412 // No flow control. The transmitter does not receive any automatic flow control signal.
413 .disabled()
414 // Selects synchronous or asynchronous operation.
415 .syncen()
416 .asynchronous_mode()
417 // Selects the clock polarity and sampling edge of received data in synchronous mode.
418 .clkpol()
419 .rising_edge()
420 // Synchronous mode Master select.
421 .syncmst()
422 // When synchronous mode is enabled, the USART is a master.
423 .master()
424 // Selects data loopback mode
425 .loop_()
426 // Normal operation
427 .normal()
428 // Output Enable Turnaround time enable for RS-485 operation.
429 .oeta()
430 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
431 // the last stop bit of a transmission.
432 .disabled()
433 // Output enable select.
434 .oesel()
435 // Standard. The RTS signal is used as the standard flow control function.
436 .standard()
437 // Automatic address matching enable.
438 .autoaddr()
439 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
440 // software. This provides the possibility of versatile addressing (e.g. respond to more
441 // than one address)
442 .disabled()
443 // Output enable polarity.
444 .oepol()
445 // Low. If selected by OESEL, the output enable is active low.
446 .low()
447 });
448 588
449 Self::usart_reg().cfg.modify(|_, w| unsafe { 589trait SealedInstance {
450 w.datalen() 590 fn info() -> &'static Info;
451 .bits(config.data_bits.bits()) 591 fn instance_number() -> usize;
452 .paritysel() 592 fn tx_pin_func() -> PioFunc;
453 .bits(config.parity.bits()) 593 fn rx_pin_func() -> PioFunc;
454 .stoplen()
455 .bit(config.stop_bits.bits())
456 .rxpol()
457 .bit(config.invert_rx)
458 .txpol()
459 .bit(config.invert_tx)
460 });
461 }
462 fn disable_dma() {
463 Self::usart_reg()
464 .fifocfg
465 .modify(|_, w| w.dmatx().disabled().dmarx().disabled());
466 }
467 fn enable_usart() {
468 Self::usart_reg()
469 .fifocfg
470 .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
471 Self::usart_reg().cfg.modify(|_, w| w.enable().enabled());
472 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_set() {
473 let _ = Self::usart_reg().fiford.read().bits();
474 }
475 }
476 fn blocking_write(buffer: &[u8]) -> Result<(), Error> {
477 for &b in buffer {
478 while Self::usart_reg().fifostat.read().txnotfull().bit_is_clear() {}
479 Self::usart_reg()
480 .fifowr
481 .modify(|_, w| unsafe { w.txdata().bits(b as u16) });
482 }
483 Ok(())
484 }
485 fn blocking_flush() -> Result<(), Error> {
486 while Self::usart_reg().fifostat.read().txempty().bit_is_clear() {}
487 Ok(())
488 }
489 fn tx_busy() -> bool {
490 Self::usart_reg().fifostat.read().txempty().bit_is_clear()
491 }
492 fn drain_fifo(buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
493 for (i, b) in buffer.iter_mut().enumerate() {
494 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_clear() {}
495
496 if Self::usart_reg().fifostat.read().rxerr().bit_is_set() {
497 return Err((i, Error::Overrun));
498 } else if Self::usart_reg().fifordnopop.read().parityerr().bit_is_set() {
499 return Err((i, Error::Parity));
500 } else if Self::usart_reg().fifordnopop.read().framerr().bit_is_set() {
501 return Err((i, Error::Framing));
502 } else if Self::usart_reg().fifordnopop.read().rxnoise().bit_is_set() {
503 return Err((i, Error::Noise));
504 } else if Self::usart_reg().intstat.read().deltarxbrk().bit_is_set() {
505 return Err((i, Error::Break));
506 }
507 let dr = Self::usart_reg().fiford.read().bits() as u8;
508 *b = dr;
509 }
510 Ok(buffer.len())
511 }
512 }
513} 594}
514 595
515/// UART instance. 596/// UART instance.
516#[allow(private_bounds)] 597#[allow(private_bounds)]
517pub trait Instance: sealed::SealedInstance + PeripheralType {} 598pub trait Instance: SealedInstance + PeripheralType {}
518 599
519#[macro_export]
520macro_rules! impl_instance { 600macro_rules! impl_instance {
521 ( 601 ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => {
522 $inst:ident, 602 impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst {
523 usart_peripheral: $USARTX:ident, 603 fn info() -> &'static Info {
524 usart_crate: $usartX:ident, 604 static INFO: Info = Info {
525 605 usart_reg: crate::pac::$inst,
526 flexcomm: { 606 fc_reg: crate::pac::$fc,
527 field: $FLEXCOMM_FIELD:ident,
528 clock_field: $FLEXCOMM_CLK_FIELD:ident
529 },
530
531 reset: {
532 bit: $RESET_BIT:ident
533 },
534
535 clock: {
536 sel_field: $CLKSEL_FIELD:ident,
537 frg_field: $FRG_FIELD:ident
538 },
539
540 pins: {
541 tx: $TX_IOCON:ident => $TX_FUNC:expr,
542 rx: $RX_IOCON:ident => $RX_FUNC:expr
543 }
544
545 ) => {
546 impl $crate::usart::SealedInstance for $crate::peripherals::$inst {
547 fn usart_reg() -> &'static UsartRegBlock {
548 unsafe { &*$crate::pac::$USARTX::ptr() }
549 }
550
551 fn enable_clock() {
552 critical_section::with(|_cs| {
553 if syscon_reg().ahbclkctrl0.read().iocon().is_disable() {
554 syscon_reg().ahbclkctrl0.modify(|_, w| w.iocon().enable());
555 }
556 if syscon_reg().ahbclkctrl1.read().$FLEXCOMM_CLK_FIELD().is_disable() {
557 syscon_reg()
558 .ahbclkctrl1
559 .modify(|_, w| w.$FLEXCOMM_CLK_FIELD().enable());
560 }
561 });
562 }
563
564 fn configure_flexcomm() {
565 let flexcomm = unsafe { &*$crate::pac::$FLEXCOMM_FIELD::ptr() };
566 flexcomm.pselid.modify(|_, w| w.persel().usart());
567 }
568
569 fn reset_flexcomm() {
570 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().set_bit());
571 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().clear_bit());
572 }
573
574 fn select_clock(baudrate: u32) -> u32 {
575 // Adaptive clock choice based on baud rate
576 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
577 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
578 // and fractional divider (fractional rate divider).
579
580 // By default, oversampling rate is 16 which is an industry standard.
581 // That means 16 clocks are used to deliver the byte to recipient.
582 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
583
584 // Minimum and maximum values were computed taking these formulas into account:
585 // For minimum value, MULT = 0, BRGVAL = 0
586 // For maximum value, MULT = 255, BRGVAL = 255
587 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
588 // By default, OSRVAL = 15 (see above)
589 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
590 return match baudrate {
591 750_001..=6000000 => {
592 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x3()); // 96 MHz
593 96_000_000
594 }
595 1501..=750_000 => {
596 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x2()); // 12 MHz
597 12_000_000
598 }
599 121..=1500 => {
600 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x4()); // 1 MHz
601 1_000_000
602 }
603 _ => {
604 panic!("{} baudrate is not permitted in this mode", baudrate);
605 }
606 }; 607 };
608 &INFO
607 } 609 }
608 610 #[inline]
609 fn set_baudrate(mult_value: u8, brg_value: u8) { 611 fn instance_number() -> usize {
610 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) 612 $fc_num
611 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
612 // to yield a denominator vale of 256. All other values are not supported
613 syscon_reg()
614 .$FRG_FIELD()
615 .modify(|_, w| unsafe { w.div().bits(0xFF).mult().bits(mult_value as u8) });
616
617 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
618 // By default, oversampling is 16x, i.e. OSRVAL = 15
619
620 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
621 // asynchronous data. This is the number of BRG clocks used for one data bit. The
622 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
623 // oversample clock. There is no oversampling in synchronous modes.
624 Self::usart_reg()
625 .brg
626 .modify(|_, w| unsafe { w.brgval().bits((brg_value - 1) as u16) });
627 } 613 }
628 614 #[inline]
629 fn tx_pin_config() { 615 fn tx_pin_func() -> PioFunc {
630 iocon_reg().$TX_IOCON.modify(|_, w| unsafe { 616 PioFunc::$tx_pin
631 w.func()
632 .bits($TX_FUNC)
633 .digimode()
634 .digital()
635 .slew()
636 .standard()
637 .mode()
638 .inactive()
639 .invert()
640 .disabled()
641 .od()
642 .normal()
643 });
644 } 617 }
645 618 #[inline]
646 fn rx_pin_config() { 619 fn rx_pin_func() -> PioFunc {
647 iocon_reg().$RX_IOCON.modify(|_, w| unsafe { 620 PioFunc::$rx_pin
648 w.func()
649 .bits($RX_FUNC)
650 .digimode()
651 .digital()
652 .slew()
653 .standard()
654 .mode()
655 .inactive()
656 .invert()
657 .disabled()
658 .od()
659 .normal()
660 });
661 } 621 }
662 } 622 }
663
664 impl $crate::usart::Instance for $crate::peripherals::$inst {} 623 impl $crate::usart::Instance for $crate::peripherals::$inst {}
665 }; 624 };
666} 625}
667 626
668impl_instance!(USART0, usart_peripheral: USART0, usart_crate: usart0, 627impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0);
669 flexcomm: { 628impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1);
670 field: FLEXCOMM0, 629impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2);
671 clock_field: fc0 630impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3);
672 }, 631impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4);
673 632impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5);
674 reset: { 633impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6);
675 bit: fc0_rst 634impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7);
676 },
677
678 clock: {
679 sel_field: fcclksel0,
680 frg_field: flexfrg0ctrl
681 },
682
683 pins: {
684 tx: pio1_6 => 1,
685 rx: pio1_5 => 1
686 }
687);
688
689impl_instance!(USART1, usart_peripheral: USART1, usart_crate: usart1,
690 flexcomm: {
691 field: FLEXCOMM1,
692 clock_field: fc1
693 },
694
695 reset: {
696 bit: fc1_rst
697 },
698
699 clock: {
700 sel_field: fcclksel1,
701 frg_field: flexfrg1ctrl
702 },
703
704 pins: {
705 tx: pio1_11 => 2,
706 rx: pio1_10 => 2
707 }
708);
709
710impl_instance!(USART2, usart_peripheral: USART2, usart_crate: usart2,
711 flexcomm: {
712 field: FLEXCOMM2,
713 clock_field: fc2
714 },
715
716 reset: {
717 bit: fc2_rst
718 },
719
720 clock: {
721 sel_field: fcclksel2,
722 frg_field: flexfrg2ctrl
723 },
724
725 pins: {
726 tx: pio0_27 => 1,
727 rx: pio1_24 => 1
728 }
729);
730
731impl_instance!(USART3, usart_peripheral: USART3, usart_crate: usart3,
732 flexcomm: {
733 field: FLEXCOMM3,
734 clock_field: fc3
735 },
736
737 reset: {
738 bit: fc3_rst
739 },
740
741 clock: {
742 sel_field: fcclksel3,
743 frg_field: flexfrg3ctrl
744 },
745
746 pins: {
747 tx: pio0_2 => 1,
748 rx: pio0_3 => 1
749 }
750);
751
752impl_instance!(USART4, usart_peripheral: USART4, usart_crate: usart4,
753 flexcomm: {
754 field: FLEXCOMM4,
755 clock_field: fc4
756 },
757
758 reset: {
759 bit: fc4_rst
760 },
761
762 clock: {
763 sel_field: fcclksel4,
764 frg_field: flexfrg4ctrl
765 },
766
767 pins: {
768 tx: pio0_16 => 1,
769 rx: pio0_5 => 2
770 }
771);
772
773impl_instance!(USART5, usart_peripheral: USART5, usart_crate: usart5,
774 flexcomm: {
775 field: FLEXCOMM5,
776 clock_field: fc5
777 },
778
779 reset: {
780 bit: fc5_rst
781 },
782
783 clock: {
784 sel_field: fcclksel5,
785 frg_field: flexfrg5ctrl
786 },
787
788 pins: {
789 tx: pio0_9 => 3,
790 rx: pio0_8 => 3
791 }
792);
793
794impl_instance!(USART6, usart_peripheral: USART6, usart_crate: usart6,
795 flexcomm: {
796 field: FLEXCOMM6,
797 clock_field: fc6
798 },
799
800 reset: {
801 bit: fc6_rst
802 },
803
804 clock: {
805 sel_field: fcclksel6,
806 frg_field: flexfrg6ctrl
807 },
808
809 pins: {
810 tx: pio1_16 => 2,
811 rx: pio1_13 => 2
812 }
813);
814
815impl_instance!(USART7, usart_peripheral: USART7, usart_crate: usart7,
816 flexcomm: {
817 field: FLEXCOMM7,
818 clock_field: fc7
819 },
820
821 reset: {
822 bit: fc7_rst
823 },
824
825 clock: {
826 sel_field: fcclksel7,
827 frg_field: flexfrg7ctrl
828 },
829
830 pins: {
831 tx: pio0_19 => 7,
832 rx: pio0_20 => 7
833 }
834);
835 635
836/// Trait for TX pins. 636/// Trait for TX pins.
837pub trait TxPin<T: Instance>: crate::gpio::Pin {} 637pub trait TxPin<T: Instance>: crate::gpio::Pin {}
838/// Trait for RX pins. 638/// Trait for RX pins.
839pub trait RxPin<T: Instance>: crate::gpio::Pin {} 639pub trait RxPin<T: Instance>: crate::gpio::Pin {}
840 640
841// TODO: Add RTS, CTS and CLK pin traits
842
843macro_rules! impl_pin { 641macro_rules! impl_pin {
844 ($pin:ident, $instance:ident, Tx) => { 642 ($pin:ident, $instance:ident, Tx) => {
845 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} 643 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
@@ -849,37 +647,19 @@ macro_rules! impl_pin {
849 }; 647 };
850} 648}
851 649
852impl_pin!(PIO1_5, USART0, Rx);
853impl_pin!(PIO1_6, USART0, Tx); 650impl_pin!(PIO1_6, USART0, Tx);
854impl_pin!(PIO1_10, USART1, Rx); 651impl_pin!(PIO1_5, USART0, Rx);
855impl_pin!(PIO1_11, USART1, Tx); 652impl_pin!(PIO1_11, USART1, Tx);
653impl_pin!(PIO1_10, USART1, Rx);
856impl_pin!(PIO0_27, USART2, Tx); 654impl_pin!(PIO0_27, USART2, Tx);
857impl_pin!(PIO1_24, USART2, Rx); 655impl_pin!(PIO1_24, USART2, Rx);
858impl_pin!(PIO0_2, USART3, Tx); 656impl_pin!(PIO0_2, USART3, Tx);
859impl_pin!(PIO0_3, USART3, Rx); 657impl_pin!(PIO0_3, USART3, Rx);
860impl_pin!(PIO0_16, USART4, Tx); 658impl_pin!(PIO0_16, USART4, Tx);
861impl_pin!(PIO0_5, USART4, Rx); 659impl_pin!(PIO0_5, USART4, Rx);
862impl_pin!(PIO0_8, USART5, Rx);
863impl_pin!(PIO0_9, USART5, Tx); 660impl_pin!(PIO0_9, USART5, Tx);
661impl_pin!(PIO0_8, USART5, Rx);
864impl_pin!(PIO1_16, USART6, Tx); 662impl_pin!(PIO1_16, USART6, Tx);
865impl_pin!(PIO1_13, USART6, Rx); 663impl_pin!(PIO1_13, USART6, Rx);
866impl_pin!(PIO0_20, USART7, Rx);
867impl_pin!(PIO0_19, USART7, Tx); 664impl_pin!(PIO0_19, USART7, Tx);
868 665impl_pin!(PIO0_20, USART7, Rx);
869/// Get the SYSCON register block.
870///
871/// # Safety
872/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
873/// registers are not accessed concurrently by multiple threads.
874pub(crate) fn syscon_reg() -> &'static crate::pac::syscon::RegisterBlock {
875 unsafe { &*crate::pac::SYSCON::ptr() }
876}
877
878/// Get the IOCON register block.
879///
880/// # Safety
881/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
882/// registers are not accessed concurrently by multiple threads.
883pub(crate) fn iocon_reg() -> &'static crate::pac::iocon::RegisterBlock {
884 unsafe { &*crate::pac::IOCON::ptr() }
885}
diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml
index 79b27f269..579748595 100644
--- a/examples/lpc55s69/Cargo.toml
+++ b/examples/lpc55s69/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7publish = false 7publish = false
8 8
9[dependencies] 9[dependencies]
10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt", "time-driver-rtc"] } 10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55-core0", "rt", "defmt", "time-driver-rtc"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] }