diff options
| author | Elias Hanelt <[email protected]> | 2025-12-01 14:43:51 -0800 |
|---|---|---|
| committer | Elias Hanelt <[email protected]> | 2025-12-01 14:43:51 -0800 |
| commit | 7772ab265c9776b3df3f7d4aeb397b6076e1f5a8 (patch) | |
| tree | 40af598203172aa76fc66bdefdd767d93952e0d0 | |
| parent | 88ce8314c5cd653ac245cc5dbf367f6814f24be9 (diff) | |
| parent | 217b683427687e8f3a27f02852e6f5bd2405ace3 (diff) | |
Merge remote-tracking branch 'origin/main' into feature/spi-bidi
46 files changed, 558 insertions, 386 deletions
| @@ -65,6 +65,7 @@ rm out/tests/pimoroni-pico-plus-2/pwm | |||
| 65 | # flaky | 65 | # flaky |
| 66 | rm out/tests/rpi-pico/pwm | 66 | rm out/tests/rpi-pico/pwm |
| 67 | rm out/tests/rpi-pico/cyw43-perf | 67 | rm out/tests/rpi-pico/cyw43-perf |
| 68 | rm out/tests/rpi-pico/uart_buffered | ||
| 68 | 69 | ||
| 69 | # tests are implemented but the HIL test farm doesn't actually have these boards, yet | 70 | # tests are implemented but the HIL test farm doesn't actually have these boards, yet |
| 70 | rm -rf out/tests/stm32c071rb | 71 | rm -rf out/tests/stm32c071rb |
diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md index c2d18919c..80343e02e 100644 --- a/cyw43-pio/CHANGELOG.md +++ b/cyw43-pio/CHANGELOG.md | |||
| @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | ## 0.9.0 - 2025-11-27 | ||
| 12 | |||
| 11 | - Select pio program based on core clock speed #4792 | 13 | - Select pio program based on core clock speed #4792 |
| 12 | 14 | ||
| 13 | ## 0.8.0 - 2025-08-28 | 15 | ## 0.8.0 - 2025-08-28 |
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index a10a091e9..3001fa92b 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "cyw43-pio" | 2 | name = "cyw43-pio" |
| 3 | version = "0.8.0" | 3 | version = "0.9.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | description = "RP2040 PIO SPI implementation for cyw43" | 5 | description = "RP2040 PIO SPI implementation for cyw43" |
| 6 | keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] | 6 | keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] |
| @@ -10,8 +10,8 @@ repository = "https://github.com/embassy-rs/embassy" | |||
| 10 | documentation = "https://docs.embassy.dev/cyw43-pio" | 10 | documentation = "https://docs.embassy.dev/cyw43-pio" |
| 11 | 11 | ||
| 12 | [dependencies] | 12 | [dependencies] |
| 13 | cyw43 = { version = "0.5.0", path = "../cyw43" } | 13 | cyw43 = { version = "0.6.0", path = "../cyw43" } |
| 14 | embassy-rp = { version = "0.8.0", path = "../embassy-rp" } | 14 | embassy-rp = { version = "0.9.0", path = "../embassy-rp" } |
| 15 | fixed = "1.23.1" | 15 | fixed = "1.23.1" |
| 16 | defmt = { version = "1.0.1", optional = true } | 16 | defmt = { version = "1.0.1", optional = true } |
| 17 | 17 | ||
diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 1045fd30b..9fe341357 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md | |||
| @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | ## 0.6.0 - 2025-11-27 | ||
| 12 | |||
| 11 | - Updated documentation for Control::join() #4678 | 13 | - Updated documentation for Control::join() #4678 |
| 12 | - Bump bt-hci to 0.6.0. | 14 | - Bump bt-hci to 0.6.0. |
| 13 | - Add error handling to HCI transport implementation. | 15 | - Add error handling to HCI transport implementation. |
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 314427611..6d7647697 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "cyw43" | 2 | name = "cyw43" |
| 3 | version = "0.5.0" | 3 | version = "0.6.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." | 5 | description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." |
| 6 | keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] | 6 | keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] |
diff --git a/embassy-boot-rp/CHANGELOG.md b/embassy-boot-rp/CHANGELOG.md index 8cc1e73c0..068075b5c 100644 --- a/embassy-boot-rp/CHANGELOG.md +++ b/embassy-boot-rp/CHANGELOG.md | |||
| @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | ## 0.9.0 - 2025-11-27 | ||
| 12 | |||
| 11 | ## 0.8.0 - 2025-08-26 | 13 | ## 0.8.0 - 2025-08-26 |
| 12 | 14 | ||
| 13 | ## 0.1.1 - 2025-08-15 | 15 | ## 0.1.1 - 2025-08-15 |
diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index e80c79374..2f63dea4c 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | edition = "2024" | 2 | edition = "2024" |
| 3 | name = "embassy-boot-rp" | 3 | name = "embassy-boot-rp" |
| 4 | version = "0.8.0" | 4 | version = "0.9.0" |
| 5 | description = "Bootloader lib for RP2040 chips" | 5 | description = "Bootloader lib for RP2040 chips" |
| 6 | license = "MIT OR Apache-2.0" | 6 | license = "MIT OR Apache-2.0" |
| 7 | repository = "https://github.com/embassy-rs/embassy" | 7 | repository = "https://github.com/embassy-rs/embassy" |
| @@ -31,7 +31,7 @@ defmt = { version = "1.0.1", optional = true } | |||
| 31 | log = { version = "0.4", optional = true } | 31 | log = { version = "0.4", optional = true } |
| 32 | 32 | ||
| 33 | embassy-sync = { version = "0.7.2", path = "../embassy-sync" } | 33 | embassy-sync = { version = "0.7.2", path = "../embassy-sync" } |
| 34 | embassy-rp = { version = "0.8.0", path = "../embassy-rp", default-features = false } | 34 | embassy-rp = { version = "0.9.0", path = "../embassy-rp", default-features = false } |
| 35 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } | 35 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } |
| 36 | embassy-time = { version = "0.5.0", path = "../embassy-time" } | 36 | embassy-time = { version = "0.5.0", path = "../embassy-time" } |
| 37 | 37 | ||
diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 75b7aeeb2..8cf11f1fb 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml | |||
| @@ -18,7 +18,7 @@ log = ["dep:log"] | |||
| 18 | defmt = { version = "1.0.1", optional = true } | 18 | defmt = { version = "1.0.1", optional = true } |
| 19 | log = { version = "0.4.14", optional = true } | 19 | log = { version = "0.4.14", optional = true } |
| 20 | 20 | ||
| 21 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } | 21 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "176dc4afe1dd8df78f3cbda4479ab5151aa32252" } |
| 22 | cortex-m = "0.7.7" | 22 | cortex-m = "0.7.7" |
| 23 | 23 | ||
| 24 | embassy-time = { version = "0.5.0", path = "../embassy-time" } | 24 | embassy-time = { version = "0.5.0", path = "../embassy-time" } |
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index cfb040ef5..5657ddcfb 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | - added: Add basic RTC support for nRF54L | ||
| 12 | - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l | 11 | - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l |
| 13 | - changed: do not panic on BufferedUarte overrun | 12 | - changed: do not panic on BufferedUarte overrun |
| 14 | - added: allow direct access to the input pin of `gpiote::InputChannel` | 13 | - added: allow direct access to the input pin of `gpiote::InputChannel` |
| @@ -29,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 29 | - bugfix: use correct flash size for nRF54l | 28 | - bugfix: use correct flash size for nRF54l |
| 30 | - changed: add workaround for anomaly 66 on nrf52 | 29 | - changed: add workaround for anomaly 66 on nrf52 |
| 31 | - added: expose PPI events available on SPIS peripheral | 30 | - added: expose PPI events available on SPIS peripheral |
| 31 | - added: add basic GRTC time driver support for nRF54L | ||
| 32 | 32 | ||
| 33 | ## 0.8.0 - 2025-09-30 | 33 | ## 0.8.0 - 2025-09-30 |
| 34 | 34 | ||
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 08f4b280b..f73772682 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -23,8 +23,8 @@ build = [ | |||
| 23 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-s", "time", "time-driver-rtc1"]}, | 23 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-s", "time", "time-driver-rtc1"]}, |
| 24 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-ns", "time", "time-driver-rtc1"]}, | 24 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-ns", "time", "time-driver-rtc1"]}, |
| 25 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-net", "time", "time-driver-rtc1"]}, | 25 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-net", "time", "time-driver-rtc1"]}, |
| 26 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-s", "time", "time-driver-rtc1"]}, | 26 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-s", "time", "time-driver-grtc"]}, |
| 27 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-ns", "time", "time-driver-rtc1"]}, | 27 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-ns", "time", "time-driver-grtc"]}, |
| 28 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]}, | 28 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]}, |
| 29 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]}, | 29 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]}, |
| 30 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]}, | 30 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]}, |
| @@ -80,9 +80,10 @@ unstable-pac = [] | |||
| 80 | gpiote = [] | 80 | gpiote = [] |
| 81 | 81 | ||
| 82 | ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz | 82 | ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz |
| 83 | ## | 83 | time-driver-rtc1 = ["_time-driver", "embassy-time-driver?/tick-hz-32_768"] |
| 84 | ## Note: For nRF54L, it's actually RTC30 | 84 | |
| 85 | time-driver-rtc1 = ["_time-driver"] | 85 | ## Use GRTC (CC n=1, GRTC_1 irq) as the time driver for `embassy-time`, with a tick rate of 1 MHz |
| 86 | time-driver-grtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"] | ||
| 86 | 87 | ||
| 87 | ## Enable embassy-net 802.15.4 driver | 88 | ## Enable embassy-net 802.15.4 driver |
| 88 | net-driver = ["_net-driver"] | 89 | net-driver = ["_net-driver"] |
| @@ -152,7 +153,7 @@ _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] | |||
| 152 | _nrf5340 = ["_gpio-p1", "_dppi"] | 153 | _nrf5340 = ["_gpio-p1", "_dppi"] |
| 153 | _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] | 154 | _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] |
| 154 | _nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] | 155 | _nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] |
| 155 | _nrf54l = ["_dppi"] | 156 | _nrf54l = ["_dppi", "_grtc"] |
| 156 | 157 | ||
| 157 | _nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] | 158 | _nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] |
| 158 | _nrf9120 = ["nrf-pac/nrf9120", "_dppi", "_spi-v1"] | 159 | _nrf9120 = ["nrf-pac/nrf9120", "_dppi", "_spi-v1"] |
| @@ -160,7 +161,7 @@ _nrf52 = ["_ppi"] | |||
| 160 | _nrf51 = ["_ppi", "_spi-v1"] | 161 | _nrf51 = ["_ppi", "_spi-v1"] |
| 161 | _nrf91 = [] | 162 | _nrf91 = [] |
| 162 | 163 | ||
| 163 | _time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] | 164 | _time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] |
| 164 | 165 | ||
| 165 | _net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"] | 166 | _net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"] |
| 166 | 167 | ||
| @@ -173,6 +174,7 @@ _dppi = [] | |||
| 173 | _gpio-p1 = [] | 174 | _gpio-p1 = [] |
| 174 | _gpio-p2 = [] | 175 | _gpio-p2 = [] |
| 175 | _spi-v1 = [] | 176 | _spi-v1 = [] |
| 177 | _grtc = [] | ||
| 176 | 178 | ||
| 177 | # Errata workarounds | 179 | # Errata workarounds |
| 178 | _nrf52832_anomaly_109 = [] | 180 | _nrf52832_anomaly_109 = [] |
| @@ -200,7 +202,7 @@ embedded-io-async = { version = "0.6.1" } | |||
| 200 | rand-core-06 = { package = "rand_core", version = "0.6" } | 202 | rand-core-06 = { package = "rand_core", version = "0.6" } |
| 201 | rand-core-09 = { package = "rand_core", version = "0.9" } | 203 | rand-core-09 = { package = "rand_core", version = "0.9" } |
| 202 | 204 | ||
| 203 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } | 205 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "176dc4afe1dd8df78f3cbda4479ab5151aa32252" } |
| 204 | 206 | ||
| 205 | defmt = { version = "1.0.1", optional = true } | 207 | defmt = { version = "1.0.1", optional = true } |
| 206 | bitflags = "2.4.2" | 208 | bitflags = "2.4.2" |
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 8846717db..8e6595248 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs | |||
| @@ -26,7 +26,6 @@ pub mod pac { | |||
| 26 | PPIB10_NS as PPIB10, | 26 | PPIB10_NS as PPIB10, |
| 27 | PPIB11_NS as PPIB11, | 27 | PPIB11_NS as PPIB11, |
| 28 | TIMER10_NS as TIMER10, | 28 | TIMER10_NS as TIMER10, |
| 29 | RTC10_NS as RTC10, | ||
| 30 | EGU10_NS as EGU10, | 29 | EGU10_NS as EGU10, |
| 31 | RADIO_NS as RADIO, | 30 | RADIO_NS as RADIO, |
| 32 | DPPIC20_NS as DPPIC20, | 31 | DPPIC20_NS as DPPIC20, |
| @@ -76,7 +75,6 @@ pub mod pac { | |||
| 76 | TWIM30_NS as TWIM30, | 75 | TWIM30_NS as TWIM30, |
| 77 | TWIS30_NS as TWIS30, | 76 | TWIS30_NS as TWIS30, |
| 78 | UARTE30_NS as UARTE30, | 77 | UARTE30_NS as UARTE30, |
| 79 | RTC30_NS as RTC30, | ||
| 80 | COMP_NS as COMP, | 78 | COMP_NS as COMP, |
| 81 | LPCOMP_NS as LPCOMP, | 79 | LPCOMP_NS as LPCOMP, |
| 82 | WDT31_NS as WDT31, | 80 | WDT31_NS as WDT31, |
| @@ -127,7 +125,6 @@ pub mod pac { | |||
| 127 | PPIB10_S as PPIB10, | 125 | PPIB10_S as PPIB10, |
| 128 | PPIB11_S as PPIB11, | 126 | PPIB11_S as PPIB11, |
| 129 | TIMER10_S as TIMER10, | 127 | TIMER10_S as TIMER10, |
| 130 | RTC10_S as RTC10, | ||
| 131 | EGU10_S as EGU10, | 128 | EGU10_S as EGU10, |
| 132 | RADIO_S as RADIO, | 129 | RADIO_S as RADIO, |
| 133 | SPU20_S as SPU20, | 130 | SPU20_S as SPU20, |
| @@ -180,7 +177,6 @@ pub mod pac { | |||
| 180 | TWIM30_S as TWIM30, | 177 | TWIM30_S as TWIM30, |
| 181 | TWIS30_S as TWIS30, | 178 | TWIS30_S as TWIS30, |
| 182 | UARTE30_S as UARTE30, | 179 | UARTE30_S as UARTE30, |
| 183 | RTC30_S as RTC30, | ||
| 184 | COMP_S as COMP, | 180 | COMP_S as COMP, |
| 185 | LPCOMP_S as LPCOMP, | 181 | LPCOMP_S as LPCOMP, |
| 186 | WDT30_S as WDT30, | 182 | WDT30_S as WDT30, |
| @@ -417,11 +413,19 @@ embassy_hal_internal::peripherals! { | |||
| 417 | P2_10, | 413 | P2_10, |
| 418 | 414 | ||
| 419 | // GRTC | 415 | // GRTC |
| 420 | GRTC, | 416 | GRTC_CH0, |
| 421 | 417 | #[cfg(not(feature = "time-driver-grtc"))] | |
| 422 | // RTC | 418 | GRTC_CH1, |
| 423 | RTC10, | 419 | GRTC_CH2, |
| 424 | RTC30, | 420 | GRTC_CH3, |
| 421 | GRTC_CH4, | ||
| 422 | GRTC_CH5, | ||
| 423 | GRTC_CH6, | ||
| 424 | GRTC_CH7, | ||
| 425 | GRTC_CH8, | ||
| 426 | GRTC_CH9, | ||
| 427 | GRTC_CH10, | ||
| 428 | GRTC_CH11, | ||
| 425 | 429 | ||
| 426 | // PWM | 430 | // PWM |
| 427 | PWM20, | 431 | PWM20, |
| @@ -548,9 +552,6 @@ cfg_if::cfg_if! { | |||
| 548 | } | 552 | } |
| 549 | } | 553 | } |
| 550 | 554 | ||
| 551 | impl_rtc!(RTC10, RTC10, RTC10); | ||
| 552 | impl_rtc!(RTC30, RTC30, RTC30); | ||
| 553 | |||
| 554 | #[cfg(feature = "_ns")] | 555 | #[cfg(feature = "_ns")] |
| 555 | impl_wdt!(WDT, WDT31, WDT31, 0); | 556 | impl_wdt!(WDT, WDT31, WDT31, 0); |
| 556 | #[cfg(feature = "_s")] | 557 | #[cfg(feature = "_s")] |
| @@ -703,7 +704,6 @@ embassy_hal_internal::interrupt_mod!( | |||
| 703 | TIMER00, | 704 | TIMER00, |
| 704 | SPU10, | 705 | SPU10, |
| 705 | TIMER10, | 706 | TIMER10, |
| 706 | RTC10, | ||
| 707 | EGU10, | 707 | EGU10, |
| 708 | RADIO_0, | 708 | RADIO_0, |
| 709 | RADIO_1, | 709 | RADIO_1, |
| @@ -737,7 +737,6 @@ embassy_hal_internal::interrupt_mod!( | |||
| 737 | GRTC_3, | 737 | GRTC_3, |
| 738 | SPU30, | 738 | SPU30, |
| 739 | SERIAL30, | 739 | SERIAL30, |
| 740 | RTC30, | ||
| 741 | COMP_LPCOMP, | 740 | COMP_LPCOMP, |
| 742 | WDT30, | 741 | WDT30, |
| 743 | WDT31, | 742 | WDT31, |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 28d2119ae..e8762b00d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -153,6 +153,7 @@ pub mod reset; | |||
| 153 | #[cfg(not(feature = "_nrf54l"))] | 153 | #[cfg(not(feature = "_nrf54l"))] |
| 154 | #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] | 154 | #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] |
| 155 | pub mod rng; | 155 | pub mod rng; |
| 156 | #[cfg(not(feature = "_nrf54l"))] | ||
| 156 | pub mod rtc; | 157 | pub mod rtc; |
| 157 | #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] | 158 | #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] |
| 158 | pub mod saadc; | 159 | pub mod saadc; |
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index ca8cbd73e..ab0e2b86a 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -771,7 +771,7 @@ pub(crate) trait SealedInput { | |||
| 771 | fn port(&self) -> u8; | 771 | fn port(&self) -> u8; |
| 772 | 772 | ||
| 773 | #[cfg(feature = "_nrf54l")] | 773 | #[cfg(feature = "_nrf54l")] |
| 774 | fn internal(&self) -> vals::Internal; | 774 | fn internal(&self) -> vals::PselpInternal; |
| 775 | 775 | ||
| 776 | #[cfg(feature = "_nrf54l")] | 776 | #[cfg(feature = "_nrf54l")] |
| 777 | fn connect(&self) -> vals::PselpConnect; | 777 | fn connect(&self) -> vals::PselpConnect; |
| @@ -832,7 +832,7 @@ pub struct AnyInput<'a> { | |||
| 832 | pub struct AnyInput<'a> { | 832 | pub struct AnyInput<'a> { |
| 833 | pin: u8, | 833 | pin: u8, |
| 834 | port: u8, | 834 | port: u8, |
| 835 | internal: vals::Internal, | 835 | internal: vals::PselpInternal, |
| 836 | connect: vals::PselpConnect, | 836 | connect: vals::PselpConnect, |
| 837 | _phantom: PhantomData<&'a ()>, | 837 | _phantom: PhantomData<&'a ()>, |
| 838 | } | 838 | } |
| @@ -881,7 +881,7 @@ impl SealedInput for AnyInput<'_> { | |||
| 881 | } | 881 | } |
| 882 | 882 | ||
| 883 | #[cfg(feature = "_nrf54l")] | 883 | #[cfg(feature = "_nrf54l")] |
| 884 | fn internal(&self) -> vals::Internal { | 884 | fn internal(&self) -> vals::PselpInternal { |
| 885 | self.internal | 885 | self.internal |
| 886 | } | 886 | } |
| 887 | 887 | ||
| @@ -923,8 +923,8 @@ macro_rules! impl_saadc_input { | |||
| 923 | $port | 923 | $port |
| 924 | } | 924 | } |
| 925 | 925 | ||
| 926 | fn internal(&self) -> crate::pac::saadc::vals::Internal { | 926 | fn internal(&self) -> crate::pac::saadc::vals::PselpInternal { |
| 927 | crate::pac::saadc::vals::Internal::$internal | 927 | crate::pac::saadc::vals::PselpInternal::$internal |
| 928 | } | 928 | } |
| 929 | 929 | ||
| 930 | fn connect(&self) -> crate::pac::saadc::vals::PselpConnect { | 930 | fn connect(&self) -> crate::pac::saadc::vals::PselpConnect { |
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index b723e2334..35f65bd64 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | use core::cell::{Cell, RefCell}; | 1 | use core::cell::{Cell, RefCell}; |
| 2 | #[cfg(not(feature = "_grtc"))] | ||
| 2 | use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; | 3 | use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; |
| 3 | 4 | ||
| 4 | use critical_section::CriticalSection; | 5 | use critical_section::CriticalSection; |
| @@ -8,21 +9,27 @@ use embassy_time_driver::Driver; | |||
| 8 | use embassy_time_queue_utils::Queue; | 9 | use embassy_time_queue_utils::Queue; |
| 9 | 10 | ||
| 10 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 12 | #[cfg(feature = "_grtc")] | ||
| 13 | use crate::pac::grtc::vals::Busy; | ||
| 11 | use crate::{interrupt, pac}; | 14 | use crate::{interrupt, pac}; |
| 12 | 15 | ||
| 13 | #[cfg(feature = "_nrf54l")] | 16 | #[cfg(feature = "_grtc")] |
| 14 | fn rtc() -> pac::rtc::Rtc { | 17 | fn rtc() -> pac::grtc::Grtc { |
| 15 | pac::RTC30 | 18 | pac::GRTC |
| 16 | } | 19 | } |
| 17 | #[cfg(not(feature = "_nrf54l"))] | 20 | |
| 21 | #[cfg(not(feature = "_grtc"))] | ||
| 18 | fn rtc() -> pac::rtc::Rtc { | 22 | fn rtc() -> pac::rtc::Rtc { |
| 19 | pac::RTC1 | 23 | pac::RTC1 |
| 20 | } | 24 | } |
| 21 | 25 | ||
| 22 | /// Calculate the timestamp from the period count and the tick count. | 26 | /// Calculate the timestamp from the period count and the tick count. |
| 23 | /// | 27 | /// |
| 24 | /// The RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes. This is | 28 | /// For nRF54 devices and newer, the GRTC counter is 52 bits, so the time driver uses the |
| 25 | /// too short. We must make it "never" overflow. | 29 | /// syscounter and ignores the periods handling, since it overflows every 142 years. |
| 30 | /// | ||
| 31 | /// For most other devices, the RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes. | ||
| 32 | /// This is too short. We must make it "never" overflow. | ||
| 26 | /// | 33 | /// |
| 27 | /// The obvious way would be to count overflow periods. Every time the counter overflows, | 34 | /// The obvious way would be to count overflow periods. Every time the counter overflows, |
| 28 | /// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic | 35 | /// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic |
| @@ -64,14 +71,39 @@ fn rtc() -> pac::rtc::Rtc { | |||
| 64 | /// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865 | 71 | /// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865 |
| 65 | /// years. For comparison, flash memory like the one containing your firmware is usually rated to retain | 72 | /// years. For comparison, flash memory like the one containing your firmware is usually rated to retain |
| 66 | /// data for only 10-20 years. 34865 years is long enough! | 73 | /// data for only 10-20 years. 34865 years is long enough! |
| 74 | #[cfg(not(feature = "_grtc"))] | ||
| 67 | fn calc_now(period: u32, counter: u32) -> u64 { | 75 | fn calc_now(period: u32, counter: u32) -> u64 { |
| 68 | ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64) | 76 | ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64) |
| 69 | } | 77 | } |
| 70 | 78 | ||
| 79 | #[cfg(feature = "_grtc")] | ||
| 80 | fn syscounter() -> u64 { | ||
| 81 | let r = rtc(); | ||
| 82 | r.syscounter(0).active().write(|w| w.set_active(true)); | ||
| 83 | loop { | ||
| 84 | let countl: u32 = r.syscounter(0).syscounterl().read(); | ||
| 85 | let counth = r.syscounter(0).syscounterh().read(); | ||
| 86 | |||
| 87 | if counth.busy() == Busy::READY && !counth.overflow() { | ||
| 88 | let counth: u32 = counth.value(); | ||
| 89 | let count = countl as u64 | ((counth as u64) << 32); | ||
| 90 | r.syscounter(0).active().write(|w| w.set_active(false)); | ||
| 91 | return count; | ||
| 92 | } | ||
| 93 | // If overflow or not ready, loop will re-read both registers | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | #[cfg(not(feature = "_grtc"))] | ||
| 71 | fn compare_n(n: usize) -> u32 { | 98 | fn compare_n(n: usize) -> u32 { |
| 72 | 1 << (n + 16) | 99 | 1 << (n + 16) |
| 73 | } | 100 | } |
| 74 | 101 | ||
| 102 | #[cfg(feature = "_grtc")] | ||
| 103 | fn compare_n(n: usize) -> u32 { | ||
| 104 | 1 << n // GRTC uses bits 0-11 for COMPARE[0-11] | ||
| 105 | } | ||
| 106 | |||
| 75 | #[cfg(test)] | 107 | #[cfg(test)] |
| 76 | mod test { | 108 | mod test { |
| 77 | use super::*; | 109 | use super::*; |
| @@ -108,6 +140,7 @@ impl AlarmState { | |||
| 108 | 140 | ||
| 109 | struct RtcDriver { | 141 | struct RtcDriver { |
| 110 | /// Number of 2^23 periods elapsed since boot. | 142 | /// Number of 2^23 periods elapsed since boot. |
| 143 | #[cfg(not(feature = "_grtc"))] | ||
| 111 | period: AtomicU32, | 144 | period: AtomicU32, |
| 112 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | 145 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. |
| 113 | alarms: Mutex<AlarmState>, | 146 | alarms: Mutex<AlarmState>, |
| @@ -115,6 +148,7 @@ struct RtcDriver { | |||
| 115 | } | 148 | } |
| 116 | 149 | ||
| 117 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 150 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { |
| 151 | #[cfg(not(feature = "_grtc"))] | ||
| 118 | period: AtomicU32::new(0), | 152 | period: AtomicU32::new(0), |
| 119 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), | 153 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), |
| 120 | queue: Mutex::new(RefCell::new(Queue::new())), | 154 | queue: Mutex::new(RefCell::new(Queue::new())), |
| @@ -123,25 +157,43 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 123 | impl RtcDriver { | 157 | impl RtcDriver { |
| 124 | fn init(&'static self, irq_prio: crate::interrupt::Priority) { | 158 | fn init(&'static self, irq_prio: crate::interrupt::Priority) { |
| 125 | let r = rtc(); | 159 | let r = rtc(); |
| 126 | r.cc(3).write(|w| w.set_compare(0x800000)); | 160 | // Chips without GRTC needs to deal with overflow |
| 161 | #[cfg(not(feature = "_grtc"))] | ||
| 162 | { | ||
| 163 | r.cc(3).write(|w| w.set_compare(0x800000)); | ||
| 127 | 164 | ||
| 128 | r.intenset().write(|w| { | 165 | r.intenset().write(|w| { |
| 129 | w.set_ovrflw(true); | 166 | w.set_ovrflw(true); |
| 130 | w.set_compare(3, true); | 167 | w.set_compare(3, true); |
| 131 | }); | 168 | }); |
| 169 | } | ||
| 132 | 170 | ||
| 171 | #[cfg(feature = "_grtc")] | ||
| 172 | { | ||
| 173 | r.mode().write(|w| { | ||
| 174 | w.set_syscounteren(true); | ||
| 175 | }); | ||
| 176 | } | ||
| 133 | r.tasks_clear().write_value(1); | 177 | r.tasks_clear().write_value(1); |
| 134 | r.tasks_start().write_value(1); | 178 | r.tasks_start().write_value(1); |
| 135 | 179 | ||
| 136 | // Wait for clear | 180 | // Wait for clear |
| 181 | #[cfg(not(feature = "_grtc"))] | ||
| 137 | while r.counter().read().0 != 0 {} | 182 | while r.counter().read().0 != 0 {} |
| 138 | 183 | ||
| 139 | #[cfg(feature = "_nrf54l")] | 184 | #[cfg(feature = "_grtc")] |
| 185 | loop { | ||
| 186 | if r.status().lftimer().read().ready() { | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | #[cfg(feature = "_grtc")] | ||
| 140 | { | 192 | { |
| 141 | interrupt::RTC30.set_priority(irq_prio); | 193 | interrupt::GRTC_1.set_priority(irq_prio); |
| 142 | unsafe { interrupt::RTC30.enable() }; | 194 | unsafe { interrupt::GRTC_1.enable() }; |
| 143 | } | 195 | } |
| 144 | #[cfg(not(feature = "_nrf54l"))] | 196 | #[cfg(not(feature = "_grtc"))] |
| 145 | { | 197 | { |
| 146 | interrupt::RTC1.set_priority(irq_prio); | 198 | interrupt::RTC1.set_priority(irq_prio); |
| 147 | unsafe { interrupt::RTC1.enable() }; | 199 | unsafe { interrupt::RTC1.enable() }; |
| @@ -150,11 +202,14 @@ impl RtcDriver { | |||
| 150 | 202 | ||
| 151 | fn on_interrupt(&self) { | 203 | fn on_interrupt(&self) { |
| 152 | let r = rtc(); | 204 | let r = rtc(); |
| 205 | |||
| 206 | #[cfg(not(feature = "_grtc"))] | ||
| 153 | if r.events_ovrflw().read() == 1 { | 207 | if r.events_ovrflw().read() == 1 { |
| 154 | r.events_ovrflw().write_value(0); | 208 | r.events_ovrflw().write_value(0); |
| 155 | self.next_period(); | 209 | self.next_period(); |
| 156 | } | 210 | } |
| 157 | 211 | ||
| 212 | #[cfg(not(feature = "_grtc"))] | ||
| 158 | if r.events_compare(3).read() == 1 { | 213 | if r.events_compare(3).read() == 1 { |
| 159 | r.events_compare(3).write_value(0); | 214 | r.events_compare(3).write_value(0); |
| 160 | self.next_period(); | 215 | self.next_period(); |
| @@ -169,6 +224,7 @@ impl RtcDriver { | |||
| 169 | } | 224 | } |
| 170 | } | 225 | } |
| 171 | 226 | ||
| 227 | #[cfg(not(feature = "_grtc"))] | ||
| 172 | fn next_period(&self) { | 228 | fn next_period(&self) { |
| 173 | critical_section::with(|cs| { | 229 | critical_section::with(|cs| { |
| 174 | let r = rtc(); | 230 | let r = rtc(); |
| @@ -190,7 +246,10 @@ impl RtcDriver { | |||
| 190 | fn trigger_alarm(&self, cs: CriticalSection) { | 246 | fn trigger_alarm(&self, cs: CriticalSection) { |
| 191 | let n = 0; | 247 | let n = 0; |
| 192 | let r = rtc(); | 248 | let r = rtc(); |
| 249 | #[cfg(not(feature = "_grtc"))] | ||
| 193 | r.intenclr().write(|w| w.0 = compare_n(n)); | 250 | r.intenclr().write(|w| w.0 = compare_n(n)); |
| 251 | #[cfg(feature = "_grtc")] | ||
| 252 | r.intenclr(1).write(|w| w.0 = compare_n(n)); | ||
| 194 | 253 | ||
| 195 | let alarm = &self.alarms.borrow(cs); | 254 | let alarm = &self.alarms.borrow(cs); |
| 196 | alarm.timestamp.set(u64::MAX); | 255 | alarm.timestamp.set(u64::MAX); |
| @@ -214,7 +273,10 @@ impl RtcDriver { | |||
| 214 | if timestamp <= t { | 273 | if timestamp <= t { |
| 215 | // If alarm timestamp has passed the alarm will not fire. | 274 | // If alarm timestamp has passed the alarm will not fire. |
| 216 | // Disarm the alarm and return `false` to indicate that. | 275 | // Disarm the alarm and return `false` to indicate that. |
| 276 | #[cfg(not(feature = "_grtc"))] | ||
| 217 | r.intenclr().write(|w| w.0 = compare_n(n)); | 277 | r.intenclr().write(|w| w.0 = compare_n(n)); |
| 278 | #[cfg(feature = "_grtc")] | ||
| 279 | r.intenclr(1).write(|w| w.0 = compare_n(n)); | ||
| 218 | 280 | ||
| 219 | alarm.timestamp.set(u64::MAX); | 281 | alarm.timestamp.set(u64::MAX); |
| 220 | 282 | ||
| @@ -226,7 +288,7 @@ impl RtcDriver { | |||
| 226 | // Write the CC value regardless of whether we're going to enable it now or not. | 288 | // Write the CC value regardless of whether we're going to enable it now or not. |
| 227 | // This way, when we enable it later, the right value is already set. | 289 | // This way, when we enable it later, the right value is already set. |
| 228 | 290 | ||
| 229 | // nrf52 docs say: | 291 | // nrf52 docs say : |
| 230 | // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. | 292 | // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. |
| 231 | // To workaround this, we never write a timestamp smaller than N+3. | 293 | // To workaround this, we never write a timestamp smaller than N+3. |
| 232 | // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. | 294 | // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. |
| @@ -238,22 +300,39 @@ impl RtcDriver { | |||
| 238 | // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed | 300 | // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed |
| 239 | // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, | 301 | // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, |
| 240 | // and we don't do that here. | 302 | // and we don't do that here. |
| 241 | let safe_timestamp = timestamp.max(t + 3); | 303 | #[cfg(not(feature = "_grtc"))] |
| 242 | r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); | 304 | { |
| 243 | 305 | let safe_timestamp = timestamp.max(t + 3); | |
| 244 | let diff = timestamp - t; | 306 | r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); |
| 245 | if diff < 0xc00000 { | 307 | let diff = timestamp - t; |
| 246 | r.intenset().write(|w| w.0 = compare_n(n)); | 308 | if diff < 0xc00000 { |
| 247 | 309 | r.intenset().write(|w| w.0 = compare_n(n)); | |
| 248 | // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, | 310 | |
| 249 | // we need to retry setting the alarm. | 311 | // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, |
| 250 | if self.now() + 2 <= timestamp { | 312 | // we need to retry setting the alarm. |
| 313 | if self.now() + 2 <= timestamp { | ||
| 314 | return true; | ||
| 315 | } | ||
| 316 | } else { | ||
| 317 | // If it's too far in the future, don't setup the compare channel yet. | ||
| 318 | // It will be setup later by `next_period`. | ||
| 319 | r.intenclr().write(|w| w.0 = compare_n(n)); | ||
| 251 | return true; | 320 | return true; |
| 252 | } | 321 | } |
| 253 | } else { | 322 | } |
| 254 | // If it's too far in the future, don't setup the compare channel yet. | 323 | |
| 255 | // It will be setup later by `next_period`. | 324 | // The nRF54 datasheet states that 'The EVENTS_COMPARE[n] event is generated immediately if the |
| 256 | r.intenclr().write(|w| w.0 = compare_n(n)); | 325 | // configured compare value at CC[n] is less than the current SYSCOUNTER value.'. This means we |
| 326 | // can write the expected timestamp and be sure the alarm is triggered. | ||
| 327 | #[cfg(feature = "_grtc")] | ||
| 328 | { | ||
| 329 | let ccl = timestamp as u32; | ||
| 330 | let cch = (timestamp >> 32) as u32 & 0xFFFFF; // 20 bits for CCH | ||
| 331 | |||
| 332 | r.cc(n).ccl().write_value(ccl); | ||
| 333 | r.cc(n).cch().write(|w| w.set_cch(cch)); | ||
| 334 | r.intenset(1).write(|w| w.0 = compare_n(n)); | ||
| 335 | |||
| 257 | return true; | 336 | return true; |
| 258 | } | 337 | } |
| 259 | } | 338 | } |
| @@ -261,6 +340,7 @@ impl RtcDriver { | |||
| 261 | } | 340 | } |
| 262 | 341 | ||
| 263 | impl Driver for RtcDriver { | 342 | impl Driver for RtcDriver { |
| 343 | #[cfg(not(feature = "_grtc"))] | ||
| 264 | fn now(&self) -> u64 { | 344 | fn now(&self) -> u64 { |
| 265 | // `period` MUST be read before `counter`, see comment at the top for details. | 345 | // `period` MUST be read before `counter`, see comment at the top for details. |
| 266 | let period = self.period.load(Ordering::Relaxed); | 346 | let period = self.period.load(Ordering::Relaxed); |
| @@ -269,10 +349,14 @@ impl Driver for RtcDriver { | |||
| 269 | calc_now(period, counter) | 349 | calc_now(period, counter) |
| 270 | } | 350 | } |
| 271 | 351 | ||
| 352 | #[cfg(feature = "_grtc")] | ||
| 353 | fn now(&self) -> u64 { | ||
| 354 | syscounter() | ||
| 355 | } | ||
| 356 | |||
| 272 | fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { | 357 | fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { |
| 273 | critical_section::with(|cs| { | 358 | critical_section::with(|cs| { |
| 274 | let mut queue = self.queue.borrow(cs).borrow_mut(); | 359 | let mut queue = self.queue.borrow(cs).borrow_mut(); |
| 275 | |||
| 276 | if queue.schedule_wake(at, waker) { | 360 | if queue.schedule_wake(at, waker) { |
| 277 | let mut next = queue.next_expiration(self.now()); | 361 | let mut next = queue.next_expiration(self.now()); |
| 278 | while !self.set_alarm(cs, next) { | 362 | while !self.set_alarm(cs, next) { |
| @@ -283,14 +367,14 @@ impl Driver for RtcDriver { | |||
| 283 | } | 367 | } |
| 284 | } | 368 | } |
| 285 | 369 | ||
| 286 | #[cfg(feature = "_nrf54l")] | 370 | #[cfg(feature = "_grtc")] |
| 287 | #[cfg(feature = "rt")] | 371 | #[cfg(feature = "rt")] |
| 288 | #[interrupt] | 372 | #[interrupt] |
| 289 | fn RTC30() { | 373 | fn GRTC_1() { |
| 290 | DRIVER.on_interrupt() | 374 | DRIVER.on_interrupt() |
| 291 | } | 375 | } |
| 292 | 376 | ||
| 293 | #[cfg(not(feature = "_nrf54l"))] | 377 | #[cfg(not(feature = "_grtc"))] |
| 294 | #[cfg(feature = "rt")] | 378 | #[cfg(feature = "rt")] |
| 295 | #[interrupt] | 379 | #[interrupt] |
| 296 | fn RTC1() { | 380 | fn RTC1() { |
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index fa8609bbf..773301b0f 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md | |||
| @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | ## 0.9.0 - 2025-11-27 | ||
| 12 | |||
| 11 | - Add documentation for pio `get_x` about autopush. | 13 | - Add documentation for pio `get_x` about autopush. |
| 12 | - Fix several minor typos in documentation | 14 | - Fix several minor typos in documentation |
| 13 | - Add PIO SPI | 15 | - Add PIO SPI |
| @@ -19,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 19 | - Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824)) | 21 | - Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824)) |
| 20 | - Add PIO::Ws2812 color order support | 22 | - Add PIO::Ws2812 color order support |
| 21 | - Add TX-only, no SCK SPI support | 23 | - Add TX-only, no SCK SPI support |
| 24 | - Remove atomic-polyfill with critical-section instead ([#4948](https://github.com/embassy-rs/embassy/pull/4948)) | ||
| 22 | 25 | ||
| 23 | ## 0.8.0 - 2025-08-26 | 26 | ## 0.8.0 - 2025-08-26 |
| 24 | 27 | ||
| @@ -116,4 +119,3 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended. | |||
| 116 | - rename the Channel trait to Slice and the PwmPin to PwmChannel | 119 | - rename the Channel trait to Slice and the PwmPin to PwmChannel |
| 117 | - i2c: Fix race condition that appears on fast repeated transfers. | 120 | - i2c: Fix race condition that appears on fast repeated transfers. |
| 118 | - Add a basic "read to break" function | 121 | - Add a basic "read to break" function |
| 119 | |||
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 9ad4b47a3..8e4bb927f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "embassy-rp" | 2 | name = "embassy-rp" |
| 3 | version = "0.8.0" | 3 | version = "0.9.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 or RP235x microcontroller" | 6 | description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 or RP235x microcontroller" |
| @@ -47,7 +47,7 @@ rt = [ "rp-pac/rt" ] | |||
| 47 | defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] | 47 | defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] |
| 48 | ## Enable log support | 48 | ## Enable log support |
| 49 | log = ["dep:log"] | 49 | log = ["dep:log"] |
| 50 | ## Enable chrono support | 50 | ## Enable chrono support |
| 51 | chrono = ["dep:chrono"] | 51 | chrono = ["dep:chrono"] |
| 52 | 52 | ||
| 53 | ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. | 53 | ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. |
| @@ -159,7 +159,6 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" } | |||
| 159 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } | 159 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } |
| 160 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } | 160 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } |
| 161 | embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } | 161 | embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } |
| 162 | atomic-polyfill = "1.0.1" | ||
| 163 | defmt = { version = "1.0.1", optional = true } | 162 | defmt = { version = "1.0.1", optional = true } |
| 164 | log = { version = "0.4.14", optional = true } | 163 | log = { version = "0.4.14", optional = true } |
| 165 | nb = "1.1.0" | 164 | nb = "1.1.0" |
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 92b2c603e..1c370fdfc 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs | |||
| @@ -2,10 +2,9 @@ | |||
| 2 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::pin::Pin as FuturePin; | 4 | use core::pin::Pin as FuturePin; |
| 5 | use core::sync::atomic::{Ordering, compiler_fence}; | 5 | use core::sync::atomic::{AtomicU8, AtomicU32, Ordering, compiler_fence}; |
| 6 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 7 | 7 | ||
| 8 | use atomic_polyfill::{AtomicU8, AtomicU64}; | ||
| 9 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | use fixed::FixedU32; | 10 | use fixed::FixedU32; |
| @@ -1232,7 +1231,13 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 1232 | w.set_pde(false); | 1231 | w.set_pde(false); |
| 1233 | }); | 1232 | }); |
| 1234 | // we can be relaxed about this because we're &mut here and nothing is cached | 1233 | // we can be relaxed about this because we're &mut here and nothing is cached |
| 1235 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); | 1234 | critical_section::with(|_| { |
| 1235 | let val = PIO::state().used_pins.load(Ordering::Relaxed); | ||
| 1236 | PIO::state() | ||
| 1237 | .used_pins | ||
| 1238 | .store(val | 1 << pin.pin_bank(), Ordering::Relaxed); | ||
| 1239 | }); | ||
| 1240 | |||
| 1236 | Pin { | 1241 | Pin { |
| 1237 | pin: pin.into(), | 1242 | pin: pin.into(), |
| 1238 | pio: PhantomData::default(), | 1243 | pio: PhantomData::default(), |
| @@ -1404,6 +1409,42 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { | |||
| 1404 | } | 1409 | } |
| 1405 | } | 1410 | } |
| 1406 | 1411 | ||
| 1412 | struct AtomicU64 { | ||
| 1413 | upper_32: AtomicU32, | ||
| 1414 | lower_32: AtomicU32, | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | impl AtomicU64 { | ||
| 1418 | const fn new(val: u64) -> Self { | ||
| 1419 | let upper_32 = (val >> 32) as u32; | ||
| 1420 | let lower_32 = val as u32; | ||
| 1421 | |||
| 1422 | Self { | ||
| 1423 | upper_32: AtomicU32::new(upper_32), | ||
| 1424 | lower_32: AtomicU32::new(lower_32), | ||
| 1425 | } | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | fn load(&self, order: Ordering) -> u64 { | ||
| 1429 | let (upper, lower) = critical_section::with(|_| (self.upper_32.load(order), self.lower_32.load(order))); | ||
| 1430 | |||
| 1431 | let upper = (upper as u64) << 32; | ||
| 1432 | let lower = lower as u64; | ||
| 1433 | |||
| 1434 | upper | lower | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | fn store(&self, val: u64, order: Ordering) { | ||
| 1438 | let upper_32 = (val >> 32) as u32; | ||
| 1439 | let lower_32 = val as u32; | ||
| 1440 | |||
| 1441 | critical_section::with(|_| { | ||
| 1442 | self.upper_32.store(upper_32, order); | ||
| 1443 | self.lower_32.store(lower_32, order); | ||
| 1444 | }); | ||
| 1445 | } | ||
| 1446 | } | ||
| 1447 | |||
| 1407 | /// Representation of the PIO state keeping a record of which pins are assigned to | 1448 | /// Representation of the PIO state keeping a record of which pins are assigned to |
| 1408 | /// each PIO. | 1449 | /// each PIO. |
| 1409 | // make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin | 1450 | // make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin |
| @@ -1418,7 +1459,12 @@ pub struct State { | |||
| 1418 | 1459 | ||
| 1419 | fn on_pio_drop<PIO: Instance>() { | 1460 | fn on_pio_drop<PIO: Instance>() { |
| 1420 | let state = PIO::state(); | 1461 | let state = PIO::state(); |
| 1421 | if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { | 1462 | let users_state = critical_section::with(|_| { |
| 1463 | let val = state.users.load(Ordering::Acquire) - 1; | ||
| 1464 | state.users.store(val, Ordering::Release); | ||
| 1465 | val | ||
| 1466 | }); | ||
| 1467 | if users_state == 1 { | ||
| 1422 | let used_pins = state.used_pins.load(Ordering::Relaxed); | 1468 | let used_pins = state.used_pins.load(Ordering::Relaxed); |
| 1423 | let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; | 1469 | let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; |
| 1424 | for i in 0..crate::gpio::BANK0_PIN_COUNT { | 1470 | for i in 0..crate::gpio::BANK0_PIN_COUNT { |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 02649ad81..fdb8ce776 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | //! Buffered UART driver. | 1 | //! Buffered UART driver. |
| 2 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::slice; | 3 | use core::slice; |
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 4 | 5 | ||
| 5 | use atomic_polyfill::AtomicU8; | ||
| 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| 7 | 7 | ||
| 8 | use super::*; | 8 | use super::*; |
| @@ -241,7 +241,11 @@ impl BufferedUartRx { | |||
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | fn get_rx_error(state: &State) -> Option<Error> { | 243 | fn get_rx_error(state: &State) -> Option<Error> { |
| 244 | let errs = state.rx_error.swap(0, Ordering::Relaxed); | 244 | let errs = critical_section::with(|_| { |
| 245 | let val = state.rx_error.load(Ordering::Relaxed); | ||
| 246 | state.rx_error.store(0, Ordering::Relaxed); | ||
| 247 | val | ||
| 248 | }); | ||
| 245 | if errs & RXE_OVERRUN != 0 { | 249 | if errs & RXE_OVERRUN != 0 { |
| 246 | Some(Error::Overrun) | 250 | Some(Error::Overrun) |
| 247 | } else if errs & RXE_BREAK != 0 { | 251 | } else if errs & RXE_BREAK != 0 { |
| @@ -555,7 +559,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr | |||
| 555 | } | 559 | } |
| 556 | let dr = r.uartdr().read(); | 560 | let dr = r.uartdr().read(); |
| 557 | if (dr.0 >> 8) != 0 { | 561 | if (dr.0 >> 8) != 0 { |
| 558 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | 562 | critical_section::with(|_| { |
| 563 | let val = s.rx_error.load(Ordering::Relaxed); | ||
| 564 | s.rx_error.store(val | ((dr.0 >> 8) as u8), Ordering::Relaxed); | ||
| 565 | }); | ||
| 559 | error = true; | 566 | error = true; |
| 560 | // only fill the buffer with valid characters. the current character is fine | 567 | // only fill the buffer with valid characters. the current character is fine |
| 561 | // if the error is an overrun, but if we add it to the buffer we'll report | 568 | // if the error is an overrun, but if we add it to the buffer we'll report |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 8be87a5d2..b7b569dd5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | //! UART driver. | 1 | //! UART driver. |
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 4 | use core::task::Poll; | 5 | use core::task::Poll; |
| 5 | 6 | ||
| 6 | use atomic_polyfill::{AtomicU16, Ordering}; | ||
| 7 | use embassy_futures::select::{Either, select}; | 7 | use embassy_futures::select::{Either, select}; |
| 8 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -456,7 +456,12 @@ impl<'d> UartRx<'d, Async> { | |||
| 456 | transfer, | 456 | transfer, |
| 457 | poll_fn(|cx| { | 457 | poll_fn(|cx| { |
| 458 | self.dma_state.rx_err_waker.register(cx.waker()); | 458 | self.dma_state.rx_err_waker.register(cx.waker()); |
| 459 | match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { | 459 | let rx_errs = critical_section::with(|_| { |
| 460 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 461 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 462 | val | ||
| 463 | }); | ||
| 464 | match rx_errs { | ||
| 460 | 0 => Poll::Pending, | 465 | 0 => Poll::Pending, |
| 461 | e => Poll::Ready(Uartris(e as u32)), | 466 | e => Poll::Ready(Uartris(e as u32)), |
| 462 | } | 467 | } |
| @@ -468,7 +473,11 @@ impl<'d> UartRx<'d, Async> { | |||
| 468 | Either::First(()) => { | 473 | Either::First(()) => { |
| 469 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 474 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 470 | // byte, then we may still need to grab the error state! | 475 | // byte, then we may still need to grab the error state! |
| 471 | Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) | 476 | Uartris(critical_section::with(|_| { |
| 477 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 478 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 479 | val | ||
| 480 | }) as u32) | ||
| 472 | } | 481 | } |
| 473 | Either::Second(e) => { | 482 | Either::Second(e) => { |
| 474 | // We're here because we errored, which means this is the error that | 483 | // We're here because we errored, which means this is the error that |
| @@ -616,7 +625,12 @@ impl<'d> UartRx<'d, Async> { | |||
| 616 | transfer, | 625 | transfer, |
| 617 | poll_fn(|cx| { | 626 | poll_fn(|cx| { |
| 618 | self.dma_state.rx_err_waker.register(cx.waker()); | 627 | self.dma_state.rx_err_waker.register(cx.waker()); |
| 619 | match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { | 628 | let rx_errs = critical_section::with(|_| { |
| 629 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 630 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 631 | val | ||
| 632 | }); | ||
| 633 | match rx_errs { | ||
| 620 | 0 => Poll::Pending, | 634 | 0 => Poll::Pending, |
| 621 | e => Poll::Ready(Uartris(e as u32)), | 635 | e => Poll::Ready(Uartris(e as u32)), |
| 622 | } | 636 | } |
| @@ -629,7 +643,11 @@ impl<'d> UartRx<'d, Async> { | |||
| 629 | Either::First(()) => { | 643 | Either::First(()) => { |
| 630 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 644 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 631 | // byte, then we may still need to grab the error state! | 645 | // byte, then we may still need to grab the error state! |
| 632 | Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) | 646 | Uartris(critical_section::with(|_| { |
| 647 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 648 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 649 | val | ||
| 650 | }) as u32) | ||
| 633 | } | 651 | } |
| 634 | Either::Second(e) => { | 652 | Either::Second(e) => { |
| 635 | // We're here because we errored, which means this is the error that | 653 | // We're here because we errored, which means this is the error that |
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index d3e5ba48d..2b273482c 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - fix: fix incorrect handling of split interrupts in timer driver | ||
| 11 | - feat: allow granular stop for regular usart | ||
| 10 | - feat: Add continuous waveform method to SimplePWM | 12 | - feat: Add continuous waveform method to SimplePWM |
| 11 | - change: remove waveform timer method | 13 | - change: remove waveform timer method |
| 12 | - change: low power: store stop mode for dma channels | 14 | - change: low power: store stop mode for dma channels |
| @@ -82,6 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 82 | - removal: ExtiInput no longer accepts AnyPin/AnyChannel; AnyChannel removed entirely | 84 | - removal: ExtiInput no longer accepts AnyPin/AnyChannel; AnyChannel removed entirely |
| 83 | - fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't | 85 | - fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't |
| 84 | - feat: stm32/lcd: added implementation | 86 | - feat: stm32/lcd: added implementation |
| 87 | - change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961)) | ||
| 85 | 88 | ||
| 86 | ## 0.4.0 - 2025-08-26 | 89 | ## 0.4.0 - 2025-08-26 |
| 87 | 90 | ||
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 109571e8f..46d6290e7 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -9,7 +9,7 @@ use proc_macro2::{Ident, TokenStream}; | |||
| 9 | use quote::{format_ident, quote}; | 9 | use quote::{format_ident, quote}; |
| 10 | use stm32_metapac::metadata::ir::BitOffset; | 10 | use stm32_metapac::metadata::ir::BitOffset; |
| 11 | use stm32_metapac::metadata::{ | 11 | use stm32_metapac::metadata::{ |
| 12 | ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, | 12 | ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, Peripheral, PeripheralRccKernelClock, |
| 13 | PeripheralRccRegister, PeripheralRegisters, StopMode, | 13 | PeripheralRccRegister, PeripheralRegisters, StopMode, |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| @@ -133,6 +133,9 @@ fn main() { | |||
| 133 | cfgs.enable("backup_sram") | 133 | cfgs.enable("backup_sram") |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | // compile a map of peripherals | ||
| 137 | let peripheral_map: BTreeMap<&str, &Peripheral> = METADATA.peripherals.iter().map(|p| (p.name, p)).collect(); | ||
| 138 | |||
| 136 | // generate one singleton per peripheral (with many exceptions...) | 139 | // generate one singleton per peripheral (with many exceptions...) |
| 137 | for p in METADATA.peripherals { | 140 | for p in METADATA.peripherals { |
| 138 | if let Some(r) = &p.registers { | 141 | if let Some(r) = &p.registers { |
| @@ -319,9 +322,33 @@ fn main() { | |||
| 319 | _ => panic!("unknown time_driver {:?}", time_driver), | 322 | _ => panic!("unknown time_driver {:?}", time_driver), |
| 320 | }; | 323 | }; |
| 321 | 324 | ||
| 322 | if !time_driver_singleton.is_empty() { | 325 | let time_driver_irq_decl = if !time_driver_singleton.is_empty() { |
| 323 | cfgs.enable(format!("time_driver_{}", time_driver_singleton.to_lowercase())); | 326 | cfgs.enable(format!("time_driver_{}", time_driver_singleton.to_lowercase())); |
| 324 | } | 327 | |
| 328 | let p = peripheral_map.get(time_driver_singleton).unwrap(); | ||
| 329 | let irqs: BTreeSet<_> = p | ||
| 330 | .interrupts | ||
| 331 | .iter() | ||
| 332 | .filter(|i| i.signal == "CC" || i.signal == "UP") | ||
| 333 | .map(|i| i.interrupt.to_ascii_uppercase()) | ||
| 334 | .collect(); | ||
| 335 | |||
| 336 | irqs.iter() | ||
| 337 | .map(|i| { | ||
| 338 | let irq = format_ident!("{}", i); | ||
| 339 | quote! { | ||
| 340 | #[cfg(feature = "rt")] | ||
| 341 | #[interrupt] | ||
| 342 | fn #irq() { | ||
| 343 | crate::time_driver::get_driver().on_interrupt(); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | }) | ||
| 347 | .collect() | ||
| 348 | } else { | ||
| 349 | TokenStream::new() | ||
| 350 | }; | ||
| 351 | |||
| 325 | for tim in [ | 352 | for tim in [ |
| 326 | "tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23", | 353 | "tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23", |
| 327 | "tim24", | 354 | "tim24", |
| @@ -371,6 +398,8 @@ fn main() { | |||
| 371 | ); | 398 | ); |
| 372 | }); | 399 | }); |
| 373 | 400 | ||
| 401 | g.extend(time_driver_irq_decl); | ||
| 402 | |||
| 374 | // ======== | 403 | // ======== |
| 375 | // Generate FLASH regions | 404 | // Generate FLASH regions |
| 376 | cfgs.declare("flash"); | 405 | cfgs.declare("flash"); |
| @@ -1862,7 +1891,7 @@ fn main() { | |||
| 1862 | flash_regions_table.push(row); | 1891 | flash_regions_table.push(row); |
| 1863 | } | 1892 | } |
| 1864 | 1893 | ||
| 1865 | let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; | 1894 | let gpio_base = peripheral_map.get("GPIOA").unwrap().address as u32; |
| 1866 | let gpio_stride = 0x400; | 1895 | let gpio_stride = 0x400; |
| 1867 | 1896 | ||
| 1868 | for pin in METADATA.pins { | 1897 | for pin in METADATA.pins { |
| @@ -1980,11 +2009,11 @@ fn main() { | |||
| 1980 | continue; | 2009 | continue; |
| 1981 | } | 2010 | } |
| 1982 | 2011 | ||
| 1983 | let stop_mode = METADATA | 2012 | let dma_peri = peripheral_map.get(ch.dma).unwrap(); |
| 1984 | .peripherals | 2013 | let stop_mode = dma_peri |
| 1985 | .iter() | 2014 | .rcc |
| 1986 | .find(|p| p.name == ch.dma) | 2015 | .as_ref() |
| 1987 | .map(|p| p.rcc.as_ref().map(|rcc| rcc.stop_mode.clone()).unwrap_or_default()) | 2016 | .map(|rcc| rcc.stop_mode.clone()) |
| 1988 | .unwrap_or_default(); | 2017 | .unwrap_or_default(); |
| 1989 | 2018 | ||
| 1990 | let stop_mode = match stop_mode { | 2019 | let stop_mode = match stop_mode { |
| @@ -2009,8 +2038,6 @@ fn main() { | |||
| 2009 | 2038 | ||
| 2010 | let dma = format_ident!("{}", ch.dma); | 2039 | let dma = format_ident!("{}", ch.dma); |
| 2011 | let ch_num = ch.channel as usize; | 2040 | let ch_num = ch.channel as usize; |
| 2012 | |||
| 2013 | let dma_peri = METADATA.peripherals.iter().find(|p| p.name == ch.dma).unwrap(); | ||
| 2014 | let bi = dma_peri.registers.as_ref().unwrap(); | 2041 | let bi = dma_peri.registers.as_ref().unwrap(); |
| 2015 | 2042 | ||
| 2016 | let dma_info = match bi.kind { | 2043 | let dma_info = match bi.kind { |
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 6d91020fc..c5900cadc 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -82,3 +82,40 @@ pub enum RefCountOp { | |||
| 82 | /// Notify sender destroyed | 82 | /// Notify sender destroyed |
| 83 | NotifySenderDestroyed, | 83 | NotifySenderDestroyed, |
| 84 | } | 84 | } |
| 85 | |||
| 86 | /// Error returned when calculating the can timing fails | ||
| 87 | #[derive(Debug)] | ||
| 88 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 89 | pub enum TimingCalcError { | ||
| 90 | /// Bitrate is lower than 1000 | ||
| 91 | BitrateTooLow { | ||
| 92 | /// The set bitrate | ||
| 93 | bitrate: u32, | ||
| 94 | }, | ||
| 95 | /// No solution possible | ||
| 96 | NoSolution { | ||
| 97 | /// The sum of BS1 and BS2 | ||
| 98 | bs1_bs2_sum: u8, | ||
| 99 | }, | ||
| 100 | /// Prescaler is not 1 < prescaler < 1024 | ||
| 101 | InvalidPrescaler { | ||
| 102 | /// The calculated prescaler value | ||
| 103 | prescaler: u32, | ||
| 104 | }, | ||
| 105 | /// BS1 or BS2 are not in the range 0 < BSx < BSx_MAX | ||
| 106 | BSNotInRange { | ||
| 107 | /// The value of BS1 | ||
| 108 | bs1: u8, | ||
| 109 | /// The value of BS2 | ||
| 110 | bs2: u8, | ||
| 111 | }, | ||
| 112 | /// Final bitrate doesn't match the requested bitrate | ||
| 113 | NoMatch { | ||
| 114 | /// The requested bitrate | ||
| 115 | requested: u32, | ||
| 116 | /// The calculated bitrate | ||
| 117 | final_calculated: u32, | ||
| 118 | }, | ||
| 119 | /// core::num::NonZeroUxx::new error | ||
| 120 | CoreNumNew, | ||
| 121 | } | ||
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs index 6d7f0c16a..beca4c34e 100644 --- a/embassy-stm32/src/can/util.rs +++ b/embassy-stm32/src/can/util.rs | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | use core::num::{NonZeroU8, NonZeroU16}; | 3 | use core::num::{NonZeroU8, NonZeroU16}; |
| 4 | 4 | ||
| 5 | use crate::can::enums::TimingCalcError; | ||
| 6 | |||
| 5 | /// Shared struct to represent bit timings used by calc_can_timings. | 7 | /// Shared struct to represent bit timings used by calc_can_timings. |
| 6 | #[derive(Clone, Copy, Debug)] | 8 | #[derive(Clone, Copy, Debug)] |
| 7 | pub struct NominalBitTiming { | 9 | pub struct NominalBitTiming { |
| @@ -17,7 +19,10 @@ pub struct NominalBitTiming { | |||
| 17 | } | 19 | } |
| 18 | 20 | ||
| 19 | /// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency | 21 | /// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency |
| 20 | pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { | 22 | pub fn calc_can_timings( |
| 23 | periph_clock: crate::time::Hertz, | ||
| 24 | can_bitrate: u32, | ||
| 25 | ) -> Result<NominalBitTiming, TimingCalcError> { | ||
| 21 | const BS1_MAX: u8 = 16; | 26 | const BS1_MAX: u8 = 16; |
| 22 | const BS2_MAX: u8 = 8; | 27 | const BS2_MAX: u8 = 8; |
| 23 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | 28 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; |
| @@ -25,7 +30,7 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O | |||
| 25 | let periph_clock = periph_clock.0; | 30 | let periph_clock = periph_clock.0; |
| 26 | 31 | ||
| 27 | if can_bitrate < 1000 { | 32 | if can_bitrate < 1000 { |
| 28 | return None; | 33 | return Err(TimingCalcError::BitrateTooLow { bitrate: can_bitrate }); |
| 29 | } | 34 | } |
| 30 | 35 | ||
| 31 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG | 36 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG |
| @@ -53,14 +58,14 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O | |||
| 53 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; | 58 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; |
| 54 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { | 59 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { |
| 55 | if bs1_bs2_sum <= 2 { | 60 | if bs1_bs2_sum <= 2 { |
| 56 | return None; // No solution | 61 | return Err(TimingCalcError::NoSolution { bs1_bs2_sum }); // No solution |
| 57 | } | 62 | } |
| 58 | bs1_bs2_sum -= 1; | 63 | bs1_bs2_sum -= 1; |
| 59 | } | 64 | } |
| 60 | 65 | ||
| 61 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; | 66 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; |
| 62 | if (prescaler < 1) || (prescaler > 1024) { | 67 | if (prescaler < 1) || (prescaler > 1024) { |
| 63 | return None; // No solution | 68 | return Err(TimingCalcError::InvalidPrescaler { prescaler }); // No solution |
| 64 | } | 69 | } |
| 65 | 70 | ||
| 66 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. | 71 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. |
| @@ -93,22 +98,26 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O | |||
| 93 | 98 | ||
| 94 | // Check is BS1 and BS2 are in range | 99 | // Check is BS1 and BS2 are in range |
| 95 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { | 100 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { |
| 96 | return None; | 101 | return Err(TimingCalcError::BSNotInRange { bs1, bs2 }); |
| 97 | } | 102 | } |
| 98 | 103 | ||
| 104 | let calculated = periph_clock / (prescaler * (1 + bs1 + bs2) as u32); | ||
| 99 | // Check if final bitrate matches the requested | 105 | // Check if final bitrate matches the requested |
| 100 | if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { | 106 | if can_bitrate != calculated { |
| 101 | return None; | 107 | return Err(TimingCalcError::NoMatch { |
| 108 | requested: can_bitrate, | ||
| 109 | final_calculated: calculated, | ||
| 110 | }); | ||
| 102 | } | 111 | } |
| 103 | 112 | ||
| 104 | // One is recommended by DS-015, CANOpen, and DeviceNet | 113 | // One is recommended by DS-015, CANOpen, and DeviceNet |
| 105 | let sync_jump_width = core::num::NonZeroU8::new(1)?; | 114 | let sync_jump_width = core::num::NonZeroU8::new(1).ok_or(TimingCalcError::CoreNumNew)?; |
| 106 | 115 | ||
| 107 | let seg1 = core::num::NonZeroU8::new(bs1)?; | 116 | let seg1 = core::num::NonZeroU8::new(bs1).ok_or(TimingCalcError::CoreNumNew)?; |
| 108 | let seg2 = core::num::NonZeroU8::new(bs2)?; | 117 | let seg2 = core::num::NonZeroU8::new(bs2).ok_or(TimingCalcError::CoreNumNew)?; |
| 109 | let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; | 118 | let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16).ok_or(TimingCalcError::CoreNumNew)?; |
| 110 | 119 | ||
| 111 | Some(NominalBitTiming { | 120 | Ok(NominalBitTiming { |
| 112 | sync_jump_width, | 121 | sync_jump_width, |
| 113 | prescaler: nz_prescaler, | 122 | prescaler: nz_prescaler, |
| 114 | seg1, | 123 | seg1, |
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index b46ae2813..adc084474 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs | |||
| @@ -8,8 +8,9 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 8 | 8 | ||
| 9 | use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; | 9 | use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; |
| 10 | use super::word::{Word, WordSize}; | 10 | use super::word::{Word, WordSize}; |
| 11 | use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE}; | 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::rcc::BusyPeripheral; | ||
| 13 | use crate::{interrupt, pac}; | 14 | use crate::{interrupt, pac}; |
| 14 | 15 | ||
| 15 | pub(crate) struct ChannelInfo { | 16 | pub(crate) struct ChannelInfo { |
| @@ -602,7 +603,7 @@ impl AnyChannel { | |||
| 602 | /// DMA transfer. | 603 | /// DMA transfer. |
| 603 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 604 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 604 | pub struct Transfer<'a> { | 605 | pub struct Transfer<'a> { |
| 605 | channel: BusyChannel<'a>, | 606 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 606 | } | 607 | } |
| 607 | 608 | ||
| 608 | impl<'a> Transfer<'a> { | 609 | impl<'a> Transfer<'a> { |
| @@ -714,7 +715,7 @@ impl<'a> Transfer<'a> { | |||
| 714 | ); | 715 | ); |
| 715 | channel.start(); | 716 | channel.start(); |
| 716 | Self { | 717 | Self { |
| 717 | channel: BusyChannel::new(channel), | 718 | channel: BusyPeripheral::new(channel), |
| 718 | } | 719 | } |
| 719 | } | 720 | } |
| 720 | 721 | ||
| @@ -818,7 +819,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { | |||
| 818 | 819 | ||
| 819 | /// Ringbuffer for receiving data using DMA circular mode. | 820 | /// Ringbuffer for receiving data using DMA circular mode. |
| 820 | pub struct ReadableRingBuffer<'a, W: Word> { | 821 | pub struct ReadableRingBuffer<'a, W: Word> { |
| 821 | channel: BusyChannel<'a>, | 822 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 822 | ringbuf: ReadableDmaRingBuffer<'a, W>, | 823 | ringbuf: ReadableDmaRingBuffer<'a, W>, |
| 823 | } | 824 | } |
| 824 | 825 | ||
| @@ -855,7 +856,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 855 | ); | 856 | ); |
| 856 | 857 | ||
| 857 | Self { | 858 | Self { |
| 858 | channel: BusyChannel::new(channel), | 859 | channel: BusyPeripheral::new(channel), |
| 859 | ringbuf: ReadableDmaRingBuffer::new(buffer), | 860 | ringbuf: ReadableDmaRingBuffer::new(buffer), |
| 860 | } | 861 | } |
| 861 | } | 862 | } |
| @@ -974,7 +975,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { | |||
| 974 | 975 | ||
| 975 | /// Ringbuffer for writing data using DMA circular mode. | 976 | /// Ringbuffer for writing data using DMA circular mode. |
| 976 | pub struct WritableRingBuffer<'a, W: Word> { | 977 | pub struct WritableRingBuffer<'a, W: Word> { |
| 977 | channel: BusyChannel<'a>, | 978 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 978 | ringbuf: WritableDmaRingBuffer<'a, W>, | 979 | ringbuf: WritableDmaRingBuffer<'a, W>, |
| 979 | } | 980 | } |
| 980 | 981 | ||
| @@ -1011,7 +1012,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 1011 | ); | 1012 | ); |
| 1012 | 1013 | ||
| 1013 | Self { | 1014 | Self { |
| 1014 | channel: BusyChannel::new(channel), | 1015 | channel: BusyPeripheral::new(channel), |
| 1015 | ringbuf: WritableDmaRingBuffer::new(buffer), | 1016 | ringbuf: WritableDmaRingBuffer::new(buffer), |
| 1016 | } | 1017 | } |
| 1017 | } | 1018 | } |
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 383c74a78..bfd0570f8 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs | |||
| @@ -11,10 +11,10 @@ use linked_list::Table; | |||
| 11 | 11 | ||
| 12 | use super::word::{Word, WordSize}; | 12 | use super::word::{Word, WordSize}; |
| 13 | use super::{AnyChannel, Channel, Dir, Request, STATE}; | 13 | use super::{AnyChannel, Channel, Dir, Request, STATE}; |
| 14 | use crate::dma::BusyChannel; | ||
| 15 | use crate::interrupt::typelevel::Interrupt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::pac; | 15 | use crate::pac; |
| 17 | use crate::pac::gpdma::vals; | 16 | use crate::pac::gpdma::vals; |
| 17 | use crate::rcc::BusyPeripheral; | ||
| 18 | 18 | ||
| 19 | pub mod linked_list; | 19 | pub mod linked_list; |
| 20 | pub mod ringbuffered; | 20 | pub mod ringbuffered; |
| @@ -409,7 +409,7 @@ impl AnyChannel { | |||
| 409 | /// Linked-list DMA transfer. | 409 | /// Linked-list DMA transfer. |
| 410 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 410 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 411 | pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { | 411 | pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { |
| 412 | channel: BusyChannel<'a>, | 412 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { | 415 | impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { |
| @@ -431,7 +431,7 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { | |||
| 431 | channel.start(); | 431 | channel.start(); |
| 432 | 432 | ||
| 433 | Self { | 433 | Self { |
| 434 | channel: BusyChannel::new(channel), | 434 | channel: BusyPeripheral::new(channel), |
| 435 | } | 435 | } |
| 436 | } | 436 | } |
| 437 | 437 | ||
| @@ -508,7 +508,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT> | |||
| 508 | /// DMA transfer. | 508 | /// DMA transfer. |
| 509 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 509 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 510 | pub struct Transfer<'a> { | 510 | pub struct Transfer<'a> { |
| 511 | channel: BusyChannel<'a>, | 511 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | impl<'a> Transfer<'a> { | 514 | impl<'a> Transfer<'a> { |
| @@ -629,7 +629,7 @@ impl<'a> Transfer<'a> { | |||
| 629 | channel.start(); | 629 | channel.start(); |
| 630 | 630 | ||
| 631 | Self { | 631 | Self { |
| 632 | channel: BusyChannel::new(channel), | 632 | channel: BusyPeripheral::new(channel), |
| 633 | } | 633 | } |
| 634 | } | 634 | } |
| 635 | 635 | ||
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 54e4d5f71..c150d0b95 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs | |||
| @@ -12,7 +12,8 @@ use super::{AnyChannel, STATE, TransferOptions}; | |||
| 12 | use crate::dma::gpdma::linked_list::{RunMode, Table}; | 12 | use crate::dma::gpdma::linked_list::{RunMode, Table}; |
| 13 | use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; | 13 | use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; |
| 14 | use crate::dma::word::Word; | 14 | use crate::dma::word::Word; |
| 15 | use crate::dma::{BusyChannel, Channel, Dir, Request}; | 15 | use crate::dma::{Channel, Dir, Request}; |
| 16 | use crate::rcc::BusyPeripheral; | ||
| 16 | 17 | ||
| 17 | struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); | 18 | struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); |
| 18 | 19 | ||
| @@ -49,7 +50,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { | |||
| 49 | 50 | ||
| 50 | /// Ringbuffer for receiving data using GPDMA linked-list mode. | 51 | /// Ringbuffer for receiving data using GPDMA linked-list mode. |
| 51 | pub struct ReadableRingBuffer<'a, W: Word> { | 52 | pub struct ReadableRingBuffer<'a, W: Word> { |
| 52 | channel: BusyChannel<'a>, | 53 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 53 | ringbuf: ReadableDmaRingBuffer<'a, W>, | 54 | ringbuf: ReadableDmaRingBuffer<'a, W>, |
| 54 | table: Table<2>, | 55 | table: Table<2>, |
| 55 | options: TransferOptions, | 56 | options: TransferOptions, |
| @@ -70,7 +71,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 70 | let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); | 71 | let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); |
| 71 | 72 | ||
| 72 | Self { | 73 | Self { |
| 73 | channel: BusyChannel::new(channel), | 74 | channel: BusyPeripheral::new(channel), |
| 74 | ringbuf: ReadableDmaRingBuffer::new(buffer), | 75 | ringbuf: ReadableDmaRingBuffer::new(buffer), |
| 75 | table, | 76 | table, |
| 76 | options, | 77 | options, |
| @@ -189,7 +190,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { | |||
| 189 | 190 | ||
| 190 | /// Ringbuffer for writing data using GPDMA linked-list mode. | 191 | /// Ringbuffer for writing data using GPDMA linked-list mode. |
| 191 | pub struct WritableRingBuffer<'a, W: Word> { | 192 | pub struct WritableRingBuffer<'a, W: Word> { |
| 192 | channel: BusyChannel<'a>, | 193 | channel: BusyPeripheral<Peri<'a, AnyChannel>>, |
| 193 | ringbuf: WritableDmaRingBuffer<'a, W>, | 194 | ringbuf: WritableDmaRingBuffer<'a, W>, |
| 194 | table: Table<2>, | 195 | table: Table<2>, |
| 195 | options: TransferOptions, | 196 | options: TransferOptions, |
| @@ -210,7 +211,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 210 | let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); | 211 | let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); |
| 211 | 212 | ||
| 212 | Self { | 213 | Self { |
| 213 | channel: BusyChannel::new(channel), | 214 | channel: BusyPeripheral::new(channel), |
| 214 | ringbuf: WritableDmaRingBuffer::new(buffer), | 215 | ringbuf: WritableDmaRingBuffer::new(buffer), |
| 215 | table, | 216 | table, |
| 216 | options, | 217 | options, |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 4becc2d87..efb324fa6 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -3,14 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #[cfg(any(bdma, dma))] | 4 | #[cfg(any(bdma, dma))] |
| 5 | mod dma_bdma; | 5 | mod dma_bdma; |
| 6 | use core::ops; | ||
| 7 | 6 | ||
| 8 | #[cfg(any(bdma, dma))] | 7 | #[cfg(any(bdma, dma))] |
| 9 | pub use dma_bdma::*; | 8 | pub use dma_bdma::*; |
| 10 | 9 | ||
| 11 | #[cfg(gpdma)] | 10 | #[cfg(gpdma)] |
| 12 | pub(crate) mod gpdma; | 11 | pub(crate) mod gpdma; |
| 13 | use embassy_hal_internal::Peri; | ||
| 14 | #[cfg(gpdma)] | 12 | #[cfg(gpdma)] |
| 15 | pub use gpdma::ringbuffered::*; | 13 | pub use gpdma::ringbuffered::*; |
| 16 | #[cfg(gpdma)] | 14 | #[cfg(gpdma)] |
| @@ -27,9 +25,10 @@ pub(crate) use util::*; | |||
| 27 | pub(crate) mod ringbuffer; | 25 | pub(crate) mod ringbuffer; |
| 28 | pub mod word; | 26 | pub mod word; |
| 29 | 27 | ||
| 30 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 28 | use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; |
| 31 | 29 | ||
| 32 | use crate::interrupt; | 30 | use crate::interrupt; |
| 31 | use crate::rcc::StoppablePeripheral; | ||
| 33 | 32 | ||
| 34 | /// The direction of a DMA transfer. | 33 | /// The direction of a DMA transfer. |
| 35 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 34 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| @@ -48,6 +47,13 @@ pub type Request = u8; | |||
| 48 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] | 47 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] |
| 49 | pub type Request = (); | 48 | pub type Request = (); |
| 50 | 49 | ||
| 50 | impl<'a> StoppablePeripheral for Peri<'a, AnyChannel> { | ||
| 51 | #[cfg(feature = "low-power")] | ||
| 52 | fn stop_mode(&self) -> crate::rcc::StopMode { | ||
| 53 | self.stop_mode | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 51 | pub(crate) trait SealedChannel { | 57 | pub(crate) trait SealedChannel { |
| 52 | #[cfg(not(stm32n6))] | 58 | #[cfg(not(stm32n6))] |
| 53 | fn id(&self) -> u8; | 59 | fn id(&self) -> u8; |
| @@ -103,44 +109,6 @@ macro_rules! dma_channel_impl { | |||
| 103 | }; | 109 | }; |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 106 | pub(crate) struct BusyChannel<'a> { | ||
| 107 | channel: Peri<'a, AnyChannel>, | ||
| 108 | } | ||
| 109 | |||
| 110 | impl<'a> BusyChannel<'a> { | ||
| 111 | pub fn new(channel: Peri<'a, AnyChannel>) -> Self { | ||
| 112 | #[cfg(feature = "low-power")] | ||
| 113 | critical_section::with(|cs| { | ||
| 114 | crate::rcc::increment_stop_refcount(cs, channel.stop_mode); | ||
| 115 | }); | ||
| 116 | |||
| 117 | Self { channel } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | impl<'a> Drop for BusyChannel<'a> { | ||
| 122 | fn drop(&mut self) { | ||
| 123 | #[cfg(feature = "low-power")] | ||
| 124 | critical_section::with(|cs| { | ||
| 125 | crate::rcc::decrement_stop_refcount(cs, self.stop_mode); | ||
| 126 | }); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | impl<'a> ops::Deref for BusyChannel<'a> { | ||
| 131 | type Target = Peri<'a, AnyChannel>; | ||
| 132 | |||
| 133 | fn deref(&self) -> &Self::Target { | ||
| 134 | &self.channel | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | impl<'a> ops::DerefMut for BusyChannel<'a> { | ||
| 139 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 140 | &mut self.channel | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Type-erased DMA channel. | 112 | /// Type-erased DMA channel. |
| 145 | pub struct AnyChannel { | 113 | pub struct AnyChannel { |
| 146 | pub(crate) id: u8, | 114 | pub(crate) id: u8, |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index bd8290da0..cdf3323fb 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -51,7 +51,7 @@ use embassy_executor::*; | |||
| 51 | 51 | ||
| 52 | use crate::interrupt; | 52 | use crate::interrupt; |
| 53 | pub use crate::rcc::StopMode; | 53 | pub use crate::rcc::StopMode; |
| 54 | use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount}; | 54 | use crate::rcc::{BusyPeripheral, RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2}; |
| 55 | use crate::time_driver::get_driver; | 55 | use crate::time_driver::get_driver; |
| 56 | 56 | ||
| 57 | const THREAD_PENDER: usize = usize::MAX; | 57 | const THREAD_PENDER: usize = usize::MAX; |
| @@ -59,7 +59,9 @@ const THREAD_PENDER: usize = usize::MAX; | |||
| 59 | static mut EXECUTOR_TAKEN: bool = false; | 59 | static mut EXECUTOR_TAKEN: bool = false; |
| 60 | 60 | ||
| 61 | /// Prevent the device from going into the stop mode if held | 61 | /// Prevent the device from going into the stop mode if held |
| 62 | pub struct DeviceBusy(StopMode); | 62 | pub struct DeviceBusy { |
| 63 | _stop_mode: BusyPeripheral<StopMode>, | ||
| 64 | } | ||
| 63 | 65 | ||
| 64 | impl DeviceBusy { | 66 | impl DeviceBusy { |
| 65 | /// Create a new DeviceBusy with stop1. | 67 | /// Create a new DeviceBusy with stop1. |
| @@ -74,19 +76,9 @@ impl DeviceBusy { | |||
| 74 | 76 | ||
| 75 | /// Create a new DeviceBusy. | 77 | /// Create a new DeviceBusy. |
| 76 | pub fn new(stop_mode: StopMode) -> Self { | 78 | pub fn new(stop_mode: StopMode) -> Self { |
| 77 | critical_section::with(|cs| { | 79 | Self { |
| 78 | increment_stop_refcount(cs, stop_mode); | 80 | _stop_mode: BusyPeripheral::new(stop_mode), |
| 79 | }); | 81 | } |
| 80 | |||
| 81 | Self(stop_mode) | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | impl Drop for DeviceBusy { | ||
| 86 | fn drop(&mut self) { | ||
| 87 | critical_section::with(|cs| { | ||
| 88 | decrement_stop_refcount(cs, self.0); | ||
| 89 | }); | ||
| 90 | } | 82 | } |
| 91 | } | 83 | } |
| 92 | 84 | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 85434fa83..1dd634cfe 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #![allow(missing_docs)] // TODO | 4 | #![allow(missing_docs)] // TODO |
| 5 | 5 | ||
| 6 | use core::mem::MaybeUninit; | 6 | use core::mem::MaybeUninit; |
| 7 | use core::ops; | ||
| 7 | 8 | ||
| 8 | mod bd; | 9 | mod bd; |
| 9 | pub use bd::*; | 10 | pub use bd::*; |
| @@ -112,7 +113,7 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo | |||
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | #[cfg(feature = "low-power")] | 115 | #[cfg(feature = "low-power")] |
| 115 | pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { | 116 | fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { |
| 116 | match stop_mode { | 117 | match stop_mode { |
| 117 | StopMode::Standby => {} | 118 | StopMode::Standby => {} |
| 118 | StopMode::Stop2 => unsafe { | 119 | StopMode::Stop2 => unsafe { |
| @@ -125,7 +126,7 @@ pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) | |||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | #[cfg(feature = "low-power")] | 128 | #[cfg(feature = "low-power")] |
| 128 | pub(crate) fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { | 129 | fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { |
| 129 | match stop_mode { | 130 | match stop_mode { |
| 130 | StopMode::Standby => {} | 131 | StopMode::Standby => {} |
| 131 | StopMode::Stop2 => unsafe { | 132 | StopMode::Stop2 => unsafe { |
| @@ -182,6 +183,12 @@ pub enum StopMode { | |||
| 182 | Standby, | 183 | Standby, |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 186 | #[cfg(feature = "low-power")] | ||
| 187 | type BusyRccPeripheral = BusyPeripheral<StopMode>; | ||
| 188 | |||
| 189 | #[cfg(not(feature = "low-power"))] | ||
| 190 | type BusyRccPeripheral = (); | ||
| 191 | |||
| 185 | impl RccInfo { | 192 | impl RccInfo { |
| 186 | /// Safety: | 193 | /// Safety: |
| 187 | /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit | 194 | /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit |
| @@ -234,9 +241,6 @@ impl RccInfo { | |||
| 234 | } | 241 | } |
| 235 | } | 242 | } |
| 236 | 243 | ||
| 237 | #[cfg(feature = "low-power")] | ||
| 238 | increment_stop_refcount(_cs, self.stop_mode); | ||
| 239 | |||
| 240 | // set the xxxRST bit | 244 | // set the xxxRST bit |
| 241 | let reset_ptr = self.reset_ptr(); | 245 | let reset_ptr = self.reset_ptr(); |
| 242 | if let Some(reset_ptr) = reset_ptr { | 246 | if let Some(reset_ptr) = reset_ptr { |
| @@ -292,9 +296,6 @@ impl RccInfo { | |||
| 292 | } | 296 | } |
| 293 | } | 297 | } |
| 294 | 298 | ||
| 295 | #[cfg(feature = "low-power")] | ||
| 296 | decrement_stop_refcount(_cs, self.stop_mode); | ||
| 297 | |||
| 298 | // clear the xxxEN bit | 299 | // clear the xxxEN bit |
| 299 | let enable_ptr = self.enable_ptr(); | 300 | let enable_ptr = self.enable_ptr(); |
| 300 | unsafe { | 301 | unsafe { |
| @@ -303,16 +304,63 @@ impl RccInfo { | |||
| 303 | } | 304 | } |
| 304 | } | 305 | } |
| 305 | 306 | ||
| 307 | #[allow(dead_code)] | ||
| 308 | pub(crate) fn increment_stop_refcount_with_cs(&self, _cs: CriticalSection) { | ||
| 309 | #[cfg(feature = "low-power")] | ||
| 310 | increment_stop_refcount(_cs, self.stop_mode); | ||
| 311 | } | ||
| 312 | |||
| 313 | #[allow(dead_code)] | ||
| 314 | pub(crate) fn increment_stop_refcount(&self) { | ||
| 315 | #[cfg(feature = "low-power")] | ||
| 316 | critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs)) | ||
| 317 | } | ||
| 318 | |||
| 319 | #[allow(dead_code)] | ||
| 320 | pub(crate) fn decrement_stop_refcount_with_cs(&self, _cs: CriticalSection) { | ||
| 321 | #[cfg(feature = "low-power")] | ||
| 322 | decrement_stop_refcount(_cs, self.stop_mode); | ||
| 323 | } | ||
| 324 | |||
| 325 | #[allow(dead_code)] | ||
| 326 | pub(crate) fn decrement_stop_refcount(&self) { | ||
| 327 | #[cfg(feature = "low-power")] | ||
| 328 | critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs)) | ||
| 329 | } | ||
| 330 | |||
| 306 | // TODO: should this be `unsafe`? | 331 | // TODO: should this be `unsafe`? |
| 307 | pub(crate) fn enable_and_reset(&self) { | 332 | pub(crate) fn enable_and_reset(&self) { |
| 333 | critical_section::with(|cs| { | ||
| 334 | self.enable_and_reset_with_cs(cs); | ||
| 335 | self.increment_stop_refcount_with_cs(cs); | ||
| 336 | }) | ||
| 337 | } | ||
| 338 | |||
| 339 | #[allow(dead_code)] | ||
| 340 | pub(crate) fn enable_and_reset_without_stop(&self) { | ||
| 308 | critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) | 341 | critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) |
| 309 | } | 342 | } |
| 310 | 343 | ||
| 311 | // TODO: should this be `unsafe`? | 344 | // TODO: should this be `unsafe`? |
| 312 | pub(crate) fn disable(&self) { | 345 | pub(crate) fn disable(&self) { |
| 346 | critical_section::with(|cs| { | ||
| 347 | self.disable_with_cs(cs); | ||
| 348 | self.decrement_stop_refcount_with_cs(cs); | ||
| 349 | }) | ||
| 350 | } | ||
| 351 | |||
| 352 | // TODO: should this be `unsafe`? | ||
| 353 | #[allow(dead_code)] | ||
| 354 | pub(crate) fn disable_without_stop(&self) { | ||
| 313 | critical_section::with(|cs| self.disable_with_cs(cs)) | 355 | critical_section::with(|cs| self.disable_with_cs(cs)) |
| 314 | } | 356 | } |
| 315 | 357 | ||
| 358 | #[allow(dead_code)] | ||
| 359 | pub(crate) fn block_stop(&self) -> BusyRccPeripheral { | ||
| 360 | #[cfg(feature = "low-power")] | ||
| 361 | BusyPeripheral::new(self.stop_mode) | ||
| 362 | } | ||
| 363 | |||
| 316 | fn reset_ptr(&self) -> Option<*mut u32> { | 364 | fn reset_ptr(&self) -> Option<*mut u32> { |
| 317 | if self.reset_offset_or_0xff != 0xff { | 365 | if self.reset_offset_or_0xff != 0xff { |
| 318 | Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) }) | 366 | Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) }) |
| @@ -326,6 +374,53 @@ impl RccInfo { | |||
| 326 | } | 374 | } |
| 327 | } | 375 | } |
| 328 | 376 | ||
| 377 | pub(crate) trait StoppablePeripheral { | ||
| 378 | #[cfg(feature = "low-power")] | ||
| 379 | #[allow(dead_code)] | ||
| 380 | fn stop_mode(&self) -> StopMode; | ||
| 381 | } | ||
| 382 | |||
| 383 | #[cfg(feature = "low-power")] | ||
| 384 | impl<'a> StoppablePeripheral for StopMode { | ||
| 385 | fn stop_mode(&self) -> StopMode { | ||
| 386 | *self | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | pub(crate) struct BusyPeripheral<T: StoppablePeripheral> { | ||
| 391 | peripheral: T, | ||
| 392 | } | ||
| 393 | |||
| 394 | impl<T: StoppablePeripheral> BusyPeripheral<T> { | ||
| 395 | pub fn new(peripheral: T) -> Self { | ||
| 396 | #[cfg(feature = "low-power")] | ||
| 397 | critical_section::with(|cs| increment_stop_refcount(cs, peripheral.stop_mode())); | ||
| 398 | |||
| 399 | Self { peripheral } | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | impl<T: StoppablePeripheral> Drop for BusyPeripheral<T> { | ||
| 404 | fn drop(&mut self) { | ||
| 405 | #[cfg(feature = "low-power")] | ||
| 406 | critical_section::with(|cs| decrement_stop_refcount(cs, self.peripheral.stop_mode())); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | impl<T: StoppablePeripheral> ops::Deref for BusyPeripheral<T> { | ||
| 411 | type Target = T; | ||
| 412 | |||
| 413 | fn deref(&self) -> &Self::Target { | ||
| 414 | &self.peripheral | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | impl<T: StoppablePeripheral> ops::DerefMut for BusyPeripheral<T> { | ||
| 419 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 420 | &mut self.peripheral | ||
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 329 | #[allow(unused)] | 424 | #[allow(unused)] |
| 330 | mod util { | 425 | mod util { |
| 331 | use crate::time::Hertz; | 426 | use crate::time::Hertz; |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 0b75aef92..cfcf5f3fd 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -14,11 +14,11 @@ use stm32_metapac::timer::{TimGp16, regs}; | |||
| 14 | 14 | ||
| 15 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::pac::timer::vals; | 16 | use crate::pac::timer::vals; |
| 17 | use crate::peripherals; | ||
| 17 | use crate::rcc::{self, SealedRccPeripheral}; | 18 | use crate::rcc::{self, SealedRccPeripheral}; |
| 18 | #[cfg(feature = "low-power")] | 19 | #[cfg(feature = "low-power")] |
| 19 | use crate::rtc::Rtc; | 20 | use crate::rtc::Rtc; |
| 20 | use crate::timer::{CoreInstance, GeneralInstance1Channel}; | 21 | use crate::timer::{CoreInstance, GeneralInstance1Channel}; |
| 21 | use crate::{interrupt, peripherals}; | ||
| 22 | 22 | ||
| 23 | // NOTE regarding ALARM_COUNT: | 23 | // NOTE regarding ALARM_COUNT: |
| 24 | // | 24 | // |
| @@ -56,121 +56,6 @@ type T = peripherals::TIM23; | |||
| 56 | #[cfg(time_driver_tim24)] | 56 | #[cfg(time_driver_tim24)] |
| 57 | type T = peripherals::TIM24; | 57 | type T = peripherals::TIM24; |
| 58 | 58 | ||
| 59 | foreach_interrupt! { | ||
| 60 | (TIM1, timer, $block:ident, CC, $irq:ident) => { | ||
| 61 | #[cfg(time_driver_tim1)] | ||
| 62 | #[cfg(feature = "rt")] | ||
| 63 | #[interrupt] | ||
| 64 | fn $irq() { | ||
| 65 | DRIVER.on_interrupt() | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | (TIM2, timer, $block:ident, CC, $irq:ident) => { | ||
| 69 | #[cfg(time_driver_tim2)] | ||
| 70 | #[cfg(feature = "rt")] | ||
| 71 | #[interrupt] | ||
| 72 | fn $irq() { | ||
| 73 | DRIVER.on_interrupt() | ||
| 74 | } | ||
| 75 | }; | ||
| 76 | (TIM3, timer, $block:ident, CC, $irq:ident) => { | ||
| 77 | #[cfg(time_driver_tim3)] | ||
| 78 | #[cfg(feature = "rt")] | ||
| 79 | #[interrupt] | ||
| 80 | fn $irq() { | ||
| 81 | DRIVER.on_interrupt() | ||
| 82 | } | ||
| 83 | }; | ||
| 84 | (TIM4, timer, $block:ident, CC, $irq:ident) => { | ||
| 85 | #[cfg(time_driver_tim4)] | ||
| 86 | #[cfg(feature = "rt")] | ||
| 87 | #[interrupt] | ||
| 88 | fn $irq() { | ||
| 89 | DRIVER.on_interrupt() | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | (TIM5, timer, $block:ident, CC, $irq:ident) => { | ||
| 93 | #[cfg(time_driver_tim5)] | ||
| 94 | #[cfg(feature = "rt")] | ||
| 95 | #[interrupt] | ||
| 96 | fn $irq() { | ||
| 97 | DRIVER.on_interrupt() | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | (TIM8, timer, $block:ident, CC, $irq:ident) => { | ||
| 101 | #[cfg(time_driver_tim8)] | ||
| 102 | #[cfg(feature = "rt")] | ||
| 103 | #[interrupt] | ||
| 104 | fn $irq() { | ||
| 105 | DRIVER.on_interrupt() | ||
| 106 | } | ||
| 107 | }; | ||
| 108 | (TIM9, timer, $block:ident, CC, $irq:ident) => { | ||
| 109 | #[cfg(time_driver_tim9)] | ||
| 110 | #[cfg(feature = "rt")] | ||
| 111 | #[interrupt] | ||
| 112 | fn $irq() { | ||
| 113 | DRIVER.on_interrupt() | ||
| 114 | } | ||
| 115 | }; | ||
| 116 | (TIM12, timer, $block:ident, CC, $irq:ident) => { | ||
| 117 | #[cfg(time_driver_tim12)] | ||
| 118 | #[cfg(feature = "rt")] | ||
| 119 | #[interrupt] | ||
| 120 | fn $irq() { | ||
| 121 | DRIVER.on_interrupt() | ||
| 122 | } | ||
| 123 | }; | ||
| 124 | (TIM15, timer, $block:ident, CC, $irq:ident) => { | ||
| 125 | #[cfg(time_driver_tim15)] | ||
| 126 | #[cfg(feature = "rt")] | ||
| 127 | #[interrupt] | ||
| 128 | fn $irq() { | ||
| 129 | DRIVER.on_interrupt() | ||
| 130 | } | ||
| 131 | }; | ||
| 132 | (TIM20, timer, $block:ident, CC, $irq:ident) => { | ||
| 133 | #[cfg(time_driver_tim20)] | ||
| 134 | #[cfg(feature = "rt")] | ||
| 135 | #[interrupt] | ||
| 136 | fn $irq() { | ||
| 137 | DRIVER.on_interrupt() | ||
| 138 | } | ||
| 139 | }; | ||
| 140 | (TIM21, timer, $block:ident, CC, $irq:ident) => { | ||
| 141 | #[cfg(time_driver_tim21)] | ||
| 142 | #[cfg(feature = "rt")] | ||
| 143 | #[interrupt] | ||
| 144 | fn $irq() { | ||
| 145 | DRIVER.on_interrupt() | ||
| 146 | } | ||
| 147 | }; | ||
| 148 | (TIM22, timer, $block:ident, CC, $irq:ident) => { | ||
| 149 | #[cfg(time_driver_tim22)] | ||
| 150 | #[cfg(feature = "rt")] | ||
| 151 | #[interrupt] | ||
| 152 | fn $irq() { | ||
| 153 | DRIVER.on_interrupt() | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | (TIM23, timer, $block:ident, CC, $irq:ident) => { | ||
| 157 | #[cfg(time_driver_tim23)] | ||
| 158 | #[cfg(feature = "rt")] | ||
| 159 | #[interrupt] | ||
| 160 | fn $irq() { | ||
| 161 | DRIVER.on_interrupt() | ||
| 162 | } | ||
| 163 | }; | ||
| 164 | (TIM24, timer, $block:ident, CC, $irq:ident) => { | ||
| 165 | #[cfg(time_driver_tim24)] | ||
| 166 | #[cfg(feature = "rt")] | ||
| 167 | #[interrupt] | ||
| 168 | fn $irq() { | ||
| 169 | DRIVER.on_interrupt() | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | } | ||
| 173 | |||
| 174 | fn regs_gp16() -> TimGp16 { | 59 | fn regs_gp16() -> TimGp16 { |
| 175 | unsafe { TimGp16::from_ptr(T::regs()) } | 60 | unsafe { TimGp16::from_ptr(T::regs()) } |
| 176 | } | 61 | } |
| @@ -282,7 +167,11 @@ impl RtcDriver { | |||
| 282 | r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst))); | 167 | r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst))); |
| 283 | 168 | ||
| 284 | <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); | 169 | <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); |
| 285 | unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() }; | 170 | <T as CoreInstance>::UpdateInterrupt::unpend(); |
| 171 | unsafe { | ||
| 172 | <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable(); | ||
| 173 | <T as CoreInstance>::UpdateInterrupt::enable(); | ||
| 174 | } | ||
| 286 | } | 175 | } |
| 287 | 176 | ||
| 288 | fn init(&'static self, cs: CriticalSection) { | 177 | fn init(&'static self, cs: CriticalSection) { |
| @@ -290,7 +179,7 @@ impl RtcDriver { | |||
| 290 | regs_gp16().cr1().modify(|w| w.set_cen(true)); | 179 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 291 | } | 180 | } |
| 292 | 181 | ||
| 293 | fn on_interrupt(&self) { | 182 | pub(crate) fn on_interrupt(&self) { |
| 294 | let r = regs_gp16(); | 183 | let r = regs_gp16(); |
| 295 | 184 | ||
| 296 | critical_section::with(|cs| { | 185 | critical_section::with(|cs| { |
| @@ -508,7 +397,6 @@ impl Driver for RtcDriver { | |||
| 508 | } | 397 | } |
| 509 | } | 398 | } |
| 510 | 399 | ||
| 511 | #[cfg(feature = "low-power")] | ||
| 512 | pub(crate) const fn get_driver() -> &'static RtcDriver { | 400 | pub(crate) const fn get_driver() -> &'static RtcDriver { |
| 513 | &DRIVER | 401 | &DRIVER |
| 514 | } | 402 | } |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0e7da634d..8047d6005 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -491,6 +491,8 @@ impl<'d> UartTx<'d, Async> { | |||
| 491 | 491 | ||
| 492 | /// Initiate an asynchronous UART write | 492 | /// Initiate an asynchronous UART write |
| 493 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 493 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 494 | let _ = self.info.rcc.block_stop(); | ||
| 495 | |||
| 494 | let r = self.info.regs; | 496 | let r = self.info.regs; |
| 495 | 497 | ||
| 496 | half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); | 498 | half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); |
| @@ -508,6 +510,8 @@ impl<'d> UartTx<'d, Async> { | |||
| 508 | 510 | ||
| 509 | /// Wait until transmission complete | 511 | /// Wait until transmission complete |
| 510 | pub async fn flush(&mut self) -> Result<(), Error> { | 512 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 513 | let _ = self.info.rcc.block_stop(); | ||
| 514 | |||
| 511 | flush(&self.info, &self.state).await | 515 | flush(&self.info, &self.state).await |
| 512 | } | 516 | } |
| 513 | } | 517 | } |
| @@ -569,7 +573,7 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 569 | let state = self.state; | 573 | let state = self.state; |
| 570 | state.tx_rx_refcount.store(1, Ordering::Relaxed); | 574 | state.tx_rx_refcount.store(1, Ordering::Relaxed); |
| 571 | 575 | ||
| 572 | info.rcc.enable_and_reset(); | 576 | info.rcc.enable_and_reset_without_stop(); |
| 573 | 577 | ||
| 574 | info.regs.cr3().modify(|w| { | 578 | info.regs.cr3().modify(|w| { |
| 575 | w.set_ctse(self.cts.is_some()); | 579 | w.set_ctse(self.cts.is_some()); |
| @@ -726,6 +730,8 @@ impl<'d> UartRx<'d, Async> { | |||
| 726 | 730 | ||
| 727 | /// Initiate an asynchronous UART read | 731 | /// Initiate an asynchronous UART read |
| 728 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 732 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 733 | let _ = self.info.rcc.block_stop(); | ||
| 734 | |||
| 729 | self.inner_read(buffer, false).await?; | 735 | self.inner_read(buffer, false).await?; |
| 730 | 736 | ||
| 731 | Ok(()) | 737 | Ok(()) |
| @@ -733,6 +739,8 @@ impl<'d> UartRx<'d, Async> { | |||
| 733 | 739 | ||
| 734 | /// Initiate an asynchronous read with idle line detection enabled | 740 | /// Initiate an asynchronous read with idle line detection enabled |
| 735 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 741 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 742 | let _ = self.info.rcc.block_stop(); | ||
| 743 | |||
| 736 | self.inner_read(buffer, true).await | 744 | self.inner_read(buffer, true).await |
| 737 | } | 745 | } |
| 738 | 746 | ||
| @@ -1004,7 +1012,7 @@ impl<'d, M: Mode> UartRx<'d, M> { | |||
| 1004 | .eager_reads | 1012 | .eager_reads |
| 1005 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); | 1013 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); |
| 1006 | 1014 | ||
| 1007 | info.rcc.enable_and_reset(); | 1015 | info.rcc.enable_and_reset_without_stop(); |
| 1008 | 1016 | ||
| 1009 | info.regs.cr3().write(|w| { | 1017 | info.regs.cr3().write(|w| { |
| 1010 | w.set_rtse(self.rts.is_some()); | 1018 | w.set_rtse(self.rts.is_some()); |
| @@ -1143,7 +1151,7 @@ fn drop_tx_rx(info: &Info, state: &State) { | |||
| 1143 | refcount == 1 | 1151 | refcount == 1 |
| 1144 | }); | 1152 | }); |
| 1145 | if is_last_drop { | 1153 | if is_last_drop { |
| 1146 | info.rcc.disable(); | 1154 | info.rcc.disable_without_stop(); |
| 1147 | } | 1155 | } |
| 1148 | } | 1156 | } |
| 1149 | 1157 | ||
| @@ -1506,7 +1514,7 @@ impl<'d, M: Mode> Uart<'d, M> { | |||
| 1506 | .eager_reads | 1514 | .eager_reads |
| 1507 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); | 1515 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); |
| 1508 | 1516 | ||
| 1509 | info.rcc.enable_and_reset(); | 1517 | info.rcc.enable_and_reset_without_stop(); |
| 1510 | 1518 | ||
| 1511 | info.regs.cr3().write(|w| { | 1519 | info.regs.cr3().write(|w| { |
| 1512 | w.set_rtse(self.rx.rts.is_some()); | 1520 | w.set_rtse(self.rx.rts.is_some()); |
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index bac570d27..cc5224b69 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs | |||
| @@ -117,6 +117,8 @@ impl<'d> UartRx<'d, Async> { | |||
| 117 | let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; | 117 | let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; |
| 118 | let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; | 118 | let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; |
| 119 | 119 | ||
| 120 | info.rcc.increment_stop_refcount(); | ||
| 121 | |||
| 120 | // Don't disable the clock | 122 | // Don't disable the clock |
| 121 | mem::forget(self); | 123 | mem::forget(self); |
| 122 | 124 | ||
| @@ -324,6 +326,7 @@ impl<'d> RingBufferedUartRx<'d> { | |||
| 324 | 326 | ||
| 325 | impl Drop for RingBufferedUartRx<'_> { | 327 | impl Drop for RingBufferedUartRx<'_> { |
| 326 | fn drop(&mut self) { | 328 | fn drop(&mut self) { |
| 329 | self.info.rcc.decrement_stop_refcount(); | ||
| 327 | self.stop_uart(); | 330 | self.stop_uart(); |
| 328 | self.rx.as_ref().map(|x| x.set_as_disconnected()); | 331 | self.rx.as_ref().map(|x| x.set_as_disconnected()); |
| 329 | self.rts.as_ref().map(|x| x.set_as_disconnected()); | 332 | self.rts.as_ref().map(|x| x.set_as_disconnected()); |
diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index cfb1bf021..3dd71ffbc 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md | |||
| @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | - Add support for USB HID Boot Protocol Mode | 11 | - Add support for USB HID Boot Protocol Mode |
| 12 | - Bump usbd-hid from 0.8.1 to 0.9.0 | ||
| 12 | 13 | ||
| 13 | ## 0.5.1 - 2025-08-26 | 14 | ## 0.5.1 - 2025-08-26 |
| 14 | 15 | ||
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index aeb7392f1..3d1e005e4 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml | |||
| @@ -69,5 +69,5 @@ heapless = "0.8" | |||
| 69 | embedded-io-async = "0.6.1" | 69 | embedded-io-async = "0.6.1" |
| 70 | 70 | ||
| 71 | # for HID | 71 | # for HID |
| 72 | usbd-hid = { version = "0.8.1", optional = true } | 72 | usbd-hid = { version = "0.9.0", optional = true } |
| 73 | ssmarshal = { version = "1.0", default-features = false, optional = true } | 73 | ssmarshal = { version = "1.0", default-features = false, optional = true } |
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 70a2c28c3..292d1abec 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml | |||
| @@ -9,8 +9,8 @@ publish = false | |||
| 9 | embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } | 9 | embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } |
| 10 | embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } | 11 | embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } |
| 12 | embassy-rp = { version = "0.8.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } | 12 | embassy-rp = { version = "0.9.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } |
| 13 | embassy-boot-rp = { version = "0.8.0", path = "../../../../embassy-boot-rp", features = [] } | 13 | embassy-boot-rp = { version = "0.9.0", path = "../../../../embassy-boot-rp", features = [] } |
| 14 | embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } | 14 | embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } |
| 15 | 15 | ||
| 16 | defmt = "1.0.1" | 16 | defmt = "1.0.1" |
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index a026d6352..1fe3d2419 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -28,7 +28,7 @@ cortex-m-rt = "0.7.0" | |||
| 28 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | 28 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } |
| 29 | rand = { version = "0.9.0", default-features = false } | 29 | rand = { version = "0.9.0", default-features = false } |
| 30 | embedded-storage = "0.3.1" | 30 | embedded-storage = "0.3.1" |
| 31 | usbd-hid = "0.8.1" | 31 | usbd-hid = "0.9.0" |
| 32 | serde = { version = "1.0.136", default-features = false } | 32 | serde = { version = "1.0.136", default-features = false } |
| 33 | embedded-hal = { version = "1.0" } | 33 | embedded-hal = { version = "1.0" } |
| 34 | embedded-hal-async = { version = "1.0" } | 34 | embedded-hal-async = { version = "1.0" } |
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 4dcbdd715..97efe58e8 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml | |||
| @@ -23,7 +23,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 23 | cortex-m-rt = "0.7.0" | 23 | cortex-m-rt = "0.7.0" |
| 24 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | 24 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } |
| 25 | embedded-storage = "0.3.1" | 25 | embedded-storage = "0.3.1" |
| 26 | usbd-hid = "0.8.1" | 26 | usbd-hid = "0.9.0" |
| 27 | serde = { version = "1.0.136", default-features = false } | 27 | serde = { version = "1.0.136", default-features = false } |
| 28 | 28 | ||
| 29 | [profile.release] | 29 | [profile.release] |
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 4ef77279f..f34df0f26 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml | |||
| @@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | |||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } |
| 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } |
| 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } |
| 16 | 16 | ||
diff --git a/examples/nrf54l15/src/bin/rtc.rs b/examples/nrf54l15/src/bin/rtc.rs deleted file mode 100644 index a45aaca52..000000000 --- a/examples/nrf54l15/src/bin/rtc.rs +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::cell::RefCell; | ||
| 5 | |||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 8 | use embassy_nrf::interrupt; | ||
| 9 | use embassy_nrf::rtc::Rtc; | ||
| 10 | use embassy_sync::blocking_mutex::Mutex; | ||
| 11 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 12 | use portable_atomic::AtomicU64; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | // 64 bit counter which will never overflow. | ||
| 16 | static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); | ||
| 17 | static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static>>>> = Mutex::new(RefCell::new(None)); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | defmt::println!("nRF54L15 RTC example"); | ||
| 22 | let p = embassy_nrf::init(Default::default()); | ||
| 23 | let mut led = Output::new(p.P2_09, Level::High, OutputDrive::Standard); | ||
| 24 | // Counter resolution is 125 ms. | ||
| 25 | let mut rtc = Rtc::new(p.RTC10, (1 << 12) - 1).unwrap(); | ||
| 26 | rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true); | ||
| 27 | rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick); | ||
| 28 | rtc.enable(); | ||
| 29 | RTC.lock(|r| { | ||
| 30 | let mut rtc_borrow = r.borrow_mut(); | ||
| 31 | *rtc_borrow = Some(rtc); | ||
| 32 | }); | ||
| 33 | |||
| 34 | let mut last_counter_val = 0; | ||
| 35 | loop { | ||
| 36 | let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed); | ||
| 37 | if current != last_counter_val { | ||
| 38 | led.toggle(); | ||
| 39 | last_counter_val = current; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | #[interrupt] | ||
| 45 | fn RTC10() { | ||
| 46 | // For 64-bit, we do not need to worry about overflowing, at least not for realistic program | ||
| 47 | // lifetimes. | ||
| 48 | TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); | ||
| 49 | RTC.lock(|r| { | ||
| 50 | let mut rtc_borrow = r.borrow_mut(); | ||
| 51 | rtc_borrow | ||
| 52 | .as_mut() | ||
| 53 | .unwrap() | ||
| 54 | .reset_event(embassy_nrf::rtc::Interrupt::Tick); | ||
| 55 | }); | ||
| 56 | } | ||
diff --git a/examples/nrf54l15/src/bin/timer.rs b/examples/nrf54l15/src/bin/timer.rs new file mode 100644 index 000000000..68acc91c1 --- /dev/null +++ b/examples/nrf54l15/src/bin/timer.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::task] | ||
| 10 | async fn run1() { | ||
| 11 | loop { | ||
| 12 | info!("BIG INFREQUENT TICK"); | ||
| 13 | Timer::after_secs(10).await; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn run2() { | ||
| 19 | loop { | ||
| 20 | info!("tick"); | ||
| 21 | Timer::after_secs(1).await; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | #[embassy_executor::main] | ||
| 26 | async fn main(spawner: Spawner) { | ||
| 27 | let _p = embassy_nrf::init(Default::default()); | ||
| 28 | spawner.spawn(unwrap!(run1())); | ||
| 29 | spawner.spawn(unwrap!(run2())); | ||
| 30 | } | ||
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 640addb28..e247f6f7a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -11,14 +11,14 @@ embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal", | |||
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 14 | embassy-rp = { version = "0.8.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } | 14 | embassy-rp = { version = "0.9.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } |
| 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } | 16 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } |
| 17 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } | 17 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 18 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | 18 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } |
| 19 | embassy-usb-logger = { version = "0.5.1", path = "../../embassy-usb-logger" } | 19 | embassy-usb-logger = { version = "0.5.1", path = "../../embassy-usb-logger" } |
| 20 | cyw43 = { version = "0.5.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 20 | cyw43 = { version = "0.6.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } |
| 21 | cyw43-pio = { version = "0.8.0", path = "../../cyw43-pio", features = ["defmt"] } | 21 | cyw43-pio = { version = "0.9.0", path = "../../cyw43-pio", features = ["defmt"] } |
| 22 | 22 | ||
| 23 | defmt = "1.0.1" | 23 | defmt = "1.0.1" |
| 24 | defmt-rtt = "1.0.0" | 24 | defmt-rtt = "1.0.0" |
| @@ -45,7 +45,7 @@ display-interface = "0.5.0" | |||
| 45 | byte-slice-cast = { version = "1.2.0", default-features = false } | 45 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 46 | smart-leds = "0.4.0" | 46 | smart-leds = "0.4.0" |
| 47 | heapless = "0.8" | 47 | heapless = "0.8" |
| 48 | usbd-hid = "0.8.1" | 48 | usbd-hid = "0.9.0" |
| 49 | 49 | ||
| 50 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | 50 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } |
| 51 | embedded-hal-async = "1.0" | 51 | embedded-hal-async = "1.0" |
diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 39a4f421a..16dfb5b77 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml | |||
| @@ -11,14 +11,14 @@ embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal", | |||
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 14 | embassy-rp = { version = "0.8.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } | 14 | embassy-rp = { version = "0.9.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } |
| 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } | 16 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } |
| 17 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } | 17 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 18 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | 18 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } |
| 19 | embassy-usb-logger = { version = "0.5.1", path = "../../embassy-usb-logger" } | 19 | embassy-usb-logger = { version = "0.5.1", path = "../../embassy-usb-logger" } |
| 20 | cyw43 = { version = "0.5.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 20 | cyw43 = { version = "0.6.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } |
| 21 | cyw43-pio = { version = "0.8.0", path = "../../cyw43-pio", features = ["defmt"] } | 21 | cyw43-pio = { version = "0.9.0", path = "../../cyw43-pio", features = ["defmt"] } |
| 22 | 22 | ||
| 23 | defmt = "1.0.1" | 23 | defmt = "1.0.1" |
| 24 | defmt-rtt = "1.0.0" | 24 | defmt-rtt = "1.0.0" |
| @@ -46,7 +46,7 @@ display-interface = "0.5.0" | |||
| 46 | byte-slice-cast = { version = "1.2.0", default-features = false } | 46 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 47 | smart-leds = "0.3.0" | 47 | smart-leds = "0.3.0" |
| 48 | heapless = "0.8" | 48 | heapless = "0.8" |
| 49 | usbd-hid = "0.8.1" | 49 | usbd-hid = "0.9.0" |
| 50 | 50 | ||
| 51 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | 51 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } |
| 52 | embedded-hal-async = "1.0" | 52 | embedded-hal-async = "1.0" |
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index d06b7505c..b4555045a 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -32,7 +32,7 @@ critical-section = "1.1" | |||
| 32 | nb = "1.0.0" | 32 | nb = "1.0.0" |
| 33 | embedded-storage = "0.3.1" | 33 | embedded-storage = "0.3.1" |
| 34 | micromath = "2.0.0" | 34 | micromath = "2.0.0" |
| 35 | usbd-hid = "0.8.1" | 35 | usbd-hid = "0.9.0" |
| 36 | static_cell = "2" | 36 | static_cell = "2" |
| 37 | chrono = { version = "^0.4", default-features = false} | 37 | chrono = { version = "^0.4", default-features = false} |
| 38 | 38 | ||
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 8bbeb594c..d1c19582b 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml | |||
| @@ -13,7 +13,7 @@ embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m | |||
| 13 | embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-usb = { path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-futures = { path = "../../embassy-futures" } | 15 | embassy-futures = { path = "../../embassy-futures" } |
| 16 | usbd-hid = "0.8.1" | 16 | usbd-hid = "0.9.0" |
| 17 | 17 | ||
| 18 | defmt = "1.0.1" | 18 | defmt = "1.0.1" |
| 19 | defmt-rtt = "1.0.0" | 19 | defmt-rtt = "1.0.0" |
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index b6158c854..586b00836 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml | |||
| @@ -14,7 +14,7 @@ embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["de | |||
| 14 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 15 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 16 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | 16 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } |
| 17 | usbd-hid = "0.8.1" | 17 | usbd-hid = "0.9.0" |
| 18 | 18 | ||
| 19 | defmt = "1.0.1" | 19 | defmt = "1.0.1" |
| 20 | defmt-rtt = "1.0.0" | 20 | defmt-rtt = "1.0.0" |
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 640e58f11..4dfe6904e 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -16,7 +16,7 @@ teleprobe-meta = "1.1" | |||
| 16 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 16 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 17 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 17 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 18 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", ] } | 18 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", ] } |
| 19 | embassy-rp = { version = "0.8.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } | 19 | embassy-rp = { version = "0.9.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } |
| 20 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | 20 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } |
| 21 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 21 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } |
| 22 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } | 22 | embassy-net-wiznet = { version = "0.2.1", path = "../../embassy-net-wiznet", features = ["defmt"] } |
