aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-03-21 13:32:14 +0000
committerGitHub <[email protected]>2025-03-21 13:32:14 +0000
commite29be82c8bc1b7e2dbf9f58dad4229d12968e1b4 (patch)
tree4ae9e7b784c82b96bcf870c3f61c62abad8a3811
parentfecb7a2b2b6f1953a2fe57557cb83d063ab5eea4 (diff)
parent91684a11c8a15b62a773a1ace40791fcf80fdad2 (diff)
Merge pull request #3966 from i509VCB/mspm0-init
Embassy for MSPM0
-rwxr-xr-x.github/ci/doc.sh1
-rw-r--r--.vscode/settings.json5
-rw-r--r--README.md1
-rwxr-xr-xci.sh14
-rw-r--r--docs/pages/overview.adoc1
-rw-r--r--embassy-mspm0/Cargo.toml131
-rw-r--r--embassy-mspm0/build.rs611
-rw-r--r--embassy-mspm0/build_common.rs94
-rw-r--r--embassy-mspm0/src/fmt.rs270
-rw-r--r--embassy-mspm0/src/gpio.rs1060
-rw-r--r--embassy-mspm0/src/int_group/c110x.rs25
-rw-r--r--embassy-mspm0/src/int_group/g350x.rs51
-rw-r--r--embassy-mspm0/src/int_group/g351x.rs52
-rw-r--r--embassy-mspm0/src/int_group/l130x.rs46
-rw-r--r--embassy-mspm0/src/int_group/l222x.rs49
-rw-r--r--embassy-mspm0/src/lib.rs107
-rw-r--r--embassy-mspm0/src/time_driver.rs423
-rw-r--r--embassy-mspm0/src/timer.rs48
-rw-r--r--examples/mspm0c1104/.cargo/config.toml11
-rw-r--r--examples/mspm0c1104/Cargo.toml32
-rw-r--r--examples/mspm0c1104/README.md27
-rw-r--r--examples/mspm0c1104/build.rs35
-rw-r--r--examples/mspm0c1104/memory.x5
-rw-r--r--examples/mspm0c1104/src/bin/blinky.rs25
-rw-r--r--examples/mspm0c1104/src/bin/button.rs33
-rw-r--r--examples/mspm0g3507/.cargo/config.toml9
-rw-r--r--examples/mspm0g3507/Cargo.toml21
-rw-r--r--examples/mspm0g3507/README.md27
-rw-r--r--examples/mspm0g3507/build.rs35
-rw-r--r--examples/mspm0g3507/memory.x6
-rw-r--r--examples/mspm0g3507/src/bin/blinky.rs25
-rw-r--r--examples/mspm0g3507/src/bin/button.rs33
-rw-r--r--examples/mspm0g3519/.cargo/config.toml9
-rw-r--r--examples/mspm0g3519/Cargo.toml21
-rw-r--r--examples/mspm0g3519/README.md27
-rw-r--r--examples/mspm0g3519/build.rs35
-rw-r--r--examples/mspm0g3519/memory.x6
-rw-r--r--examples/mspm0g3519/src/bin/blinky.rs25
-rw-r--r--examples/mspm0g3519/src/bin/button.rs33
-rw-r--r--examples/mspm0l1306/.cargo/config.toml9
-rw-r--r--examples/mspm0l1306/Cargo.toml21
-rw-r--r--examples/mspm0l1306/README.md27
-rw-r--r--examples/mspm0l1306/build.rs35
-rw-r--r--examples/mspm0l1306/memory.x5
-rw-r--r--examples/mspm0l1306/src/bin/blinky.rs25
-rw-r--r--examples/mspm0l1306/src/bin/button.rs33
-rw-r--r--examples/mspm0l2228/.cargo/config.toml9
-rw-r--r--examples/mspm0l2228/Cargo.toml21
-rw-r--r--examples/mspm0l2228/README.md27
-rw-r--r--examples/mspm0l2228/build.rs35
-rw-r--r--examples/mspm0l2228/memory.x6
-rw-r--r--examples/mspm0l2228/src/bin/blinky.rs25
-rw-r--r--examples/mspm0l2228/src/bin/button.rs33
53 files changed, 3780 insertions, 0 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index c92892406..58ffe5f2e 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -25,6 +25,7 @@ docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.z
25docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup 25docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
26docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup 26docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
27docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup 27docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
28docserver-builder -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
28docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup 29docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
29docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup 30docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
30docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup 31docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 48d0957e6..e4814ff27 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -28,6 +28,11 @@
28 // To work on the examples, comment the line above and all of the cargo.features lines, 28 // To work on the examples, comment the line above and all of the cargo.features lines,
29 // then uncomment ONE line below to select the chip you want to work on. 29 // then uncomment ONE line below to select the chip you want to work on.
30 // This makes rust-analyzer work on the example crate and all its dependencies. 30 // This makes rust-analyzer work on the example crate and all its dependencies.
31 // "examples/mspm0c1104/Cargo.toml",
32 // "examples/mspm0g3507/Cargo.toml",
33 // "examples/mspm0g3519/Cargo.toml",
34 // "examples/mspm0l1306/Cargo.toml",
35 // "examples/mspm0l2228/Cargo.toml",
31 // "examples/nrf52840-rtic/Cargo.toml", 36 // "examples/nrf52840-rtic/Cargo.toml",
32 // "examples/nrf5340/Cargo.toml", 37 // "examples/nrf5340/Cargo.toml",
33 // "examples/nrf-rtos-trace/Cargo.toml", 38 // "examples/nrf-rtos-trace/Cargo.toml",
diff --git a/README.md b/README.md
index e9f0d3b24..c64a07be8 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families. 15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families.
16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. 16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series.
17 - <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 and RP23xx microcontrollers. 17 - <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 and RP23xx microcontrollers.
18 - <a href="https://docs.embassy.dev/embassy-mspm0/">embassy-mspm0</a>, for the Texas Instruments MSPM0 microcontrollers.
18 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips. 19 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips.
19 - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. 20 - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
20 - <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips. 21 - <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips.
diff --git a/ci.sh b/ci.sh
index e32105b16..5b63c507b 100755
--- a/ci.sh
+++ b/ci.sh
@@ -170,6 +170,11 @@ cargo batch \
170 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ 170 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
171 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ 171 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
172 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \ 172 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \
173 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c110x,defmt,time-driver-any \
174 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g350x,defmt,time-driver-any \
175 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g351x,defmt,time-driver-any \
176 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l130x,defmt,time-driver-any \
177 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l222x,defmt,time-driver-any \
173 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ 178 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
174 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ 179 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
175 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 180 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
@@ -239,6 +244,10 @@ cargo batch \
239 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ 244 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
240 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ 245 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
241 --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ 246 --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
247 --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
248 --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
249 --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
250 --- build --release --manifest-path examples/mspm0l2228/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l2228 \
242 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \ 251 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \
243 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \ 252 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \
244 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \ 253 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \
@@ -303,6 +312,11 @@ cargo batch \
303 $BUILD_EXTRA 312 $BUILD_EXTRA
304 313
305 314
315# MSPM0C1104 must be built seperately since cargo batch does not consider env vars set in `.cargo/config.toml`.
316# Since the target has 1KB of ram, we need to limit defmt's buffer size.
317DEFMT_RTT_BUFFER_SIZE="72" cargo batch \
318 --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \
319
306# temporarily disabled, these boards are dead. 320# temporarily disabled, these boards are dead.
307rm -rf out/tests/stm32f103c8 321rm -rf out/tests/stm32f103c8
308rm -rf out/tests/nrf52840-dk 322rm -rf out/tests/nrf52840-dk
diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc
index abc7d25de..b169c686e 100644
--- a/docs/pages/overview.adoc
+++ b/docs/pages/overview.adoc
@@ -29,6 +29,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA
29* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. 29* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. 30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. 31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
32* link:https://docs.embassy.dev/embassy-mspm0/[embassy-mspm0], for the Texas Instruments MSPM0 microcontrollers.
32* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. 33* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
33* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. 34* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips.
34* link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC. 35* link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC.
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
new file mode 100644
index 000000000..cfe0c85a9
--- /dev/null
+++ b/embassy-mspm0/Cargo.toml
@@ -0,0 +1,131 @@
1[package]
2name = "embassy-mspm0"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers"
7keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"]
8categories = ["embedded", "hardware-support", "no-std", "asynchronous"]
9repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/embassy-mspm0"
11
12[package.metadata.embassy_docs]
13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-mspm0-v$VERSION/embassy-mspm0/src/"
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-mspm0/src/"
15
16features = ["defmt", "unstable-pac", "time-driver-any"]
17
18[package.metadata.docs.rs]
19features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"]
20rustdoc-args = ["--cfg", "docsrs"]
21
22[dependencies]
23embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
24embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
25# TODO: Support other tick rates
26embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true, features = ["tick-hz-32_768"] }
27embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
28embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
29embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
30embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false }
31embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
32
33embedded-hal = { version = "1.0" }
34embedded-hal-async = { version = "1.0" }
35
36defmt = { version = "0.3", optional = true }
37log = { version = "0.4.14", optional = true }
38cortex-m-rt = ">=0.6.15,<0.8"
39cortex-m = "0.7.6"
40critical-section = "1.2.0"
41
42# mspm0-metapac = { version = "" }
43mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d" }
44
45[build-dependencies]
46proc-macro2 = "1.0.94"
47quote = "1.0.40"
48
49# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
50mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d", default-features = false, features = ["metadata"] }
51
52[features]
53default = ["rt"]
54
55## Enable `mspm0-metapac`'s `rt` feature
56rt = ["mspm0-metapac/rt"]
57
58## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging
59defmt = [
60 "dep:defmt",
61 "embassy-sync/defmt",
62 "embassy-embedded-hal/defmt",
63 "embassy-hal-internal/defmt",
64 "embassy-time?/defmt",
65]
66
67## Re-export mspm0-metapac at `mspm0::pac`.
68## This is unstable because semver-minor (non-breaking) releases of embassy-mspm0 may major-bump (breaking) the mspm0-metapac version.
69## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
70## There are no plans to make this stable.
71unstable-pac = []
72
73#! ## Time
74
75# Features starting with `_` are for internal use only. They're not intended
76# to be enabled by other crates, and are not covered by semver guarantees.
77_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
78
79# Use any time driver
80time-driver-any = ["_time-driver"]
81## Use TIMG0 as time driver
82time-driver-timg0 = ["_time-driver"]
83## Use TIMG1 as time driver
84time-driver-timg1 = ["_time-driver"]
85## Use TIMG2 as time driver
86time-driver-timg2 = ["_time-driver"]
87## Use TIMG3 as time driver
88time-driver-timg3 = ["_time-driver"]
89## Use TIMG4 as time driver
90time-driver-timg4 = ["_time-driver"]
91## Use TIMG5 as time driver
92time-driver-timg5 = ["_time-driver"]
93## Use TIMG6 as time driver
94time-driver-timg6 = ["_time-driver"]
95## Use TIMG7 as time driver
96time-driver-timg7 = ["_time-driver"]
97## Use TIMG8 as time driver
98time-driver-timg8 = ["_time-driver"]
99## Use TIMG9 as time driver
100time-driver-timg9 = ["_time-driver"]
101## Use TIMG10 as time driver
102time-driver-timg10 = ["_time-driver"]
103## Use TIMG11 as time driver
104time-driver-timg11 = ["_time-driver"]
105# TODO: Support TIMG12 and TIMG13
106## Use TIMG14 as time driver
107time-driver-timg14 = ["_time-driver"]
108## Use TIMA0 as time driver
109time-driver-tima0 = ["_time-driver"]
110## Use TIMA1 as time driver
111time-driver-tima1 = ["_time-driver"]
112
113#! ## Chip-selection features
114#! Select your chip by specifying the model as a feature, e.g. `mspm0g350x`.
115#! Check the `Cargo.toml` for the latest list of supported chips.
116#!
117#! **Important:** Do not forget to adapt the target chip in your toolchain,
118#! e.g. in `.cargo/config.toml`.
119
120mspm0c110x = [ "mspm0-metapac/mspm0c110x" ]
121mspm0g110x = [ "mspm0-metapac/mspm0g110x" ]
122mspm0g150x = [ "mspm0-metapac/mspm0g150x" ]
123mspm0g151x = [ "mspm0-metapac/mspm0g151x" ]
124mspm0g310x = [ "mspm0-metapac/mspm0g310x" ]
125mspm0g350x = [ "mspm0-metapac/mspm0g350x" ]
126mspm0g351x = [ "mspm0-metapac/mspm0g351x" ]
127mspm0l110x = [ "mspm0-metapac/mspm0l110x" ]
128mspm0l122x = [ "mspm0-metapac/mspm0l122x" ]
129mspm0l130x = [ "mspm0-metapac/mspm0l130x" ]
130mspm0l134x = [ "mspm0-metapac/mspm0l134x" ]
131mspm0l222x = [ "mspm0-metapac/mspm0l222x" ]
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs
new file mode 100644
index 000000000..8c6dd4a5c
--- /dev/null
+++ b/embassy-mspm0/build.rs
@@ -0,0 +1,611 @@
1use std::collections::HashMap;
2use std::io::Write;
3use std::path::{Path, PathBuf};
4use std::process::Command;
5use std::sync::LazyLock;
6use std::{env, fs};
7
8use common::CfgSet;
9use mspm0_metapac::metadata::METADATA;
10use proc_macro2::{Ident, Literal, Span, TokenStream};
11use quote::{format_ident, quote};
12
13#[path = "./build_common.rs"]
14mod common;
15
16fn main() {
17 generate_code();
18}
19
20fn generate_code() {
21 let mut cfgs = common::CfgSet::new();
22 common::set_target_cfgs(&mut cfgs);
23
24 cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]);
25
26 let mut singletons = Vec::new();
27
28 // Generate singletons for GPIO pins. To only consider pins available on a family, use the name of
29 // the pins from the pincm mappings.
30 for pincm_mapping in METADATA.pincm_mappings.iter() {
31 singletons.push(pincm_mapping.pin.to_string());
32 }
33
34 for peri in METADATA.peripherals {
35 match peri.kind {
36 // Specially generated.
37 "gpio" => match peri.name {
38 "GPIOB" => cfgs.enable("gpio_pb"),
39 "GPIOC" => cfgs.enable("gpio_pc"),
40 _ => (),
41 },
42
43 // These peripherals are managed internally by the hal.
44 "iomux" | "cpuss" => {}
45
46 _ => singletons.push(peri.name.to_string()),
47 }
48 }
49
50 time_driver(&singletons, &mut cfgs);
51
52 // ========
53 // Write singletons
54 let mut g = TokenStream::new();
55
56 let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect();
57
58 g.extend(quote! {
59 embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*);
60 });
61
62 g.extend(quote! {
63 embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*);
64 });
65
66 // ========
67 // Generate GPIO pincm lookup tables.
68 let pincms = METADATA.pincm_mappings.iter().map(|mapping| {
69 let port_letter = mapping.pin.strip_prefix("P").unwrap();
70 let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32;
71 // This assumes all ports are single letter length.
72 // This is fine unless TI releases a part with 833+ GPIO pins.
73 let pin_number = mapping.pin[2..].parse::<u8>().unwrap();
74
75 let num = port_base + pin_number;
76
77 // But subtract 1 since pincm indices start from 0, not 1.
78 let pincm = Literal::u8_unsuffixed(mapping.pincm - 1);
79 quote! {
80 #num => #pincm
81 }
82 });
83
84 g.extend(quote! {
85 #[doc = "Get the mapping from GPIO pin port to IOMUX PINCM index. This is required since the mapping from IO to PINCM index is not consistent across parts."]
86 pub(crate) fn gpio_pincm(pin_port: u8) -> u8 {
87 match pin_port {
88 #(#pincms),*,
89 _ => unreachable!(),
90 }
91 }
92 });
93
94 for pincm_mapping in METADATA.pincm_mappings.iter() {
95 let name = Ident::new(&pincm_mapping.pin, Span::call_site());
96 let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap();
97 let port_letter = port_letter.chars().next().unwrap();
98 let pin_number = Literal::u8_unsuffixed(pincm_mapping.pin[2..].parse::<u8>().unwrap());
99
100 let port = Ident::new(&format!("Port{}", port_letter), Span::call_site());
101
102 // TODO: Feature gate pins that can be used as NRST
103
104 g.extend(quote! {
105 impl_pin!(#name, crate::gpio::Port::#port, #pin_number);
106 });
107 }
108
109 // Generate timers
110 for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("TIM")) {
111 let name = Ident::new(&peripheral.name, Span::call_site());
112 let timers = &*TIMERS;
113
114 let timer = timers.get(peripheral.name).expect("Timer does not exist");
115 assert!(timer.bits == 16 || timer.bits == 32);
116 let bits = if timer.bits == 16 {
117 quote! { Bits16 }
118 } else {
119 quote! { Bits32 }
120 };
121
122 g.extend(quote! {
123 impl_timer!(#name, #bits);
124 });
125 }
126
127 // Generate interrupt module
128 let interrupts: Vec<Ident> = METADATA
129 .interrupts
130 .iter()
131 .map(|interrupt| Ident::new(interrupt.name, Span::call_site()))
132 .collect();
133
134 g.extend(quote! {
135 embassy_hal_internal::interrupt_mod! {
136 #(#interrupts),*
137 }
138 });
139
140 let group_interrupt_enables = METADATA
141 .interrupts
142 .iter()
143 .filter(|interrupt| interrupt.name.contains("GROUP"))
144 .map(|interrupt| {
145 let name = Ident::new(interrupt.name, Span::call_site());
146
147 quote! {
148 crate::interrupt::typelevel::#name::enable();
149 }
150 });
151
152 // Generate interrupt enables for groups
153 g.extend(quote! {
154 pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) {
155 use crate::interrupt::typelevel::Interrupt;
156
157 unsafe {
158 #(#group_interrupt_enables)*
159 }
160 }
161 });
162
163 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
164 let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
165 fs::write(&out_file, g.to_string()).unwrap();
166 rustfmt(&out_file);
167}
168
169fn time_driver(singletons: &[String], cfgs: &mut CfgSet) {
170 // Timer features
171 for (timer, desc) in TIMERS.iter() {
172 if desc.bits != 16 {
173 continue;
174 }
175
176 let name = timer.to_lowercase();
177 cfgs.declare(&format!("time_driver_{}", name));
178 }
179
180 let time_driver = match env::vars()
181 .map(|(a, _)| a)
182 .filter(|x| x.starts_with("CARGO_FEATURE_TIME_DRIVER_"))
183 .get_one()
184 {
185 Ok(x) => Some(
186 x.strip_prefix("CARGO_FEATURE_TIME_DRIVER_")
187 .unwrap()
188 .to_ascii_lowercase(),
189 ),
190 Err(GetOneError::None) => None,
191 Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"),
192 };
193
194 // Verify the selected timer is available
195 let singleton = match time_driver.as_ref().map(|x| x.as_ref()) {
196 None => "",
197 Some("timg0") => "TIMG0",
198 Some("timg1") => "TIMG1",
199 Some("timg2") => "TIMG2",
200 Some("timg3") => "TIMG3",
201 Some("timg4") => "TIMG4",
202 Some("timg5") => "TIMG5",
203 Some("timg6") => "TIMG6",
204 Some("timg7") => "TIMG7",
205 Some("timg8") => "TIMG8",
206 Some("timg9") => "TIMG9",
207 Some("timg10") => "TIMG10",
208 Some("timg11") => "TIMG11",
209 Some("timg14") => "TIMG14",
210 Some("tima0") => "TIMA0",
211 Some("tima1") => "TIMA1",
212 Some("any") => {
213 // Order of timer candidates:
214 // 1. 16-bit, 2 channel
215 // 2. 16-bit, 2 channel with shadow registers
216 // 3. 16-bit, 4 channel
217 // 4. 16-bit with QEI
218 // 5. Advanced timers
219 //
220 // TODO: Select RTC first if available
221 // TODO: 32-bit timers are not considered yet
222 [
223 // 16-bit, 2 channel
224 "TIMG0", "TIMG1", "TIMG2", "TIMG3", // 16-bit, 2 channel with shadow registers
225 "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel
226 "TIMG14", // 16-bit with QEI
227 "TIMG8", "TIMG9", "TIMG10", "TIMG11", // Advanced timers
228 "TIMA0", "TIMA1",
229 ]
230 .iter()
231 .find(|tim| singletons.contains(&tim.to_string()))
232 .expect("Could not find any timer")
233 }
234 _ => panic!("unknown time_driver {:?}", time_driver),
235 };
236
237 if !singleton.is_empty() {
238 cfgs.enable(format!("time_driver_{}", singleton.to_lowercase()));
239 }
240}
241
242/// rustfmt a given path.
243/// Failures are logged to stderr and ignored.
244fn rustfmt(path: impl AsRef<Path>) {
245 let path = path.as_ref();
246 match Command::new("rustfmt").args([path]).output() {
247 Err(e) => {
248 eprintln!("failed to exec rustfmt {:?}: {:?}", path, e);
249 }
250 Ok(out) => {
251 if !out.status.success() {
252 eprintln!("rustfmt {:?} failed:", path);
253 eprintln!("=== STDOUT:");
254 std::io::stderr().write_all(&out.stdout).unwrap();
255 eprintln!("=== STDERR:");
256 std::io::stderr().write_all(&out.stderr).unwrap();
257 }
258 }
259 }
260}
261
262#[allow(dead_code)]
263struct TimerDesc {
264 bits: u8,
265 /// Is there an 8-bit prescaler
266 prescaler: bool,
267 /// Is there a repeat counter
268 repeat_counter: bool,
269 ccp_channels_internal: u8,
270 ccp_channels_external: u8,
271 external_pwm_channels: u8,
272 phase_load: bool,
273 shadow_load: bool,
274 shadow_ccs: bool,
275 deadband: bool,
276 fault_handler: bool,
277 qei_hall: bool,
278}
279
280/// Description of all timer instances.
281const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| {
282 let mut map = HashMap::new();
283 map.insert(
284 "TIMG0".into(),
285 TimerDesc {
286 bits: 16,
287 prescaler: true,
288 repeat_counter: false,
289 ccp_channels_internal: 2,
290 ccp_channels_external: 2,
291 external_pwm_channels: 2,
292 phase_load: false,
293 shadow_load: false,
294 shadow_ccs: false,
295 deadband: false,
296 fault_handler: false,
297 qei_hall: false,
298 },
299 );
300
301 map.insert(
302 "TIMG1".into(),
303 TimerDesc {
304 bits: 16,
305 prescaler: true,
306 repeat_counter: false,
307 ccp_channels_internal: 2,
308 ccp_channels_external: 2,
309 external_pwm_channels: 2,
310 phase_load: false,
311 shadow_load: false,
312 shadow_ccs: false,
313 deadband: false,
314 fault_handler: false,
315 qei_hall: false,
316 },
317 );
318
319 map.insert(
320 "TIMG2".into(),
321 TimerDesc {
322 bits: 16,
323 prescaler: true,
324 repeat_counter: false,
325 ccp_channels_internal: 2,
326 ccp_channels_external: 2,
327 external_pwm_channels: 2,
328 phase_load: false,
329 shadow_load: false,
330 shadow_ccs: false,
331 deadband: false,
332 fault_handler: false,
333 qei_hall: false,
334 },
335 );
336
337 map.insert(
338 "TIMG3".into(),
339 TimerDesc {
340 bits: 16,
341 prescaler: true,
342 repeat_counter: false,
343 ccp_channels_internal: 2,
344 ccp_channels_external: 2,
345 external_pwm_channels: 2,
346 phase_load: false,
347 shadow_load: false,
348 shadow_ccs: false,
349 deadband: false,
350 fault_handler: false,
351 qei_hall: false,
352 },
353 );
354
355 map.insert(
356 "TIMG4".into(),
357 TimerDesc {
358 bits: 16,
359 prescaler: true,
360 repeat_counter: false,
361 ccp_channels_internal: 2,
362 ccp_channels_external: 2,
363 external_pwm_channels: 2,
364 phase_load: false,
365 shadow_load: true,
366 shadow_ccs: true,
367 deadband: false,
368 fault_handler: false,
369 qei_hall: false,
370 },
371 );
372
373 map.insert(
374 "TIMG5".into(),
375 TimerDesc {
376 bits: 16,
377 prescaler: true,
378 repeat_counter: false,
379 ccp_channels_internal: 2,
380 ccp_channels_external: 2,
381 external_pwm_channels: 2,
382 phase_load: false,
383 shadow_load: true,
384 shadow_ccs: true,
385 deadband: false,
386 fault_handler: false,
387 qei_hall: false,
388 },
389 );
390
391 map.insert(
392 "TIMG6".into(),
393 TimerDesc {
394 bits: 16,
395 prescaler: true,
396 repeat_counter: false,
397 ccp_channels_internal: 2,
398 ccp_channels_external: 2,
399 external_pwm_channels: 2,
400 phase_load: false,
401 shadow_load: true,
402 shadow_ccs: true,
403 deadband: false,
404 fault_handler: false,
405 qei_hall: false,
406 },
407 );
408
409 map.insert(
410 "TIMG7".into(),
411 TimerDesc {
412 bits: 16,
413 prescaler: true,
414 repeat_counter: false,
415 ccp_channels_internal: 2,
416 ccp_channels_external: 2,
417 external_pwm_channels: 2,
418 phase_load: false,
419 shadow_load: true,
420 shadow_ccs: true,
421 deadband: false,
422 fault_handler: false,
423 qei_hall: false,
424 },
425 );
426
427 map.insert(
428 "TIMG8".into(),
429 TimerDesc {
430 bits: 16,
431 prescaler: true,
432 repeat_counter: false,
433 ccp_channels_internal: 2,
434 ccp_channels_external: 2,
435 external_pwm_channels: 2,
436 phase_load: false,
437 shadow_load: false,
438 shadow_ccs: false,
439 deadband: false,
440 fault_handler: false,
441 qei_hall: true,
442 },
443 );
444
445 map.insert(
446 "TIMG9".into(),
447 TimerDesc {
448 bits: 16,
449 prescaler: true,
450 repeat_counter: false,
451 ccp_channels_internal: 2,
452 ccp_channels_external: 2,
453 external_pwm_channels: 2,
454 phase_load: false,
455 shadow_load: false,
456 shadow_ccs: false,
457 deadband: false,
458 fault_handler: false,
459 qei_hall: true,
460 },
461 );
462
463 map.insert(
464 "TIMG10".into(),
465 TimerDesc {
466 bits: 16,
467 prescaler: true,
468 repeat_counter: false,
469 ccp_channels_internal: 2,
470 ccp_channels_external: 2,
471 external_pwm_channels: 2,
472 phase_load: false,
473 shadow_load: false,
474 shadow_ccs: false,
475 deadband: false,
476 fault_handler: false,
477 qei_hall: true,
478 },
479 );
480
481 map.insert(
482 "TIMG11".into(),
483 TimerDesc {
484 bits: 16,
485 prescaler: true,
486 repeat_counter: false,
487 ccp_channels_internal: 2,
488 ccp_channels_external: 2,
489 external_pwm_channels: 2,
490 phase_load: false,
491 shadow_load: false,
492 shadow_ccs: false,
493 deadband: false,
494 fault_handler: false,
495 qei_hall: true,
496 },
497 );
498
499 map.insert(
500 "TIMG12".into(),
501 TimerDesc {
502 bits: 32,
503 prescaler: false,
504 repeat_counter: false,
505 ccp_channels_internal: 2,
506 ccp_channels_external: 2,
507 external_pwm_channels: 2,
508 phase_load: false,
509 shadow_load: false,
510 shadow_ccs: true,
511 deadband: false,
512 fault_handler: false,
513 qei_hall: false,
514 },
515 );
516
517 map.insert(
518 "TIMG13".into(),
519 TimerDesc {
520 bits: 32,
521 prescaler: false,
522 repeat_counter: false,
523 ccp_channels_internal: 2,
524 ccp_channels_external: 2,
525 external_pwm_channels: 2,
526 phase_load: false,
527 shadow_load: false,
528 shadow_ccs: true,
529 deadband: false,
530 fault_handler: false,
531 qei_hall: false,
532 },
533 );
534
535 map.insert(
536 "TIMG14".into(),
537 TimerDesc {
538 bits: 16,
539 prescaler: true,
540 repeat_counter: false,
541 ccp_channels_internal: 4,
542 ccp_channels_external: 4,
543 external_pwm_channels: 4,
544 phase_load: false,
545 shadow_load: false,
546 shadow_ccs: false,
547 deadband: false,
548 fault_handler: false,
549 qei_hall: false,
550 },
551 );
552
553 map.insert(
554 "TIMA0".into(),
555 TimerDesc {
556 bits: 16,
557 prescaler: true,
558 repeat_counter: true,
559 ccp_channels_internal: 4,
560 ccp_channels_external: 2,
561 external_pwm_channels: 8,
562 phase_load: true,
563 shadow_load: true,
564 shadow_ccs: true,
565 deadband: true,
566 fault_handler: true,
567 qei_hall: false,
568 },
569 );
570
571 map.insert(
572 "TIMA1".into(),
573 TimerDesc {
574 bits: 16,
575 prescaler: true,
576 repeat_counter: true,
577 ccp_channels_internal: 2,
578 ccp_channels_external: 2,
579 external_pwm_channels: 4,
580 phase_load: true,
581 shadow_load: true,
582 shadow_ccs: true,
583 deadband: true,
584 fault_handler: true,
585 qei_hall: false,
586 },
587 );
588
589 map
590});
591
592enum GetOneError {
593 None,
594 Multiple,
595}
596
597trait IteratorExt: Iterator {
598 fn get_one(self) -> Result<Self::Item, GetOneError>;
599}
600
601impl<T: Iterator> IteratorExt for T {
602 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
603 match self.next() {
604 None => Err(GetOneError::None),
605 Some(res) => match self.next() {
606 Some(_) => Err(GetOneError::Multiple),
607 None => Ok(res),
608 },
609 }
610 }
611}
diff --git a/embassy-mspm0/build_common.rs b/embassy-mspm0/build_common.rs
new file mode 100644
index 000000000..4f24e6d37
--- /dev/null
+++ b/embassy-mspm0/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-mspm0/src/fmt.rs b/embassy-mspm0/src/fmt.rs
new file mode 100644
index 000000000..8ca61bc39
--- /dev/null
+++ b/embassy-mspm0/src/fmt.rs
@@ -0,0 +1,270 @@
1#![macro_use]
2#![allow(unused)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9#[collapse_debuginfo(yes)]
10macro_rules! assert {
11 ($($x:tt)*) => {
12 {
13 #[cfg(not(feature = "defmt"))]
14 ::core::assert!($($x)*);
15 #[cfg(feature = "defmt")]
16 ::defmt::assert!($($x)*);
17 }
18 };
19}
20
21#[collapse_debuginfo(yes)]
22macro_rules! assert_eq {
23 ($($x:tt)*) => {
24 {
25 #[cfg(not(feature = "defmt"))]
26 ::core::assert_eq!($($x)*);
27 #[cfg(feature = "defmt")]
28 ::defmt::assert_eq!($($x)*);
29 }
30 };
31}
32
33#[collapse_debuginfo(yes)]
34macro_rules! assert_ne {
35 ($($x:tt)*) => {
36 {
37 #[cfg(not(feature = "defmt"))]
38 ::core::assert_ne!($($x)*);
39 #[cfg(feature = "defmt")]
40 ::defmt::assert_ne!($($x)*);
41 }
42 };
43}
44
45#[collapse_debuginfo(yes)]
46macro_rules! debug_assert {
47 ($($x:tt)*) => {
48 {
49 #[cfg(not(feature = "defmt"))]
50 ::core::debug_assert!($($x)*);
51 #[cfg(feature = "defmt")]
52 ::defmt::debug_assert!($($x)*);
53 }
54 };
55}
56
57#[collapse_debuginfo(yes)]
58macro_rules! debug_assert_eq {
59 ($($x:tt)*) => {
60 {
61 #[cfg(not(feature = "defmt"))]
62 ::core::debug_assert_eq!($($x)*);
63 #[cfg(feature = "defmt")]
64 ::defmt::debug_assert_eq!($($x)*);
65 }
66 };
67}
68
69#[collapse_debuginfo(yes)]
70macro_rules! debug_assert_ne {
71 ($($x:tt)*) => {
72 {
73 #[cfg(not(feature = "defmt"))]
74 ::core::debug_assert_ne!($($x)*);
75 #[cfg(feature = "defmt")]
76 ::defmt::debug_assert_ne!($($x)*);
77 }
78 };
79}
80
81#[collapse_debuginfo(yes)]
82macro_rules! todo {
83 ($($x:tt)*) => {
84 {
85 #[cfg(not(feature = "defmt"))]
86 ::core::todo!($($x)*);
87 #[cfg(feature = "defmt")]
88 ::defmt::todo!($($x)*);
89 }
90 };
91}
92
93#[collapse_debuginfo(yes)]
94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
102 };
103}
104
105#[collapse_debuginfo(yes)]
106macro_rules! panic {
107 ($($x:tt)*) => {
108 {
109 #[cfg(not(feature = "defmt"))]
110 ::core::panic!($($x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::panic!($($x)*);
113 }
114 };
115}
116
117#[collapse_debuginfo(yes)]
118macro_rules! trace {
119 ($s:literal $(, $x:expr)* $(,)?) => {
120 {
121 #[cfg(feature = "log")]
122 ::log::trace!($s $(, $x)*);
123 #[cfg(feature = "defmt")]
124 ::defmt::trace!($s $(, $x)*);
125 #[cfg(not(any(feature = "log", feature="defmt")))]
126 let _ = ($( & $x ),*);
127 }
128 };
129}
130
131#[collapse_debuginfo(yes)]
132macro_rules! debug {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::debug!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::debug!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145#[collapse_debuginfo(yes)]
146macro_rules! info {
147 ($s:literal $(, $x:expr)* $(,)?) => {
148 {
149 #[cfg(feature = "log")]
150 ::log::info!($s $(, $x)*);
151 #[cfg(feature = "defmt")]
152 ::defmt::info!($s $(, $x)*);
153 #[cfg(not(any(feature = "log", feature="defmt")))]
154 let _ = ($( & $x ),*);
155 }
156 };
157}
158
159#[collapse_debuginfo(yes)]
160macro_rules! warn {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::warn!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::warn!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ = ($( & $x ),*);
169 }
170 };
171}
172
173#[collapse_debuginfo(yes)]
174macro_rules! error {
175 ($s:literal $(, $x:expr)* $(,)?) => {
176 {
177 #[cfg(feature = "log")]
178 ::log::error!($s $(, $x)*);
179 #[cfg(feature = "defmt")]
180 ::defmt::error!($s $(, $x)*);
181 #[cfg(not(any(feature = "log", feature="defmt")))]
182 let _ = ($( & $x ),*);
183 }
184 };
185}
186
187#[cfg(feature = "defmt")]
188#[collapse_debuginfo(yes)]
189macro_rules! unwrap {
190 ($($x:tt)*) => {
191 ::defmt::unwrap!($($x)*)
192 };
193}
194
195#[cfg(not(feature = "defmt"))]
196#[collapse_debuginfo(yes)]
197macro_rules! unwrap {
198 ($arg:expr) => {
199 match $crate::fmt::Try::into_result($arg) {
200 ::core::result::Result::Ok(t) => t,
201 ::core::result::Result::Err(e) => {
202 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
203 }
204 }
205 };
206 ($arg:expr, $($msg:expr),+ $(,)? ) => {
207 match $crate::fmt::Try::into_result($arg) {
208 ::core::result::Result::Ok(t) => t,
209 ::core::result::Result::Err(e) => {
210 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
211 }
212 }
213 }
214}
215
216#[derive(Debug, Copy, Clone, Eq, PartialEq)]
217pub struct NoneError;
218
219pub trait Try {
220 type Ok;
221 type Error;
222 fn into_result(self) -> Result<Self::Ok, Self::Error>;
223}
224
225impl<T> Try for Option<T> {
226 type Ok = T;
227 type Error = NoneError;
228
229 #[inline]
230 fn into_result(self) -> Result<T, NoneError> {
231 self.ok_or(NoneError)
232 }
233}
234
235impl<T, E> Try for Result<T, E> {
236 type Ok = T;
237 type Error = E;
238
239 #[inline]
240 fn into_result(self) -> Self {
241 self
242 }
243}
244
245pub(crate) struct Bytes<'a>(pub &'a [u8]);
246
247impl<'a> Debug for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253impl<'a> Display for Bytes<'a> {
254 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255 write!(f, "{:#02x?}", self.0)
256 }
257}
258
259impl<'a> LowerHex for Bytes<'a> {
260 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
261 write!(f, "{:#02x?}", self.0)
262 }
263}
264
265#[cfg(feature = "defmt")]
266impl<'a> defmt::Format for Bytes<'a> {
267 fn format(&self, fmt: defmt::Formatter) {
268 defmt::write!(fmt, "{:02x}", self.0)
269 }
270}
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs
new file mode 100644
index 000000000..e1eb7eecf
--- /dev/null
+++ b/embassy-mspm0/src/gpio.rs
@@ -0,0 +1,1060 @@
1#![macro_use]
2
3use core::convert::Infallible;
4use core::future::Future;
5use core::pin::Pin as FuturePin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::pac::gpio::vals::*;
12use crate::pac::gpio::{self};
13#[cfg(all(feature = "rt", feature = "mspm0c110x"))]
14use crate::pac::interrupt;
15use crate::pac::{self};
16
17/// Represents a digital input or output level.
18#[derive(Debug, Eq, PartialEq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Level {
21 /// Logical low.
22 Low,
23 /// Logical high.
24 High,
25}
26
27impl From<bool> for Level {
28 fn from(val: bool) -> Self {
29 match val {
30 true => Self::High,
31 false => Self::Low,
32 }
33 }
34}
35
36impl From<Level> for bool {
37 fn from(level: Level) -> bool {
38 match level {
39 Level::Low => false,
40 Level::High => true,
41 }
42 }
43}
44
45/// Represents a pull setting for an input.
46#[derive(Debug, Clone, Copy, Eq, PartialEq)]
47pub enum Pull {
48 /// No pull.
49 None,
50 /// Internal pull-up resistor.
51 Up,
52 /// Internal pull-down resistor.
53 Down,
54}
55
56/// A GPIO bank with up to 32 pins.
57#[derive(Debug, Clone, Copy, Eq, PartialEq)]
58pub enum Port {
59 /// Port A.
60 PortA = 0,
61
62 /// Port B.
63 #[cfg(gpio_pb)]
64 PortB = 1,
65
66 /// Port C.
67 #[cfg(gpio_pc)]
68 PortC = 2,
69}
70
71/// GPIO flexible pin.
72///
73/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
74/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
75/// mode.
76pub struct Flex<'d> {
77 pin: PeripheralRef<'d, AnyPin>,
78}
79
80impl<'d> Flex<'d> {
81 /// Wrap the pin in a `Flex`.
82 ///
83 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
84 /// before the pin is put into output mode.
85 #[inline]
86 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
87 into_ref!(pin);
88
89 // Pin will be in disconnected state.
90 Self { pin: pin.map_into() }
91 }
92
93 /// Set the pin's pull.
94 #[inline]
95 pub fn set_pull(&mut self, pull: Pull) {
96 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
97
98 pincm.modify(|w| {
99 w.set_pipd(matches!(pull, Pull::Down));
100 w.set_pipu(matches!(pull, Pull::Up));
101 });
102 }
103
104 /// Put the pin into input mode.
105 ///
106 /// The pull setting is left unchanged.
107 #[inline]
108 pub fn set_as_input(&mut self) {
109 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
110
111 pincm.modify(|w| {
112 w.set_pf(GPIO_PF);
113 w.set_hiz1(false);
114 w.set_pc(true);
115 w.set_inena(true);
116 });
117
118 self.pin.block().doeclr31_0().write(|w| {
119 w.set_dio(self.pin.bit_index(), true);
120 });
121 }
122
123 /// Put the pin into output mode.
124 ///
125 /// The pin level will be whatever was set before (or low by default). If you want it to begin
126 /// at a specific level, call `set_high`/`set_low` on the pin first.
127 #[inline]
128 pub fn set_as_output(&mut self) {
129 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
130
131 pincm.modify(|w| {
132 w.set_pf(GPIO_PF);
133 w.set_hiz1(false);
134 w.set_pc(true);
135 w.set_inena(false);
136 });
137
138 self.pin.block().doeset31_0().write(|w| {
139 w.set_dio(self.pin.bit_index(), true);
140 });
141 }
142
143 /// Put the pin into input + open-drain output mode.
144 ///
145 /// The hardware will drive the line low if you set it to low, and will leave it floating if you set
146 /// it to high, in which case you can read the input to figure out whether another device
147 /// is driving the line low.
148 ///
149 /// The pin level will be whatever was set before (or low by default). If you want it to begin
150 /// at a specific level, call `set_high`/`set_low` on the pin first.
151 ///
152 /// The internal weak pull-up and pull-down resistors will be disabled.
153 #[inline]
154 pub fn set_as_input_output(&mut self) {
155 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
156
157 pincm.modify(|w| {
158 w.set_pf(GPIO_PF);
159 w.set_hiz1(true);
160 w.set_pc(true);
161 w.set_inena(false);
162 });
163
164 self.set_pull(Pull::None);
165 }
166
167 /// Set the pin as "disconnected", ie doing nothing and consuming the lowest
168 /// amount of power possible.
169 ///
170 /// This is currently the same as [`Self::set_as_analog()`] but is semantically different
171 /// really. Drivers should `set_as_disconnected()` pins when dropped.
172 ///
173 /// Note that this also disables the internal weak pull-up and pull-down resistors.
174 #[inline]
175 pub fn set_as_disconnected(&mut self) {
176 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
177
178 pincm.modify(|w| {
179 w.set_pf(DISCONNECT_PF);
180 w.set_hiz1(false);
181 w.set_pc(false);
182 w.set_inena(false);
183 });
184
185 self.set_pull(Pull::None);
186 self.set_inversion(false);
187 }
188
189 /// Configure the logic inversion of this pin.
190 ///
191 /// Logic inversion applies to both the input and output path of this pin.
192 #[inline]
193 pub fn set_inversion(&mut self, invert: bool) {
194 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
195
196 pincm.modify(|w| {
197 w.set_inv(invert);
198 });
199 }
200
201 // TODO: drive strength, hysteresis, wakeup enable, wakeup compare
202
203 /// Put the pin into the PF mode, unchecked.
204 ///
205 /// This puts the pin into the PF mode, with the request number. This is completely unchecked,
206 /// it can attach the pin to literally any peripheral, so use with care. In addition the pin
207 /// peripheral is connected in the iomux.
208 ///
209 /// The peripheral attached to the pin depends on the part in use. Consult the datasheet
210 /// or technical reference manual for additional details.
211 #[inline]
212 pub fn set_pf_unchecked(&mut self, pf: u8) {
213 // Per SLAU893, PF is only 5 bits
214 assert!((pf & 0x3F) != 0, "PF is out of range");
215
216 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
217
218 pincm.modify(|w| {
219 w.set_pf(pf);
220 // If the PF is manually set, connect the pin
221 w.set_pc(true);
222 });
223 }
224
225 /// Get whether the pin input level is high.
226 #[inline]
227 pub fn is_high(&self) -> bool {
228 !self.is_low()
229 }
230
231 /// Get whether the pin input level is low.
232 #[inline]
233 pub fn is_low(&self) -> bool {
234 self.pin.block().din31_0().read().dio(self.pin.bit_index())
235 }
236
237 /// Returns current pin level
238 #[inline]
239 pub fn get_level(&self) -> Level {
240 self.is_high().into()
241 }
242
243 /// Set the output as high.
244 #[inline]
245 pub fn set_high(&mut self) {
246 self.pin.block().doutset31_0().write(|w| {
247 w.set_dio(self.pin.bit_index() as usize, true);
248 });
249 }
250
251 /// Set the output as low.
252 #[inline]
253 pub fn set_low(&mut self) {
254 self.pin.block().doutclr31_0().write(|w| {
255 w.set_dio(self.pin.bit_index(), true);
256 });
257 }
258
259 /// Toggle pin output
260 #[inline]
261 pub fn toggle(&mut self) {
262 self.pin.block().douttgl31_0().write(|w| {
263 w.set_dio(self.pin.bit_index(), true);
264 })
265 }
266
267 /// Set the output level.
268 #[inline]
269 pub fn set_level(&mut self, level: Level) {
270 match level {
271 Level::Low => self.set_low(),
272 Level::High => self.set_high(),
273 }
274 }
275
276 /// Get the current pin input level.
277 #[inline]
278 pub fn get_output_level(&self) -> Level {
279 self.is_high().into()
280 }
281
282 /// Is the output level high?
283 #[inline]
284 pub fn is_set_high(&self) -> bool {
285 !self.is_set_low()
286 }
287
288 /// Is the output level low?
289 #[inline]
290 pub fn is_set_low(&self) -> bool {
291 (self.pin.block().dout31_0().read().0 & self.pin.bit_index() as u32) == 0
292 }
293
294 /// Wait until the pin is high. If it is already high, return immediately.
295 #[inline]
296 pub async fn wait_for_high(&mut self) {
297 if self.is_high() {
298 return;
299 }
300
301 self.wait_for_rising_edge().await
302 }
303
304 /// Wait until the pin is low. If it is already low, return immediately.
305 #[inline]
306 pub async fn wait_for_low(&mut self) {
307 if self.is_low() {
308 return;
309 }
310
311 self.wait_for_falling_edge().await
312 }
313
314 /// Wait for the pin to undergo a transition from low to high.
315 #[inline]
316 pub async fn wait_for_rising_edge(&mut self) {
317 InputFuture::new(self.pin.reborrow(), Polarity::RISE).await
318 }
319
320 /// Wait for the pin to undergo a transition from high to low.
321 #[inline]
322 pub async fn wait_for_falling_edge(&mut self) {
323 InputFuture::new(self.pin.reborrow(), Polarity::FALL).await
324 }
325
326 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
327 #[inline]
328 pub async fn wait_for_any_edge(&mut self) {
329 InputFuture::new(self.pin.reborrow(), Polarity::RISE_FALL).await
330 }
331}
332
333impl<'d> Drop for Flex<'d> {
334 #[inline]
335 fn drop(&mut self) {
336 self.set_as_disconnected();
337 }
338}
339
340/// GPIO input driver.
341pub struct Input<'d> {
342 pin: Flex<'d>,
343}
344
345impl<'d> Input<'d> {
346 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
347 #[inline]
348 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
349 let mut pin = Flex::new(pin);
350 pin.set_as_input();
351 pin.set_pull(pull);
352 Self { pin }
353 }
354
355 /// Get whether the pin input level is high.
356 #[inline]
357 pub fn is_high(&self) -> bool {
358 self.pin.is_high()
359 }
360
361 /// Get whether the pin input level is low.
362 #[inline]
363 pub fn is_low(&self) -> bool {
364 self.pin.is_low()
365 }
366
367 /// Get the current pin input level.
368 #[inline]
369 pub fn get_level(&self) -> Level {
370 self.pin.get_level()
371 }
372
373 /// Configure the logic inversion of this pin.
374 ///
375 /// Logic inversion applies to the input path of this pin.
376 #[inline]
377 pub fn set_inversion(&mut self, invert: bool) {
378 self.pin.set_inversion(invert)
379 }
380
381 /// Wait until the pin is high. If it is already high, return immediately.
382 #[inline]
383 pub async fn wait_for_high(&mut self) {
384 self.pin.wait_for_high().await
385 }
386
387 /// Wait until the pin is low. If it is already low, return immediately.
388 #[inline]
389 pub async fn wait_for_low(&mut self) {
390 self.pin.wait_for_low().await
391 }
392
393 /// Wait for the pin to undergo a transition from low to high.
394 #[inline]
395 pub async fn wait_for_rising_edge(&mut self) {
396 self.pin.wait_for_rising_edge().await
397 }
398
399 /// Wait for the pin to undergo a transition from high to low.
400 #[inline]
401 pub async fn wait_for_falling_edge(&mut self) {
402 self.pin.wait_for_falling_edge().await
403 }
404
405 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
406 #[inline]
407 pub async fn wait_for_any_edge(&mut self) {
408 self.pin.wait_for_any_edge().await
409 }
410}
411
412/// GPIO output driver.
413///
414/// Note that pins will **return to their floating state** when `Output` is dropped.
415/// If pins should retain their state indefinitely, either keep ownership of the
416/// `Output`, or pass it to [`core::mem::forget`].
417pub struct Output<'d> {
418 pin: Flex<'d>,
419}
420
421impl<'d> Output<'d> {
422 /// Create GPIO output driver for a [Pin] with the provided [Level] configuration.
423 #[inline]
424 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
425 let mut pin = Flex::new(pin);
426 pin.set_as_output();
427 pin.set_level(initial_output);
428 Self { pin }
429 }
430
431 /// Set the output as high.
432 #[inline]
433 pub fn set_high(&mut self) {
434 self.pin.set_high();
435 }
436
437 /// Set the output as low.
438 #[inline]
439 pub fn set_low(&mut self) {
440 self.pin.set_low();
441 }
442
443 /// Set the output level.
444 #[inline]
445 pub fn set_level(&mut self, level: Level) {
446 self.pin.set_level(level)
447 }
448
449 /// Is the output pin set as high?
450 #[inline]
451 pub fn is_set_high(&self) -> bool {
452 self.pin.is_set_high()
453 }
454
455 /// Is the output pin set as low?
456 #[inline]
457 pub fn is_set_low(&self) -> bool {
458 self.pin.is_set_low()
459 }
460
461 /// What level output is set to
462 #[inline]
463 pub fn get_output_level(&self) -> Level {
464 self.pin.get_output_level()
465 }
466
467 /// Toggle pin output
468 #[inline]
469 pub fn toggle(&mut self) {
470 self.pin.toggle();
471 }
472
473 /// Configure the logic inversion of this pin.
474 ///
475 /// Logic inversion applies to the input path of this pin.
476 #[inline]
477 pub fn set_inversion(&mut self, invert: bool) {
478 self.pin.set_inversion(invert)
479 }
480}
481
482/// GPIO output open-drain driver.
483///
484/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
485/// If pins should retain their state indefinitely, either keep ownership of the
486/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
487pub struct OutputOpenDrain<'d> {
488 pin: Flex<'d>,
489}
490
491impl<'d> OutputOpenDrain<'d> {
492 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level].
493 #[inline]
494 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
495 let mut pin = Flex::new(pin);
496 pin.set_level(initial_output);
497 pin.set_as_input_output();
498 Self { pin }
499 }
500
501 /// Get whether the pin input level is high.
502 #[inline]
503 pub fn is_high(&self) -> bool {
504 !self.pin.is_low()
505 }
506
507 /// Get whether the pin input level is low.
508 #[inline]
509 pub fn is_low(&self) -> bool {
510 self.pin.is_low()
511 }
512
513 /// Get the current pin input level.
514 #[inline]
515 pub fn get_level(&self) -> Level {
516 self.pin.get_level()
517 }
518
519 /// Set the output as high.
520 #[inline]
521 pub fn set_high(&mut self) {
522 self.pin.set_high();
523 }
524
525 /// Set the output as low.
526 #[inline]
527 pub fn set_low(&mut self) {
528 self.pin.set_low();
529 }
530
531 /// Set the output level.
532 #[inline]
533 pub fn set_level(&mut self, level: Level) {
534 self.pin.set_level(level);
535 }
536
537 /// Get whether the output level is set to high.
538 #[inline]
539 pub fn is_set_high(&self) -> bool {
540 self.pin.is_set_high()
541 }
542
543 /// Get whether the output level is set to low.
544 #[inline]
545 pub fn is_set_low(&self) -> bool {
546 self.pin.is_set_low()
547 }
548
549 /// Get the current output level.
550 #[inline]
551 pub fn get_output_level(&self) -> Level {
552 self.pin.get_output_level()
553 }
554
555 /// Toggle pin output
556 #[inline]
557 pub fn toggle(&mut self) {
558 self.pin.toggle()
559 }
560
561 /// Configure the logic inversion of this pin.
562 ///
563 /// Logic inversion applies to the input path of this pin.
564 #[inline]
565 pub fn set_inversion(&mut self, invert: bool) {
566 self.pin.set_inversion(invert)
567 }
568
569 /// Wait until the pin is high. If it is already high, return immediately.
570 #[inline]
571 pub async fn wait_for_high(&mut self) {
572 self.pin.wait_for_high().await
573 }
574
575 /// Wait until the pin is low. If it is already low, return immediately.
576 #[inline]
577 pub async fn wait_for_low(&mut self) {
578 self.pin.wait_for_low().await
579 }
580
581 /// Wait for the pin to undergo a transition from low to high.
582 #[inline]
583 pub async fn wait_for_rising_edge(&mut self) {
584 self.pin.wait_for_rising_edge().await
585 }
586
587 /// Wait for the pin to undergo a transition from high to low.
588 #[inline]
589 pub async fn wait_for_falling_edge(&mut self) {
590 self.pin.wait_for_falling_edge().await
591 }
592
593 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
594 #[inline]
595 pub async fn wait_for_any_edge(&mut self) {
596 self.pin.wait_for_any_edge().await
597 }
598}
599
600/// Type-erased GPIO pin
601pub struct AnyPin {
602 pin_port: u8,
603}
604
605impl AnyPin {
606 /// Create an [AnyPin] for a specific pin.
607 ///
608 /// # Safety
609 /// - `pin_port` should not in use by another driver.
610 #[inline]
611 pub unsafe fn steal(pin_port: u8) -> Self {
612 Self { pin_port }
613 }
614}
615
616impl_peripheral!(AnyPin);
617
618impl Pin for AnyPin {}
619impl SealedPin for AnyPin {
620 #[inline]
621 fn pin_port(&self) -> u8 {
622 self.pin_port
623 }
624}
625
626/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
627#[allow(private_bounds)]
628pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
629 fn degrade(self) -> AnyPin {
630 AnyPin {
631 pin_port: self.pin_port(),
632 }
633 }
634
635 /// The index of this pin in PINCM (pin control management) registers.
636 #[inline]
637 fn pin_cm(&self) -> u8 {
638 self._pin_cm()
639 }
640}
641
642impl<'d> embedded_hal::digital::ErrorType for Flex<'d> {
643 type Error = Infallible;
644}
645
646impl<'d> embedded_hal::digital::InputPin for Flex<'d> {
647 #[inline]
648 fn is_high(&mut self) -> Result<bool, Self::Error> {
649 Ok((*self).is_high())
650 }
651
652 #[inline]
653 fn is_low(&mut self) -> Result<bool, Self::Error> {
654 Ok((*self).is_low())
655 }
656}
657
658impl<'d> embedded_hal::digital::OutputPin for Flex<'d> {
659 #[inline]
660 fn set_low(&mut self) -> Result<(), Self::Error> {
661 Ok(self.set_low())
662 }
663
664 #[inline]
665 fn set_high(&mut self) -> Result<(), Self::Error> {
666 Ok(self.set_high())
667 }
668}
669
670impl<'d> embedded_hal::digital::StatefulOutputPin for Flex<'d> {
671 #[inline]
672 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
673 Ok((*self).is_set_high())
674 }
675
676 #[inline]
677 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
678 Ok((*self).is_set_low())
679 }
680}
681
682impl<'d> embedded_hal_async::digital::Wait for Flex<'d> {
683 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
684 self.wait_for_high().await;
685 Ok(())
686 }
687
688 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
689 self.wait_for_low().await;
690 Ok(())
691 }
692
693 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
694 self.wait_for_rising_edge().await;
695 Ok(())
696 }
697
698 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
699 self.wait_for_falling_edge().await;
700 Ok(())
701 }
702
703 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
704 self.wait_for_any_edge().await;
705 Ok(())
706 }
707}
708
709impl<'d> embedded_hal::digital::ErrorType for Input<'d> {
710 type Error = Infallible;
711}
712
713impl<'d> embedded_hal::digital::InputPin for Input<'d> {
714 #[inline]
715 fn is_high(&mut self) -> Result<bool, Self::Error> {
716 Ok((*self).is_high())
717 }
718
719 #[inline]
720 fn is_low(&mut self) -> Result<bool, Self::Error> {
721 Ok((*self).is_low())
722 }
723}
724
725impl<'d> embedded_hal_async::digital::Wait for Input<'d> {
726 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
727 self.wait_for_high().await;
728 Ok(())
729 }
730
731 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
732 self.wait_for_low().await;
733 Ok(())
734 }
735
736 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
737 self.wait_for_rising_edge().await;
738 Ok(())
739 }
740
741 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
742 self.wait_for_falling_edge().await;
743 Ok(())
744 }
745
746 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
747 self.wait_for_any_edge().await;
748 Ok(())
749 }
750}
751
752impl<'d> embedded_hal::digital::ErrorType for Output<'d> {
753 type Error = Infallible;
754}
755
756impl<'d> embedded_hal::digital::OutputPin for Output<'d> {
757 #[inline]
758 fn set_low(&mut self) -> Result<(), Self::Error> {
759 Ok(self.set_low())
760 }
761
762 #[inline]
763 fn set_high(&mut self) -> Result<(), Self::Error> {
764 Ok(self.set_high())
765 }
766}
767
768impl<'d> embedded_hal::digital::StatefulOutputPin for Output<'d> {
769 #[inline]
770 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
771 Ok((*self).is_set_high())
772 }
773
774 #[inline]
775 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
776 Ok((*self).is_set_low())
777 }
778}
779
780impl<'d> embedded_hal::digital::ErrorType for OutputOpenDrain<'d> {
781 type Error = Infallible;
782}
783
784impl<'d> embedded_hal::digital::InputPin for OutputOpenDrain<'d> {
785 #[inline]
786 fn is_high(&mut self) -> Result<bool, Self::Error> {
787 Ok((*self).is_high())
788 }
789
790 #[inline]
791 fn is_low(&mut self) -> Result<bool, Self::Error> {
792 Ok((*self).is_low())
793 }
794}
795
796impl<'d> embedded_hal::digital::OutputPin for OutputOpenDrain<'d> {
797 #[inline]
798 fn set_low(&mut self) -> Result<(), Self::Error> {
799 Ok(self.set_low())
800 }
801
802 #[inline]
803 fn set_high(&mut self) -> Result<(), Self::Error> {
804 Ok(self.set_high())
805 }
806}
807
808impl<'d> embedded_hal::digital::StatefulOutputPin for OutputOpenDrain<'d> {
809 #[inline]
810 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
811 Ok((*self).is_set_high())
812 }
813
814 #[inline]
815 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
816 Ok((*self).is_set_low())
817 }
818}
819
820impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
821 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
822 self.wait_for_high().await;
823 Ok(())
824 }
825
826 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
827 self.wait_for_low().await;
828 Ok(())
829 }
830
831 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
832 self.wait_for_rising_edge().await;
833 Ok(())
834 }
835
836 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
837 self.wait_for_falling_edge().await;
838 Ok(())
839 }
840
841 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
842 self.wait_for_any_edge().await;
843 Ok(())
844 }
845}
846
847/// The pin function to disconnect peripherals from the pin.
848///
849/// This is also the pin function used to connect to analog peripherals, such as an ADC.
850const DISCONNECT_PF: u8 = 0;
851
852/// The pin function for the GPIO peripheral.
853///
854/// This is fixed to `1` for every part.
855const GPIO_PF: u8 = 1;
856
857macro_rules! impl_pin {
858 ($name: ident, $port: expr, $pin_num: expr) => {
859 impl crate::gpio::Pin for crate::peripherals::$name {}
860 impl crate::gpio::SealedPin for crate::peripherals::$name {
861 #[inline]
862 fn pin_port(&self) -> u8 {
863 ($port as u8) * 32 + $pin_num
864 }
865 }
866
867 impl From<crate::peripherals::$name> for crate::gpio::AnyPin {
868 fn from(val: crate::peripherals::$name) -> Self {
869 crate::gpio::Pin::degrade(val)
870 }
871 }
872 };
873}
874
875// TODO: Possible micro-op for C110X, not every pin is instantiated even on the 20 pin parts.
876// This would mean cfg guarding to just cfg guarding every pin instance.
877static PORTA_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
878#[cfg(gpio_pb)]
879static PORTB_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
880#[cfg(gpio_pc)]
881static PORTC_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
882
883pub(crate) trait SealedPin {
884 fn pin_port(&self) -> u8;
885
886 fn port(&self) -> Port {
887 match self.pin_port() / 32 {
888 0 => Port::PortA,
889 #[cfg(gpio_pb)]
890 1 => Port::PortB,
891 #[cfg(gpio_pc)]
892 2 => Port::PortC,
893 _ => unreachable!(),
894 }
895 }
896
897 fn waker(&self) -> &AtomicWaker {
898 match self.port() {
899 Port::PortA => &PORTA_WAKERS[self.bit_index()],
900 #[cfg(gpio_pb)]
901 Port::PortB => &PORTB_WAKERS[self.bit_index()],
902 #[cfg(gpio_pc)]
903 Port::PortC => &PORTC_WAKERS[self.bit_index()],
904 }
905 }
906
907 fn _pin_cm(&self) -> u8 {
908 // Some parts like the MSPM0L222x have pincm mappings all over the place.
909 crate::gpio_pincm(self.pin_port())
910 }
911
912 fn bit_index(&self) -> usize {
913 (self.pin_port() % 32) as usize
914 }
915
916 #[inline]
917 fn block(&self) -> gpio::Gpio {
918 match self.pin_port() / 32 {
919 0 => pac::GPIOA,
920 #[cfg(gpio_pb)]
921 1 => pac::GPIOB,
922 #[cfg(gpio_pc)]
923 2 => pac::GPIOC,
924 _ => unreachable!(),
925 }
926 }
927}
928
929#[must_use = "futures do nothing unless you `.await` or poll them"]
930struct InputFuture<'d> {
931 pin: PeripheralRef<'d, AnyPin>,
932}
933
934impl<'d> InputFuture<'d> {
935 fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self {
936 let block = pin.block();
937
938 // First clear the bit for this event. Otherwise previous edge events may be recorded.
939 block.cpu_int().iclr().write(|w| {
940 w.set_dio(pin.bit_index(), true);
941 });
942
943 // Selecting which polarity events happens is a RMW operation.
944 //
945 // Guard with a critical section in case two different threads try to select events at the
946 // same time.
947 critical_section::with(|_cs| {
948 // Tell the hardware which pin event we want to receive.
949 if pin.bit_index() >= 16 {
950 block.polarity31_16().modify(|w| {
951 w.set_dio(pin.bit_index() - 16, polarity);
952 });
953 } else {
954 block.polarity15_0().modify(|w| {
955 w.set_dio(pin.bit_index(), polarity);
956 });
957 };
958 });
959
960 Self { pin }
961 }
962}
963
964impl<'d> Future for InputFuture<'d> {
965 type Output = ();
966
967 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
968 // We need to register/re-register the waker for each poll because any
969 // calls to wake will deregister the waker.
970 let waker = self.pin.waker();
971 waker.register(cx.waker());
972
973 // The interrupt handler will mask the interrupt if the event has occurred.
974 if self.pin.block().cpu_int().ris().read().dio(self.pin.bit_index()) {
975 return Poll::Ready(());
976 }
977
978 // Unmasking the interrupt is a RMW operation.
979 //
980 // Guard with a critical section in case two different threads try to unmask at the same time.
981 critical_section::with(|_cs| {
982 self.pin.block().cpu_int().imask().modify(|w| {
983 w.set_dio(self.pin.bit_index(), true);
984 });
985 });
986
987 Poll::Pending
988 }
989}
990
991pub(crate) fn init(gpio: gpio::Gpio) {
992 gpio.gprcm().rstctl().write(|w| {
993 w.set_resetstkyclr(true);
994 w.set_resetassert(true);
995 w.set_key(ResetKey::KEY);
996 });
997
998 gpio.gprcm().pwren().write(|w| {
999 w.set_enable(true);
1000 w.set_key(PwrenKey::KEY);
1001 });
1002
1003 gpio.evt_mode().modify(|w| {
1004 // The CPU will clear it's own interrupts
1005 w.set_cpu_cfg(EvtCfg::SOFTWARE);
1006 });
1007}
1008
1009#[cfg(feature = "rt")]
1010fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) {
1011 // Only consider pins which have interrupts unmasked.
1012 let bits = gpio.cpu_int().mis().read().0;
1013
1014 for i in BitIter(bits) {
1015 wakers[i as usize].wake();
1016
1017 // Notify the future that an edge event has occurred by masking the interrupt for this pin.
1018 gpio.cpu_int().imask().modify(|w| {
1019 w.set_dio(i as usize, false);
1020 });
1021 }
1022}
1023
1024struct BitIter(u32);
1025
1026impl Iterator for BitIter {
1027 type Item = u32;
1028
1029 fn next(&mut self) -> Option<Self::Item> {
1030 match self.0.trailing_zeros() {
1031 32 => None,
1032 b => {
1033 self.0 &= !(1 << b);
1034 Some(b)
1035 }
1036 }
1037 }
1038}
1039
1040// C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt.
1041#[cfg(all(feature = "rt", feature = "mspm0c110x"))]
1042#[interrupt]
1043fn GPIOA() {
1044 gpioa_interrupt();
1045}
1046
1047#[cfg(feature = "rt")]
1048pub(crate) fn gpioa_interrupt() {
1049 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1050}
1051
1052#[cfg(all(feature = "rt", gpio_pb))]
1053pub(crate) fn gpiob_interrupt() {
1054 irq_handler(pac::GPIOB, &PORTB_WAKERS);
1055}
1056
1057#[cfg(all(feature = "rt", gpio_pc))]
1058pub(crate) fn gpioc_interrupt() {
1059 irq_handler(pac::GPIOC, &PORTC_WAKERS);
1060}
diff --git a/embassy-mspm0/src/int_group/c110x.rs b/embassy-mspm0/src/int_group/c110x.rs
new file mode 100644
index 000000000..e6a9ddb99
--- /dev/null
+++ b/embassy-mspm0/src/int_group/c110x.rs
@@ -0,0 +1,25 @@
1use crate::pac;
2use crate::pac::interrupt;
3
4#[cfg(feature = "rt")]
5#[interrupt]
6fn GROUP0() {
7 use mspm0_metapac::Group0;
8
9 let group = pac::CPUSS.int_group(0);
10
11 // TODO: Decompose to direct u8
12 let iidx = group.iidx().read().stat().to_bits();
13
14 let Ok(group) = pac::Group0::try_from(iidx as u8) else {
15 debug!("Invalid IIDX for group 0: {}", iidx);
16 return;
17 };
18
19 match group {
20 Group0::WWDT0 => todo!("implement WWDT0"),
21 Group0::DEBUGSS => todo!("implement DEBUGSS"),
22 Group0::FLASHCTL => todo!("implement FLASHCTL"),
23 Group0::SYSCTL => todo!("implement SYSCTL"),
24 }
25}
diff --git a/embassy-mspm0/src/int_group/g350x.rs b/embassy-mspm0/src/int_group/g350x.rs
new file mode 100644
index 000000000..706ba2078
--- /dev/null
+++ b/embassy-mspm0/src/int_group/g350x.rs
@@ -0,0 +1,51 @@
1use crate::pac;
2use crate::pac::interrupt;
3
4#[cfg(feature = "rt")]
5#[interrupt]
6fn GROUP0() {
7 use mspm0_metapac::Group0;
8
9 let group = pac::CPUSS.int_group(0);
10
11 // Must subtract by 1 since NO_INTR is value 0
12 let iidx = group.iidx().read().stat().to_bits() - 1;
13
14 let Ok(group) = pac::Group0::try_from(iidx as u8) else {
15 debug!("Invalid IIDX for group 0: {}", iidx);
16 return;
17 };
18
19 match group {
20 Group0::WWDT0 => todo!("implement WWDT0"),
21 Group0::WWDT1 => todo!("implement WWDT1"),
22 Group0::DEBUGSS => todo!("implement DEBUGSS"),
23 Group0::FLASHCTL => todo!("implement FLASHCTL"),
24 Group0::SYSCTL => todo!("implement SYSCTL"),
25 }
26}
27
28#[cfg(feature = "rt")]
29#[interrupt]
30fn GROUP1() {
31 use mspm0_metapac::Group1;
32
33 let group = pac::CPUSS.int_group(1);
34
35 // Must subtract by 1 since NO_INTR is value 0
36 let iidx = group.iidx().read().stat().to_bits() - 1;
37
38 let Ok(group) = pac::Group1::try_from(iidx as u8) else {
39 debug!("Invalid IIDX for group 1: {}", iidx);
40 return;
41 };
42
43 match group {
44 Group1::GPIOA => crate::gpio::gpioa_interrupt(),
45 Group1::GPIOB => crate::gpio::gpiob_interrupt(),
46 Group1::COMP0 => todo!("implement COMP0"),
47 Group1::COMP1 => todo!("implement COMP1"),
48 Group1::COMP2 => todo!("implement COMP2"),
49 Group1::TRNG => todo!("implement TRNG"),
50 }
51}
diff --git a/embassy-mspm0/src/int_group/g351x.rs b/embassy-mspm0/src/int_group/g351x.rs
new file mode 100644
index 000000000..e785018a7
--- /dev/null
+++ b/embassy-mspm0/src/int_group/g351x.rs
@@ -0,0 +1,52 @@
1use crate::pac;
2use crate::pac::interrupt;
3
4#[cfg(feature = "rt")]
5#[interrupt]
6fn GROUP0() {
7 use mspm0_metapac::Group0;
8
9 let group = pac::CPUSS.int_group(0);
10
11 // Must subtract by 1 since NO_INTR is value 0
12 let iidx = group.iidx().read().stat().to_bits() - 1;
13
14 let Ok(group) = pac::Group0::try_from(iidx as u8) else {
15 debug!("Invalid IIDX for group 0: {}", iidx);
16 return;
17 };
18
19 match group {
20 Group0::WWDT0 => todo!("implement WWDT0"),
21 Group0::WWDT1 => todo!("implement WWDT1"),
22 Group0::DEBUGSS => todo!("implement DEBUGSS"),
23 Group0::FLASHCTL => todo!("implement FLASHCTL"),
24 Group0::SYSCTL => todo!("implement SYSCTL"),
25 }
26}
27
28#[cfg(feature = "rt")]
29#[interrupt]
30fn GROUP1() {
31 use mspm0_metapac::Group1;
32
33 let group = pac::CPUSS.int_group(1);
34
35 // Must subtract by 1 since NO_INTR is value 0
36 let iidx = group.iidx().read().stat().to_bits() - 1;
37
38 let Ok(group) = pac::Group1::try_from(iidx as u8) else {
39 debug!("Invalid IIDX for group 1: {}", iidx);
40 return;
41 };
42
43 match group {
44 Group1::GPIOA => crate::gpio::gpioa_interrupt(),
45 Group1::GPIOB => crate::gpio::gpiob_interrupt(),
46 Group1::COMP0 => todo!("implement COMP0"),
47 Group1::COMP1 => todo!("implement COMP1"),
48 Group1::COMP2 => todo!("implement COMP2"),
49 Group1::TRNG => todo!("implement TRNG"),
50 Group1::GPIOC => crate::gpio::gpioc_interrupt(),
51 }
52}
diff --git a/embassy-mspm0/src/int_group/l130x.rs b/embassy-mspm0/src/int_group/l130x.rs
new file mode 100644
index 000000000..8be5adcad
--- /dev/null
+++ b/embassy-mspm0/src/int_group/l130x.rs
@@ -0,0 +1,46 @@
1use crate::pac;
2use crate::pac::interrupt;
3
4#[cfg(feature = "rt")]
5#[interrupt]
6fn GROUP0() {
7 use mspm0_metapac::Group0;
8
9 let group = pac::CPUSS.int_group(0);
10
11 // Must subtract by 1 since NO_INTR is value 0
12 let iidx = group.iidx().read().stat().to_bits() - 1;
13
14 let Ok(group) = pac::Group0::try_from(iidx as u8) else {
15 debug!("Invalid IIDX for group 0: {}", iidx);
16 return;
17 };
18
19 match group {
20 Group0::WWDT0 => todo!("implement WWDT0"),
21 Group0::DEBUGSS => todo!("implement DEBUGSS"),
22 Group0::FLASHCTL => todo!("implement FLASHCTL"),
23 Group0::SYSCTL => todo!("implement SYSCTL"),
24 }
25}
26
27#[cfg(feature = "rt")]
28#[interrupt]
29fn GROUP1() {
30 use mspm0_metapac::Group1;
31
32 let group = pac::CPUSS.int_group(1);
33
34 // Must subtract by 1 since NO_INTR is value 0
35 let iidx = group.iidx().read().stat().to_bits() - 1;
36
37 let Ok(group) = pac::Group1::try_from(iidx as u8) else {
38 debug!("Invalid IIDX for group 1: {}", iidx);
39 return;
40 };
41
42 match group {
43 Group1::GPIOA => crate::gpio::gpioa_interrupt(),
44 Group1::COMP0 => todo!("implement COMP0"),
45 }
46}
diff --git a/embassy-mspm0/src/int_group/l222x.rs b/embassy-mspm0/src/int_group/l222x.rs
new file mode 100644
index 000000000..eeb2ce70d
--- /dev/null
+++ b/embassy-mspm0/src/int_group/l222x.rs
@@ -0,0 +1,49 @@
1use crate::pac;
2use crate::pac::interrupt;
3
4#[cfg(feature = "rt")]
5#[interrupt]
6fn GROUP0() {
7 use mspm0_metapac::Group0;
8
9 let group = pac::CPUSS.int_group(0);
10
11 // Must subtract by 1 since NO_INTR is value 0
12 let iidx = group.iidx().read().stat().to_bits() - 1;
13
14 let Ok(group) = pac::Group0::try_from(iidx as u8) else {
15 debug!("Invalid IIDX for group 0: {}", iidx);
16 return;
17 };
18
19 match group {
20 Group0::WWDT0 => todo!("implement WWDT0"),
21 Group0::DEBUGSS => todo!("implement DEBUGSS"),
22 Group0::FLASHCTL => todo!("implement FLASHCTL"),
23 Group0::SYSCTL => todo!("implement SYSCTL"),
24 }
25}
26
27#[cfg(feature = "rt")]
28#[interrupt]
29fn GROUP1() {
30 use mspm0_metapac::Group1;
31
32 let group = pac::CPUSS.int_group(1);
33
34 // Must subtract by 1 since NO_INTR is value 0
35 let iidx = group.iidx().read().stat().to_bits() - 1;
36
37 let Ok(group) = pac::Group1::try_from(iidx as u8) else {
38 debug!("Invalid IIDX for group 1: {}", iidx);
39 return;
40 };
41
42 match group {
43 Group1::GPIOA => crate::gpio::gpioa_interrupt(),
44 Group1::GPIOB => crate::gpio::gpiob_interrupt(),
45 Group1::COMP0 => todo!("implement COMP0"),
46 Group1::TRNG => todo!("implement TRNG"),
47 Group1::GPIOC => crate::gpio::gpioc_interrupt(),
48 }
49}
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
new file mode 100644
index 000000000..1191b1010
--- /dev/null
+++ b/embassy-mspm0/src/lib.rs
@@ -0,0 +1,107 @@
1#![no_std]
2// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
3#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8pub mod gpio;
9pub mod timer;
10
11#[cfg(feature = "_time-driver")]
12mod time_driver;
13
14// Interrupt group handlers.
15#[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")]
16#[cfg_attr(feature = "mspm0g110x", path = "int_group/g110x.rs")]
17#[cfg_attr(feature = "mspm0g150x", path = "int_group/g150x.rs")]
18#[cfg_attr(feature = "mspm0g151x", path = "int_group/g151x.rs")]
19#[cfg_attr(feature = "mspm0g310x", path = "int_group/g310x.rs")]
20#[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")]
21#[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")]
22#[cfg_attr(feature = "mspm0l110x", path = "int_group/l110x.rs")]
23#[cfg_attr(feature = "mspm0l122x", path = "int_group/l122x.rs")]
24#[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")]
25#[cfg_attr(feature = "mspm0l134x", path = "int_group/l134x.rs")]
26#[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")]
27mod int_group;
28
29pub(crate) mod _generated {
30 #![allow(dead_code)]
31 #![allow(unused_imports)]
32 #![allow(non_snake_case)]
33 #![allow(missing_docs)]
34
35 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
36}
37
38// Reexports
39pub(crate) use _generated::gpio_pincm;
40pub use _generated::{peripherals, Peripherals};
41pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
42#[cfg(feature = "unstable-pac")]
43pub use mspm0_metapac as pac;
44#[cfg(not(feature = "unstable-pac"))]
45pub(crate) use mspm0_metapac as pac;
46
47pub use crate::_generated::interrupt;
48
49/// `embassy-mspm0` global configuration.
50#[non_exhaustive]
51#[derive(Clone, Copy)]
52pub struct Config {
53 // TODO
54}
55
56impl Default for Config {
57 fn default() -> Self {
58 Self {
59 // TODO
60 }
61 }
62}
63
64pub fn init(_config: Config) -> Peripherals {
65 critical_section::with(|cs| {
66 let peripherals = Peripherals::take_with_cs(cs);
67
68 // TODO: Further clock configuration
69
70 pac::SYSCTL.mclkcfg().modify(|w| {
71 // Enable MFCLK
72 w.set_usemftick(true);
73 // MDIV must be disabled if MFCLK is enabled.
74 w.set_mdiv(0);
75 });
76
77 // Enable MFCLK for peripheral use
78 //
79 // TODO: Optional?
80 pac::SYSCTL.genclken().modify(|w| {
81 w.set_mfpclken(true);
82 });
83
84 pac::SYSCTL.borthreshold().modify(|w| {
85 w.set_level(0);
86 });
87
88 gpio::init(pac::GPIOA);
89 #[cfg(gpio_pb)]
90 gpio::init(pac::GPIOB);
91 #[cfg(gpio_pc)]
92 gpio::init(pac::GPIOC);
93
94 _generated::enable_group_interrupts(cs);
95
96 #[cfg(feature = "mspm0c110x")]
97 unsafe {
98 use crate::_generated::interrupt::typelevel::Interrupt;
99 crate::interrupt::typelevel::GPIOA::enable();
100 }
101
102 #[cfg(feature = "_time-driver")]
103 time_driver::init(cs);
104
105 peripherals
106 })
107}
diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs
new file mode 100644
index 000000000..937ce58d4
--- /dev/null
+++ b/embassy-mspm0/src/time_driver.rs
@@ -0,0 +1,423 @@
1use core::cell::{Cell, RefCell};
2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
3use core::task::Waker;
4
5use critical_section::{CriticalSection, Mutex};
6use embassy_time_driver::Driver;
7use embassy_time_queue_utils::Queue;
8use mspm0_metapac::interrupt;
9use mspm0_metapac::tim::vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey};
10use mspm0_metapac::tim::{Counterregs16, Tim};
11
12use crate::peripherals;
13use crate::timer::SealedTimer;
14
15// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers.
16#[cfg(time_driver_timg0)]
17type T = peripherals::TIMG0;
18#[cfg(time_driver_timg1)]
19type T = peripherals::TIMG1;
20#[cfg(time_driver_timg2)]
21type T = peripherals::TIMG2;
22#[cfg(time_driver_timg3)]
23type T = peripherals::TIMG3;
24#[cfg(time_driver_timg4)]
25type T = peripherals::TIMG4;
26#[cfg(time_driver_timg5)]
27type T = peripherals::TIMG5;
28#[cfg(time_driver_timg6)]
29type T = peripherals::TIMG6;
30#[cfg(time_driver_timg7)]
31type T = peripherals::TIMG7;
32#[cfg(time_driver_timg8)]
33type T = peripherals::TIMG8;
34#[cfg(time_driver_timg9)]
35type T = peripherals::TIMG9;
36#[cfg(time_driver_timg10)]
37type T = peripherals::TIMG10;
38#[cfg(time_driver_timg11)]
39type T = peripherals::TIMG11;
40#[cfg(time_driver_timg14)]
41type T = peripherals::TIMG14;
42#[cfg(time_driver_tima0)]
43type T = peripherals::TIMA0;
44#[cfg(time_driver_tima1)]
45type T = peripherals::TIMA1;
46
47// TODO: RTC
48
49fn regs() -> Tim {
50 unsafe { Tim::from_ptr(T::regs()) }
51}
52
53fn regs_counter(tim: Tim) -> Counterregs16 {
54 unsafe { Counterregs16::from_ptr(tim.counterregs(0).as_ptr()) }
55}
56
57/// Clock timekeeping works with something we call "periods", which are time intervals
58/// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
59fn calc_now(period: u32, counter: u16) -> u64 {
60 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
61}
62
63/// The TIMx driver uses one of the `TIMG` or `TIMA` timer instances to implement a timer with a 32.768 kHz
64/// tick rate. (TODO: Allow setting the tick rate)
65///
66/// This driver defines a period to be 2^15 ticks. 16-bit timers of course count to 2^16 ticks.
67///
68/// To generate a period every 2^15 ticks, the CC0 value is set to 2^15 and the load value set to 2^16.
69/// Incrementing the period on a CCU0 and load results in the a period of 2^15 ticks.
70///
71/// For a specific timestamp, load the lower 16 bits into the CC1 value. When the period where the timestamp
72/// should be enabled is reached, then the CCU1 (CC1 up) interrupt runs to actually wake the timer.
73///
74/// TODO: Compensate for per part variance. This can supposedly be done with the FCC system.
75/// TODO: Allow using 32-bit timers (TIMG12 and TIMG13).
76struct TimxDriver {
77 /// Number of 2^15 periods elapsed since boot.
78 period: AtomicU32,
79 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
80 alarm: Mutex<Cell<u64>>,
81 queue: Mutex<RefCell<Queue>>,
82}
83
84impl TimxDriver {
85 #[inline(never)]
86 fn init(&'static self, _cs: CriticalSection) {
87 // Clock config
88 // TODO: Configurable tick rate up to 4 MHz (32 kHz for now)
89 let regs = regs();
90
91 // Reset timer
92 regs.gprcm(0).rstctl().write(|w| {
93 w.set_resetassert(true);
94 w.set_key(ResetKey::KEY);
95 w.set_resetstkyclr(true);
96 });
97
98 // Power up timer
99 regs.gprcm(0).pwren().write(|w| {
100 w.set_enable(true);
101 w.set_key(PwrenKey::KEY);
102 });
103
104 // Following the instructions according to SLAU847D 23.2.1: TIMCLK Configuration
105
106 // 1. Select TIMCLK source
107 regs.clksel().modify(|w| {
108 // Use LFCLK for a 32.768kHz tick rate
109 w.set_lfclk_sel(true);
110 // TODO: Allow MFCLK for configurable tick rate up to 4 MHz
111 // w.set_mfclk_sel(ClkSel::ENABLE);
112 });
113
114 // 2. Divide by TIMCLK, we don't need to divide further for the 32kHz tick rate
115 regs.clkdiv().modify(|w| {
116 w.set_ratio(Ratio::DIV_BY_1);
117 });
118
119 // 3. To be generic across timer instances, we do not use the prescaler.
120 // TODO: mspm0-sdk always sets this, regardless of timer width?
121 regs.commonregs(0).cps().modify(|w| {
122 w.set_pcnt(0);
123 });
124
125 regs.pdbgctl().modify(|w| {
126 w.set_free(true);
127 });
128
129 // 4. Enable the TIMCLK.
130 regs.commonregs(0).cclkctl().modify(|w| {
131 w.set_clken(true);
132 });
133
134 regs.counterregs(0).ctrctl().modify(|w| {
135 // allow counting during debug
136 w.set_repeat(Repeat::REPEAT_3);
137 w.set_cvae(Cvae::ZEROVAL);
138 w.set_cm(Cm::UP);
139
140 // Must explicitly set CZC, CAC and CLC to 0 in order for all the timers to count.
141 //
142 // The reset value of these registers is 0x07, which is a reserved value.
143 //
144 // Looking at a bit representation of the reset value, this appears to be an AND
145 // of 2-input QEI mode and CCCTL_3 ACOND. Given that TIMG14 and TIMA0 have no QEI
146 // and 4 capture and compare channels, this works by accident for those timer units.
147 w.set_czc(CxC::CCTL0);
148 w.set_cac(CxC::CCTL0);
149 w.set_clc(CxC::CCTL0);
150 });
151
152 // Setup the period
153 let ctr = regs_counter(regs);
154
155 // Middle
156 ctr.cc(0).modify(|w| {
157 w.set_ccval(0x7FFF);
158 });
159
160 ctr.load().modify(|w| {
161 w.set_ld(u16::MAX);
162 });
163
164 // Enable the period interrupts
165 //
166 // This does not appear to ever be set for CPU_INT in the TI SDK and is not technically needed.
167 regs.evt_mode().modify(|w| {
168 w.set_evt_cfg(0, EvtCfg::SOFTWARE);
169 });
170
171 regs.int_event(0).imask().modify(|w| {
172 w.set_l(true);
173 w.set_ccu0(true);
174 });
175
176 unsafe { T::enable_interrupt() };
177
178 // Allow the counter to start counting.
179 regs.counterregs(0).ctrctl().modify(|w| {
180 w.set_en(true);
181 });
182 }
183
184 #[inline(never)]
185 fn next_period(&self) {
186 let r = regs();
187
188 // We only modify the period from the timer interrupt, so we know this can't race.
189 let period = self.period.load(Ordering::Relaxed) + 1;
190 self.period.store(period, Ordering::Relaxed);
191 let t = (period as u64) << 15;
192
193 critical_section::with(move |cs| {
194 r.int_event(0).imask().modify(move |w| {
195 let alarm = self.alarm.borrow(cs);
196 let at = alarm.get();
197
198 if at < t + 0xC000 {
199 // just enable it. `set_alarm` has already set the correct CC1 val.
200 w.set_ccu1(true);
201 }
202 })
203 });
204 }
205
206 #[inline(never)]
207 fn on_interrupt(&self) {
208 let r = regs();
209
210 critical_section::with(|cs| {
211 let mis = r.int_event(0).mis().read();
212
213 // Advance to next period if overflowed
214 if mis.l() {
215 self.next_period();
216
217 r.int_event(0).iclr().write(|w| {
218 w.set_l(true);
219 });
220 }
221
222 if mis.ccu0() {
223 self.next_period();
224
225 r.int_event(0).iclr().write(|w| {
226 w.set_ccu0(true);
227 });
228 }
229
230 if mis.ccu1() {
231 r.int_event(0).iclr().write(|w| {
232 w.set_ccu1(true);
233 });
234
235 self.trigger_alarm(cs);
236 }
237 });
238 }
239
240 fn trigger_alarm(&self, cs: CriticalSection) {
241 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
242
243 while !self.set_alarm(cs, next) {
244 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
245 }
246 }
247
248 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
249 let r = regs();
250 let ctr = regs_counter(r);
251
252 self.alarm.borrow(cs).set(timestamp);
253
254 let t = self.now();
255
256 if timestamp <= t {
257 // If alarm timestamp has passed the alarm will not fire.
258 // Disarm the alarm and return `false` to indicate that.
259 r.int_event(0).imask().modify(|w| w.set_ccu1(false));
260
261 self.alarm.borrow(cs).set(u64::MAX);
262
263 return false;
264 }
265
266 // Write the CC1 value regardless of whether we're going to enable it now or not.
267 // This way, when we enable it later, the right value is already set.
268 ctr.cc(1).write(|w| {
269 w.set_ccval(timestamp as u16);
270 });
271
272 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
273 let diff = timestamp - t;
274 r.int_event(0).imask().modify(|w| w.set_ccu1(diff < 0xC000));
275
276 // Reevaluate if the alarm timestamp is still in the future
277 let t = self.now();
278 if timestamp <= t {
279 // If alarm timestamp has passed since we set it, we have a race condition and
280 // the alarm may or may not have fired.
281 // Disarm the alarm and return `false` to indicate that.
282 // It is the caller's responsibility to handle this ambiguity.
283 r.int_event(0).imask().modify(|w| w.set_ccu1(false));
284
285 self.alarm.borrow(cs).set(u64::MAX);
286
287 return false;
288 }
289
290 // We're confident the alarm will ring in the future.
291 true
292 }
293}
294
295impl Driver for TimxDriver {
296 fn now(&self) -> u64 {
297 let regs = regs();
298
299 let period = self.period.load(Ordering::Relaxed);
300 // Ensure the compiler does not read the counter before the period.
301 compiler_fence(Ordering::Acquire);
302
303 let counter = regs_counter(regs).ctr().read().cctr() as u16;
304
305 calc_now(period, counter)
306 }
307
308 fn schedule_wake(&self, at: u64, waker: &Waker) {
309 critical_section::with(|cs| {
310 let mut queue = self.queue.borrow(cs).borrow_mut();
311
312 if queue.schedule_wake(at, waker) {
313 let mut next = queue.next_expiration(self.now());
314
315 while !self.set_alarm(cs, next) {
316 next = queue.next_expiration(self.now());
317 }
318 }
319 });
320 }
321}
322
323embassy_time_driver::time_driver_impl!(static DRIVER: TimxDriver = TimxDriver {
324 period: AtomicU32::new(0),
325 alarm: Mutex::new(Cell::new(u64::MAX)),
326 queue: Mutex::new(RefCell::new(Queue::new()))
327});
328
329pub(crate) fn init(cs: CriticalSection) {
330 DRIVER.init(cs);
331}
332
333#[cfg(time_driver_timg0)]
334#[interrupt]
335fn TIMG0() {
336 DRIVER.on_interrupt();
337}
338
339#[cfg(time_driver_timg1)]
340#[interrupt]
341fn TIMG1() {
342 DRIVER.on_interrupt();
343}
344
345#[cfg(time_driver_timg2)]
346#[interrupt]
347fn TIMG2() {
348 DRIVER.on_interrupt();
349}
350
351#[cfg(time_driver_timg3)]
352#[interrupt]
353fn TIMG3() {
354 DRIVER.on_interrupt();
355}
356
357#[cfg(time_driver_timg4)]
358#[interrupt]
359fn TIMG4() {
360 DRIVER.on_interrupt();
361}
362
363#[cfg(time_driver_timg5)]
364#[interrupt]
365fn TIMG5() {
366 DRIVER.on_interrupt();
367}
368
369#[cfg(time_driver_timg6)]
370#[interrupt]
371fn TIMG6() {
372 DRIVER.on_interrupt();
373}
374
375#[cfg(time_driver_timg7)]
376#[interrupt]
377fn TIMG7() {
378 DRIVER.on_interrupt();
379}
380
381#[cfg(time_driver_timg8)]
382#[interrupt]
383fn TIMG8() {
384 DRIVER.on_interrupt();
385}
386
387#[cfg(time_driver_timg9)]
388#[interrupt]
389fn TIMG9() {
390 DRIVER.on_interrupt();
391}
392
393#[cfg(time_driver_timg10)]
394#[interrupt]
395fn TIMG10() {
396 DRIVER.on_interrupt();
397}
398
399#[cfg(time_driver_timg11)]
400#[interrupt]
401fn TIMG11() {
402 DRIVER.on_interrupt();
403}
404
405// TODO: TIMG12 and TIMG13
406
407#[cfg(time_driver_timg14)]
408#[interrupt]
409fn TIMG14() {
410 DRIVER.on_interrupt();
411}
412
413#[cfg(time_driver_tima0)]
414#[interrupt]
415fn TIMA0() {
416 DRIVER.on_interrupt();
417}
418
419#[cfg(time_driver_tima1)]
420#[interrupt]
421fn TIMA1() {
422 DRIVER.on_interrupt();
423}
diff --git a/embassy-mspm0/src/timer.rs b/embassy-mspm0/src/timer.rs
new file mode 100644
index 000000000..4441e5640
--- /dev/null
+++ b/embassy-mspm0/src/timer.rs
@@ -0,0 +1,48 @@
1#![macro_use]
2
3/// Amount of bits of a timer.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum TimerBits {
7 /// 16 bits.
8 Bits16,
9 /// 32 bits.
10 Bits32,
11}
12
13#[allow(private_bounds)]
14pub trait Timer: SealedTimer + 'static {
15 /// Amount of bits this timer has.
16 const BITS: TimerBits;
17}
18
19pub(crate) trait SealedTimer {
20 /// Registers for this timer.
21 ///
22 /// This is a raw pointer to the register block. The actual register block layout varies depending on the
23 /// timer type.
24 fn regs() -> *mut ();
25
26 /// Enable the interrupt corresponding to this timer.
27 unsafe fn enable_interrupt();
28}
29
30macro_rules! impl_timer {
31 ($name: ident, $bits: ident) => {
32 impl crate::timer::SealedTimer for crate::peripherals::$name {
33 fn regs() -> *mut () {
34 crate::pac::$name.as_ptr()
35 }
36
37 unsafe fn enable_interrupt() {
38 use embassy_hal_internal::interrupt::InterruptExt;
39 crate::interrupt::$name.unpend();
40 crate::interrupt::$name.enable();
41 }
42 }
43
44 impl crate::timer::Timer for crate::peripherals::$name {
45 const BITS: crate::timer::TimerBits = crate::timer::TimerBits::$bits;
46 }
47 };
48}
diff --git a/examples/mspm0c1104/.cargo/config.toml b/examples/mspm0c1104/.cargo/config.toml
new file mode 100644
index 000000000..204a56b1c
--- /dev/null
+++ b/examples/mspm0c1104/.cargo/config.toml
@@ -0,0 +1,11 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0C1104 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0C1104 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
10# defmt's buffer needs to be shrunk since the MSPM0C1104 only has 1KB of ram.
11DEFMT_RTT_BUFFER_SIZE = "72"
diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml
new file mode 100644
index 000000000..3996939a5
--- /dev/null
+++ b/examples/mspm0c1104/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-c1104-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-128", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "0.2.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3.2", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20# The chip only has 1KB of ram, so we must optimize binaries regardless
21[profile.dev]
22debug = 0
23opt-level = "z"
24lto = true
25codegen-units = 1
26# strip = true
27
28[profile.release]
29debug = 0
30opt-level = "z"
31lto = true
32codegen-units = 1
diff --git a/examples/mspm0c1104/README.md b/examples/mspm0c1104/README.md
new file mode 100644
index 000000000..e5c9f961d
--- /dev/null
+++ b/examples/mspm0c1104/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0C110x family
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0C1104](https://www.ti.com/tool/LP-MSPM0C1104) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for C1104 it should be `probe-rs run --chip MSPM0C1104`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for C1104 it should be `mspm0c1104`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0c1104/build.rs b/examples/mspm0c1104/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/mspm0c1104/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/mspm0c1104/memory.x b/examples/mspm0c1104/memory.x
new file mode 100644
index 000000000..a9108835a
--- /dev/null
+++ b/examples/mspm0c1104/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 16K
4 RAM : ORIGIN = 0x20000000, LENGTH = 1K
5}
diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs
new file mode 100644
index 000000000..0d974cc5e
--- /dev/null
+++ b/examples/mspm0c1104/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA22, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs
new file mode 100644
index 000000000..7face1618
--- /dev/null
+++ b/examples/mspm0c1104/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA22;
17 let s2 = p.PA16;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0g3507/.cargo/config.toml b/examples/mspm0g3507/.cargo/config.toml
new file mode 100644
index 000000000..34c720cdd
--- /dev/null
+++ b/examples/mspm0g3507/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0G3507 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0G3507 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml
new file mode 100644
index 000000000..c1f304174
--- /dev/null
+++ b/examples/mspm0g3507/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-g3507-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "0.2.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3.2", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0g3507/README.md b/examples/mspm0g3507/README.md
new file mode 100644
index 000000000..5e8a83212
--- /dev/null
+++ b/examples/mspm0g3507/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0C350x family
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0G3507](https://www.ti.com/tool/LP-MSPM0G3507) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3507 it should be `probe-rs run --chip MSPM0G3507`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3507 it should be `mspm0g3507`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0g3507/build.rs b/examples/mspm0g3507/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/mspm0g3507/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/mspm0g3507/memory.x b/examples/mspm0g3507/memory.x
new file mode 100644
index 000000000..37e381fbd
--- /dev/null
+++ b/examples/mspm0g3507/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 32K
6}
diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs
new file mode 100644
index 000000000..cde1f2892
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB21;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0g3519/.cargo/config.toml b/examples/mspm0g3519/.cargo/config.toml
new file mode 100644
index 000000000..7bba4646f
--- /dev/null
+++ b/examples/mspm0g3519/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0G3519 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml
new file mode 100644
index 000000000..fc6f0e31b
--- /dev/null
+++ b/examples/mspm0g3519/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-g3519-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "0.2.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3.2", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0g3519/README.md b/examples/mspm0g3519/README.md
new file mode 100644
index 000000000..5034b1913
--- /dev/null
+++ b/examples/mspm0g3519/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0G351x family
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0G3519](https://www.ti.com/tool/LP-MSPM0G3519) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3519 it should be `probe-rs run --chip MSPM0G3519`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3519 it should be `mspm0g3519`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0g3519/build.rs b/examples/mspm0g3519/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/mspm0g3519/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/mspm0g3519/memory.x b/examples/mspm0g3519/memory.x
new file mode 100644
index 000000000..e6e0ec9e9
--- /dev/null
+++ b/examples/mspm0g3519/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 512K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 128K
6}
diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0g3519/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs
new file mode 100644
index 000000000..c81cc2918
--- /dev/null
+++ b/examples/mspm0g3519/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB3;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0l1306/.cargo/config.toml b/examples/mspm0l1306/.cargo/config.toml
new file mode 100644
index 000000000..93f148a71
--- /dev/null
+++ b/examples/mspm0l1306/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0L1306 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip MSPM0L1306 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml
new file mode 100644
index 000000000..6b87916b8
--- /dev/null
+++ b/examples/mspm0l1306/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-l1306-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "0.2.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3.2", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0l1306/README.md b/examples/mspm0l1306/README.md
new file mode 100644
index 000000000..5a55d721e
--- /dev/null
+++ b/examples/mspm0l1306/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0L130x family
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0L1306](https://www.ti.com/tool/LP-MSPM0L1306) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L1306 it should be `probe-rs run --chip MSPM0L1306`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L1306 it should be `mspm0l1306`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0l1306/build.rs b/examples/mspm0l1306/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/mspm0l1306/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/mspm0l1306/memory.x b/examples/mspm0l1306/memory.x
new file mode 100644
index 000000000..d93b61f44
--- /dev/null
+++ b/examples/mspm0l1306/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 64K
4 RAM : ORIGIN = 0x20000000, LENGTH = 4K
5}
diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs
new file mode 100644
index 000000000..d8c85947f
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PA14;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0l2228/.cargo/config.toml b/examples/mspm0l2228/.cargo/config.toml
new file mode 100644
index 000000000..f383afd9e
--- /dev/null
+++ b/examples/mspm0l2228/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0L2228 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml
new file mode 100644
index 000000000..9474c2ced
--- /dev/null
+++ b/examples/mspm0l2228/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-mspm0-l2228-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] }
9embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
12panic-halt = "0.2.0"
13cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
14cortex-m-rt = { version = "0.7.0"}
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3.2", features = ["print-defmt"] }
18panic-semihosting = "0.6.0"
19
20[profile.release]
21debug = 2
diff --git a/examples/mspm0l2228/README.md b/examples/mspm0l2228/README.md
new file mode 100644
index 000000000..c73fa13b6
--- /dev/null
+++ b/examples/mspm0l2228/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0L222x family
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0L2228](https://www.ti.com/tool/LP-MSPM0L2228) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L2228 it should be `probe-rs run --chip MSPM0L2228`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L2228 it should be `mspm0l2228`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0l2228/build.rs b/examples/mspm0l2228/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/mspm0l2228/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/mspm0l2228/memory.x b/examples/mspm0l2228/memory.x
new file mode 100644
index 000000000..aba414a88
--- /dev/null
+++ b/examples/mspm0l2228/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 256K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 32K
6}
diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs
new file mode 100644
index 000000000..055a5cd81
--- /dev/null
+++ b/examples/mspm0l2228/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Level, Output};
7use embassy_mspm0::Config;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs
new file mode 100644
index 000000000..47bfd274b
--- /dev/null
+++ b/examples/mspm0l2228/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::gpio::{Input, Level, Output, Pull};
7use embassy_mspm0::Config;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PB8;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}