aboutsummaryrefslogtreecommitdiff
path: root/embassy-nxp
diff options
context:
space:
mode:
authorGerzain Mata <[email protected]>2025-07-23 00:53:10 -0700
committerGerzain Mata <[email protected]>2025-07-23 00:53:10 -0700
commite2cec28805a66fa913fcdc3af2de07b95b06aa0d (patch)
tree1ea685cd96ceef15a7b0f2975a55495598c0e5ef /embassy-nxp
parenta80eb48e67d486ace9b9a4733f2b54d58a80eb52 (diff)
parent8f5e4ac06d1d06dd6520a8eecf8697b199005f34 (diff)
Merge branch 'main' into feat/stm32wba-usb-example
Diffstat (limited to 'embassy-nxp')
-rw-r--r--embassy-nxp/Cargo.toml37
-rw-r--r--embassy-nxp/build.rs138
-rw-r--r--embassy-nxp/build_common.rs94
-rw-r--r--embassy-nxp/src/chips/mimxrt1011.rs113
-rw-r--r--embassy-nxp/src/chips/mimxrt1062.rs282
-rw-r--r--embassy-nxp/src/fmt.rs284
-rw-r--r--embassy-nxp/src/gpio.rs2
-rw-r--r--embassy-nxp/src/gpio/lpc55.rs1
-rw-r--r--embassy-nxp/src/gpio/rt1xxx.rs945
-rw-r--r--embassy-nxp/src/lib.rs87
-rw-r--r--embassy-nxp/src/pint.rs2
-rw-r--r--embassy-nxp/src/time_driver/pit.rs187
12 files changed, 2164 insertions, 8 deletions
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index 01f57c4e2..293791d34 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -10,23 +10,52 @@ critical-section = "1.1.2"
10embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 10embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
11embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 11embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
12defmt = { version = "1", optional = true } 12defmt = { version = "1", optional = true }
13log = { version = "0.4.27", optional = true }
14embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
15embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true }
16embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
13 17
14## Chip dependencies 18## Chip dependencies
15lpc55-pac = { version = "0.5.0", optional = true } 19lpc55-pac = { version = "0.5.0", optional = true }
20nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
21
22imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
23
24[build-dependencies]
25cfg_aliases = "0.2.1"
26nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true }
27proc-macro2 = "1.0.95"
28quote = "1.0.15"
16 29
17[features] 30[features]
18default = ["rt"] 31default = ["rt"]
19# Enable PACs as optional dependencies, since some chip families will use different pac crates. 32# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
20rt = ["lpc55-pac?/rt"] 33rt = ["lpc55-pac?/rt", "nxp-pac?/rt"]
21 34
22## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 35## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
23defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"] 36defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
24 37
38log = ["dep:log"]
39
40## Use Periodic Interrupt Timer (PIT) as the time driver for `embassy-time`, with a tick rate of 1 MHz
41time-driver-pit = ["_time_driver", "embassy-time?/tick-hz-1_000_000"]
42
25## Reexport the PAC for the currently enabled chip at `embassy_nxp::pac` (unstable) 43## Reexport the PAC for the currently enabled chip at `embassy_nxp::pac` (unstable)
26unstable-pac = [] 44unstable-pac = []
27# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 45# This is unstable because semver-minor (non-breaking) releases of embassy-nxp may major-bump (breaking) the PAC version.
28# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 46# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
29# There are no plans to make this stable. 47# There are no plans to make this stable.
30 48
49## internal use only
50#
51# This feature is unfortunately a hack around the fact that cfg_aliases cannot apply to the buildscript
52# that creates the aliases.
53_rt1xxx = []
54
55# A timer driver is enabled.
56_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
57
31#! ### Chip selection features 58#! ### Chip selection features
32lpc55 = ["lpc55-pac"] 59lpc55 = ["dep:lpc55-pac"]
60mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
61mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]
diff --git a/embassy-nxp/build.rs b/embassy-nxp/build.rs
new file mode 100644
index 000000000..f3c062c87
--- /dev/null
+++ b/embassy-nxp/build.rs
@@ -0,0 +1,138 @@
1use std::io::Write;
2use std::path::{Path, PathBuf};
3use std::process::Command;
4use std::{env, fs};
5
6use cfg_aliases::cfg_aliases;
7#[cfg(feature = "_rt1xxx")]
8use nxp_pac::metadata;
9#[allow(unused)]
10use proc_macro2::TokenStream;
11#[allow(unused)]
12use quote::quote;
13
14#[path = "./build_common.rs"]
15mod common;
16
17fn main() {
18 let mut cfgs = common::CfgSet::new();
19 common::set_target_cfgs(&mut cfgs);
20
21 let chip_name = match env::vars()
22 .map(|(a, _)| a)
23 .filter(|x| x.starts_with("CARGO_FEATURE_MIMXRT") || x.starts_with("CARGO_FEATURE_LPC"))
24 .get_one()
25 {
26 Ok(x) => x,
27 Err(GetOneError::None) => panic!("No mimxrt/lpc Cargo feature enabled"),
28 Err(GetOneError::Multiple) => panic!("Multiple mimxrt/lpc Cargo features enabled"),
29 }
30 .strip_prefix("CARGO_FEATURE_")
31 .unwrap()
32 .to_ascii_lowercase();
33
34 cfg_aliases! {
35 rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
36 gpio1: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
37 gpio2: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
38 gpio3: { feature = "mimxrt1062" },
39 gpio4: { feature = "mimxrt1062" },
40 gpio5: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
41 }
42
43 eprintln!("chip: {chip_name}");
44
45 generate_code();
46}
47
48#[cfg(feature = "_rt1xxx")]
49fn generate_iomuxc() -> TokenStream {
50 use proc_macro2::{Ident, Span};
51
52 let pads = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
53 let name = Ident::new(&registers.name, Span::call_site());
54 let address = registers.pad_ctl;
55
56 quote! {
57 pub const #name: u32 = #address;
58 }
59 });
60
61 let muxes = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
62 let name = Ident::new(&registers.name, Span::call_site());
63 let address = registers.mux_ctl;
64
65 quote! {
66 pub const #name: u32 = #address;
67 }
68 });
69
70 quote! {
71 pub mod iomuxc {
72 pub mod pads {
73 #(#pads)*
74 }
75
76 pub mod muxes {
77 #(#muxes)*
78 }
79 }
80 }
81}
82
83fn generate_code() {
84 #[allow(unused)]
85 use std::fmt::Write;
86
87 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
88 #[allow(unused_mut)]
89 let mut output = String::new();
90
91 #[cfg(feature = "_rt1xxx")]
92 writeln!(&mut output, "{}", generate_iomuxc()).unwrap();
93
94 let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
95 fs::write(&out_file, output).unwrap();
96 rustfmt(&out_file);
97}
98
99/// rustfmt a given path.
100/// Failures are logged to stderr and ignored.
101fn rustfmt(path: impl AsRef<Path>) {
102 let path = path.as_ref();
103 match Command::new("rustfmt").args([path]).output() {
104 Err(e) => {
105 eprintln!("failed to exec rustfmt {:?}: {:?}", path, e);
106 }
107 Ok(out) => {
108 if !out.status.success() {
109 eprintln!("rustfmt {:?} failed:", path);
110 eprintln!("=== STDOUT:");
111 std::io::stderr().write_all(&out.stdout).unwrap();
112 eprintln!("=== STDERR:");
113 std::io::stderr().write_all(&out.stderr).unwrap();
114 }
115 }
116 }
117}
118
119enum GetOneError {
120 None,
121 Multiple,
122}
123
124trait IteratorExt: Iterator {
125 fn get_one(self) -> Result<Self::Item, GetOneError>;
126}
127
128impl<T: Iterator> IteratorExt for T {
129 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
130 match self.next() {
131 None => Err(GetOneError::None),
132 Some(res) => match self.next() {
133 Some(_) => Err(GetOneError::Multiple),
134 None => Ok(res),
135 },
136 }
137 }
138}
diff --git a/embassy-nxp/build_common.rs b/embassy-nxp/build_common.rs
new file mode 100644
index 000000000..4f24e6d37
--- /dev/null
+++ b/embassy-nxp/build_common.rs
@@ -0,0 +1,94 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11
12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
13/// them (`cargo:rust-check-cfg=cfg(X)`).
14#[derive(Debug)]
15pub struct CfgSet {
16 enabled: HashSet<String>,
17 declared: HashSet<String>,
18}
19
20impl CfgSet {
21 pub fn new() -> Self {
22 Self {
23 enabled: HashSet::new(),
24 declared: HashSet::new(),
25 }
26 }
27
28 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
29 ///
30 /// All configs that can potentially be enabled should be unconditionally declared using
31 /// [`Self::declare()`].
32 pub fn enable(&mut self, cfg: impl AsRef<str>) {
33 if self.enabled.insert(cfg.as_ref().to_owned()) {
34 println!("cargo:rustc-cfg={}", cfg.as_ref());
35 }
36 }
37
38 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
39 for cfg in cfgs.iter() {
40 self.enable(cfg.as_ref());
41 }
42 }
43
44 /// Declare a valid config for conditional compilation, without enabling it.
45 ///
46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
48 if self.declared.insert(cfg.as_ref().to_owned()) {
49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
50 }
51 }
52
53 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
54 for cfg in cfgs.iter() {
55 self.declare(cfg.as_ref());
56 }
57 }
58
59 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
60 let cfg = cfg.into();
61 if enable {
62 self.enable(cfg.clone());
63 }
64 self.declare(cfg);
65 }
66}
67
68/// Sets configs that describe the target platform.
69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
70 let target = env::var("TARGET").unwrap();
71
72 if target.starts_with("thumbv6m-") {
73 cfgs.enable_all(&["cortex_m", "armv6m"]);
74 } else if target.starts_with("thumbv7m-") {
75 cfgs.enable_all(&["cortex_m", "armv7m"]);
76 } else if target.starts_with("thumbv7em-") {
77 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
78 } else if target.starts_with("thumbv8m.base") {
79 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
80 } else if target.starts_with("thumbv8m.main") {
81 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
82 }
83 cfgs.declare_all(&[
84 "cortex_m",
85 "armv6m",
86 "armv7m",
87 "armv7em",
88 "armv8m",
89 "armv8m_base",
90 "armv8m_main",
91 ]);
92
93 cfgs.set("has_fpu", target.ends_with("-eabihf"));
94}
diff --git a/embassy-nxp/src/chips/mimxrt1011.rs b/embassy-nxp/src/chips/mimxrt1011.rs
new file mode 100644
index 000000000..a74d953fc
--- /dev/null
+++ b/embassy-nxp/src/chips/mimxrt1011.rs
@@ -0,0 +1,113 @@
1// This must be imported so that __preinit is defined.
2use imxrt_rt as _;
3pub use nxp_pac as pac;
4
5embassy_hal_internal::peripherals! {
6 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
7 // peripheral types (e.g. I2C).
8 GPIO_00,
9 GPIO_01,
10 GPIO_02,
11 GPIO_03,
12 GPIO_04,
13 GPIO_05,
14 GPIO_06,
15 GPIO_07,
16 GPIO_08,
17 GPIO_09,
18 GPIO_10,
19 GPIO_11,
20 GPIO_12,
21 GPIO_13,
22 GPIO_AD_00,
23 GPIO_AD_01,
24 GPIO_AD_02,
25 GPIO_AD_03,
26 GPIO_AD_04,
27 GPIO_AD_05,
28 GPIO_AD_06,
29 GPIO_AD_07,
30 GPIO_AD_08,
31 GPIO_AD_09,
32 GPIO_AD_10,
33 GPIO_AD_11,
34 GPIO_AD_12,
35 GPIO_AD_13,
36 GPIO_AD_14,
37 GPIO_SD_00,
38 GPIO_SD_01,
39 GPIO_SD_02,
40 GPIO_SD_03,
41 GPIO_SD_04,
42 GPIO_SD_05,
43 GPIO_SD_06,
44 GPIO_SD_07,
45 GPIO_SD_08,
46 GPIO_SD_09,
47 GPIO_SD_10,
48 GPIO_SD_11,
49 GPIO_SD_12,
50 GPIO_SD_13,
51 PMIC_ON_REQ,
52}
53
54impl_gpio! {
55 // GPIO Bank 1
56 GPIO_00(Gpio1, 0);
57 GPIO_01(Gpio1, 1);
58 GPIO_02(Gpio1, 2);
59 GPIO_03(Gpio1, 3);
60 GPIO_04(Gpio1, 4);
61 GPIO_05(Gpio1, 5);
62 GPIO_06(Gpio1, 6);
63 GPIO_07(Gpio1, 7);
64 GPIO_08(Gpio1, 8);
65 GPIO_09(Gpio1, 9);
66 GPIO_10(Gpio1, 10);
67 GPIO_11(Gpio1, 11);
68 GPIO_12(Gpio1, 12);
69 GPIO_13(Gpio1, 13);
70 GPIO_AD_00(Gpio1, 14);
71 GPIO_AD_01(Gpio1, 15);
72 GPIO_AD_02(Gpio1, 16);
73 GPIO_AD_03(Gpio1, 17);
74 GPIO_AD_04(Gpio1, 18);
75 GPIO_AD_05(Gpio1, 19);
76 GPIO_AD_06(Gpio1, 20);
77 GPIO_AD_07(Gpio1, 21);
78 GPIO_AD_08(Gpio1, 22);
79 GPIO_AD_09(Gpio1, 23);
80 GPIO_AD_10(Gpio1, 24);
81 GPIO_AD_11(Gpio1, 25);
82 GPIO_AD_12(Gpio1, 26);
83 GPIO_AD_13(Gpio1, 27);
84 GPIO_AD_14(Gpio1, 28);
85
86 // GPIO Bank 2
87 GPIO_SD_00(Gpio2, 0);
88 GPIO_SD_01(Gpio2, 1);
89 GPIO_SD_02(Gpio2, 2);
90 GPIO_SD_03(Gpio2, 3);
91 GPIO_SD_04(Gpio2, 4);
92 GPIO_SD_05(Gpio2, 5);
93 GPIO_SD_06(Gpio2, 6);
94 GPIO_SD_07(Gpio2, 7);
95 GPIO_SD_08(Gpio2, 8);
96 GPIO_SD_09(Gpio2, 9);
97 GPIO_SD_10(Gpio2, 10);
98 GPIO_SD_11(Gpio2, 11);
99 GPIO_SD_12(Gpio2, 12);
100 GPIO_SD_13(Gpio2, 13);
101
102 // GPIO Bank 5
103 PMIC_ON_REQ(Gpio5, 0);
104}
105
106pub(crate) mod _generated {
107 #![allow(dead_code)]
108 #![allow(unused_imports)]
109 #![allow(non_snake_case)]
110 #![allow(missing_docs)]
111
112 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
113}
diff --git a/embassy-nxp/src/chips/mimxrt1062.rs b/embassy-nxp/src/chips/mimxrt1062.rs
new file mode 100644
index 000000000..ef153bd66
--- /dev/null
+++ b/embassy-nxp/src/chips/mimxrt1062.rs
@@ -0,0 +1,282 @@
1// This must be imported so that __preinit is defined.
2use imxrt_rt as _;
3pub use nxp_pac as pac;
4
5embassy_hal_internal::peripherals! {
6 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
7 // peripheral types (e.g. I2C).
8 GPIO_AD_B0_00,
9 GPIO_AD_B0_01,
10 GPIO_AD_B0_02,
11 GPIO_AD_B0_03,
12 GPIO_AD_B0_04,
13 GPIO_AD_B0_05,
14 GPIO_AD_B0_06,
15 GPIO_AD_B0_07,
16 GPIO_AD_B0_08,
17 GPIO_AD_B0_09,
18 GPIO_AD_B0_10,
19 GPIO_AD_B0_11,
20 GPIO_AD_B0_12,
21 GPIO_AD_B0_13,
22 GPIO_AD_B0_14,
23 GPIO_AD_B0_15,
24 GPIO_AD_B1_00,
25 GPIO_AD_B1_01,
26 GPIO_AD_B1_02,
27 GPIO_AD_B1_03,
28 GPIO_AD_B1_04,
29 GPIO_AD_B1_05,
30 GPIO_AD_B1_06,
31 GPIO_AD_B1_07,
32 GPIO_AD_B1_08,
33 GPIO_AD_B1_09,
34 GPIO_AD_B1_10,
35 GPIO_AD_B1_11,
36 GPIO_AD_B1_12,
37 GPIO_AD_B1_13,
38 GPIO_AD_B1_14,
39 GPIO_AD_B1_15,
40 GPIO_B0_00,
41 GPIO_B0_01,
42 GPIO_B0_02,
43 GPIO_B0_03,
44 GPIO_B0_04,
45 GPIO_B0_05,
46 GPIO_B0_06,
47 GPIO_B0_07,
48 GPIO_B0_08,
49 GPIO_B0_09,
50 GPIO_B0_10,
51 GPIO_B0_11,
52 GPIO_B0_12,
53 GPIO_B0_13,
54 GPIO_B0_14,
55 GPIO_B0_15,
56 GPIO_B1_00,
57 GPIO_B1_01,
58 GPIO_B1_02,
59 GPIO_B1_03,
60 GPIO_B1_04,
61 GPIO_B1_05,
62 GPIO_B1_06,
63 GPIO_B1_07,
64 GPIO_B1_08,
65 GPIO_B1_09,
66 GPIO_B1_10,
67 GPIO_B1_11,
68 GPIO_B1_12,
69 GPIO_B1_13,
70 GPIO_B1_14,
71 GPIO_B1_15,
72 GPIO_EMC_00,
73 GPIO_EMC_01,
74 GPIO_EMC_02,
75 GPIO_EMC_03,
76 GPIO_EMC_04,
77 GPIO_EMC_05,
78 GPIO_EMC_06,
79 GPIO_EMC_07,
80 GPIO_EMC_08,
81 GPIO_EMC_09,
82 GPIO_EMC_10,
83 GPIO_EMC_11,
84 GPIO_EMC_12,
85 GPIO_EMC_13,
86 GPIO_EMC_14,
87 GPIO_EMC_15,
88 GPIO_EMC_16,
89 GPIO_EMC_17,
90 GPIO_EMC_18,
91 GPIO_EMC_19,
92 GPIO_EMC_20,
93 GPIO_EMC_21,
94 GPIO_EMC_22,
95 GPIO_EMC_23,
96 GPIO_EMC_24,
97 GPIO_EMC_25,
98 GPIO_EMC_26,
99 GPIO_EMC_27,
100 GPIO_EMC_28,
101 GPIO_EMC_29,
102 GPIO_EMC_30,
103 GPIO_EMC_31,
104 GPIO_EMC_32,
105 GPIO_EMC_33,
106 GPIO_EMC_34,
107 GPIO_EMC_35,
108 GPIO_EMC_36,
109 GPIO_EMC_37,
110 GPIO_EMC_38,
111 GPIO_EMC_39,
112 GPIO_EMC_40,
113 GPIO_EMC_41,
114 GPIO_SD_B0_00,
115 GPIO_SD_B0_01,
116 GPIO_SD_B0_02,
117 GPIO_SD_B0_03,
118 GPIO_SD_B0_04,
119 GPIO_SD_B0_05,
120 GPIO_SD_B1_00,
121 GPIO_SD_B1_01,
122 GPIO_SD_B1_02,
123 GPIO_SD_B1_03,
124 GPIO_SD_B1_04,
125 GPIO_SD_B1_05,
126 GPIO_SD_B1_06,
127 GPIO_SD_B1_07,
128 GPIO_SD_B1_08,
129 GPIO_SD_B1_09,
130 GPIO_SD_B1_10,
131 GPIO_SD_B1_11,
132 WAKEUP,
133 PMIC_ON_REQ,
134 PMIC_STBY_REQ,
135}
136
137impl_gpio! {
138 // GPIO Bank 1
139 GPIO_AD_B0_00(Gpio1, 0);
140 GPIO_AD_B0_01(Gpio1, 1);
141 GPIO_AD_B0_02(Gpio1, 2);
142 GPIO_AD_B0_03(Gpio1, 3);
143 GPIO_AD_B0_04(Gpio1, 4);
144 GPIO_AD_B0_05(Gpio1, 5);
145 GPIO_AD_B0_06(Gpio1, 6);
146 GPIO_AD_B0_07(Gpio1, 7);
147 GPIO_AD_B0_08(Gpio1, 8);
148 GPIO_AD_B0_09(Gpio1, 9);
149 GPIO_AD_B0_10(Gpio1, 10);
150 GPIO_AD_B0_11(Gpio1, 11);
151 GPIO_AD_B0_12(Gpio1, 12);
152 GPIO_AD_B0_13(Gpio1, 13);
153 GPIO_AD_B0_14(Gpio1, 14);
154 GPIO_AD_B0_15(Gpio1, 15);
155 GPIO_AD_B1_00(Gpio1, 16);
156 GPIO_AD_B1_01(Gpio1, 17);
157 GPIO_AD_B1_02(Gpio1, 18);
158 GPIO_AD_B1_03(Gpio1, 19);
159 GPIO_AD_B1_04(Gpio1, 20);
160 GPIO_AD_B1_05(Gpio1, 21);
161 GPIO_AD_B1_06(Gpio1, 22);
162 GPIO_AD_B1_07(Gpio1, 23);
163 GPIO_AD_B1_08(Gpio1, 24);
164 GPIO_AD_B1_09(Gpio1, 25);
165 GPIO_AD_B1_10(Gpio1, 26);
166 GPIO_AD_B1_11(Gpio1, 27);
167 GPIO_AD_B1_12(Gpio1, 28);
168 GPIO_AD_B1_13(Gpio1, 29);
169 GPIO_AD_B1_14(Gpio1, 30);
170 GPIO_AD_B1_15(Gpio1, 31);
171
172 // GPIO Bank 2
173 GPIO_B0_00(Gpio2, 0);
174 GPIO_B0_01(Gpio2, 1);
175 GPIO_B0_02(Gpio2, 2);
176 GPIO_B0_03(Gpio2, 3);
177 GPIO_B0_04(Gpio2, 4);
178 GPIO_B0_05(Gpio2, 5);
179 GPIO_B0_06(Gpio2, 6);
180 GPIO_B0_07(Gpio2, 7);
181 GPIO_B0_08(Gpio2, 8);
182 GPIO_B0_09(Gpio2, 9);
183 GPIO_B0_10(Gpio2, 10);
184 GPIO_B0_11(Gpio2, 11);
185 GPIO_B0_12(Gpio2, 12);
186 GPIO_B0_13(Gpio2, 13);
187 GPIO_B0_14(Gpio2, 14);
188 GPIO_B0_15(Gpio2, 15);
189 GPIO_B1_00(Gpio2, 16);
190 GPIO_B1_01(Gpio2, 17);
191 GPIO_B1_02(Gpio2, 18);
192 GPIO_B1_03(Gpio2, 19);
193 GPIO_B1_04(Gpio2, 20);
194 GPIO_B1_05(Gpio2, 21);
195 GPIO_B1_06(Gpio2, 22);
196 GPIO_B1_07(Gpio2, 23);
197 GPIO_B1_08(Gpio2, 24);
198 GPIO_B1_09(Gpio2, 25);
199 GPIO_B1_10(Gpio2, 26);
200 GPIO_B1_11(Gpio2, 27);
201 GPIO_B1_12(Gpio2, 28);
202 GPIO_B1_13(Gpio2, 29);
203 GPIO_B1_14(Gpio2, 30);
204 GPIO_B1_15(Gpio2, 31);
205
206 // GPIO Bank 4 (EMC is 4, then 3)
207 GPIO_EMC_00(Gpio4, 0);
208 GPIO_EMC_01(Gpio4, 1);
209 GPIO_EMC_02(Gpio4, 2);
210 GPIO_EMC_03(Gpio4, 3);
211 GPIO_EMC_04(Gpio4, 4);
212 GPIO_EMC_05(Gpio4, 5);
213 GPIO_EMC_06(Gpio4, 6);
214 GPIO_EMC_07(Gpio4, 7);
215 GPIO_EMC_08(Gpio4, 8);
216 GPIO_EMC_09(Gpio4, 9);
217 GPIO_EMC_10(Gpio4, 10);
218 GPIO_EMC_11(Gpio4, 11);
219 GPIO_EMC_12(Gpio4, 12);
220 GPIO_EMC_13(Gpio4, 13);
221 GPIO_EMC_14(Gpio4, 14);
222 GPIO_EMC_15(Gpio4, 15);
223 GPIO_EMC_16(Gpio4, 16);
224 GPIO_EMC_17(Gpio4, 17);
225 GPIO_EMC_18(Gpio4, 18);
226 GPIO_EMC_19(Gpio4, 19);
227 GPIO_EMC_20(Gpio4, 20);
228 GPIO_EMC_21(Gpio4, 21);
229 GPIO_EMC_22(Gpio4, 22);
230 GPIO_EMC_23(Gpio4, 23);
231 GPIO_EMC_24(Gpio4, 24);
232 GPIO_EMC_25(Gpio4, 25);
233 GPIO_EMC_26(Gpio4, 26);
234 GPIO_EMC_27(Gpio4, 27);
235 GPIO_EMC_28(Gpio4, 28);
236 GPIO_EMC_29(Gpio4, 29);
237 GPIO_EMC_30(Gpio4, 30);
238 GPIO_EMC_31(Gpio4, 31);
239
240 // GPIO Bank 3
241 GPIO_EMC_32(Gpio3, 18);
242 GPIO_EMC_33(Gpio3, 19);
243 GPIO_EMC_34(Gpio3, 20);
244 GPIO_EMC_35(Gpio3, 21);
245 GPIO_EMC_36(Gpio3, 22);
246 GPIO_EMC_37(Gpio3, 23);
247 GPIO_EMC_38(Gpio3, 24);
248 GPIO_EMC_39(Gpio3, 25);
249 GPIO_EMC_40(Gpio3, 26);
250 GPIO_EMC_41(Gpio3, 27);
251 GPIO_SD_B0_00(Gpio3, 12);
252 GPIO_SD_B0_01(Gpio3, 13);
253 GPIO_SD_B0_02(Gpio3, 14);
254 GPIO_SD_B0_03(Gpio3, 15);
255 GPIO_SD_B0_04(Gpio3, 16);
256 GPIO_SD_B0_05(Gpio3, 17);
257 GPIO_SD_B1_00(Gpio3, 0);
258 GPIO_SD_B1_01(Gpio3, 1);
259 GPIO_SD_B1_02(Gpio3, 2);
260 GPIO_SD_B1_03(Gpio3, 3);
261 GPIO_SD_B1_04(Gpio3, 4);
262 GPIO_SD_B1_05(Gpio3, 5);
263 GPIO_SD_B1_06(Gpio3, 6);
264 GPIO_SD_B1_07(Gpio3, 7);
265 GPIO_SD_B1_08(Gpio3, 8);
266 GPIO_SD_B1_09(Gpio3, 9);
267 GPIO_SD_B1_10(Gpio3, 10);
268 GPIO_SD_B1_11(Gpio3, 11);
269
270 WAKEUP(Gpio5, 0);
271 PMIC_ON_REQ(Gpio5, 1);
272 PMIC_STBY_REQ(Gpio5, 2);
273}
274
275pub(crate) mod _generated {
276 #![allow(dead_code)]
277 #![allow(unused_imports)]
278 #![allow(non_snake_case)]
279 #![allow(missing_docs)]
280
281 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
282}
diff --git a/embassy-nxp/src/fmt.rs b/embassy-nxp/src/fmt.rs
new file mode 100644
index 000000000..27d41ace6
--- /dev/null
+++ b/embassy-nxp/src/fmt.rs
@@ -0,0 +1,284 @@
1//! Copied from embassy-rp
2
3#![macro_use]
4#![allow(unused)]
5
6use core::fmt::{Debug, Display, LowerHex};
7
8#[cfg(all(feature = "defmt", feature = "log"))]
9compile_error!("You may not enable both `defmt` and `log` features.");
10
11#[collapse_debuginfo(yes)]
12macro_rules! assert {
13 ($($x:tt)*) => {
14 {
15 #[cfg(not(feature = "defmt"))]
16 ::core::assert!($($x)*);
17 #[cfg(feature = "defmt")]
18 ::defmt::assert!($($x)*);
19 }
20 };
21}
22
23#[collapse_debuginfo(yes)]
24macro_rules! assert_eq {
25 ($($x:tt)*) => {
26 {
27 #[cfg(not(feature = "defmt"))]
28 ::core::assert_eq!($($x)*);
29 #[cfg(feature = "defmt")]
30 ::defmt::assert_eq!($($x)*);
31 }
32 };
33}
34
35#[collapse_debuginfo(yes)]
36macro_rules! assert_ne {
37 ($($x:tt)*) => {
38 {
39 #[cfg(not(feature = "defmt"))]
40 ::core::assert_ne!($($x)*);
41 #[cfg(feature = "defmt")]
42 ::defmt::assert_ne!($($x)*);
43 }
44 };
45}
46
47#[collapse_debuginfo(yes)]
48macro_rules! debug_assert {
49 ($($x:tt)*) => {
50 {
51 #[cfg(not(feature = "defmt"))]
52 ::core::debug_assert!($($x)*);
53 #[cfg(feature = "defmt")]
54 ::defmt::debug_assert!($($x)*);
55 }
56 };
57}
58
59#[collapse_debuginfo(yes)]
60macro_rules! debug_assert_eq {
61 ($($x:tt)*) => {
62 {
63 #[cfg(not(feature = "defmt"))]
64 ::core::debug_assert_eq!($($x)*);
65 #[cfg(feature = "defmt")]
66 ::defmt::debug_assert_eq!($($x)*);
67 }
68 };
69}
70
71#[collapse_debuginfo(yes)]
72macro_rules! debug_assert_ne {
73 ($($x:tt)*) => {
74 {
75 #[cfg(not(feature = "defmt"))]
76 ::core::debug_assert_ne!($($x)*);
77 #[cfg(feature = "defmt")]
78 ::defmt::debug_assert_ne!($($x)*);
79 }
80 };
81}
82
83#[collapse_debuginfo(yes)]
84macro_rules! todo {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::todo!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::todo!($($x)*);
91 }
92 };
93}
94
95#[collapse_debuginfo(yes)]
96macro_rules! unreachable {
97 ($($x:tt)*) => {
98 {
99 #[cfg(not(feature = "defmt"))]
100 ::core::unreachable!($($x)*);
101 #[cfg(feature = "defmt")]
102 ::defmt::unreachable!($($x)*);
103 }
104 };
105}
106
107#[collapse_debuginfo(yes)]
108macro_rules! unimplemented {
109 ($($x:tt)*) => {
110 {
111 #[cfg(not(feature = "defmt"))]
112 ::core::unimplemented!($($x)*);
113 #[cfg(feature = "defmt")]
114 ::defmt::unimplemented!($($x)*);
115 }
116 };
117}
118
119#[collapse_debuginfo(yes)]
120macro_rules! panic {
121 ($($x:tt)*) => {
122 {
123 #[cfg(not(feature = "defmt"))]
124 ::core::panic!($($x)*);
125 #[cfg(feature = "defmt")]
126 ::defmt::panic!($($x)*);
127 }
128 };
129}
130
131#[collapse_debuginfo(yes)]
132macro_rules! trace {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::trace!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::trace!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145#[collapse_debuginfo(yes)]
146macro_rules! debug {
147 ($s:literal $(, $x:expr)* $(,)?) => {
148 {
149 #[cfg(feature = "log")]
150 ::log::debug!($s $(, $x)*);
151 #[cfg(feature = "defmt")]
152 ::defmt::debug!($s $(, $x)*);
153 #[cfg(not(any(feature = "log", feature="defmt")))]
154 let _ = ($( & $x ),*);
155 }
156 };
157}
158
159#[collapse_debuginfo(yes)]
160macro_rules! info {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::info!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::info!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ = ($( & $x ),*);
169 }
170 };
171}
172
173#[collapse_debuginfo(yes)]
174macro_rules! warn {
175 ($s:literal $(, $x:expr)* $(,)?) => {
176 {
177 #[cfg(feature = "log")]
178 ::log::warn!($s $(, $x)*);
179 #[cfg(feature = "defmt")]
180 ::defmt::warn!($s $(, $x)*);
181 #[cfg(not(any(feature = "log", feature="defmt")))]
182 let _ = ($( & $x ),*);
183 }
184 };
185}
186
187#[collapse_debuginfo(yes)]
188macro_rules! error {
189 ($s:literal $(, $x:expr)* $(,)?) => {
190 {
191 #[cfg(feature = "log")]
192 ::log::error!($s $(, $x)*);
193 #[cfg(feature = "defmt")]
194 ::defmt::error!($s $(, $x)*);
195 #[cfg(not(any(feature = "log", feature="defmt")))]
196 let _ = ($( & $x ),*);
197 }
198 };
199}
200
201#[cfg(feature = "defmt")]
202#[collapse_debuginfo(yes)]
203macro_rules! unwrap {
204 ($($x:tt)*) => {
205 ::defmt::unwrap!($($x)*)
206 };
207}
208
209#[cfg(not(feature = "defmt"))]
210#[collapse_debuginfo(yes)]
211macro_rules! unwrap {
212 ($arg:expr) => {
213 match $crate::fmt::Try::into_result($arg) {
214 ::core::result::Result::Ok(t) => t,
215 ::core::result::Result::Err(e) => {
216 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
217 }
218 }
219 };
220 ($arg:expr, $($msg:expr),+ $(,)? ) => {
221 match $crate::fmt::Try::into_result($arg) {
222 ::core::result::Result::Ok(t) => t,
223 ::core::result::Result::Err(e) => {
224 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
225 }
226 }
227 }
228}
229
230#[derive(Debug, Copy, Clone, Eq, PartialEq)]
231pub struct NoneError;
232
233pub trait Try {
234 type Ok;
235 type Error;
236 fn into_result(self) -> Result<Self::Ok, Self::Error>;
237}
238
239impl<T> Try for Option<T> {
240 type Ok = T;
241 type Error = NoneError;
242
243 #[inline]
244 fn into_result(self) -> Result<T, NoneError> {
245 self.ok_or(NoneError)
246 }
247}
248
249impl<T, E> Try for Result<T, E> {
250 type Ok = T;
251 type Error = E;
252
253 #[inline]
254 fn into_result(self) -> Self {
255 self
256 }
257}
258
259pub(crate) struct Bytes<'a>(pub &'a [u8]);
260
261impl<'a> Debug for Bytes<'a> {
262 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
263 write!(f, "{:#02x?}", self.0)
264 }
265}
266
267impl<'a> Display for Bytes<'a> {
268 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
269 write!(f, "{:#02x?}", self.0)
270 }
271}
272
273impl<'a> LowerHex for Bytes<'a> {
274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275 write!(f, "{:#02x?}", self.0)
276 }
277}
278
279#[cfg(feature = "defmt")]
280impl<'a> defmt::Format for Bytes<'a> {
281 fn format(&self, fmt: defmt::Formatter) {
282 defmt::write!(fmt, "{:02x}", self.0)
283 }
284}
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
index 809903d97..3049cc12d 100644
--- a/embassy-nxp/src/gpio.rs
+++ b/embassy-nxp/src/gpio.rs
@@ -1,5 +1,7 @@
1//! General purpose input/output (GPIO) driver. 1//! General purpose input/output (GPIO) driver.
2#![macro_use]
2 3
3#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")] 4#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")]
5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
4mod inner; 6mod inner;
5pub use inner::*; 7pub use inner::*;
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs
index 94cd8b7f8..8f407bb3a 100644
--- a/embassy-nxp/src/gpio/lpc55.rs
+++ b/embassy-nxp/src/gpio/lpc55.rs
@@ -7,6 +7,7 @@ pub(crate) fn init() {
7 syscon_reg() 7 syscon_reg()
8 .ahbclkctrl0 8 .ahbclkctrl0
9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable()); 9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
10 info!("GPIO initialized");
10} 11}
11 12
12/// The GPIO pin level for pins set on "Digital" mode. 13/// The GPIO pin level for pins set on "Digital" mode.
diff --git a/embassy-nxp/src/gpio/rt1xxx.rs b/embassy-nxp/src/gpio/rt1xxx.rs
new file mode 100644
index 000000000..1d60a0d51
--- /dev/null
+++ b/embassy-nxp/src/gpio/rt1xxx.rs
@@ -0,0 +1,945 @@
1#![macro_use]
2
3use core::future::Future;
4use core::ops::Not;
5use core::pin::Pin as FuturePin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10use nxp_pac::gpio::vals::Icr;
11use nxp_pac::iomuxc::vals::Pus;
12
13use crate::chip::{mux_address, pad_address};
14use crate::pac::common::{Reg, RW};
15use crate::pac::gpio::Gpio;
16#[cfg(feature = "rt")]
17use crate::pac::interrupt;
18use crate::pac::iomuxc::regs::{Ctl, MuxCtl};
19use crate::pac::{self};
20
21/// The GPIO pin level for pins set on "Digital" mode.
22#[derive(Debug, Eq, PartialEq, Clone, Copy)]
23pub enum Level {
24 /// Logical low. Corresponds to 0V.
25 Low,
26 /// Logical high. Corresponds to VDD.
27 High,
28}
29
30impl From<bool> for Level {
31 fn from(val: bool) -> Self {
32 match val {
33 true => Self::High,
34 false => Self::Low,
35 }
36 }
37}
38
39impl From<Level> for bool {
40 fn from(level: Level) -> bool {
41 match level {
42 Level::Low => false,
43 Level::High => true,
44 }
45 }
46}
47
48impl Not for Level {
49 type Output = Self;
50
51 fn not(self) -> Self::Output {
52 match self {
53 Level::Low => Level::High,
54 Level::High => Level::Low,
55 }
56 }
57}
58
59/// Pull setting for a GPIO input set on "Digital" mode.
60#[derive(Debug, Clone, Copy, Eq, PartialEq)]
61pub enum Pull {
62 /// No pull.
63 None,
64
65 // TODO: What Does PUE::KEEPER mean here?
66
67 // 22 kOhm pull-up resistor.
68 Up22K,
69
70 // 47 kOhm pull-up resistor.
71 Up47K,
72
73 // 100 kOhm pull-up resistor.
74 Up100K,
75
76 // 100 kOhm pull-down resistor.
77 Down100K,
78}
79
80/// Drive strength of an output
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Drive {
84 Disabled,
85 _150R,
86 _75R,
87 _50R,
88 _37R,
89 _30R,
90 _25R,
91 _20R,
92}
93
94/// Slew rate of an output
95#[derive(Copy, Clone, Debug, Eq, PartialEq)]
96#[cfg_attr(feature = "defmt", derive(defmt::Format))]
97pub enum SlewRate {
98 Slow,
99
100 Fast,
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum Bank {
105 /// Bank 1
106 #[cfg(gpio1)]
107 Gpio1,
108
109 /// Bank 2
110 #[cfg(gpio2)]
111 Gpio2,
112
113 /// Bank 3
114 #[cfg(gpio3)]
115 Gpio3,
116
117 /// Bank 4
118 #[cfg(gpio4)]
119 Gpio4,
120
121 /// Bank 5
122 #[cfg(gpio5)]
123 Gpio5,
124}
125
126/// GPIO flexible pin.
127///
128/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
129/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
130/// mode.
131pub struct Flex<'d> {
132 pub(crate) pin: Peri<'d, AnyPin>,
133}
134
135impl<'d> Flex<'d> {
136 /// Wrap the pin in a `Flex`.
137 ///
138 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
139 /// before the pin is put into output mode.
140 #[inline]
141 pub fn new(pin: Peri<'d, impl Pin>) -> Self {
142 Self { pin: pin.into() }
143 }
144
145 /// Set the pin's pull.
146 #[inline]
147 pub fn set_pull(&mut self, pull: Pull) {
148 let (pke, pue, pus) = match pull {
149 Pull::None => (false, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
150 Pull::Up22K => (true, true, Pus::PUS_3_22K_OHM_PULL_UP),
151 Pull::Up47K => (true, true, Pus::PUS_1_47K_OHM_PULL_UP),
152 Pull::Up100K => (true, true, Pus::PUS_2_100K_OHM_PULL_UP),
153 Pull::Down100K => (true, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
154 };
155
156 self.pin.pad().modify(|w| {
157 w.set_pke(pke);
158 w.set_pue(pue);
159 w.set_pus(pus);
160 });
161 }
162
163 // Set the pin's slew rate.
164 #[inline]
165 pub fn set_slewrate(&mut self, rate: SlewRate) {
166 self.pin.pad().modify(|w| {
167 w.set_sre(match rate {
168 SlewRate::Slow => false,
169 SlewRate::Fast => true,
170 });
171 });
172 }
173
174 /// Set the pin's Schmitt trigger.
175 #[inline]
176 pub fn set_schmitt(&mut self, enable: bool) {
177 self.pin.pad().modify(|w| {
178 w.set_hys(enable);
179 });
180 }
181
182 /// Put the pin into input mode.
183 ///
184 /// The pull setting is left unchanged.
185 #[inline]
186 pub fn set_as_input(&mut self) {
187 self.pin.mux().modify(|w| {
188 w.set_mux_mode(GPIO_MUX_MODE);
189 });
190
191 // Setting direction is RMW
192 critical_section::with(|_cs| {
193 self.pin.block().gdir().modify(|w| {
194 w.set_gdir(self.pin.pin_number() as usize, false);
195 });
196 })
197 }
198
199 /// Put the pin into output mode.
200 ///
201 /// The pin level will be whatever was set before (or low by default). If you want it to begin
202 /// at a specific level, call `set_high`/`set_low` on the pin first.
203 #[inline]
204 pub fn set_as_output(&mut self) {
205 self.pin.mux().modify(|w| {
206 w.set_mux_mode(GPIO_MUX_MODE);
207 });
208
209 // Setting direction is RMW
210 critical_section::with(|_cs| {
211 self.pin.block().gdir().modify(|w| {
212 w.set_gdir(self.pin.pin_number() as usize, true);
213 });
214 })
215 }
216
217 /// Put the pin into input + open-drain output mode.
218 ///
219 /// The hardware will drive the line low if you set it to low, and will leave it floating if you set
220 /// it to high, in which case you can read the input to figure out whether another device
221 /// is driving the line low.
222 ///
223 /// The pin level will be whatever was set before (or low by default). If you want it to begin
224 /// at a specific level, call `set_high`/`set_low` on the pin first.
225 ///
226 /// The internal weak pull-up and pull-down resistors will be disabled.
227 #[inline]
228 pub fn set_as_input_output(&mut self) {
229 self.pin.pad().modify(|w| {
230 w.set_ode(true);
231 });
232 }
233
234 /// Set the pin as "disconnected", ie doing nothing and consuming the lowest
235 /// amount of power possible.
236 ///
237 /// This is currently the same as [`Self::set_as_analog()`] but is semantically different
238 /// really. Drivers should `set_as_disconnected()` pins when dropped.
239 ///
240 /// Note that this also disables the pull-up and pull-down resistors.
241 #[inline]
242 pub fn set_as_disconnected(&mut self) {
243 self.pin.pad().modify(|w| {
244 w.set_ode(false);
245 w.set_pke(false);
246 w.set_pue(false);
247 w.set_pus(Pus::PUS_0_100K_OHM_PULL_DOWN);
248 });
249 }
250
251 /// Get whether the pin input level is high.
252 #[inline]
253 pub fn is_high(&self) -> bool {
254 self.pin.block().psr().read().psr(self.pin.pin_number() as usize)
255 }
256
257 /// Get whether the pin input level is low.
258 #[inline]
259 pub fn is_low(&self) -> bool {
260 !self.is_high()
261 }
262
263 /// Returns current pin level
264 #[inline]
265 pub fn get_level(&self) -> Level {
266 self.is_high().into()
267 }
268
269 /// Set the output as high.
270 #[inline]
271 pub fn set_high(&mut self) {
272 self.pin.block().dr_set().write(|w| {
273 w.set_dr_set(self.pin.pin_number() as usize, true);
274 });
275 }
276
277 /// Set the output as low.
278 #[inline]
279 pub fn set_low(&mut self) {
280 self.pin.block().dr_clear().write(|w| {
281 w.set_dr_clear(self.pin.pin_number() as usize, true);
282 });
283 }
284
285 /// Toggle pin output
286 #[inline]
287 pub fn toggle(&mut self) {
288 self.pin.block().dr_toggle().write(|w| {
289 w.set_dr_toggle(self.pin.pin_number() as usize, true);
290 });
291 }
292
293 /// Set the output level.
294 #[inline]
295 pub fn set_level(&mut self, level: Level) {
296 match level {
297 Level::Low => self.set_low(),
298 Level::High => self.set_high(),
299 }
300 }
301
302 /// Get the current pin output level.
303 #[inline]
304 pub fn get_output_level(&self) -> Level {
305 self.is_set_high().into()
306 }
307
308 /// Is the output level high?
309 ///
310 /// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_high`].
311 #[inline]
312 pub fn is_set_high(&self) -> bool {
313 self.pin.block().dr().read().dr(self.pin.pin_number() as usize)
314 }
315
316 /// Is the output level low?
317 ///
318 /// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_low`].
319 #[inline]
320 pub fn is_set_low(&self) -> bool {
321 !self.is_set_high()
322 }
323
324 /// Wait until the pin is high. If it is already high, return immediately.
325 #[inline]
326 pub async fn wait_for_high(&mut self) {
327 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::High).await
328 }
329
330 /// Wait until the pin is low. If it is already low, return immediately.
331 #[inline]
332 pub async fn wait_for_low(&mut self) {
333 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::Low).await
334 }
335
336 /// Wait for the pin to undergo a transition from low to high.
337 #[inline]
338 pub async fn wait_for_rising_edge(&mut self) {
339 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::RisingEdge).await
340 }
341
342 /// Wait for the pin to undergo a transition from high to low.
343 #[inline]
344 pub async fn wait_for_falling_edge(&mut self) {
345 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::FallingEdge).await
346 }
347
348 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
349 #[inline]
350 pub async fn wait_for_any_edge(&mut self) {
351 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::AnyEdge).await
352 }
353}
354
355impl<'d> Drop for Flex<'d> {
356 fn drop(&mut self) {
357 self.set_as_disconnected();
358 }
359}
360
361/// GPIO input driver.
362pub struct Input<'d> {
363 pin: Flex<'d>,
364}
365
366impl<'d> Input<'d> {
367 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
368 #[inline]
369 pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
370 let mut pin = Flex::new(pin);
371 pin.set_as_input();
372 pin.set_pull(pull);
373 Self { pin }
374 }
375
376 /// Get whether the pin input level is high.
377 #[inline]
378 pub fn is_high(&self) -> bool {
379 self.pin.is_high()
380 }
381
382 /// Get whether the pin input level is low.
383 #[inline]
384 pub fn is_low(&self) -> bool {
385 self.pin.is_low()
386 }
387
388 /// Get the current pin input level.
389 #[inline]
390 pub fn get_level(&self) -> Level {
391 self.pin.get_level()
392 }
393
394 /// Wait until the pin is high. If it is already high, return immediately.
395 #[inline]
396 pub async fn wait_for_high(&mut self) {
397 self.pin.wait_for_high().await
398 }
399
400 /// Wait until the pin is low. If it is already low, return immediately.
401 #[inline]
402 pub async fn wait_for_low(&mut self) {
403 self.pin.wait_for_low().await
404 }
405
406 /// Wait for the pin to undergo a transition from low to high.
407 #[inline]
408 pub async fn wait_for_rising_edge(&mut self) {
409 self.pin.wait_for_rising_edge().await
410 }
411
412 /// Wait for the pin to undergo a transition from high to low.
413 #[inline]
414 pub async fn wait_for_falling_edge(&mut self) {
415 self.pin.wait_for_falling_edge().await
416 }
417
418 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
419 #[inline]
420 pub async fn wait_for_any_edge(&mut self) {
421 self.pin.wait_for_any_edge().await
422 }
423}
424
425/// GPIO output driver.
426///
427/// Note that pins will **return to their floating state** when `Output` is dropped.
428/// If pins should retain their state indefinitely, either keep ownership of the
429/// `Output`, or pass it to [`core::mem::forget`].
430pub struct Output<'d> {
431 pin: Flex<'d>,
432}
433
434impl<'d> Output<'d> {
435 /// Create GPIO output driver for a [Pin] with the provided [Level] configuration.
436 #[inline]
437 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
438 let mut pin = Flex::new(pin);
439 pin.set_as_output();
440 pin.set_level(initial_output);
441 Self { pin }
442 }
443
444 /// Set the output as high.
445 #[inline]
446 pub fn set_high(&mut self) {
447 self.pin.set_high();
448 }
449
450 /// Set the output as low.
451 #[inline]
452 pub fn set_low(&mut self) {
453 self.pin.set_low();
454 }
455
456 /// Set the output level.
457 #[inline]
458 pub fn set_level(&mut self, level: Level) {
459 self.pin.set_level(level)
460 }
461
462 /// Is the output pin set as high?
463 #[inline]
464 pub fn is_set_high(&self) -> bool {
465 self.pin.is_set_high()
466 }
467
468 /// Is the output pin set as low?
469 #[inline]
470 pub fn is_set_low(&self) -> bool {
471 self.pin.is_set_low()
472 }
473
474 /// What level output is set to
475 #[inline]
476 pub fn get_output_level(&self) -> Level {
477 self.pin.get_output_level()
478 }
479
480 /// Toggle pin output
481 #[inline]
482 pub fn toggle(&mut self) {
483 self.pin.toggle();
484 }
485}
486
487/// GPIO output open-drain driver.
488///
489/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
490/// If pins should retain their state indefinitely, either keep ownership of the
491/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
492pub struct OutputOpenDrain<'d> {
493 pin: Flex<'d>,
494}
495
496impl<'d> OutputOpenDrain<'d> {
497 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level].
498 #[inline]
499 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
500 let mut pin = Flex::new(pin);
501 pin.set_level(initial_output);
502 pin.set_as_input_output();
503 Self { pin }
504 }
505
506 /// Get whether the pin input level is high.
507 #[inline]
508 pub fn is_high(&self) -> bool {
509 !self.pin.is_low()
510 }
511
512 /// Get whether the pin input level is low.
513 #[inline]
514 pub fn is_low(&self) -> bool {
515 self.pin.is_low()
516 }
517
518 /// Get the current pin input level.
519 #[inline]
520 pub fn get_level(&self) -> Level {
521 self.pin.get_level()
522 }
523
524 /// Set the output as high.
525 #[inline]
526 pub fn set_high(&mut self) {
527 self.pin.set_high();
528 }
529
530 /// Set the output as low.
531 #[inline]
532 pub fn set_low(&mut self) {
533 self.pin.set_low();
534 }
535
536 /// Set the output level.
537 #[inline]
538 pub fn set_level(&mut self, level: Level) {
539 self.pin.set_level(level);
540 }
541
542 /// Get whether the output level is set to high.
543 #[inline]
544 pub fn is_set_high(&self) -> bool {
545 self.pin.is_set_high()
546 }
547
548 /// Get whether the output level is set to low.
549 #[inline]
550 pub fn is_set_low(&self) -> bool {
551 self.pin.is_set_low()
552 }
553
554 /// Get the current output level.
555 #[inline]
556 pub fn get_output_level(&self) -> Level {
557 self.pin.get_output_level()
558 }
559
560 /// Toggle pin output
561 #[inline]
562 pub fn toggle(&mut self) {
563 self.pin.toggle()
564 }
565
566 /// Wait until the pin is high. If it is already high, return immediately.
567 #[inline]
568 pub async fn wait_for_high(&mut self) {
569 self.pin.wait_for_high().await
570 }
571
572 /// Wait until the pin is low. If it is already low, return immediately.
573 #[inline]
574 pub async fn wait_for_low(&mut self) {
575 self.pin.wait_for_low().await
576 }
577
578 /// Wait for the pin to undergo a transition from low to high.
579 #[inline]
580 pub async fn wait_for_rising_edge(&mut self) {
581 self.pin.wait_for_rising_edge().await
582 }
583
584 /// Wait for the pin to undergo a transition from high to low.
585 #[inline]
586 pub async fn wait_for_falling_edge(&mut self) {
587 self.pin.wait_for_falling_edge().await
588 }
589
590 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
591 #[inline]
592 pub async fn wait_for_any_edge(&mut self) {
593 self.pin.wait_for_any_edge().await
594 }
595}
596
597#[allow(private_bounds)]
598pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
599 /// Returns the pin number within a bank
600 #[inline]
601 fn pin(&self) -> u8 {
602 self.pin_number()
603 }
604
605 #[inline]
606 fn bank(&self) -> Bank {
607 self._bank()
608 }
609}
610
611/// Type-erased GPIO pin.
612pub struct AnyPin {
613 pub(crate) pin_number: u8,
614 pub(crate) bank: Bank,
615}
616
617impl AnyPin {
618 /// Unsafely create a new type-erased pin.
619 ///
620 /// # Safety
621 ///
622 /// You must ensure that you’re only using one instance of this type at a time.
623 pub unsafe fn steal(bank: Bank, pin_number: u8) -> Peri<'static, Self> {
624 Peri::new_unchecked(Self { pin_number, bank })
625 }
626}
627
628impl_peripheral!(AnyPin);
629
630impl Pin for AnyPin {}
631impl SealedPin for AnyPin {
632 #[inline]
633 fn pin_number(&self) -> u8 {
634 self.pin_number
635 }
636
637 #[inline]
638 fn _bank(&self) -> Bank {
639 self.bank
640 }
641}
642
643// Impl details
644
645/// Mux mode for GPIO pins. This is constant across all RT1xxx parts.
646const GPIO_MUX_MODE: u8 = 0b101;
647
648// FIXME: These don't always need to be 32 entries. GPIO5 on RT1101 contains a single pin and GPIO2 only 14.
649#[cfg(gpio1)]
650static GPIO1_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
651#[cfg(gpio2)]
652static GPIO2_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
653#[cfg(gpio3)]
654static GPIO3_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
655#[cfg(gpio4)]
656static GPIO4_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
657#[cfg(gpio5)]
658static GPIO5_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
659
660/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
661pub(crate) trait SealedPin: Sized {
662 fn pin_number(&self) -> u8;
663
664 fn _bank(&self) -> Bank;
665
666 #[inline]
667 fn block(&self) -> Gpio {
668 match self._bank() {
669 #[cfg(gpio1)]
670 Bank::Gpio1 => pac::GPIO1,
671 #[cfg(gpio2)]
672 Bank::Gpio2 => pac::GPIO2,
673 #[cfg(gpio3)]
674 Bank::Gpio3 => pac::GPIO3,
675 #[cfg(gpio4)]
676 Bank::Gpio4 => pac::GPIO4,
677 #[cfg(gpio5)]
678 Bank::Gpio5 => pac::GPIO5,
679 }
680 }
681
682 #[inline]
683 fn mux(&self) -> Reg<MuxCtl, RW> {
684 // SAFETY: The generated mux address table is valid since it is generated from the SVD files.
685 let address = unsafe { mux_address(self._bank(), self.pin_number()).unwrap_unchecked() };
686
687 // SAFETY: The register at the address is an instance of MuxCtl.
688 unsafe { Reg::from_ptr(address as *mut _) }
689 }
690
691 #[inline]
692 fn pad(&self) -> Reg<Ctl, RW> {
693 // SAFETY: The generated pad address table is valid since it is generated from the SVD files.
694 let address = unsafe { pad_address(self._bank(), self.pin_number()).unwrap_unchecked() };
695
696 // SAFETY: The register at the address is an instance of Ctl.
697 unsafe { Reg::from_ptr(address as *mut _) }
698 }
699
700 fn waker(&self) -> &AtomicWaker {
701 match self._bank() {
702 #[cfg(gpio1)]
703 Bank::Gpio1 => &GPIO1_WAKERS[self.pin_number() as usize],
704 #[cfg(gpio2)]
705 Bank::Gpio2 => &GPIO2_WAKERS[self.pin_number() as usize],
706 #[cfg(gpio3)]
707 Bank::Gpio3 => &GPIO3_WAKERS[self.pin_number() as usize],
708 #[cfg(gpio4)]
709 Bank::Gpio4 => &GPIO4_WAKERS[self.pin_number() as usize],
710 #[cfg(gpio5)]
711 Bank::Gpio5 => &GPIO5_WAKERS[self.pin_number() as usize],
712 }
713 }
714}
715
716/// This enum matches the layout of Icr.
717enum InterruptConfiguration {
718 Low,
719 High,
720 RisingEdge,
721 FallingEdge,
722 AnyEdge,
723}
724
725#[must_use = "futures do nothing unless you `.await` or poll them"]
726struct InputFuture<'d> {
727 pin: Peri<'d, AnyPin>,
728}
729
730impl<'d> InputFuture<'d> {
731 fn new(pin: Peri<'d, AnyPin>, config: InterruptConfiguration) -> Self {
732 let block = pin.block();
733
734 let (icr, edge_sel) = match config {
735 InterruptConfiguration::Low => (Icr::LOW_LEVEL, false),
736 InterruptConfiguration::High => (Icr::HIGH_LEVEL, false),
737 InterruptConfiguration::RisingEdge => (Icr::RISING_EDGE, false),
738 InterruptConfiguration::FallingEdge => (Icr::FALLING_EDGE, false),
739 InterruptConfiguration::AnyEdge => (Icr::FALLING_EDGE, true),
740 };
741
742 let index = if pin.pin_number() > 15 { 1 } else { 0 };
743
744 // Interrupt configuration performs RMW
745 critical_section::with(|_cs| {
746 // Disable interrupt so a level/edge detection change does not cause ISR to be set.
747 block.imr().modify(|w| {
748 w.set_imr(pin.pin_number() as usize, false);
749 });
750
751 block.icr(index).modify(|w| {
752 w.set_pin(pin.pin_number() as usize, icr);
753 });
754
755 block.edge_sel().modify(|w| {
756 w.set_edge_sel(pin.pin_number() as usize, edge_sel);
757 });
758
759 // Clear the previous interrupt.
760 block.isr().modify(|w| {
761 // "Status flags are cleared by writing a 1 to the corresponding bit position."
762 w.set_isr(pin.pin_number() as usize, true);
763 });
764 });
765
766 Self { pin }
767 }
768}
769
770impl<'d> Future for InputFuture<'d> {
771 type Output = ();
772
773 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
774 // We need to register/re-register the waker for each poll because any
775 // calls to wake will deregister the waker.
776 let waker = self.pin.waker();
777 waker.register(cx.waker());
778
779 // Enabling interrupt is RMW
780 critical_section::with(|_cs| {
781 self.pin.block().imr().modify(|w| {
782 w.set_imr(self.pin.pin_number() as usize, true);
783 });
784 });
785
786 let isr = self.pin.block().isr().read();
787
788 if isr.isr(self.pin.pin_number() as usize) {
789 return Poll::Ready(());
790 }
791
792 Poll::Pending
793 }
794}
795
796/// A macro to generate all GPIO pins.
797///
798/// This generates a lookup table for IOMUX register addresses.
799macro_rules! impl_gpio {
800 (
801 $($name: ident($bank: ident, $pin_number: expr);)*
802 ) => {
803 #[inline]
804 pub(crate) const fn pad_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
805 match (bank, pin) {
806 $(
807 (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::pads::$name),
808 )*
809 _ => None
810 }
811 }
812
813 #[inline]
814 pub(crate) const fn mux_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
815 match (bank, pin) {
816 $(
817 (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::muxes::$name),
818 )*
819 _ => None
820 }
821 }
822
823 $(
824 impl_pin!($name, $bank, $pin_number);
825 )*
826 };
827}
828
829macro_rules! impl_pin {
830 ($name: ident, $bank: ident, $pin_num: expr) => {
831 impl crate::gpio::Pin for crate::peripherals::$name {}
832 impl crate::gpio::SealedPin for crate::peripherals::$name {
833 #[inline]
834 fn pin_number(&self) -> u8 {
835 $pin_num
836 }
837
838 #[inline]
839 fn _bank(&self) -> crate::gpio::Bank {
840 crate::gpio::Bank::$bank
841 }
842 }
843
844 impl From<peripherals::$name> for crate::gpio::AnyPin {
845 fn from(val: peripherals::$name) -> Self {
846 use crate::gpio::SealedPin;
847
848 Self {
849 pin_number: val.pin_number(),
850 bank: val._bank(),
851 }
852 }
853 }
854 };
855}
856
857pub(crate) fn init() {
858 #[cfg(feature = "rt")]
859 unsafe {
860 use embassy_hal_internal::interrupt::InterruptExt;
861
862 pac::Interrupt::GPIO1_COMBINED_0_15.enable();
863 pac::Interrupt::GPIO1_COMBINED_16_31.enable();
864 pac::Interrupt::GPIO2_COMBINED_0_15.enable();
865 pac::Interrupt::GPIO5_COMBINED_0_15.enable();
866 }
867}
868
869/// IRQ handler for GPIO pins.
870///
871/// If `high_bits` is false, then the interrupt is for pins 0 through 15. If true, then the interrupt
872/// is for pins 16 through 31
873#[cfg(feature = "rt")]
874fn irq_handler(block: Gpio, wakers: &[AtomicWaker; 32], high_bits: bool) {
875 use crate::BitIter;
876
877 let isr = block.isr().read().0;
878 let imr = block.imr().read().0;
879 let mask = if high_bits { 0xFFFF_0000 } else { 0x0000_FFFF };
880 let bits = isr & imr & mask;
881
882 for bit in BitIter(bits) {
883 wakers[bit as usize].wake();
884
885 // Disable further interrupts for this pin. The input future will check ISR (which is kept
886 // until reset).
887 block.imr().modify(|w| {
888 w.set_imr(bit as usize, false);
889 });
890 }
891}
892
893#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
894#[interrupt]
895fn GPIO1_COMBINED_0_15() {
896 irq_handler(pac::GPIO1, &GPIO1_WAKERS, false);
897}
898
899#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
900#[interrupt]
901fn GPIO1_COMBINED_16_31() {
902 irq_handler(pac::GPIO1, &GPIO1_WAKERS, true);
903}
904
905#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
906#[interrupt]
907fn GPIO2_COMBINED_0_15() {
908 irq_handler(pac::GPIO2, &GPIO2_WAKERS, false);
909}
910
911#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
912#[interrupt]
913fn GPIO2_COMBINED_16_31() {
914 irq_handler(pac::GPIO2, &GPIO2_WAKERS, true);
915}
916
917#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
918#[interrupt]
919fn GPIO3_COMBINED_0_15() {
920 irq_handler(pac::GPIO3, &GPIO3_WAKERS, false);
921}
922
923#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
924#[interrupt]
925fn GPIO3_COMBINED_16_31() {
926 irq_handler(pac::GPIO3, &GPIO3_WAKERS, true);
927}
928
929#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
930#[interrupt]
931fn GPIO4_COMBINED_0_15() {
932 irq_handler(pac::GPIO4, &GPIO4_WAKERS, false);
933}
934
935#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
936#[interrupt]
937fn GPIO4_COMBINED_16_31() {
938 irq_handler(pac::GPIO4, &GPIO4_WAKERS, true);
939}
940
941#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
942#[interrupt]
943fn GPIO5_COMBINED_0_15() {
944 irq_handler(pac::GPIO5, &GPIO5_WAKERS, false);
945}
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
index 433aca9e0..5e77fc0db 100644
--- a/embassy-nxp/src/lib.rs
+++ b/embassy-nxp/src/lib.rs
@@ -1,11 +1,20 @@
1#![no_std] 1#![no_std]
2 2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
3pub mod gpio; 6pub mod gpio;
4#[cfg(feature = "lpc55")] 7#[cfg(feature = "lpc55")]
5pub mod pint; 8pub mod pint;
6 9
10#[cfg(feature = "_time_driver")]
11#[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")]
12mod time_driver;
13
7// This mod MUST go last, so that it sees all the `impl_foo!` macros 14// This mod MUST go last, so that it sees all the `impl_foo!` macros
8#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")] 15#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")]
16#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
17#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
9mod chip; 18mod chip;
10 19
11#[cfg(feature = "unstable-pac")] 20#[cfg(feature = "unstable-pac")]
@@ -21,13 +30,66 @@ pub use embassy_hal_internal::{Peri, PeripheralType};
21/// 30///
22/// This should only be called once and at startup, otherwise it panics. 31/// This should only be called once and at startup, otherwise it panics.
23pub fn init(_config: config::Config) -> Peripherals { 32pub fn init(_config: config::Config) -> Peripherals {
24 #[cfg(feature = "lpc55")] 33 // Do this first, so that it panics if user is calling `init` a second time
34 // before doing anything important.
35 let peripherals = Peripherals::take();
36
37 #[cfg(feature = "mimxrt1011")]
25 { 38 {
26 gpio::init(); 39 // The RT1010 Reference manual states that core clock root must be switched before
27 pint::init(); 40 // reprogramming PLL2.
41 pac::CCM.cbcdr().modify(|w| {
42 w.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_1);
43 });
44
45 while matches!(
46 pac::CCM.cdhipr().read().periph_clk_sel_busy(),
47 pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
48 ) {}
49
50 info!("Core clock root switched");
51
52 // 480 * 18 / 24 = 360
53 pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd2_frac(12));
54
55 //480*18/24(pfd0)/4
56 pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd0_frac(24));
57 pac::CCM.cscmr1().modify(|x| x.set_flexspi_podf(3.into()));
58
59 // CPU Core
60 pac::CCM_ANALOG.pfd_528().modify(|x| x.set_pfd3_frac(18));
61 cortex_m::asm::delay(500_000);
62
63 // Clock core clock with PLL 2.
64 pac::CCM
65 .cbcdr()
66 .modify(|x| x.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_0)); // false
67
68 while matches!(
69 pac::CCM.cdhipr().read().periph_clk_sel_busy(),
70 pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
71 ) {}
72
73 pac::CCM
74 .cbcmr()
75 .write(|v| v.set_pre_periph_clk_sel(pac::ccm::vals::PrePeriphClkSel::PRE_PERIPH_CLK_SEL_0));
76
77 // TODO: Some for USB PLLs
78
79 // DCDC clock?
80 pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
28 } 81 }
29 82
30 crate::Peripherals::take() 83 #[cfg(any(feature = "lpc55", rt1xxx))]
84 gpio::init();
85
86 #[cfg(feature = "lpc55")]
87 pint::init();
88
89 #[cfg(feature = "_time_driver")]
90 time_driver::init();
91
92 peripherals
31} 93}
32 94
33/// HAL configuration for the NXP board. 95/// HAL configuration for the NXP board.
@@ -35,3 +97,20 @@ pub mod config {
35 #[derive(Default)] 97 #[derive(Default)]
36 pub struct Config {} 98 pub struct Config {}
37} 99}
100
101#[allow(unused)]
102struct BitIter(u32);
103
104impl Iterator for BitIter {
105 type Item = u32;
106
107 fn next(&mut self) -> Option<Self::Item> {
108 match self.0.trailing_zeros() {
109 32 => None,
110 b => {
111 self.0 &= !(1 << b);
112 Some(b)
113 }
114 }
115 }
116}
diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs
index dc117e7e3..ff414b4e6 100644
--- a/embassy-nxp/src/pint.rs
+++ b/embassy-nxp/src/pint.rs
@@ -101,6 +101,8 @@ pub(crate) fn init() {
101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6); 101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6);
102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7); 102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7);
103 }; 103 };
104
105 info!("Pin interrupts initialized");
104} 106}
105 107
106#[must_use = "futures do nothing unless you `.await` or poll them"] 108#[must_use = "futures do nothing unless you `.await` or poll them"]
diff --git a/embassy-nxp/src/time_driver/pit.rs b/embassy-nxp/src/time_driver/pit.rs
new file mode 100644
index 000000000..985e5e815
--- /dev/null
+++ b/embassy-nxp/src/time_driver/pit.rs
@@ -0,0 +1,187 @@
1//! Time driver using Periodic Interrupt Timer (PIT)
2//!
3//! This driver is used with the iMXRT1xxx parts.
4//!
5//! The PIT is run in lifetime mode. Timer 1 is chained to timer 0 to provide a free-running 64-bit timer.
6//! The 64-bit timer is used to track how many ticks since boot.
7//!
8//! Timer 2 counts how many ticks there are within the current u32::MAX tick period. Timer 2 is restarted when
9//! a new alarm is set (or every u32::MAX ticks). One caveat is that an alarm could be a few ticks late due to
10//! restart. However the Cortex-M7 cores run at 500 MHz easily and the PIT will generally run at 1 MHz or lower.
11//! Along with the fact that scheduling an alarm takes a critical section worst case an alarm may be a few
12//! microseconds late.
13//!
14//! All PIT timers are clocked in lockstep, so the late start will not cause the now() count to drift.
15
16use core::cell::{Cell, RefCell};
17use core::task::Waker;
18
19use critical_section::{CriticalSection, Mutex};
20use embassy_hal_internal::interrupt::InterruptExt;
21use embassy_time_driver::Driver as _;
22use embassy_time_queue_utils::Queue;
23
24use crate::pac::{self, interrupt};
25
26struct Driver {
27 alarm: Mutex<Cell<u64>>,
28 queue: Mutex<RefCell<Queue>>,
29}
30
31impl embassy_time_driver::Driver for Driver {
32 fn now(&self) -> u64 {
33 loop {
34 // Even though reading LTMR64H will latch LTMR64L if another thread preempts between any of the
35 // three reads and calls now() then the value in LTMR64L will be wrong when execution returns to
36 // thread which was preempted.
37 let hi = pac::PIT.ltmr64h().read().lth();
38 let lo = pac::PIT.ltmr64l().read().ltl();
39 let hi2 = pac::PIT.ltmr64h().read().lth();
40
41 if hi == hi2 {
42 // PIT timers always count down.
43 return u64::MAX - ((hi as u64) << 32 | (lo as u64));
44 }
45 }
46 }
47
48 fn schedule_wake(&self, at: u64, waker: &Waker) {
49 critical_section::with(|cs| {
50 let mut queue = self.queue.borrow(cs).borrow_mut();
51
52 if queue.schedule_wake(at, waker) {
53 let mut next = queue.next_expiration(self.now());
54
55 while !self.set_alarm(cs, next) {
56 next = queue.next_expiration(self.now());
57 }
58 }
59 })
60 }
61}
62
63impl Driver {
64 fn init(&'static self) {
65 // Disable PIT clock during mux configuration.
66 pac::CCM.ccgr1().modify(|r| r.set_cg6(0b00));
67
68 // TODO: This forces the PIT to be driven by the oscillator. However that isn't the only option as you
69 // could divide the clock root by up to 64.
70 pac::CCM.cscmr1().modify(|r| {
71 // 1 MHz
72 r.set_perclk_podf(pac::ccm::vals::PerclkPodf::DIVIDE_24);
73 r.set_perclk_clk_sel(pac::ccm::vals::PerclkClkSel::PERCLK_CLK_SEL_1);
74 });
75
76 pac::CCM.ccgr1().modify(|r| r.set_cg6(0b11));
77
78 // Disable clock during init.
79 //
80 // It is important that the PIT clock is prepared to not exceed limit (50 MHz on RT1011), or else
81 // you will need to recover the device with boot mode switches when using any PIT registers.
82 pac::PIT.mcr().modify(|w| {
83 w.set_mdis(true);
84 });
85
86 pac::PIT.timer(0).ldval().write_value(u32::MAX);
87 pac::PIT.timer(1).ldval().write_value(u32::MAX);
88 pac::PIT.timer(2).ldval().write_value(0);
89 pac::PIT.timer(3).ldval().write_value(0);
90
91 pac::PIT.timer(1).tctrl().write(|w| {
92 // In lifetime mode, timer 1 is chained to timer 0 to form a 64-bit timer.
93 w.set_chn(true);
94 w.set_ten(true);
95 w.set_tie(false);
96 });
97
98 pac::PIT.timer(0).tctrl().write(|w| {
99 w.set_chn(false);
100 w.set_ten(true);
101 w.set_tie(false);
102 });
103
104 pac::PIT.timer(2).tctrl().write(|w| {
105 w.set_tie(true);
106 });
107
108 unsafe { interrupt::PIT.enable() };
109
110 pac::PIT.mcr().write(|w| {
111 w.set_mdis(false);
112 });
113 }
114
115 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
116 let alarm = self.alarm.borrow(cs);
117 alarm.set(timestamp);
118
119 let timer = pac::PIT.timer(2);
120 let now = self.now();
121
122 if timestamp <= now {
123 alarm.set(u64::MAX);
124
125 return false;
126 }
127
128 timer.tctrl().modify(|x| x.set_ten(false));
129 timer.tflg().modify(|x| x.set_tif(true));
130
131 // If the next alarm happens in more than u32::MAX cycles then the alarm will be restarted later.
132 timer.ldval().write_value((timestamp - now) as u32);
133 timer.tctrl().modify(|x| x.set_ten(true));
134
135 true
136 }
137
138 fn trigger_alarm(&self, cs: CriticalSection) {
139 let mut next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
140
141 while !self.set_alarm(cs, next) {
142 next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
143 }
144 }
145
146 fn on_interrupt(&self) {
147 critical_section::with(|cs| {
148 let timer = pac::PIT.timer(2);
149 let alarm = self.alarm.borrow(cs);
150 let interrupted = timer.tflg().read().tif();
151 timer.tflg().write(|r| r.set_tif(true));
152
153 if interrupted {
154 // A new load value will not apply until the next timer expiration.
155 //
156 // The expiry may be up to u32::MAX cycles away, so the timer must be restarted.
157 timer.tctrl().modify(|r| r.set_ten(false));
158
159 let now = self.now();
160 let timestamp = alarm.get();
161
162 if timestamp <= now {
163 self.trigger_alarm(cs);
164 } else {
165 // The alarm is not ready. Wait for u32::MAX cycles and check again or set the next alarm.
166 timer.ldval().write_value((timestamp - now) as u32);
167 timer.tctrl().modify(|r| r.set_ten(true));
168 }
169 }
170 });
171 }
172}
173
174embassy_time_driver::time_driver_impl!(static DRIVER: Driver = Driver {
175 alarm: Mutex::new(Cell::new(0)),
176 queue: Mutex::new(RefCell::new(Queue::new()))
177});
178
179pub(crate) fn init() {
180 DRIVER.init();
181}
182
183#[cfg(feature = "rt")]
184#[interrupt]
185fn PIT() {
186 DRIVER.on_interrupt();
187}