aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-04-09 18:56:30 +0000
committerGitHub <[email protected]>2025-04-09 18:56:30 +0000
commit6919732666bdcb4b2a4d26be348c87e4ca70280b (patch)
tree865ae0aa84bcb4c438463d34dd567ea07abe98e3 /embassy-imxrt
parent0ec3e78c1bb0cdb20749cca4b294cb8a16e7fd43 (diff)
parentaa9a16e569dfb56ce2b689733975f4d854af0b00 (diff)
Merge pull request #4042 from felipebalbi/imxrt
Add embassy-imxrt
Diffstat (limited to 'embassy-imxrt')
-rw-r--r--embassy-imxrt/Cargo.toml84
-rw-r--r--embassy-imxrt/README.md59
-rw-r--r--embassy-imxrt/src/chips/mimxrt633s.rs389
-rw-r--r--embassy-imxrt/src/chips/mimxrt685s.rs388
-rw-r--r--embassy-imxrt/src/clocks.rs1687
-rw-r--r--embassy-imxrt/src/fmt.rs257
-rw-r--r--embassy-imxrt/src/gpio.rs1060
-rw-r--r--embassy-imxrt/src/iopctl.rs717
-rw-r--r--embassy-imxrt/src/lib.rs130
9 files changed, 4771 insertions, 0 deletions
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
new file mode 100644
index 000000000..38087bf77
--- /dev/null
+++ b/embassy-imxrt/Cargo.toml
@@ -0,0 +1,84 @@
1[package]
2name = "embassy-imxrt"
3version = "0.1.0"
4edition = "2021"
5license = "MIT"
6description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller"
7keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"]
8categories = ["embedded", "hardware-support", "no-std", "asynchronous"]
9repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/embassy-imxrt"
11
12[package.metadata.embassy_docs]
13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
15features = ["defmt", "unstable-pac"]
16flavors = [
17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
18]
19
20[package.metadata.docs.rs]
21features = ["mimxrt685s", "defmt", "unstable-pac"]
22rustdoc-args = ["--cfg", "docsrs"]
23
24[features]
25default = ["rt"]
26
27## Cortex-M runtime (enabled by default)
28rt = [
29 "mimxrt685s-pac?/rt",
30 "mimxrt633s-pac?/rt",
31]
32
33## Enable defmt
34defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"]
35
36## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
37unstable-pac = []
38
39# Features starting with `_` are for internal use only. They're not intended
40# to be enabled by other crates, and are not covered by semver guarantees.
41
42_mimxrt685s = []
43_mimxrt633s = ["_espi"]
44
45# Peripherals
46_espi = []
47
48#! ### Chip selection features
49## MIMXRT685S
50mimxrt685s = ["mimxrt685s-pac", "_mimxrt685s"]
51## MIMXRT633S
52mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"]
53
54[dependencies]
55embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
56embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
57embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false }
58embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
59
60defmt = { version = "1.0", optional = true }
61log = { version = "0.4.14", optional = true }
62nb = "1.0.0"
63cfg-if = "1.0.0"
64cortex-m-rt = ">=0.7.3,<0.8"
65cortex-m = "0.7.6"
66critical-section = "1.1"
67embedded-io = { version = "0.6.1" }
68embedded-io-async = { version = "0.6.1" }
69rand_core = "0.6.4"
70fixed = "1.23.1"
71
72embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
73 "unproven",
74] }
75embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
76embedded-hal-async = { version = "1.0" }
77embedded-hal-nb = { version = "1.0" }
78
79document-features = "0.2.7"
80paste = "1.0"
81
82# PACs
83mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] }
84mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] }
diff --git a/embassy-imxrt/README.md b/embassy-imxrt/README.md
new file mode 100644
index 000000000..cfdfb8ce2
--- /dev/null
+++ b/embassy-imxrt/README.md
@@ -0,0 +1,59 @@
1# Embassy iMXRT HAL
2
3## Introduction
4
5HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so
6raw register manipulation is not needed.
7
8The Embassy iMXRT HAL targets the NXP iMXRT Family of MCUs. The HAL implements
9both blocking and async APIs for many peripherals. The benefit of using the
10async APIs is that the HAL takes care of waiting for peripherals to complete
11operations in low power mode and handling of interrupts, so that applications
12can focus on business logic.
13
14NOTE: The Embassy HALs can be used both for non-async and async operations. For
15async, you can choose which runtime you want to use.
16
17For a complete list of available peripherals and features, see the
18[embassy-imxrt documentation](https://docs.embassy.dev/embassy-imxrt).
19
20## Hardware support
21
22The `embassy-imxrt` HAL currently supports two main variants of the iMXRT
23family:
24
25* MIMXRT685S
26 ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt685s-evk))
27* MIMXRT633s
28 ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt633))
29
30Several peripherals are supported and tested on both supported chip variants. To
31check what's available, make sure to the MCU you're targetting in the top menu
32in the [documentation](https://docs.embassy.dev/embassy-imxrt).
33
34## TrustZone support
35
36TrustZone support is yet to be implemented.
37
38## Time driver
39
40If the `time-driver` feature is enabled, the HAL uses the RTC peripheral as a
41global time driver for [embassy-time](https://crates.io/crates/embassy-time),
42with a tick rate of 32768 Hz.
43
44## Embedded-hal
45
46The `embassy-imxrt` HAL implements the traits from
47[embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and
48[embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as
49[embedded-io](https://crates.io/crates/embedded-io) and
50[embedded-io-async](https://crates.io/crates/embedded-io-async).
51
52## Interoperability
53
54This crate can run on any executor.
55
56Optionally, some features requiring
57[`embassy-time`](https://crates.io/crates/embassy-time) can be activated with
58the `time` feature. If you enable it, you must link an `embassy-time` driver in
59your project.
diff --git a/embassy-imxrt/src/chips/mimxrt633s.rs b/embassy-imxrt/src/chips/mimxrt633s.rs
new file mode 100644
index 000000000..30072132a
--- /dev/null
+++ b/embassy-imxrt/src/chips/mimxrt633s.rs
@@ -0,0 +1,389 @@
1pub use mimxrt633s_pac as pac;
2
3#[allow(clippy::missing_safety_doc)]
4pub mod interrupts {
5 embassy_hal_internal::interrupt_mod!(
6 ACMP,
7 ADC0,
8 CASPER,
9 CTIMER0,
10 CTIMER1,
11 CTIMER2,
12 CTIMER3,
13 CTIMER4,
14 DMA0,
15 DMA1,
16 DMIC0,
17 ESPI,
18 FLEXCOMM0,
19 FLEXCOMM1,
20 FLEXCOMM14,
21 FLEXCOMM15,
22 FLEXCOMM2,
23 FLEXCOMM3,
24 FLEXCOMM4,
25 FLEXCOMM5,
26 FLEXCOMM6,
27 FLEXCOMM7,
28 FLEXSPI,
29 GPIO_INTA,
30 GPIO_INTB,
31 HASHCRYPT,
32 HWVAD0,
33 HYPERVISOR,
34 I3C0,
35 MRT0,
36 MU_A,
37 OS_EVENT,
38 PIN_INT0,
39 PIN_INT1,
40 PIN_INT2,
41 PIN_INT3,
42 PIN_INT4,
43 PIN_INT5,
44 PIN_INT6,
45 PIN_INT7,
46 PMC_PMIC,
47 POWERQUAD,
48 PUF,
49 RNG,
50 RTC,
51 SCT0,
52 SECUREVIOLATION,
53 SGPIO_INTA,
54 SGPIO_INTB,
55 USB,
56 USBPHY_DCD,
57 USB_WAKEUP,
58 USDHC0,
59 USDHC1,
60 UTICK0,
61 WDT0,
62 WDT1,
63 );
64}
65
66embassy_hal_internal::peripherals!(
67 ACMP,
68 ADC0,
69 CASPER,
70 CRC,
71 CTIMER0_COUNT_CHANNEL0,
72 CTIMER0_COUNT_CHANNEL1,
73 CTIMER0_COUNT_CHANNEL2,
74 CTIMER0_COUNT_CHANNEL3,
75 CTIMER0_CAPTURE_CHANNEL0,
76 CTIMER0_CAPTURE_CHANNEL1,
77 CTIMER0_CAPTURE_CHANNEL2,
78 CTIMER0_CAPTURE_CHANNEL3,
79 CTIMER1_COUNT_CHANNEL0,
80 CTIMER1_COUNT_CHANNEL1,
81 CTIMER1_COUNT_CHANNEL2,
82 CTIMER1_COUNT_CHANNEL3,
83 CTIMER1_CAPTURE_CHANNEL0,
84 CTIMER1_CAPTURE_CHANNEL1,
85 CTIMER1_CAPTURE_CHANNEL2,
86 CTIMER1_CAPTURE_CHANNEL3,
87 CTIMER2_COUNT_CHANNEL0,
88 CTIMER2_COUNT_CHANNEL1,
89 CTIMER2_COUNT_CHANNEL2,
90 CTIMER2_COUNT_CHANNEL3,
91 CTIMER2_CAPTURE_CHANNEL0,
92 CTIMER2_CAPTURE_CHANNEL1,
93 CTIMER2_CAPTURE_CHANNEL2,
94 CTIMER2_CAPTURE_CHANNEL3,
95 CTIMER3_COUNT_CHANNEL0,
96 CTIMER3_COUNT_CHANNEL1,
97 CTIMER3_COUNT_CHANNEL2,
98 CTIMER3_COUNT_CHANNEL3,
99 CTIMER3_CAPTURE_CHANNEL0,
100 CTIMER3_CAPTURE_CHANNEL1,
101 CTIMER3_CAPTURE_CHANNEL2,
102 CTIMER3_CAPTURE_CHANNEL3,
103 CTIMER4_COUNT_CHANNEL0,
104 CTIMER4_COUNT_CHANNEL1,
105 CTIMER4_COUNT_CHANNEL2,
106 CTIMER4_COUNT_CHANNEL3,
107 CTIMER4_CAPTURE_CHANNEL0,
108 CTIMER4_CAPTURE_CHANNEL1,
109 CTIMER4_CAPTURE_CHANNEL2,
110 CTIMER4_CAPTURE_CHANNEL3,
111 DMA0,
112 DMA0_CH0,
113 DMA0_CH1,
114 DMA0_CH2,
115 DMA0_CH3,
116 DMA0_CH4,
117 DMA0_CH5,
118 DMA0_CH6,
119 DMA0_CH7,
120 DMA0_CH8,
121 DMA0_CH9,
122 DMA0_CH10,
123 DMA0_CH11,
124 DMA0_CH12,
125 DMA0_CH13,
126 DMA0_CH14,
127 DMA0_CH15,
128 DMA0_CH16,
129 DMA0_CH17,
130 DMA0_CH18,
131 DMA0_CH19,
132 DMA0_CH20,
133 DMA0_CH21,
134 DMA0_CH22,
135 DMA0_CH23,
136 DMA0_CH24,
137 DMA0_CH25,
138 DMA0_CH26,
139 DMA0_CH27,
140 DMA0_CH28,
141 DMA0_CH29,
142 DMA0_CH30,
143 DMA0_CH31,
144 DMA0_CH32,
145 DMA1,
146 DMA1_CH0,
147 DMA1_CH1,
148 DMA1_CH2,
149 DMA1_CH3,
150 DMA1_CH4,
151 DMA1_CH5,
152 DMA1_CH6,
153 DMA1_CH7,
154 DMA1_CH8,
155 DMA1_CH9,
156 DMA1_CH10,
157 DMA1_CH11,
158 DMA1_CH12,
159 DMA1_CH13,
160 DMA1_CH14,
161 DMA1_CH15,
162 DMA1_CH16,
163 DMA1_CH17,
164 DMA1_CH18,
165 DMA1_CH19,
166 DMA1_CH20,
167 DMA1_CH21,
168 DMA1_CH22,
169 DMA1_CH23,
170 DMA1_CH24,
171 DMA1_CH25,
172 DMA1_CH26,
173 DMA1_CH27,
174 DMA1_CH28,
175 DMA1_CH29,
176 DMA1_CH30,
177 DMA1_CH31,
178 DMA1_CH32,
179 DMIC0,
180 DSPWAKE,
181 ESPI,
182 FLEXCOMM0,
183 FLEXCOMM1,
184 FLEXCOMM14,
185 FLEXCOMM15,
186 FLEXCOMM2,
187 FLEXCOMM3,
188 FLEXCOMM4,
189 FLEXCOMM5,
190 FLEXCOMM6,
191 FLEXCOMM7,
192 FLEXSPI,
193 FREQME,
194 GPIO_INTA,
195 GPIO_INTB,
196 HASHCRYPT,
197 HSGPIO0,
198 HSGPIO1,
199 HSGPIO2,
200 HSGPIO3,
201 HSGPIO4,
202 HSGPIO5,
203 HSGPIO6,
204 HSGPIO7,
205 HWVAD0,
206 HYPERVISOR,
207 I3C0,
208 MRT0,
209 MU_A,
210 OS_EVENT,
211 PIN_INT0,
212 PIN_INT1,
213 PIN_INT2,
214 PIN_INT3,
215 PIN_INT4,
216 PIN_INT5,
217 PIN_INT6,
218 PIN_INT7,
219 PIO0_0,
220 PIO0_1,
221 PIO0_10,
222 PIO0_11,
223 PIO0_12,
224 PIO0_13,
225 PIO0_14,
226 PIO0_15,
227 PIO0_16,
228 PIO0_17,
229 PIO0_18,
230 PIO0_19,
231 PIO0_2,
232 PIO0_20,
233 PIO0_21,
234 PIO0_22,
235 PIO0_23,
236 PIO0_24,
237 PIO0_25,
238 PIO0_26,
239 PIO0_27,
240 PIO0_28,
241 PIO0_29,
242 PIO0_3,
243 PIO0_30,
244 PIO0_31,
245 PIO0_4,
246 PIO0_5,
247 PIO0_6,
248 PIO0_7,
249 PIO0_8,
250 PIO0_9,
251 PIO1_0,
252 PIO1_1,
253 PIO1_10,
254 PIO1_11,
255 PIO1_12,
256 PIO1_13,
257 PIO1_14,
258 PIO1_15,
259 PIO1_16,
260 PIO1_17,
261 PIO1_18,
262 PIO1_19,
263 PIO1_2,
264 PIO1_20,
265 PIO1_21,
266 PIO1_22,
267 PIO1_23,
268 PIO1_24,
269 PIO1_25,
270 PIO1_26,
271 PIO1_27,
272 PIO1_28,
273 PIO1_29,
274 PIO1_3,
275 PIO1_30,
276 PIO1_31,
277 PIO1_4,
278 PIO1_5,
279 PIO1_6,
280 PIO1_7,
281 PIO1_8,
282 PIO1_9,
283 PIO2_0,
284 PIO2_1,
285 PIO2_10,
286 PIO2_11,
287 PIO2_12,
288 PIO2_13,
289 PIO2_14,
290 PIO2_15,
291 PIO2_16,
292 PIO2_17,
293 PIO2_18,
294 PIO2_19,
295 PIO2_2,
296 PIO2_20,
297 PIO2_21,
298 PIO2_22,
299 PIO2_23,
300 PIO2_24,
301 PIO2_25,
302 PIO2_26,
303 PIO2_27,
304 PIO2_28,
305 PIO2_29,
306 PIO2_3,
307 PIO2_30,
308 PIO2_31,
309 PIO2_4,
310 PIO2_5,
311 PIO2_6,
312 PIO2_7,
313 PIO2_8,
314 PIO2_9,
315 PIO3_0,
316 PIO3_1,
317 PIO3_10,
318 PIO3_11,
319 PIO3_12,
320 PIO3_13,
321 PIO3_14,
322 PIO3_15,
323 PIO3_16,
324 PIO3_17,
325 PIO3_18,
326 PIO3_19,
327 PIO3_2,
328 PIO3_20,
329 PIO3_21,
330 PIO3_22,
331 PIO3_23,
332 PIO3_24,
333 PIO3_25,
334 PIO3_26,
335 PIO3_27,
336 PIO3_28,
337 PIO3_29,
338 PIO3_3,
339 PIO3_30,
340 PIO3_31,
341 PIO3_4,
342 PIO3_5,
343 PIO3_6,
344 PIO3_7,
345 PIO3_8,
346 PIO3_9,
347 PIO4_0,
348 PIO4_1,
349 PIO4_10,
350 PIO4_2,
351 PIO4_3,
352 PIO4_4,
353 PIO4_5,
354 PIO4_6,
355 PIO4_7,
356 PIO4_8,
357 PIO4_9,
358 PIO7_24,
359 PIO7_25,
360 PIO7_26,
361 PIO7_27,
362 PIO7_28,
363 PIO7_29,
364 PIO7_30,
365 PIO7_31,
366 PIOFC15_SCL,
367 PIOFC15_SDA,
368 PMC_PMIC,
369 PIMCTL,
370 POWERQUAD,
371 PUF,
372 RNG,
373 RTC,
374 SCT0,
375 SECGPIO,
376 SECUREVIOLATION,
377 SEMA42,
378 SGPIO_INTA,
379 SGPIO_INTB,
380 USBHSD,
381 USBHSH,
382 USBPHY,
383 USB_WAKEUP,
384 USDHC0,
385 USDHC1,
386 UTICK0,
387 WDT0,
388 WDT1,
389);
diff --git a/embassy-imxrt/src/chips/mimxrt685s.rs b/embassy-imxrt/src/chips/mimxrt685s.rs
new file mode 100644
index 000000000..746861e35
--- /dev/null
+++ b/embassy-imxrt/src/chips/mimxrt685s.rs
@@ -0,0 +1,388 @@
1pub use mimxrt685s_pac as pac;
2
3#[allow(clippy::missing_safety_doc)]
4pub mod interrupts {
5 embassy_hal_internal::interrupt_mod!(
6 ACMP,
7 ADC0,
8 CASPER,
9 CTIMER0,
10 CTIMER1,
11 CTIMER2,
12 CTIMER3,
13 CTIMER4,
14 DMA0,
15 DMA1,
16 DMIC0,
17 DSPWAKE,
18 FLEXCOMM0,
19 FLEXCOMM1,
20 FLEXCOMM14,
21 FLEXCOMM15,
22 FLEXCOMM2,
23 FLEXCOMM3,
24 FLEXCOMM4,
25 FLEXCOMM5,
26 FLEXCOMM6,
27 FLEXCOMM7,
28 FLEXSPI,
29 GPIO_INTA,
30 GPIO_INTB,
31 HASHCRYPT,
32 HWVAD0,
33 HYPERVISOR,
34 I3C0,
35 MRT0,
36 MU_A,
37 OS_EVENT,
38 PIN_INT0,
39 PIN_INT1,
40 PIN_INT2,
41 PIN_INT3,
42 PIN_INT4,
43 PIN_INT5,
44 PIN_INT6,
45 PIN_INT7,
46 PMC_PMIC,
47 POWERQUAD,
48 PUF,
49 RNG,
50 RTC,
51 SCT0,
52 SECUREVIOLATION,
53 SGPIO_INTA,
54 SGPIO_INTB,
55 USB,
56 USBPHY_DCD,
57 USB_WAKEUP,
58 USDHC0,
59 USDHC1,
60 UTICK0,
61 WDT0,
62 WDT1,
63 );
64}
65
66embassy_hal_internal::peripherals!(
67 ACMP,
68 ADC0,
69 CASPER,
70 CRC,
71 CTIMER0_COUNT_CHANNEL0,
72 CTIMER0_COUNT_CHANNEL1,
73 CTIMER0_COUNT_CHANNEL2,
74 CTIMER0_COUNT_CHANNEL3,
75 CTIMER0_CAPTURE_CHANNEL0,
76 CTIMER0_CAPTURE_CHANNEL1,
77 CTIMER0_CAPTURE_CHANNEL2,
78 CTIMER0_CAPTURE_CHANNEL3,
79 CTIMER1_COUNT_CHANNEL0,
80 CTIMER1_COUNT_CHANNEL1,
81 CTIMER1_COUNT_CHANNEL2,
82 CTIMER1_COUNT_CHANNEL3,
83 CTIMER1_CAPTURE_CHANNEL0,
84 CTIMER1_CAPTURE_CHANNEL1,
85 CTIMER1_CAPTURE_CHANNEL2,
86 CTIMER1_CAPTURE_CHANNEL3,
87 CTIMER2_COUNT_CHANNEL0,
88 CTIMER2_COUNT_CHANNEL1,
89 CTIMER2_COUNT_CHANNEL2,
90 CTIMER2_COUNT_CHANNEL3,
91 CTIMER2_CAPTURE_CHANNEL0,
92 CTIMER2_CAPTURE_CHANNEL1,
93 CTIMER2_CAPTURE_CHANNEL2,
94 CTIMER2_CAPTURE_CHANNEL3,
95 CTIMER3_COUNT_CHANNEL0,
96 CTIMER3_COUNT_CHANNEL1,
97 CTIMER3_COUNT_CHANNEL2,
98 CTIMER3_COUNT_CHANNEL3,
99 CTIMER3_CAPTURE_CHANNEL0,
100 CTIMER3_CAPTURE_CHANNEL1,
101 CTIMER3_CAPTURE_CHANNEL2,
102 CTIMER3_CAPTURE_CHANNEL3,
103 CTIMER4_COUNT_CHANNEL0,
104 CTIMER4_COUNT_CHANNEL1,
105 CTIMER4_COUNT_CHANNEL2,
106 CTIMER4_COUNT_CHANNEL3,
107 CTIMER4_CAPTURE_CHANNEL0,
108 CTIMER4_CAPTURE_CHANNEL1,
109 CTIMER4_CAPTURE_CHANNEL2,
110 CTIMER4_CAPTURE_CHANNEL3,
111 DMA0,
112 DMA0_CH0,
113 DMA0_CH1,
114 DMA0_CH2,
115 DMA0_CH3,
116 DMA0_CH4,
117 DMA0_CH5,
118 DMA0_CH6,
119 DMA0_CH7,
120 DMA0_CH8,
121 DMA0_CH9,
122 DMA0_CH10,
123 DMA0_CH11,
124 DMA0_CH12,
125 DMA0_CH13,
126 DMA0_CH14,
127 DMA0_CH15,
128 DMA0_CH16,
129 DMA0_CH17,
130 DMA0_CH18,
131 DMA0_CH19,
132 DMA0_CH20,
133 DMA0_CH21,
134 DMA0_CH22,
135 DMA0_CH23,
136 DMA0_CH24,
137 DMA0_CH25,
138 DMA0_CH26,
139 DMA0_CH27,
140 DMA0_CH28,
141 DMA0_CH29,
142 DMA0_CH30,
143 DMA0_CH31,
144 DMA0_CH32,
145 DMA1,
146 DMA1_CH0,
147 DMA1_CH1,
148 DMA1_CH2,
149 DMA1_CH3,
150 DMA1_CH4,
151 DMA1_CH5,
152 DMA1_CH6,
153 DMA1_CH7,
154 DMA1_CH8,
155 DMA1_CH9,
156 DMA1_CH10,
157 DMA1_CH11,
158 DMA1_CH12,
159 DMA1_CH13,
160 DMA1_CH14,
161 DMA1_CH15,
162 DMA1_CH16,
163 DMA1_CH17,
164 DMA1_CH18,
165 DMA1_CH19,
166 DMA1_CH20,
167 DMA1_CH21,
168 DMA1_CH22,
169 DMA1_CH23,
170 DMA1_CH24,
171 DMA1_CH25,
172 DMA1_CH26,
173 DMA1_CH27,
174 DMA1_CH28,
175 DMA1_CH29,
176 DMA1_CH30,
177 DMA1_CH31,
178 DMA1_CH32,
179 DMIC0,
180 DSPWAKE,
181 FLEXCOMM0,
182 FLEXCOMM1,
183 FLEXCOMM14,
184 FLEXCOMM15,
185 FLEXCOMM2,
186 FLEXCOMM3,
187 FLEXCOMM4,
188 FLEXCOMM5,
189 FLEXCOMM6,
190 FLEXCOMM7,
191 FLEXSPI,
192 FREQME,
193 GPIO_INTA,
194 GPIO_INTB,
195 HASHCRYPT,
196 HSGPIO0,
197 HSGPIO1,
198 HSGPIO2,
199 HSGPIO3,
200 HSGPIO4,
201 HSGPIO5,
202 HSGPIO6,
203 HSGPIO7,
204 HWVAD0,
205 HYPERVISOR,
206 I3C0,
207 MRT0,
208 MU_A,
209 OS_EVENT,
210 PIN_INT0,
211 PIN_INT1,
212 PIN_INT2,
213 PIN_INT3,
214 PIN_INT4,
215 PIN_INT5,
216 PIN_INT6,
217 PIN_INT7,
218 PIO0_0,
219 PIO0_1,
220 PIO0_10,
221 PIO0_11,
222 PIO0_12,
223 PIO0_13,
224 PIO0_14,
225 PIO0_15,
226 PIO0_16,
227 PIO0_17,
228 PIO0_18,
229 PIO0_19,
230 PIO0_2,
231 PIO0_20,
232 PIO0_21,
233 PIO0_22,
234 PIO0_23,
235 PIO0_24,
236 PIO0_25,
237 PIO0_26,
238 PIO0_27,
239 PIO0_28,
240 PIO0_29,
241 PIO0_3,
242 PIO0_30,
243 PIO0_31,
244 PIO0_4,
245 PIO0_5,
246 PIO0_6,
247 PIO0_7,
248 PIO0_8,
249 PIO0_9,
250 PIO1_0,
251 PIO1_1,
252 PIO1_10,
253 PIO1_11,
254 PIO1_12,
255 PIO1_13,
256 PIO1_14,
257 PIO1_15,
258 PIO1_16,
259 PIO1_17,
260 PIO1_18,
261 PIO1_19,
262 PIO1_2,
263 PIO1_20,
264 PIO1_21,
265 PIO1_22,
266 PIO1_23,
267 PIO1_24,
268 PIO1_25,
269 PIO1_26,
270 PIO1_27,
271 PIO1_28,
272 PIO1_29,
273 PIO1_3,
274 PIO1_30,
275 PIO1_31,
276 PIO1_4,
277 PIO1_5,
278 PIO1_6,
279 PIO1_7,
280 PIO1_8,
281 PIO1_9,
282 PIO2_0,
283 PIO2_1,
284 PIO2_10,
285 PIO2_11,
286 PIO2_12,
287 PIO2_13,
288 PIO2_14,
289 PIO2_15,
290 PIO2_16,
291 PIO2_17,
292 PIO2_18,
293 PIO2_19,
294 PIO2_2,
295 PIO2_20,
296 PIO2_21,
297 PIO2_22,
298 PIO2_23,
299 PIO2_24,
300 PIO2_25,
301 PIO2_26,
302 PIO2_27,
303 PIO2_28,
304 PIO2_29,
305 PIO2_3,
306 PIO2_30,
307 PIO2_31,
308 PIO2_4,
309 PIO2_5,
310 PIO2_6,
311 PIO2_7,
312 PIO2_8,
313 PIO2_9,
314 PIO3_0,
315 PIO3_1,
316 PIO3_10,
317 PIO3_11,
318 PIO3_12,
319 PIO3_13,
320 PIO3_14,
321 PIO3_15,
322 PIO3_16,
323 PIO3_17,
324 PIO3_18,
325 PIO3_19,
326 PIO3_2,
327 PIO3_20,
328 PIO3_21,
329 PIO3_22,
330 PIO3_23,
331 PIO3_24,
332 PIO3_25,
333 PIO3_26,
334 PIO3_27,
335 PIO3_28,
336 PIO3_29,
337 PIO3_3,
338 PIO3_30,
339 PIO3_31,
340 PIO3_4,
341 PIO3_5,
342 PIO3_6,
343 PIO3_7,
344 PIO3_8,
345 PIO3_9,
346 PIO4_0,
347 PIO4_1,
348 PIO4_10,
349 PIO4_2,
350 PIO4_3,
351 PIO4_4,
352 PIO4_5,
353 PIO4_6,
354 PIO4_7,
355 PIO4_8,
356 PIO4_9,
357 PIO7_24,
358 PIO7_25,
359 PIO7_26,
360 PIO7_27,
361 PIO7_28,
362 PIO7_29,
363 PIO7_30,
364 PIO7_31,
365 PIOFC15_SCL,
366 PIOFC15_SDA,
367 PMC_PMIC,
368 PIMCTL,
369 POWERQUAD,
370 PUF,
371 RNG,
372 RTC,
373 SCT0,
374 SECGPIO,
375 SECUREVIOLATION,
376 SEMA42,
377 SGPIO_INTA,
378 SGPIO_INTB,
379 USBHSD,
380 USBHSH,
381 USBPHY,
382 USB_WAKEUP,
383 USDHC0,
384 USDHC1,
385 UTICK0,
386 WDT0,
387 WDT1,
388);
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs
new file mode 100644
index 000000000..1d36fb142
--- /dev/null
+++ b/embassy-imxrt/src/clocks.rs
@@ -0,0 +1,1687 @@
1//! Clock configuration for the `RT6xx`
2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering};
3
4#[cfg(feature = "defmt")]
5use defmt;
6use paste::paste;
7
8use crate::pac;
9
10/// Clock configuration;
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum Clocks {
14 /// Low power oscillator
15 Lposc,
16 /// System Frequency Resonance Oscillator (SFRO)
17 Sfro,
18 /// Real Time Clock
19 Rtc,
20 /// Feed-forward Ring Oscillator
21 Ffro, // This includes that div2 and div4 variations
22 /// External Clock Input
23 ClkIn,
24 /// AHB Clock
25 Hclk,
26 /// Main Clock
27 MainClk,
28 /// Main PLL Clock
29 MainPllClk, // also has aux0,aux1,dsp, and audio pll's downstream
30 /// System Clock
31 SysClk,
32 /// System Oscillator
33 SysOscClk,
34 /// ADC Clock
35 Adc,
36}
37
38/// Clock configuration.
39pub struct ClockConfig {
40 /// low-power oscillator config
41 pub lposc: LposcConfig,
42 /// 16Mhz internal oscillator config
43 pub sfro: SfroConfig,
44 /// Real Time Clock config
45 pub rtc: RtcClkConfig,
46 /// 48/60 Mhz internal oscillator config
47 pub ffro: FfroConfig,
48 // pub pll: Option<PllPfdConfig>, //potentially covered in main pll clk
49 /// External Clock-In config
50 pub clk_in: ClkInConfig,
51 /// AHB bus clock config
52 pub hclk: HclkConfig,
53 /// Main Clock config
54 pub main_clk: MainClkConfig,
55 /// Main Pll clock config
56 pub main_pll_clk: MainPllClkConfig,
57 /// Software concept to be used with systick, doesn't map to a register
58 pub sys_clk: SysClkConfig,
59 /// System Oscillator Config
60 pub sys_osc: SysOscConfig,
61 // todo: move ADC here
62}
63
64impl ClockConfig {
65 /// Clock configuration derived from external crystal.
66 #[must_use]
67 pub fn crystal() -> Self {
68 const CORE_CPU_FREQ: u32 = 500_000_000;
69 const PLL_CLK_FREQ: u32 = 528_000_000;
70 const SYS_CLK_FREQ: u32 = CORE_CPU_FREQ / 2;
71 Self {
72 lposc: LposcConfig {
73 state: State::Enabled,
74 freq: AtomicU32::new(Into::into(LposcFreq::Lp1m)),
75 },
76 sfro: SfroConfig { state: State::Enabled },
77 rtc: RtcClkConfig {
78 state: State::Enabled,
79 wake_alarm_state: State::Disabled,
80 sub_second_state: State::Disabled,
81 freq: AtomicU32::new(Into::into(RtcFreq::Default1Hz)),
82 rtc_int: RtcInterrupts::None,
83 },
84 ffro: FfroConfig {
85 state: State::Enabled,
86 freq: AtomicU32::new(Into::into(FfroFreq::Ffro48m)),
87 },
88 //pll: Some(PllConfig {}),//includes aux0 and aux1 pll
89 clk_in: ClkInConfig {
90 state: State::Disabled,
91 // This is an externally sourced clock
92 // Don't give it an initial frequency
93 freq: Some(AtomicU32::new(0)),
94 },
95 hclk: HclkConfig { state: State::Disabled },
96 main_clk: MainClkConfig {
97 state: State::Enabled,
98 //FFRO divided by 4 is reset values of Main Clk Sel A, Sel B
99 src: MainClkSrc::FFRO,
100 div_int: AtomicU32::new(4),
101 freq: AtomicU32::new(CORE_CPU_FREQ),
102 },
103 main_pll_clk: MainPllClkConfig {
104 state: State::Enabled,
105 src: MainPllClkSrc::SFRO,
106 freq: AtomicU32::new(PLL_CLK_FREQ),
107 mult: AtomicU8::new(16),
108 pfd0: 19, //
109 pfd1: 0, // future field
110 pfd2: 19, // 0x13
111 pfd3: 0, // future field
112 aux0_div: 0,
113 aux1_div: 0,
114 },
115 sys_clk: SysClkConfig {
116 sysclkfreq: AtomicU32::new(SYS_CLK_FREQ),
117 },
118 sys_osc: SysOscConfig { state: State::Enabled },
119 //adc: Some(AdcConfig {}), // TODO: add config
120 }
121 }
122}
123
124#[derive(Clone, Copy, Debug, PartialEq, Eq)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126/// Clock state enum
127pub enum State {
128 /// Clock is enabled
129 Enabled,
130 /// Clock is disabled
131 Disabled,
132}
133
134#[derive(Clone, Copy, Debug, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136/// Low Power Oscillator valid frequencies
137pub enum LposcFreq {
138 /// 1 `MHz` oscillator
139 Lp1m,
140 /// 32kHz oscillator
141 Lp32k,
142}
143
144impl From<LposcFreq> for u32 {
145 fn from(value: LposcFreq) -> Self {
146 match value {
147 LposcFreq::Lp1m => 1_000_000,
148 LposcFreq::Lp32k => 32_768,
149 }
150 }
151}
152
153impl TryFrom<u32> for LposcFreq {
154 type Error = ClockError;
155 fn try_from(value: u32) -> Result<Self, Self::Error> {
156 match value {
157 1_000_000 => Ok(LposcFreq::Lp1m),
158 32_768 => Ok(LposcFreq::Lp32k),
159 _ => Err(ClockError::InvalidFrequency),
160 }
161 }
162}
163
164/// Low power oscillator config
165pub struct LposcConfig {
166 state: State,
167 // low power osc
168 freq: AtomicU32,
169}
170
171const SFRO_FREQ: u32 = 16_000_000;
172/// SFRO config
173pub struct SfroConfig {
174 state: State,
175}
176
177/// Valid RTC frequencies
178pub enum RtcFreq {
179 /// "Alarm" aka 1Hz clock
180 Default1Hz,
181 /// "Wake" aka 1kHz clock
182 HighResolution1khz,
183 /// 32kHz clock
184 SubSecond32kHz,
185}
186
187impl From<RtcFreq> for u32 {
188 fn from(value: RtcFreq) -> Self {
189 match value {
190 RtcFreq::Default1Hz => 1,
191 RtcFreq::HighResolution1khz => 1_000,
192 RtcFreq::SubSecond32kHz => 32_768,
193 }
194 }
195}
196
197impl TryFrom<u32> for RtcFreq {
198 type Error = ClockError;
199 fn try_from(value: u32) -> Result<Self, Self::Error> {
200 match value {
201 1 => Ok(RtcFreq::Default1Hz),
202 1_000 => Ok(RtcFreq::HighResolution1khz),
203 32_768 => Ok(RtcFreq::SubSecond32kHz),
204 _ => Err(ClockError::InvalidFrequency),
205 }
206 }
207}
208
209/// RTC Interrupt options
210pub enum RtcInterrupts {
211 /// No interrupts are set
212 None,
213 /// 1Hz RTC clock aka Alarm interrupt set
214 Alarm,
215 /// 1kHz RTC clock aka Wake interrupt set
216 Wake,
217}
218
219impl From<RtcInterrupts> for u8 {
220 fn from(value: RtcInterrupts) -> Self {
221 match value {
222 RtcInterrupts::None => 0b00,
223 RtcInterrupts::Alarm => 0b01,
224 RtcInterrupts::Wake => 0b10,
225 }
226 }
227}
228/// RTC clock config.
229pub struct RtcClkConfig {
230 /// 1 Hz Clock state
231 pub state: State,
232 /// 1kHz Clock state
233 pub wake_alarm_state: State,
234 /// 32kHz Clock state
235 pub sub_second_state: State,
236 /// RTC clock source.
237 pub freq: AtomicU32,
238 /// RTC Interrupt
239 pub rtc_int: RtcInterrupts,
240}
241
242/// Valid FFRO Frequencies
243pub enum FfroFreq {
244 /// 48 Mhz Internal Oscillator
245 Ffro48m,
246 /// 60 `MHz` Internal Oscillator
247 Ffro60m,
248}
249
250/// FFRO Clock Config
251pub struct FfroConfig {
252 /// FFRO Clock state
253 state: State,
254 /// FFRO Frequency
255 freq: AtomicU32,
256}
257
258impl From<FfroFreq> for u32 {
259 fn from(value: FfroFreq) -> Self {
260 match value {
261 FfroFreq::Ffro48m => 48_000_000,
262 FfroFreq::Ffro60m => 60_000_000,
263 }
264 }
265}
266
267impl TryFrom<u32> for FfroFreq {
268 type Error = ClockError;
269 fn try_from(value: u32) -> Result<Self, Self::Error> {
270 match value {
271 48_000_000 => Ok(FfroFreq::Ffro48m),
272 60_000_000 => Ok(FfroFreq::Ffro60m),
273 _ => Err(ClockError::InvalidFrequency),
274 }
275 }
276}
277
278/// PLL clock source
279#[derive(Clone, Copy, Debug, PartialEq, Eq)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281pub enum MainPllClkSrc {
282 /// SFRO
283 SFRO,
284 /// External Clock
285 ClkIn,
286 /// FFRO
287 FFRO,
288}
289
290/// Transform from Source Clock enum to Clocks
291impl From<MainPllClkSrc> for Clocks {
292 fn from(value: MainPllClkSrc) -> Self {
293 match value {
294 MainPllClkSrc::SFRO => Clocks::Sfro,
295 MainPllClkSrc::ClkIn => Clocks::ClkIn,
296 MainPllClkSrc::FFRO => Clocks::Ffro,
297 }
298 }
299}
300
301impl TryFrom<Clocks> for MainPllClkSrc {
302 type Error = ClockError;
303 fn try_from(value: Clocks) -> Result<Self, Self::Error> {
304 match value {
305 Clocks::Sfro => Ok(MainPllClkSrc::SFRO),
306 Clocks::Ffro => Ok(MainPllClkSrc::FFRO),
307 Clocks::ClkIn => Ok(MainPllClkSrc::ClkIn),
308 _ => Err(ClockError::ClockNotSupported),
309 }
310 }
311}
312
313/// PLL configuration.
314pub struct MainPllClkConfig {
315 /// Clock active state
316 pub state: State,
317 /// Main clock source.
318 pub src: MainPllClkSrc,
319 /// Main clock frequency
320 pub freq: AtomicU32,
321 //TODO: numerator and denominator not used but present in register
322 /// Multiplication factor.
323 pub mult: AtomicU8,
324 // the following are actually 6-bits not 8
325 /// Fractional divider 0, main pll clock
326 pub pfd0: u8,
327 /// Fractional divider 1
328 pub pfd1: u8,
329 /// Fractional divider 2
330 pub pfd2: u8,
331 /// Fractional divider 3
332 pub pfd3: u8,
333 // Aux dividers
334 /// aux divider 0
335 pub aux0_div: u8,
336 /// aux divider 1
337 pub aux1_div: u8,
338}
339/// External input clock config
340pub struct ClkInConfig {
341 /// External clock input state
342 state: State,
343 /// External clock input rate
344 freq: Option<AtomicU32>,
345}
346
347/// AHB clock config
348pub struct HclkConfig {
349 /// divider to turn main clk into hclk for AHB bus
350 pub state: State,
351}
352
353/// Main clock source.
354#[derive(Clone, Copy, Debug, PartialEq, Eq)]
355#[cfg_attr(feature = "defmt", derive(defmt::Format))]
356pub enum MainClkSrc {
357 /// FFRO divided by 4
358 FFROdiv4, // probably don't need since it'll be covered by div_int
359 /// External Clock
360 ClkIn,
361 /// Low Power Oscillator
362 Lposc,
363 /// FFRO
364 FFRO,
365 /// SFRO
366 SFRO,
367 /// Main PLL Clock
368 PllMain,
369 /// RTC 32kHz oscillator.
370 RTC32k,
371}
372
373impl From<MainClkSrc> for Clocks {
374 fn from(value: MainClkSrc) -> Self {
375 match value {
376 MainClkSrc::ClkIn => Clocks::ClkIn,
377 MainClkSrc::Lposc => Clocks::Lposc,
378 MainClkSrc::FFRO => Clocks::Ffro,
379 MainClkSrc::SFRO => Clocks::Sfro,
380 MainClkSrc::PllMain => Clocks::MainPllClk,
381 MainClkSrc::RTC32k => Clocks::Rtc,
382 MainClkSrc::FFROdiv4 => Clocks::Ffro,
383 }
384 }
385}
386
387impl TryFrom<Clocks> for MainClkSrc {
388 type Error = ClockError;
389 fn try_from(value: Clocks) -> Result<Self, Self::Error> {
390 match value {
391 Clocks::ClkIn => Ok(MainClkSrc::ClkIn),
392 Clocks::Lposc => Ok(MainClkSrc::Lposc),
393 Clocks::Sfro => Ok(MainClkSrc::SFRO),
394 Clocks::MainPllClk => Ok(MainClkSrc::PllMain),
395 Clocks::Rtc => Ok(MainClkSrc::RTC32k),
396 Clocks::Ffro => Ok(MainClkSrc::FFRO),
397 _ => Err(ClockError::ClockNotSupported),
398 }
399 }
400}
401
402/// Main clock config.
403pub struct MainClkConfig {
404 /// Main clock state
405 pub state: State,
406 /// Main clock source.
407 pub src: MainClkSrc,
408 /// Main clock divider.
409 pub div_int: AtomicU32,
410 /// Clock Frequency
411 pub freq: AtomicU32,
412}
413
414/// System Core Clock config, SW concept for systick
415pub struct SysClkConfig {
416 /// keeps track of the system core clock frequency
417 /// future use with systick
418 pub sysclkfreq: AtomicU32,
419}
420
421/// System Oscillator Config
422pub struct SysOscConfig {
423 /// Clock State
424 pub state: State,
425}
426const SYS_OSC_DEFAULT_FREQ: u32 = 24_000_000;
427
428/// Clock Errors
429#[derive(Clone, Copy, Debug, PartialEq, Eq)]
430#[cfg_attr(feature = "defmt", derive(defmt::Format))]
431pub enum ClockError {
432 /// Error due to attempting to change a clock with the wrong config block
433 ClockMismatch,
434 /// Error due to attempting to modify a clock that's not yet been enabled
435 ClockNotEnabled,
436 /// Error due to attempting to set a clock source that's not a supported option
437 ClockNotSupported,
438 /// Error due to attempting to set a clock to an invalid frequency
439 InvalidFrequency,
440 /// Error due to attempting to modify a clock output with an invalid divider
441 InvalidDiv,
442 /// Error due to attempting to modify a clock output with an invalid multiplier
443 InvalidMult,
444}
445
446/// Trait to configure one of the clocks
447pub trait ConfigurableClock {
448 /// Reset the clock, will enable it
449 fn disable(&self) -> Result<(), ClockError>;
450 /// Enable the clock
451 fn enable_and_reset(&self) -> Result<(), ClockError>;
452 /// Return the clock rate (Hz)
453 fn get_clock_rate(&self) -> Result<u32, ClockError>;
454 /// Set the desired clock rate (Hz)
455 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError>;
456 /// Returns whether this clock is enabled
457 fn is_enabled(&self) -> bool;
458}
459
460impl LposcConfig {
461 /// Initializes low-power oscillator.
462 fn init_lposc() {
463 // Enable low power oscillator
464 // SAFETY: unsafe needed to take pointer to Sysctl0, only happens once during init
465 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
466 sysctl0.pdruncfg0_clr().write(|w| w.lposc_pd().clr_pdruncfg0());
467
468 // Wait for low-power oscillator to be ready (typically 64 us)
469 // Busy loop seems better here than trying to shoe-in an async delay
470 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to validate HW is ready
471 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
472 while clkctl0.lposcctl0().read().clkrdy().bit_is_clear() {}
473 }
474}
475impl ConfigurableClock for LposcConfig {
476 fn enable_and_reset(&self) -> Result<(), ClockError> {
477 LposcConfig::init_lposc();
478 Ok(())
479 }
480 fn disable(&self) -> Result<(), ClockError> {
481 // SAFETY: unsafe needed to take pointer to Sysctl0, needed to power down the LPOSC HW
482 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
483 sysctl0.pdruncfg0_set().write(|w| w.lposc_pd().set_pdruncfg0());
484 // Wait until LPOSC disabled
485 while !sysctl0.pdruncfg0().read().lposc_pd().is_power_down() {}
486 Ok(())
487 }
488 fn get_clock_rate(&self) -> Result<u32, ClockError> {
489 Ok(self.freq.load(Ordering::Relaxed))
490 }
491 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
492 if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(freq) {
493 match r {
494 LposcFreq::Lp1m => {
495 self.freq
496 .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed);
497 Ok(())
498 }
499 LposcFreq::Lp32k => {
500 self.freq
501 .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed);
502 Ok(())
503 }
504 }
505 } else {
506 error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq);
507 Err(ClockError::InvalidFrequency)
508 }
509 }
510 fn is_enabled(&self) -> bool {
511 self.state == State::Enabled
512 }
513}
514
515impl FfroConfig {
516 /// Necessary register writes to initialize the FFRO clock
517 pub fn init_ffro_clk() {
518 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up FFRO
519 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
520
521 /* Power on FFRO (48/60MHz) */
522 sysctl0.pdruncfg0_clr().write(|w| w.ffro_pd().clr_pdruncfg0());
523
524 // SAFETY: unsafe needed to take pointer to Clkctl0, only to set proper ffro update mode
525 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
526
527 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
528
529 // No FFRO enable/disable control in CLKCTL.
530 // Delay enough for FFRO to be stable in case it was just powered on
531 delay_loop_clocks(50, 12_000_000);
532 }
533}
534
535impl ConfigurableClock for FfroConfig {
536 fn enable_and_reset(&self) -> Result<(), ClockError> {
537 // SAFETY: should be called once
538 FfroConfig::init_ffro_clk();
539 // default is 48 MHz
540 Ok(())
541 }
542 fn disable(&self) -> Result<(), ClockError> {
543 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down FFRO
544 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
545 sysctl0.pdruncfg0_set().write(|w| w.ffro_pd().set_pdruncfg0());
546 delay_loop_clocks(30, 12_000_000);
547 // Wait until FFRO disabled
548 while !sysctl0.pdruncfg0().read().ffro_pd().is_power_down() {}
549 Ok(())
550 }
551 fn get_clock_rate(&self) -> Result<u32, ClockError> {
552 trace!("getting ffro clock rate");
553 Ok(self.freq.load(Ordering::Relaxed))
554 }
555 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
556 if let Ok(r) = <u32 as TryInto<FfroFreq>>::try_into(freq) {
557 match r {
558 FfroFreq::Ffro48m => {
559 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency
560 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
561 clkctl0.ffroctl1().write(|w| w.update().update_safe_mode());
562 clkctl0.ffroctl0().write(|w| w.trim_range().ffro_48mhz());
563 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
564
565 self.freq
566 .store(FfroFreq::Ffro48m as u32, core::sync::atomic::Ordering::Relaxed);
567 Ok(())
568 }
569 FfroFreq::Ffro60m => {
570 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency
571 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
572 clkctl0.ffroctl1().write(|w| w.update().update_safe_mode());
573 clkctl0.ffroctl0().write(|w| w.trim_range().ffro_60mhz());
574 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
575
576 self.freq
577 .store(FfroFreq::Ffro60m as u32, core::sync::atomic::Ordering::Relaxed);
578 Ok(())
579 }
580 }
581 } else {
582 error!("failed to convert desired clock rate, {:#}, to FFRO Freq", freq);
583 Err(ClockError::InvalidFrequency)
584 }
585 }
586 fn is_enabled(&self) -> bool {
587 self.state == State::Enabled
588 }
589}
590
591impl ConfigurableClock for SfroConfig {
592 fn enable_and_reset(&self) -> Result<(), ClockError> {
593 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up SFRO
594 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
595 sysctl0.pdruncfg0_clr().write(|w| w.sfro_pd().clr_pdruncfg0());
596 // wait until ready
597 while !sysctl0.pdruncfg0().read().sfro_pd().is_enabled() {}
598 Ok(())
599 }
600 fn disable(&self) -> Result<(), ClockError> {
601 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down SFRO
602 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
603 sysctl0.pdruncfg0_set().write(|w| w.sfro_pd().set_pdruncfg0());
604 delay_loop_clocks(30, 12_000_000);
605 // Wait until SFRO disabled
606 while !sysctl0.pdruncfg0().read().sfro_pd().is_power_down() {}
607 Ok(())
608 }
609 fn get_clock_rate(&self) -> Result<u32, ClockError> {
610 if self.state == State::Enabled {
611 Ok(SFRO_FREQ)
612 } else {
613 Err(ClockError::ClockNotEnabled)
614 }
615 }
616 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
617 if self.state == State::Enabled {
618 if freq == SFRO_FREQ {
619 trace!("Sfro frequency is already set at 16MHz");
620 Ok(())
621 } else {
622 Err(ClockError::InvalidFrequency)
623 }
624 } else {
625 Err(ClockError::ClockNotEnabled)
626 }
627 }
628 fn is_enabled(&self) -> bool {
629 self.state == State::Enabled
630 }
631}
632
633/// A Clock with multiple options for clock source
634pub trait MultiSourceClock {
635 /// Returns which clock is being used as the clock source and its rate
636 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError>;
637 /// Sets a specific clock source and its associated rate
638 fn set_clock_source_and_rate(
639 &mut self,
640 clock_src_config: &mut impl ConfigurableClock,
641 clock_src: &Clocks,
642 rate: u32,
643 ) -> Result<(), ClockError>;
644}
645
646impl MultiSourceClock for MainPllClkConfig {
647 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> {
648 match clock {
649 Clocks::MainPllClk => {
650 let converted_clock = Clocks::from(self.src);
651 Ok((converted_clock, self.freq.load(Ordering::Relaxed)))
652 }
653 _ => Err(ClockError::ClockMismatch),
654 }
655 }
656 fn set_clock_source_and_rate(
657 &mut self,
658 clock_src_config: &mut impl ConfigurableClock,
659 clock_src: &Clocks,
660 rate: u32,
661 ) -> Result<(), ClockError> {
662 if let Ok(c) = <Clocks as TryInto<MainPllClkSrc>>::try_into(*clock_src) {
663 match c {
664 MainPllClkSrc::ClkIn => {
665 self.src = MainPllClkSrc::ClkIn;
666 // div mult and rate don't matter since this is an external clock
667 self.set_clock_rate(1, 1, rate)
668 }
669 MainPllClkSrc::FFRO => {
670 // FFRO Clock is divided by 2
671 let r = clock_src_config.get_clock_rate()?;
672 let base_rate = r / 2;
673 let m = MainPllClkConfig::calc_mult(rate, base_rate)?;
674
675 self.src = MainPllClkSrc::FFRO;
676 self.set_clock_rate(2, m, rate)
677 }
678 MainPllClkSrc::SFRO => {
679 if !clock_src_config.is_enabled() {
680 error!("Can't set SFRO as source for MainPll as it's not enabled");
681 return Err(ClockError::ClockNotEnabled);
682 }
683 // check if desired frequency is a valid multiple of 16m SFRO clock
684 let m = MainPllClkConfig::calc_mult(rate, SFRO_FREQ)?;
685 self.src = MainPllClkSrc::SFRO;
686 self.set_clock_rate(1, m, rate)
687 }
688 }
689 } else {
690 Err(ClockError::ClockNotSupported)
691 }
692 }
693}
694
695impl ConfigurableClock for MainPllClkConfig {
696 fn enable_and_reset(&self) -> Result<(), ClockError> {
697 MainPllClkConfig::init_syspll();
698
699 MainPllClkConfig::init_syspll_pfd0(self.pfd0);
700
701 MainPllClkConfig::init_syspll_pfd2(self.pfd2);
702 Ok(())
703 }
704 fn disable(&self) -> Result<(), ClockError> {
705 if self.is_enabled() {
706 error!("Attempting to reset the Main Pll Clock, should be resetting its source");
707 Err(ClockError::ClockNotSupported)
708 } else {
709 Err(ClockError::ClockNotEnabled)
710 }
711 }
712 fn get_clock_rate(&self) -> Result<u32, ClockError> {
713 if self.is_enabled() {
714 let (_c, rate) = self.get_clock_source_and_rate(&Clocks::MainPllClk)?;
715 Ok(rate)
716 } else {
717 Err(ClockError::ClockNotEnabled)
718 }
719 }
720 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> {
721 if self.is_enabled() {
722 trace!("attempting to set main pll clock rate");
723 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
724 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
725 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
726
727 // Power down pll before changes
728 sysctl0
729 .pdruncfg0_set()
730 .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0());
731
732 let desired_freq: u64 = self.freq.load(Ordering::Relaxed).into();
733
734 match self.src {
735 c if c == MainPllClkSrc::ClkIn || c == MainPllClkSrc::FFRO || c == MainPllClkSrc::SFRO => {
736 let mut base_rate;
737 match c {
738 MainPllClkSrc::ClkIn => {
739 clkctl0.syspll0clksel().write(|w| w.sel().sysxtal_clk());
740 let r = self.get_clock_rate()?;
741 base_rate = r;
742 }
743 MainPllClkSrc::FFRO => {
744 trace!("found FFRO as source, wait a bit");
745 delay_loop_clocks(1000, desired_freq);
746 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() {
747 true => base_rate = Into::into(FfroFreq::Ffro48m),
748 false => base_rate = Into::into(FfroFreq::Ffro60m),
749 }
750 trace!("found ffro rate to be: {:#}", base_rate);
751 if div == 2 {
752 trace!("dividing FFRO rate by 2");
753 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
754 delay_loop_clocks(150, desired_freq);
755 base_rate /= 2;
756 } else {
757 return Err(ClockError::InvalidDiv);
758 }
759 }
760 MainPllClkSrc::SFRO => {
761 base_rate = SFRO_FREQ;
762 clkctl0.syspll0clksel().write(|w| w.sel().sfro_clk());
763 }
764 };
765 base_rate *= u32::from(mult);
766 trace!("calculated base rate at: {:#}", base_rate);
767 if base_rate != freq {
768 // make sure to power syspll back up before returning the error
769 error!("invalid frequency found, powering syspll back up before returning error. Check div and mult");
770 // Clear System PLL reset
771 clkctl0.syspll0ctl0().write(|w| w.reset().normal());
772 // Power up SYSPLL
773 sysctl0
774 .pdruncfg0_clr()
775 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
776 return Err(ClockError::InvalidFrequency);
777 }
778 trace!("setting default num and denom");
779 // SAFETY: unsafe needed to write the bits for the num and demon fields
780 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) });
781 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) });
782 delay_loop_clocks(30, desired_freq);
783 self.mult.store(mult, Ordering::Relaxed);
784 trace!("setting self.mult as: {:#}", mult);
785 match mult {
786 16 => {
787 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16());
788 }
789 17 => {
790 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_17());
791 }
792 20 => {
793 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_20());
794 }
795 22 => {
796 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_22());
797 }
798 27 => {
799 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_27());
800 }
801 33 => {
802 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_33());
803 }
804 _ => return Err(ClockError::InvalidMult),
805 }
806 trace!("clear syspll reset");
807 // Clear System PLL reset
808 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal());
809 // Power up SYSPLL
810 sysctl0
811 .pdruncfg0_clr()
812 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
813
814 // Set System PLL HOLDRINGOFF_ENA
815 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable());
816 delay_loop_clocks(75, desired_freq);
817
818 // Clear System PLL HOLDRINGOFF_ENA
819 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
820 delay_loop_clocks(15, desired_freq);
821
822 trace!("setting new PFD0 bits");
823 // gate the output and clear bits.
824 // SAFETY: unsafe needed to write the bits for pfd0
825 clkctl0
826 .syspll0pfd()
827 .modify(|_, w| unsafe { w.pfd0_clkgate().gated().pfd0().bits(0x0) });
828 // set pfd bits and un-gate the clock output
829 // output is multiplied by syspll * 18/pfd0_bits
830 // SAFETY: unsafe needed to write the bits for pfd0
831 clkctl0
832 .syspll0pfd()
833 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) });
834 // wait for ready bit to be set
835 delay_loop_clocks(50, desired_freq);
836 trace!("waiting for mainpll clock to be ready");
837 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
838 // clear by writing a 1
839 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit());
840
841 Ok(())
842 }
843 _ => Err(ClockError::ClockNotSupported),
844 }
845 } else {
846 Err(ClockError::ClockNotEnabled)
847 }
848 }
849 fn is_enabled(&self) -> bool {
850 self.state == State::Enabled
851 }
852}
853
854impl MainPllClkConfig {
855 /// Calculate the mult value of a desired frequency, return error if invalid
856 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> {
857 trace!("calculating mult for {:#} / {:#}", rate, base_freq);
858 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33];
859 if rate > base_freq && rate % base_freq == 0 {
860 let mult = (rate / base_freq) as u8;
861 trace!("verifying that calculated mult {:#} is a valid one", mult);
862 if VALIDMULTS.into_iter().any(|i| i == mult) {
863 Ok(mult)
864 } else {
865 Err(ClockError::InvalidFrequency)
866 }
867 } else {
868 Err(ClockError::InvalidFrequency)
869 }
870 }
871 pub(self) fn init_syspll() {
872 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
873 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
874 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
875
876 // Power down SYSPLL before change fractional settings
877 sysctl0
878 .pdruncfg0_set()
879 .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0());
880
881 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
882 // SAFETY: unsafe needed to write the bits for both num and denom
883 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0x0) });
884 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0x1) });
885
886 // kCLOCK_SysPllMult22
887 clkctl0.syspll0ctl0().modify(|_, w| w.mult().div_22());
888
889 // Clear System PLL reset
890 clkctl0.syspll0ctl0().modify(|_, w| w.reset().normal());
891
892 // Power up SYSPLL
893 sysctl0
894 .pdruncfg0_clr()
895 .write(|w| w.syspllldo_pd().clr_pdruncfg0().syspllana_pd().clr_pdruncfg0());
896 delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000);
897
898 // Set System PLL HOLDRINGOFF_ENA
899 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable());
900 delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000);
901
902 // Clear System PLL HOLDRINGOFF_ENA
903 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
904 delay_loop_clocks((15 & 0xFFFF) / 2, 12_000_000);
905 }
906 /// enables default settings for pfd2 bits
907 pub(self) fn init_syspll_pfd2(config_bits: u8) {
908 // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits
909 // needed to change the output of pfd0
910 unsafe {
911 let clkctl0 = crate::pac::Clkctl0::steal();
912
913 // Disable the clock output first.
914 // SAFETY: unsafe needed to write the bits for pfd2
915 clkctl0
916 .syspll0pfd()
917 .modify(|_, w| w.pfd2_clkgate().gated().pfd2().bits(0x0));
918
919 // Set the new value and enable output.
920 // SAFETY: unsafe needed to write the bits for pfd2
921 clkctl0
922 .syspll0pfd()
923 .modify(|_, w| w.pfd2_clkgate().not_gated().pfd2().bits(config_bits));
924
925 // Wait for output becomes stable.
926 while clkctl0.syspll0pfd().read().pfd2_clkrdy().bit_is_clear() {}
927
928 // Clear ready status flag.
929 clkctl0.syspll0pfd().modify(|_, w| w.pfd2_clkrdy().clear_bit());
930 }
931 }
932 /// Enables default settings for pfd0
933 pub(self) fn init_syspll_pfd0(config_bits: u8) {
934 // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits
935 // needed to change the output of pfd0
936 unsafe {
937 let clkctl0 = crate::pac::Clkctl0::steal();
938 // Disable the clock output first
939 clkctl0
940 .syspll0pfd()
941 .modify(|_, w| w.pfd0_clkgate().gated().pfd0().bits(0x0));
942
943 // Set the new value and enable output
944 clkctl0
945 .syspll0pfd()
946 .modify(|_, w| w.pfd0_clkgate().not_gated().pfd0().bits(config_bits));
947
948 // Wait for output becomes stable
949 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
950
951 // Clear ready status flag
952 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().clear_bit());
953 }
954 }
955}
956
957impl MainClkConfig {
958 fn init_main_clk() {
959 // SAFETY:: unsafe needed to take pointers to Clkctl0 and Clkctl1
960 // used to set the right HW frequency
961 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
962 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
963
964 clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk());
965
966 // Set PFC0DIV divider to value 2, Subtract 1 since 0-> 1, 1-> 2, etc...
967 clkctl0.pfcdiv(0).modify(|_, w| w.reset().set_bit());
968 // SAFETY: unsafe needed to write the bits for pfcdiv
969 clkctl0
970 .pfcdiv(0)
971 .write(|w| unsafe { w.div().bits(2 - 1).halt().clear_bit() });
972 while clkctl0.pfcdiv(0).read().reqflag().bit_is_set() {}
973
974 // Set FRGPLLCLKDIV divider to value 12, Subtract 1 since 0-> 1, 1-> 2, etc...
975 clkctl1.frgpllclkdiv().modify(|_, w| w.reset().set_bit());
976 // SAFETY: unsafe needed to write the bits for frgpllclkdiv
977 clkctl1
978 .frgpllclkdiv()
979 .write(|w| unsafe { w.div().bits(12 - 1).halt().clear_bit() });
980 while clkctl1.frgpllclkdiv().read().reqflag().bit_is_set() {}
981 }
982}
983impl MultiSourceClock for MainClkConfig {
984 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> {
985 match clock {
986 Clocks::MainClk => {
987 let div: u32 = if self.src == MainClkSrc::FFROdiv4 { 4 } else { 1 };
988 let converted_clock = Clocks::from(self.src);
989 match ConfigurableClock::get_clock_rate(self) {
990 Ok(_rate) => {
991 // SAFETY: unsafe needed to take pointer to Clkctl0
992 // needed to calculate the clock rate from the bits written in the registers
993 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
994 if self.src == MainClkSrc::PllMain && clkctl0.syspll0ctl0().read().bypass().is_programmed_clk()
995 {
996 let mut temp;
997 temp = self.freq.load(Ordering::Relaxed)
998 * u32::from(clkctl0.syspll0ctl0().read().mult().bits());
999 temp = (u64::from(temp) * 18 / u64::from(clkctl0.syspll0pfd().read().pfd0().bits())) as u32;
1000 return Ok((converted_clock, temp));
1001 }
1002 Ok((converted_clock, self.freq.load(Ordering::Relaxed) / div))
1003 }
1004 Err(clk_err) => Err(clk_err),
1005 }
1006 }
1007 _ => Err(ClockError::ClockMismatch),
1008 }
1009 }
1010 fn set_clock_source_and_rate(
1011 &mut self,
1012 clock_src_config: &mut impl ConfigurableClock,
1013 clock_src: &Clocks,
1014 rate: u32,
1015 ) -> Result<(), ClockError> {
1016 if !clock_src_config.is_enabled() {
1017 return Err(ClockError::ClockNotEnabled);
1018 }
1019 if let Ok(c) = <Clocks as TryInto<MainClkSrc>>::try_into(*clock_src) {
1020 // SAFETY: unsafe needed to take pointer to Clkctl0
1021 // needed to change the clock source
1022 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1023 match c {
1024 MainClkSrc::ClkIn => {
1025 self.src = MainClkSrc::ClkIn;
1026
1027 clkctl0.mainclksela().write(|w| w.sel().sysxtal_clk());
1028 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1029 Ok(())
1030 }
1031 // the following will yield the same result as if compared to FFROdiv4
1032 MainClkSrc::FFRO | MainClkSrc::FFROdiv4 => match rate {
1033 div4 if div4 == (FfroFreq::Ffro60m as u32) / 4 || div4 == (FfroFreq::Ffro48m as u32) / 4 => {
1034 self.src = MainClkSrc::FFROdiv4;
1035 self.freq.store(div4, Ordering::Relaxed);
1036
1037 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1038 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1039 Ok(())
1040 }
1041 div1 if div1 == FfroFreq::Ffro60m as u32 || div1 == FfroFreq::Ffro48m as u32 => {
1042 self.src = MainClkSrc::FFRO;
1043 self.freq.store(div1, Ordering::Relaxed);
1044
1045 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1046 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1047 Ok(())
1048 }
1049 _ => Err(ClockError::InvalidFrequency),
1050 },
1051 MainClkSrc::Lposc => {
1052 if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(rate) {
1053 match r {
1054 LposcFreq::Lp1m => {
1055 self.src = MainClkSrc::Lposc;
1056 self.freq.store(rate, Ordering::Relaxed);
1057
1058 clkctl0.mainclksela().write(|w| w.sel().lposc());
1059 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1060 Ok(())
1061 }
1062 LposcFreq::Lp32k => Err(ClockError::InvalidFrequency),
1063 }
1064 } else {
1065 Err(ClockError::InvalidFrequency)
1066 }
1067 }
1068 MainClkSrc::SFRO => {
1069 if rate == SFRO_FREQ {
1070 self.src = MainClkSrc::SFRO;
1071 self.freq.store(rate, Ordering::Relaxed);
1072 clkctl0.mainclkselb().write(|w| w.sel().sfro_clk());
1073 Ok(())
1074 } else {
1075 Err(ClockError::InvalidFrequency)
1076 }
1077 }
1078 MainClkSrc::PllMain => {
1079 let r = rate;
1080 // From Section 4.6.1.1 Pll Limitations of the RT6xx User manual
1081 let pll_max = 572_000_000;
1082 let pll_min = 80_000_000;
1083 if pll_min <= r && r <= pll_max {
1084 clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk());
1085 self.src = MainClkSrc::PllMain;
1086 self.freq.store(r, Ordering::Relaxed);
1087 Ok(())
1088 } else {
1089 Err(ClockError::InvalidFrequency)
1090 }
1091 }
1092 MainClkSrc::RTC32k => {
1093 if rate == RtcFreq::SubSecond32kHz as u32 {
1094 self.src = MainClkSrc::RTC32k;
1095 self.freq.store(rate, Ordering::Relaxed);
1096 clkctl0.mainclkselb().write(|w| w.sel().rtc_32k_clk());
1097 Ok(())
1098 } else {
1099 Err(ClockError::InvalidFrequency)
1100 }
1101 }
1102 }
1103 } else {
1104 Err(ClockError::ClockNotSupported)
1105 }
1106 }
1107}
1108
1109impl ConfigurableClock for MainClkConfig {
1110 fn enable_and_reset(&self) -> Result<(), ClockError> {
1111 MainClkConfig::init_main_clk();
1112 Ok(())
1113 }
1114 fn disable(&self) -> Result<(), ClockError> {
1115 error!("Attempting to reset the main clock, should NOT happen during runtime");
1116 Err(ClockError::ClockNotSupported)
1117 }
1118 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1119 let (_c, rate) = MainClkConfig::get_clock_source_and_rate(self, &Clocks::MainClk)?;
1120 Ok(rate)
1121 }
1122 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1123 error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate");
1124 Err(ClockError::ClockNotSupported)
1125 }
1126 fn is_enabled(&self) -> bool {
1127 self.state == State::Enabled
1128 }
1129}
1130
1131impl ConfigurableClock for ClkInConfig {
1132 fn enable_and_reset(&self) -> Result<(), ClockError> {
1133 // External Input, no hw writes needed
1134 Ok(())
1135 }
1136 fn disable(&self) -> Result<(), ClockError> {
1137 error!("Attempting to reset a clock input");
1138 Err(ClockError::ClockNotSupported)
1139 }
1140 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1141 if self.freq.is_some() {
1142 Ok(self.freq.as_ref().unwrap().load(Ordering::Relaxed))
1143 } else {
1144 Err(ClockError::ClockNotEnabled)
1145 }
1146 }
1147 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1148 trace!("Setting value of clk in config, this won't change the clock itself");
1149 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed);
1150 Ok(())
1151 }
1152 fn is_enabled(&self) -> bool {
1153 self.state == State::Enabled
1154 }
1155}
1156
1157impl RtcClkConfig {
1158 /// Register writes to initialize the RTC Clock
1159 fn init_rtc_clk() {
1160 // SAFETY: unsafe needed to take pointer to Clkctl0, Clkctl1, and RTC
1161 // needed to enable the RTC HW
1162 let cc0 = unsafe { pac::Clkctl0::steal() };
1163 let cc1 = unsafe { pac::Clkctl1::steal() };
1164 let r = unsafe { pac::Rtc::steal() };
1165 // Enable the RTC peripheral clock
1166 cc1.pscctl2_set().write(|w| w.rtc_lite_clk_set().set_clock());
1167 // Make sure the reset bit is cleared amd RTC OSC is powered up
1168 r.ctrl().modify(|_, w| w.swreset().not_in_reset().rtc_osc_pd().enable());
1169
1170 // set initial match value, note that with a 15 bit count-down timer this would
1171 // typically be 0x8000, but we are "doing some clever things" in time-driver.rs,
1172 // read more about it in the comments there
1173 // SAFETY: unsafe needed to write the bits
1174 r.wake().write(|w| unsafe { w.bits(0xA) });
1175
1176 // Enable 32K OSC
1177 cc0.osc32khzctl0().write(|w| w.ena32khz().enabled());
1178
1179 // enable rtc clk
1180 r.ctrl().modify(|_, w| w.rtc_en().enable());
1181 }
1182}
1183
1184impl ConfigurableClock for RtcClkConfig {
1185 fn enable_and_reset(&self) -> Result<(), ClockError> {
1186 // should only be called once if previously disabled
1187 RtcClkConfig::init_rtc_clk();
1188 Ok(())
1189 }
1190 fn disable(&self) -> Result<(), ClockError> {
1191 error!("Resetting the RTC clock, this should NOT happen during runtime");
1192 Err(ClockError::ClockNotSupported)
1193 }
1194 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1195 if let Ok(r) = <u32 as TryInto<RtcFreq>>::try_into(freq) {
1196 // SAFETY: unsafe needed to take pointer to RTC
1197 // needed to enable the HW for the different RTC frequencies, powered down by default
1198 let rtc = unsafe { crate::pac::Rtc::steal() };
1199 match r {
1200 RtcFreq::Default1Hz => {
1201 if rtc.ctrl().read().rtc_en().is_enable() {
1202 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1203 } else {
1204 rtc.ctrl().modify(|_r, w| w.rtc_en().enable());
1205 }
1206 Ok(())
1207 }
1208 RtcFreq::HighResolution1khz => {
1209 if rtc.ctrl().read().rtc1khz_en().is_enable() {
1210 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1211 } else {
1212 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable());
1213 }
1214 Ok(())
1215 }
1216 RtcFreq::SubSecond32kHz => {
1217 if rtc.ctrl().read().rtc_subsec_ena().is_enable() {
1218 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1219 } else {
1220 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable());
1221 }
1222 Ok(())
1223 }
1224 }
1225 } else {
1226 Err(ClockError::InvalidFrequency)
1227 }
1228 }
1229 // unlike the others, since this provides multiple clocks, return the fastest one
1230 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1231 if self.sub_second_state == State::Enabled {
1232 Ok(RtcFreq::SubSecond32kHz as u32)
1233 } else if self.wake_alarm_state == State::Enabled {
1234 Ok(RtcFreq::HighResolution1khz as u32)
1235 } else if self.state == State::Enabled {
1236 Ok(RtcFreq::Default1Hz as u32)
1237 } else {
1238 Err(ClockError::ClockNotEnabled)
1239 }
1240 }
1241 fn is_enabled(&self) -> bool {
1242 self.state == State::Enabled
1243 }
1244}
1245
1246impl SysClkConfig {
1247 /// Updates the system core clock frequency, SW concept used for systick
1248 fn update_sys_core_clock(&self) {
1249 trace!(
1250 "System core clock has been updated to {:?}, this involves no HW reg writes",
1251 self.sysclkfreq.load(Ordering::Relaxed)
1252 );
1253 }
1254}
1255
1256impl ConfigurableClock for SysOscConfig {
1257 fn enable_and_reset(&self) -> Result<(), ClockError> {
1258 if self.state == State::Enabled {
1259 trace!("SysOsc was already enabled");
1260 return Ok(());
1261 }
1262
1263 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW
1264 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1265 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
1266
1267 // Let CPU run on ffro for safe switching
1268 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1269 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1270
1271 // Power on SYSXTAL
1272 sysctl0.pdruncfg0_clr().write(|w| w.sysxtal_pd().clr_pdruncfg0());
1273
1274 // Enable system OSC
1275 clkctl0
1276 .sysoscctl0()
1277 .write(|w| w.lp_enable().lp().bypass_enable().normal_mode());
1278
1279 delay_loop_clocks(260, SYS_OSC_DEFAULT_FREQ.into());
1280 Ok(())
1281 }
1282 fn disable(&self) -> Result<(), ClockError> {
1283 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW
1284 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1285 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
1286
1287 // Let CPU run on ffro for safe switching
1288 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1289 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1290
1291 // Power on SYSXTAL
1292 sysctl0.pdruncfg0_set().write(|w| w.sysxtal_pd().set_pdruncfg0());
1293 Ok(())
1294 }
1295 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1296 if self.state == State::Enabled {
1297 Ok(SYS_OSC_DEFAULT_FREQ)
1298 } else {
1299 Err(ClockError::ClockNotEnabled)
1300 }
1301 }
1302 fn is_enabled(&self) -> bool {
1303 self.state == State::Enabled
1304 }
1305 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1306 Err(ClockError::ClockNotSupported)
1307 }
1308}
1309
1310/// Method to delay for a certain number of microseconds given a clock rate
1311pub fn delay_loop_clocks(usec: u64, freq_mhz: u64) {
1312 let mut ticks = usec * freq_mhz / 1_000_000 / 4;
1313 if ticks > u64::from(u32::MAX) {
1314 ticks = u64::from(u32::MAX);
1315 }
1316 // won't panic since we check value above
1317 cortex_m::asm::delay(ticks as u32);
1318}
1319
1320/// Configure the pad voltage pmc registers for all 3 vddio ranges
1321fn set_pad_voltage_range() {
1322 // SAFETY: unsafe needed to take pointer to PNC as well as to write specific bits
1323 unsafe {
1324 let pmc = crate::pac::Pmc::steal();
1325 // Set up IO voltages
1326 // all 3 ranges need to be 1.71-1.98V which is 01
1327 pmc.padvrange().write(|w| {
1328 w.vddio_0range()
1329 .bits(0b01)
1330 .vddio_1range()
1331 .bits(0b01)
1332 .vddio_2range()
1333 .bits(0b01)
1334 });
1335 }
1336}
1337
1338/// Initialize AHB clock
1339fn init_syscpuahb_clk() {
1340 // SAFETY: unsafe needed to take pointer to Clkctl0
1341 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1342 // SAFETY: unsafe needed to write the bits
1343 // Set syscpuahbclkdiv to value 2, Subtract 1 since 0-> 1, 1-> 2, etc...
1344 clkctl0.syscpuahbclkdiv().write(|w| unsafe { w.div().bits(2 - 1) });
1345
1346 while clkctl0.syscpuahbclkdiv().read().reqflag().bit_is_set() {}
1347}
1348
1349/// `ClockOut` config
1350pub struct ClockOutConfig {
1351 src: ClkOutSrc,
1352 div: u8,
1353}
1354
1355/// `ClockOut` sources
1356#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1357#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1358/// `ClockOut` sources
1359pub enum ClkOutSrc {
1360 /// No Source, reduce power consumption
1361 None,
1362 /// SFRO clock
1363 Sfro,
1364 /// External input clock
1365 ClkIn,
1366 /// Low-power oscillator
1367 Lposc,
1368 /// FFRO clock
1369 Ffro,
1370 /// Main clock
1371 MainClk,
1372 /// Main DSP clock
1373 DspMainClk,
1374 /// Main Pll clock
1375 MainPllClk,
1376 /// `SysPll` Aux0 clock
1377 Aux0PllClk,
1378 /// `SysPll` DSP clock
1379 DspPllClk,
1380 /// `SysPll` Aux1 clock
1381 Aux1PllClk,
1382 /// Audio Pll clock
1383 AudioPllClk,
1384 /// 32 `KHz` RTC
1385 RTC32k,
1386}
1387
1388/// Initialize the `ClkOutConfig`
1389impl ClockOutConfig {
1390 /// Default configuration for Clock out
1391 #[must_use]
1392 pub fn default_config() -> Self {
1393 Self {
1394 src: ClkOutSrc::None,
1395 div: 0,
1396 }
1397 }
1398
1399 /// Enable the Clock Out output
1400 pub fn enable_and_reset(&mut self) -> Result<(), ClockError> {
1401 self.set_clkout_source_and_div(self.src, self.div)?;
1402 Ok(())
1403 }
1404
1405 /// Disable Clock Out output and select None as the source to conserve power
1406 pub fn disable(&mut self) -> Result<(), ClockError> {
1407 self.set_clkout_source_and_div(ClkOutSrc::None, 0)?;
1408 Ok(())
1409 }
1410
1411 /// Set the source of the Clock Out pin
1412 fn set_clkout_source(&mut self, src: ClkOutSrc) -> Result<(), ClockError> {
1413 // SAFETY: unsafe needed to take pointers to Clkctl1, needed to set source in HW
1414 let cc1 = unsafe { pac::Clkctl1::steal() };
1415 match src {
1416 ClkOutSrc::None => {
1417 cc1.clkoutsel0().write(|w| w.sel().none());
1418 cc1.clkoutsel1().write(|w| w.sel().none());
1419 }
1420 ClkOutSrc::Sfro => {
1421 cc1.clkoutsel0().write(|w| w.sel().sfro_clk());
1422 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1423 }
1424 ClkOutSrc::ClkIn => {
1425 cc1.clkoutsel0().write(|w| w.sel().xtalin_clk());
1426 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1427 }
1428 ClkOutSrc::Lposc => {
1429 cc1.clkoutsel0().write(|w| w.sel().lposc());
1430 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1431 }
1432 ClkOutSrc::Ffro => {
1433 cc1.clkoutsel0().write(|w| w.sel().ffro_clk());
1434 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1435 }
1436 ClkOutSrc::MainClk => {
1437 cc1.clkoutsel0().write(|w| w.sel().main_clk());
1438 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1439 }
1440 ClkOutSrc::DspMainClk => {
1441 cc1.clkoutsel0().write(|w| w.sel().dsp_main_clk());
1442 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1443 }
1444 ClkOutSrc::MainPllClk => {
1445 cc1.clkoutsel0().write(|w| w.sel().none());
1446 cc1.clkoutsel1().write(|w| w.sel().main_pll_clk());
1447 }
1448 ClkOutSrc::Aux0PllClk => {
1449 cc1.clkoutsel0().write(|w| w.sel().none());
1450 cc1.clkoutsel1().write(|w| w.sel().syspll0_aux0_pll_clk());
1451 }
1452 ClkOutSrc::DspPllClk => {
1453 cc1.clkoutsel0().write(|w| w.sel().none());
1454 cc1.clkoutsel1().write(|w| w.sel().dsp_pll_clk());
1455 }
1456 ClkOutSrc::AudioPllClk => {
1457 cc1.clkoutsel0().write(|w| w.sel().none());
1458 cc1.clkoutsel1().write(|w| w.sel().audio_pll_clk());
1459 }
1460 ClkOutSrc::Aux1PllClk => {
1461 cc1.clkoutsel0().write(|w| w.sel().none());
1462 cc1.clkoutsel1().write(|w| w.sel().syspll0_aux1_pll_clk());
1463 }
1464 ClkOutSrc::RTC32k => {
1465 cc1.clkoutsel0().write(|w| w.sel().none());
1466 cc1.clkoutsel1().write(|w| w.sel().rtc_clk_32khz());
1467 }
1468 }
1469 self.src = src;
1470 Ok(())
1471 }
1472 /// set the clock out divider
1473 /// note that 1 will be added to div when mapping to the divider
1474 /// so bits(0) -> divide by 1
1475 /// ...
1476 /// bits(255)-> divide by 256
1477 pub fn set_clkout_divider(&self, div: u8) -> Result<(), ClockError> {
1478 // don't wait for clock to be ready if there's no source
1479 if self.src != ClkOutSrc::None {
1480 let cc1 = unsafe { pac::Clkctl1::steal() };
1481
1482 cc1.clkoutdiv()
1483 .modify(|_, w| unsafe { w.div().bits(div).halt().clear_bit() });
1484 while cc1.clkoutdiv().read().reqflag().bit_is_set() {}
1485 }
1486 Ok(())
1487 }
1488 /// set the source and divider for the clockout pin
1489 pub fn set_clkout_source_and_div(&mut self, src: ClkOutSrc, div: u8) -> Result<(), ClockError> {
1490 self.set_clkout_source(src)?;
1491
1492 self.set_clkout_divider(div)?;
1493
1494 Ok(())
1495 }
1496}
1497
1498/// Using the config, enables all desired clocks to desired clock rates
1499fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1500 if let Err(e) = config.rtc.enable_and_reset() {
1501 error!("couldn't Power on OSC for RTC, result: {:?}", e);
1502 return Err(e);
1503 }
1504
1505 if let Err(e) = config.lposc.enable_and_reset() {
1506 error!("couldn't Power on LPOSC, result: {:?}", e);
1507 return Err(e);
1508 }
1509
1510 if let Err(e) = config.ffro.enable_and_reset() {
1511 error!("couldn't Power on FFRO, result: {:?}", e);
1512 return Err(e);
1513 }
1514
1515 if let Err(e) = config.sfro.enable_and_reset() {
1516 error!("couldn't Power on SFRO, result: {:?}", e);
1517 return Err(e);
1518 }
1519
1520 if let Err(e) = config.sys_osc.enable_and_reset() {
1521 error!("Couldn't enable sys oscillator {:?}", e);
1522 return Err(e);
1523 }
1524
1525 if let Err(e) = config.main_pll_clk.enable_and_reset() {
1526 error!("Couldn't enable main pll clock {:?}", e);
1527 return Err(e);
1528 }
1529
1530 // Move FLEXSPI clock source from main clock to FFRO to avoid instruction/data fetch issue in XIP when
1531 // updating PLL and main clock.
1532 // SAFETY: unsafe needed to take pointers to Clkctl0
1533 let cc0 = unsafe { pac::Clkctl0::steal() };
1534 cc0.flexspifclksel().write(|w| w.sel().ffro_clk());
1535
1536 // Move ESPI clock source to FFRO
1537 #[cfg(feature = "_espi")]
1538 {
1539 cc0.espiclksel().write(|w| w.sel().use_48_60m());
1540 }
1541
1542 init_syscpuahb_clk();
1543
1544 if let Err(e) = config.main_clk.enable_and_reset() {
1545 error!("Couldn't enable main clock {:?}", e);
1546 return Err(e);
1547 }
1548
1549 config.sys_clk.update_sys_core_clock();
1550 Ok(())
1551}
1552
1553/// SAFETY: must be called exactly once at bootup
1554pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> {
1555 init_clock_hw(config)?;
1556
1557 // set VDDIO ranges 0-2
1558 set_pad_voltage_range();
1559 Ok(())
1560}
1561
1562///Trait to expose perph clocks
1563trait SealedSysconPeripheral {
1564 fn enable_and_reset_perph_clock();
1565 fn disable_perph_clock();
1566}
1567
1568/// Clock and Reset control for peripherals
1569#[allow(private_bounds)]
1570pub trait SysconPeripheral: SealedSysconPeripheral + 'static {}
1571/// Enables and resets peripheral `T`.
1572///
1573/// # Safety
1574///
1575/// Peripheral must not be in use.
1576pub fn enable_and_reset<T: SysconPeripheral>() {
1577 T::enable_and_reset_perph_clock();
1578}
1579
1580/// Disables peripheral `T`.
1581///
1582/// # Safety
1583///
1584/// Peripheral must not be in use.
1585pub fn disable<T: SysconPeripheral>() {
1586 T::disable_perph_clock();
1587}
1588macro_rules! impl_perph_clk {
1589 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => {
1590 impl SealedSysconPeripheral for crate::peripherals::$peripheral {
1591 fn enable_and_reset_perph_clock() {
1592 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1593 let cc1 = unsafe { pac::$clkctl::steal() };
1594 let rc1 = unsafe { pac::$rstctl::steal() };
1595
1596 paste! {
1597 // SAFETY: unsafe due to the use of bits()
1598 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1599
1600 // SAFETY: unsafe due to the use of bits()
1601 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1602 }
1603 }
1604
1605 fn disable_perph_clock() {
1606 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1607 let cc1 = unsafe { pac::$clkctl::steal() };
1608 let rc1 = unsafe { pac::$rstctl::steal() };
1609
1610 paste! {
1611 // SAFETY: unsafe due to the use of bits()
1612 rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1613
1614 // SAFETY: unsafe due to the use of bits()
1615 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1616 }
1617 }
1618 }
1619
1620 impl SysconPeripheral for crate::peripherals::$peripheral {}
1621 };
1622}
1623
1624// These should enabled once the relevant peripherals are implemented.
1625// impl_perph_clk!(GPIOINTCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 30);
1626// impl_perph_clk!(OTP, Clkctl0, pscctl0, Rstctl0, prstctl0, 17);
1627
1628// impl_perph_clk!(ROM_CTL_128KB, Clkctl0, pscctl0, Rstctl0, prstctl0, 2);
1629// impl_perph_clk!(USBHS_SRAM, Clkctl0, pscctl0, Rstctl0, prstctl0, 23);
1630
1631impl_perph_clk!(PIMCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 31);
1632impl_perph_clk!(ACMP, Clkctl0, pscctl1, Rstctl0, prstctl1, 15);
1633impl_perph_clk!(ADC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 16);
1634impl_perph_clk!(CASPER, Clkctl0, pscctl0, Rstctl0, prstctl0, 9);
1635impl_perph_clk!(CRC, Clkctl1, pscctl1, Rstctl1, prstctl1, 16);
1636impl_perph_clk!(CTIMER0_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 0);
1637impl_perph_clk!(CTIMER1_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 1);
1638impl_perph_clk!(CTIMER2_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 2);
1639impl_perph_clk!(CTIMER3_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 3);
1640impl_perph_clk!(CTIMER4_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 4);
1641impl_perph_clk!(DMA0, Clkctl1, pscctl1, Rstctl1, prstctl1, 23);
1642impl_perph_clk!(DMA1, Clkctl1, pscctl1, Rstctl1, prstctl1, 24);
1643impl_perph_clk!(DMIC0, Clkctl1, pscctl0, Rstctl1, prstctl0, 24);
1644
1645#[cfg(feature = "_espi")]
1646impl_perph_clk!(ESPI, Clkctl0, pscctl1, Rstctl0, prstctl1, 7);
1647
1648impl_perph_clk!(FLEXCOMM0, Clkctl1, pscctl0, Rstctl1, prstctl0, 8);
1649impl_perph_clk!(FLEXCOMM1, Clkctl1, pscctl0, Rstctl1, prstctl0, 9);
1650impl_perph_clk!(FLEXCOMM14, Clkctl1, pscctl0, Rstctl1, prstctl0, 22);
1651impl_perph_clk!(FLEXCOMM15, Clkctl1, pscctl0, Rstctl1, prstctl0, 23);
1652impl_perph_clk!(FLEXCOMM2, Clkctl1, pscctl0, Rstctl1, prstctl0, 10);
1653impl_perph_clk!(FLEXCOMM3, Clkctl1, pscctl0, Rstctl1, prstctl0, 11);
1654impl_perph_clk!(FLEXCOMM4, Clkctl1, pscctl0, Rstctl1, prstctl0, 12);
1655impl_perph_clk!(FLEXCOMM5, Clkctl1, pscctl0, Rstctl1, prstctl0, 13);
1656impl_perph_clk!(FLEXCOMM6, Clkctl1, pscctl0, Rstctl1, prstctl0, 14);
1657impl_perph_clk!(FLEXCOMM7, Clkctl1, pscctl0, Rstctl1, prstctl0, 15);
1658impl_perph_clk!(FLEXSPI, Clkctl0, pscctl0, Rstctl0, prstctl0, 16);
1659impl_perph_clk!(FREQME, Clkctl1, pscctl1, Rstctl1, prstctl1, 31);
1660impl_perph_clk!(HASHCRYPT, Clkctl0, pscctl0, Rstctl0, prstctl0, 10);
1661impl_perph_clk!(HSGPIO0, Clkctl1, pscctl1, Rstctl1, prstctl1, 0);
1662impl_perph_clk!(HSGPIO1, Clkctl1, pscctl1, Rstctl1, prstctl1, 1);
1663impl_perph_clk!(HSGPIO2, Clkctl1, pscctl1, Rstctl1, prstctl1, 2);
1664impl_perph_clk!(HSGPIO3, Clkctl1, pscctl1, Rstctl1, prstctl1, 3);
1665impl_perph_clk!(HSGPIO4, Clkctl1, pscctl1, Rstctl1, prstctl1, 4);
1666impl_perph_clk!(HSGPIO5, Clkctl1, pscctl1, Rstctl1, prstctl1, 5);
1667impl_perph_clk!(HSGPIO6, Clkctl1, pscctl1, Rstctl1, prstctl1, 6);
1668impl_perph_clk!(HSGPIO7, Clkctl1, pscctl1, Rstctl1, prstctl1, 7);
1669impl_perph_clk!(I3C0, Clkctl1, pscctl2, Rstctl1, prstctl2, 16);
1670impl_perph_clk!(MRT0, Clkctl1, pscctl2, Rstctl1, prstctl2, 8);
1671impl_perph_clk!(MU_A, Clkctl1, pscctl1, Rstctl1, prstctl1, 28);
1672impl_perph_clk!(OS_EVENT, Clkctl1, pscctl0, Rstctl1, prstctl0, 27);
1673impl_perph_clk!(POWERQUAD, Clkctl0, pscctl0, Rstctl0, prstctl0, 8);
1674impl_perph_clk!(PUF, Clkctl0, pscctl0, Rstctl0, prstctl0, 11);
1675impl_perph_clk!(RNG, Clkctl0, pscctl0, Rstctl0, prstctl0, 12);
1676impl_perph_clk!(RTC, Clkctl1, pscctl2, Rstctl1, prstctl2, 7);
1677impl_perph_clk!(SCT0, Clkctl0, pscctl0, Rstctl0, prstctl0, 24);
1678impl_perph_clk!(SECGPIO, Clkctl0, pscctl1, Rstctl0, prstctl1, 24);
1679impl_perph_clk!(SEMA42, Clkctl1, pscctl1, Rstctl1, prstctl1, 29);
1680impl_perph_clk!(USBHSD, Clkctl0, pscctl0, Rstctl0, prstctl0, 21);
1681impl_perph_clk!(USBHSH, Clkctl0, pscctl0, Rstctl0, prstctl0, 22);
1682impl_perph_clk!(USBPHY, Clkctl0, pscctl0, Rstctl0, prstctl0, 20);
1683impl_perph_clk!(USDHC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 2);
1684impl_perph_clk!(USDHC1, Clkctl0, pscctl1, Rstctl0, prstctl1, 3);
1685impl_perph_clk!(UTICK0, Clkctl0, pscctl2, Rstctl0, prstctl2, 0);
1686impl_perph_clk!(WDT0, Clkctl0, pscctl2, Rstctl0, prstctl2, 1);
1687impl_perph_clk!(WDT1, Clkctl1, pscctl2, Rstctl1, prstctl2, 10);
diff --git a/embassy-imxrt/src/fmt.rs b/embassy-imxrt/src/fmt.rs
new file mode 100644
index 000000000..c65273340
--- /dev/null
+++ b/embassy-imxrt/src/fmt.rs
@@ -0,0 +1,257 @@
1#![macro_use]
2#![allow(unused)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[collapse_debuginfo(yes)]
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18#[collapse_debuginfo(yes)]
19macro_rules! assert_eq {
20 ($($x:tt)*) => {
21 {
22 #[cfg(not(feature = "defmt"))]
23 ::core::assert_eq!($($x)*);
24 #[cfg(feature = "defmt")]
25 ::defmt::assert_eq!($($x)*);
26 }
27 };
28}
29
30#[collapse_debuginfo(yes)]
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42#[collapse_debuginfo(yes)]
43macro_rules! debug_assert {
44 ($($x:tt)*) => {
45 {
46 #[cfg(not(feature = "defmt"))]
47 ::core::debug_assert!($($x)*);
48 #[cfg(feature = "defmt")]
49 ::defmt::debug_assert!($($x)*);
50 }
51 };
52}
53
54#[collapse_debuginfo(yes)]
55macro_rules! debug_assert_eq {
56 ($($x:tt)*) => {
57 {
58 #[cfg(not(feature = "defmt"))]
59 ::core::debug_assert_eq!($($x)*);
60 #[cfg(feature = "defmt")]
61 ::defmt::debug_assert_eq!($($x)*);
62 }
63 };
64}
65
66#[collapse_debuginfo(yes)]
67macro_rules! debug_assert_ne {
68 ($($x:tt)*) => {
69 {
70 #[cfg(not(feature = "defmt"))]
71 ::core::debug_assert_ne!($($x)*);
72 #[cfg(feature = "defmt")]
73 ::defmt::debug_assert_ne!($($x)*);
74 }
75 };
76}
77
78#[collapse_debuginfo(yes)]
79macro_rules! todo {
80 ($($x:tt)*) => {
81 {
82 #[cfg(not(feature = "defmt"))]
83 ::core::todo!($($x)*);
84 #[cfg(feature = "defmt")]
85 ::defmt::todo!($($x)*);
86 }
87 };
88}
89
90#[collapse_debuginfo(yes)]
91macro_rules! unreachable {
92 ($($x:tt)*) => {
93 {
94 #[cfg(not(feature = "defmt"))]
95 ::core::unreachable!($($x)*);
96 #[cfg(feature = "defmt")]
97 ::defmt::unreachable!($($x)*);
98 }
99 };
100}
101
102#[collapse_debuginfo(yes)]
103macro_rules! panic {
104 ($($x:tt)*) => {
105 {
106 #[cfg(not(feature = "defmt"))]
107 ::core::panic!($($x)*);
108 #[cfg(feature = "defmt")]
109 ::defmt::panic!($($x)*);
110 }
111 };
112}
113
114#[collapse_debuginfo(yes)]
115macro_rules! trace {
116 ($s:literal $(, $x:expr)* $(,)?) => {
117 {
118 #[cfg(feature = "defmt")]
119 ::defmt::trace!($s $(, $x)*);
120 #[cfg(not(feature = "defmt"))]
121 let _ = ($( & $x ),*);
122 }
123 };
124}
125
126#[collapse_debuginfo(yes)]
127macro_rules! debug {
128 ($s:literal $(, $x:expr)* $(,)?) => {
129 {
130 #[cfg(feature = "defmt")]
131 ::defmt::debug!($s $(, $x)*);
132 #[cfg(not(feature = "defmt"))]
133 let _ = ($( & $x ),*);
134 }
135 };
136}
137
138#[collapse_debuginfo(yes)]
139macro_rules! info {
140 ($s:literal $(, $x:expr)* $(,)?) => {
141 {
142 #[cfg(feature = "defmt")]
143 ::defmt::info!($s $(, $x)*);
144 #[cfg(not(feature = "defmt"))]
145 let _ = ($( & $x ),*);
146 }
147 };
148}
149
150#[collapse_debuginfo(yes)]
151macro_rules! warn {
152 ($s:literal $(, $x:expr)* $(,)?) => {
153 {
154 #[cfg(feature = "defmt")]
155 ::defmt::warn!($s $(, $x)*);
156 #[cfg(not(feature = "defmt"))]
157 let _ = ($( & $x ),*);
158 }
159 };
160}
161
162#[collapse_debuginfo(yes)]
163macro_rules! error {
164 ($s:literal $(, $x:expr)* $(,)?) => {
165 {
166 #[cfg(feature = "defmt")]
167 ::defmt::error!($s $(, $x)*);
168 #[cfg(not(feature = "defmt"))]
169 let _ = ($( & $x ),*);
170 }
171 };
172}
173
174#[cfg(feature = "defmt")]
175#[collapse_debuginfo(yes)]
176macro_rules! unwrap {
177 ($($x:tt)*) => {
178 ::defmt::unwrap!($($x)*)
179 };
180}
181
182#[cfg(not(feature = "defmt"))]
183#[collapse_debuginfo(yes)]
184macro_rules! unwrap {
185 ($arg:expr) => {
186 match $crate::fmt::Try::into_result($arg) {
187 ::core::result::Result::Ok(t) => t,
188 ::core::result::Result::Err(e) => {
189 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
190 }
191 }
192 };
193 ($arg:expr, $($msg:expr),+ $(,)? ) => {
194 match $crate::fmt::Try::into_result($arg) {
195 ::core::result::Result::Ok(t) => t,
196 ::core::result::Result::Err(e) => {
197 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
198 }
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError;
205
206pub trait Try {
207 type Ok;
208 type Error;
209 fn into_result(self) -> Result<Self::Ok, Self::Error>;
210}
211
212impl<T> Try for Option<T> {
213 type Ok = T;
214 type Error = NoneError;
215
216 #[inline]
217 fn into_result(self) -> Result<T, NoneError> {
218 self.ok_or(NoneError)
219 }
220}
221
222impl<T, E> Try for Result<T, E> {
223 type Ok = T;
224 type Error = E;
225
226 #[inline]
227 fn into_result(self) -> Self {
228 self
229 }
230}
231
232pub(crate) struct Bytes<'a>(pub &'a [u8]);
233
234impl Debug for Bytes<'_> {
235 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236 write!(f, "{:#02x?}", self.0)
237 }
238}
239
240impl Display for Bytes<'_> {
241 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 write!(f, "{:#02x?}", self.0)
243 }
244}
245
246impl LowerHex for Bytes<'_> {
247 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248 write!(f, "{:#02x?}", self.0)
249 }
250}
251
252#[cfg(feature = "defmt")]
253impl defmt::Format for Bytes<'_> {
254 fn format(&self, fmt: defmt::Formatter) {
255 defmt::write!(fmt, "{:02x}", self.0)
256 }
257}
diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs
new file mode 100644
index 000000000..6883c4ee0
--- /dev/null
+++ b/embassy-imxrt/src/gpio.rs
@@ -0,0 +1,1060 @@
1//! GPIO
2
3use core::convert::Infallible;
4use core::future::Future;
5use core::marker::PhantomData;
6use core::pin::Pin as FuturePin;
7use core::task::{Context, Poll};
8
9use embassy_hal_internal::interrupt::InterruptExt;
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::clocks::enable_and_reset;
13use crate::iopctl::IopctlPin;
14pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate};
15use crate::sealed::Sealed;
16use crate::{interrupt, peripherals, Peri, PeripheralType};
17
18// This should be unique per IMXRT package
19const PORT_COUNT: usize = 8;
20
21/// Digital input or output level.
22#[derive(Debug, Eq, PartialEq, Copy, Clone)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum Level {
25 /// Logic Low
26 Low,
27 /// Logic High
28 High,
29}
30
31impl From<bool> for Level {
32 fn from(val: bool) -> Self {
33 match val {
34 true => Self::High,
35 false => Self::Low,
36 }
37 }
38}
39
40impl From<Level> for bool {
41 fn from(level: Level) -> bool {
42 match level {
43 Level::Low => false,
44 Level::High => true,
45 }
46 }
47}
48
49/// Interrupt trigger levels.
50#[derive(Debug, Eq, PartialEq, Copy, Clone)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52pub enum InterruptType {
53 /// Trigger on level.
54 Level,
55 /// Trigger on edge.
56 Edge,
57}
58
59#[cfg(feature = "rt")]
60#[interrupt]
61#[allow(non_snake_case)]
62fn GPIO_INTA() {
63 irq_handler(&GPIO_WAKERS);
64}
65
66#[cfg(feature = "rt")]
67struct BitIter(u32);
68
69#[cfg(feature = "rt")]
70impl Iterator for BitIter {
71 type Item = u32;
72
73 fn next(&mut self) -> Option<Self::Item> {
74 match self.0.trailing_zeros() {
75 32 => None,
76 b => {
77 self.0 &= !(1 << b);
78 Some(b)
79 }
80 }
81 }
82}
83
84#[cfg(feature = "rt")]
85fn irq_handler(port_wakers: &[Option<&PortWaker>]) {
86 let reg = unsafe { crate::pac::Gpio::steal() };
87
88 for (port, port_waker) in port_wakers.iter().enumerate() {
89 let Some(port_waker) = port_waker else {
90 continue;
91 };
92
93 let stat = reg.intstata(port).read().bits();
94 for pin in BitIter(stat) {
95 // Clear the interrupt from this pin
96 reg.intstata(port).write(|w| unsafe { w.status().bits(1 << pin) });
97 // Disable interrupt from this pin
98 reg.intena(port)
99 .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() & !(1 << pin)) });
100
101 let Some(waker) = port_waker.get_waker(pin as usize) else {
102 continue;
103 };
104
105 waker.wake();
106 }
107 }
108}
109
110/// Initialization Logic
111/// Note: GPIO port clocks are initialized in the clocks module.
112pub(crate) fn init() {
113 // Enable GPIO clocks
114 enable_and_reset::<peripherals::HSGPIO0>();
115 enable_and_reset::<peripherals::HSGPIO1>();
116 enable_and_reset::<peripherals::HSGPIO2>();
117 enable_and_reset::<peripherals::HSGPIO3>();
118 enable_and_reset::<peripherals::HSGPIO4>();
119 enable_and_reset::<peripherals::HSGPIO5>();
120 enable_and_reset::<peripherals::HSGPIO6>();
121 enable_and_reset::<peripherals::HSGPIO7>();
122
123 // Enable INTA
124 interrupt::GPIO_INTA.unpend();
125
126 // SAFETY:
127 //
128 // At this point, all GPIO interrupts are masked. No interrupts
129 // will trigger until a pin is configured as Input, which can only
130 // happen after initialization of the HAL
131 unsafe { interrupt::GPIO_INTA.enable() };
132}
133
134/// Input Sense mode.
135pub trait Sense: Sealed {}
136
137/// Sense Enabled Flex pin.
138///
139/// This is a true flex pin as the input buffer is enabled.
140/// It can sense its own level when even when configured as an output pin.
141pub enum SenseEnabled {}
142impl Sealed for SenseEnabled {}
143impl Sense for SenseEnabled {}
144
145/// Sense Enabled Flex pin.
146///
147/// This is **not** a true flex pin as the input buffer is disabled.
148/// It cannot be turned into an input and it cannot see its own state, but it consumes less power.
149/// Consider using a sense enabled flex pin if you need to read the pin's state or turn this into an input,
150/// however note that **power consumption may be increased**.
151pub enum SenseDisabled {}
152impl Sealed for SenseDisabled {}
153impl Sense for SenseDisabled {}
154
155/// Flex pin.
156///
157/// This pin can be either an input or output pin. The output level register bit will
158/// remain set while not in output mode, so the pin's level will be 'remembered' when it is not in
159/// output mode.
160pub struct Flex<'d, S: Sense> {
161 pin: Peri<'d, AnyPin>,
162 _sense_mode: PhantomData<S>,
163}
164
165impl<S: Sense> Flex<'_, S> {
166 /// Converts pin to output pin
167 ///
168 /// The pin level will be whatever was set before (or low by default). If you want it to begin
169 /// at a specific level, call `set_high`/`set_low` on the pin first.
170 pub fn set_as_output(&mut self, mode: DriveMode, strength: DriveStrength, slew_rate: SlewRate) {
171 self.pin
172 .set_pull(Pull::None)
173 .set_drive_mode(mode)
174 .set_drive_strength(strength)
175 .set_slew_rate(slew_rate);
176
177 self.pin.block().dirset(self.pin.port()).write(|w|
178 // SAFETY: Writing a 0 to bits in this register has no effect,
179 // however PAC has it marked unsafe due to using the bits() method.
180 // There is not currently a "safe" method for setting a single-bit.
181 unsafe { w.dirsetp().bits(1 << self.pin.pin()) });
182 }
183
184 /// Set high
185 pub fn set_high(&mut self) {
186 self.pin.block().set(self.pin.port()).write(|w|
187 // SAFETY: Writing a 0 to bits in this register has no effect,
188 // however PAC has it marked unsafe due to using the bits() method.
189 // There is not currently a "safe" method for setting a single-bit.
190 unsafe { w.setp().bits(1 << self.pin.pin()) });
191 }
192
193 /// Set low
194 pub fn set_low(&mut self) {
195 self.pin.block().clr(self.pin.port()).write(|w|
196 // SAFETY: Writing a 0 to bits in this register has no effect,
197 // however PAC has it marked unsafe due to using the bits() method.
198 // There is not currently a "safe" method for setting a single-bit.
199 unsafe { w.clrp().bits(1 << self.pin.pin()) });
200 }
201
202 /// Set level
203 pub fn set_level(&mut self, level: Level) {
204 match level {
205 Level::High => self.set_high(),
206 Level::Low => self.set_low(),
207 }
208 }
209
210 /// Is the output level high?
211 #[must_use]
212 pub fn is_set_high(&self) -> bool {
213 !self.is_set_low()
214 }
215
216 /// Is the output level low?
217 #[must_use]
218 pub fn is_set_low(&self) -> bool {
219 (self.pin.block().set(self.pin.port()).read().setp().bits() & (1 << self.pin.pin())) == 0
220 }
221
222 /// Toggle
223 pub fn toggle(&mut self) {
224 self.pin.block().not(self.pin.port()).write(|w|
225 // SAFETY: Writing a 0 to bits in this register has no effect,
226 // however PAC has it marked unsafe due to using the bits() method.
227 // There is not currently a "safe" method for setting a single-bit.
228 unsafe { w.notp().bits(1 << self.pin.pin()) });
229 }
230}
231
232impl<S: Sense> Drop for Flex<'_, S> {
233 #[inline]
234 fn drop(&mut self) {
235 critical_section::with(|_| {
236 self.pin.reset();
237 });
238 }
239}
240
241impl<'d> Flex<'d, SenseEnabled> {
242 /// New flex pin.
243 pub fn new_with_sense(pin: Peri<'d, impl GpioPin>) -> Self {
244 pin.set_function(Function::F0)
245 .disable_analog_multiplex()
246 .enable_input_buffer();
247
248 Self {
249 pin: pin.into(),
250 _sense_mode: PhantomData::<SenseEnabled>,
251 }
252 }
253
254 /// Converts pin to input pin
255 pub fn set_as_input(&mut self, pull: Pull, inverter: Inverter) {
256 self.pin.set_pull(pull).set_input_inverter(inverter);
257
258 self.pin.block().dirclr(self.pin.port()).write(|w|
259 // SAFETY: Writing a 0 to bits in this register has no effect,
260 // however PAC has it marked unsafe due to using the bits() method.
261 // There is not currently a "safe" method for setting a single-bit.
262 unsafe { w.dirclrp().bits(1 << self.pin.pin()) });
263 }
264
265 /// Converts pin to special function pin
266 /// # Safety
267 /// Unsafe to require justifying change from default to a special function
268 ///
269 pub unsafe fn set_as_special_function(&mut self, func: Function) {
270 self.pin.set_function(func);
271 }
272
273 /// Is high?
274 #[must_use]
275 pub fn is_high(&self) -> bool {
276 !self.is_low()
277 }
278
279 /// Is low?
280 #[must_use]
281 pub fn is_low(&self) -> bool {
282 self.pin.block().b(self.pin.port()).b_(self.pin.pin()).read() == 0
283 }
284
285 /// Current level
286 #[must_use]
287 pub fn get_level(&self) -> Level {
288 self.is_high().into()
289 }
290
291 /// Wait until the pin is high. If it is already high, return immediately.
292 #[inline]
293 pub async fn wait_for_high(&mut self) {
294 InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::High).await;
295 }
296
297 /// Wait until the pin is low. If it is already low, return immediately.
298 #[inline]
299 pub async fn wait_for_low(&mut self) {
300 InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::Low).await;
301 }
302
303 /// Wait for the pin to undergo a transition from low to high.
304 #[inline]
305 pub async fn wait_for_rising_edge(&mut self) {
306 InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await;
307 }
308
309 /// Wait for the pin to undergo a transition from high to low.
310 #[inline]
311 pub async fn wait_for_falling_edge(&mut self) {
312 InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await;
313 }
314
315 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
316 #[inline]
317 pub async fn wait_for_any_edge(&mut self) {
318 if self.is_high() {
319 InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await;
320 } else {
321 InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await;
322 }
323 }
324
325 /// Return a new Flex pin instance with level sensing disabled.
326 ///
327 /// Consumes less power than a flex pin with sensing enabled.
328 #[must_use]
329 pub fn disable_sensing(self) -> Flex<'d, SenseDisabled> {
330 // Cloning the pin is ok since we consume self immediately
331 let new_pin = unsafe { self.pin.clone_unchecked() };
332 drop(self);
333 Flex::<SenseDisabled>::new(new_pin)
334 }
335}
336
337impl<'d> Flex<'d, SenseDisabled> {
338 /// New flex pin.
339 pub fn new(pin: Peri<'d, impl GpioPin>) -> Self {
340 pin.set_function(Function::F0)
341 .disable_analog_multiplex()
342 .disable_input_buffer();
343
344 Self {
345 pin: pin.into(),
346 _sense_mode: PhantomData::<SenseDisabled>,
347 }
348 }
349
350 /// Return a new Flex pin instance with level sensing enabled.
351 #[must_use]
352 pub fn enable_sensing(self) -> Flex<'d, SenseEnabled> {
353 // Cloning the pin is ok since we consume self immediately
354 let new_pin = unsafe { self.pin.clone_unchecked() };
355 drop(self);
356 Flex::new_with_sense(new_pin)
357 }
358}
359
360/// Input pin
361pub struct Input<'d> {
362 // When Input is dropped, Flex's drop() will make sure the pin is reset to its default state.
363 pin: Flex<'d, SenseEnabled>,
364}
365
366impl<'d> Input<'d> {
367 /// New input pin
368 pub fn new(pin: Peri<'d, impl GpioPin>, pull: Pull, inverter: Inverter) -> Self {
369 let mut pin = Flex::new_with_sense(pin);
370 pin.set_as_input(pull, inverter);
371 Self { pin }
372 }
373
374 /// Is high?
375 #[must_use]
376 pub fn is_high(&self) -> bool {
377 self.pin.is_high()
378 }
379
380 /// Is low?
381 #[must_use]
382 pub fn is_low(&self) -> bool {
383 self.pin.is_low()
384 }
385
386 /// Input level
387 #[must_use]
388 pub fn get_level(&self) -> Level {
389 self.pin.get_level()
390 }
391
392 /// Wait until the pin is high. If it is already high, return immediately.
393 #[inline]
394 pub async fn wait_for_high(&mut self) {
395 self.pin.wait_for_high().await;
396 }
397
398 /// Wait until the pin is low. If it is already low, return immediately.
399 #[inline]
400 pub async fn wait_for_low(&mut self) {
401 self.pin.wait_for_low().await;
402 }
403
404 /// Wait for the pin to undergo a transition from low to high.
405 #[inline]
406 pub async fn wait_for_rising_edge(&mut self) {
407 self.pin.wait_for_rising_edge().await;
408 }
409
410 /// Wait for the pin to undergo a transition from high to low.
411 #[inline]
412 pub async fn wait_for_falling_edge(&mut self) {
413 self.pin.wait_for_falling_edge().await;
414 }
415
416 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
417 #[inline]
418 pub async fn wait_for_any_edge(&mut self) {
419 self.pin.wait_for_any_edge().await;
420 }
421}
422
423#[must_use = "futures do nothing unless you `.await` or poll them"]
424struct InputFuture<'d> {
425 pin: Peri<'d, AnyPin>,
426}
427
428impl<'d> InputFuture<'d> {
429 fn new(pin: Peri<'d, impl GpioPin>, int_type: InterruptType, level: Level) -> Self {
430 critical_section::with(|_| {
431 // Clear any existing pending interrupt on this pin
432 pin.block()
433 .intstata(pin.port())
434 .write(|w| unsafe { w.status().bits(1 << pin.pin()) });
435
436 /* Pin interrupt configuration */
437 pin.block().intedg(pin.port()).modify(|r, w| match int_type {
438 InterruptType::Edge => unsafe { w.bits(r.bits() | (1 << pin.pin())) },
439 InterruptType::Level => unsafe { w.bits(r.bits() & !(1 << pin.pin())) },
440 });
441
442 pin.block().intpol(pin.port()).modify(|r, w| match level {
443 Level::High => unsafe { w.bits(r.bits() & !(1 << pin.pin())) },
444 Level::Low => unsafe { w.bits(r.bits() | (1 << pin.pin())) },
445 });
446
447 // Enable pin interrupt on GPIO INT A
448 pin.block()
449 .intena(pin.port())
450 .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() | (1 << pin.pin())) });
451 });
452
453 Self { pin: pin.into() }
454 }
455}
456
457impl Future for InputFuture<'_> {
458 type Output = ();
459
460 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
461 // We need to register/re-register the waker for each poll because any
462 // calls to wake will deregister the waker.
463 if self.pin.port() >= GPIO_WAKERS.len() {
464 panic!("Invalid GPIO port index {}", self.pin.port());
465 }
466
467 let port_waker = GPIO_WAKERS[self.pin.port()];
468 if port_waker.is_none() {
469 panic!("Waker not present for GPIO port {}", self.pin.port());
470 }
471
472 let waker = port_waker.unwrap().get_waker(self.pin.pin());
473 if waker.is_none() {
474 panic!(
475 "Waker not present for GPIO pin {}, port {}",
476 self.pin.pin(),
477 self.pin.port()
478 );
479 }
480 waker.unwrap().register(cx.waker());
481
482 // Double check that the pin interrut has been disabled by IRQ handler
483 if self.pin.block().intena(self.pin.port()).read().bits() & (1 << self.pin.pin()) == 0 {
484 Poll::Ready(())
485 } else {
486 Poll::Pending
487 }
488 }
489}
490
491/// Output pin
492/// Cannot be set as an input and cannot read its own pin state!
493/// Consider using a Flex pin if you want that functionality, at the cost of higher power consumption.
494pub struct Output<'d> {
495 // When Output is dropped, Flex's drop() will make sure the pin is reset to its default state.
496 pin: Flex<'d, SenseDisabled>,
497}
498
499impl<'d> Output<'d> {
500 /// New output pin
501 pub fn new(
502 pin: Peri<'d, impl GpioPin>,
503 initial_output: Level,
504 mode: DriveMode,
505 strength: DriveStrength,
506 slew_rate: SlewRate,
507 ) -> Self {
508 let mut pin = Flex::new(pin);
509 pin.set_level(initial_output);
510 pin.set_as_output(mode, strength, slew_rate);
511
512 Self { pin }
513 }
514
515 /// Set high
516 pub fn set_high(&mut self) {
517 self.pin.set_high();
518 }
519
520 /// Set low
521 pub fn set_low(&mut self) {
522 self.pin.set_low();
523 }
524
525 /// Toggle
526 pub fn toggle(&mut self) {
527 self.pin.toggle();
528 }
529
530 /// Set level
531 pub fn set_level(&mut self, level: Level) {
532 self.pin.set_level(level);
533 }
534
535 /// Is set high?
536 #[must_use]
537 pub fn is_set_high(&self) -> bool {
538 self.pin.is_set_high()
539 }
540
541 /// Is set low?
542 #[must_use]
543 pub fn is_set_low(&self) -> bool {
544 self.pin.is_set_low()
545 }
546}
547
548trait SealedPin: IopctlPin {
549 fn pin_port(&self) -> usize;
550
551 fn port(&self) -> usize {
552 self.pin_port() / 32
553 }
554
555 fn pin(&self) -> usize {
556 self.pin_port() % 32
557 }
558
559 fn block(&self) -> crate::pac::Gpio {
560 // SAFETY: Assuming GPIO pin specific registers are only accessed through this HAL,
561 // this is safe because the HAL ensures ownership or exclusive mutable references
562 // to pins.
563 unsafe { crate::pac::Gpio::steal() }
564 }
565}
566
567/// GPIO pin trait.
568#[allow(private_bounds)]
569pub trait GpioPin: SealedPin + Sized + PeripheralType + Into<AnyPin> + 'static {
570 /// Type-erase the pin.
571 fn degrade(self) -> AnyPin {
572 // SAFETY: This is only called within the GpioPin trait, which is only
573 // implemented within this module on valid pin peripherals and thus
574 // has been verified to be correct.
575 unsafe { AnyPin::steal(self.port() as u8, self.pin() as u8) }
576 }
577}
578
579impl SealedPin for AnyPin {
580 fn pin_port(&self) -> usize {
581 self.pin_port()
582 }
583}
584impl GpioPin for AnyPin {}
585
586macro_rules! impl_pin {
587 ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => {
588 impl SealedPin for crate::peripherals::$pin_periph {
589 fn pin_port(&self) -> usize {
590 $pin_port * 32 + $pin_no
591 }
592 }
593 impl GpioPin for crate::peripherals::$pin_periph {}
594 impl From<crate::peripherals::$pin_periph> for AnyPin {
595 fn from(value: crate::peripherals::$pin_periph) -> Self {
596 value.degrade()
597 }
598 }
599 };
600}
601
602/// Container for pin wakers
603struct PortWaker {
604 offset: usize,
605 wakers: &'static [AtomicWaker],
606}
607
608impl PortWaker {
609 fn get_waker(&self, pin: usize) -> Option<&AtomicWaker> {
610 self.wakers.get(pin - self.offset)
611 }
612}
613
614macro_rules! define_port_waker {
615 ($name:ident, $start:expr, $end:expr) => {
616 mod $name {
617 static PIN_WAKERS: [super::AtomicWaker; $end - $start + 1] =
618 [const { super::AtomicWaker::new() }; $end - $start + 1];
619 pub static WAKER: super::PortWaker = super::PortWaker {
620 offset: $start,
621 wakers: &PIN_WAKERS,
622 };
623 }
624 };
625}
626
627// GPIO port 0
628define_port_waker!(port0_waker, 0, 31);
629impl_pin!(PIO0_0, 0, 0);
630impl_pin!(PIO0_1, 0, 1);
631impl_pin!(PIO0_2, 0, 2);
632impl_pin!(PIO0_3, 0, 3);
633impl_pin!(PIO0_4, 0, 4);
634impl_pin!(PIO0_5, 0, 5);
635impl_pin!(PIO0_6, 0, 6);
636impl_pin!(PIO0_7, 0, 7);
637impl_pin!(PIO0_8, 0, 8);
638impl_pin!(PIO0_9, 0, 9);
639impl_pin!(PIO0_10, 0, 10);
640impl_pin!(PIO0_11, 0, 11);
641impl_pin!(PIO0_12, 0, 12);
642impl_pin!(PIO0_13, 0, 13);
643impl_pin!(PIO0_14, 0, 14);
644impl_pin!(PIO0_15, 0, 15);
645impl_pin!(PIO0_16, 0, 16);
646impl_pin!(PIO0_17, 0, 17);
647impl_pin!(PIO0_18, 0, 18);
648impl_pin!(PIO0_19, 0, 19);
649impl_pin!(PIO0_20, 0, 20);
650impl_pin!(PIO0_21, 0, 21);
651impl_pin!(PIO0_22, 0, 22);
652impl_pin!(PIO0_23, 0, 23);
653impl_pin!(PIO0_24, 0, 24);
654impl_pin!(PIO0_25, 0, 25);
655impl_pin!(PIO0_26, 0, 26);
656impl_pin!(PIO0_27, 0, 27);
657impl_pin!(PIO0_28, 0, 28);
658impl_pin!(PIO0_29, 0, 29);
659impl_pin!(PIO0_30, 0, 30);
660impl_pin!(PIO0_31, 0, 31);
661
662// GPIO port 1
663define_port_waker!(port1_waker, 0, 31);
664impl_pin!(PIO1_0, 1, 0);
665impl_pin!(PIO1_1, 1, 1);
666impl_pin!(PIO1_2, 1, 2);
667impl_pin!(PIO1_3, 1, 3);
668impl_pin!(PIO1_4, 1, 4);
669impl_pin!(PIO1_5, 1, 5);
670impl_pin!(PIO1_6, 1, 6);
671impl_pin!(PIO1_7, 1, 7);
672impl_pin!(PIO1_8, 1, 8);
673impl_pin!(PIO1_9, 1, 9);
674impl_pin!(PIO1_10, 1, 10);
675impl_pin!(PIO1_11, 1, 11);
676impl_pin!(PIO1_12, 1, 12);
677impl_pin!(PIO1_13, 1, 13);
678impl_pin!(PIO1_14, 1, 14);
679impl_pin!(PIO1_15, 1, 15);
680impl_pin!(PIO1_16, 1, 16);
681impl_pin!(PIO1_17, 1, 17);
682impl_pin!(PIO1_18, 1, 18);
683impl_pin!(PIO1_19, 1, 19);
684impl_pin!(PIO1_20, 1, 20);
685impl_pin!(PIO1_21, 1, 21);
686impl_pin!(PIO1_22, 1, 22);
687impl_pin!(PIO1_23, 1, 23);
688impl_pin!(PIO1_24, 1, 24);
689impl_pin!(PIO1_25, 1, 25);
690impl_pin!(PIO1_26, 1, 26);
691impl_pin!(PIO1_27, 1, 27);
692impl_pin!(PIO1_28, 1, 28);
693impl_pin!(PIO1_29, 1, 29);
694impl_pin!(PIO1_30, 1, 30);
695impl_pin!(PIO1_31, 1, 31);
696
697// GPIO port 2
698define_port_waker!(port2_waker, 0, 31);
699impl_pin!(PIO2_0, 2, 0);
700impl_pin!(PIO2_1, 2, 1);
701impl_pin!(PIO2_2, 2, 2);
702impl_pin!(PIO2_3, 2, 3);
703impl_pin!(PIO2_4, 2, 4);
704impl_pin!(PIO2_5, 2, 5);
705impl_pin!(PIO2_6, 2, 6);
706impl_pin!(PIO2_7, 2, 7);
707impl_pin!(PIO2_8, 2, 8);
708impl_pin!(PIO2_9, 2, 9);
709impl_pin!(PIO2_10, 2, 10);
710impl_pin!(PIO2_11, 2, 11);
711impl_pin!(PIO2_12, 2, 12);
712impl_pin!(PIO2_13, 2, 13);
713impl_pin!(PIO2_14, 2, 14);
714impl_pin!(PIO2_15, 2, 15);
715impl_pin!(PIO2_16, 2, 16);
716impl_pin!(PIO2_17, 2, 17);
717impl_pin!(PIO2_18, 2, 18);
718impl_pin!(PIO2_19, 2, 19);
719impl_pin!(PIO2_20, 2, 20);
720impl_pin!(PIO2_21, 2, 21);
721impl_pin!(PIO2_22, 2, 22);
722impl_pin!(PIO2_23, 2, 23);
723impl_pin!(PIO2_24, 2, 24);
724impl_pin!(PIO2_25, 2, 25);
725impl_pin!(PIO2_26, 2, 26);
726impl_pin!(PIO2_27, 2, 27);
727impl_pin!(PIO2_28, 2, 28);
728impl_pin!(PIO2_29, 2, 29);
729impl_pin!(PIO2_30, 2, 30);
730impl_pin!(PIO2_31, 2, 31);
731
732// GPIO port 3
733define_port_waker!(port3_waker, 0, 31);
734impl_pin!(PIO3_0, 3, 0);
735impl_pin!(PIO3_1, 3, 1);
736impl_pin!(PIO3_2, 3, 2);
737impl_pin!(PIO3_3, 3, 3);
738impl_pin!(PIO3_4, 3, 4);
739impl_pin!(PIO3_5, 3, 5);
740impl_pin!(PIO3_6, 3, 6);
741impl_pin!(PIO3_7, 3, 7);
742impl_pin!(PIO3_8, 3, 8);
743impl_pin!(PIO3_9, 3, 9);
744impl_pin!(PIO3_10, 3, 10);
745impl_pin!(PIO3_11, 3, 11);
746impl_pin!(PIO3_12, 3, 12);
747impl_pin!(PIO3_13, 3, 13);
748impl_pin!(PIO3_14, 3, 14);
749impl_pin!(PIO3_15, 3, 15);
750impl_pin!(PIO3_16, 3, 16);
751impl_pin!(PIO3_17, 3, 17);
752impl_pin!(PIO3_18, 3, 18);
753impl_pin!(PIO3_19, 3, 19);
754impl_pin!(PIO3_20, 3, 20);
755impl_pin!(PIO3_21, 3, 21);
756impl_pin!(PIO3_22, 3, 22);
757impl_pin!(PIO3_23, 3, 23);
758impl_pin!(PIO3_24, 3, 24);
759impl_pin!(PIO3_25, 3, 25);
760impl_pin!(PIO3_26, 3, 26);
761impl_pin!(PIO3_27, 3, 27);
762impl_pin!(PIO3_28, 3, 28);
763impl_pin!(PIO3_29, 3, 29);
764impl_pin!(PIO3_30, 3, 30);
765impl_pin!(PIO3_31, 3, 31);
766
767// GPIO port 4
768define_port_waker!(port4_waker, 0, 10);
769impl_pin!(PIO4_0, 4, 0);
770impl_pin!(PIO4_1, 4, 1);
771impl_pin!(PIO4_2, 4, 2);
772impl_pin!(PIO4_3, 4, 3);
773impl_pin!(PIO4_4, 4, 4);
774impl_pin!(PIO4_5, 4, 5);
775impl_pin!(PIO4_6, 4, 6);
776impl_pin!(PIO4_7, 4, 7);
777impl_pin!(PIO4_8, 4, 8);
778impl_pin!(PIO4_9, 4, 9);
779impl_pin!(PIO4_10, 4, 10);
780
781// GPIO port 7
782define_port_waker!(port7_waker, 24, 31);
783impl_pin!(PIO7_24, 7, 24);
784impl_pin!(PIO7_25, 7, 25);
785impl_pin!(PIO7_26, 7, 26);
786impl_pin!(PIO7_27, 7, 27);
787impl_pin!(PIO7_28, 7, 28);
788impl_pin!(PIO7_29, 7, 29);
789impl_pin!(PIO7_30, 7, 30);
790impl_pin!(PIO7_31, 7, 31);
791
792static GPIO_WAKERS: [Option<&PortWaker>; PORT_COUNT] = [
793 Some(&port0_waker::WAKER),
794 Some(&port1_waker::WAKER),
795 Some(&port2_waker::WAKER),
796 Some(&port3_waker::WAKER),
797 Some(&port4_waker::WAKER),
798 None,
799 None,
800 Some(&port7_waker::WAKER),
801];
802
803impl embedded_hal_02::digital::v2::InputPin for Flex<'_, SenseEnabled> {
804 type Error = Infallible;
805
806 #[inline]
807 fn is_high(&self) -> Result<bool, Self::Error> {
808 Ok(self.is_high())
809 }
810
811 #[inline]
812 fn is_low(&self) -> Result<bool, Self::Error> {
813 Ok(self.is_low())
814 }
815}
816
817impl<S: Sense> embedded_hal_02::digital::v2::OutputPin for Flex<'_, S> {
818 type Error = Infallible;
819
820 #[inline]
821 fn set_high(&mut self) -> Result<(), Self::Error> {
822 self.set_high();
823 Ok(())
824 }
825
826 #[inline]
827 fn set_low(&mut self) -> Result<(), Self::Error> {
828 self.set_low();
829 Ok(())
830 }
831}
832
833impl embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'_, SenseEnabled> {
834 #[inline]
835 fn is_set_high(&self) -> Result<bool, Self::Error> {
836 Ok(self.is_set_high())
837 }
838
839 #[inline]
840 fn is_set_low(&self) -> Result<bool, Self::Error> {
841 Ok(self.is_set_low())
842 }
843}
844
845impl<S: Sense> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'_, S> {
846 type Error = Infallible;
847
848 #[inline]
849 fn toggle(&mut self) -> Result<(), Self::Error> {
850 self.toggle();
851 Ok(())
852 }
853}
854
855impl embedded_hal_02::digital::v2::InputPin for Input<'_> {
856 type Error = Infallible;
857
858 #[inline]
859 fn is_high(&self) -> Result<bool, Self::Error> {
860 Ok(self.is_high())
861 }
862
863 #[inline]
864 fn is_low(&self) -> Result<bool, Self::Error> {
865 Ok(self.is_low())
866 }
867}
868
869impl embedded_hal_02::digital::v2::OutputPin for Output<'_> {
870 type Error = Infallible;
871
872 #[inline]
873 fn set_high(&mut self) -> Result<(), Self::Error> {
874 self.set_high();
875 Ok(())
876 }
877
878 #[inline]
879 fn set_low(&mut self) -> Result<(), Self::Error> {
880 self.set_low();
881 Ok(())
882 }
883}
884
885impl embedded_hal_02::digital::v2::StatefulOutputPin for Output<'_> {
886 #[inline]
887 fn is_set_high(&self) -> Result<bool, Self::Error> {
888 Ok(self.is_set_high())
889 }
890
891 #[inline]
892 fn is_set_low(&self) -> Result<bool, Self::Error> {
893 Ok(self.is_set_low())
894 }
895}
896
897impl embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'_> {
898 type Error = Infallible;
899
900 #[inline]
901 fn toggle(&mut self) -> Result<(), Self::Error> {
902 self.toggle();
903 Ok(())
904 }
905}
906
907impl<S: Sense> embedded_hal_1::digital::ErrorType for Flex<'_, S> {
908 type Error = Infallible;
909}
910
911impl embedded_hal_1::digital::InputPin for Flex<'_, SenseEnabled> {
912 #[inline]
913 fn is_high(&mut self) -> Result<bool, Self::Error> {
914 // Dereference of self is used here and a few other places to
915 // access the correct method (since different types/traits
916 // share method names)
917 Ok((*self).is_high())
918 }
919
920 #[inline]
921 fn is_low(&mut self) -> Result<bool, Self::Error> {
922 Ok((*self).is_low())
923 }
924}
925
926impl<S: Sense> embedded_hal_1::digital::OutputPin for Flex<'_, S> {
927 #[inline]
928 fn set_high(&mut self) -> Result<(), Self::Error> {
929 self.set_high();
930 Ok(())
931 }
932
933 #[inline]
934 fn set_low(&mut self) -> Result<(), Self::Error> {
935 self.set_low();
936 Ok(())
937 }
938}
939
940impl embedded_hal_1::digital::StatefulOutputPin for Flex<'_, SenseEnabled> {
941 #[inline]
942 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
943 Ok((*self).is_set_high())
944 }
945
946 #[inline]
947 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
948 Ok((*self).is_set_low())
949 }
950}
951
952impl<'d> embedded_hal_async::digital::Wait for Flex<'d, SenseEnabled> {
953 #[inline]
954 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
955 self.wait_for_high().await;
956 Ok(())
957 }
958
959 #[inline]
960 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
961 self.wait_for_low().await;
962 Ok(())
963 }
964
965 #[inline]
966 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
967 self.wait_for_rising_edge().await;
968 Ok(())
969 }
970
971 #[inline]
972 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
973 self.wait_for_falling_edge().await;
974 Ok(())
975 }
976
977 #[inline]
978 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
979 self.wait_for_any_edge().await;
980 Ok(())
981 }
982}
983
984impl embedded_hal_1::digital::ErrorType for Input<'_> {
985 type Error = Infallible;
986}
987
988impl embedded_hal_1::digital::InputPin for Input<'_> {
989 #[inline]
990 fn is_high(&mut self) -> Result<bool, Self::Error> {
991 Ok((*self).is_high())
992 }
993
994 #[inline]
995 fn is_low(&mut self) -> Result<bool, Self::Error> {
996 Ok((*self).is_low())
997 }
998}
999
1000impl<'d> embedded_hal_async::digital::Wait for Input<'d> {
1001 #[inline]
1002 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1003 self.wait_for_high().await;
1004 Ok(())
1005 }
1006
1007 #[inline]
1008 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
1009 self.wait_for_low().await;
1010 Ok(())
1011 }
1012
1013 #[inline]
1014 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
1015 self.wait_for_rising_edge().await;
1016 Ok(())
1017 }
1018
1019 #[inline]
1020 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
1021 self.wait_for_falling_edge().await;
1022 Ok(())
1023 }
1024
1025 #[inline]
1026 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
1027 self.wait_for_any_edge().await;
1028 Ok(())
1029 }
1030}
1031
1032impl embedded_hal_1::digital::ErrorType for Output<'_> {
1033 type Error = Infallible;
1034}
1035
1036impl embedded_hal_1::digital::OutputPin for Output<'_> {
1037 #[inline]
1038 fn set_high(&mut self) -> Result<(), Self::Error> {
1039 self.set_high();
1040 Ok(())
1041 }
1042
1043 #[inline]
1044 fn set_low(&mut self) -> Result<(), Self::Error> {
1045 self.set_low();
1046 Ok(())
1047 }
1048}
1049
1050impl embedded_hal_1::digital::StatefulOutputPin for Output<'_> {
1051 #[inline]
1052 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1053 Ok((*self).is_set_high())
1054 }
1055
1056 #[inline]
1057 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1058 Ok((*self).is_set_low())
1059 }
1060}
diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs
new file mode 100644
index 000000000..a3b8b14d6
--- /dev/null
+++ b/embassy-imxrt/src/iopctl.rs
@@ -0,0 +1,717 @@
1//! IO Pad Controller (IOPCTL)
2//!
3//! Also known as IO Pin Configuration (IOCON)
4
5use crate::pac::{iopctl, Iopctl};
6
7// A generic pin of any type.
8//
9// The actual pin type used here is arbitrary,
10// as all PioM_N types provide the same methods.
11//
12// Merely need some pin type to cast a raw pointer
13// to in order to access the provided methods.
14#[allow(non_camel_case_types)]
15type PioM_N = iopctl::Pio0_0;
16
17/// Pin function number.
18#[derive(Debug, Copy, Clone, Eq, PartialEq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Function {
21 /// Function 0
22 F0,
23 /// Function 1
24 F1,
25 /// Function 2
26 F2,
27 /// Function 3
28 F3,
29 /// Function 4
30 F4,
31 /// Function 5
32 F5,
33 /// Function 6
34 F6,
35 /// Function 7
36 F7,
37 /// Function 8
38 F8,
39}
40
41/// Internal pull-up/down resistors on a pin.
42#[derive(Debug, Copy, Clone, Eq, PartialEq)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44pub enum Pull {
45 /// No pull-up or pull-down resistor selected
46 None,
47 /// Pull-up resistor
48 Up,
49 /// Pull-down resistor
50 Down,
51}
52
53/// Pin slew rate.
54#[derive(Debug, Copy, Clone, Eq, PartialEq)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56pub enum SlewRate {
57 /// Standard slew rate
58 Standard,
59 /// Slow slew rate
60 Slow,
61}
62
63/// Output drive strength of a pin.
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66pub enum DriveStrength {
67 /// Normal
68 Normal,
69 /// Full
70 Full,
71}
72
73/// Output drive mode of a pin.
74#[derive(Debug, Copy, Clone, Eq, PartialEq)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76pub enum DriveMode {
77 /// Push-Pull
78 PushPull,
79 /// Pseudo Open-Drain
80 OpenDrain,
81}
82
83/// Input inverter of a pin.
84#[derive(Debug, Copy, Clone, Eq, PartialEq)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub enum Inverter {
87 /// No inverter
88 Disabled,
89 /// Enable input inverter on the input port. A low signal will be
90 /// seen as a high signal by the pin.
91 Enabled,
92}
93
94trait SealedPin {}
95trait ToAnyPin: SealedPin {
96 #[inline]
97 fn to_raw(port: u8, pin: u8) -> AnyPin {
98 // SAFETY: This is safe since this is only called from within the module,
99 // where the port and pin numbers have been verified to be correct.
100 unsafe { AnyPin::steal(port, pin) }
101 }
102}
103
104trait ToFC15Pin: SealedPin {
105 #[inline]
106 fn to_raw(pin: u8) -> FC15Pin {
107 // SAFETY: This is safe since this is only called from within the module,
108 // where the port and pin numbers have been verified to be correct.
109 unsafe { FC15Pin::steal(pin) }
110 }
111}
112
113/// A pin that can be configured via iopctl.
114#[allow(private_bounds)]
115pub trait IopctlPin: SealedPin {
116 /// Sets the function number of a pin.
117 ///
118 /// This number corresponds to a specific function that the pin supports.
119 ///
120 /// Typically, function 0 corresponds to GPIO while other numbers correspond to a special function.
121 ///
122 /// See Section 7.5.3 in reference manual for list of pins and their supported functions.
123 fn set_function(&self, function: Function) -> &Self;
124
125 /// Enables either a pull-up or pull-down resistor on a pin.
126 ///
127 /// Setting this to [`Pull::None`] will disable the resistor.
128 fn set_pull(&self, pull: Pull) -> &Self;
129
130 /// Enables the input buffer of a pin.
131 ///
132 /// This must be enabled for any pin acting as an input,
133 /// and some peripheral pins acting as output may need this enabled as well.
134 ///
135 /// If there is any doubt, it is best to enable the input buffer.
136 ///
137 /// See Section 7.4.2.3 of reference manual.
138 fn enable_input_buffer(&self) -> &Self;
139
140 /// Disables the input buffer of a pin.
141 fn disable_input_buffer(&self) -> &Self;
142
143 /// Sets the slew rate of a pin.
144 ///
145 /// This controls the speed at which a pin can toggle,
146 /// which is voltage and load dependent.
147 fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self;
148
149 /// Sets the output drive strength of a pin.
150 ///
151 /// A drive strength of [`DriveStrength::Full`] has twice the
152 /// high and low drive capability of the [`DriveStrength::Normal`] setting.
153 fn set_drive_strength(&self, strength: DriveStrength) -> &Self;
154
155 /// Enables the analog multiplexer of a pin.
156 ///
157 /// This must be called to allow analog functionalities of a pin.
158 ///
159 /// To protect the analog input, [`IopctlPin::set_function`] should be
160 /// called with [`Function::F0`] to disable digital functions.
161 ///
162 /// Additionally, [`IopctlPin::disable_input_buffer`] and [`IopctlPin::set_pull`]
163 /// with [`Pull::None`] should be called.
164 fn enable_analog_multiplex(&self) -> &Self;
165
166 /// Disables the analog multiplexer of a pin.
167 fn disable_analog_multiplex(&self) -> &Self;
168
169 /// Sets the ouput drive mode of a pin.
170 ///
171 /// A pin configured as [`DriveMode::OpenDrain`] actually operates in
172 /// a "pseudo" open-drain mode which is somewhat different than true open-drain.
173 ///
174 /// See Section 7.4.2.7 of reference manual.
175 fn set_drive_mode(&self, mode: DriveMode) -> &Self;
176
177 /// Sets the input inverter of an input pin.
178 ///
179 /// Setting this to [`Inverter::Enabled`] will invert
180 /// the input signal.
181 fn set_input_inverter(&self, inverter: Inverter) -> &Self;
182
183 /// Returns a pin to its reset state.
184 fn reset(&self) -> &Self;
185}
186
187/// Represents a pin peripheral created at run-time from given port and pin numbers.
188pub struct AnyPin {
189 pin_port: u8,
190 reg: &'static PioM_N,
191}
192
193impl AnyPin {
194 /// Creates a pin from raw port and pin numbers which can then be configured.
195 ///
196 /// This should ONLY be called when there is no other choice
197 /// (e.g. from a type-erased GPIO pin).
198 ///
199 /// Otherwise, pin peripherals should be configured directly.
200 ///
201 /// # Safety
202 ///
203 /// The caller MUST ensure valid port and pin numbers are provided,
204 /// and that multiple instances of [`AnyPin`] with the same port
205 /// and pin combination are not being used simultaneously.
206 ///
207 /// Failure to uphold these requirements will result in undefined behavior.
208 ///
209 /// See Table 297 in reference manual for a list of valid
210 /// pin and port number combinations.
211 #[must_use]
212 pub unsafe fn steal(port: u8, pin: u8) -> Self {
213 // Calculates the offset from the beginning of the IOPCTL register block
214 // address to the register address representing the pin.
215 //
216 // See Table 297 in reference manual for how this offset is calculated.
217 let offset = ((port as usize) << 7) + ((pin as usize) << 2);
218
219 // SAFETY: This is safe assuming the caller of this function satisfies the safety requirements above.
220 let reg = unsafe { &*Iopctl::ptr().byte_offset(offset as isize).cast() };
221 Self {
222 pin_port: port * 32 + pin,
223 reg,
224 }
225 }
226
227 /// Returns the pin's port and pin combination.
228 #[must_use]
229 pub fn pin_port(&self) -> usize {
230 self.pin_port as usize
231 }
232}
233
234/// Represents a FC15 pin peripheral created at run-time from given pin number.
235pub struct FC15Pin {
236 reg: &'static PioM_N,
237}
238
239impl FC15Pin {
240 /// Creates an FC15 pin from raw pin number which can then be configured.
241 ///
242 /// This should ONLY be called when there is no other choice
243 /// (e.g. from a type-erased GPIO pin).
244 ///
245 /// Otherwise, pin peripherals should be configured directly.
246 ///
247 /// # Safety
248 ///
249 /// The caller MUST ensure valid port and pin numbers are provided,
250 /// and that multiple instances of [`AnyPin`] with the same port
251 /// and pin combination are not being used simultaneously.
252 ///
253 /// Failure to uphold these requirements will result in undefined behavior.
254 ///
255 /// See Table 297 in reference manual for a list of valid
256 /// pin and port number combinations.
257 #[must_use]
258 pub unsafe fn steal(pin: u8) -> Self {
259 // Table 297: FC15_I2C_SCL offset = 0x400, FC15_I2C_SCL offset = 0x404
260 let iopctl = unsafe { crate::pac::Iopctl::steal() };
261
262 let reg = if pin == 0 {
263 &*iopctl.fc15_i2c_scl().as_ptr().cast()
264 } else {
265 &*iopctl.fc15_i2c_sda().as_ptr().cast()
266 };
267
268 Self { reg }
269 }
270}
271
272// This allows AnyPin/FC15Pin to be used in HAL constructors that require types
273// which impl Peripheral. Used primarily by GPIO HAL to convert type-erased
274// GPIO pins back into an Output or Input pin specifically.
275embassy_hal_internal::impl_peripheral!(AnyPin);
276
277impl SealedPin for AnyPin {}
278
279embassy_hal_internal::impl_peripheral!(FC15Pin);
280
281impl SealedPin for FC15Pin {}
282
283macro_rules! impl_iopctlpin {
284 ($pintype:ident) => {
285 impl IopctlPin for $pintype {
286 fn set_function(&self, function: Function) -> &Self {
287 critical_section::with(|_| match function {
288 Function::F0 => {
289 self.reg.modify(|_, w| w.fsel().function_0());
290 }
291 Function::F1 => {
292 self.reg.modify(|_, w| w.fsel().function_1());
293 }
294 Function::F2 => {
295 self.reg.modify(|_, w| w.fsel().function_2());
296 }
297 Function::F3 => {
298 self.reg.modify(|_, w| w.fsel().function_3());
299 }
300 Function::F4 => {
301 self.reg.modify(|_, w| w.fsel().function_4());
302 }
303 Function::F5 => {
304 self.reg.modify(|_, w| w.fsel().function_5());
305 }
306 Function::F6 => {
307 self.reg.modify(|_, w| w.fsel().function_6());
308 }
309 Function::F7 => {
310 self.reg.modify(|_, w| w.fsel().function_7());
311 }
312 Function::F8 => {
313 self.reg.modify(|_, w| w.fsel().function_8());
314 }
315 });
316 self
317 }
318
319 fn set_pull(&self, pull: Pull) -> &Self {
320 critical_section::with(|_| {
321 match pull {
322 Pull::None => {
323 self.reg.modify(|_, w| w.pupdena().disabled());
324 }
325 Pull::Up => {
326 self.reg.modify(|_, w| w.pupdena().enabled().pupdsel().pull_up());
327 }
328 Pull::Down => {
329 self.reg
330 .modify(|_, w| w.pupdena().enabled().pupdsel().pull_down());
331 }
332 }
333 self
334 })
335 }
336
337 fn enable_input_buffer(&self) -> &Self {
338 critical_section::with(|_| self.reg.modify(|_, w| w.ibena().enabled()));
339 self
340 }
341
342 fn disable_input_buffer(&self) -> &Self {
343 critical_section::with(|_| self.reg.modify(|_, w| w.ibena().disabled()));
344 self
345 }
346
347 fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
348 critical_section::with(|_| match slew_rate {
349 SlewRate::Standard => {
350 self.reg.modify(|_, w| w.slewrate().normal());
351 }
352 SlewRate::Slow => {
353 self.reg.modify(|_, w| w.slewrate().slow());
354 }
355 });
356 self
357 }
358
359 fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
360 critical_section::with(|_| match strength {
361 DriveStrength::Normal => {
362 self.reg.modify(|_, w| w.fulldrive().normal_drive());
363 }
364 DriveStrength::Full => {
365 self.reg.modify(|_, w| w.fulldrive().full_drive());
366 }
367 });
368 self
369 }
370
371 fn enable_analog_multiplex(&self) -> &Self {
372 critical_section::with(|_| self.reg.modify(|_, w| w.amena().enabled()));
373 self
374 }
375
376 fn disable_analog_multiplex(&self) -> &Self {
377 critical_section::with(|_| self.reg.modify(|_, w| w.amena().disabled()));
378 self
379 }
380
381 fn set_drive_mode(&self, mode: DriveMode) -> &Self {
382 critical_section::with(|_| match mode {
383 DriveMode::PushPull => {
384 self.reg.modify(|_, w| w.odena().disabled());
385 }
386 DriveMode::OpenDrain => {
387 self.reg.modify(|_, w| w.odena().enabled());
388 }
389 });
390 self
391 }
392
393 fn set_input_inverter(&self, inverter: Inverter) -> &Self {
394 critical_section::with(|_| match inverter {
395 Inverter::Disabled => {
396 self.reg.modify(|_, w| w.iiena().disabled());
397 }
398 Inverter::Enabled => {
399 self.reg.modify(|_, w| w.iiena().enabled());
400 }
401 });
402 self
403 }
404
405 fn reset(&self) -> &Self {
406 self.reg.reset();
407 self
408 }
409 }
410 };
411}
412
413impl_iopctlpin!(AnyPin);
414impl_iopctlpin!(FC15Pin);
415
416macro_rules! impl_FC15pin {
417 ($pin_periph:ident, $pin_no:expr) => {
418 impl SealedPin for crate::peripherals::$pin_periph {}
419 impl ToFC15Pin for crate::peripherals::$pin_periph {}
420 impl IopctlPin for crate::peripherals::$pin_periph {
421 #[inline]
422 fn set_function(&self, _function: Function) -> &Self {
423 //No function configuration for FC15 pin
424 self
425 }
426
427 #[inline]
428 fn set_pull(&self, pull: Pull) -> &Self {
429 Self::to_raw($pin_no).set_pull(pull);
430 self
431 }
432
433 #[inline]
434 fn enable_input_buffer(&self) -> &Self {
435 Self::to_raw($pin_no).enable_input_buffer();
436 self
437 }
438
439 #[inline]
440 fn disable_input_buffer(&self) -> &Self {
441 Self::to_raw($pin_no).disable_input_buffer();
442 self
443 }
444
445 #[inline]
446 fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
447 Self::to_raw($pin_no).set_slew_rate(slew_rate);
448 self
449 }
450
451 #[inline]
452 fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
453 Self::to_raw($pin_no).set_drive_strength(strength);
454 self
455 }
456
457 #[inline]
458 fn enable_analog_multiplex(&self) -> &Self {
459 Self::to_raw($pin_no).enable_analog_multiplex();
460 self
461 }
462
463 #[inline]
464 fn disable_analog_multiplex(&self) -> &Self {
465 Self::to_raw($pin_no).disable_analog_multiplex();
466 self
467 }
468
469 #[inline]
470 fn set_drive_mode(&self, mode: DriveMode) -> &Self {
471 Self::to_raw($pin_no).set_drive_mode(mode);
472 self
473 }
474
475 #[inline]
476 fn set_input_inverter(&self, inverter: Inverter) -> &Self {
477 Self::to_raw($pin_no).set_input_inverter(inverter);
478 self
479 }
480
481 #[inline]
482 fn reset(&self) -> &Self {
483 Self::to_raw($pin_no).reset();
484 self
485 }
486 }
487 };
488}
489
490macro_rules! impl_pin {
491 ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => {
492 impl SealedPin for crate::peripherals::$pin_periph {}
493 impl ToAnyPin for crate::peripherals::$pin_periph {}
494 impl IopctlPin for crate::peripherals::$pin_periph {
495 #[inline]
496 fn set_function(&self, function: Function) -> &Self {
497 Self::to_raw($pin_port, $pin_no).set_function(function);
498 self
499 }
500
501 #[inline]
502 fn set_pull(&self, pull: Pull) -> &Self {
503 Self::to_raw($pin_port, $pin_no).set_pull(pull);
504 self
505 }
506
507 #[inline]
508 fn enable_input_buffer(&self) -> &Self {
509 Self::to_raw($pin_port, $pin_no).enable_input_buffer();
510 self
511 }
512
513 #[inline]
514 fn disable_input_buffer(&self) -> &Self {
515 Self::to_raw($pin_port, $pin_no).disable_input_buffer();
516 self
517 }
518
519 #[inline]
520 fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self {
521 Self::to_raw($pin_port, $pin_no).set_slew_rate(slew_rate);
522 self
523 }
524
525 #[inline]
526 fn set_drive_strength(&self, strength: DriveStrength) -> &Self {
527 Self::to_raw($pin_port, $pin_no).set_drive_strength(strength);
528 self
529 }
530
531 #[inline]
532 fn enable_analog_multiplex(&self) -> &Self {
533 Self::to_raw($pin_port, $pin_no).enable_analog_multiplex();
534 self
535 }
536
537 #[inline]
538 fn disable_analog_multiplex(&self) -> &Self {
539 Self::to_raw($pin_port, $pin_no).disable_analog_multiplex();
540 self
541 }
542
543 #[inline]
544 fn set_drive_mode(&self, mode: DriveMode) -> &Self {
545 Self::to_raw($pin_port, $pin_no).set_drive_mode(mode);
546 self
547 }
548
549 #[inline]
550 fn set_input_inverter(&self, inverter: Inverter) -> &Self {
551 Self::to_raw($pin_port, $pin_no).set_input_inverter(inverter);
552 self
553 }
554
555 #[inline]
556 fn reset(&self) -> &Self {
557 Self::to_raw($pin_port, $pin_no).reset();
558 self
559 }
560 }
561 };
562}
563
564impl_pin!(PIO0_0, 0, 0);
565impl_pin!(PIO0_1, 0, 1);
566impl_pin!(PIO0_2, 0, 2);
567impl_pin!(PIO0_3, 0, 3);
568impl_pin!(PIO0_4, 0, 4);
569impl_pin!(PIO0_5, 0, 5);
570impl_pin!(PIO0_6, 0, 6);
571impl_pin!(PIO0_7, 0, 7);
572impl_pin!(PIO0_8, 0, 8);
573impl_pin!(PIO0_9, 0, 9);
574impl_pin!(PIO0_10, 0, 10);
575impl_pin!(PIO0_11, 0, 11);
576impl_pin!(PIO0_12, 0, 12);
577impl_pin!(PIO0_13, 0, 13);
578impl_pin!(PIO0_14, 0, 14);
579impl_pin!(PIO0_15, 0, 15);
580impl_pin!(PIO0_16, 0, 16);
581impl_pin!(PIO0_17, 0, 17);
582impl_pin!(PIO0_18, 0, 18);
583impl_pin!(PIO0_19, 0, 19);
584impl_pin!(PIO0_20, 0, 20);
585impl_pin!(PIO0_21, 0, 21);
586impl_pin!(PIO0_22, 0, 22);
587impl_pin!(PIO0_23, 0, 23);
588impl_pin!(PIO0_24, 0, 24);
589impl_pin!(PIO0_25, 0, 25);
590impl_pin!(PIO0_26, 0, 26);
591impl_pin!(PIO0_27, 0, 27);
592impl_pin!(PIO0_28, 0, 28);
593impl_pin!(PIO0_29, 0, 29);
594impl_pin!(PIO0_30, 0, 30);
595impl_pin!(PIO0_31, 0, 31);
596impl_pin!(PIO1_0, 1, 0);
597impl_pin!(PIO1_1, 1, 1);
598impl_pin!(PIO1_2, 1, 2);
599impl_pin!(PIO1_3, 1, 3);
600impl_pin!(PIO1_4, 1, 4);
601impl_pin!(PIO1_5, 1, 5);
602impl_pin!(PIO1_6, 1, 6);
603impl_pin!(PIO1_7, 1, 7);
604impl_pin!(PIO1_8, 1, 8);
605impl_pin!(PIO1_9, 1, 9);
606impl_pin!(PIO1_10, 1, 10);
607impl_pin!(PIO1_11, 1, 11);
608impl_pin!(PIO1_12, 1, 12);
609impl_pin!(PIO1_13, 1, 13);
610impl_pin!(PIO1_14, 1, 14);
611impl_pin!(PIO1_15, 1, 15);
612impl_pin!(PIO1_16, 1, 16);
613impl_pin!(PIO1_17, 1, 17);
614impl_pin!(PIO1_18, 1, 18);
615impl_pin!(PIO1_19, 1, 19);
616impl_pin!(PIO1_20, 1, 20);
617impl_pin!(PIO1_21, 1, 21);
618impl_pin!(PIO1_22, 1, 22);
619impl_pin!(PIO1_23, 1, 23);
620impl_pin!(PIO1_24, 1, 24);
621impl_pin!(PIO1_25, 1, 25);
622impl_pin!(PIO1_26, 1, 26);
623impl_pin!(PIO1_27, 1, 27);
624impl_pin!(PIO1_28, 1, 28);
625impl_pin!(PIO1_29, 1, 29);
626impl_pin!(PIO1_30, 1, 30);
627impl_pin!(PIO1_31, 1, 31);
628impl_pin!(PIO2_0, 2, 0);
629impl_pin!(PIO2_1, 2, 1);
630impl_pin!(PIO2_2, 2, 2);
631impl_pin!(PIO2_3, 2, 3);
632impl_pin!(PIO2_4, 2, 4);
633impl_pin!(PIO2_5, 2, 5);
634impl_pin!(PIO2_6, 2, 6);
635impl_pin!(PIO2_7, 2, 7);
636impl_pin!(PIO2_8, 2, 8);
637impl_pin!(PIO2_9, 2, 9);
638impl_pin!(PIO2_10, 2, 10);
639impl_pin!(PIO2_11, 2, 11);
640impl_pin!(PIO2_12, 2, 12);
641impl_pin!(PIO2_13, 2, 13);
642impl_pin!(PIO2_14, 2, 14);
643impl_pin!(PIO2_15, 2, 15);
644impl_pin!(PIO2_16, 2, 16);
645impl_pin!(PIO2_17, 2, 17);
646impl_pin!(PIO2_18, 2, 18);
647impl_pin!(PIO2_19, 2, 19);
648impl_pin!(PIO2_20, 2, 20);
649impl_pin!(PIO2_21, 2, 21);
650impl_pin!(PIO2_22, 2, 22);
651impl_pin!(PIO2_23, 2, 23);
652impl_pin!(PIO2_24, 2, 24);
653
654// Note: These have have reset values of 0x41 to support SWD by default
655impl_pin!(PIO2_25, 2, 25);
656impl_pin!(PIO2_26, 2, 26);
657
658impl_pin!(PIO2_27, 2, 27);
659impl_pin!(PIO2_28, 2, 28);
660impl_pin!(PIO2_29, 2, 29);
661impl_pin!(PIO2_30, 2, 30);
662impl_pin!(PIO2_31, 2, 31);
663impl_pin!(PIO3_0, 3, 0);
664impl_pin!(PIO3_1, 3, 1);
665impl_pin!(PIO3_2, 3, 2);
666impl_pin!(PIO3_3, 3, 3);
667impl_pin!(PIO3_4, 3, 4);
668impl_pin!(PIO3_5, 3, 5);
669impl_pin!(PIO3_6, 3, 6);
670impl_pin!(PIO3_7, 3, 7);
671impl_pin!(PIO3_8, 3, 8);
672impl_pin!(PIO3_9, 3, 9);
673impl_pin!(PIO3_10, 3, 10);
674impl_pin!(PIO3_11, 3, 11);
675impl_pin!(PIO3_12, 3, 12);
676impl_pin!(PIO3_13, 3, 13);
677impl_pin!(PIO3_14, 3, 14);
678impl_pin!(PIO3_15, 3, 15);
679impl_pin!(PIO3_16, 3, 16);
680impl_pin!(PIO3_17, 3, 17);
681impl_pin!(PIO3_18, 3, 18);
682impl_pin!(PIO3_19, 3, 19);
683impl_pin!(PIO3_20, 3, 20);
684impl_pin!(PIO3_21, 3, 21);
685impl_pin!(PIO3_22, 3, 22);
686impl_pin!(PIO3_23, 3, 23);
687impl_pin!(PIO3_24, 3, 24);
688impl_pin!(PIO3_25, 3, 25);
689impl_pin!(PIO3_26, 3, 26);
690impl_pin!(PIO3_27, 3, 27);
691impl_pin!(PIO3_28, 3, 28);
692impl_pin!(PIO3_29, 3, 29);
693impl_pin!(PIO3_30, 3, 30);
694impl_pin!(PIO3_31, 3, 31);
695impl_pin!(PIO4_0, 4, 0);
696impl_pin!(PIO4_1, 4, 1);
697impl_pin!(PIO4_2, 4, 2);
698impl_pin!(PIO4_3, 4, 3);
699impl_pin!(PIO4_4, 4, 4);
700impl_pin!(PIO4_5, 4, 5);
701impl_pin!(PIO4_6, 4, 6);
702impl_pin!(PIO4_7, 4, 7);
703impl_pin!(PIO4_8, 4, 8);
704impl_pin!(PIO4_9, 4, 9);
705impl_pin!(PIO4_10, 4, 10);
706impl_pin!(PIO7_24, 7, 24);
707impl_pin!(PIO7_25, 7, 25);
708impl_pin!(PIO7_26, 7, 26);
709impl_pin!(PIO7_27, 7, 27);
710impl_pin!(PIO7_28, 7, 28);
711impl_pin!(PIO7_29, 7, 29);
712impl_pin!(PIO7_30, 7, 30);
713impl_pin!(PIO7_31, 7, 31);
714
715// FC15 pins
716impl_FC15pin!(PIOFC15_SCL, 0);
717impl_FC15pin!(PIOFC15_SDA, 1);
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
new file mode 100644
index 000000000..d56d993c3
--- /dev/null
+++ b/embassy-imxrt/src/lib.rs
@@ -0,0 +1,130 @@
1#![no_std]
2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
9#[cfg(not(any(feature = "mimxrt633s", feature = "mimxrt685s",)))]
10compile_error!(
11 "No chip feature activated. You must activate exactly one of the following features:
12 mimxrt633s,
13 mimxrt685s,
14 "
15);
16
17// This mod MUST go first, so that the others see its macros.
18pub(crate) mod fmt;
19
20pub mod clocks;
21pub mod gpio;
22pub mod iopctl;
23
24// This mod MUST go last, so that it sees all the `impl_foo!' macros
25#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")]
26#[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")]
27mod chip;
28
29// Reexports
30pub use chip::interrupts::*;
31#[cfg(feature = "unstable-pac")]
32pub use chip::pac;
33#[cfg(not(feature = "unstable-pac"))]
34pub(crate) use chip::pac;
35pub use chip::{peripherals, Peripherals};
36pub use embassy_hal_internal::{Peri, PeripheralType};
37
38#[cfg(feature = "rt")]
39pub use crate::pac::NVIC_PRIO_BITS;
40
41/// Macro to bind interrupts to handlers.
42///
43/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
44/// and implements the right \[`Binding`\]s for it. You can pass this struct to drivers to
45/// prove at compile-time that the right interrupts have been bound.
46///
47/// Example of how to bind one interrupt:
48///
49/// ```rust,ignore
50/// use embassy_imxrt::{bind_interrupts, flexspi, peripherals};
51///
52/// bind_interrupts!(struct Irqs {
53/// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>;
54/// });
55/// ```
56///
57// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
58#[macro_export]
59macro_rules! bind_interrupts {
60 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
61 #[derive(Copy, Clone)]
62 $vis struct $name;
63
64 $(
65 #[allow(non_snake_case)]
66 #[no_mangle]
67 unsafe extern "C" fn $irq() {
68 $(
69 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
70 )*
71 }
72
73 $(
74 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
75 )*
76 )*
77 };
78}
79
80/// HAL configuration for iMX RT600.
81pub mod config {
82 use crate::clocks::ClockConfig;
83
84 /// HAL configuration passed when initializing.
85 #[non_exhaustive]
86 pub struct Config {
87 /// Clock configuration.
88 pub clocks: ClockConfig,
89 }
90
91 impl Default for Config {
92 fn default() -> Self {
93 Self {
94 clocks: ClockConfig::crystal(),
95 }
96 }
97 }
98
99 impl Config {
100 /// Create a new configuration with the provided clock config.
101 pub fn new(clocks: ClockConfig) -> Self {
102 Self { clocks }
103 }
104 }
105}
106
107/// Initialize the `embassy-imxrt` HAL with the provided configuration.
108///
109/// This returns the peripheral singletons that can be used for creating drivers.
110///
111/// This should only be called once at startup, otherwise it panics.
112pub fn init(config: config::Config) -> Peripherals {
113 // Do this first, so that it panics if user is calling `init` a second time
114 // before doing anything important.
115 let peripherals = Peripherals::take();
116
117 unsafe {
118 if let Err(e) = clocks::init(config.clocks) {
119 error!("unable to initialize Clocks for reason: {:?}", e);
120 // Panic here?
121 }
122 gpio::init();
123 }
124
125 peripherals
126}
127
128pub(crate) mod sealed {
129 pub trait Sealed {}
130}