aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorobe1line <[email protected]>2025-07-23 12:40:48 +1000
committerGitHub <[email protected]>2025-07-23 12:40:48 +1000
commiteb15a555196050166acdf53db02f1d0fffbfb2be (patch)
tree4bf95c120a4fbd84e5d55beca92bc0af05af99e8
parente64c23076d2c003efe60419eab6b86630d7886b4 (diff)
parent8f5e4ac06d1d06dd6520a8eecf8697b199005f34 (diff)
Merge branch 'embassy-rs:main' into obe1line-stm32c071
-rw-r--r--.vscode/settings.json2
-rwxr-xr-xci.sh5
-rw-r--r--embassy-boot-nrf/Cargo.toml4
-rw-r--r--embassy-boot-rp/Cargo.toml4
-rw-r--r--embassy-boot-stm32/Cargo.toml4
-rw-r--r--embassy-boot/Cargo.toml2
-rw-r--r--embassy-mspm0/Cargo.toml4
-rw-r--r--embassy-mspm0/src/uart/buffered.rs1060
-rw-r--r--embassy-mspm0/src/uart/mod.rs (renamed from embassy-mspm0/src/uart.rs)145
-rw-r--r--embassy-nxp/Cargo.toml37
-rw-r--r--embassy-nxp/build.rs138
-rw-r--r--embassy-nxp/build_common.rs94
-rw-r--r--embassy-nxp/src/chips/mimxrt1011.rs113
-rw-r--r--embassy-nxp/src/chips/mimxrt1062.rs282
-rw-r--r--embassy-nxp/src/fmt.rs284
-rw-r--r--embassy-nxp/src/gpio.rs2
-rw-r--r--embassy-nxp/src/gpio/lpc55.rs1
-rw-r--r--embassy-nxp/src/gpio/rt1xxx.rs945
-rw-r--r--embassy-nxp/src/lib.rs87
-rw-r--r--embassy-nxp/src/pint.rs2
-rw-r--r--embassy-nxp/src/time_driver/pit.rs187
-rw-r--r--embassy-stm32/Cargo.toml2
-rw-r--r--embassy-stm32/src/adc/adc4.rs4
-rw-r--r--embassy-stm32/src/adc/c0.rs3
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs2
-rw-r--r--embassy-stm32/src/adc/v3.rs19
-rw-r--r--embassy-stm32/src/adc/v4.rs1
-rw-r--r--embassy-stm32/src/low_power.rs3
-rw-r--r--embassy-usb-dfu/Cargo.toml2
-rw-r--r--embassy-usb-logger/CHANGELOG.md4
-rw-r--r--embassy-usb-logger/Cargo.toml2
-rw-r--r--embassy-usb-synopsys-otg/CHANGELOG.md4
-rw-r--r--embassy-usb-synopsys-otg/Cargo.toml2
-rw-r--r--examples/boot/application/nrf/Cargo.toml4
-rw-r--r--examples/boot/application/rp/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/lpc55s69/Cargo.toml2
-rw-r--r--examples/mimxrt1011/.cargo/config.toml8
-rw-r--r--examples/mimxrt1011/Cargo.toml29
-rw-r--r--examples/mimxrt1011/build.rs14
-rw-r--r--examples/mimxrt1011/src/bin/blinky.rs48
-rw-r--r--examples/mimxrt1011/src/bin/button.rs62
-rw-r--r--examples/mimxrt1011/src/lib.rs75
-rw-r--r--examples/mimxrt1062-evk/.cargo/config.toml8
-rw-r--r--examples/mimxrt1062-evk/Cargo.toml29
-rw-r--r--examples/mimxrt1062-evk/build.rs12
-rw-r--r--examples/mimxrt1062-evk/src/bin/blinky.rs25
-rw-r--r--examples/mimxrt1062-evk/src/bin/button.rs36
-rw-r--r--examples/mimxrt1062-evk/src/lib.rs60
-rw-r--r--examples/mspm0g3507/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp235x/Cargo.toml2
-rw-r--r--tests/mspm0/Cargo.toml3
-rw-r--r--tests/mspm0/src/bin/uart_buffered.rs115
61 files changed, 3928 insertions, 76 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e4814ff27..6edd9312a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -36,6 +36,8 @@
36 // "examples/nrf52840-rtic/Cargo.toml", 36 // "examples/nrf52840-rtic/Cargo.toml",
37 // "examples/nrf5340/Cargo.toml", 37 // "examples/nrf5340/Cargo.toml",
38 // "examples/nrf-rtos-trace/Cargo.toml", 38 // "examples/nrf-rtos-trace/Cargo.toml",
39 // "examples/mimxrt1011/Cargo.toml",
40 // "examples/mimxrt1062-evk/Cargo.toml",
39 // "examples/rp/Cargo.toml", 41 // "examples/rp/Cargo.toml",
40 // "examples/std/Cargo.toml", 42 // "examples/std/Cargo.toml",
41 // "examples/stm32c0/Cargo.toml", 43 // "examples/stm32c0/Cargo.toml",
diff --git a/ci.sh b/ci.sh
index b2277a6d7..6be6e98e4 100755
--- a/ci.sh
+++ b/ci.sh
@@ -183,6 +183,8 @@ cargo batch \
183 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ 183 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
184 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ 184 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
185 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \ 185 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \
186 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \
187 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \
186 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,defmt,time-driver-any \ 188 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,defmt,time-driver-any \
187 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,defmt,time-driver-any \ 189 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,defmt,time-driver-any \
188 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \ 190 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \
@@ -266,6 +268,8 @@ cargo batch \
266 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ 268 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
267 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ 269 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
268 --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ 270 --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
271 --- build --release --manifest-path examples/mimxrt1011/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1011 \
272 --- build --release --manifest-path examples/mimxrt1062-evk/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1062-evk \
269 --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \ 273 --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
270 --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \ 274 --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
271 --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \ 275 --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
@@ -379,6 +383,7 @@ rm out/tests/pimoroni-pico-plus-2/pwm
379 383
380# flaky 384# flaky
381rm out/tests/rpi-pico/pwm 385rm out/tests/rpi-pico/pwm
386rm out/tests/rpi-pico/cyw43-perf
382 387
383if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 388if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
384 echo No teleprobe token found, skipping running HIL tests 389 echo No teleprobe token found, skipping running HIL tests
diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml
index 1230cbd3b..81479759c 100644
--- a/embassy-boot-nrf/Cargo.toml
+++ b/embassy-boot-nrf/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-nrf" 3name = "embassy-boot-nrf"
4version = "0.5.0" 4version = "0.6.0"
5description = "Bootloader lib for nRF chips" 5description = "Bootloader lib for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -26,7 +26,7 @@ log = { version = "0.4.17", optional = true }
26 26
27embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
28embassy-nrf = { version = "0.5.0", path = "../embassy-nrf", default-features = false } 28embassy-nrf = { version = "0.5.0", path = "../embassy-nrf", default-features = false }
29embassy-boot = { version = "0.4.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
30cortex-m = { version = "0.7.6" } 30cortex-m = { version = "0.7.6" }
31cortex-m-rt = { version = "0.7" } 31cortex-m-rt = { version = "0.7" }
32embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml
index 23d6c7853..8ca999f67 100644
--- a/embassy-boot-rp/Cargo.toml
+++ b/embassy-boot-rp/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-rp" 3name = "embassy-boot-rp"
4version = "0.5.0" 4version = "0.6.0"
5description = "Bootloader lib for RP2040 chips" 5description = "Bootloader lib for RP2040 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
26 26
27embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
28embassy-rp = { version = "0.6.0", path = "../embassy-rp", default-features = false } 28embassy-rp = { version = "0.6.0", path = "../embassy-rp", default-features = false }
29embassy-boot = { version = "0.4.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
30embassy-time = { version = "0.4.0", path = "../embassy-time" } 30embassy-time = { version = "0.4.0", path = "../embassy-time" }
31 31
32cortex-m = { version = "0.7.6" } 32cortex-m = { version = "0.7.6" }
diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml
index 11ad453b8..b92d06c54 100644
--- a/embassy-boot-stm32/Cargo.toml
+++ b/embassy-boot-stm32/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32" 3name = "embassy-boot-stm32"
4version = "0.3.0" 4version = "0.4.0"
5description = "Bootloader lib for STM32 chips" 5description = "Bootloader lib for STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
26 26
27embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
28embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false } 28embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false }
29embassy-boot = { version = "0.4.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
30cortex-m = { version = "0.7.6" } 30cortex-m = { version = "0.7.6" }
31cortex-m-rt = { version = "0.7" } 31cortex-m-rt = { version = "0.7" }
32embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml
index 281278abb..172330ef2 100644
--- a/embassy-boot/Cargo.toml
+++ b/embassy-boot/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot" 3name = "embassy-boot"
4version = "0.4.0" 4version = "0.5.0"
5description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." 5description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
index d2adc63d7..61afcd76d 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -36,7 +36,10 @@ embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", de
36embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } 36embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
37 37
38embedded-hal = { version = "1.0" } 38embedded-hal = { version = "1.0" }
39embedded-hal-nb = { version = "1.0" }
39embedded-hal-async = { version = "1.0" } 40embedded-hal-async = { version = "1.0" }
41embedded-io = "0.6.1"
42embedded-io-async = "0.6.1"
40 43
41defmt = { version = "1.0.1", optional = true } 44defmt = { version = "1.0.1", optional = true }
42fixed = "1.29" 45fixed = "1.29"
@@ -51,6 +54,7 @@ mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag
51[build-dependencies] 54[build-dependencies]
52proc-macro2 = "1.0.94" 55proc-macro2 = "1.0.94"
53quote = "1.0.40" 56quote = "1.0.40"
57cfg_aliases = "0.2.1"
54 58
55# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } 59# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
56mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-235158ac2865d8aac3a1eceb2d62026eb12bf38f", default-features = false, features = ["metadata"] } 60mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-235158ac2865d8aac3a1eceb2d62026eb12bf38f", default-features = false, features = ["metadata"] }
diff --git a/embassy-mspm0/src/uart/buffered.rs b/embassy-mspm0/src/uart/buffered.rs
new file mode 100644
index 000000000..cbc0b6c80
--- /dev/null
+++ b/embassy-mspm0/src/uart/buffered.rs
@@ -0,0 +1,1060 @@
1use core::future::{poll_fn, Future};
2use core::marker::PhantomData;
3use core::slice;
4use core::sync::atomic::{AtomicU8, Ordering};
5use core::task::Poll;
6
7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::interrupt::InterruptExt;
10use embassy_sync::waitqueue::AtomicWaker;
11use embedded_hal_nb::nb;
12
13use crate::gpio::{AnyPin, SealedPin};
14use crate::interrupt::typelevel::Binding;
15use crate::pac::uart::Uart as Regs;
16use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin};
17use crate::{interrupt, Peri};
18
19/// Interrupt handler.
20pub struct BufferedInterruptHandler<T: Instance> {
21 _uart: PhantomData<T>,
22}
23
24impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
25 unsafe fn on_interrupt() {
26 on_interrupt(T::info().regs, T::buffered_state())
27 }
28}
29
30/// Bidirectional buffered UART which acts as a combination of [`BufferedUartTx`] and [`BufferedUartRx`].
31pub struct BufferedUart<'d> {
32 rx: BufferedUartRx<'d>,
33 tx: BufferedUartTx<'d>,
34}
35
36impl SetConfig for BufferedUart<'_> {
37 type Config = Config;
38 type ConfigError = ConfigError;
39
40 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
41 self.set_config(config)
42 }
43}
44
45impl<'d> BufferedUart<'d> {
46 /// Create a new bidirectional buffered UART.
47 pub fn new<T: Instance>(
48 uart: Peri<'d, T>,
49 tx: Peri<'d, impl TxPin<T>>,
50 rx: Peri<'d, impl RxPin<T>>,
51 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
52 tx_buffer: &'d mut [u8],
53 rx_buffer: &'d mut [u8],
54 config: Config,
55 ) -> Result<Self, ConfigError> {
56 Self::new_inner(
57 uart,
58 new_pin!(rx, config.rx_pf()),
59 new_pin!(tx, config.tx_pf()),
60 None,
61 None,
62 tx_buffer,
63 rx_buffer,
64 config,
65 )
66 }
67
68 /// Create a new bidirectional buffered UART with request-to-send and clear-to-send pins
69 pub fn new_with_rtscts<T: Instance>(
70 uart: Peri<'d, T>,
71 tx: Peri<'d, impl TxPin<T>>,
72 rx: Peri<'d, impl RxPin<T>>,
73 rts: Peri<'d, impl RtsPin<T>>,
74 cts: Peri<'d, impl CtsPin<T>>,
75 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
76 tx_buffer: &'d mut [u8],
77 rx_buffer: &'d mut [u8],
78 config: Config,
79 ) -> Result<Self, ConfigError> {
80 Self::new_inner(
81 uart,
82 new_pin!(rx, config.rx_pf()),
83 new_pin!(tx, config.tx_pf()),
84 new_pin!(rts, config.rts_pf()),
85 new_pin!(cts, config.cts_pf()),
86 tx_buffer,
87 rx_buffer,
88 config,
89 )
90 }
91
92 /// Reconfigure the driver
93 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
94 self.tx.set_config(config)?;
95 self.rx.set_config(config)
96 }
97
98 /// Set baudrate
99 pub fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
100 self.rx.set_baudrate(baudrate)
101 }
102
103 /// Write to UART TX buffer, blocking execution until done.
104 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> {
105 self.tx.blocking_write(buffer)
106 }
107
108 /// Flush UART TX buffer, blocking execution until done.
109 pub fn blocking_flush(&mut self) -> Result<(), Error> {
110 self.tx.blocking_flush()
111 }
112
113 /// Check if UART is busy.
114 pub fn busy(&self) -> bool {
115 self.tx.busy()
116 }
117
118 /// Read from UART RX buffer, blocking execution until done.
119 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
120 self.rx.blocking_read(buffer)
121 }
122
123 /// Send break character.
124 pub fn send_break(&mut self) {
125 self.tx.send_break()
126 }
127
128 /// Split into separate RX and TX handles.
129 pub fn split(self) -> (BufferedUartTx<'d>, BufferedUartRx<'d>) {
130 (self.tx, self.rx)
131 }
132
133 /// Split into separate RX and TX handles.
134 pub fn split_ref(&mut self) -> (BufferedUartTx<'_>, BufferedUartRx<'_>) {
135 (
136 BufferedUartTx {
137 info: self.tx.info,
138 state: self.tx.state,
139 tx: self.tx.tx.as_mut().map(Peri::reborrow),
140 cts: self.tx.cts.as_mut().map(Peri::reborrow),
141 reborrowed: true,
142 },
143 BufferedUartRx {
144 info: self.rx.info,
145 state: self.rx.state,
146 rx: self.rx.rx.as_mut().map(Peri::reborrow),
147 rts: self.rx.rts.as_mut().map(Peri::reborrow),
148 reborrowed: true,
149 },
150 )
151 }
152}
153
154/// Rx-only buffered UART.
155///
156/// Can be obtained from [`BufferedUart::split`], or can be constructed independently,
157/// if you do not need the transmitting half of the driver.
158pub struct BufferedUartRx<'d> {
159 info: &'static Info,
160 state: &'static BufferedState,
161 rx: Option<Peri<'d, AnyPin>>,
162 rts: Option<Peri<'d, AnyPin>>,
163 reborrowed: bool,
164}
165
166impl SetConfig for BufferedUartRx<'_> {
167 type Config = Config;
168 type ConfigError = ConfigError;
169
170 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
171 self.set_config(config)
172 }
173}
174
175impl<'d> BufferedUartRx<'d> {
176 /// Create a new rx-only buffered UART with no hardware flow control.
177 ///
178 /// Useful if you only want Uart Rx. It saves 1 pin.
179 pub fn new<T: Instance>(
180 uart: Peri<'d, T>,
181 rx: Peri<'d, impl RxPin<T>>,
182 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
183 rx_buffer: &'d mut [u8],
184 config: Config,
185 ) -> Result<Self, ConfigError> {
186 Self::new_inner(uart, new_pin!(rx, config.rx_pf()), None, rx_buffer, config)
187 }
188
189 /// Create a new rx-only buffered UART with a request-to-send pin
190 pub fn new_with_rts<T: Instance>(
191 uart: Peri<'d, T>,
192 rx: Peri<'d, impl RxPin<T>>,
193 rts: Peri<'d, impl RtsPin<T>>,
194 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
195 rx_buffer: &'d mut [u8],
196 config: Config,
197 ) -> Result<Self, ConfigError> {
198 Self::new_inner(
199 uart,
200 new_pin!(rx, config.rx_pf()),
201 new_pin!(rts, config.rts_pf()),
202 rx_buffer,
203 config,
204 )
205 }
206
207 /// Reconfigure the driver
208 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
209 if let Some(ref rx) = self.rx {
210 rx.update_pf(config.rx_pf());
211 }
212
213 if let Some(ref rts) = self.rts {
214 rts.update_pf(config.rts_pf());
215 }
216
217 super::reconfigure(&self.info, &self.state.state, config)
218 }
219
220 /// Set baudrate
221 pub fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> {
222 super::set_baudrate(&self.info, self.state.state.clock.load(Ordering::Relaxed), baudrate)
223 }
224
225 /// Read from UART RX buffer, blocking execution until done.
226 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
227 self.blocking_read_inner(buffer)
228 }
229}
230
231impl Drop for BufferedUartRx<'_> {
232 fn drop(&mut self) {
233 if !self.reborrowed {
234 let state = self.state;
235
236 // SAFETY: RX is being dropped (and is not reborrowed), so the ring buffer must be deinitialized
237 // in order to meet the requirements of init.
238 unsafe {
239 state.rx_buf.deinit();
240 }
241
242 // TX is inactive if the buffer is not available. If this is true, then disable the
243 // interrupt handler since we are running in RX only mode.
244 if state.tx_buf.len() == 0 {
245 self.info.interrupt.disable();
246 }
247
248 self.rx.as_ref().map(|x| x.set_as_disconnected());
249 self.rts.as_ref().map(|x| x.set_as_disconnected());
250 }
251 }
252}
253
254/// Tx-only buffered UART.
255///
256/// Can be obtained from [`BufferedUart::split`], or can be constructed independently,
257/// if you do not need the receiving half of the driver.
258pub struct BufferedUartTx<'d> {
259 info: &'static Info,
260 state: &'static BufferedState,
261 tx: Option<Peri<'d, AnyPin>>,
262 cts: Option<Peri<'d, AnyPin>>,
263 reborrowed: bool,
264}
265
266impl SetConfig for BufferedUartTx<'_> {
267 type Config = Config;
268 type ConfigError = ConfigError;
269
270 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
271 self.set_config(config)
272 }
273}
274
275impl<'d> BufferedUartTx<'d> {
276 /// Create a new tx-only buffered UART with no hardware flow control.
277 ///
278 /// Useful if you only want Uart Tx. It saves 1 pin.
279 pub fn new<T: Instance>(
280 uart: Peri<'d, T>,
281 tx: Peri<'d, impl TxPin<T>>,
282 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
283 tx_buffer: &'d mut [u8],
284 config: Config,
285 ) -> Result<Self, ConfigError> {
286 Self::new_inner(uart, new_pin!(tx, config.tx_pf()), None, tx_buffer, config)
287 }
288
289 /// Create a new tx-only buffered UART with a clear-to-send pin
290 pub fn new_with_rts<T: Instance>(
291 uart: Peri<'d, T>,
292 tx: Peri<'d, impl TxPin<T>>,
293 cts: Peri<'d, impl CtsPin<T>>,
294 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
295 tx_buffer: &'d mut [u8],
296 config: Config,
297 ) -> Result<Self, ConfigError> {
298 Self::new_inner(
299 uart,
300 new_pin!(tx, config.tx_pf()),
301 new_pin!(cts, config.cts_pf()),
302 tx_buffer,
303 config,
304 )
305 }
306
307 /// Reconfigure the driver
308 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
309 if let Some(ref tx) = self.tx {
310 tx.update_pf(config.tx_pf());
311 }
312
313 if let Some(ref cts) = self.cts {
314 cts.update_pf(config.cts_pf());
315 }
316
317 super::reconfigure(self.info, &self.state.state, config)
318 }
319
320 /// Set baudrate
321 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
322 super::set_baudrate(&self.info, self.state.state.clock.load(Ordering::Relaxed), baudrate)
323 }
324
325 /// Write to UART TX buffer, blocking execution until done.
326 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> {
327 self.blocking_write_inner(buffer)
328 }
329
330 /// Flush UART TX buffer, blocking execution until done.
331 pub fn blocking_flush(&mut self) -> Result<(), Error> {
332 let state = self.state;
333
334 loop {
335 if state.tx_buf.is_empty() {
336 return Ok(());
337 }
338 }
339 }
340
341 /// Check if UART is busy.
342 pub fn busy(&self) -> bool {
343 super::busy(self.info.regs)
344 }
345
346 /// Send break character
347 pub fn send_break(&mut self) {
348 let r = self.info.regs;
349
350 r.lcrh().modify(|w| {
351 w.set_brk(true);
352 });
353 }
354}
355
356impl Drop for BufferedUartTx<'_> {
357 fn drop(&mut self) {
358 if !self.reborrowed {
359 let state = self.state;
360
361 // SAFETY: TX is being dropped (and is not reborrowed), so the ring buffer must be deinitialized
362 // in order to meet the requirements of init.
363 unsafe {
364 state.tx_buf.deinit();
365 }
366
367 // RX is inactive if the buffer is not available. If this is true, then disable the
368 // interrupt handler since we are running in TX only mode.
369 if state.rx_buf.len() == 0 {
370 self.info.interrupt.disable();
371 }
372
373 self.tx.as_ref().map(|x| x.set_as_disconnected());
374 self.cts.as_ref().map(|x| x.set_as_disconnected());
375 }
376 }
377}
378
379impl embedded_io_async::ErrorType for BufferedUart<'_> {
380 type Error = Error;
381}
382
383impl embedded_io_async::ErrorType for BufferedUartRx<'_> {
384 type Error = Error;
385}
386
387impl embedded_io_async::ErrorType for BufferedUartTx<'_> {
388 type Error = Error;
389}
390
391impl embedded_io_async::Read for BufferedUart<'_> {
392 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
393 self.rx.read(buf).await
394 }
395}
396
397impl embedded_io_async::Read for BufferedUartRx<'_> {
398 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
399 self.read_inner(buf).await
400 }
401}
402
403impl embedded_io_async::ReadReady for BufferedUart<'_> {
404 fn read_ready(&mut self) -> Result<bool, Self::Error> {
405 self.rx.read_ready()
406 }
407}
408
409impl embedded_io_async::ReadReady for BufferedUartRx<'_> {
410 fn read_ready(&mut self) -> Result<bool, Self::Error> {
411 self.read_ready_inner()
412 }
413}
414
415impl embedded_io_async::BufRead for BufferedUart<'_> {
416 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
417 self.rx.fill_buf().await
418 }
419
420 fn consume(&mut self, amt: usize) {
421 self.rx.consume(amt);
422 }
423}
424
425impl embedded_io_async::BufRead for BufferedUartRx<'_> {
426 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
427 self.fill_buf_inner().await
428 }
429
430 fn consume(&mut self, amt: usize) {
431 self.consume_inner(amt);
432 }
433}
434
435impl embedded_io_async::Write for BufferedUart<'_> {
436 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
437 self.tx.write_inner(buf).await
438 }
439}
440
441impl embedded_io_async::Write for BufferedUartTx<'_> {
442 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
443 self.write_inner(buf).await
444 }
445
446 async fn flush(&mut self) -> Result<(), Self::Error> {
447 self.flush_inner().await
448 }
449}
450
451impl embedded_io::Read for BufferedUart<'_> {
452 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
453 self.rx.read(buf)
454 }
455}
456
457impl embedded_io::Read for BufferedUartRx<'_> {
458 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
459 self.blocking_read_inner(buf)
460 }
461}
462
463impl embedded_io::Write for BufferedUart<'_> {
464 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
465 self.tx.write(buf)
466 }
467
468 fn flush(&mut self) -> Result<(), Self::Error> {
469 self.tx.flush()
470 }
471}
472
473impl embedded_io::Write for BufferedUartTx<'_> {
474 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
475 self.blocking_write_inner(buf)
476 }
477
478 fn flush(&mut self) -> Result<(), Self::Error> {
479 self.blocking_flush()
480 }
481}
482
483impl embedded_hal_nb::serial::Error for Error {
484 fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
485 match self {
486 Error::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
487 Error::Noise => embedded_hal_nb::serial::ErrorKind::Noise,
488 Error::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
489 Error::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
490 Error::Break => embedded_hal_nb::serial::ErrorKind::Other,
491 }
492 }
493}
494
495impl embedded_hal_nb::serial::ErrorType for BufferedUart<'_> {
496 type Error = Error;
497}
498
499impl embedded_hal_nb::serial::ErrorType for BufferedUartRx<'_> {
500 type Error = Error;
501}
502
503impl embedded_hal_nb::serial::ErrorType for BufferedUartTx<'_> {
504 type Error = Error;
505}
506
507impl embedded_hal_nb::serial::Read for BufferedUart<'_> {
508 fn read(&mut self) -> nb::Result<u8, Self::Error> {
509 self.rx.read()
510 }
511}
512
513impl embedded_hal_nb::serial::Read for BufferedUartRx<'_> {
514 fn read(&mut self) -> nb::Result<u8, Self::Error> {
515 if self.info.regs.stat().read().rxfe() {
516 return Err(nb::Error::WouldBlock);
517 }
518
519 super::read_with_error(self.info.regs).map_err(nb::Error::Other)
520 }
521}
522
523impl embedded_hal_nb::serial::Write for BufferedUart<'_> {
524 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
525 self.tx.write(word)
526 }
527
528 fn flush(&mut self) -> nb::Result<(), Self::Error> {
529 self.tx.flush()
530 }
531}
532
533impl embedded_hal_nb::serial::Write for BufferedUartTx<'_> {
534 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
535 self.blocking_write(&[word]).map(drop).map_err(nb::Error::Other)
536 }
537
538 fn flush(&mut self) -> nb::Result<(), Self::Error> {
539 self.blocking_flush().map_err(nb::Error::Other)
540 }
541}
542
543// Impl details
544
545/// Buffered UART state.
546pub(crate) struct BufferedState {
547 /// non-buffered UART state. This is inline in order to avoid [`BufferedUartRx`]/Tx
548 /// needing to carry around a 2nd static reference and waste another 4 bytes.
549 state: State,
550 rx_waker: AtomicWaker,
551 rx_buf: RingBuffer,
552 tx_waker: AtomicWaker,
553 tx_buf: RingBuffer,
554 rx_error: AtomicU8,
555}
556
557// these must match bits 8..12 in RXDATA, but shifted by 8 to the right
558const RXE_NOISE: u8 = 16;
559const RXE_OVERRUN: u8 = 8;
560const RXE_BREAK: u8 = 4;
561const RXE_PARITY: u8 = 2;
562const RXE_FRAMING: u8 = 1;
563
564impl BufferedState {
565 pub const fn new() -> Self {
566 Self {
567 state: State::new(),
568 rx_waker: AtomicWaker::new(),
569 rx_buf: RingBuffer::new(),
570 tx_waker: AtomicWaker::new(),
571 tx_buf: RingBuffer::new(),
572 rx_error: AtomicU8::new(0),
573 }
574 }
575}
576
577impl<'d> BufferedUart<'d> {
578 fn new_inner<T: Instance>(
579 _peri: Peri<'d, T>,
580 rx: Option<Peri<'d, AnyPin>>,
581 tx: Option<Peri<'d, AnyPin>>,
582 rts: Option<Peri<'d, AnyPin>>,
583 cts: Option<Peri<'d, AnyPin>>,
584 tx_buffer: &'d mut [u8],
585 rx_buffer: &'d mut [u8],
586 config: Config,
587 ) -> Result<Self, ConfigError> {
588 let info = T::info();
589 let state = T::buffered_state();
590
591 let mut this = Self {
592 tx: BufferedUartTx {
593 info,
594 state,
595 tx,
596 cts,
597 reborrowed: false,
598 },
599 rx: BufferedUartRx {
600 info,
601 state,
602 rx,
603 rts,
604 reborrowed: false,
605 },
606 };
607 this.enable_and_configure(tx_buffer, rx_buffer, &config)?;
608
609 Ok(this)
610 }
611
612 fn enable_and_configure(
613 &mut self,
614 tx_buffer: &'d mut [u8],
615 rx_buffer: &'d mut [u8],
616 config: &Config,
617 ) -> Result<(), ConfigError> {
618 let info = self.rx.info;
619 let state = self.rx.state;
620
621 assert!(!tx_buffer.is_empty());
622 assert!(!rx_buffer.is_empty());
623
624 init_buffers(info, state, Some(tx_buffer), Some(rx_buffer));
625 super::enable(info.regs);
626 super::configure(
627 info,
628 &state.state,
629 config,
630 true,
631 self.rx.rts.is_some(),
632 true,
633 self.tx.cts.is_some(),
634 )?;
635
636 info.interrupt.unpend();
637 unsafe { info.interrupt.enable() };
638
639 Ok(())
640 }
641}
642
643impl<'d> BufferedUartRx<'d> {
644 fn new_inner<T: Instance>(
645 _peri: Peri<'d, T>,
646 rx: Option<Peri<'d, AnyPin>>,
647 rts: Option<Peri<'d, AnyPin>>,
648 rx_buffer: &'d mut [u8],
649 config: Config,
650 ) -> Result<Self, ConfigError> {
651 let mut this = Self {
652 info: T::info(),
653 state: T::buffered_state(),
654 rx,
655 rts,
656 reborrowed: false,
657 };
658 this.enable_and_configure(rx_buffer, &config)?;
659
660 Ok(this)
661 }
662
663 fn enable_and_configure(&mut self, rx_buffer: &'d mut [u8], config: &Config) -> Result<(), ConfigError> {
664 let info = self.info;
665 let state = self.state;
666
667 init_buffers(info, state, None, Some(rx_buffer));
668 super::enable(info.regs);
669 super::configure(info, &self.state.state, config, true, self.rts.is_some(), false, false)?;
670
671 info.interrupt.unpend();
672 unsafe { info.interrupt.enable() };
673
674 Ok(())
675 }
676
677 async fn read_inner(&self, buf: &mut [u8]) -> Result<usize, Error> {
678 poll_fn(move |cx| {
679 let state = self.state;
680
681 if let Poll::Ready(r) = self.try_read(buf) {
682 return Poll::Ready(r);
683 }
684
685 state.rx_waker.register(cx.waker());
686 Poll::Pending
687 })
688 .await
689 }
690
691 fn blocking_read_inner(&self, buffer: &mut [u8]) -> Result<usize, Error> {
692 loop {
693 match self.try_read(buffer) {
694 Poll::Ready(res) => return res,
695 Poll::Pending => continue,
696 }
697 }
698 }
699
700 fn fill_buf_inner(&self) -> impl Future<Output = Result<&'_ [u8], Error>> {
701 poll_fn(move |cx| {
702 let mut rx_reader = unsafe { self.state.rx_buf.reader() };
703 let (p, n) = rx_reader.pop_buf();
704 let result = if n == 0 {
705 match Self::get_rx_error(self.state) {
706 None => {
707 self.state.rx_waker.register(cx.waker());
708 return Poll::Pending;
709 }
710 Some(e) => Err(e),
711 }
712 } else {
713 let buf = unsafe { slice::from_raw_parts(p, n) };
714 Ok(buf)
715 };
716
717 Poll::Ready(result)
718 })
719 }
720
721 fn consume_inner(&self, amt: usize) {
722 let mut rx_reader = unsafe { self.state.rx_buf.reader() };
723 rx_reader.pop_done(amt);
724
725 // (Re-)Enable the interrupt to receive more data in case it was
726 // disabled because the buffer was full or errors were detected.
727 self.info.regs.cpu_int(0).imask().modify(|w| {
728 w.set_rxint(true);
729 w.set_rtout(true);
730 });
731 }
732
733 /// we are ready to read if there is data in the buffer
734 fn read_ready_inner(&self) -> Result<bool, Error> {
735 Ok(!self.state.rx_buf.is_empty())
736 }
737
738 fn try_read(&self, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
739 let state = self.state;
740
741 if buf.is_empty() {
742 return Poll::Ready(Ok(0));
743 }
744
745 let mut rx_reader = unsafe { state.rx_buf.reader() };
746 let n = rx_reader.pop(|data| {
747 let n = data.len().min(buf.len());
748 buf[..n].copy_from_slice(&data[..n]);
749 n
750 });
751
752 let result = if n == 0 {
753 match Self::get_rx_error(state) {
754 None => return Poll::Pending,
755 Some(e) => Err(e),
756 }
757 } else {
758 Ok(n)
759 };
760
761 // (Re-)Enable the interrupt to receive more data in case it was
762 // disabled because the buffer was full or errors were detected.
763 self.info.regs.cpu_int(0).imask().modify(|w| {
764 w.set_rxint(true);
765 w.set_rtout(true);
766 });
767
768 Poll::Ready(result)
769 }
770
771 fn get_rx_error(state: &BufferedState) -> Option<Error> {
772 // Cortex-M0 has does not support atomic swap, so we must do two operations.
773 let errs = critical_section::with(|_cs| {
774 let errs = state.rx_error.load(Ordering::Relaxed);
775 state.rx_error.store(0, Ordering::Relaxed);
776
777 errs
778 });
779
780 if errs & RXE_NOISE != 0 {
781 Some(Error::Noise)
782 } else if errs & RXE_OVERRUN != 0 {
783 Some(Error::Overrun)
784 } else if errs & RXE_BREAK != 0 {
785 Some(Error::Break)
786 } else if errs & RXE_PARITY != 0 {
787 Some(Error::Parity)
788 } else if errs & RXE_FRAMING != 0 {
789 Some(Error::Framing)
790 } else {
791 None
792 }
793 }
794}
795
796impl<'d> BufferedUartTx<'d> {
797 fn new_inner<T: Instance>(
798 _peri: Peri<'d, T>,
799 tx: Option<Peri<'d, AnyPin>>,
800 cts: Option<Peri<'d, AnyPin>>,
801 tx_buffer: &'d mut [u8],
802 config: Config,
803 ) -> Result<Self, ConfigError> {
804 let mut this = Self {
805 info: T::info(),
806 state: T::buffered_state(),
807 tx,
808 cts,
809 reborrowed: false,
810 };
811
812 this.enable_and_configure(tx_buffer, &config)?;
813
814 Ok(this)
815 }
816
817 async fn write_inner(&self, buf: &[u8]) -> Result<usize, Error> {
818 poll_fn(move |cx| {
819 let state = self.state;
820
821 if buf.is_empty() {
822 return Poll::Ready(Ok(0));
823 }
824
825 let mut tx_writer = unsafe { state.tx_buf.writer() };
826 let n = tx_writer.push(|data| {
827 let n = data.len().min(buf.len());
828 data[..n].copy_from_slice(&buf[..n]);
829 n
830 });
831
832 if n == 0 {
833 state.tx_waker.register(cx.waker());
834 return Poll::Pending;
835 }
836
837 // The TX interrupt only triggers when the there was data in the
838 // FIFO and the number of bytes drops below a threshold. When the
839 // FIFO was empty we have to manually pend the interrupt to shovel
840 // TX data from the buffer into the FIFO.
841 self.info.interrupt.pend();
842 Poll::Ready(Ok(n))
843 })
844 .await
845 }
846
847 fn blocking_write_inner(&self, buffer: &[u8]) -> Result<usize, Error> {
848 let state = self.state;
849
850 loop {
851 let empty = state.tx_buf.is_empty();
852
853 // SAFETY: tx buf must be initialized if BufferedUartTx exists.
854 let mut tx_writer = unsafe { state.tx_buf.writer() };
855 let data = tx_writer.push_slice();
856
857 if !data.is_empty() {
858 let n = data.len().min(buffer.len());
859 data[..n].copy_from_slice(&buffer[..n]);
860 tx_writer.push_done(n);
861
862 if empty {
863 self.info.interrupt.pend();
864 }
865
866 return Ok(n);
867 }
868 }
869 }
870
871 async fn flush_inner(&self) -> Result<(), Error> {
872 poll_fn(move |cx| {
873 let state = self.state;
874
875 if !state.tx_buf.is_empty() {
876 state.tx_waker.register(cx.waker());
877 return Poll::Pending;
878 }
879
880 Poll::Ready(Ok(()))
881 })
882 .await
883 }
884
885 fn enable_and_configure(&mut self, tx_buffer: &'d mut [u8], config: &Config) -> Result<(), ConfigError> {
886 let info = self.info;
887 let state = self.state;
888
889 init_buffers(info, state, Some(tx_buffer), None);
890 super::enable(info.regs);
891 super::configure(info, &state.state, config, false, false, true, self.cts.is_some())?;
892
893 info.interrupt.unpend();
894 unsafe { info.interrupt.enable() };
895
896 Ok(())
897 }
898}
899
900fn init_buffers<'d>(
901 info: &Info,
902 state: &BufferedState,
903 tx_buffer: Option<&'d mut [u8]>,
904 rx_buffer: Option<&'d mut [u8]>,
905) {
906 if let Some(tx_buffer) = tx_buffer {
907 let len = tx_buffer.len();
908 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
909 }
910
911 if let Some(rx_buffer) = rx_buffer {
912 let len = rx_buffer.len();
913 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
914 }
915
916 info.regs.cpu_int(0).imask().modify(|w| {
917 w.set_nerr(true);
918 w.set_frmerr(true);
919 w.set_parerr(true);
920 w.set_brkerr(true);
921 w.set_ovrerr(true);
922 });
923}
924
925fn on_interrupt(r: Regs, state: &'static BufferedState) {
926 let int = r.cpu_int(0).mis().read();
927
928 // Per https://github.com/embassy-rs/embassy/pull/1458, both buffered and unbuffered handlers may be bound.
929 if super::dma_enabled(r) {
930 return;
931 }
932
933 // RX
934 if state.rx_buf.is_available() {
935 // SAFETY: RX must have been initialized if RXE is set.
936 let mut rx_writer = unsafe { state.rx_buf.writer() };
937 let rx_buf = rx_writer.push_slice();
938 let mut n_read = 0;
939 let mut error = false;
940
941 for rx_byte in rx_buf {
942 let stat = r.stat().read();
943
944 if stat.rxfe() {
945 break;
946 }
947
948 let data = r.rxdata().read();
949
950 if (data.0 >> 8) != 0 {
951 // Cortex-M0 does not support atomic fetch_or, must do 2 operations.
952 critical_section::with(|_cs| {
953 let mut value = state.rx_error.load(Ordering::Relaxed);
954 value |= (data.0 >> 8) as u8;
955 state.rx_error.store(value, Ordering::Relaxed);
956 });
957 error = true;
958
959 // only fill the buffer with valid characters. the current character is fine
960 // if the error is an overrun, but if we add it to the buffer we'll report
961 // the overrun one character too late. drop it instead and pretend we were
962 // a bit slower at draining the rx fifo than we actually were.
963 // this is consistent with blocking uart error reporting.
964 break;
965 }
966
967 *rx_byte = data.data();
968 n_read += 1;
969 }
970
971 if n_read > 0 {
972 rx_writer.push_done(n_read);
973 state.rx_waker.wake();
974 } else if error {
975 state.rx_waker.wake();
976 }
977
978 // Disable any further RX interrupts when the buffer becomes full or
979 // errors have occurred. This lets us buffer additional errors in the
980 // fifo without needing more error storage locations, and most applications
981 // will want to do a full reset of their uart state anyway once an error
982 // has happened.
983 if state.rx_buf.is_full() || error {
984 r.cpu_int(0).imask().modify(|w| {
985 w.set_rxint(false);
986 w.set_rtout(false);
987 });
988 }
989 }
990
991 if int.eot() {
992 r.cpu_int(0).imask().modify(|w| {
993 w.set_eot(false);
994 });
995
996 r.cpu_int(0).iclr().write(|w| {
997 w.set_eot(true);
998 });
999
1000 state.tx_waker.wake();
1001 }
1002
1003 // TX
1004 if state.tx_buf.is_available() {
1005 // SAFETY: TX must have been initialized if TXE is set.
1006 let mut tx_reader = unsafe { state.tx_buf.reader() };
1007 let buf = tx_reader.pop_slice();
1008 let mut n_written = 0;
1009
1010 for tx_byte in buf.iter_mut() {
1011 let stat = r.stat().read();
1012
1013 if stat.txff() {
1014 break;
1015 }
1016
1017 r.txdata().write(|w| {
1018 w.set_data(*tx_byte);
1019 });
1020 n_written += 1;
1021 }
1022
1023 if n_written > 0 {
1024 // EOT will wake.
1025 r.cpu_int(0).imask().modify(|w| {
1026 w.set_eot(true);
1027 });
1028
1029 tx_reader.pop_done(n_written);
1030 }
1031 }
1032
1033 // Clear TX and error interrupt flags
1034 // RX interrupt flags are cleared by writing to ICLR.
1035 let mis = r.cpu_int(0).mis().read();
1036 r.cpu_int(0).iclr().write(|w| {
1037 w.set_nerr(mis.nerr());
1038 w.set_frmerr(mis.frmerr());
1039 w.set_parerr(mis.parerr());
1040 w.set_brkerr(mis.brkerr());
1041 w.set_ovrerr(mis.ovrerr());
1042 });
1043
1044 // Errors
1045 if mis.nerr() {
1046 warn!("Noise error");
1047 }
1048 if mis.frmerr() {
1049 warn!("Framing error");
1050 }
1051 if mis.parerr() {
1052 warn!("Parity error");
1053 }
1054 if mis.brkerr() {
1055 warn!("Break error");
1056 }
1057 if mis.ovrerr() {
1058 warn!("Overrun error");
1059 }
1060}
diff --git a/embassy-mspm0/src/uart.rs b/embassy-mspm0/src/uart/mod.rs
index bc1d2e343..6599cea06 100644
--- a/embassy-mspm0/src/uart.rs
+++ b/embassy-mspm0/src/uart/mod.rs
@@ -1,8 +1,11 @@
1#![macro_use] 1#![macro_use]
2 2
3mod buffered;
4
3use core::marker::PhantomData; 5use core::marker::PhantomData;
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 6use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
5 7
8pub use buffered::*;
6use embassy_embedded_hal::SetConfig; 9use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralType; 10use embassy_hal_internal::PeripheralType;
8 11
@@ -128,8 +131,8 @@ pub struct Config {
128 // pub manchester: bool, 131 // pub manchester: bool,
129 132
130 // TODO: majority voting 133 // TODO: majority voting
131 134 /// If true: the built-in FIFO is enabled.
132 // TODO: fifo level select - need power domain info in metapac 135 pub fifo_enable: bool,
133 136
134 // TODO: glitch suppression 137 // TODO: glitch suppression
135 /// If true: invert TX pin signal values (V<sub>DD</sub> = 0/mark, Gnd = 1/idle). 138 /// If true: invert TX pin signal values (V<sub>DD</sub> = 0/mark, Gnd = 1/idle).
@@ -169,6 +172,7 @@ impl Default for Config {
169 msb_order: BitOrder::LsbFirst, 172 msb_order: BitOrder::LsbFirst,
170 loop_back_enable: false, 173 loop_back_enable: false,
171 // manchester: false, 174 // manchester: false,
175 fifo_enable: false,
172 invert_tx: false, 176 invert_tx: false,
173 invert_rx: false, 177 invert_rx: false,
174 invert_rts: false, 178 invert_rts: false,
@@ -185,7 +189,7 @@ impl Default for Config {
185/// 189///
186/// ### Notes on [`embedded_io::Read`] 190/// ### Notes on [`embedded_io::Read`]
187/// 191///
188/// `embedded_io::Read` requires guarantees that the base [`UartRx`] cannot provide. 192/// [`embedded_io::Read`] requires guarantees that the base [`UartRx`] cannot provide.
189/// 193///
190/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] 194/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
191/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. 195/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
@@ -199,8 +203,7 @@ impl<'d, M: Mode> SetConfig for Uart<'d, M> {
199 type ConfigError = ConfigError; 203 type ConfigError = ConfigError;
200 204
201 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { 205 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
202 self.tx.set_config(config)?; 206 self.set_config(config)
203 self.rx.set_config(config)
204 } 207 }
205} 208}
206 209
@@ -236,6 +239,12 @@ impl core::fmt::Display for Error {
236 239
237impl core::error::Error for Error {} 240impl core::error::Error for Error {}
238 241
242impl embedded_io::Error for Error {
243 fn kind(&self) -> embedded_io::ErrorKind {
244 embedded_io::ErrorKind::Other
245 }
246}
247
239/// Rx-only UART Driver. 248/// Rx-only UART Driver.
240/// 249///
241/// Can be obtained from [`Uart::split`], or can be constructed independently, 250/// Can be obtained from [`Uart::split`], or can be constructed independently,
@@ -260,7 +269,7 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
260impl<'d> UartRx<'d, Blocking> { 269impl<'d> UartRx<'d, Blocking> {
261 /// Create a new rx-only UART with no hardware flow control. 270 /// Create a new rx-only UART with no hardware flow control.
262 /// 271 ///
263 /// Useful if you only want Uart Rx. It saves 1 pin . 272 /// Useful if you only want Uart Rx. It saves 1 pin.
264 pub fn new_blocking<T: Instance>( 273 pub fn new_blocking<T: Instance>(
265 peri: Peri<'d, T>, 274 peri: Peri<'d, T>,
266 rx: Peri<'d, impl RxPin<T>>, 275 rx: Peri<'d, impl RxPin<T>>,
@@ -286,19 +295,6 @@ impl<'d> UartRx<'d, Blocking> {
286} 295}
287 296
288impl<'d, M: Mode> UartRx<'d, M> { 297impl<'d, M: Mode> UartRx<'d, M> {
289 /// Reconfigure the driver
290 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
291 if let Some(ref rx) = self.rx {
292 rx.update_pf(config.rx_pf());
293 }
294
295 if let Some(ref rts) = self.rts {
296 rts.update_pf(config.rts_pf());
297 }
298
299 reconfigure(self.info, self.state, config)
300 }
301
302 /// Perform a blocking read into `buffer` 298 /// Perform a blocking read into `buffer`
303 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 299 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
304 let r = self.info.regs; 300 let r = self.info.regs;
@@ -315,6 +311,19 @@ impl<'d, M: Mode> UartRx<'d, M> {
315 Ok(()) 311 Ok(())
316 } 312 }
317 313
314 /// Reconfigure the driver
315 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
316 if let Some(ref rx) = self.rx {
317 rx.update_pf(config.rx_pf());
318 }
319
320 if let Some(ref rts) = self.rts {
321 rts.update_pf(config.rts_pf());
322 }
323
324 reconfigure(self.info, self.state, config)
325 }
326
318 /// Set baudrate 327 /// Set baudrate
319 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { 328 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
320 set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate) 329 set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate)
@@ -378,19 +387,6 @@ impl<'d> UartTx<'d, Blocking> {
378} 387}
379 388
380impl<'d, M: Mode> UartTx<'d, M> { 389impl<'d, M: Mode> UartTx<'d, M> {
381 /// Reconfigure the driver
382 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
383 if let Some(ref tx) = self.tx {
384 tx.update_pf(config.tx_pf());
385 }
386
387 if let Some(ref cts) = self.cts {
388 cts.update_pf(config.cts_pf());
389 }
390
391 reconfigure(self.info, self.state, config)
392 }
393
394 /// Perform a blocking UART write 390 /// Perform a blocking UART write
395 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 391 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
396 let r = self.info.regs; 392 let r = self.info.regs;
@@ -427,6 +423,24 @@ impl<'d, M: Mode> UartTx<'d, M> {
427 }); 423 });
428 } 424 }
429 425
426 /// Check if UART is busy.
427 pub fn busy(&self) -> bool {
428 busy(self.info.regs)
429 }
430
431 /// Reconfigure the driver
432 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
433 if let Some(ref tx) = self.tx {
434 tx.update_pf(config.tx_pf());
435 }
436
437 if let Some(ref cts) = self.cts {
438 cts.update_pf(config.cts_pf());
439 }
440
441 reconfigure(self.info, self.state, config)
442 }
443
430 /// Set baudrate 444 /// Set baudrate
431 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { 445 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
432 set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate) 446 set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate)
@@ -489,6 +503,11 @@ impl<'d, M: Mode> Uart<'d, M> {
489 self.tx.blocking_flush() 503 self.tx.blocking_flush()
490 } 504 }
491 505
506 /// Check if UART is busy.
507 pub fn busy(&self) -> bool {
508 self.tx.busy()
509 }
510
492 /// Perform a blocking read into `buffer` 511 /// Perform a blocking read into `buffer`
493 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 512 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
494 self.rx.blocking_read(buffer) 513 self.rx.blocking_read(buffer)
@@ -508,6 +527,12 @@ impl<'d, M: Mode> Uart<'d, M> {
508 (&mut self.tx, &mut self.rx) 527 (&mut self.tx, &mut self.rx)
509 } 528 }
510 529
530 /// Reconfigure the driver
531 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
532 self.tx.set_config(config)?;
533 self.rx.set_config(config)
534 }
535
511 /// Send break character 536 /// Send break character
512 pub fn send_break(&self) { 537 pub fn send_break(&self) {
513 self.tx.send_break(); 538 self.tx.send_break();
@@ -557,8 +582,16 @@ pub(crate) struct Info {
557} 582}
558 583
559pub(crate) struct State { 584pub(crate) struct State {
560 /// The clock rate of the UART. This might be configured. 585 /// The clock rate of the UART in Hz.
561 pub(crate) clock: AtomicU32, 586 clock: AtomicU32,
587}
588
589impl State {
590 pub const fn new() -> Self {
591 Self {
592 clock: AtomicU32::new(0),
593 }
594 }
562} 595}
563 596
564impl<'d, M: Mode> UartRx<'d, M> { 597impl<'d, M: Mode> UartRx<'d, M> {
@@ -746,7 +779,8 @@ fn configure(
746 779
747 info.regs.ctl0().modify(|w| { 780 info.regs.ctl0().modify(|w| {
748 w.set_lbe(config.loop_back_enable); 781 w.set_lbe(config.loop_back_enable);
749 w.set_rxe(enable_rx); 782 // Errata UART_ERR_02, must set RXE to allow use of EOT.
783 w.set_rxe(enable_rx | enable_tx);
750 w.set_txe(enable_tx); 784 w.set_txe(enable_tx);
751 // RXD_OUT_EN and TXD_OUT_EN? 785 // RXD_OUT_EN and TXD_OUT_EN?
752 w.set_menc(false); 786 w.set_menc(false);
@@ -754,13 +788,18 @@ fn configure(
754 w.set_rtsen(enable_rts); 788 w.set_rtsen(enable_rts);
755 w.set_ctsen(enable_cts); 789 w.set_ctsen(enable_cts);
756 // oversampling is set later 790 // oversampling is set later
757 // TODO: config 791 w.set_fen(config.fifo_enable);
758 w.set_fen(false);
759 // TODO: config 792 // TODO: config
760 w.set_majvote(false); 793 w.set_majvote(false);
761 w.set_msbfirst(matches!(config.msb_order, BitOrder::MsbFirst)); 794 w.set_msbfirst(matches!(config.msb_order, BitOrder::MsbFirst));
762 }); 795 });
763 796
797 info.regs.ifls().modify(|w| {
798 // TODO: Need power domain info for other options.
799 w.set_txiflsel(vals::Iflssel::AT_LEAST_ONE);
800 w.set_rxiflsel(vals::Iflssel::AT_LEAST_ONE);
801 });
802
764 info.regs.lcrh().modify(|w| { 803 info.regs.lcrh().modify(|w| {
765 let eps = if matches!(config.parity, Parity::ParityEven) { 804 let eps = if matches!(config.parity, Parity::ParityEven) {
766 vals::Eps::EVEN 805 vals::Eps::EVEN
@@ -1021,9 +1060,29 @@ fn read_with_error(r: Regs) -> Result<u8, Error> {
1021 Ok(rx.data()) 1060 Ok(rx.data())
1022} 1061}
1023 1062
1063/// This function assumes CTL0.ENABLE is set (for errata cases).
1064fn busy(r: Regs) -> bool {
1065 // Errata UART_ERR_08
1066 if cfg!(any(
1067 mspm0g151x, mspm0g351x, mspm0l110x, mspm0l130x, mspm0l134x, mspm0c110x,
1068 )) {
1069 let stat = r.stat().read();
1070 // "Poll TXFIFO status and the CTL0.ENABLE register bit to identify BUSY status."
1071 !stat.txfe()
1072 } else {
1073 r.stat().read().busy()
1074 }
1075}
1076
1077// TODO: Implement when dma uart is implemented.
1078fn dma_enabled(_r: Regs) -> bool {
1079 false
1080}
1081
1024pub(crate) trait SealedInstance { 1082pub(crate) trait SealedInstance {
1025 fn info() -> &'static Info; 1083 fn info() -> &'static Info;
1026 fn state() -> &'static State; 1084 fn state() -> &'static State;
1085 fn buffered_state() -> &'static BufferedState;
1027} 1086}
1028 1087
1029macro_rules! impl_uart_instance { 1088macro_rules! impl_uart_instance {
@@ -1041,12 +1100,16 @@ macro_rules! impl_uart_instance {
1041 } 1100 }
1042 1101
1043 fn state() -> &'static crate::uart::State { 1102 fn state() -> &'static crate::uart::State {
1044 use crate::interrupt::typelevel::Interrupt;
1045 use crate::uart::State; 1103 use crate::uart::State;
1046 1104
1047 static STATE: State = State { 1105 static STATE: State = State::new();
1048 clock: core::sync::atomic::AtomicU32::new(0), 1106 &STATE
1049 }; 1107 }
1108
1109 fn buffered_state() -> &'static crate::uart::BufferedState {
1110 use crate::uart::BufferedState;
1111
1112 static STATE: BufferedState = BufferedState::new();
1050 &STATE 1113 &STATE
1051 } 1114 }
1052 } 1115 }
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index 01f57c4e2..293791d34 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -10,23 +10,52 @@ critical-section = "1.1.2"
10embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 10embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
11embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 11embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
12defmt = { version = "1", optional = true } 12defmt = { version = "1", optional = true }
13log = { version = "0.4.27", optional = true }
14embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
15embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true }
16embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
13 17
14## Chip dependencies 18## Chip dependencies
15lpc55-pac = { version = "0.5.0", optional = true } 19lpc55-pac = { version = "0.5.0", optional = true }
20nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
21
22imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
23
24[build-dependencies]
25cfg_aliases = "0.2.1"
26nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true }
27proc-macro2 = "1.0.95"
28quote = "1.0.15"
16 29
17[features] 30[features]
18default = ["rt"] 31default = ["rt"]
19# Enable PACs as optional dependencies, since some chip families will use different pac crates. 32# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
20rt = ["lpc55-pac?/rt"] 33rt = ["lpc55-pac?/rt", "nxp-pac?/rt"]
21 34
22## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 35## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
23defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"] 36defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
24 37
38log = ["dep:log"]
39
40## Use Periodic Interrupt Timer (PIT) as the time driver for `embassy-time`, with a tick rate of 1 MHz
41time-driver-pit = ["_time_driver", "embassy-time?/tick-hz-1_000_000"]
42
25## Reexport the PAC for the currently enabled chip at `embassy_nxp::pac` (unstable) 43## Reexport the PAC for the currently enabled chip at `embassy_nxp::pac` (unstable)
26unstable-pac = [] 44unstable-pac = []
27# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 45# This is unstable because semver-minor (non-breaking) releases of embassy-nxp may major-bump (breaking) the PAC version.
28# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 46# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
29# There are no plans to make this stable. 47# There are no plans to make this stable.
30 48
49## internal use only
50#
51# This feature is unfortunately a hack around the fact that cfg_aliases cannot apply to the buildscript
52# that creates the aliases.
53_rt1xxx = []
54
55# A timer driver is enabled.
56_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
57
31#! ### Chip selection features 58#! ### Chip selection features
32lpc55 = ["lpc55-pac"] 59lpc55 = ["dep:lpc55-pac"]
60mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
61mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]
diff --git a/embassy-nxp/build.rs b/embassy-nxp/build.rs
new file mode 100644
index 000000000..f3c062c87
--- /dev/null
+++ b/embassy-nxp/build.rs
@@ -0,0 +1,138 @@
1use std::io::Write;
2use std::path::{Path, PathBuf};
3use std::process::Command;
4use std::{env, fs};
5
6use cfg_aliases::cfg_aliases;
7#[cfg(feature = "_rt1xxx")]
8use nxp_pac::metadata;
9#[allow(unused)]
10use proc_macro2::TokenStream;
11#[allow(unused)]
12use quote::quote;
13
14#[path = "./build_common.rs"]
15mod common;
16
17fn main() {
18 let mut cfgs = common::CfgSet::new();
19 common::set_target_cfgs(&mut cfgs);
20
21 let chip_name = match env::vars()
22 .map(|(a, _)| a)
23 .filter(|x| x.starts_with("CARGO_FEATURE_MIMXRT") || x.starts_with("CARGO_FEATURE_LPC"))
24 .get_one()
25 {
26 Ok(x) => x,
27 Err(GetOneError::None) => panic!("No mimxrt/lpc Cargo feature enabled"),
28 Err(GetOneError::Multiple) => panic!("Multiple mimxrt/lpc Cargo features enabled"),
29 }
30 .strip_prefix("CARGO_FEATURE_")
31 .unwrap()
32 .to_ascii_lowercase();
33
34 cfg_aliases! {
35 rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
36 gpio1: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
37 gpio2: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
38 gpio3: { feature = "mimxrt1062" },
39 gpio4: { feature = "mimxrt1062" },
40 gpio5: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
41 }
42
43 eprintln!("chip: {chip_name}");
44
45 generate_code();
46}
47
48#[cfg(feature = "_rt1xxx")]
49fn generate_iomuxc() -> TokenStream {
50 use proc_macro2::{Ident, Span};
51
52 let pads = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
53 let name = Ident::new(&registers.name, Span::call_site());
54 let address = registers.pad_ctl;
55
56 quote! {
57 pub const #name: u32 = #address;
58 }
59 });
60
61 let muxes = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| {
62 let name = Ident::new(&registers.name, Span::call_site());
63 let address = registers.mux_ctl;
64
65 quote! {
66 pub const #name: u32 = #address;
67 }
68 });
69
70 quote! {
71 pub mod iomuxc {
72 pub mod pads {
73 #(#pads)*
74 }
75
76 pub mod muxes {
77 #(#muxes)*
78 }
79 }
80 }
81}
82
83fn generate_code() {
84 #[allow(unused)]
85 use std::fmt::Write;
86
87 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
88 #[allow(unused_mut)]
89 let mut output = String::new();
90
91 #[cfg(feature = "_rt1xxx")]
92 writeln!(&mut output, "{}", generate_iomuxc()).unwrap();
93
94 let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
95 fs::write(&out_file, output).unwrap();
96 rustfmt(&out_file);
97}
98
99/// rustfmt a given path.
100/// Failures are logged to stderr and ignored.
101fn rustfmt(path: impl AsRef<Path>) {
102 let path = path.as_ref();
103 match Command::new("rustfmt").args([path]).output() {
104 Err(e) => {
105 eprintln!("failed to exec rustfmt {:?}: {:?}", path, e);
106 }
107 Ok(out) => {
108 if !out.status.success() {
109 eprintln!("rustfmt {:?} failed:", path);
110 eprintln!("=== STDOUT:");
111 std::io::stderr().write_all(&out.stdout).unwrap();
112 eprintln!("=== STDERR:");
113 std::io::stderr().write_all(&out.stderr).unwrap();
114 }
115 }
116 }
117}
118
119enum GetOneError {
120 None,
121 Multiple,
122}
123
124trait IteratorExt: Iterator {
125 fn get_one(self) -> Result<Self::Item, GetOneError>;
126}
127
128impl<T: Iterator> IteratorExt for T {
129 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
130 match self.next() {
131 None => Err(GetOneError::None),
132 Some(res) => match self.next() {
133 Some(_) => Err(GetOneError::Multiple),
134 None => Ok(res),
135 },
136 }
137 }
138}
diff --git a/embassy-nxp/build_common.rs b/embassy-nxp/build_common.rs
new file mode 100644
index 000000000..4f24e6d37
--- /dev/null
+++ b/embassy-nxp/build_common.rs
@@ -0,0 +1,94 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11
12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
13/// them (`cargo:rust-check-cfg=cfg(X)`).
14#[derive(Debug)]
15pub struct CfgSet {
16 enabled: HashSet<String>,
17 declared: HashSet<String>,
18}
19
20impl CfgSet {
21 pub fn new() -> Self {
22 Self {
23 enabled: HashSet::new(),
24 declared: HashSet::new(),
25 }
26 }
27
28 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
29 ///
30 /// All configs that can potentially be enabled should be unconditionally declared using
31 /// [`Self::declare()`].
32 pub fn enable(&mut self, cfg: impl AsRef<str>) {
33 if self.enabled.insert(cfg.as_ref().to_owned()) {
34 println!("cargo:rustc-cfg={}", cfg.as_ref());
35 }
36 }
37
38 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
39 for cfg in cfgs.iter() {
40 self.enable(cfg.as_ref());
41 }
42 }
43
44 /// Declare a valid config for conditional compilation, without enabling it.
45 ///
46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
48 if self.declared.insert(cfg.as_ref().to_owned()) {
49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
50 }
51 }
52
53 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
54 for cfg in cfgs.iter() {
55 self.declare(cfg.as_ref());
56 }
57 }
58
59 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
60 let cfg = cfg.into();
61 if enable {
62 self.enable(cfg.clone());
63 }
64 self.declare(cfg);
65 }
66}
67
68/// Sets configs that describe the target platform.
69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
70 let target = env::var("TARGET").unwrap();
71
72 if target.starts_with("thumbv6m-") {
73 cfgs.enable_all(&["cortex_m", "armv6m"]);
74 } else if target.starts_with("thumbv7m-") {
75 cfgs.enable_all(&["cortex_m", "armv7m"]);
76 } else if target.starts_with("thumbv7em-") {
77 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
78 } else if target.starts_with("thumbv8m.base") {
79 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
80 } else if target.starts_with("thumbv8m.main") {
81 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
82 }
83 cfgs.declare_all(&[
84 "cortex_m",
85 "armv6m",
86 "armv7m",
87 "armv7em",
88 "armv8m",
89 "armv8m_base",
90 "armv8m_main",
91 ]);
92
93 cfgs.set("has_fpu", target.ends_with("-eabihf"));
94}
diff --git a/embassy-nxp/src/chips/mimxrt1011.rs b/embassy-nxp/src/chips/mimxrt1011.rs
new file mode 100644
index 000000000..a74d953fc
--- /dev/null
+++ b/embassy-nxp/src/chips/mimxrt1011.rs
@@ -0,0 +1,113 @@
1// This must be imported so that __preinit is defined.
2use imxrt_rt as _;
3pub use nxp_pac as pac;
4
5embassy_hal_internal::peripherals! {
6 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
7 // peripheral types (e.g. I2C).
8 GPIO_00,
9 GPIO_01,
10 GPIO_02,
11 GPIO_03,
12 GPIO_04,
13 GPIO_05,
14 GPIO_06,
15 GPIO_07,
16 GPIO_08,
17 GPIO_09,
18 GPIO_10,
19 GPIO_11,
20 GPIO_12,
21 GPIO_13,
22 GPIO_AD_00,
23 GPIO_AD_01,
24 GPIO_AD_02,
25 GPIO_AD_03,
26 GPIO_AD_04,
27 GPIO_AD_05,
28 GPIO_AD_06,
29 GPIO_AD_07,
30 GPIO_AD_08,
31 GPIO_AD_09,
32 GPIO_AD_10,
33 GPIO_AD_11,
34 GPIO_AD_12,
35 GPIO_AD_13,
36 GPIO_AD_14,
37 GPIO_SD_00,
38 GPIO_SD_01,
39 GPIO_SD_02,
40 GPIO_SD_03,
41 GPIO_SD_04,
42 GPIO_SD_05,
43 GPIO_SD_06,
44 GPIO_SD_07,
45 GPIO_SD_08,
46 GPIO_SD_09,
47 GPIO_SD_10,
48 GPIO_SD_11,
49 GPIO_SD_12,
50 GPIO_SD_13,
51 PMIC_ON_REQ,
52}
53
54impl_gpio! {
55 // GPIO Bank 1
56 GPIO_00(Gpio1, 0);
57 GPIO_01(Gpio1, 1);
58 GPIO_02(Gpio1, 2);
59 GPIO_03(Gpio1, 3);
60 GPIO_04(Gpio1, 4);
61 GPIO_05(Gpio1, 5);
62 GPIO_06(Gpio1, 6);
63 GPIO_07(Gpio1, 7);
64 GPIO_08(Gpio1, 8);
65 GPIO_09(Gpio1, 9);
66 GPIO_10(Gpio1, 10);
67 GPIO_11(Gpio1, 11);
68 GPIO_12(Gpio1, 12);
69 GPIO_13(Gpio1, 13);
70 GPIO_AD_00(Gpio1, 14);
71 GPIO_AD_01(Gpio1, 15);
72 GPIO_AD_02(Gpio1, 16);
73 GPIO_AD_03(Gpio1, 17);
74 GPIO_AD_04(Gpio1, 18);
75 GPIO_AD_05(Gpio1, 19);
76 GPIO_AD_06(Gpio1, 20);
77 GPIO_AD_07(Gpio1, 21);
78 GPIO_AD_08(Gpio1, 22);
79 GPIO_AD_09(Gpio1, 23);
80 GPIO_AD_10(Gpio1, 24);
81 GPIO_AD_11(Gpio1, 25);
82 GPIO_AD_12(Gpio1, 26);
83 GPIO_AD_13(Gpio1, 27);
84 GPIO_AD_14(Gpio1, 28);
85
86 // GPIO Bank 2
87 GPIO_SD_00(Gpio2, 0);
88 GPIO_SD_01(Gpio2, 1);
89 GPIO_SD_02(Gpio2, 2);
90 GPIO_SD_03(Gpio2, 3);
91 GPIO_SD_04(Gpio2, 4);
92 GPIO_SD_05(Gpio2, 5);
93 GPIO_SD_06(Gpio2, 6);
94 GPIO_SD_07(Gpio2, 7);
95 GPIO_SD_08(Gpio2, 8);
96 GPIO_SD_09(Gpio2, 9);
97 GPIO_SD_10(Gpio2, 10);
98 GPIO_SD_11(Gpio2, 11);
99 GPIO_SD_12(Gpio2, 12);
100 GPIO_SD_13(Gpio2, 13);
101
102 // GPIO Bank 5
103 PMIC_ON_REQ(Gpio5, 0);
104}
105
106pub(crate) mod _generated {
107 #![allow(dead_code)]
108 #![allow(unused_imports)]
109 #![allow(non_snake_case)]
110 #![allow(missing_docs)]
111
112 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
113}
diff --git a/embassy-nxp/src/chips/mimxrt1062.rs b/embassy-nxp/src/chips/mimxrt1062.rs
new file mode 100644
index 000000000..ef153bd66
--- /dev/null
+++ b/embassy-nxp/src/chips/mimxrt1062.rs
@@ -0,0 +1,282 @@
1// This must be imported so that __preinit is defined.
2use imxrt_rt as _;
3pub use nxp_pac as pac;
4
5embassy_hal_internal::peripherals! {
6 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
7 // peripheral types (e.g. I2C).
8 GPIO_AD_B0_00,
9 GPIO_AD_B0_01,
10 GPIO_AD_B0_02,
11 GPIO_AD_B0_03,
12 GPIO_AD_B0_04,
13 GPIO_AD_B0_05,
14 GPIO_AD_B0_06,
15 GPIO_AD_B0_07,
16 GPIO_AD_B0_08,
17 GPIO_AD_B0_09,
18 GPIO_AD_B0_10,
19 GPIO_AD_B0_11,
20 GPIO_AD_B0_12,
21 GPIO_AD_B0_13,
22 GPIO_AD_B0_14,
23 GPIO_AD_B0_15,
24 GPIO_AD_B1_00,
25 GPIO_AD_B1_01,
26 GPIO_AD_B1_02,
27 GPIO_AD_B1_03,
28 GPIO_AD_B1_04,
29 GPIO_AD_B1_05,
30 GPIO_AD_B1_06,
31 GPIO_AD_B1_07,
32 GPIO_AD_B1_08,
33 GPIO_AD_B1_09,
34 GPIO_AD_B1_10,
35 GPIO_AD_B1_11,
36 GPIO_AD_B1_12,
37 GPIO_AD_B1_13,
38 GPIO_AD_B1_14,
39 GPIO_AD_B1_15,
40 GPIO_B0_00,
41 GPIO_B0_01,
42 GPIO_B0_02,
43 GPIO_B0_03,
44 GPIO_B0_04,
45 GPIO_B0_05,
46 GPIO_B0_06,
47 GPIO_B0_07,
48 GPIO_B0_08,
49 GPIO_B0_09,
50 GPIO_B0_10,
51 GPIO_B0_11,
52 GPIO_B0_12,
53 GPIO_B0_13,
54 GPIO_B0_14,
55 GPIO_B0_15,
56 GPIO_B1_00,
57 GPIO_B1_01,
58 GPIO_B1_02,
59 GPIO_B1_03,
60 GPIO_B1_04,
61 GPIO_B1_05,
62 GPIO_B1_06,
63 GPIO_B1_07,
64 GPIO_B1_08,
65 GPIO_B1_09,
66 GPIO_B1_10,
67 GPIO_B1_11,
68 GPIO_B1_12,
69 GPIO_B1_13,
70 GPIO_B1_14,
71 GPIO_B1_15,
72 GPIO_EMC_00,
73 GPIO_EMC_01,
74 GPIO_EMC_02,
75 GPIO_EMC_03,
76 GPIO_EMC_04,
77 GPIO_EMC_05,
78 GPIO_EMC_06,
79 GPIO_EMC_07,
80 GPIO_EMC_08,
81 GPIO_EMC_09,
82 GPIO_EMC_10,
83 GPIO_EMC_11,
84 GPIO_EMC_12,
85 GPIO_EMC_13,
86 GPIO_EMC_14,
87 GPIO_EMC_15,
88 GPIO_EMC_16,
89 GPIO_EMC_17,
90 GPIO_EMC_18,
91 GPIO_EMC_19,
92 GPIO_EMC_20,
93 GPIO_EMC_21,
94 GPIO_EMC_22,
95 GPIO_EMC_23,
96 GPIO_EMC_24,
97 GPIO_EMC_25,
98 GPIO_EMC_26,
99 GPIO_EMC_27,
100 GPIO_EMC_28,
101 GPIO_EMC_29,
102 GPIO_EMC_30,
103 GPIO_EMC_31,
104 GPIO_EMC_32,
105 GPIO_EMC_33,
106 GPIO_EMC_34,
107 GPIO_EMC_35,
108 GPIO_EMC_36,
109 GPIO_EMC_37,
110 GPIO_EMC_38,
111 GPIO_EMC_39,
112 GPIO_EMC_40,
113 GPIO_EMC_41,
114 GPIO_SD_B0_00,
115 GPIO_SD_B0_01,
116 GPIO_SD_B0_02,
117 GPIO_SD_B0_03,
118 GPIO_SD_B0_04,
119 GPIO_SD_B0_05,
120 GPIO_SD_B1_00,
121 GPIO_SD_B1_01,
122 GPIO_SD_B1_02,
123 GPIO_SD_B1_03,
124 GPIO_SD_B1_04,
125 GPIO_SD_B1_05,
126 GPIO_SD_B1_06,
127 GPIO_SD_B1_07,
128 GPIO_SD_B1_08,
129 GPIO_SD_B1_09,
130 GPIO_SD_B1_10,
131 GPIO_SD_B1_11,
132 WAKEUP,
133 PMIC_ON_REQ,
134 PMIC_STBY_REQ,
135}
136
137impl_gpio! {
138 // GPIO Bank 1
139 GPIO_AD_B0_00(Gpio1, 0);
140 GPIO_AD_B0_01(Gpio1, 1);
141 GPIO_AD_B0_02(Gpio1, 2);
142 GPIO_AD_B0_03(Gpio1, 3);
143 GPIO_AD_B0_04(Gpio1, 4);
144 GPIO_AD_B0_05(Gpio1, 5);
145 GPIO_AD_B0_06(Gpio1, 6);
146 GPIO_AD_B0_07(Gpio1, 7);
147 GPIO_AD_B0_08(Gpio1, 8);
148 GPIO_AD_B0_09(Gpio1, 9);
149 GPIO_AD_B0_10(Gpio1, 10);
150 GPIO_AD_B0_11(Gpio1, 11);
151 GPIO_AD_B0_12(Gpio1, 12);
152 GPIO_AD_B0_13(Gpio1, 13);
153 GPIO_AD_B0_14(Gpio1, 14);
154 GPIO_AD_B0_15(Gpio1, 15);
155 GPIO_AD_B1_00(Gpio1, 16);
156 GPIO_AD_B1_01(Gpio1, 17);
157 GPIO_AD_B1_02(Gpio1, 18);
158 GPIO_AD_B1_03(Gpio1, 19);
159 GPIO_AD_B1_04(Gpio1, 20);
160 GPIO_AD_B1_05(Gpio1, 21);
161 GPIO_AD_B1_06(Gpio1, 22);
162 GPIO_AD_B1_07(Gpio1, 23);
163 GPIO_AD_B1_08(Gpio1, 24);
164 GPIO_AD_B1_09(Gpio1, 25);
165 GPIO_AD_B1_10(Gpio1, 26);
166 GPIO_AD_B1_11(Gpio1, 27);
167 GPIO_AD_B1_12(Gpio1, 28);
168 GPIO_AD_B1_13(Gpio1, 29);
169 GPIO_AD_B1_14(Gpio1, 30);
170 GPIO_AD_B1_15(Gpio1, 31);
171
172 // GPIO Bank 2
173 GPIO_B0_00(Gpio2, 0);
174 GPIO_B0_01(Gpio2, 1);
175 GPIO_B0_02(Gpio2, 2);
176 GPIO_B0_03(Gpio2, 3);
177 GPIO_B0_04(Gpio2, 4);
178 GPIO_B0_05(Gpio2, 5);
179 GPIO_B0_06(Gpio2, 6);
180 GPIO_B0_07(Gpio2, 7);
181 GPIO_B0_08(Gpio2, 8);
182 GPIO_B0_09(Gpio2, 9);
183 GPIO_B0_10(Gpio2, 10);
184 GPIO_B0_11(Gpio2, 11);
185 GPIO_B0_12(Gpio2, 12);
186 GPIO_B0_13(Gpio2, 13);
187 GPIO_B0_14(Gpio2, 14);
188 GPIO_B0_15(Gpio2, 15);
189 GPIO_B1_00(Gpio2, 16);
190 GPIO_B1_01(Gpio2, 17);
191 GPIO_B1_02(Gpio2, 18);
192 GPIO_B1_03(Gpio2, 19);
193 GPIO_B1_04(Gpio2, 20);
194 GPIO_B1_05(Gpio2, 21);
195 GPIO_B1_06(Gpio2, 22);
196 GPIO_B1_07(Gpio2, 23);
197 GPIO_B1_08(Gpio2, 24);
198 GPIO_B1_09(Gpio2, 25);
199 GPIO_B1_10(Gpio2, 26);
200 GPIO_B1_11(Gpio2, 27);
201 GPIO_B1_12(Gpio2, 28);
202 GPIO_B1_13(Gpio2, 29);
203 GPIO_B1_14(Gpio2, 30);
204 GPIO_B1_15(Gpio2, 31);
205
206 // GPIO Bank 4 (EMC is 4, then 3)
207 GPIO_EMC_00(Gpio4, 0);
208 GPIO_EMC_01(Gpio4, 1);
209 GPIO_EMC_02(Gpio4, 2);
210 GPIO_EMC_03(Gpio4, 3);
211 GPIO_EMC_04(Gpio4, 4);
212 GPIO_EMC_05(Gpio4, 5);
213 GPIO_EMC_06(Gpio4, 6);
214 GPIO_EMC_07(Gpio4, 7);
215 GPIO_EMC_08(Gpio4, 8);
216 GPIO_EMC_09(Gpio4, 9);
217 GPIO_EMC_10(Gpio4, 10);
218 GPIO_EMC_11(Gpio4, 11);
219 GPIO_EMC_12(Gpio4, 12);
220 GPIO_EMC_13(Gpio4, 13);
221 GPIO_EMC_14(Gpio4, 14);
222 GPIO_EMC_15(Gpio4, 15);
223 GPIO_EMC_16(Gpio4, 16);
224 GPIO_EMC_17(Gpio4, 17);
225 GPIO_EMC_18(Gpio4, 18);
226 GPIO_EMC_19(Gpio4, 19);
227 GPIO_EMC_20(Gpio4, 20);
228 GPIO_EMC_21(Gpio4, 21);
229 GPIO_EMC_22(Gpio4, 22);
230 GPIO_EMC_23(Gpio4, 23);
231 GPIO_EMC_24(Gpio4, 24);
232 GPIO_EMC_25(Gpio4, 25);
233 GPIO_EMC_26(Gpio4, 26);
234 GPIO_EMC_27(Gpio4, 27);
235 GPIO_EMC_28(Gpio4, 28);
236 GPIO_EMC_29(Gpio4, 29);
237 GPIO_EMC_30(Gpio4, 30);
238 GPIO_EMC_31(Gpio4, 31);
239
240 // GPIO Bank 3
241 GPIO_EMC_32(Gpio3, 18);
242 GPIO_EMC_33(Gpio3, 19);
243 GPIO_EMC_34(Gpio3, 20);
244 GPIO_EMC_35(Gpio3, 21);
245 GPIO_EMC_36(Gpio3, 22);
246 GPIO_EMC_37(Gpio3, 23);
247 GPIO_EMC_38(Gpio3, 24);
248 GPIO_EMC_39(Gpio3, 25);
249 GPIO_EMC_40(Gpio3, 26);
250 GPIO_EMC_41(Gpio3, 27);
251 GPIO_SD_B0_00(Gpio3, 12);
252 GPIO_SD_B0_01(Gpio3, 13);
253 GPIO_SD_B0_02(Gpio3, 14);
254 GPIO_SD_B0_03(Gpio3, 15);
255 GPIO_SD_B0_04(Gpio3, 16);
256 GPIO_SD_B0_05(Gpio3, 17);
257 GPIO_SD_B1_00(Gpio3, 0);
258 GPIO_SD_B1_01(Gpio3, 1);
259 GPIO_SD_B1_02(Gpio3, 2);
260 GPIO_SD_B1_03(Gpio3, 3);
261 GPIO_SD_B1_04(Gpio3, 4);
262 GPIO_SD_B1_05(Gpio3, 5);
263 GPIO_SD_B1_06(Gpio3, 6);
264 GPIO_SD_B1_07(Gpio3, 7);
265 GPIO_SD_B1_08(Gpio3, 8);
266 GPIO_SD_B1_09(Gpio3, 9);
267 GPIO_SD_B1_10(Gpio3, 10);
268 GPIO_SD_B1_11(Gpio3, 11);
269
270 WAKEUP(Gpio5, 0);
271 PMIC_ON_REQ(Gpio5, 1);
272 PMIC_STBY_REQ(Gpio5, 2);
273}
274
275pub(crate) mod _generated {
276 #![allow(dead_code)]
277 #![allow(unused_imports)]
278 #![allow(non_snake_case)]
279 #![allow(missing_docs)]
280
281 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
282}
diff --git a/embassy-nxp/src/fmt.rs b/embassy-nxp/src/fmt.rs
new file mode 100644
index 000000000..27d41ace6
--- /dev/null
+++ b/embassy-nxp/src/fmt.rs
@@ -0,0 +1,284 @@
1//! Copied from embassy-rp
2
3#![macro_use]
4#![allow(unused)]
5
6use core::fmt::{Debug, Display, LowerHex};
7
8#[cfg(all(feature = "defmt", feature = "log"))]
9compile_error!("You may not enable both `defmt` and `log` features.");
10
11#[collapse_debuginfo(yes)]
12macro_rules! assert {
13 ($($x:tt)*) => {
14 {
15 #[cfg(not(feature = "defmt"))]
16 ::core::assert!($($x)*);
17 #[cfg(feature = "defmt")]
18 ::defmt::assert!($($x)*);
19 }
20 };
21}
22
23#[collapse_debuginfo(yes)]
24macro_rules! assert_eq {
25 ($($x:tt)*) => {
26 {
27 #[cfg(not(feature = "defmt"))]
28 ::core::assert_eq!($($x)*);
29 #[cfg(feature = "defmt")]
30 ::defmt::assert_eq!($($x)*);
31 }
32 };
33}
34
35#[collapse_debuginfo(yes)]
36macro_rules! assert_ne {
37 ($($x:tt)*) => {
38 {
39 #[cfg(not(feature = "defmt"))]
40 ::core::assert_ne!($($x)*);
41 #[cfg(feature = "defmt")]
42 ::defmt::assert_ne!($($x)*);
43 }
44 };
45}
46
47#[collapse_debuginfo(yes)]
48macro_rules! debug_assert {
49 ($($x:tt)*) => {
50 {
51 #[cfg(not(feature = "defmt"))]
52 ::core::debug_assert!($($x)*);
53 #[cfg(feature = "defmt")]
54 ::defmt::debug_assert!($($x)*);
55 }
56 };
57}
58
59#[collapse_debuginfo(yes)]
60macro_rules! debug_assert_eq {
61 ($($x:tt)*) => {
62 {
63 #[cfg(not(feature = "defmt"))]
64 ::core::debug_assert_eq!($($x)*);
65 #[cfg(feature = "defmt")]
66 ::defmt::debug_assert_eq!($($x)*);
67 }
68 };
69}
70
71#[collapse_debuginfo(yes)]
72macro_rules! debug_assert_ne {
73 ($($x:tt)*) => {
74 {
75 #[cfg(not(feature = "defmt"))]
76 ::core::debug_assert_ne!($($x)*);
77 #[cfg(feature = "defmt")]
78 ::defmt::debug_assert_ne!($($x)*);
79 }
80 };
81}
82
83#[collapse_debuginfo(yes)]
84macro_rules! todo {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::todo!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::todo!($($x)*);
91 }
92 };
93}
94
95#[collapse_debuginfo(yes)]
96macro_rules! unreachable {
97 ($($x:tt)*) => {
98 {
99 #[cfg(not(feature = "defmt"))]
100 ::core::unreachable!($($x)*);
101 #[cfg(feature = "defmt")]
102 ::defmt::unreachable!($($x)*);
103 }
104 };
105}
106
107#[collapse_debuginfo(yes)]
108macro_rules! unimplemented {
109 ($($x:tt)*) => {
110 {
111 #[cfg(not(feature = "defmt"))]
112 ::core::unimplemented!($($x)*);
113 #[cfg(feature = "defmt")]
114 ::defmt::unimplemented!($($x)*);
115 }
116 };
117}
118
119#[collapse_debuginfo(yes)]
120macro_rules! panic {
121 ($($x:tt)*) => {
122 {
123 #[cfg(not(feature = "defmt"))]
124 ::core::panic!($($x)*);
125 #[cfg(feature = "defmt")]
126 ::defmt::panic!($($x)*);
127 }
128 };
129}
130
131#[collapse_debuginfo(yes)]
132macro_rules! trace {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::trace!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::trace!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145#[collapse_debuginfo(yes)]
146macro_rules! debug {
147 ($s:literal $(, $x:expr)* $(,)?) => {
148 {
149 #[cfg(feature = "log")]
150 ::log::debug!($s $(, $x)*);
151 #[cfg(feature = "defmt")]
152 ::defmt::debug!($s $(, $x)*);
153 #[cfg(not(any(feature = "log", feature="defmt")))]
154 let _ = ($( & $x ),*);
155 }
156 };
157}
158
159#[collapse_debuginfo(yes)]
160macro_rules! info {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::info!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::info!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ = ($( & $x ),*);
169 }
170 };
171}
172
173#[collapse_debuginfo(yes)]
174macro_rules! warn {
175 ($s:literal $(, $x:expr)* $(,)?) => {
176 {
177 #[cfg(feature = "log")]
178 ::log::warn!($s $(, $x)*);
179 #[cfg(feature = "defmt")]
180 ::defmt::warn!($s $(, $x)*);
181 #[cfg(not(any(feature = "log", feature="defmt")))]
182 let _ = ($( & $x ),*);
183 }
184 };
185}
186
187#[collapse_debuginfo(yes)]
188macro_rules! error {
189 ($s:literal $(, $x:expr)* $(,)?) => {
190 {
191 #[cfg(feature = "log")]
192 ::log::error!($s $(, $x)*);
193 #[cfg(feature = "defmt")]
194 ::defmt::error!($s $(, $x)*);
195 #[cfg(not(any(feature = "log", feature="defmt")))]
196 let _ = ($( & $x ),*);
197 }
198 };
199}
200
201#[cfg(feature = "defmt")]
202#[collapse_debuginfo(yes)]
203macro_rules! unwrap {
204 ($($x:tt)*) => {
205 ::defmt::unwrap!($($x)*)
206 };
207}
208
209#[cfg(not(feature = "defmt"))]
210#[collapse_debuginfo(yes)]
211macro_rules! unwrap {
212 ($arg:expr) => {
213 match $crate::fmt::Try::into_result($arg) {
214 ::core::result::Result::Ok(t) => t,
215 ::core::result::Result::Err(e) => {
216 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
217 }
218 }
219 };
220 ($arg:expr, $($msg:expr),+ $(,)? ) => {
221 match $crate::fmt::Try::into_result($arg) {
222 ::core::result::Result::Ok(t) => t,
223 ::core::result::Result::Err(e) => {
224 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
225 }
226 }
227 }
228}
229
230#[derive(Debug, Copy, Clone, Eq, PartialEq)]
231pub struct NoneError;
232
233pub trait Try {
234 type Ok;
235 type Error;
236 fn into_result(self) -> Result<Self::Ok, Self::Error>;
237}
238
239impl<T> Try for Option<T> {
240 type Ok = T;
241 type Error = NoneError;
242
243 #[inline]
244 fn into_result(self) -> Result<T, NoneError> {
245 self.ok_or(NoneError)
246 }
247}
248
249impl<T, E> Try for Result<T, E> {
250 type Ok = T;
251 type Error = E;
252
253 #[inline]
254 fn into_result(self) -> Self {
255 self
256 }
257}
258
259pub(crate) struct Bytes<'a>(pub &'a [u8]);
260
261impl<'a> Debug for Bytes<'a> {
262 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
263 write!(f, "{:#02x?}", self.0)
264 }
265}
266
267impl<'a> Display for Bytes<'a> {
268 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
269 write!(f, "{:#02x?}", self.0)
270 }
271}
272
273impl<'a> LowerHex for Bytes<'a> {
274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275 write!(f, "{:#02x?}", self.0)
276 }
277}
278
279#[cfg(feature = "defmt")]
280impl<'a> defmt::Format for Bytes<'a> {
281 fn format(&self, fmt: defmt::Formatter) {
282 defmt::write!(fmt, "{:02x}", self.0)
283 }
284}
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
index 809903d97..3049cc12d 100644
--- a/embassy-nxp/src/gpio.rs
+++ b/embassy-nxp/src/gpio.rs
@@ -1,5 +1,7 @@
1//! General purpose input/output (GPIO) driver. 1//! General purpose input/output (GPIO) driver.
2#![macro_use]
2 3
3#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")] 4#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")]
5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
4mod inner; 6mod inner;
5pub use inner::*; 7pub use inner::*;
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs
index 94cd8b7f8..8f407bb3a 100644
--- a/embassy-nxp/src/gpio/lpc55.rs
+++ b/embassy-nxp/src/gpio/lpc55.rs
@@ -7,6 +7,7 @@ pub(crate) fn init() {
7 syscon_reg() 7 syscon_reg()
8 .ahbclkctrl0 8 .ahbclkctrl0
9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable()); 9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
10 info!("GPIO initialized");
10} 11}
11 12
12/// The GPIO pin level for pins set on "Digital" mode. 13/// The GPIO pin level for pins set on "Digital" mode.
diff --git a/embassy-nxp/src/gpio/rt1xxx.rs b/embassy-nxp/src/gpio/rt1xxx.rs
new file mode 100644
index 000000000..1d60a0d51
--- /dev/null
+++ b/embassy-nxp/src/gpio/rt1xxx.rs
@@ -0,0 +1,945 @@
1#![macro_use]
2
3use core::future::Future;
4use core::ops::Not;
5use core::pin::Pin as FuturePin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10use nxp_pac::gpio::vals::Icr;
11use nxp_pac::iomuxc::vals::Pus;
12
13use crate::chip::{mux_address, pad_address};
14use crate::pac::common::{Reg, RW};
15use crate::pac::gpio::Gpio;
16#[cfg(feature = "rt")]
17use crate::pac::interrupt;
18use crate::pac::iomuxc::regs::{Ctl, MuxCtl};
19use crate::pac::{self};
20
21/// The GPIO pin level for pins set on "Digital" mode.
22#[derive(Debug, Eq, PartialEq, Clone, Copy)]
23pub enum Level {
24 /// Logical low. Corresponds to 0V.
25 Low,
26 /// Logical high. Corresponds to VDD.
27 High,
28}
29
30impl From<bool> for Level {
31 fn from(val: bool) -> Self {
32 match val {
33 true => Self::High,
34 false => Self::Low,
35 }
36 }
37}
38
39impl From<Level> for bool {
40 fn from(level: Level) -> bool {
41 match level {
42 Level::Low => false,
43 Level::High => true,
44 }
45 }
46}
47
48impl Not for Level {
49 type Output = Self;
50
51 fn not(self) -> Self::Output {
52 match self {
53 Level::Low => Level::High,
54 Level::High => Level::Low,
55 }
56 }
57}
58
59/// Pull setting for a GPIO input set on "Digital" mode.
60#[derive(Debug, Clone, Copy, Eq, PartialEq)]
61pub enum Pull {
62 /// No pull.
63 None,
64
65 // TODO: What Does PUE::KEEPER mean here?
66
67 // 22 kOhm pull-up resistor.
68 Up22K,
69
70 // 47 kOhm pull-up resistor.
71 Up47K,
72
73 // 100 kOhm pull-up resistor.
74 Up100K,
75
76 // 100 kOhm pull-down resistor.
77 Down100K,
78}
79
80/// Drive strength of an output
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Drive {
84 Disabled,
85 _150R,
86 _75R,
87 _50R,
88 _37R,
89 _30R,
90 _25R,
91 _20R,
92}
93
94/// Slew rate of an output
95#[derive(Copy, Clone, Debug, Eq, PartialEq)]
96#[cfg_attr(feature = "defmt", derive(defmt::Format))]
97pub enum SlewRate {
98 Slow,
99
100 Fast,
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum Bank {
105 /// Bank 1
106 #[cfg(gpio1)]
107 Gpio1,
108
109 /// Bank 2
110 #[cfg(gpio2)]
111 Gpio2,
112
113 /// Bank 3
114 #[cfg(gpio3)]
115 Gpio3,
116
117 /// Bank 4
118 #[cfg(gpio4)]
119 Gpio4,
120
121 /// Bank 5
122 #[cfg(gpio5)]
123 Gpio5,
124}
125
126/// GPIO flexible pin.
127///
128/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
129/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
130/// mode.
131pub struct Flex<'d> {
132 pub(crate) pin: Peri<'d, AnyPin>,
133}
134
135impl<'d> Flex<'d> {
136 /// Wrap the pin in a `Flex`.
137 ///
138 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
139 /// before the pin is put into output mode.
140 #[inline]
141 pub fn new(pin: Peri<'d, impl Pin>) -> Self {
142 Self { pin: pin.into() }
143 }
144
145 /// Set the pin's pull.
146 #[inline]
147 pub fn set_pull(&mut self, pull: Pull) {
148 let (pke, pue, pus) = match pull {
149 Pull::None => (false, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
150 Pull::Up22K => (true, true, Pus::PUS_3_22K_OHM_PULL_UP),
151 Pull::Up47K => (true, true, Pus::PUS_1_47K_OHM_PULL_UP),
152 Pull::Up100K => (true, true, Pus::PUS_2_100K_OHM_PULL_UP),
153 Pull::Down100K => (true, true, Pus::PUS_0_100K_OHM_PULL_DOWN),
154 };
155
156 self.pin.pad().modify(|w| {
157 w.set_pke(pke);
158 w.set_pue(pue);
159 w.set_pus(pus);
160 });
161 }
162
163 // Set the pin's slew rate.
164 #[inline]
165 pub fn set_slewrate(&mut self, rate: SlewRate) {
166 self.pin.pad().modify(|w| {
167 w.set_sre(match rate {
168 SlewRate::Slow => false,
169 SlewRate::Fast => true,
170 });
171 });
172 }
173
174 /// Set the pin's Schmitt trigger.
175 #[inline]
176 pub fn set_schmitt(&mut self, enable: bool) {
177 self.pin.pad().modify(|w| {
178 w.set_hys(enable);
179 });
180 }
181
182 /// Put the pin into input mode.
183 ///
184 /// The pull setting is left unchanged.
185 #[inline]
186 pub fn set_as_input(&mut self) {
187 self.pin.mux().modify(|w| {
188 w.set_mux_mode(GPIO_MUX_MODE);
189 });
190
191 // Setting direction is RMW
192 critical_section::with(|_cs| {
193 self.pin.block().gdir().modify(|w| {
194 w.set_gdir(self.pin.pin_number() as usize, false);
195 });
196 })
197 }
198
199 /// Put the pin into output mode.
200 ///
201 /// The pin level will be whatever was set before (or low by default). If you want it to begin
202 /// at a specific level, call `set_high`/`set_low` on the pin first.
203 #[inline]
204 pub fn set_as_output(&mut self) {
205 self.pin.mux().modify(|w| {
206 w.set_mux_mode(GPIO_MUX_MODE);
207 });
208
209 // Setting direction is RMW
210 critical_section::with(|_cs| {
211 self.pin.block().gdir().modify(|w| {
212 w.set_gdir(self.pin.pin_number() as usize, true);
213 });
214 })
215 }
216
217 /// Put the pin into input + open-drain output mode.
218 ///
219 /// The hardware will drive the line low if you set it to low, and will leave it floating if you set
220 /// it to high, in which case you can read the input to figure out whether another device
221 /// is driving the line low.
222 ///
223 /// The pin level will be whatever was set before (or low by default). If you want it to begin
224 /// at a specific level, call `set_high`/`set_low` on the pin first.
225 ///
226 /// The internal weak pull-up and pull-down resistors will be disabled.
227 #[inline]
228 pub fn set_as_input_output(&mut self) {
229 self.pin.pad().modify(|w| {
230 w.set_ode(true);
231 });
232 }
233
234 /// Set the pin as "disconnected", ie doing nothing and consuming the lowest
235 /// amount of power possible.
236 ///
237 /// This is currently the same as [`Self::set_as_analog()`] but is semantically different
238 /// really. Drivers should `set_as_disconnected()` pins when dropped.
239 ///
240 /// Note that this also disables the pull-up and pull-down resistors.
241 #[inline]
242 pub fn set_as_disconnected(&mut self) {
243 self.pin.pad().modify(|w| {
244 w.set_ode(false);
245 w.set_pke(false);
246 w.set_pue(false);
247 w.set_pus(Pus::PUS_0_100K_OHM_PULL_DOWN);
248 });
249 }
250
251 /// Get whether the pin input level is high.
252 #[inline]
253 pub fn is_high(&self) -> bool {
254 self.pin.block().psr().read().psr(self.pin.pin_number() as usize)
255 }
256
257 /// Get whether the pin input level is low.
258 #[inline]
259 pub fn is_low(&self) -> bool {
260 !self.is_high()
261 }
262
263 /// Returns current pin level
264 #[inline]
265 pub fn get_level(&self) -> Level {
266 self.is_high().into()
267 }
268
269 /// Set the output as high.
270 #[inline]
271 pub fn set_high(&mut self) {
272 self.pin.block().dr_set().write(|w| {
273 w.set_dr_set(self.pin.pin_number() as usize, true);
274 });
275 }
276
277 /// Set the output as low.
278 #[inline]
279 pub fn set_low(&mut self) {
280 self.pin.block().dr_clear().write(|w| {
281 w.set_dr_clear(self.pin.pin_number() as usize, true);
282 });
283 }
284
285 /// Toggle pin output
286 #[inline]
287 pub fn toggle(&mut self) {
288 self.pin.block().dr_toggle().write(|w| {
289 w.set_dr_toggle(self.pin.pin_number() as usize, true);
290 });
291 }
292
293 /// Set the output level.
294 #[inline]
295 pub fn set_level(&mut self, level: Level) {
296 match level {
297 Level::Low => self.set_low(),
298 Level::High => self.set_high(),
299 }
300 }
301
302 /// Get the current pin output level.
303 #[inline]
304 pub fn get_output_level(&self) -> Level {
305 self.is_set_high().into()
306 }
307
308 /// Is the output level high?
309 ///
310 /// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_high`].
311 #[inline]
312 pub fn is_set_high(&self) -> bool {
313 self.pin.block().dr().read().dr(self.pin.pin_number() as usize)
314 }
315
316 /// Is the output level low?
317 ///
318 /// If the [`Flex`] is set as an input, then this is equivalent to [`Flex::is_low`].
319 #[inline]
320 pub fn is_set_low(&self) -> bool {
321 !self.is_set_high()
322 }
323
324 /// Wait until the pin is high. If it is already high, return immediately.
325 #[inline]
326 pub async fn wait_for_high(&mut self) {
327 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::High).await
328 }
329
330 /// Wait until the pin is low. If it is already low, return immediately.
331 #[inline]
332 pub async fn wait_for_low(&mut self) {
333 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::Low).await
334 }
335
336 /// Wait for the pin to undergo a transition from low to high.
337 #[inline]
338 pub async fn wait_for_rising_edge(&mut self) {
339 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::RisingEdge).await
340 }
341
342 /// Wait for the pin to undergo a transition from high to low.
343 #[inline]
344 pub async fn wait_for_falling_edge(&mut self) {
345 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::FallingEdge).await
346 }
347
348 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
349 #[inline]
350 pub async fn wait_for_any_edge(&mut self) {
351 InputFuture::new(self.pin.reborrow(), InterruptConfiguration::AnyEdge).await
352 }
353}
354
355impl<'d> Drop for Flex<'d> {
356 fn drop(&mut self) {
357 self.set_as_disconnected();
358 }
359}
360
361/// GPIO input driver.
362pub struct Input<'d> {
363 pin: Flex<'d>,
364}
365
366impl<'d> Input<'d> {
367 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
368 #[inline]
369 pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
370 let mut pin = Flex::new(pin);
371 pin.set_as_input();
372 pin.set_pull(pull);
373 Self { pin }
374 }
375
376 /// Get whether the pin input level is high.
377 #[inline]
378 pub fn is_high(&self) -> bool {
379 self.pin.is_high()
380 }
381
382 /// Get whether the pin input level is low.
383 #[inline]
384 pub fn is_low(&self) -> bool {
385 self.pin.is_low()
386 }
387
388 /// Get the current pin input level.
389 #[inline]
390 pub fn get_level(&self) -> Level {
391 self.pin.get_level()
392 }
393
394 /// Wait until the pin is high. If it is already high, return immediately.
395 #[inline]
396 pub async fn wait_for_high(&mut self) {
397 self.pin.wait_for_high().await
398 }
399
400 /// Wait until the pin is low. If it is already low, return immediately.
401 #[inline]
402 pub async fn wait_for_low(&mut self) {
403 self.pin.wait_for_low().await
404 }
405
406 /// Wait for the pin to undergo a transition from low to high.
407 #[inline]
408 pub async fn wait_for_rising_edge(&mut self) {
409 self.pin.wait_for_rising_edge().await
410 }
411
412 /// Wait for the pin to undergo a transition from high to low.
413 #[inline]
414 pub async fn wait_for_falling_edge(&mut self) {
415 self.pin.wait_for_falling_edge().await
416 }
417
418 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
419 #[inline]
420 pub async fn wait_for_any_edge(&mut self) {
421 self.pin.wait_for_any_edge().await
422 }
423}
424
425/// GPIO output driver.
426///
427/// Note that pins will **return to their floating state** when `Output` is dropped.
428/// If pins should retain their state indefinitely, either keep ownership of the
429/// `Output`, or pass it to [`core::mem::forget`].
430pub struct Output<'d> {
431 pin: Flex<'d>,
432}
433
434impl<'d> Output<'d> {
435 /// Create GPIO output driver for a [Pin] with the provided [Level] configuration.
436 #[inline]
437 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
438 let mut pin = Flex::new(pin);
439 pin.set_as_output();
440 pin.set_level(initial_output);
441 Self { pin }
442 }
443
444 /// Set the output as high.
445 #[inline]
446 pub fn set_high(&mut self) {
447 self.pin.set_high();
448 }
449
450 /// Set the output as low.
451 #[inline]
452 pub fn set_low(&mut self) {
453 self.pin.set_low();
454 }
455
456 /// Set the output level.
457 #[inline]
458 pub fn set_level(&mut self, level: Level) {
459 self.pin.set_level(level)
460 }
461
462 /// Is the output pin set as high?
463 #[inline]
464 pub fn is_set_high(&self) -> bool {
465 self.pin.is_set_high()
466 }
467
468 /// Is the output pin set as low?
469 #[inline]
470 pub fn is_set_low(&self) -> bool {
471 self.pin.is_set_low()
472 }
473
474 /// What level output is set to
475 #[inline]
476 pub fn get_output_level(&self) -> Level {
477 self.pin.get_output_level()
478 }
479
480 /// Toggle pin output
481 #[inline]
482 pub fn toggle(&mut self) {
483 self.pin.toggle();
484 }
485}
486
487/// GPIO output open-drain driver.
488///
489/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
490/// If pins should retain their state indefinitely, either keep ownership of the
491/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
492pub struct OutputOpenDrain<'d> {
493 pin: Flex<'d>,
494}
495
496impl<'d> OutputOpenDrain<'d> {
497 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level].
498 #[inline]
499 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
500 let mut pin = Flex::new(pin);
501 pin.set_level(initial_output);
502 pin.set_as_input_output();
503 Self { pin }
504 }
505
506 /// Get whether the pin input level is high.
507 #[inline]
508 pub fn is_high(&self) -> bool {
509 !self.pin.is_low()
510 }
511
512 /// Get whether the pin input level is low.
513 #[inline]
514 pub fn is_low(&self) -> bool {
515 self.pin.is_low()
516 }
517
518 /// Get the current pin input level.
519 #[inline]
520 pub fn get_level(&self) -> Level {
521 self.pin.get_level()
522 }
523
524 /// Set the output as high.
525 #[inline]
526 pub fn set_high(&mut self) {
527 self.pin.set_high();
528 }
529
530 /// Set the output as low.
531 #[inline]
532 pub fn set_low(&mut self) {
533 self.pin.set_low();
534 }
535
536 /// Set the output level.
537 #[inline]
538 pub fn set_level(&mut self, level: Level) {
539 self.pin.set_level(level);
540 }
541
542 /// Get whether the output level is set to high.
543 #[inline]
544 pub fn is_set_high(&self) -> bool {
545 self.pin.is_set_high()
546 }
547
548 /// Get whether the output level is set to low.
549 #[inline]
550 pub fn is_set_low(&self) -> bool {
551 self.pin.is_set_low()
552 }
553
554 /// Get the current output level.
555 #[inline]
556 pub fn get_output_level(&self) -> Level {
557 self.pin.get_output_level()
558 }
559
560 /// Toggle pin output
561 #[inline]
562 pub fn toggle(&mut self) {
563 self.pin.toggle()
564 }
565
566 /// Wait until the pin is high. If it is already high, return immediately.
567 #[inline]
568 pub async fn wait_for_high(&mut self) {
569 self.pin.wait_for_high().await
570 }
571
572 /// Wait until the pin is low. If it is already low, return immediately.
573 #[inline]
574 pub async fn wait_for_low(&mut self) {
575 self.pin.wait_for_low().await
576 }
577
578 /// Wait for the pin to undergo a transition from low to high.
579 #[inline]
580 pub async fn wait_for_rising_edge(&mut self) {
581 self.pin.wait_for_rising_edge().await
582 }
583
584 /// Wait for the pin to undergo a transition from high to low.
585 #[inline]
586 pub async fn wait_for_falling_edge(&mut self) {
587 self.pin.wait_for_falling_edge().await
588 }
589
590 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
591 #[inline]
592 pub async fn wait_for_any_edge(&mut self) {
593 self.pin.wait_for_any_edge().await
594 }
595}
596
597#[allow(private_bounds)]
598pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
599 /// Returns the pin number within a bank
600 #[inline]
601 fn pin(&self) -> u8 {
602 self.pin_number()
603 }
604
605 #[inline]
606 fn bank(&self) -> Bank {
607 self._bank()
608 }
609}
610
611/// Type-erased GPIO pin.
612pub struct AnyPin {
613 pub(crate) pin_number: u8,
614 pub(crate) bank: Bank,
615}
616
617impl AnyPin {
618 /// Unsafely create a new type-erased pin.
619 ///
620 /// # Safety
621 ///
622 /// You must ensure that you’re only using one instance of this type at a time.
623 pub unsafe fn steal(bank: Bank, pin_number: u8) -> Peri<'static, Self> {
624 Peri::new_unchecked(Self { pin_number, bank })
625 }
626}
627
628impl_peripheral!(AnyPin);
629
630impl Pin for AnyPin {}
631impl SealedPin for AnyPin {
632 #[inline]
633 fn pin_number(&self) -> u8 {
634 self.pin_number
635 }
636
637 #[inline]
638 fn _bank(&self) -> Bank {
639 self.bank
640 }
641}
642
643// Impl details
644
645/// Mux mode for GPIO pins. This is constant across all RT1xxx parts.
646const GPIO_MUX_MODE: u8 = 0b101;
647
648// FIXME: These don't always need to be 32 entries. GPIO5 on RT1101 contains a single pin and GPIO2 only 14.
649#[cfg(gpio1)]
650static GPIO1_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
651#[cfg(gpio2)]
652static GPIO2_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
653#[cfg(gpio3)]
654static GPIO3_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
655#[cfg(gpio4)]
656static GPIO4_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
657#[cfg(gpio5)]
658static GPIO5_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
659
660/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
661pub(crate) trait SealedPin: Sized {
662 fn pin_number(&self) -> u8;
663
664 fn _bank(&self) -> Bank;
665
666 #[inline]
667 fn block(&self) -> Gpio {
668 match self._bank() {
669 #[cfg(gpio1)]
670 Bank::Gpio1 => pac::GPIO1,
671 #[cfg(gpio2)]
672 Bank::Gpio2 => pac::GPIO2,
673 #[cfg(gpio3)]
674 Bank::Gpio3 => pac::GPIO3,
675 #[cfg(gpio4)]
676 Bank::Gpio4 => pac::GPIO4,
677 #[cfg(gpio5)]
678 Bank::Gpio5 => pac::GPIO5,
679 }
680 }
681
682 #[inline]
683 fn mux(&self) -> Reg<MuxCtl, RW> {
684 // SAFETY: The generated mux address table is valid since it is generated from the SVD files.
685 let address = unsafe { mux_address(self._bank(), self.pin_number()).unwrap_unchecked() };
686
687 // SAFETY: The register at the address is an instance of MuxCtl.
688 unsafe { Reg::from_ptr(address as *mut _) }
689 }
690
691 #[inline]
692 fn pad(&self) -> Reg<Ctl, RW> {
693 // SAFETY: The generated pad address table is valid since it is generated from the SVD files.
694 let address = unsafe { pad_address(self._bank(), self.pin_number()).unwrap_unchecked() };
695
696 // SAFETY: The register at the address is an instance of Ctl.
697 unsafe { Reg::from_ptr(address as *mut _) }
698 }
699
700 fn waker(&self) -> &AtomicWaker {
701 match self._bank() {
702 #[cfg(gpio1)]
703 Bank::Gpio1 => &GPIO1_WAKERS[self.pin_number() as usize],
704 #[cfg(gpio2)]
705 Bank::Gpio2 => &GPIO2_WAKERS[self.pin_number() as usize],
706 #[cfg(gpio3)]
707 Bank::Gpio3 => &GPIO3_WAKERS[self.pin_number() as usize],
708 #[cfg(gpio4)]
709 Bank::Gpio4 => &GPIO4_WAKERS[self.pin_number() as usize],
710 #[cfg(gpio5)]
711 Bank::Gpio5 => &GPIO5_WAKERS[self.pin_number() as usize],
712 }
713 }
714}
715
716/// This enum matches the layout of Icr.
717enum InterruptConfiguration {
718 Low,
719 High,
720 RisingEdge,
721 FallingEdge,
722 AnyEdge,
723}
724
725#[must_use = "futures do nothing unless you `.await` or poll them"]
726struct InputFuture<'d> {
727 pin: Peri<'d, AnyPin>,
728}
729
730impl<'d> InputFuture<'d> {
731 fn new(pin: Peri<'d, AnyPin>, config: InterruptConfiguration) -> Self {
732 let block = pin.block();
733
734 let (icr, edge_sel) = match config {
735 InterruptConfiguration::Low => (Icr::LOW_LEVEL, false),
736 InterruptConfiguration::High => (Icr::HIGH_LEVEL, false),
737 InterruptConfiguration::RisingEdge => (Icr::RISING_EDGE, false),
738 InterruptConfiguration::FallingEdge => (Icr::FALLING_EDGE, false),
739 InterruptConfiguration::AnyEdge => (Icr::FALLING_EDGE, true),
740 };
741
742 let index = if pin.pin_number() > 15 { 1 } else { 0 };
743
744 // Interrupt configuration performs RMW
745 critical_section::with(|_cs| {
746 // Disable interrupt so a level/edge detection change does not cause ISR to be set.
747 block.imr().modify(|w| {
748 w.set_imr(pin.pin_number() as usize, false);
749 });
750
751 block.icr(index).modify(|w| {
752 w.set_pin(pin.pin_number() as usize, icr);
753 });
754
755 block.edge_sel().modify(|w| {
756 w.set_edge_sel(pin.pin_number() as usize, edge_sel);
757 });
758
759 // Clear the previous interrupt.
760 block.isr().modify(|w| {
761 // "Status flags are cleared by writing a 1 to the corresponding bit position."
762 w.set_isr(pin.pin_number() as usize, true);
763 });
764 });
765
766 Self { pin }
767 }
768}
769
770impl<'d> Future for InputFuture<'d> {
771 type Output = ();
772
773 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
774 // We need to register/re-register the waker for each poll because any
775 // calls to wake will deregister the waker.
776 let waker = self.pin.waker();
777 waker.register(cx.waker());
778
779 // Enabling interrupt is RMW
780 critical_section::with(|_cs| {
781 self.pin.block().imr().modify(|w| {
782 w.set_imr(self.pin.pin_number() as usize, true);
783 });
784 });
785
786 let isr = self.pin.block().isr().read();
787
788 if isr.isr(self.pin.pin_number() as usize) {
789 return Poll::Ready(());
790 }
791
792 Poll::Pending
793 }
794}
795
796/// A macro to generate all GPIO pins.
797///
798/// This generates a lookup table for IOMUX register addresses.
799macro_rules! impl_gpio {
800 (
801 $($name: ident($bank: ident, $pin_number: expr);)*
802 ) => {
803 #[inline]
804 pub(crate) const fn pad_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
805 match (bank, pin) {
806 $(
807 (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::pads::$name),
808 )*
809 _ => None
810 }
811 }
812
813 #[inline]
814 pub(crate) const fn mux_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> {
815 match (bank, pin) {
816 $(
817 (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::muxes::$name),
818 )*
819 _ => None
820 }
821 }
822
823 $(
824 impl_pin!($name, $bank, $pin_number);
825 )*
826 };
827}
828
829macro_rules! impl_pin {
830 ($name: ident, $bank: ident, $pin_num: expr) => {
831 impl crate::gpio::Pin for crate::peripherals::$name {}
832 impl crate::gpio::SealedPin for crate::peripherals::$name {
833 #[inline]
834 fn pin_number(&self) -> u8 {
835 $pin_num
836 }
837
838 #[inline]
839 fn _bank(&self) -> crate::gpio::Bank {
840 crate::gpio::Bank::$bank
841 }
842 }
843
844 impl From<peripherals::$name> for crate::gpio::AnyPin {
845 fn from(val: peripherals::$name) -> Self {
846 use crate::gpio::SealedPin;
847
848 Self {
849 pin_number: val.pin_number(),
850 bank: val._bank(),
851 }
852 }
853 }
854 };
855}
856
857pub(crate) fn init() {
858 #[cfg(feature = "rt")]
859 unsafe {
860 use embassy_hal_internal::interrupt::InterruptExt;
861
862 pac::Interrupt::GPIO1_COMBINED_0_15.enable();
863 pac::Interrupt::GPIO1_COMBINED_16_31.enable();
864 pac::Interrupt::GPIO2_COMBINED_0_15.enable();
865 pac::Interrupt::GPIO5_COMBINED_0_15.enable();
866 }
867}
868
869/// IRQ handler for GPIO pins.
870///
871/// If `high_bits` is false, then the interrupt is for pins 0 through 15. If true, then the interrupt
872/// is for pins 16 through 31
873#[cfg(feature = "rt")]
874fn irq_handler(block: Gpio, wakers: &[AtomicWaker; 32], high_bits: bool) {
875 use crate::BitIter;
876
877 let isr = block.isr().read().0;
878 let imr = block.imr().read().0;
879 let mask = if high_bits { 0xFFFF_0000 } else { 0x0000_FFFF };
880 let bits = isr & imr & mask;
881
882 for bit in BitIter(bits) {
883 wakers[bit as usize].wake();
884
885 // Disable further interrupts for this pin. The input future will check ISR (which is kept
886 // until reset).
887 block.imr().modify(|w| {
888 w.set_imr(bit as usize, false);
889 });
890 }
891}
892
893#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
894#[interrupt]
895fn GPIO1_COMBINED_0_15() {
896 irq_handler(pac::GPIO1, &GPIO1_WAKERS, false);
897}
898
899#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
900#[interrupt]
901fn GPIO1_COMBINED_16_31() {
902 irq_handler(pac::GPIO1, &GPIO1_WAKERS, true);
903}
904
905#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
906#[interrupt]
907fn GPIO2_COMBINED_0_15() {
908 irq_handler(pac::GPIO2, &GPIO2_WAKERS, false);
909}
910
911#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
912#[interrupt]
913fn GPIO2_COMBINED_16_31() {
914 irq_handler(pac::GPIO2, &GPIO2_WAKERS, true);
915}
916
917#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
918#[interrupt]
919fn GPIO3_COMBINED_0_15() {
920 irq_handler(pac::GPIO3, &GPIO3_WAKERS, false);
921}
922
923#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
924#[interrupt]
925fn GPIO3_COMBINED_16_31() {
926 irq_handler(pac::GPIO3, &GPIO3_WAKERS, true);
927}
928
929#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
930#[interrupt]
931fn GPIO4_COMBINED_0_15() {
932 irq_handler(pac::GPIO4, &GPIO4_WAKERS, false);
933}
934
935#[cfg(all(feature = "mimxrt1062", feature = "rt"))]
936#[interrupt]
937fn GPIO4_COMBINED_16_31() {
938 irq_handler(pac::GPIO4, &GPIO4_WAKERS, true);
939}
940
941#[cfg(all(any(feature = "mimxrt1011", feature = "mimxrt1062"), feature = "rt"))]
942#[interrupt]
943fn GPIO5_COMBINED_0_15() {
944 irq_handler(pac::GPIO5, &GPIO5_WAKERS, false);
945}
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
index 433aca9e0..5e77fc0db 100644
--- a/embassy-nxp/src/lib.rs
+++ b/embassy-nxp/src/lib.rs
@@ -1,11 +1,20 @@
1#![no_std] 1#![no_std]
2 2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
3pub mod gpio; 6pub mod gpio;
4#[cfg(feature = "lpc55")] 7#[cfg(feature = "lpc55")]
5pub mod pint; 8pub mod pint;
6 9
10#[cfg(feature = "_time_driver")]
11#[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")]
12mod time_driver;
13
7// This mod MUST go last, so that it sees all the `impl_foo!` macros 14// This mod MUST go last, so that it sees all the `impl_foo!` macros
8#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")] 15#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")]
16#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
17#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
9mod chip; 18mod chip;
10 19
11#[cfg(feature = "unstable-pac")] 20#[cfg(feature = "unstable-pac")]
@@ -21,13 +30,66 @@ pub use embassy_hal_internal::{Peri, PeripheralType};
21/// 30///
22/// This should only be called once and at startup, otherwise it panics. 31/// This should only be called once and at startup, otherwise it panics.
23pub fn init(_config: config::Config) -> Peripherals { 32pub fn init(_config: config::Config) -> Peripherals {
24 #[cfg(feature = "lpc55")] 33 // Do this first, so that it panics if user is calling `init` a second time
34 // before doing anything important.
35 let peripherals = Peripherals::take();
36
37 #[cfg(feature = "mimxrt1011")]
25 { 38 {
26 gpio::init(); 39 // The RT1010 Reference manual states that core clock root must be switched before
27 pint::init(); 40 // reprogramming PLL2.
41 pac::CCM.cbcdr().modify(|w| {
42 w.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_1);
43 });
44
45 while matches!(
46 pac::CCM.cdhipr().read().periph_clk_sel_busy(),
47 pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
48 ) {}
49
50 info!("Core clock root switched");
51
52 // 480 * 18 / 24 = 360
53 pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd2_frac(12));
54
55 //480*18/24(pfd0)/4
56 pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd0_frac(24));
57 pac::CCM.cscmr1().modify(|x| x.set_flexspi_podf(3.into()));
58
59 // CPU Core
60 pac::CCM_ANALOG.pfd_528().modify(|x| x.set_pfd3_frac(18));
61 cortex_m::asm::delay(500_000);
62
63 // Clock core clock with PLL 2.
64 pac::CCM
65 .cbcdr()
66 .modify(|x| x.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_0)); // false
67
68 while matches!(
69 pac::CCM.cdhipr().read().periph_clk_sel_busy(),
70 pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
71 ) {}
72
73 pac::CCM
74 .cbcmr()
75 .write(|v| v.set_pre_periph_clk_sel(pac::ccm::vals::PrePeriphClkSel::PRE_PERIPH_CLK_SEL_0));
76
77 // TODO: Some for USB PLLs
78
79 // DCDC clock?
80 pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
28 } 81 }
29 82
30 crate::Peripherals::take() 83 #[cfg(any(feature = "lpc55", rt1xxx))]
84 gpio::init();
85
86 #[cfg(feature = "lpc55")]
87 pint::init();
88
89 #[cfg(feature = "_time_driver")]
90 time_driver::init();
91
92 peripherals
31} 93}
32 94
33/// HAL configuration for the NXP board. 95/// HAL configuration for the NXP board.
@@ -35,3 +97,20 @@ pub mod config {
35 #[derive(Default)] 97 #[derive(Default)]
36 pub struct Config {} 98 pub struct Config {}
37} 99}
100
101#[allow(unused)]
102struct BitIter(u32);
103
104impl Iterator for BitIter {
105 type Item = u32;
106
107 fn next(&mut self) -> Option<Self::Item> {
108 match self.0.trailing_zeros() {
109 32 => None,
110 b => {
111 self.0 &= !(1 << b);
112 Some(b)
113 }
114 }
115 }
116}
diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs
index dc117e7e3..ff414b4e6 100644
--- a/embassy-nxp/src/pint.rs
+++ b/embassy-nxp/src/pint.rs
@@ -101,6 +101,8 @@ pub(crate) fn init() {
101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6); 101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6);
102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7); 102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7);
103 }; 103 };
104
105 info!("Pin interrupts initialized");
104} 106}
105 107
106#[must_use = "futures do nothing unless you `.await` or poll them"] 108#[must_use = "futures do nothing unless you `.await` or poll them"]
diff --git a/embassy-nxp/src/time_driver/pit.rs b/embassy-nxp/src/time_driver/pit.rs
new file mode 100644
index 000000000..985e5e815
--- /dev/null
+++ b/embassy-nxp/src/time_driver/pit.rs
@@ -0,0 +1,187 @@
1//! Time driver using Periodic Interrupt Timer (PIT)
2//!
3//! This driver is used with the iMXRT1xxx parts.
4//!
5//! The PIT is run in lifetime mode. Timer 1 is chained to timer 0 to provide a free-running 64-bit timer.
6//! The 64-bit timer is used to track how many ticks since boot.
7//!
8//! Timer 2 counts how many ticks there are within the current u32::MAX tick period. Timer 2 is restarted when
9//! a new alarm is set (or every u32::MAX ticks). One caveat is that an alarm could be a few ticks late due to
10//! restart. However the Cortex-M7 cores run at 500 MHz easily and the PIT will generally run at 1 MHz or lower.
11//! Along with the fact that scheduling an alarm takes a critical section worst case an alarm may be a few
12//! microseconds late.
13//!
14//! All PIT timers are clocked in lockstep, so the late start will not cause the now() count to drift.
15
16use core::cell::{Cell, RefCell};
17use core::task::Waker;
18
19use critical_section::{CriticalSection, Mutex};
20use embassy_hal_internal::interrupt::InterruptExt;
21use embassy_time_driver::Driver as _;
22use embassy_time_queue_utils::Queue;
23
24use crate::pac::{self, interrupt};
25
26struct Driver {
27 alarm: Mutex<Cell<u64>>,
28 queue: Mutex<RefCell<Queue>>,
29}
30
31impl embassy_time_driver::Driver for Driver {
32 fn now(&self) -> u64 {
33 loop {
34 // Even though reading LTMR64H will latch LTMR64L if another thread preempts between any of the
35 // three reads and calls now() then the value in LTMR64L will be wrong when execution returns to
36 // thread which was preempted.
37 let hi = pac::PIT.ltmr64h().read().lth();
38 let lo = pac::PIT.ltmr64l().read().ltl();
39 let hi2 = pac::PIT.ltmr64h().read().lth();
40
41 if hi == hi2 {
42 // PIT timers always count down.
43 return u64::MAX - ((hi as u64) << 32 | (lo as u64));
44 }
45 }
46 }
47
48 fn schedule_wake(&self, at: u64, waker: &Waker) {
49 critical_section::with(|cs| {
50 let mut queue = self.queue.borrow(cs).borrow_mut();
51
52 if queue.schedule_wake(at, waker) {
53 let mut next = queue.next_expiration(self.now());
54
55 while !self.set_alarm(cs, next) {
56 next = queue.next_expiration(self.now());
57 }
58 }
59 })
60 }
61}
62
63impl Driver {
64 fn init(&'static self) {
65 // Disable PIT clock during mux configuration.
66 pac::CCM.ccgr1().modify(|r| r.set_cg6(0b00));
67
68 // TODO: This forces the PIT to be driven by the oscillator. However that isn't the only option as you
69 // could divide the clock root by up to 64.
70 pac::CCM.cscmr1().modify(|r| {
71 // 1 MHz
72 r.set_perclk_podf(pac::ccm::vals::PerclkPodf::DIVIDE_24);
73 r.set_perclk_clk_sel(pac::ccm::vals::PerclkClkSel::PERCLK_CLK_SEL_1);
74 });
75
76 pac::CCM.ccgr1().modify(|r| r.set_cg6(0b11));
77
78 // Disable clock during init.
79 //
80 // It is important that the PIT clock is prepared to not exceed limit (50 MHz on RT1011), or else
81 // you will need to recover the device with boot mode switches when using any PIT registers.
82 pac::PIT.mcr().modify(|w| {
83 w.set_mdis(true);
84 });
85
86 pac::PIT.timer(0).ldval().write_value(u32::MAX);
87 pac::PIT.timer(1).ldval().write_value(u32::MAX);
88 pac::PIT.timer(2).ldval().write_value(0);
89 pac::PIT.timer(3).ldval().write_value(0);
90
91 pac::PIT.timer(1).tctrl().write(|w| {
92 // In lifetime mode, timer 1 is chained to timer 0 to form a 64-bit timer.
93 w.set_chn(true);
94 w.set_ten(true);
95 w.set_tie(false);
96 });
97
98 pac::PIT.timer(0).tctrl().write(|w| {
99 w.set_chn(false);
100 w.set_ten(true);
101 w.set_tie(false);
102 });
103
104 pac::PIT.timer(2).tctrl().write(|w| {
105 w.set_tie(true);
106 });
107
108 unsafe { interrupt::PIT.enable() };
109
110 pac::PIT.mcr().write(|w| {
111 w.set_mdis(false);
112 });
113 }
114
115 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
116 let alarm = self.alarm.borrow(cs);
117 alarm.set(timestamp);
118
119 let timer = pac::PIT.timer(2);
120 let now = self.now();
121
122 if timestamp <= now {
123 alarm.set(u64::MAX);
124
125 return false;
126 }
127
128 timer.tctrl().modify(|x| x.set_ten(false));
129 timer.tflg().modify(|x| x.set_tif(true));
130
131 // If the next alarm happens in more than u32::MAX cycles then the alarm will be restarted later.
132 timer.ldval().write_value((timestamp - now) as u32);
133 timer.tctrl().modify(|x| x.set_ten(true));
134
135 true
136 }
137
138 fn trigger_alarm(&self, cs: CriticalSection) {
139 let mut next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
140
141 while !self.set_alarm(cs, next) {
142 next = self.queue.borrow_ref_mut(cs).next_expiration(self.now());
143 }
144 }
145
146 fn on_interrupt(&self) {
147 critical_section::with(|cs| {
148 let timer = pac::PIT.timer(2);
149 let alarm = self.alarm.borrow(cs);
150 let interrupted = timer.tflg().read().tif();
151 timer.tflg().write(|r| r.set_tif(true));
152
153 if interrupted {
154 // A new load value will not apply until the next timer expiration.
155 //
156 // The expiry may be up to u32::MAX cycles away, so the timer must be restarted.
157 timer.tctrl().modify(|r| r.set_ten(false));
158
159 let now = self.now();
160 let timestamp = alarm.get();
161
162 if timestamp <= now {
163 self.trigger_alarm(cs);
164 } else {
165 // The alarm is not ready. Wait for u32::MAX cycles and check again or set the next alarm.
166 timer.ldval().write_value((timestamp - now) as u32);
167 timer.tctrl().modify(|r| r.set_ten(true));
168 }
169 }
170 });
171 }
172}
173
174embassy_time_driver::time_driver_impl!(static DRIVER: Driver = Driver {
175 alarm: Mutex::new(Cell::new(0)),
176 queue: Mutex::new(RefCell::new(Queue::new()))
177});
178
179pub(crate) fn init() {
180 DRIVER.init();
181}
182
183#[cfg(feature = "rt")]
184#[interrupt]
185fn PIT() {
186 DRIVER.on_interrupt();
187}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 8f3a471af..38254ee40 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -57,7 +57,7 @@ embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", fe
57embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", default-features = false } 57embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", default-features = false }
58embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 58embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
59embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } 59embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" }
60embassy-usb-synopsys-otg = { version = "0.2.0", path = "../embassy-usb-synopsys-otg" } 60embassy-usb-synopsys-otg = { version = "0.3.0", path = "../embassy-usb-synopsys-otg" }
61embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } 61embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
62 62
63embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 63embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 98483489f..31cbdc0d7 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -76,12 +76,14 @@ impl<T: Instance> SealedAdcChannel<T> for Vcore {
76 } 76 }
77} 77}
78 78
79#[derive(Copy, Clone)]
79pub enum DacChannel { 80pub enum DacChannel {
80 OUT1, 81 OUT1,
81 OUT2, 82 OUT2,
82} 83}
83 84
84/// Number of samples used for averaging. 85/// Number of samples used for averaging.
86#[derive(Copy, Clone)]
85pub enum Averaging { 87pub enum Averaging {
86 Disabled, 88 Disabled,
87 Samples2, 89 Samples2,
@@ -187,7 +189,7 @@ pub struct Adc4<'d, T: Instance> {
187 adc: crate::Peri<'d, T>, 189 adc: crate::Peri<'d, T>,
188} 190}
189 191
190#[derive(Debug)] 192#[derive(Copy, Clone, Debug)]
191pub enum Adc4Error { 193pub enum Adc4Error {
192 InvalidSequence, 194 InvalidSequence,
193 DMAError, 195 DMAError,
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index 936ad7413..f5870801e 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -48,7 +48,7 @@ impl<T: Instance> SealedAdcChannel<T> for Temperature {
48 } 48 }
49} 49}
50 50
51#[derive(Debug)] 51#[derive(Copy, Clone, Debug)]
52pub enum Prescaler { 52pub enum Prescaler {
53 NotDivided, 53 NotDivided,
54 DividedBy2, 54 DividedBy2,
@@ -138,6 +138,7 @@ impl<'a> defmt::Format for Prescaler {
138/// Number of samples used for averaging. 138/// Number of samples used for averaging.
139/// TODO: Implement hardware averaging setting. 139/// TODO: Implement hardware averaging setting.
140#[allow(unused)] 140#[allow(unused)]
141#[derive(Copy, Clone)]
141pub enum Averaging { 142pub enum Averaging {
142 Disabled, 143 Disabled,
143 Samples2, 144 Samples2,
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 944e971bb..84613078c 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -17,6 +17,7 @@ pub const VDDA_CALIB_MV: u32 = 3300;
17pub const ADC_MAX: u32 = (1 << 12) - 1; 17pub const ADC_MAX: u32 = (1 << 12) - 1;
18pub const VREF_INT: u32 = 1230; 18pub const VREF_INT: u32 = 1230;
19 19
20#[derive(Copy, Clone)]
20pub enum AdcPowerMode { 21pub enum AdcPowerMode {
21 AlwaysOn, 22 AlwaysOn,
22 DelayOff, 23 DelayOff,
@@ -24,6 +25,7 @@ pub enum AdcPowerMode {
24 DelayIdleOff, 25 DelayIdleOff,
25} 26}
26 27
28#[derive(Copy, Clone)]
27pub enum Prescaler { 29pub enum Prescaler {
28 Div1, 30 Div1,
29 Div2, 31 Div2,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 313244e19..fd74d5318 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,5 +1,7 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2use pac::adc::vals::Dmacfg; 2use pac::adc::vals::Dmacfg;
3#[cfg(adc_v3)]
4use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
3 5
4use super::{ 6use super::{
5 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
@@ -470,6 +472,23 @@ impl<'d, T: Instance> Adc<'d, T> {
470 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); 472 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
471 } 473 }
472 474
475 #[cfg(adc_v3)]
476 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
477 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
478 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
479 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
480 }
481
482 #[cfg(adc_v3)]
483 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) {
484 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
485 }
486
487 #[cfg(adc_v3)]
488 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) {
489 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
490 }
491
473 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 492 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
474 cfg_if! { 493 cfg_if! {
475 if #[cfg(any(adc_g0, adc_u0))] { 494 if #[cfg(any(adc_g0, adc_u0))] {
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 39e0d51b9..b0871019a 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -142,6 +142,7 @@ impl Prescaler {
142} 142}
143 143
144/// Number of samples used for averaging. 144/// Number of samples used for averaging.
145#[derive(Copy, Clone)]
145pub enum Averaging { 146pub enum Averaging {
146 Disabled, 147 Disabled,
147 Samples2, 148 Samples2,
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 4607eb230..d13df5a6b 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -132,7 +132,10 @@ impl Into<Lpms> for StopMode {
132 fn into(self) -> Lpms { 132 fn into(self) -> Lpms {
133 match self { 133 match self {
134 StopMode::Stop1 => Lpms::STOP1, 134 StopMode::Stop1 => Lpms::STOP1,
135 #[cfg(not(stm32wba))]
135 StopMode::Stop2 => Lpms::STOP2, 136 StopMode::Stop2 => Lpms::STOP2,
137 #[cfg(stm32wba)]
138 StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
136 } 139 }
137 } 140 }
138} 141}
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index cdad3ce00..011046ba4 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -31,7 +31,7 @@ log = { version = "0.4.17", optional = true }
31 31
32bitflags = "2.4.1" 32bitflags = "2.4.1"
33cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } 33cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
34embassy-boot = { version = "0.4.0", path = "../embassy-boot" } 34embassy-boot = { version = "0.5.0", path = "../embassy-boot" }
35embassy-futures = { version = "0.1.1", path = "../embassy-futures" } 35embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
36embassy-sync = { version = "0.7.0", path = "../embassy-sync" } 36embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
37embassy-time = { version = "0.4.0", path = "../embassy-time" } 37embassy-time = { version = "0.4.0", path = "../embassy-time" }
diff --git a/embassy-usb-logger/CHANGELOG.md b/embassy-usb-logger/CHANGELOG.md
index 86a9fb032..79ea25839 100644
--- a/embassy-usb-logger/CHANGELOG.md
+++ b/embassy-usb-logger/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.5.0 - 2025-07-22
11
12- Update `embassy-usb` to 0.5.0
13
10## 0.4.0 - 2025-01-15 14## 0.4.0 - 2025-01-15
11 15
12- Update `embassy-usb` to 0.4.0 16- Update `embassy-usb` to 0.4.0
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
index 6dd2637f2..68b11ad8a 100644
--- a/embassy-usb-logger/Cargo.toml
+++ b/embassy-usb-logger/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-usb-logger" 2name = "embassy-usb-logger"
3version = "0.4.0" 3version = "0.5.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "`log` implementation for USB serial using `embassy-usb`." 6description = "`log` implementation for USB serial using `embassy-usb`."
diff --git a/embassy-usb-synopsys-otg/CHANGELOG.md b/embassy-usb-synopsys-otg/CHANGELOG.md
index 293363d9a..9913ee533 100644
--- a/embassy-usb-synopsys-otg/CHANGELOG.md
+++ b/embassy-usb-synopsys-otg/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.3.0 - 2025-07-22
11
12- Bump `embassy-usb-driver` to v0.2.0
13
10## 0.2.0 - 2024-12-06 14## 0.2.0 - 2024-12-06
11 15
12- Fix corruption in CONTROL OUT transfers (and remove `quirk_setup_late_cnak`) 16- Fix corruption in CONTROL OUT transfers (and remove `quirk_setup_late_cnak`)
diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml
index 511cddacf..78cce24de 100644
--- a/embassy-usb-synopsys-otg/Cargo.toml
+++ b/embassy-usb-synopsys-otg/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-usb-synopsys-otg" 2name = "embassy-usb-synopsys-otg"
3version = "0.2.0" 3version = "0.3.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers" 6description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers"
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 9c7fdf148..37183df97 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -9,8 +9,8 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.5.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.5.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] } 12embassy-boot = { version = "0.5.0", path = "../../../../embassy-boot", features = [] }
13embassy-boot-nrf = { version = "0.5.0", path = "../../../../embassy-boot-nrf", features = [] } 13embassy-boot-nrf = { version = "0.6.0", path = "../../../../embassy-boot-nrf", features = [] }
14embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
15 15
16defmt = { version = "1.0.1", optional = true } 16defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index afb0871e6..e5568f6bb 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.6.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } 11embassy-rp = { version = "0.6.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
12embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] } 12embassy-boot-rp = { version = "0.6.0", path = "../../../../embassy-boot-rp", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = "1.0.1" 15defmt = "1.0.1"
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 4cd2d1338..be8b7bff1 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32" } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32" }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index f3d74f53a..2b0175a0c 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 427b15bcb..3c88f4241 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 46e79f7ed..b4e7e090a 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index ae3cd3600..394578e1a 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index a41b25562..abe0451fd 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 287fcf806..bc4681f79 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.5.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.5.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } 15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index af49db260..0552d109a 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.4.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.1", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml
index 6ec6e51a8..1724a22d4 100644
--- a/examples/lpc55s69/Cargo.toml
+++ b/examples/lpc55s69/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7 7
8[dependencies] 8[dependencies]
9embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt"] } 9embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt"] }
10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
diff --git a/examples/mimxrt1011/.cargo/config.toml b/examples/mimxrt1011/.cargo/config.toml
new file mode 100644
index 000000000..12f4b27b2
--- /dev/null
+++ b/examples/mimxrt1011/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip MIMXRT1010'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M7
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/mimxrt1011/Cargo.toml b/examples/mimxrt1011/Cargo.toml
new file mode 100644
index 000000000..cf4e4c163
--- /dev/null
+++ b/examples/mimxrt1011/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2name = "embassy-imxrt1011-examples"
3version = "0.1.0"
4edition = "2021"
5license = "MIT or Apache-2.0"
6
7[dependencies]
8cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] }
9cortex-m-rt = "0.7.3"
10defmt = "1.0.1"
11defmt-rtt = "1.0.0"
12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["defmt", "mimxrt1011", "unstable-pac", "time-driver-pit"] }
16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", ] } # "defmt-timestamp-uptime" # RT1011 hard faults currently with this enabled.
17embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0"
20
21imxrt-boot-gen = { version = "0.3.4", features = ["imxrt1010"] }
22panic-probe = { version = "1.0.0", features = ["print-defmt"] }
23panic-semihosting = "0.6.0"
24
25[build-dependencies]
26imxrt-rt = { version = "0.1.7", features = ["device"] }
27
28[profile.release]
29debug = 2
diff --git a/examples/mimxrt1011/build.rs b/examples/mimxrt1011/build.rs
new file mode 100644
index 000000000..99e172aba
--- /dev/null
+++ b/examples/mimxrt1011/build.rs
@@ -0,0 +1,14 @@
1use imxrt_rt::{Family, RuntimeBuilder};
2
3fn main() {
4 // The IMXRT1010-EVK technically has 128M of flash, but we only ever use 8MB so that the examples
5 // will build fine on the Adafruit Metro M7 boards.
6 RuntimeBuilder::from_flexspi(Family::Imxrt1010, 8 * 1024 * 1024)
7 .build()
8 .unwrap();
9
10 println!("cargo:rustc-link-arg-bins=--nmagic");
11 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
12 // Not link.x, as imxrt-rt needs to do some special things
13 println!("cargo:rustc-link-arg-bins=-Timxrt-link.x");
14}
diff --git a/examples/mimxrt1011/src/bin/blinky.rs b/examples/mimxrt1011/src/bin/blinky.rs
new file mode 100644
index 000000000..a5d5de6b3
--- /dev/null
+++ b/examples/mimxrt1011/src/bin/blinky.rs
@@ -0,0 +1,48 @@
1//! This example works on the following boards:
2//! - IMXRT1010-EVK
3//! - Adafruit Metro M7 (with microSD or with AirLift), requires an external button
4//! - Makerdiary iMX RT1011 Nano Kit (TODO: currently untested, please change this)
5//!
6//! Although beware you will need to change the GPIO pins being used (scroll down).
7
8#![no_std]
9#![no_main]
10
11use defmt::info;
12use embassy_executor::Spawner;
13use embassy_nxp::gpio::{Level, Output};
14use embassy_time::Timer;
15// Must include `embassy_imxrt1011_examples` to ensure the FCB gets linked.
16use {defmt_rtt as _, embassy_imxrt1011_examples as _, panic_probe as _};
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 let p = embassy_nxp::init(Default::default());
21 info!("Hello world!");
22
23 /* Pick the pins to use depending on your board. */
24
25 // IMXRT1010-EVK
26 //
27 // LED (D25)
28 let led = p.GPIO_11;
29
30 // Adafruit Metro M7 (both microSD and AirLift variants)
31 //
32 // The LED is connected to D13 on the board.
33 // let led = p.GPIO_03;
34
35 // Makerdiary iMX RT1011 Nano Kit
36 //
37 // LED0
38 // let led = p.GPIO_SD_04;
39
40 let mut led = Output::new(led, Level::Low);
41
42 loop {
43 Timer::after_millis(500).await;
44
45 info!("Toggle");
46 led.toggle();
47 }
48}
diff --git a/examples/mimxrt1011/src/bin/button.rs b/examples/mimxrt1011/src/bin/button.rs
new file mode 100644
index 000000000..e63d7171d
--- /dev/null
+++ b/examples/mimxrt1011/src/bin/button.rs
@@ -0,0 +1,62 @@
1//! This example works on the following boards:
2//! - IMXRT1010-EVK
3//! - Adafruit Metro M7 (with microSD or with AirLift), requires an external button
4//! - Makerdiary iMX RT1011 Nano Kit (TODO: currently untested, please change this)
5//!
6//! Although beware you will need to change the GPIO pins being used (scroll down).
7
8#![no_std]
9#![no_main]
10
11use defmt::info;
12use embassy_executor::Spawner;
13use embassy_nxp::gpio::{Input, Level, Output, Pull};
14// Must include `embassy_imxrt1011_examples` to ensure the FCB gets linked.
15use {defmt_rtt as _, embassy_imxrt1011_examples as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) -> ! {
19 let p = embassy_nxp::init(Default::default());
20 info!("Hello world!");
21
22 /* Pick the pins to use depending on your board. */
23
24 // IMXRT1010-EVK
25 //
26 // LED (D25) and user button (SW4)
27 let (led, button) = (p.GPIO_11, p.GPIO_SD_05);
28
29 // Adafruit Metro M7 (both microSD and AirLift variants)
30 //
31 // The LED is connected to D13 on the board.
32 //
33 // In particular the Metro M7 has no board user buttons, so you will need to connect a button.
34 // Any other GPIO pin can be used. GPIO_04 is used for example since it is on pin D12.
35 // let (led, button) = (p.GPIO_03, p.GPIO_04);
36
37 // Makerdiary iMX RT1011 Nano Kit
38 //
39 // LED0 and user button.
40 // let (led, button) = (p.GPIO_SD_04, p.GPIO_SD_03);
41
42 let mut button = Input::new(button, Pull::Up100K);
43 let mut led = Output::new(led, Level::Low);
44 led.set_high();
45
46 loop {
47 button.wait_for_falling_edge().await;
48
49 info!("Toggled");
50 led.toggle();
51
52 // The RT1010EVK has a 100 nF debouncing capacitor which results in false positive events
53 // when listening for a falling edge in a loop, wait for the rising edge and then wait for
54 // stabilization.
55 button.wait_for_rising_edge().await;
56
57 // Stabilization.
58 for _ in 0..100_000 {
59 cortex_m::asm::nop();
60 }
61 }
62}
diff --git a/examples/mimxrt1011/src/lib.rs b/examples/mimxrt1011/src/lib.rs
new file mode 100644
index 000000000..f0391ef57
--- /dev/null
+++ b/examples/mimxrt1011/src/lib.rs
@@ -0,0 +1,75 @@
1//! FlexSPI configuration block (FCB) for iMXRT1011 boards.
2//!
3//! This is a generic FCB that should work with most QSPI flash.
4
5#![no_std]
6
7use imxrt_boot_gen::flexspi;
8use imxrt_boot_gen::flexspi::opcodes::sdr::*;
9use imxrt_boot_gen::flexspi::{
10 ColumnAddressWidth, Command, DeviceModeConfiguration, FlashPadType, Instr, LookupTable, Pads,
11 ReadSampleClockSource, Sequence, SequenceBuilder, SerialClockFrequency, SerialFlashRegion,
12 WaitTimeConfigurationCommands,
13};
14use imxrt_boot_gen::serial_flash::nor;
15
16/// While the IMXRT1010-EVK and Makerdiary iMX RT1011 Nano Kit have 128MBit of flash we limit to 64Mbit
17/// to allow the Metro M7 boards to use the same FCB configuration.
18const DENSITY_BITS: u32 = 64 * 1024 * 1024;
19const DENSITY_BYTES: u32 = DENSITY_BITS / 8;
20
21const SEQ_READ: Sequence = SequenceBuilder::new()
22 .instr(Instr::new(CMD, Pads::One, 0xEB))
23 .instr(Instr::new(RADDR, Pads::Four, 0x18))
24 .instr(Instr::new(DUMMY, Pads::Four, 0x06))
25 .instr(Instr::new(READ, Pads::Four, 0x04))
26 .build();
27
28const SEQ_READ_STATUS: Sequence = SequenceBuilder::new()
29 .instr(Instr::new(CMD, Pads::One, 0x05))
30 .instr(Instr::new(READ, Pads::One, 0x01))
31 .build();
32
33const SEQ_WRITE_ENABLE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x06)).build();
34
35const SEQ_ERASE_SECTOR: Sequence = SequenceBuilder::new()
36 .instr(Instr::new(CMD, Pads::One, 0x20))
37 .instr(Instr::new(RADDR, Pads::One, 0x18))
38 .build();
39
40const SEQ_PAGE_PROGRAM: Sequence = SequenceBuilder::new()
41 .instr(Instr::new(CMD, Pads::One, 0x02))
42 .instr(Instr::new(RADDR, Pads::One, 0x18))
43 .instr(Instr::new(WRITE, Pads::One, 0x04))
44 .build();
45
46const SEQ_CHIP_ERASE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x60)).build();
47
48const LUT: LookupTable = LookupTable::new()
49 .command(Command::Read, SEQ_READ)
50 .command(Command::ReadStatus, SEQ_READ_STATUS)
51 .command(Command::WriteEnable, SEQ_WRITE_ENABLE)
52 .command(Command::EraseSector, SEQ_ERASE_SECTOR)
53 .command(Command::PageProgram, SEQ_PAGE_PROGRAM)
54 .command(Command::ChipErase, SEQ_CHIP_ERASE);
55
56const COMMON_CONFIGURATION_BLOCK: flexspi::ConfigurationBlock = flexspi::ConfigurationBlock::new(LUT)
57 .read_sample_clk_src(ReadSampleClockSource::LoopbackFromDQSPad)
58 .cs_hold_time(0x03)
59 .cs_setup_time(0x03)
60 .column_address_width(ColumnAddressWidth::OtherDevices)
61 .device_mode_configuration(DeviceModeConfiguration::Disabled)
62 .wait_time_cfg_commands(WaitTimeConfigurationCommands::disable())
63 .flash_size(SerialFlashRegion::A1, DENSITY_BYTES)
64 .serial_clk_freq(SerialClockFrequency::MHz120)
65 .serial_flash_pad_type(FlashPadType::Quad);
66
67pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock =
68 nor::ConfigurationBlock::new(COMMON_CONFIGURATION_BLOCK)
69 .page_size(256)
70 .sector_size(4096)
71 .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30);
72
73#[unsafe(no_mangle)]
74#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")]
75pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK;
diff --git a/examples/mimxrt1062-evk/.cargo/config.toml b/examples/mimxrt1062-evk/.cargo/config.toml
new file mode 100644
index 000000000..ca4c606dc
--- /dev/null
+++ b/examples/mimxrt1062-evk/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip MIMXRT1060'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M7
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/mimxrt1062-evk/Cargo.toml b/examples/mimxrt1062-evk/Cargo.toml
new file mode 100644
index 000000000..430a26b41
--- /dev/null
+++ b/examples/mimxrt1062-evk/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2name = "embassy-imxrt1062-evk-examples"
3version = "0.1.0"
4edition = "2021"
5license = "MIT or Apache-2.0"
6
7[dependencies]
8cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] }
9cortex-m-rt = "0.7.3"
10defmt = "1.0.1"
11defmt-rtt = "1.0.0"
12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["defmt", "mimxrt1062", "unstable-pac", "time-driver-pit"] }
16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", ] } # "defmt-timestamp-uptime"
17embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0"
20
21imxrt-boot-gen = { version = "0.3.4", features = ["imxrt1060"] }
22panic-probe = { version = "1.0.0", features = ["print-defmt"] }
23panic-semihosting = "0.6.0"
24
25[build-dependencies]
26imxrt-rt = { version = "0.1.7", features = ["device"] }
27
28[profile.release]
29debug = 2
diff --git a/examples/mimxrt1062-evk/build.rs b/examples/mimxrt1062-evk/build.rs
new file mode 100644
index 000000000..e0e0d547e
--- /dev/null
+++ b/examples/mimxrt1062-evk/build.rs
@@ -0,0 +1,12 @@
1use imxrt_rt::{Family, RuntimeBuilder};
2
3fn main() {
4 RuntimeBuilder::from_flexspi(Family::Imxrt1060, 8 * 1024 * 1024)
5 .build()
6 .unwrap();
7
8 println!("cargo:rustc-link-arg-bins=--nmagic");
9 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
10 // Not link.x, as imxrt-rt needs to do some special things
11 println!("cargo:rustc-link-arg-bins=-Timxrt-link.x");
12}
diff --git a/examples/mimxrt1062-evk/src/bin/blinky.rs b/examples/mimxrt1062-evk/src/bin/blinky.rs
new file mode 100644
index 000000000..b6d90d94d
--- /dev/null
+++ b/examples/mimxrt1062-evk/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_nxp::gpio::{Level, Output};
7use embassy_time::Timer;
8// Must include `embassy_imxrt1062_evk_examples` to ensure the FCB gets linked.
9use {defmt_rtt as _, embassy_imxrt1062_evk_examples as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 let p = embassy_nxp::init(Default::default());
14 info!("Hello world!");
15
16 let led = p.GPIO_AD_B0_08;
17 let mut led = Output::new(led, Level::Low);
18
19 loop {
20 Timer::after_millis(500).await;
21
22 info!("Toggle");
23 led.toggle();
24 }
25}
diff --git a/examples/mimxrt1062-evk/src/bin/button.rs b/examples/mimxrt1062-evk/src/bin/button.rs
new file mode 100644
index 000000000..d60fa3dac
--- /dev/null
+++ b/examples/mimxrt1062-evk/src/bin/button.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_nxp::gpio::{Input, Level, Output, Pull};
7use {defmt_rtt as _, embassy_imxrt1062_evk_examples as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) -> ! {
11 let p = embassy_nxp::init(Default::default());
12 info!("Hello world!");
13
14 // User LED (D8)
15 let led = p.GPIO_AD_B0_08;
16 // User button (SW5)
17 let button = p.WAKEUP;
18 let mut button = Input::new(button, Pull::Up100K);
19 let mut led = Output::new(led, Level::Low);
20 led.set_high();
21
22 loop {
23 button.wait_for_falling_edge().await;
24
25 info!("Toggled");
26 led.toggle();
27
28 // Software debounce.
29 button.wait_for_rising_edge().await;
30
31 // Stabilization.
32 for _ in 0..100_000 {
33 cortex_m::asm::nop();
34 }
35 }
36}
diff --git a/examples/mimxrt1062-evk/src/lib.rs b/examples/mimxrt1062-evk/src/lib.rs
new file mode 100644
index 000000000..3f99f9db3
--- /dev/null
+++ b/examples/mimxrt1062-evk/src/lib.rs
@@ -0,0 +1,60 @@
1//! FlexSPI configuration block (FCB) for the iMXRT1060-EVK
2//!
3//! This uses IS25WP QuadSPI flash.
4
5#![no_std]
6
7use imxrt_boot_gen::flexspi::opcodes::sdr::*;
8use imxrt_boot_gen::flexspi::{self, FlashPadType, ReadSampleClockSource, SerialClockFrequency, SerialFlashRegion, *};
9use imxrt_boot_gen::serial_flash::*;
10pub use nor::ConfigurationBlock;
11
12const SEQ_READ: Sequence = SequenceBuilder::new()
13 .instr(Instr::new(CMD, Pads::One, 0xEB))
14 .instr(Instr::new(RADDR, Pads::Four, 0x18))
15 .instr(Instr::new(DUMMY, Pads::Four, 0x06))
16 .instr(Instr::new(READ, Pads::Four, 0x04))
17 .build();
18const SEQ_READ_STATUS: Sequence = SequenceBuilder::new()
19 .instr(Instr::new(CMD, Pads::One, 0x05))
20 .instr(Instr::new(READ, Pads::One, 0x04))
21 .build();
22const SEQ_WRITE_ENABLE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x06)).build();
23const SEQ_ERASE_SECTOR: Sequence = SequenceBuilder::new()
24 .instr(Instr::new(CMD, Pads::One, 0x20))
25 .instr(Instr::new(RADDR, Pads::One, 0x18))
26 .build();
27const SEQ_PAGE_PROGRAM: Sequence = SequenceBuilder::new()
28 .instr(Instr::new(CMD, Pads::One, 0x02))
29 .instr(Instr::new(RADDR, Pads::One, 0x18))
30 .instr(Instr::new(WRITE, Pads::One, 0x04))
31 .build();
32const SEQ_CHIP_ERASE: Sequence = SequenceBuilder::new().instr(Instr::new(CMD, Pads::One, 0x60)).build();
33
34const LUT: LookupTable = LookupTable::new()
35 .command(Command::Read, SEQ_READ)
36 .command(Command::ReadStatus, SEQ_READ_STATUS)
37 .command(Command::WriteEnable, SEQ_WRITE_ENABLE)
38 .command(Command::EraseSector, SEQ_ERASE_SECTOR)
39 .command(Command::PageProgram, SEQ_PAGE_PROGRAM)
40 .command(Command::ChipErase, SEQ_CHIP_ERASE);
41
42const COMMON_CONFIGURATION_BLOCK: flexspi::ConfigurationBlock = flexspi::ConfigurationBlock::new(LUT)
43 .version(Version::new(1, 4, 0))
44 .read_sample_clk_src(ReadSampleClockSource::LoopbackFromDQSPad)
45 .cs_hold_time(3)
46 .cs_setup_time(3)
47 .controller_misc_options(0x10)
48 .serial_flash_pad_type(FlashPadType::Quad)
49 .serial_clk_freq(SerialClockFrequency::MHz133)
50 .flash_size(SerialFlashRegion::A1, 8 * 1024 * 1024);
51
52pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock =
53 nor::ConfigurationBlock::new(COMMON_CONFIGURATION_BLOCK)
54 .page_size(256)
55 .sector_size(4096)
56 .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30);
57
58#[no_mangle]
59#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")]
60pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK;
diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml
index b6621c9c5..cc40b3109 100644
--- a/examples/mspm0g3507/Cargo.toml
+++ b/examples/mspm0g3507/Cargo.toml
@@ -17,5 +17,7 @@ defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] } 17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
18panic-semihosting = "0.6.0" 18panic-semihosting = "0.6.0"
19 19
20embedded-io-async = "0.6.1"
21
20[profile.release] 22[profile.release]
21debug = 2 23debug = 2
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 971f99fff..eefd69315 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -15,7 +15,7 @@ embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defm
15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } 15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] }
16embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.5.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
20cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] } 20cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] }
21 21
diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml
index d909aca1b..4d3dc77b5 100644
--- a/examples/rp235x/Cargo.toml
+++ b/examples/rp235x/Cargo.toml
@@ -15,7 +15,7 @@ embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defm
15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } 15embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.5.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.4.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
20cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] } 20cyw43-pio = { version = "0.5.1", path = "../../cyw43-pio", features = ["defmt"] }
21 21
diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml
index 2d5b8cd52..5ba3e586b 100644
--- a/tests/mspm0/Cargo.toml
+++ b/tests/mspm0/Cargo.toml
@@ -13,6 +13,7 @@ teleprobe-meta = "1.1"
13 13
14embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] } 14embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] }
15embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } 15embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt" ] } 17embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt" ] }
17embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [ "rt", "defmt", "unstable-pac", "time-driver-any" ] } 18embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [ "rt", "defmt", "unstable-pac", "time-driver-any" ] }
18embassy-embedded-hal = { version = "0.3.1", path = "../../embassy-embedded-hal/"} 19embassy-embedded-hal = { version = "0.3.1", path = "../../embassy-embedded-hal/"}
@@ -24,6 +25,8 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-sin
24cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
25embedded-hal = { package = "embedded-hal", version = "1.0" } 26embedded-hal = { package = "embedded-hal", version = "1.0" }
26embedded-hal-async = { version = "1.0" } 27embedded-hal-async = { version = "1.0" }
28embedded-io = { version = "0.6.1", features = ["defmt-03"] }
29embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
27panic-probe = { version = "1.0.0", features = ["print-defmt"] } 30panic-probe = { version = "1.0.0", features = ["print-defmt"] }
28static_cell = "2" 31static_cell = "2"
29portable-atomic = { version = "1.5", features = ["critical-section"] } 32portable-atomic = { version = "1.5", features = ["critical-section"] }
diff --git a/tests/mspm0/src/bin/uart_buffered.rs b/tests/mspm0/src/bin/uart_buffered.rs
new file mode 100644
index 000000000..135ac1287
--- /dev/null
+++ b/tests/mspm0/src/bin/uart_buffered.rs
@@ -0,0 +1,115 @@
1#![no_std]
2#![no_main]
3
4#[cfg(feature = "mspm0g3507")]
5teleprobe_meta::target!(b"lp-mspm0g3507");
6
7use defmt::{assert_eq, unwrap, *};
8use embassy_executor::Spawner;
9use embassy_mspm0::uart::{BufferedInterruptHandler, BufferedUart, Config};
10use embassy_mspm0::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 UART1 => BufferedInterruptHandler<peripherals::UART1>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_mspm0::init(Default::default());
20 info!("Hello World!");
21
22 // TODO: Allow creating a looped-back UART (so pins are not needed).
23 // Do not select default UART since the virtual COM port is attached to UART0.
24 #[cfg(any(feature = "mspm0g3507"))]
25 let (mut tx, mut rx, mut uart) = (p.PA8, p.PA9, p.UART1);
26
27 {
28 use embedded_io_async::{Read, Write};
29
30 let mut config = Config::default();
31 config.loop_back_enable = true;
32 config.fifo_enable = false;
33
34 let tx_buf = &mut [0u8; 16];
35 let rx_buf = &mut [0u8; 16];
36 let mut uart = unwrap!(BufferedUart::new(
37 uart.reborrow(),
38 tx.reborrow(),
39 rx.reborrow(),
40 Irqs,
41 tx_buf,
42 rx_buf,
43 config
44 ));
45
46 let mut buf = [0; 16];
47 for (j, b) in buf.iter_mut().enumerate() {
48 *b = j as u8;
49 }
50
51 unwrap!(uart.write_all(&buf).await);
52 unwrap!(uart.flush().await);
53
54 unwrap!(uart.read_exact(&mut buf).await);
55 for (j, b) in buf.iter().enumerate() {
56 assert_eq!(*b, j as u8);
57 }
58
59 // Buffer is unclogged, should be able to write again.
60 unwrap!(uart.write_all(&buf).await);
61 unwrap!(uart.flush().await);
62
63 unwrap!(uart.read_exact(&mut buf).await);
64 for (j, b) in buf.iter().enumerate() {
65 assert_eq!(*b, j as u8);
66 }
67 }
68
69 info!("Blocking buffered");
70 {
71 use embedded_io::{Read, Write};
72
73 let mut config = Config::default();
74 config.loop_back_enable = true;
75 config.fifo_enable = false;
76
77 let tx_buf = &mut [0u8; 16];
78 let rx_buf = &mut [0u8; 16];
79 let mut uart = unwrap!(BufferedUart::new(
80 uart.reborrow(),
81 tx.reborrow(),
82 rx.reborrow(),
83 Irqs,
84 tx_buf,
85 rx_buf,
86 config
87 ));
88
89 let mut buf = [0; 16];
90
91 for (j, b) in buf.iter_mut().enumerate() {
92 *b = j as u8;
93 }
94
95 unwrap!(uart.write_all(&buf));
96 unwrap!(uart.blocking_flush());
97 unwrap!(uart.read_exact(&mut buf));
98
99 for (j, b) in buf.iter().enumerate() {
100 assert_eq!(*b, j as u8);
101 }
102
103 // Buffer is unclogged, should be able to write again.
104 unwrap!(uart.write_all(&buf));
105 unwrap!(uart.blocking_flush());
106 unwrap!(uart.read_exact(&mut buf));
107
108 for (j, b) in buf.iter().enumerate() {
109 assert_eq!(*b, j as u8, "at {}", j);
110 }
111 }
112
113 info!("Test OK");
114 cortex_m::asm::bkpt();
115}