aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob <[email protected]>2025-05-14 18:57:49 +0200
committerGitHub <[email protected]>2025-05-14 18:57:49 +0200
commitb17da5b79470cb6b9877ec9fd5682062f7a37aec (patch)
tree4d60a3e4b9404a8b566b069358d700a6cfb5f8b2
parenta71642ca01190d1a8f8bd652bd41d8a9539fe2ee (diff)
parentb9ed61cdd99be4a58a757a0eb32c1fa77a696d6a (diff)
Merge branch 'embassy-rs:main' into update_doc_comment_for_adc_read
-rwxr-xr-x.github/ci/test.sh8
-rw-r--r--README.md91
-rwxr-xr-xci.sh27
-rw-r--r--docs/examples/basic/.cargo/config.toml4
-rw-r--r--docs/examples/layer-by-layer/.cargo/config.toml3
-rw-r--r--docs/pages/faq.adoc2
-rw-r--r--docs/pages/getting_started.adoc2
-rw-r--r--docs/pages/imxrt.adoc3
-rw-r--r--docs/pages/new_project.adoc2
-rw-r--r--docs/pages/project_structure.adoc4
-rw-r--r--embassy-imxrt/Cargo.toml9
-rw-r--r--embassy-imxrt/src/clocks.rs72
-rw-r--r--embassy-imxrt/src/crc.rs190
-rw-r--r--embassy-imxrt/src/lib.rs10
-rw-r--r--embassy-imxrt/src/rng.rs257
-rw-r--r--embassy-imxrt/src/time_driver.rs (renamed from embassy-imxrt/src/rtc.rs)196
-rw-r--r--embassy-net/CHANGELOG.md4
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/ipc.rs363
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--embassy-nrf/src/radio/ble.rs394
-rw-r--r--embassy-nrf/src/radio/ieee802154.rs7
-rw-r--r--embassy-nrf/src/radio/mod.rs8
-rw-r--r--embassy-nrf/src/twim.rs171
-rw-r--r--embassy-rp/Cargo.toml5
-rw-r--r--embassy-rp/src/clocks.rs991
-rw-r--r--embassy-rp/src/pio_programs/clock_divider.rs25
-rw-r--r--embassy-rp/src/pio_programs/hd44780.rs11
-rw-r--r--embassy-rp/src/pio_programs/mod.rs1
-rw-r--r--embassy-rp/src/pio_programs/rotary_encoder.rs8
-rw-r--r--embassy-rp/src/pio_programs/stepper.rs17
-rw-r--r--embassy-rp/src/uart/buffered.rs304
-rw-r--r--embassy-rp/src/uart/mod.rs300
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/Cargo.toml7
-rw-r--r--embassy-stm32/build.rs68
-rw-r--r--embassy-stm32/src/flash/asynch.rs7
-rw-r--r--embassy-stm32/src/flash/common.rs11
-rw-r--r--embassy-stm32/src/flash/f0.rs10
-rw-r--r--embassy-stm32/src/flash/f1f3.rs10
-rw-r--r--embassy-stm32/src/flash/f2.rs10
-rw-r--r--embassy-stm32/src/flash/f4.rs337
-rw-r--r--embassy-stm32/src/flash/f7.rs77
-rw-r--r--embassy-stm32/src/flash/g.rs30
-rw-r--r--embassy-stm32/src/flash/h5.rs14
-rw-r--r--embassy-stm32/src/flash/h50.rs10
-rw-r--r--embassy-stm32/src/flash/h7.rs10
-rw-r--r--embassy-stm32/src/flash/l.rs30
-rw-r--r--embassy-stm32/src/flash/mod.rs10
-rw-r--r--embassy-stm32/src/flash/other.rs10
-rw-r--r--embassy-stm32/src/flash/u0.rs10
-rw-r--r--embassy-stm32/src/flash/u5.rs10
-rw-r--r--embassy-stm32/src/lib.rs17
-rw-r--r--embassy-stm32/src/opamp.rs2
-rw-r--r--embassy-stm32/src/rcc/mod.rs31
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs2
-rw-r--r--embassy-stm32/src/usb/otg.rs2
-rw-r--r--embassy-sync/src/signal.rs5
-rw-r--r--embassy-sync/src/watch.rs4
-rw-r--r--embassy-time-driver/Cargo.toml2
-rw-r--r--embassy-time-driver/gen_tick.py1
-rw-r--r--embassy-time-driver/src/tick.rs3
-rw-r--r--embassy-time/Cargo.toml2
-rw-r--r--embassy-usb-dfu/src/application.rs51
-rw-r--r--embassy-usb-dfu/src/dfu.rs14
-rw-r--r--embassy-usb-dfu/src/lib.rs8
-rw-r--r--embassy-usb-driver/Cargo.toml1
-rw-r--r--embassy-usb-driver/src/lib.rs9
-rw-r--r--embassy-usb/Cargo.toml1
-rw-r--r--embassy-usb/src/class/cdc_acm.rs99
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/mimxrt6/Cargo.toml4
-rw-r--r--examples/mimxrt6/build.rs2
-rw-r--r--examples/mimxrt6/src/bin/crc.rs175
-rw-r--r--examples/mimxrt6/src/bin/rng.rs40
-rw-r--r--examples/mimxrt6/src/lib.rs6
-rw-r--r--examples/nrf52840/src/bin/twim.rs4
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs2
-rw-r--r--examples/rp/src/bin/overclock.rs64
-rw-r--r--examples/rp/src/bin/overclock_manual.rs81
-rw-r--r--examples/rp/src/bin/sharing.rs2
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp/src/bin/uart_unidir.rs2
-rw-r--r--examples/rp235x/src/bin/blinky.rs2
-rw-r--r--examples/rp235x/src/bin/blinky_wifi.rs2
-rw-r--r--examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs2
-rw-r--r--examples/rp235x/src/bin/overclock.rs74
-rw-r--r--examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs6
-rw-r--r--examples/rp235x/src/bin/sharing.rs2
-rw-r--r--examples/rp235x/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp235x/src/bin/uart_unidir.rs2
-rw-r--r--examples/stm32f7/Cargo.toml2
-rw-r--r--examples/stm32h7/src/bin/adc_dma.rs2
-rw-r--r--examples/stm32h7/src/bin/sai.rs8
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs2
-rw-r--r--examples/stm32h723/src/bin/spdifrx.rs4
-rw-r--r--examples/stm32h755cm4/src/bin/blinky.rs2
-rw-r--r--examples/stm32h755cm7/src/bin/blinky.rs2
-rw-r--r--examples/stm32l4/Cargo.toml2
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/blinky.rs2
-rw-r--r--examples/stm32wl/src/bin/button.rs2
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs2
-rw-r--r--examples/stm32wl/src/bin/flash.rs2
-rw-r--r--examples/stm32wl/src/bin/random.rs2
-rw-r--r--examples/stm32wl/src/bin/rtc.rs2
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs2
-rw-r--r--tests/rp/src/bin/overclock.rs69
-rw-r--r--tests/rp/src/bin/uart.rs6
-rw-r--r--tests/rp/src/bin/uart_buffered.rs6
-rw-r--r--tests/rp/src/bin/uart_dma.rs6
-rw-r--r--tests/stm32/Cargo.toml8
118 files changed, 3529 insertions, 1525 deletions
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index c78865e54..c9b332cf8 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -29,8 +29,10 @@ cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --feat
29cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test 29cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test
30cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test 30cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test
31 31
32cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti 32cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,time-driver-any,exti,single-bank
33cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti 33cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,time-driver-any,exti,dual-bank
34cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,exti,time-driver-any,exti 34cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,time-driver-any,exti
35cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,time-driver-any,exti,single-bank
36cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,time-driver-any,exti,dual-bank
35 37
36cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml 38cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml
diff --git a/README.md b/README.md
index 383fb6671..669fa469b 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,55 @@
1# Embassy 1# Embassy
2 2
3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. 3Embassy is the next-generation framework for embedded applications. Write safe, correct, and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries.
4
5## [Documentation](https://embassy.dev/book/index.html) - [API reference](https://docs.embassy.dev/) - [Website](https://embassy.dev/) - [Chat](https://matrix.to/#/#embassy-rs:matrix.org)
4 6
5## <a href="https://embassy.dev/book/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a>
6## Rust + async ❤️ embedded 7## Rust + async ❤️ embedded
7 8
8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. 9The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector, or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
9 10
10Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a> 11Rust's [async/await](https://rust-lang.github.io/async-book/) allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is [faster and smaller than one!](https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown)
11 12
12## Batteries included 13## Batteries included
13 14
14- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. 15- **Hardware Abstraction Layers
15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families. 16 ** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. 17 - [embassy-stm32](https://docs.embassy.dev/embassy-stm32/), for all STM32 microcontroller families.
17 - <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 and RP23xx microcontrollers. 18 - [embassy-nrf](https://docs.embassy.dev/embassy-nrf/), for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series.
18 - <a href="https://docs.embassy.dev/embassy-mspm0/">embassy-mspm0</a>, for the Texas Instruments MSPM0 microcontrollers. 19 - [embassy-rp](https://docs.embassy.dev/embassy-rp/), for the Raspberry Pi RP2040 and RP23xx microcontrollers.
19 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips. 20 - [embassy-mspm0](https://docs.embassy.dev/embassy-mspm0/), for the Texas Instruments MSPM0 microcontrollers.
20 - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. 21 - [esp-rs](https://github.com/esp-rs), for the Espressif Systems ESP32 series of chips.
21 - <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips. 22 - Embassy HAL support for Espressif chips, as well as Async Wi-Fi, Bluetooth, and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
22 - <a href="https://github.com/AlexCharlton/mpfs-hal">mpfs-hal</a>, for the Microchip PolarFire SoC. 23 - [ch32-hal](https://github.com/ch32-rs/ch32-hal), for the WCH 32-bit RISC-V(CH32V) series of chips.
23 - <a href="https://github.com/py32-rs/py32-hal">py32-hal</a>, for the Puya Semiconductor PY32 series of microcontrollers. 24 - [mpfs-hal](https://github.com/AlexCharlton/mpfs-hal), for the Microchip PolarFire SoC.
24 25 - [py32-hal](https://github.com/py32-rs/py32-hal), for the Puya Semiconductor PY32 series of microcontrollers.
25- **Time that Just Works** -
26No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow.
27
28- **Real-time ready** -
29Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities, so that higher priority tasks preempt lower priority ones. See the <a href="https://github.com/embassy-rs/embassy/blob/master/examples/nrf52840/src/bin/multiprio.rs">example</a>.
30
31- **Low-power ready** -
32Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting.
33
34- **Networking** -
35The <a href="https://docs.embassy.dev/embassy-net/">embassy-net</a> network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
36 26
37- **Bluetooth** 27- **Time that Just Works** -
38 - The <a href="https://github.com/embassy-rs/trouble">trouble</a> crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the <a href="https://github.com/embassy-rs/bt-hci">bt-hci</a> traits (currently `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported). 28 No more messing with hardware timers. [embassy_time](https://docs.embassy.dev/embassy-time) provides Instant, Duration, and Timer types that are globally available and never overflow.
39 - The <a href="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. 29
40 - The <a href="https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan">embassy-stm32-wpan</a> crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. 30- **Real-time ready** -
31 Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities so that higher priority tasks preempt lower priority ones. See the [example](https://github.com/embassy-rs/embassy/blob/master/examples/nrf52840/src/bin/multiprio.rs).
41 32
42- **LoRa** - The <a href="https://github.com/lora-rs/lora-rs">lora-rs</a> project provides an async LoRa and LoRaWAN stack that works well on Embassy. 33- **Low-power ready** -
34 Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting.
35
36- **Networking** -
37 The [embassy-net](https://docs.embassy.dev/embassy-net/) network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP, and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
38
39- **Bluetooth**
40 - The [trouble](https://github.com/embassy-rs/trouble) crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the [bt-hci](https://github.com/embassy-rs/bt-hci) traits (currently
41 `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported).
42 - The [nrf-softdevice](https://github.com/embassy-rs/nrf-softdevice) crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
43 - The [embassy-stm32-wpan](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan) crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers.
43 44
44- **USB** - 45- **LoRa** -
45<a href="https://docs.embassy.dev/embassy-usb/">embassy-usb</a> implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. 46 The [lora-rs](https://github.com/lora-rs/lora-rs) project provides an async LoRa and LoRaWAN stack that works well on Embassy.
46 47
47- **Bootloader and DFU** - 48- **USB** -
48<a href="https://github.com/embassy-rs/embassy/tree/master/embassy-boot">embassy-boot</a> is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. 49 [embassy-usb](https://docs.embassy.dev/embassy-usb/) implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
49 50
51- **Bootloader and DFU** -
52 [embassy-boot](https://github.com/embassy-rs/embassy/tree/master/embassy-boot) is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
50 53
51## Sneak peek 54## Sneak peek
52 55
@@ -93,13 +96,15 @@ async fn main(spawner: Spawner) {
93 96
94## Examples 97## Examples
95 98
96Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example: 99Examples are found in the
100`examples/` folder separated by the chip manufacturer they are designed to run on. For example:
97 101
98* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. 102* `examples/nrf52840` run on the
99* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). 103 `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards.
100* `examples/stm32xx` for the various STM32 families. 104* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095).
101* `examples/rp` are for the RP2040 chip. 105* `examples/stm32xx` for the various STM32 families.
102* `examples/std` are designed to run locally on your PC. 106* `examples/rp` are for the RP2040 chip.
107* `examples/std` are designed to run locally on your PC.
103 108
104### Running examples 109### Running examples
105 110
@@ -126,7 +131,7 @@ cargo run --release --bin blinky
126 131
127For more help getting started, see [Getting Started][1] and [Running the Examples][2]. 132For more help getting started, see [Getting Started][1] and [Running the Examples][2].
128 133
129## Developing Embassy with Rust Analyzer based editors 134## Developing Embassy with Rust Analyzer-based editors
130 135
131The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/) 136The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/)
132and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer 137and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer
@@ -136,7 +141,7 @@ please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects
136## Minimum supported Rust version (MSRV) 141## Minimum supported Rust version (MSRV)
137 142
138Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might* 143Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might*
139compile with older versions but that may change in any new patch release. 144compile with older versions, but that may change in any new patch release.
140 145
141## Why the name? 146## Why the name?
142 147
diff --git a/ci.sh b/ci.sh
index 5a438f0b1..f2d461c1a 100755
--- a/ci.sh
+++ b/ci.sh
@@ -19,7 +19,7 @@ fi
19TARGET=$(rustc -vV | sed -n 's|host: ||p') 19TARGET=$(rustc -vV | sed -n 's|host: ||p')
20 20
21BUILD_EXTRA="" 21BUILD_EXTRA=""
22if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then 22if [ $TARGET = "x86_64-unknown-linux-gnu" ] || [ $TARGET = "aarch64-unknown-linux-gnu" ]; then
23 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std" 23 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std"
24fi 24fi
25 25
@@ -88,16 +88,17 @@ cargo batch \
88 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \ 88 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \
89 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \ 89 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \
90 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \ 90 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \
91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ 91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ 92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ 93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ 94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ 95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ 96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ 97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ 98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ 99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti \
100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ 100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt \
101 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,single-bank,defmt \
101 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ 102 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \
102 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \ 103 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \
103 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \ 104 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \
@@ -153,10 +154,10 @@ cargo batch \
153 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ 154 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \
154 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ 155 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \
155 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ 156 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
156 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,low-power,time \ 157 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,low-power,time \
157 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \ 158 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \
158 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \ 159 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \
159 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,defmt,exti,time-driver-any,time \ 160 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,dual-bank,defmt,exti,time-driver-any,time \
160 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \ 161 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \
161 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \ 162 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \
162 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ 163 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \
diff --git a/docs/examples/basic/.cargo/config.toml b/docs/examples/basic/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/docs/examples/basic/.cargo/config.toml
+++ b/docs/examples/basic/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/docs/examples/layer-by-layer/.cargo/config.toml b/docs/examples/layer-by-layer/.cargo/config.toml
index 3012f05dc..f30d9e446 100644
--- a/docs/examples/layer-by-layer/.cargo/config.toml
+++ b/docs/examples/layer-by-layer/.cargo/config.toml
@@ -1,5 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip STM32L475VG" 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32L475VG"
3 4
4rustflags = [ 5rustflags = [
5 "-C", "link-arg=--nmagic", 6 "-C", "link-arg=--nmagic",
diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc
index a535e89f8..b21be9a30 100644
--- a/docs/pages/faq.adoc
+++ b/docs/pages/faq.adoc
@@ -268,7 +268,7 @@ General steps:
2681. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet. 2681. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet.
2692. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips. 2692. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips.
2703. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`. 2703. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`.
2714. In your code, access the defined memory region using `#[link_section = ".xxx"]` 2714. In your code, access the defined memory region using `#[unsafe(link_section = ".xxx")]`
2725. Copy data to that region before using BDMA. 2725. Copy data to that region before using BDMA.
273 273
274See link:https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/spi_bdma.rs[SMT32H7 SPI BDMA example] for more details. 274See link:https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/spi_bdma.rs[SMT32H7 SPI BDMA example] for more details.
diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc
index 954f3fd28..d1f65a885 100644
--- a/docs/pages/getting_started.adoc
+++ b/docs/pages/getting_started.adoc
@@ -66,7 +66,7 @@ If everything worked correctly, you should see a blinking LED on your board, and
66[source] 66[source]
67---- 67----
68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s 68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
69 Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky` 69 Running `probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky`
70(HOST) INFO flashing program (71.36 KiB) 70(HOST) INFO flashing program (71.36 KiB)
71(HOST) INFO success! 71(HOST) INFO success!
72──────────────────────────────────────────────────────────────────────────────── 72────────────────────────────────────────────────────────────────────────────────
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc
index adf5218e8..bbd65e494 100644
--- a/docs/pages/imxrt.adoc
+++ b/docs/pages/imxrt.adoc
@@ -9,5 +9,6 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb
9 9
10The following peripherals have a HAL implementation at present 10The following peripherals have a HAL implementation at present
11 11
12* CRC
12* GPIO 13* GPIO
13 14* RNG
diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc
index af1cb75c5..cd943b4f6 100644
--- a/docs/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -150,7 +150,7 @@ stm32g474-example
150# Before upgrading check that everything is available on all tier1 targets here: 150# Before upgrading check that everything is available on all tier1 targets here:
151# https://rust-lang.github.io/rustup-components-history 151# https://rust-lang.github.io/rustup-components-history
152[toolchain] 152[toolchain]
153channel = "nightly-2023-11-01" 153channel = "1.85"
154components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 154components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
155targets = ["thumbv7em-none-eabi"] 155targets = ["thumbv7em-none-eabi"]
156---- 156----
diff --git a/docs/pages/project_structure.adoc b/docs/pages/project_structure.adoc
index 722ec8d9d..227508b97 100644
--- a/docs/pages/project_structure.adoc
+++ b/docs/pages/project_structure.adoc
@@ -85,9 +85,9 @@ A minimal example:
85[source,toml] 85[source,toml]
86---- 86----
87[toolchain] 87[toolchain]
88channel = "nightly-2023-08-19" # <- as of writing, this is the exact rust version embassy uses 88channel = "1.85" # <- as of writing, this is the exact rust version embassy uses
89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size" 89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size"
90targets = [ 90targets = [
91 "thumbv6m-none-eabi" # <-change for your platform 91 "thumbv6m-none-eabi" # <- change for your platform
92] 92]
93---- 93----
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index d58de6353..f16002a8d 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -12,7 +12,7 @@ documentation = "https://docs.embassy.dev/embassy-imxrt"
12[package.metadata.embassy_docs] 12[package.metadata.embassy_docs]
13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" 13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" 14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
15features = ["defmt", "unstable-pac", "time", "time-driver"] 15features = ["defmt", "unstable-pac", "time", "time-driver-os-timer"]
16flavors = [ 16flavors = [
17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } 17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
18] 18]
@@ -37,9 +37,12 @@ defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxr
37time = ["dep:embassy-time", "embassy-embedded-hal/time"] 37time = ["dep:embassy-time", "embassy-embedded-hal/time"]
38 38
39## Enable custom embassy time-driver implementation, using 32KHz RTC 39## Enable custom embassy time-driver implementation, using 32KHz RTC
40time-driver-rtc = ["_time-driver"] 40time-driver-rtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000"]
41 41
42_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] 42## Enable custom embassy time-driver implementation, using 1MHz OS Timer
43time-driver-os-timer = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"]
44
45_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
43 46
44## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) 47## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
45unstable-pac = [] 48unstable-pac = []
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs
index 1d36fb142..39c3e6238 100644
--- a/embassy-imxrt/src/clocks.rs
+++ b/embassy-imxrt/src/clocks.rs
@@ -1,8 +1,6 @@
1//! Clock configuration for the `RT6xx` 1//! Clock configuration for the `RT6xx`
2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering};
3 3
4#[cfg(feature = "defmt")]
5use defmt;
6use paste::paste; 4use paste::paste;
7 5
8use crate::pac; 6use crate::pac;
@@ -503,7 +501,6 @@ impl ConfigurableClock for LposcConfig {
503 } 501 }
504 } 502 }
505 } else { 503 } else {
506 error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq);
507 Err(ClockError::InvalidFrequency) 504 Err(ClockError::InvalidFrequency)
508 } 505 }
509 } 506 }
@@ -549,7 +546,6 @@ impl ConfigurableClock for FfroConfig {
549 Ok(()) 546 Ok(())
550 } 547 }
551 fn get_clock_rate(&self) -> Result<u32, ClockError> { 548 fn get_clock_rate(&self) -> Result<u32, ClockError> {
552 trace!("getting ffro clock rate");
553 Ok(self.freq.load(Ordering::Relaxed)) 549 Ok(self.freq.load(Ordering::Relaxed))
554 } 550 }
555 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 551 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -616,7 +612,6 @@ impl ConfigurableClock for SfroConfig {
616 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 612 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
617 if self.state == State::Enabled { 613 if self.state == State::Enabled {
618 if freq == SFRO_FREQ { 614 if freq == SFRO_FREQ {
619 trace!("Sfro frequency is already set at 16MHz");
620 Ok(()) 615 Ok(())
621 } else { 616 } else {
622 Err(ClockError::InvalidFrequency) 617 Err(ClockError::InvalidFrequency)
@@ -677,7 +672,6 @@ impl MultiSourceClock for MainPllClkConfig {
677 } 672 }
678 MainPllClkSrc::SFRO => { 673 MainPllClkSrc::SFRO => {
679 if !clock_src_config.is_enabled() { 674 if !clock_src_config.is_enabled() {
680 error!("Can't set SFRO as source for MainPll as it's not enabled");
681 return Err(ClockError::ClockNotEnabled); 675 return Err(ClockError::ClockNotEnabled);
682 } 676 }
683 // check if desired frequency is a valid multiple of 16m SFRO clock 677 // check if desired frequency is a valid multiple of 16m SFRO clock
@@ -703,7 +697,6 @@ impl ConfigurableClock for MainPllClkConfig {
703 } 697 }
704 fn disable(&self) -> Result<(), ClockError> { 698 fn disable(&self) -> Result<(), ClockError> {
705 if self.is_enabled() { 699 if self.is_enabled() {
706 error!("Attempting to reset the Main Pll Clock, should be resetting its source");
707 Err(ClockError::ClockNotSupported) 700 Err(ClockError::ClockNotSupported)
708 } else { 701 } else {
709 Err(ClockError::ClockNotEnabled) 702 Err(ClockError::ClockNotEnabled)
@@ -719,7 +712,6 @@ impl ConfigurableClock for MainPllClkConfig {
719 } 712 }
720 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> { 713 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> {
721 if self.is_enabled() { 714 if self.is_enabled() {
722 trace!("attempting to set main pll clock rate");
723 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 715 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
724 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; 716 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
725 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; 717 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
@@ -741,15 +733,12 @@ impl ConfigurableClock for MainPllClkConfig {
741 base_rate = r; 733 base_rate = r;
742 } 734 }
743 MainPllClkSrc::FFRO => { 735 MainPllClkSrc::FFRO => {
744 trace!("found FFRO as source, wait a bit");
745 delay_loop_clocks(1000, desired_freq); 736 delay_loop_clocks(1000, desired_freq);
746 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() { 737 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() {
747 true => base_rate = Into::into(FfroFreq::Ffro48m), 738 true => base_rate = Into::into(FfroFreq::Ffro48m),
748 false => base_rate = Into::into(FfroFreq::Ffro60m), 739 false => base_rate = Into::into(FfroFreq::Ffro60m),
749 } 740 }
750 trace!("found ffro rate to be: {:#}", base_rate);
751 if div == 2 { 741 if div == 2 {
752 trace!("dividing FFRO rate by 2");
753 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); 742 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
754 delay_loop_clocks(150, desired_freq); 743 delay_loop_clocks(150, desired_freq);
755 base_rate /= 2; 744 base_rate /= 2;
@@ -763,10 +752,8 @@ impl ConfigurableClock for MainPllClkConfig {
763 } 752 }
764 }; 753 };
765 base_rate *= u32::from(mult); 754 base_rate *= u32::from(mult);
766 trace!("calculated base rate at: {:#}", base_rate);
767 if base_rate != freq { 755 if base_rate != freq {
768 // make sure to power syspll back up before returning the error 756 // make sure to power syspll back up before returning the error
769 error!("invalid frequency found, powering syspll back up before returning error. Check div and mult");
770 // Clear System PLL reset 757 // Clear System PLL reset
771 clkctl0.syspll0ctl0().write(|w| w.reset().normal()); 758 clkctl0.syspll0ctl0().write(|w| w.reset().normal());
772 // Power up SYSPLL 759 // Power up SYSPLL
@@ -775,13 +762,11 @@ impl ConfigurableClock for MainPllClkConfig {
775 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); 762 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
776 return Err(ClockError::InvalidFrequency); 763 return Err(ClockError::InvalidFrequency);
777 } 764 }
778 trace!("setting default num and denom");
779 // SAFETY: unsafe needed to write the bits for the num and demon fields 765 // SAFETY: unsafe needed to write the bits for the num and demon fields
780 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) }); 766 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) });
781 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) }); 767 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) });
782 delay_loop_clocks(30, desired_freq); 768 delay_loop_clocks(30, desired_freq);
783 self.mult.store(mult, Ordering::Relaxed); 769 self.mult.store(mult, Ordering::Relaxed);
784 trace!("setting self.mult as: {:#}", mult);
785 match mult { 770 match mult {
786 16 => { 771 16 => {
787 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16()); 772 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16());
@@ -803,7 +788,6 @@ impl ConfigurableClock for MainPllClkConfig {
803 } 788 }
804 _ => return Err(ClockError::InvalidMult), 789 _ => return Err(ClockError::InvalidMult),
805 } 790 }
806 trace!("clear syspll reset");
807 // Clear System PLL reset 791 // Clear System PLL reset
808 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal()); 792 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal());
809 // Power up SYSPLL 793 // Power up SYSPLL
@@ -819,7 +803,6 @@ impl ConfigurableClock for MainPllClkConfig {
819 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); 803 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
820 delay_loop_clocks(15, desired_freq); 804 delay_loop_clocks(15, desired_freq);
821 805
822 trace!("setting new PFD0 bits");
823 // gate the output and clear bits. 806 // gate the output and clear bits.
824 // SAFETY: unsafe needed to write the bits for pfd0 807 // SAFETY: unsafe needed to write the bits for pfd0
825 clkctl0 808 clkctl0
@@ -833,7 +816,6 @@ impl ConfigurableClock for MainPllClkConfig {
833 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) }); 816 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) });
834 // wait for ready bit to be set 817 // wait for ready bit to be set
835 delay_loop_clocks(50, desired_freq); 818 delay_loop_clocks(50, desired_freq);
836 trace!("waiting for mainpll clock to be ready");
837 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} 819 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
838 // clear by writing a 1 820 // clear by writing a 1
839 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit()); 821 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit());
@@ -854,11 +836,9 @@ impl ConfigurableClock for MainPllClkConfig {
854impl MainPllClkConfig { 836impl MainPllClkConfig {
855 /// Calculate the mult value of a desired frequency, return error if invalid 837 /// Calculate the mult value of a desired frequency, return error if invalid
856 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> { 838 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> {
857 trace!("calculating mult for {:#} / {:#}", rate, base_freq);
858 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33]; 839 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33];
859 if rate > base_freq && rate % base_freq == 0 { 840 if rate > base_freq && rate % base_freq == 0 {
860 let mult = (rate / base_freq) as u8; 841 let mult = (rate / base_freq) as u8;
861 trace!("verifying that calculated mult {:#} is a valid one", mult);
862 if VALIDMULTS.into_iter().any(|i| i == mult) { 842 if VALIDMULTS.into_iter().any(|i| i == mult) {
863 Ok(mult) 843 Ok(mult)
864 } else { 844 } else {
@@ -1112,7 +1092,6 @@ impl ConfigurableClock for MainClkConfig {
1112 Ok(()) 1092 Ok(())
1113 } 1093 }
1114 fn disable(&self) -> Result<(), ClockError> { 1094 fn disable(&self) -> Result<(), ClockError> {
1115 error!("Attempting to reset the main clock, should NOT happen during runtime");
1116 Err(ClockError::ClockNotSupported) 1095 Err(ClockError::ClockNotSupported)
1117 } 1096 }
1118 fn get_clock_rate(&self) -> Result<u32, ClockError> { 1097 fn get_clock_rate(&self) -> Result<u32, ClockError> {
@@ -1120,7 +1099,6 @@ impl ConfigurableClock for MainClkConfig {
1120 Ok(rate) 1099 Ok(rate)
1121 } 1100 }
1122 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { 1101 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1123 error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate");
1124 Err(ClockError::ClockNotSupported) 1102 Err(ClockError::ClockNotSupported)
1125 } 1103 }
1126 fn is_enabled(&self) -> bool { 1104 fn is_enabled(&self) -> bool {
@@ -1145,7 +1123,6 @@ impl ConfigurableClock for ClkInConfig {
1145 } 1123 }
1146 } 1124 }
1147 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 1125 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1148 trace!("Setting value of clk in config, this won't change the clock itself");
1149 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed); 1126 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed);
1150 Ok(()) 1127 Ok(())
1151 } 1128 }
@@ -1188,7 +1165,6 @@ impl ConfigurableClock for RtcClkConfig {
1188 Ok(()) 1165 Ok(())
1189 } 1166 }
1190 fn disable(&self) -> Result<(), ClockError> { 1167 fn disable(&self) -> Result<(), ClockError> {
1191 error!("Resetting the RTC clock, this should NOT happen during runtime");
1192 Err(ClockError::ClockNotSupported) 1168 Err(ClockError::ClockNotSupported)
1193 } 1169 }
1194 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 1170 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -1199,7 +1175,6 @@ impl ConfigurableClock for RtcClkConfig {
1199 match r { 1175 match r {
1200 RtcFreq::Default1Hz => { 1176 RtcFreq::Default1Hz => {
1201 if rtc.ctrl().read().rtc_en().is_enable() { 1177 if rtc.ctrl().read().rtc_en().is_enable() {
1202 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1203 } else { 1178 } else {
1204 rtc.ctrl().modify(|_r, w| w.rtc_en().enable()); 1179 rtc.ctrl().modify(|_r, w| w.rtc_en().enable());
1205 } 1180 }
@@ -1207,7 +1182,6 @@ impl ConfigurableClock for RtcClkConfig {
1207 } 1182 }
1208 RtcFreq::HighResolution1khz => { 1183 RtcFreq::HighResolution1khz => {
1209 if rtc.ctrl().read().rtc1khz_en().is_enable() { 1184 if rtc.ctrl().read().rtc1khz_en().is_enable() {
1210 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1211 } else { 1185 } else {
1212 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable()); 1186 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable());
1213 } 1187 }
@@ -1215,7 +1189,6 @@ impl ConfigurableClock for RtcClkConfig {
1215 } 1189 }
1216 RtcFreq::SubSecond32kHz => { 1190 RtcFreq::SubSecond32kHz => {
1217 if rtc.ctrl().read().rtc_subsec_ena().is_enable() { 1191 if rtc.ctrl().read().rtc_subsec_ena().is_enable() {
1218 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1219 } else { 1192 } else {
1220 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable()); 1193 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable());
1221 } 1194 }
@@ -1245,18 +1218,12 @@ impl ConfigurableClock for RtcClkConfig {
1245 1218
1246impl SysClkConfig { 1219impl SysClkConfig {
1247 /// Updates the system core clock frequency, SW concept used for systick 1220 /// Updates the system core clock frequency, SW concept used for systick
1248 fn update_sys_core_clock(&self) { 1221 fn update_sys_core_clock(&self) {}
1249 trace!(
1250 "System core clock has been updated to {:?}, this involves no HW reg writes",
1251 self.sysclkfreq.load(Ordering::Relaxed)
1252 );
1253 }
1254} 1222}
1255 1223
1256impl ConfigurableClock for SysOscConfig { 1224impl ConfigurableClock for SysOscConfig {
1257 fn enable_and_reset(&self) -> Result<(), ClockError> { 1225 fn enable_and_reset(&self) -> Result<(), ClockError> {
1258 if self.state == State::Enabled { 1226 if self.state == State::Enabled {
1259 trace!("SysOsc was already enabled");
1260 return Ok(()); 1227 return Ok(());
1261 } 1228 }
1262 1229
@@ -1498,32 +1465,26 @@ impl ClockOutConfig {
1498/// Using the config, enables all desired clocks to desired clock rates 1465/// Using the config, enables all desired clocks to desired clock rates
1499fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { 1466fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1500 if let Err(e) = config.rtc.enable_and_reset() { 1467 if let Err(e) = config.rtc.enable_and_reset() {
1501 error!("couldn't Power on OSC for RTC, result: {:?}", e);
1502 return Err(e); 1468 return Err(e);
1503 } 1469 }
1504 1470
1505 if let Err(e) = config.lposc.enable_and_reset() { 1471 if let Err(e) = config.lposc.enable_and_reset() {
1506 error!("couldn't Power on LPOSC, result: {:?}", e);
1507 return Err(e); 1472 return Err(e);
1508 } 1473 }
1509 1474
1510 if let Err(e) = config.ffro.enable_and_reset() { 1475 if let Err(e) = config.ffro.enable_and_reset() {
1511 error!("couldn't Power on FFRO, result: {:?}", e);
1512 return Err(e); 1476 return Err(e);
1513 } 1477 }
1514 1478
1515 if let Err(e) = config.sfro.enable_and_reset() { 1479 if let Err(e) = config.sfro.enable_and_reset() {
1516 error!("couldn't Power on SFRO, result: {:?}", e);
1517 return Err(e); 1480 return Err(e);
1518 } 1481 }
1519 1482
1520 if let Err(e) = config.sys_osc.enable_and_reset() { 1483 if let Err(e) = config.sys_osc.enable_and_reset() {
1521 error!("Couldn't enable sys oscillator {:?}", e);
1522 return Err(e); 1484 return Err(e);
1523 } 1485 }
1524 1486
1525 if let Err(e) = config.main_pll_clk.enable_and_reset() { 1487 if let Err(e) = config.main_pll_clk.enable_and_reset() {
1526 error!("Couldn't enable main pll clock {:?}", e);
1527 return Err(e); 1488 return Err(e);
1528 } 1489 }
1529 1490
@@ -1542,7 +1503,6 @@ fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1542 init_syscpuahb_clk(); 1503 init_syscpuahb_clk();
1543 1504
1544 if let Err(e) = config.main_clk.enable_and_reset() { 1505 if let Err(e) = config.main_clk.enable_and_reset() {
1545 error!("Couldn't enable main clock {:?}", e);
1546 return Err(e); 1506 return Err(e);
1547 } 1507 }
1548 1508
@@ -1561,7 +1521,8 @@ pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> {
1561 1521
1562///Trait to expose perph clocks 1522///Trait to expose perph clocks
1563trait SealedSysconPeripheral { 1523trait SealedSysconPeripheral {
1564 fn enable_and_reset_perph_clock(); 1524 fn enable_perph_clock();
1525 fn reset_perph();
1565 fn disable_perph_clock(); 1526 fn disable_perph_clock();
1566} 1527}
1567 1528
@@ -1574,7 +1535,18 @@ pub trait SysconPeripheral: SealedSysconPeripheral + 'static {}
1574/// 1535///
1575/// Peripheral must not be in use. 1536/// Peripheral must not be in use.
1576pub fn enable_and_reset<T: SysconPeripheral>() { 1537pub fn enable_and_reset<T: SysconPeripheral>() {
1577 T::enable_and_reset_perph_clock(); 1538 T::enable_perph_clock();
1539 T::reset_perph();
1540}
1541
1542/// Enables peripheral `T`.
1543pub fn enable<T: SysconPeripheral>() {
1544 T::enable_perph_clock();
1545}
1546
1547/// Reset peripheral `T`.
1548pub fn reset<T: SysconPeripheral>() {
1549 T::reset_perph();
1578} 1550}
1579 1551
1580/// Disables peripheral `T`. 1552/// Disables peripheral `T`.
@@ -1588,15 +1560,21 @@ pub fn disable<T: SysconPeripheral>() {
1588macro_rules! impl_perph_clk { 1560macro_rules! impl_perph_clk {
1589 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => { 1561 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => {
1590 impl SealedSysconPeripheral for crate::peripherals::$peripheral { 1562 impl SealedSysconPeripheral for crate::peripherals::$peripheral {
1591 fn enable_and_reset_perph_clock() { 1563 fn enable_perph_clock() {
1592 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 1564 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1593 let cc1 = unsafe { pac::$clkctl::steal() }; 1565 let cc1 = unsafe { pac::$clkctl::steal() };
1594 let rc1 = unsafe { pac::$rstctl::steal() };
1595 1566
1596 paste! { 1567 paste! {
1597 // SAFETY: unsafe due to the use of bits() 1568 // SAFETY: unsafe due to the use of bits()
1598 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); 1569 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1570 }
1571 }
1599 1572
1573 fn reset_perph() {
1574 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1575 let rc1 = unsafe { pac::$rstctl::steal() };
1576
1577 paste! {
1600 // SAFETY: unsafe due to the use of bits() 1578 // SAFETY: unsafe due to the use of bits()
1601 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); 1579 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1602 } 1580 }
@@ -1605,13 +1583,9 @@ macro_rules! impl_perph_clk {
1605 fn disable_perph_clock() { 1583 fn disable_perph_clock() {
1606 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 1584 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1607 let cc1 = unsafe { pac::$clkctl::steal() }; 1585 let cc1 = unsafe { pac::$clkctl::steal() };
1608 let rc1 = unsafe { pac::$rstctl::steal() };
1609 1586
1610 paste! { 1587 paste! {
1611 // SAFETY: unsafe due to the use of bits() 1588 // SAFETY: unsafe due to the use of bits()
1612 rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1613
1614 // SAFETY: unsafe due to the use of bits()
1615 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); 1589 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1616 } 1590 }
1617 } 1591 }
diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs
new file mode 100644
index 000000000..24d6ba5bd
--- /dev/null
+++ b/embassy-imxrt/src/crc.rs
@@ -0,0 +1,190 @@
1//! Cyclic Redundancy Check (CRC)
2
3use core::marker::PhantomData;
4
5use crate::clocks::{enable_and_reset, SysconPeripheral};
6pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial;
7use crate::{peripherals, Peri, PeripheralType};
8
9/// CRC driver.
10pub struct Crc<'d> {
11 info: Info,
12 _config: Config,
13 _lifetime: PhantomData<&'d ()>,
14}
15
16/// CRC configuration
17pub struct Config {
18 /// Polynomial to be used
19 pub polynomial: Polynomial,
20
21 /// Reverse bit order of input?
22 pub reverse_in: bool,
23
24 /// 1's complement input?
25 pub complement_in: bool,
26
27 /// Reverse CRC bit order?
28 pub reverse_out: bool,
29
30 /// 1's complement CRC?
31 pub complement_out: bool,
32
33 /// CRC Seed
34 pub seed: u32,
35}
36
37impl Config {
38 /// Create a new CRC config.
39 #[must_use]
40 pub fn new(
41 polynomial: Polynomial,
42 reverse_in: bool,
43 complement_in: bool,
44 reverse_out: bool,
45 complement_out: bool,
46 seed: u32,
47 ) -> Self {
48 Config {
49 polynomial,
50 reverse_in,
51 complement_in,
52 reverse_out,
53 complement_out,
54 seed,
55 }
56 }
57}
58
59impl Default for Config {
60 fn default() -> Self {
61 Self {
62 polynomial: Polynomial::CrcCcitt,
63 reverse_in: false,
64 complement_in: false,
65 reverse_out: false,
66 complement_out: false,
67 seed: 0xffff,
68 }
69 }
70}
71
72impl<'d> Crc<'d> {
73 /// Instantiates new CRC peripheral and initializes to default values.
74 pub fn new<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self {
75 // enable CRC clock
76 enable_and_reset::<T>();
77
78 let mut instance = Self {
79 info: T::info(),
80 _config: config,
81 _lifetime: PhantomData,
82 };
83
84 instance.reconfigure();
85 instance
86 }
87
88 /// Reconfigured the CRC peripheral.
89 fn reconfigure(&mut self) {
90 self.info.regs.mode().write(|w| {
91 w.crc_poly()
92 .variant(self._config.polynomial)
93 .bit_rvs_wr()
94 .variant(self._config.reverse_in)
95 .cmpl_wr()
96 .variant(self._config.complement_in)
97 .bit_rvs_sum()
98 .variant(self._config.reverse_out)
99 .cmpl_sum()
100 .variant(self._config.complement_out)
101 });
102
103 // Init CRC value
104 self.info
105 .regs
106 .seed()
107 .write(|w| unsafe { w.crc_seed().bits(self._config.seed) });
108 }
109
110 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
111 pub fn feed_byte(&mut self, byte: u8) -> u32 {
112 self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) });
113
114 self.info.regs.sum().read().bits()
115 }
116
117 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
118 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
119 let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() };
120
121 for b in prefix {
122 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
123 }
124
125 for d in data {
126 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) });
127 }
128
129 for b in suffix {
130 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
131 }
132
133 self.info.regs.sum().read().bits()
134 }
135
136 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
137 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
138 self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) });
139
140 self.info.regs.sum().read().bits()
141 }
142
143 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
144 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
145 for halfword in halfwords {
146 self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) });
147 }
148
149 self.info.regs.sum().read().bits()
150 }
151
152 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
153 pub fn feed_word(&mut self, word: u32) -> u32 {
154 self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) });
155
156 self.info.regs.sum().read().bits()
157 }
158
159 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
160 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
161 for word in words {
162 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) });
163 }
164
165 self.info.regs.sum().read().bits()
166 }
167}
168
169struct Info {
170 regs: crate::pac::CrcEngine,
171}
172
173trait SealedInstance {
174 fn info() -> Info;
175}
176
177/// CRC instance trait.
178#[allow(private_bounds)]
179pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {}
180
181impl Instance for peripherals::CRC {}
182
183impl SealedInstance for peripherals::CRC {
184 fn info() -> Info {
185 // SAFETY: safe from single executor
186 Info {
187 regs: unsafe { crate::pac::CrcEngine::steal() },
188 }
189 }
190}
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index 5fbf3244b..b1183d8fc 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -18,11 +18,13 @@ compile_error!(
18pub(crate) mod fmt; 18pub(crate) mod fmt;
19 19
20pub mod clocks; 20pub mod clocks;
21pub mod crc;
21pub mod gpio; 22pub mod gpio;
22pub mod iopctl; 23pub mod iopctl;
24pub mod rng;
23 25
24#[cfg(feature = "_time-driver")] 26#[cfg(feature = "_time-driver")]
25pub mod rtc; 27pub mod time_driver;
26 28
27// This mod MUST go last, so that it sees all the `impl_foo!' macros 29// This mod MUST go last, so that it sees all the `impl_foo!' macros
28#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] 30#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")]
@@ -132,12 +134,10 @@ pub fn init(config: config::Config) -> Peripherals {
132 error!("unable to initialize Clocks for reason: {:?}", e); 134 error!("unable to initialize Clocks for reason: {:?}", e);
133 // Panic here? 135 // Panic here?
134 } 136 }
135 gpio::init();
136 } 137 }
137
138 // init RTC time driver
139 #[cfg(feature = "_time-driver")] 138 #[cfg(feature = "_time-driver")]
140 rtc::init(config.time_interrupt_priority); 139 time_driver::init(config.time_interrupt_priority);
140 gpio::init();
141 141
142 peripherals 142 peripherals
143} 143}
diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs
new file mode 100644
index 000000000..67e7ab65d
--- /dev/null
+++ b/embassy-imxrt/src/rng.rs
@@ -0,0 +1,257 @@
1//! True Random Number Generator (TRNG)
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy_futures::block_on;
8use embassy_sync::waitqueue::AtomicWaker;
9use rand_core::{CryptoRng, RngCore};
10
11use crate::clocks::{enable_and_reset, SysconPeripheral};
12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, peripherals, Peri, PeripheralType};
14
15static RNG_WAKER: AtomicWaker = AtomicWaker::new();
16
17/// RNG ;error
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error {
21 /// Seed error.
22 SeedError,
23
24 /// HW Error.
25 HwError,
26
27 /// Frequency Count Fail
28 FreqCountFail,
29}
30
31/// RNG interrupt handler.
32pub struct InterruptHandler<T: Instance> {
33 _phantom: PhantomData<T>,
34}
35
36impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
37 unsafe fn on_interrupt() {
38 let regs = T::info().regs;
39 let int_status = regs.int_status().read();
40
41 if int_status.ent_val().bit_is_set()
42 || int_status.hw_err().bit_is_set()
43 || int_status.frq_ct_fail().bit_is_set()
44 {
45 regs.int_ctrl().modify(|_, w| {
46 w.ent_val()
47 .ent_val_0()
48 .hw_err()
49 .hw_err_0()
50 .frq_ct_fail()
51 .frq_ct_fail_0()
52 });
53 RNG_WAKER.wake();
54 }
55 }
56}
57
58/// RNG driver.
59pub struct Rng<'d> {
60 info: Info,
61 _lifetime: PhantomData<&'d ()>,
62}
63
64impl<'d> Rng<'d> {
65 /// Create a new RNG driver.
66 pub fn new<T: Instance>(
67 _inner: Peri<'d, T>,
68 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
69 ) -> Self {
70 enable_and_reset::<T>();
71
72 let mut random = Self {
73 info: T::info(),
74 _lifetime: PhantomData,
75 };
76 random.init();
77
78 T::Interrupt::unpend();
79 unsafe { T::Interrupt::enable() };
80
81 random
82 }
83
84 /// Reset the RNG.
85 pub fn reset(&mut self) {
86 self.info.regs.mctl().write(|w| w.rst_def().set_bit().prgm().set_bit());
87 }
88
89 /// Fill the given slice with random values.
90 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
91 // We have a total of 16 words (512 bits) of entropy at our
92 // disposal. The idea here is to read all bits and copy the
93 // necessary bytes to the slice.
94 for chunk in dest.chunks_mut(64) {
95 self.async_fill_chunk(chunk).await?;
96 }
97
98 Ok(())
99 }
100
101 async fn async_fill_chunk(&mut self, chunk: &mut [u8]) -> Result<(), Error> {
102 // wait for interrupt
103 let res = poll_fn(|cx| {
104 // Check if already ready.
105 // TODO: Is this necessary? Could we just check once after
106 // the waker has been registered?
107 if self.info.regs.int_status().read().ent_val().bit_is_set() {
108 return Poll::Ready(Ok(()));
109 }
110
111 RNG_WAKER.register(cx.waker());
112
113 self.unmask_interrupts();
114
115 let mctl = self.info.regs.mctl().read();
116
117 // Check again if interrupt fired
118 if mctl.ent_val().bit_is_set() {
119 Poll::Ready(Ok(()))
120 } else if mctl.err().bit_is_set() {
121 Poll::Ready(Err(Error::HwError))
122 } else if mctl.fct_fail().bit_is_set() {
123 Poll::Ready(Err(Error::FreqCountFail))
124 } else {
125 Poll::Pending
126 }
127 })
128 .await;
129
130 let bits = self.info.regs.mctl().read();
131
132 if bits.ent_val().bit_is_set() {
133 let mut entropy = [0; 16];
134
135 for (i, item) in entropy.iter_mut().enumerate() {
136 *item = self.info.regs.ent(i).read().bits();
137 }
138
139 // Read MCTL after reading ENT15
140 let _ = self.info.regs.mctl().read();
141
142 if entropy.iter().any(|e| *e == 0) {
143 return Err(Error::SeedError);
144 }
145
146 // SAFETY: entropy is the same for input and output types in
147 // native endianness.
148 let entropy: [u8; 64] = unsafe { core::mem::transmute(entropy) };
149
150 // write bytes to chunk
151 chunk.copy_from_slice(&entropy[..chunk.len()]);
152 }
153
154 res
155 }
156
157 fn mask_interrupts(&mut self) {
158 self.info.regs.int_mask().write(|w| {
159 w.ent_val()
160 .ent_val_0()
161 .hw_err()
162 .hw_err_0()
163 .frq_ct_fail()
164 .frq_ct_fail_0()
165 });
166 }
167
168 fn unmask_interrupts(&mut self) {
169 self.info.regs.int_mask().modify(|_, w| {
170 w.ent_val()
171 .ent_val_1()
172 .hw_err()
173 .hw_err_1()
174 .frq_ct_fail()
175 .frq_ct_fail_1()
176 });
177 }
178
179 fn enable_interrupts(&mut self) {
180 self.info.regs.int_ctrl().write(|w| {
181 w.ent_val()
182 .ent_val_1()
183 .hw_err()
184 .hw_err_1()
185 .frq_ct_fail()
186 .frq_ct_fail_1()
187 });
188 }
189
190 fn init(&mut self) {
191 self.mask_interrupts();
192
193 // Switch TRNG to programming mode
194 self.info.regs.mctl().modify(|_, w| w.prgm().set_bit());
195
196 self.enable_interrupts();
197
198 // Switch TRNG to Run Mode
199 self.info
200 .regs
201 .mctl()
202 .modify(|_, w| w.trng_acc().set_bit().prgm().clear_bit());
203 }
204}
205
206impl RngCore for Rng<'_> {
207 fn next_u32(&mut self) -> u32 {
208 let mut bytes = [0u8; 4];
209 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
210 u32::from_ne_bytes(bytes)
211 }
212
213 fn next_u64(&mut self) -> u64 {
214 let mut bytes = [0u8; 8];
215 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
216 u64::from_ne_bytes(bytes)
217 }
218
219 fn fill_bytes(&mut self, dest: &mut [u8]) {
220 block_on(self.async_fill_bytes(dest)).unwrap();
221 }
222
223 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
224 self.fill_bytes(dest);
225 Ok(())
226 }
227}
228
229impl CryptoRng for Rng<'_> {}
230
231struct Info {
232 regs: crate::pac::Trng,
233}
234
235trait SealedInstance {
236 fn info() -> Info;
237}
238
239/// RNG instance trait.
240#[allow(private_bounds)]
241pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {
242 /// Interrupt for this RNG instance.
243 type Interrupt: interrupt::typelevel::Interrupt;
244}
245
246impl Instance for peripherals::RNG {
247 type Interrupt = crate::interrupt::typelevel::RNG;
248}
249
250impl SealedInstance for peripherals::RNG {
251 fn info() -> Info {
252 // SAFETY: safe from single executor
253 Info {
254 regs: unsafe { crate::pac::Trng::steal() },
255 }
256 }
257}
diff --git a/embassy-imxrt/src/rtc.rs b/embassy-imxrt/src/time_driver.rs
index 56a8f7397..c68679d3e 100644
--- a/embassy-imxrt/src/rtc.rs
+++ b/embassy-imxrt/src/time_driver.rs
@@ -1,5 +1,6 @@
1//! RTC Time Driver. 1//! Time Driver.
2use core::cell::{Cell, RefCell}; 2use core::cell::{Cell, RefCell};
3#[cfg(feature = "time-driver-rtc")]
3use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
4 5
5use critical_section::CriticalSection; 6use critical_section::CriticalSection;
@@ -8,9 +9,26 @@ use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::Driver; 9use embassy_time_driver::Driver;
9use embassy_time_queue_utils::Queue; 10use embassy_time_queue_utils::Queue;
10 11
12#[cfg(feature = "time-driver-os-timer")]
13use crate::clocks::enable;
11use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
12use crate::{interrupt, pac}; 15use crate::{interrupt, pac};
13 16
17struct AlarmState {
18 timestamp: Cell<u64>,
19}
20
21unsafe impl Send for AlarmState {}
22
23impl AlarmState {
24 const fn new() -> Self {
25 Self {
26 timestamp: Cell::new(u64::MAX),
27 }
28 }
29}
30
31#[cfg(feature = "time-driver-rtc")]
14fn rtc() -> &'static pac::rtc::RegisterBlock { 32fn rtc() -> &'static pac::rtc::RegisterBlock {
15 unsafe { &*pac::Rtc::ptr() } 33 unsafe { &*pac::Rtc::ptr() }
16} 34}
@@ -25,24 +43,19 @@ fn rtc() -> &'static pac::rtc::RegisterBlock {
25/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, 43/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels,
26/// so using a 32 bit GPREG0-2 as counter, compare, and int_en 44/// so using a 32 bit GPREG0-2 as counter, compare, and int_en
27/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection 45/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection
46#[cfg(feature = "time-driver-rtc")]
28fn calc_now(period: u32, counter: u32) -> u64 { 47fn calc_now(period: u32, counter: u32) -> u64 {
29 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) 48 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64)
30} 49}
31 50
32struct AlarmState { 51#[cfg(feature = "time-driver-rtc")]
33 timestamp: Cell<u64>, 52embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc {
34} 53 period: AtomicU32::new(0),
35 54 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
36unsafe impl Send for AlarmState {} 55 queue: Mutex::new(RefCell::new(Queue::new())),
37 56});
38impl AlarmState {
39 const fn new() -> Self {
40 Self {
41 timestamp: Cell::new(u64::MAX),
42 }
43 }
44}
45 57
58#[cfg(feature = "time-driver-rtc")]
46struct Rtc { 59struct Rtc {
47 /// Number of 2^31 periods elapsed since boot. 60 /// Number of 2^31 periods elapsed since boot.
48 period: AtomicU32, 61 period: AtomicU32,
@@ -51,12 +64,7 @@ struct Rtc {
51 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 64 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
52} 65}
53 66
54embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { 67#[cfg(feature = "time-driver-rtc")]
55 period: AtomicU32::new(0),
56 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
57 queue: Mutex::new(RefCell::new(Queue::new())),
58});
59
60impl Rtc { 68impl Rtc {
61 /// Access the GPREG0 register to use it as a 31-bit counter. 69 /// Access the GPREG0 register to use it as a 31-bit counter.
62 #[inline] 70 #[inline]
@@ -219,6 +227,7 @@ impl Rtc {
219 } 227 }
220} 228}
221 229
230#[cfg(feature = "time-driver-rtc")]
222impl Driver for Rtc { 231impl Driver for Rtc {
223 fn now(&self) -> u64 { 232 fn now(&self) -> u64 {
224 // `period` MUST be read before `counter`, see comment at the top for details. 233 // `period` MUST be read before `counter`, see comment at the top for details.
@@ -242,13 +251,158 @@ impl Driver for Rtc {
242 } 251 }
243} 252}
244 253
245#[cfg(feature = "rt")] 254#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
246#[allow(non_snake_case)] 255#[allow(non_snake_case)]
247#[interrupt] 256#[interrupt]
248fn RTC() { 257fn RTC() {
249 DRIVER.on_interrupt() 258 DRIVER.on_interrupt()
250} 259}
251 260
261#[cfg(feature = "time-driver-os-timer")]
262fn os() -> &'static pac::ostimer0::RegisterBlock {
263 unsafe { &*pac::Ostimer0::ptr() }
264}
265
266/// Convert gray to decimal
267///
268/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
269/// do here is read both 32-bit halves of the register and convert
270/// from gray to regular binary.
271#[cfg(feature = "time-driver-os-timer")]
272fn gray_to_dec(gray: u64) -> u64 {
273 let mut dec = gray;
274
275 dec ^= dec >> 1;
276 dec ^= dec >> 2;
277 dec ^= dec >> 4;
278 dec ^= dec >> 8;
279 dec ^= dec >> 16;
280 dec ^= dec >> 32;
281
282 dec
283}
284
285/// Convert decimal to gray
286///
287/// Before writing match value to the target register, we must convert
288/// it back into gray code.
289#[cfg(feature = "time-driver-os-timer")]
290fn dec_to_gray(dec: u64) -> u64 {
291 let gray = dec;
292 gray ^ (gray >> 1)
293}
294
295#[cfg(feature = "time-driver-os-timer")]
296embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
297 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
298 queue: Mutex::new(RefCell::new(Queue::new())),
299});
300
301#[cfg(feature = "time-driver-os-timer")]
302struct OsTimer {
303 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
304 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
305 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
306}
307
308#[cfg(feature = "time-driver-os-timer")]
309impl OsTimer {
310 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
311 // init alarms
312 critical_section::with(|cs| {
313 let alarm = DRIVER.alarms.borrow(cs);
314 alarm.timestamp.set(u64::MAX);
315 });
316
317 // Enable clocks. Documentation advises AGAINST resetting this
318 // peripheral.
319 enable::<crate::peripherals::OS_EVENT>();
320
321 interrupt::OS_EVENT.disable();
322
323 // Make sure interrupt is masked
324 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
325
326 // Default to the end of time
327 os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
328 os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
329
330 interrupt::OS_EVENT.unpend();
331 interrupt::OS_EVENT.set_priority(irq_prio);
332 unsafe { interrupt::OS_EVENT.enable() };
333 }
334
335 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
336 let alarm = self.alarms.borrow(cs);
337 alarm.timestamp.set(timestamp);
338
339 let t = self.now();
340 if timestamp <= t {
341 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
342 alarm.timestamp.set(u64::MAX);
343 return false;
344 }
345
346 let gray_timestamp = dec_to_gray(timestamp);
347
348 os().match_l()
349 .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) });
350 os().match_h()
351 .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) });
352 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit());
353
354 true
355 }
356
357 #[cfg(feature = "rt")]
358 fn trigger_alarm(&self, cs: CriticalSection) {
359 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
360 while !self.set_alarm(cs, next) {
361 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
362 }
363 }
364
365 #[cfg(feature = "rt")]
366 fn on_interrupt(&self) {
367 critical_section::with(|cs| {
368 if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() {
369 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
370 self.trigger_alarm(cs);
371 }
372 });
373 }
374}
375
376#[cfg(feature = "time-driver-os-timer")]
377impl Driver for OsTimer {
378 fn now(&self) -> u64 {
379 let mut t = os().evtimerh().read().bits() as u64;
380 t <<= 32;
381 t |= os().evtimerl().read().bits() as u64;
382 gray_to_dec(t)
383 }
384
385 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
386 critical_section::with(|cs| {
387 let mut queue = self.queue.borrow(cs).borrow_mut();
388
389 if queue.schedule_wake(at, waker) {
390 let mut next = queue.next_expiration(self.now());
391 while !self.set_alarm(cs, next) {
392 next = queue.next_expiration(self.now());
393 }
394 }
395 })
396 }
397}
398
399#[cfg(all(feature = "rt", feature = "time-driver-os-timer"))]
400#[allow(non_snake_case)]
401#[interrupt]
402fn OS_EVENT() {
403 DRIVER.on_interrupt()
404}
405
252pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 406pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
253 DRIVER.init(irq_prio) 407 DRIVER.init(irq_prio)
254} 408}
diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md
index cfee5f3cf..8773772ce 100644
--- a/embassy-net/CHANGELOG.md
+++ b/embassy-net/CHANGELOG.md
@@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9 9
10No unreleased changes yet... Quick, go send a PR! 10No unreleased changes yet... Quick, go send a PR!
11 11
12## 0.7 - 2025-02-14 12## 0.7 - 2025-05-06
13 13
14- don't infinite loop if udp::send methods receive a buffer too large to ever be sent 14- don't infinite loop if udp::send methods receive a buffer too large to ever be sent
15- add ICMP sockets and a ping utility 15- add ICMP sockets and a ping utility
16- configurable rate_limit for the ping utility
17- Feature match udp sockets
16 18
17## 0.6 - 2025-01-05 19## 0.6 - 2025-01-05
18 20
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 0103fa7ae..99cf29487 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
262 PPI_GROUP4, 262 PPI_GROUP4,
263 PPI_GROUP5, 263 PPI_GROUP5,
264 264
265 // IPC
266 IPC,
267
265 // GPIO port 0 268 // GPIO port 0
266 #[cfg(feature = "lfxo-pins-as-gpio")] 269 #[cfg(feature = "lfxo-pins-as-gpio")]
267 P0_00, 270 P0_00,
@@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
327 EGU5, 330 EGU5,
328} 331}
329 332
333impl_ipc!(IPC, IPC, IPC);
334
330impl_usb!(USBD, USBD, USBD); 335impl_usb!(USBD, USBD, USBD);
331 336
332impl_uarte!(SERIAL0, UARTE0, SERIAL0); 337impl_uarte!(SERIAL0, UARTE0, SERIAL0);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 22d33d080..c2932be31 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
141 PPI_GROUP4, 141 PPI_GROUP4,
142 PPI_GROUP5, 142 PPI_GROUP5,
143 143
144 // IPC
145 IPC,
146
144 // GPIO port 0 147 // GPIO port 0
145 P0_00, 148 P0_00,
146 P0_01, 149 P0_01,
@@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
200 EGU0, 203 EGU0,
201} 204}
202 205
206impl_ipc!(IPC, IPC, IPC);
207
203impl_uarte!(SERIAL0, UARTE0, SERIAL0); 208impl_uarte!(SERIAL0, UARTE0, SERIAL0);
204impl_spim!(SERIAL0, SPIM0, SERIAL0); 209impl_spim!(SERIAL0, SPIM0, SERIAL0);
205impl_spis!(SERIAL0, SPIS0, SERIAL0); 210impl_spis!(SERIAL0, SPIS0, SERIAL0);
diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs
new file mode 100644
index 000000000..a8a08c911
--- /dev/null
+++ b/embassy-nrf/src/ipc.rs
@@ -0,0 +1,363 @@
1//! InterProcessor Communication (IPC)
2
3#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::task::Poll;
8
9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac, ppi};
14
15const EVENT_COUNT: usize = 16;
16
17/// IPC Event
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub enum EventNumber {
20 /// IPC Event 0
21 Event0 = 0,
22 /// IPC Event 1
23 Event1 = 1,
24 /// IPC Event 2
25 Event2 = 2,
26 /// IPC Event 3
27 Event3 = 3,
28 /// IPC Event 4
29 Event4 = 4,
30 /// IPC Event 5
31 Event5 = 5,
32 /// IPC Event 6
33 Event6 = 6,
34 /// IPC Event 7
35 Event7 = 7,
36 /// IPC Event 8
37 Event8 = 8,
38 /// IPC Event 9
39 Event9 = 9,
40 /// IPC Event 10
41 Event10 = 10,
42 /// IPC Event 11
43 Event11 = 11,
44 /// IPC Event 12
45 Event12 = 12,
46 /// IPC Event 13
47 Event13 = 13,
48 /// IPC Event 14
49 Event14 = 14,
50 /// IPC Event 15
51 Event15 = 15,
52}
53
54const EVENTS: [EventNumber; EVENT_COUNT] = [
55 EventNumber::Event0,
56 EventNumber::Event1,
57 EventNumber::Event2,
58 EventNumber::Event3,
59 EventNumber::Event4,
60 EventNumber::Event5,
61 EventNumber::Event6,
62 EventNumber::Event7,
63 EventNumber::Event8,
64 EventNumber::Event9,
65 EventNumber::Event10,
66 EventNumber::Event11,
67 EventNumber::Event12,
68 EventNumber::Event13,
69 EventNumber::Event14,
70 EventNumber::Event15,
71];
72
73/// IPC Channel
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub enum IpcChannel {
76 /// IPC Channel 0
77 Channel0,
78 /// IPC Channel 1
79 Channel1,
80 /// IPC Channel 2
81 Channel2,
82 /// IPC Channel 3
83 Channel3,
84 /// IPC Channel 4
85 Channel4,
86 /// IPC Channel 5
87 Channel5,
88 /// IPC Channel 6
89 Channel6,
90 /// IPC Channel 7
91 Channel7,
92 /// IPC Channel 8
93 Channel8,
94 /// IPC Channel 9
95 Channel9,
96 /// IPC Channel 10
97 Channel10,
98 /// IPC Channel 11
99 Channel11,
100 /// IPC Channel 12
101 Channel12,
102 /// IPC Channel 13
103 Channel13,
104 /// IPC Channel 14
105 Channel14,
106 /// IPC Channel 15
107 Channel15,
108}
109
110impl IpcChannel {
111 fn mask(self) -> u32 {
112 1 << (self as u32)
113 }
114}
115
116/// Interrupt Handler
117pub struct InterruptHandler<T: Instance> {
118 _phantom: PhantomData<T>,
119}
120
121impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
122 unsafe fn on_interrupt() {
123 let regs = T::regs();
124
125 // Check if an event was generated, and if it was, trigger the corresponding waker
126 for event in EVENTS {
127 if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
128 regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
129 T::state().wakers[event as usize].wake();
130 }
131 }
132 }
133}
134
135/// IPC driver
136#[non_exhaustive]
137pub struct Ipc<'d, T: Instance> {
138 /// Event 0
139 pub event0: Event<'d, T>,
140 /// Event 1
141 pub event1: Event<'d, T>,
142 /// Event 2
143 pub event2: Event<'d, T>,
144 /// Event 3
145 pub event3: Event<'d, T>,
146 /// Event 4
147 pub event4: Event<'d, T>,
148 /// Event 5
149 pub event5: Event<'d, T>,
150 /// Event 6
151 pub event6: Event<'d, T>,
152 /// Event 7
153 pub event7: Event<'d, T>,
154 /// Event 8
155 pub event8: Event<'d, T>,
156 /// Event 9
157 pub event9: Event<'d, T>,
158 /// Event 10
159 pub event10: Event<'d, T>,
160 /// Event 11
161 pub event11: Event<'d, T>,
162 /// Event 12
163 pub event12: Event<'d, T>,
164 /// Event 13
165 pub event13: Event<'d, T>,
166 /// Event 14
167 pub event14: Event<'d, T>,
168 /// Event 15
169 pub event15: Event<'d, T>,
170}
171
172impl<'d, T: Instance> Ipc<'d, T> {
173 /// Create a new IPC driver.
174 pub fn new(
175 _p: Peri<'d, T>,
176 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
177 ) -> Self {
178 T::Interrupt::unpend();
179 unsafe { T::Interrupt::enable() };
180
181 let _phantom = PhantomData;
182 #[rustfmt::skip]
183 let r = Self { // attributes on expressions are experimental
184 event0: Event { number: EventNumber::Event0, _phantom },
185 event1: Event { number: EventNumber::Event1, _phantom },
186 event2: Event { number: EventNumber::Event2, _phantom },
187 event3: Event { number: EventNumber::Event3, _phantom },
188 event4: Event { number: EventNumber::Event4, _phantom },
189 event5: Event { number: EventNumber::Event5, _phantom },
190 event6: Event { number: EventNumber::Event6, _phantom },
191 event7: Event { number: EventNumber::Event7, _phantom },
192 event8: Event { number: EventNumber::Event8, _phantom },
193 event9: Event { number: EventNumber::Event9, _phantom },
194 event10: Event { number: EventNumber::Event10, _phantom },
195 event11: Event { number: EventNumber::Event11, _phantom },
196 event12: Event { number: EventNumber::Event12, _phantom },
197 event13: Event { number: EventNumber::Event13, _phantom },
198 event14: Event { number: EventNumber::Event14, _phantom },
199 event15: Event { number: EventNumber::Event15, _phantom },
200 };
201 r
202 }
203}
204
205/// IPC event
206pub struct Event<'d, T: Instance> {
207 number: EventNumber,
208 _phantom: PhantomData<&'d T>,
209}
210
211impl<'d, T: Instance> Event<'d, T> {
212 /// Trigger the event.
213 pub fn trigger(&self) {
214 let nr = self.number;
215 T::regs().tasks_send(nr as usize).write_value(1);
216 }
217
218 /// Wait for the event to be triggered.
219 pub async fn wait(&mut self) {
220 let regs = T::regs();
221 let nr = self.number as usize;
222 regs.intenset().write(|w| w.0 = 1 << nr);
223 poll_fn(|cx| {
224 T::state().wakers[nr].register(cx.waker());
225
226 if regs.events_receive(nr).read() == 1 {
227 regs.events_receive(nr).write_value(0x00);
228 Poll::Ready(())
229 } else {
230 Poll::Pending
231 }
232 })
233 .await;
234 }
235
236 /// Returns the [`EventNumber`] of the event.
237 pub fn number(&self) -> EventNumber {
238 self.number
239 }
240
241 /// Create a handle that can trigger the event.
242 pub fn trigger_handle(&self) -> EventTrigger<'d, T> {
243 EventTrigger {
244 number: self.number,
245 _phantom: PhantomData,
246 }
247 }
248
249 /// Configure the channels the event will broadcast to
250 pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
251 T::regs().send_cnf(self.number as usize).write(|w| {
252 for channel in channels {
253 w.0 |= channel.mask();
254 }
255 })
256 }
257
258 /// Configure the channels the event will listen on
259 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
260 T::regs().receive_cnf(self.number as usize).write(|w| {
261 for channel in channels {
262 w.0 |= channel.mask();
263 }
264 });
265 }
266
267 /// Get the task for the IPC event to use with PPI.
268 pub fn task(&self) -> ppi::Task<'d> {
269 let nr = self.number as usize;
270 let regs = T::regs();
271 ppi::Task::from_reg(regs.tasks_send(nr))
272 }
273
274 /// Get the event for the IPC event to use with PPI.
275 pub fn event(&self) -> ppi::Event<'d> {
276 let nr = self.number as usize;
277 let regs = T::regs();
278 ppi::Event::from_reg(regs.events_receive(nr))
279 }
280
281 /// Reborrow into a "child" Event.
282 ///
283 /// `self` will stay borrowed until the child Event is dropped.
284 pub fn reborrow(&mut self) -> Event<'_, T> {
285 Self { ..*self }
286 }
287
288 /// Steal an IPC event by number.
289 ///
290 /// # Safety
291 ///
292 /// The event number must not be in use by another [`Event`].
293 pub unsafe fn steal(number: EventNumber) -> Self {
294 Self {
295 number,
296 _phantom: PhantomData,
297 }
298 }
299}
300
301/// A handle that can trigger an IPC event.
302///
303/// This `struct` is returned by [`Event::trigger_handle`].
304#[derive(Debug, Copy, Clone)]
305pub struct EventTrigger<'d, T: Instance> {
306 number: EventNumber,
307 _phantom: PhantomData<&'d T>,
308}
309
310impl<T: Instance> EventTrigger<'_, T> {
311 /// Trigger the event.
312 pub fn trigger(&self) {
313 let nr = self.number;
314 T::regs().tasks_send(nr as usize).write_value(1);
315 }
316
317 /// Returns the [`EventNumber`] of the event.
318 pub fn number(&self) -> EventNumber {
319 self.number
320 }
321}
322
323pub(crate) struct State {
324 wakers: [AtomicWaker; EVENT_COUNT],
325}
326
327impl State {
328 pub(crate) const fn new() -> Self {
329 Self {
330 wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
331 }
332 }
333}
334
335pub(crate) trait SealedInstance {
336 fn regs() -> pac::ipc::Ipc;
337 fn state() -> &'static State;
338}
339
340/// IPC peripheral instance.
341#[allow(private_bounds)]
342pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
343 /// Interrupt for this peripheral.
344 type Interrupt: interrupt::typelevel::Interrupt;
345}
346
347macro_rules! impl_ipc {
348 ($type:ident, $pac_type:ident, $irq:ident) => {
349 impl crate::ipc::SealedInstance for peripherals::$type {
350 fn regs() -> pac::ipc::Ipc {
351 pac::$pac_type
352 }
353
354 fn state() -> &'static crate::ipc::State {
355 static STATE: crate::ipc::State = crate::ipc::State::new();
356 &STATE
357 }
358 }
359 impl crate::ipc::Instance for peripherals::$type {
360 type Interrupt = crate::interrupt::typelevel::$irq;
361 }
362 };
363}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 07ba2f6d4..5bce65a98 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -88,6 +88,8 @@ pub mod gpiote;
88#[cfg(not(feature = "_nrf54l"))] // TODO 88#[cfg(not(feature = "_nrf54l"))] // TODO
89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] 89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
90pub mod i2s; 90pub mod i2s;
91#[cfg(feature = "_nrf5340")]
92pub mod ipc;
91#[cfg(not(feature = "_nrf54l"))] // TODO 93#[cfg(not(feature = "_nrf54l"))] // TODO
92#[cfg(any( 94#[cfg(any(
93 feature = "nrf52832", 95 feature = "nrf52832",
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
deleted file mode 100644
index d42bbe5f6..000000000
--- a/embassy-nrf/src/radio/ble.rs
+++ /dev/null
@@ -1,394 +0,0 @@
1//! Radio driver implementation focused on Bluetooth Low-Energy transmission.
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_hal_internal::drop::OnDrop;
8pub use pac::radio::vals::Mode;
9#[cfg(not(feature = "_nrf51"))]
10use pac::radio::vals::Plen as PreambleLength;
11
12use crate::interrupt::typelevel::Interrupt;
13use crate::pac::radio::vals;
14use crate::radio::*;
15pub use crate::radio::{Error, TxPower};
16use crate::util::slice_in_ram_or;
17use crate::Peri;
18
19/// Radio driver.
20pub struct Radio<'d, T: Instance> {
21 _p: Peri<'d, T>,
22}
23
24impl<'d, T: Instance> Radio<'d, T> {
25 /// Create a new radio driver.
26 pub fn new(
27 radio: Peri<'d, T>,
28 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
29 ) -> Self {
30 let r = T::regs();
31
32 r.pcnf1().write(|w| {
33 // It is 0 bytes long in a standard BLE packet
34 w.set_statlen(0);
35 // MaxLen configures the maximum packet payload plus add-on size in
36 // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
37 // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
38 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
39 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
40 //
41 // To simplify the implementation, It is setted as the maximum value
42 // and the length of the packet is controlled only by the LENGTH field in the packet
43 w.set_maxlen(255);
44 // Configure the length of the address field in the packet
45 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
46 // The base address is truncated from the least significant byte if the BALEN is less than 4
47 //
48 // BLE address is always 4 bytes long
49 w.set_balen(3); // 3 bytes base address (+ 1 prefix);
50 // Configure the endianess
51 // For BLE is always little endian (LSB first)
52 w.set_endian(vals::Endian::LITTLE);
53 // Data whitening is used to avoid long sequences of zeros or
54 // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
55 // The whitener and de-whitener are defined the same way,
56 // using a 7-bit linear feedback shift register with the
57 // polynomial x7 + x4 + 1.
58 //
59 // In BLE Whitening shall be applied on the PDU and CRC of all
60 // Link Layer packets and is performed after the CRC generation
61 // in the transmitter. No other parts of the packets are whitened.
62 // De-whitening is performed before the CRC checking in the receiver
63 // Before whitening or de-whitening, the shift register should be
64 // initialized based on the channel index.
65 w.set_whiteen(true);
66 });
67
68 // Configure CRC
69 r.crccnf().write(|w| {
70 // In BLE the CRC shall be calculated on the PDU of all Link Layer
71 // packets (even if the packet is encrypted).
72 // It skips the address field
73 w.set_skipaddr(vals::Skipaddr::SKIP);
74 // In BLE 24-bit CRC = 3 bytes
75 w.set_len(vals::Len::THREE);
76 });
77
78 // Ch map between 2400 MHZ .. 2500 MHz
79 // All modes use this range
80 #[cfg(not(feature = "_nrf51"))]
81 r.frequency().write(|w| w.set_map(vals::Map::DEFAULT));
82
83 // Configure shortcuts to simplify and speed up sending and receiving packets.
84 r.shorts().write(|w| {
85 // start transmission/recv immediately after ramp-up
86 // disable radio when transmission/recv is done
87 w.set_ready_start(true);
88 w.set_end_disable(true);
89 });
90
91 // Enable NVIC interrupt
92 T::Interrupt::unpend();
93 unsafe { T::Interrupt::enable() };
94
95 Self { _p: radio }
96 }
97
98 fn state(&self) -> RadioState {
99 super::state(T::regs())
100 }
101
102 /// Set the radio mode
103 ///
104 /// The radio must be disabled before calling this function
105 pub fn set_mode(&mut self, mode: Mode) {
106 assert!(self.state() == RadioState::DISABLED);
107
108 let r = T::regs();
109 r.mode().write(|w| w.set_mode(mode));
110
111 #[cfg(not(feature = "_nrf51"))]
112 r.pcnf0().write(|w| {
113 w.set_plen(match mode {
114 Mode::BLE_1MBIT => PreambleLength::_8BIT,
115 Mode::BLE_2MBIT => PreambleLength::_16BIT,
116 #[cfg(any(
117 feature = "nrf52811",
118 feature = "nrf52820",
119 feature = "nrf52833",
120 feature = "nrf52840",
121 feature = "_nrf5340-net"
122 ))]
123 Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE,
124 _ => unimplemented!(),
125 })
126 });
127 }
128
129 /// Set the header size changing the S1's len field
130 ///
131 /// The radio must be disabled before calling this function
132 pub fn set_header_expansion(&mut self, use_s1_field: bool) {
133 assert!(self.state() == RadioState::DISABLED);
134
135 let r = T::regs();
136
137 // s1 len in bits
138 let s1len: u8 = match use_s1_field {
139 false => 0,
140 true => 8,
141 };
142
143 r.pcnf0().write(|w| {
144 // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
145 w.set_s0len(true);
146 // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
147 // and also be used to know how many bytes to read/write from/to the buffer
148 w.set_lflen(0);
149 // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
150 w.set_s1len(s1len);
151 });
152 }
153
154 /// Set initial data whitening value
155 /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream
156 /// On BLE the initial value is the channel index | 0x40
157 ///
158 /// The radio must be disabled before calling this function
159 pub fn set_whitening_init(&mut self, whitening_init: u8) {
160 assert!(self.state() == RadioState::DISABLED);
161
162 let r = T::regs();
163
164 r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init));
165 }
166
167 /// Set the central frequency to be used
168 /// It should be in the range 2400..2500
169 ///
170 /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change)
171 pub fn set_frequency(&mut self, frequency: u32) {
172 assert!(self.state() == RadioState::DISABLED);
173 assert!((2400..=2500).contains(&frequency));
174
175 let r = T::regs();
176
177 r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8));
178 }
179
180 /// Set the acess address
181 /// This address is always constants for advertising
182 /// And a random value generate on each connection
183 /// It is used to filter the packages
184 ///
185 /// The radio must be disabled before calling this function
186 pub fn set_access_address(&mut self, access_address: u32) {
187 assert!(self.state() == RadioState::DISABLED);
188
189 let r = T::regs();
190
191 // Configure logical address
192 // The byte ordering on air is always least significant byte first for the address
193 // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
194 // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
195 r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8));
196
197 // The base address is truncated from the least significant byte (because the BALEN is less than 4)
198 // So it shifts the address to the right
199 r.base0().write_value(access_address << 8);
200
201 // Don't match tx address
202 r.txaddress().write(|w| w.set_txaddress(0));
203
204 // Match on logical address
205 // This config only filter the packets by the address,
206 // so only packages send to the previous address
207 // will finish the reception (TODO: check the explanation)
208 r.rxaddresses().write(|w| {
209 w.set_addr0(true);
210 w.set_addr1(true);
211 w.set_addr2(true);
212 w.set_addr3(true);
213 w.set_addr4(true);
214 });
215 }
216
217 /// Set the CRC polynomial
218 /// It only uses the 24 least significant bits
219 ///
220 /// The radio must be disabled before calling this function
221 pub fn set_crc_poly(&mut self, crc_poly: u32) {
222 assert!(self.state() == RadioState::DISABLED);
223
224 let r = T::regs();
225
226 r.crcpoly().write(|w| {
227 // Configure the CRC polynomial
228 // Each term in the CRC polynomial is mapped to a bit in this
229 // register which index corresponds to the term's exponent.
230 // The least significant term/bit is hard-wired internally to
231 // 1, and bit number 0 of the register content is ignored by
232 // the hardware. The following example is for an 8 bit CRC
233 // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
234 w.set_crcpoly(crc_poly & 0xFFFFFF)
235 });
236 }
237
238 /// Set the CRC init value
239 /// It only uses the 24 least significant bits
240 /// The CRC initial value varies depending of the PDU type
241 ///
242 /// The radio must be disabled before calling this function
243 pub fn set_crc_init(&mut self, crc_init: u32) {
244 assert!(self.state() == RadioState::DISABLED);
245
246 let r = T::regs();
247
248 r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF));
249 }
250
251 /// Set the radio tx power
252 ///
253 /// The radio must be disabled before calling this function
254 pub fn set_tx_power(&mut self, tx_power: TxPower) {
255 assert!(self.state() == RadioState::DISABLED);
256
257 let r = T::regs();
258
259 r.txpower().write(|w| w.set_txpower(tx_power));
260 }
261
262 /// Set buffer to read/write
263 ///
264 /// This method is unsound. You should guarantee that the buffer will live
265 /// for the life time of the transmission or if the buffer will be modified.
266 /// Also if the buffer is smaller than the packet length, the radio will
267 /// read/write memory out of the buffer bounds.
268 fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
269 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
270
271 let r = T::regs();
272
273 // Here it consider that the length of the packet is
274 // correctly set in the buffer, otherwise it will send
275 // unowned regions of memory
276 let ptr = buffer.as_ptr();
277
278 // Configure the payload
279 r.packetptr().write_value(ptr as u32);
280
281 Ok(())
282 }
283
284 /// Send packet
285 /// If the length byte in the package is greater than the buffer length
286 /// the radio will read memory out of the buffer bounds
287 pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> {
288 self.set_buffer(buffer)?;
289
290 let r = T::regs();
291 self.trigger_and_wait_end(move || {
292 // Initialize the transmission
293 // trace!("txen");
294
295 r.tasks_txen().write_value(1);
296 })
297 .await;
298
299 Ok(())
300 }
301
302 /// Receive packet
303 /// If the length byte in the received package is greater than the buffer length
304 /// the radio will write memory out of the buffer bounds
305 pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
306 self.set_buffer(buffer)?;
307
308 let r = T::regs();
309 self.trigger_and_wait_end(move || {
310 // Initialize the transmission
311 // trace!("rxen");
312 r.tasks_rxen().write_value(1);
313 })
314 .await;
315
316 Ok(())
317 }
318
319 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) {
320 let r = T::regs();
321 let s = T::state();
322
323 // If the Future is dropped before the end of the transmission
324 // it disable the interrupt and stop the transmission
325 // to keep the state consistent
326 let drop = OnDrop::new(|| {
327 trace!("radio drop: stopping");
328
329 r.intenclr().write(|w| w.set_end(true));
330
331 r.tasks_stop().write_value(1);
332
333 r.events_end().write_value(0);
334
335 trace!("radio drop: stopped");
336 });
337
338 // trace!("radio:enable interrupt");
339 // Clear some remnant side-effects (TODO: check if this is necessary)
340 r.events_end().write_value(0);
341
342 // Enable interrupt
343 r.intenset().write(|w| w.set_end(true));
344
345 compiler_fence(Ordering::SeqCst);
346
347 // Trigger the transmission
348 trigger();
349
350 // On poll check if interrupt happen
351 poll_fn(|cx| {
352 s.event_waker.register(cx.waker());
353 if r.events_end().read() == 1 {
354 // trace!("radio:end");
355 return core::task::Poll::Ready(());
356 }
357 Poll::Pending
358 })
359 .await;
360
361 compiler_fence(Ordering::SeqCst);
362 r.events_end().write_value(0); // ACK
363
364 // Everthing ends fine, so it disable the drop
365 drop.defuse();
366 }
367
368 /// Disable the radio
369 fn disable(&mut self) {
370 let r = T::regs();
371
372 compiler_fence(Ordering::SeqCst);
373 // If it is already disabled, do nothing
374 if self.state() != RadioState::DISABLED {
375 trace!("radio:disable");
376 // Trigger the disable task
377 r.tasks_disable().write_value(1);
378
379 // Wait until the radio is disabled
380 while r.events_disabled().read() == 0 {}
381
382 compiler_fence(Ordering::SeqCst);
383
384 // Acknowledge it
385 r.events_disabled().write_value(0);
386 }
387 }
388}
389
390impl<'d, T: Instance> Drop for Radio<'d, T> {
391 fn drop(&mut self) {
392 self.disable();
393 }
394}
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
index 2f0bcbe04..7f4f8f462 100644
--- a/embassy-nrf/src/radio/ieee802154.rs
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -5,10 +5,11 @@ use core::task::Poll;
5 5
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7 7
8use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; 8use super::{Error, Instance, InterruptHandler, TxPower};
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::interrupt::{self}; 10use crate::interrupt::{self};
11use crate::pac::radio::vals; 11use crate::pac::radio::vals;
12pub use crate::pac::radio::vals::State as RadioState;
12use crate::Peri; 13use crate::Peri;
13 14
14/// Default (IEEE compliant) Start of Frame Delimiter 15/// Default (IEEE compliant) Start of Frame Delimiter
@@ -200,7 +201,7 @@ impl<'d, T: Instance> Radio<'d, T> {
200 201
201 /// Get the current radio state 202 /// Get the current radio state
202 fn state(&self) -> RadioState { 203 fn state(&self) -> RadioState {
203 state(T::regs()) 204 T::regs().state().read().state()
204 } 205 }
205 206
206 /// Moves the radio from any state to the DISABLED state 207 /// Moves the radio from any state to the DISABLED state
@@ -293,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> {
293 r.shorts().write(|_| {}); 294 r.shorts().write(|_| {});
294 r.tasks_stop().write_value(1); 295 r.tasks_stop().write_value(1);
295 loop { 296 loop {
296 match state(r) { 297 match r.state().read().state() {
297 RadioState::DISABLED | RadioState::RX_IDLE => break, 298 RadioState::DISABLED | RadioState::RX_IDLE => break,
298 _ => (), 299 _ => (),
299 } 300 }
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
index 982436266..608ef9024 100644
--- a/embassy-nrf/src/radio/mod.rs
+++ b/embassy-nrf/src/radio/mod.rs
@@ -6,7 +6,6 @@
6#![macro_use] 6#![macro_use]
7 7
8/// Bluetooth Low Energy Radio driver. 8/// Bluetooth Low Energy Radio driver.
9pub mod ble;
10#[cfg(any( 9#[cfg(any(
11 feature = "nrf52811", 10 feature = "nrf52811",
12 feature = "nrf52820", 11 feature = "nrf52820",
@@ -21,7 +20,6 @@ use core::marker::PhantomData;
21 20
22use embassy_hal_internal::PeripheralType; 21use embassy_hal_internal::PeripheralType;
23use embassy_sync::waitqueue::AtomicWaker; 22use embassy_sync::waitqueue::AtomicWaker;
24use pac::radio::vals::State as RadioState;
25pub use pac::radio::vals::Txpower as TxPower; 23pub use pac::radio::vals::Txpower as TxPower;
26 24
27use crate::{interrupt, pac}; 25use crate::{interrupt, pac};
@@ -82,6 +80,7 @@ macro_rules! impl_radio {
82 pac::$pac_type 80 pac::$pac_type
83 } 81 }
84 82
83 #[allow(unused)]
85 fn state() -> &'static crate::radio::State { 84 fn state() -> &'static crate::radio::State {
86 static STATE: crate::radio::State = crate::radio::State::new(); 85 static STATE: crate::radio::State = crate::radio::State::new();
87 &STATE 86 &STATE
@@ -99,8 +98,3 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
99 /// Interrupt for this peripheral. 98 /// Interrupt for this peripheral.
100 type Interrupt: interrupt::typelevel::Interrupt; 99 type Interrupt: interrupt::typelevel::Interrupt;
101} 100}
102
103/// Get the state of the radio
104pub(crate) fn state(radio: pac::radio::Radio) -> RadioState {
105 radio.state().read().state()
106}
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 083b54b99..3d5e841d1 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -4,7 +4,6 @@
4 4
5use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
9use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
10use core::task::Poll; 9use core::task::Poll;
@@ -17,7 +16,7 @@ use embassy_time::{Duration, Instant};
17use embedded_hal_1::i2c::Operation; 16use embedded_hal_1::i2c::Operation;
18pub use pac::twim::vals::Frequency; 17pub use pac::twim::vals::Frequency;
19 18
20use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 19use crate::chip::EASY_DMA_SIZE;
21use crate::gpio::Pin as GpioPin; 20use crate::gpio::Pin as GpioPin;
22use crate::interrupt::typelevel::Interrupt; 21use crate::interrupt::typelevel::Interrupt;
23use crate::pac::gpio::vals as gpiovals; 22use crate::pac::gpio::vals as gpiovals;
@@ -75,8 +74,8 @@ pub enum Error {
75 Transmit, 74 Transmit,
76 /// Data reception failed. 75 /// Data reception failed.
77 Receive, 76 Receive,
78 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. 77 /// The buffer is not in data RAM and is larger than the RAM buffer. It's most likely in flash, and nRF's DMA cannot access flash.
79 BufferNotInRAM, 78 RAMBufferTooSmall,
80 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly. 79 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly.
81 AddressNack, 80 AddressNack,
82 /// Didn't receive an ACK bit after a data byte. 81 /// Didn't receive an ACK bit after a data byte.
@@ -115,16 +114,24 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
115/// TWI driver. 114/// TWI driver.
116pub struct Twim<'d, T: Instance> { 115pub struct Twim<'d, T: Instance> {
117 _p: Peri<'d, T>, 116 _p: Peri<'d, T>,
117 tx_ram_buffer: &'d mut [u8],
118} 118}
119 119
120impl<'d, T: Instance> Twim<'d, T> { 120impl<'d, T: Instance> Twim<'d, T> {
121 /// Create a new TWI driver. 121 /// Create a new TWI driver.
122 ///
123 /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM.
124 /// Usually this is static data that the compiler locates in flash instead of RAM. The `tx_ram_buffer`
125 /// needs to be at least as large as the largest write operation that will be executed with a buffer
126 /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may
127 /// be used.
122 pub fn new( 128 pub fn new(
123 twim: Peri<'d, T>, 129 twim: Peri<'d, T>,
124 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
125 sda: Peri<'d, impl GpioPin>, 131 sda: Peri<'d, impl GpioPin>,
126 scl: Peri<'d, impl GpioPin>, 132 scl: Peri<'d, impl GpioPin>,
127 config: Config, 133 config: Config,
134 tx_ram_buffer: &'d mut [u8],
128 ) -> Self { 135 ) -> Self {
129 let r = T::regs(); 136 let r = T::regs();
130 137
@@ -159,7 +166,10 @@ impl<'d, T: Instance> Twim<'d, T> {
159 // Enable TWIM instance. 166 // Enable TWIM instance.
160 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 167 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
161 168
162 let mut twim = Self { _p: twim }; 169 let mut twim = Self {
170 _p: twim,
171 tx_ram_buffer,
172 };
163 173
164 // Apply runtime peripheral configuration 174 // Apply runtime peripheral configuration
165 Self::set_config(&mut twim, &config).unwrap(); 175 Self::set_config(&mut twim, &config).unwrap();
@@ -174,21 +184,17 @@ impl<'d, T: Instance> Twim<'d, T> {
174 } 184 }
175 185
176 /// Set TX buffer, checking that it is in RAM and has suitable length. 186 /// Set TX buffer, checking that it is in RAM and has suitable length.
177 unsafe fn set_tx_buffer( 187 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
178 &mut self,
179 buffer: &[u8],
180 ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
181 ) -> Result<(), Error> {
182 let buffer = if slice_in_ram(buffer) { 188 let buffer = if slice_in_ram(buffer) {
183 buffer 189 buffer
184 } else { 190 } else {
185 let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; 191 if buffer.len() > self.tx_ram_buffer.len() {
192 return Err(Error::RAMBufferTooSmall);
193 }
186 trace!("Copying TWIM tx buffer into RAM for DMA"); 194 trace!("Copying TWIM tx buffer into RAM for DMA");
187 let ram_buffer = &mut ram_buffer[..buffer.len()]; 195 let ram_buffer = &mut self.tx_ram_buffer[..buffer.len()];
188 // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) 196 ram_buffer.copy_from_slice(buffer);
189 let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; 197 &*ram_buffer
190 ram_buffer.copy_from_slice(uninit_src);
191 unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) }
192 }; 198 };
193 199
194 if buffer.len() > EASY_DMA_SIZE { 200 if buffer.len() > EASY_DMA_SIZE {
@@ -358,7 +364,6 @@ impl<'d, T: Instance> Twim<'d, T> {
358 &mut self, 364 &mut self,
359 address: u8, 365 address: u8,
360 operations: &mut [Operation<'_>], 366 operations: &mut [Operation<'_>],
361 tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
362 last_op: Option<&Operation<'_>>, 367 last_op: Option<&Operation<'_>>,
363 inten: bool, 368 inten: bool,
364 ) -> Result<usize, Error> { 369 ) -> Result<usize, Error> {
@@ -397,7 +402,7 @@ impl<'d, T: Instance> Twim<'d, T> {
397 402
398 // Set up DMA buffers. 403 // Set up DMA buffers.
399 unsafe { 404 unsafe {
400 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 405 self.set_tx_buffer(wr_buffer)?;
401 self.set_rx_buffer(rd_buffer)?; 406 self.set_rx_buffer(rd_buffer)?;
402 } 407 }
403 408
@@ -450,7 +455,7 @@ impl<'d, T: Instance> Twim<'d, T> {
450 { 455 {
451 // Set up DMA buffers. 456 // Set up DMA buffers.
452 unsafe { 457 unsafe {
453 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 458 self.set_tx_buffer(wr_buffer)?;
454 self.set_rx_buffer(rd_buffer)?; 459 self.set_rx_buffer(rd_buffer)?;
455 } 460 }
456 461
@@ -472,7 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> {
472 477
473 // Set up DMA buffers. 478 // Set up DMA buffers.
474 unsafe { 479 unsafe {
475 self.set_tx_buffer(buffer, tx_ram_buffer)?; 480 self.set_tx_buffer(buffer)?;
476 } 481 }
477 482
478 // Start write operation. 483 // Start write operation.
@@ -539,28 +544,9 @@ impl<'d, T: Instance> Twim<'d, T> {
539 /// An `Operation::Write` following an `Operation::Read` must have a 544 /// An `Operation::Write` following an `Operation::Read` must have a
540 /// non-empty buffer. 545 /// non-empty buffer.
541 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 546 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
542 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
543 let mut last_op = None; 547 let mut last_op = None;
544 while !operations.is_empty() { 548 while !operations.is_empty() {
545 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; 549 let ops = self.setup_operations(address, operations, last_op, false)?;
546 let (in_progress, rest) = operations.split_at_mut(ops);
547 self.blocking_wait();
548 self.check_operations(in_progress)?;
549 last_op = in_progress.last();
550 operations = rest;
551 }
552 Ok(())
553 }
554
555 /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
556 pub fn blocking_transaction_from_ram(
557 &mut self,
558 address: u8,
559 mut operations: &mut [Operation<'_>],
560 ) -> Result<(), Error> {
561 let mut last_op = None;
562 while !operations.is_empty() {
563 let ops = self.setup_operations(address, operations, None, last_op, false)?;
564 let (in_progress, rest) = operations.split_at_mut(ops); 550 let (in_progress, rest) = operations.split_at_mut(ops);
565 self.blocking_wait(); 551 self.blocking_wait();
566 self.check_operations(in_progress)?; 552 self.check_operations(in_progress)?;
@@ -580,30 +566,9 @@ impl<'d, T: Instance> Twim<'d, T> {
580 mut operations: &mut [Operation<'_>], 566 mut operations: &mut [Operation<'_>],
581 timeout: Duration, 567 timeout: Duration,
582 ) -> Result<(), Error> { 568 ) -> Result<(), Error> {
583 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
584 let mut last_op = None;
585 while !operations.is_empty() {
586 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?;
587 let (in_progress, rest) = operations.split_at_mut(ops);
588 self.blocking_wait_timeout(timeout)?;
589 self.check_operations(in_progress)?;
590 last_op = in_progress.last();
591 operations = rest;
592 }
593 Ok(())
594 }
595
596 /// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
597 #[cfg(feature = "time")]
598 pub fn blocking_transaction_from_ram_timeout(
599 &mut self,
600 address: u8,
601 mut operations: &mut [Operation<'_>],
602 timeout: Duration,
603 ) -> Result<(), Error> {
604 let mut last_op = None; 569 let mut last_op = None;
605 while !operations.is_empty() { 570 while !operations.is_empty() {
606 let ops = self.setup_operations(address, operations, None, last_op, false)?; 571 let ops = self.setup_operations(address, operations, last_op, false)?;
607 let (in_progress, rest) = operations.split_at_mut(ops); 572 let (in_progress, rest) = operations.split_at_mut(ops);
608 self.blocking_wait_timeout(timeout)?; 573 self.blocking_wait_timeout(timeout)?;
609 self.check_operations(in_progress)?; 574 self.check_operations(in_progress)?;
@@ -624,28 +589,9 @@ impl<'d, T: Instance> Twim<'d, T> {
624 /// An `Operation::Write` following an `Operation::Read` must have a 589 /// An `Operation::Write` following an `Operation::Read` must have a
625 /// non-empty buffer. 590 /// non-empty buffer.
626 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 591 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
627 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
628 let mut last_op = None;
629 while !operations.is_empty() {
630 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?;
631 let (in_progress, rest) = operations.split_at_mut(ops);
632 self.async_wait().await?;
633 self.check_operations(in_progress)?;
634 last_op = in_progress.last();
635 operations = rest;
636 }
637 Ok(())
638 }
639
640 /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
641 pub async fn transaction_from_ram(
642 &mut self,
643 address: u8,
644 mut operations: &mut [Operation<'_>],
645 ) -> Result<(), Error> {
646 let mut last_op = None; 592 let mut last_op = None;
647 while !operations.is_empty() { 593 while !operations.is_empty() {
648 let ops = self.setup_operations(address, operations, None, last_op, true)?; 594 let ops = self.setup_operations(address, operations, last_op, true)?;
649 let (in_progress, rest) = operations.split_at_mut(ops); 595 let (in_progress, rest) = operations.split_at_mut(ops);
650 self.async_wait().await?; 596 self.async_wait().await?;
651 self.check_operations(in_progress)?; 597 self.check_operations(in_progress)?;
@@ -665,11 +611,6 @@ impl<'d, T: Instance> Twim<'d, T> {
665 self.blocking_transaction(address, &mut [Operation::Write(buffer)]) 611 self.blocking_transaction(address, &mut [Operation::Write(buffer)])
666 } 612 }
667 613
668 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
669 pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
670 self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)])
671 }
672
673 /// Read from an I2C slave. 614 /// Read from an I2C slave.
674 /// 615 ///
675 /// The buffer must have a length of at most 255 bytes on the nRF52832 616 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -687,16 +628,6 @@ impl<'d, T: Instance> Twim<'d, T> {
687 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 628 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
688 } 629 }
689 630
690 /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
691 pub fn blocking_write_read_from_ram(
692 &mut self,
693 address: u8,
694 wr_buffer: &[u8],
695 rd_buffer: &mut [u8],
696 ) -> Result<(), Error> {
697 self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
698 }
699
700 // =========================================== 631 // ===========================================
701 632
702 /// Write to an I2C slave with timeout. 633 /// Write to an I2C slave with timeout.
@@ -707,17 +638,6 @@ impl<'d, T: Instance> Twim<'d, T> {
707 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) 638 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
708 } 639 }
709 640
710 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
711 #[cfg(feature = "time")]
712 pub fn blocking_write_from_ram_timeout(
713 &mut self,
714 address: u8,
715 buffer: &[u8],
716 timeout: Duration,
717 ) -> Result<(), Error> {
718 self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout)
719 }
720
721 /// Read from an I2C slave. 641 /// Read from an I2C slave.
722 /// 642 ///
723 /// The buffer must have a length of at most 255 bytes on the nRF52832 643 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -747,22 +667,6 @@ impl<'d, T: Instance> Twim<'d, T> {
747 ) 667 )
748 } 668 }
749 669
750 /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
751 #[cfg(feature = "time")]
752 pub fn blocking_write_read_from_ram_timeout(
753 &mut self,
754 address: u8,
755 wr_buffer: &[u8],
756 rd_buffer: &mut [u8],
757 timeout: Duration,
758 ) -> Result<(), Error> {
759 self.blocking_transaction_from_ram_timeout(
760 address,
761 &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)],
762 timeout,
763 )
764 }
765
766 // =========================================== 670 // ===========================================
767 671
768 /// Read from an I2C slave. 672 /// Read from an I2C slave.
@@ -781,12 +685,6 @@ impl<'d, T: Instance> Twim<'d, T> {
781 self.transaction(address, &mut [Operation::Write(buffer)]).await 685 self.transaction(address, &mut [Operation::Write(buffer)]).await
782 } 686 }
783 687
784 /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
785 pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
786 self.transaction_from_ram(address, &mut [Operation::Write(buffer)])
787 .await
788 }
789
790 /// Write data to an I2C slave, then read data from the slave without 688 /// Write data to an I2C slave, then read data from the slave without
791 /// triggering a stop condition between the two. 689 /// triggering a stop condition between the two.
792 /// 690 ///
@@ -796,17 +694,6 @@ impl<'d, T: Instance> Twim<'d, T> {
796 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 694 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
797 .await 695 .await
798 } 696 }
799
800 /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
801 pub async fn write_read_from_ram(
802 &mut self,
803 address: u8,
804 wr_buffer: &[u8],
805 rd_buffer: &mut [u8],
806 ) -> Result<(), Error> {
807 self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
808 .await
809 }
810} 697}
811 698
812impl<'a, T: Instance> Drop for Twim<'a, T> { 699impl<'a, T: Instance> Drop for Twim<'a, T> {
@@ -904,7 +791,7 @@ impl embedded_hal_1::i2c::Error for Error {
904 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, 791 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
905 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, 792 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
906 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, 793 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
907 Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, 794 Self::RAMBufferTooSmall => embedded_hal_1::i2c::ErrorKind::Other,
908 Self::AddressNack => { 795 Self::AddressNack => {
909 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 796 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
910 } 797 }
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b440591cf..8fb8a50fd 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
26 26
27[features] 27[features]
28default = [ "rt" ] 28default = [ "rt" ]
29## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. 29
30## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac).
31## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that.
32## See <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> for more info.
30rt = [ "rp-pac/rt" ] 33rt = [ "rp-pac/rt" ]
31 34
32## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 35## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 67aa5e540..857877680 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,4 +1,67 @@
1//! Clock configuration for the RP2040 1//! # Clock configuration for the RP2040 and RP235x microcontrollers.
2//!
3//! # Clock Configuration API
4//!
5//! This module provides both high-level convenience functions and low-level manual
6//! configuration options for the RP2040 clock system.
7//!
8//! ## High-Level Convenience Functions
9//!
10//! For most users, these functions provide an easy way to configure clocks:
11//!
12//! - `ClockConfig::system_freq(125_000_000)` - Set system clock to a specific frequency with automatic voltage scaling
13//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock
14//!
15//! ## Manual Configuration
16//!
17//! For advanced users who need precise control:
18//!
19//! ```rust,ignore
20//! // Start with default configuration and customize it
21//! let mut config = ClockConfig::default();
22//!
23//! // Set custom PLL parameters
24//! config.xosc = Some(XoscConfig {
25//! hz: 12_000_000,
26//! sys_pll: Some(PllConfig {
27//! refdiv: 1,
28//! fbdiv: 200,
29//! post_div1: 6,
30//! post_div2: 2,
31//! }),
32//! // ... other fields
33//! });
34//!
35//! // Set voltage for overclocking
36//! config.core_voltage = CoreVoltage::V1_15;
37//! ```
38//!
39//! ## Examples
40//!
41//! ### Standard 125MHz (rp2040) or 150Mhz (rp235x) configuration
42//! ```rust,ignore
43//! let config = ClockConfig::crystal(12_000_000);
44//! ```
45//!
46//! Or using the default configuration:
47//! ```rust,ignore
48//! let config = ClockConfig::default();
49//! ```
50//!
51//! ### Overclock to 200MHz
52//! ```rust,ignore
53//! let config = ClockConfig::system_freq(200_000_000);
54//! ```
55//!
56//! ### Manual configuration for advanced scenarios
57//! ```rust,ignore
58//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, CoreVoltage};
59//!
60//! // Start with defaults and customize
61//! let mut config = ClockConfig::default();
62//! config.core_voltage = CoreVoltage::V1_15;
63//! // Set other parameters as needed...
64//! ```
2 65
3#[cfg(feature = "rp2040")] 66#[cfg(feature = "rp2040")]
4use core::arch::asm; 67use core::arch::asm;
@@ -18,6 +81,19 @@ use crate::{pac, reset, Peri};
18// gpin is not usually safe to use during the boot init() call, so it won't 81// gpin is not usually safe to use during the boot init() call, so it won't
19// be very useful until we have runtime clock reconfiguration. once this 82// be very useful until we have runtime clock reconfiguration. once this
20// happens we can resurrect the commented-out gpin bits. 83// happens we can resurrect the commented-out gpin bits.
84
85/// Clock error types.
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum ClockError {
89 /// PLL failed to lock within the timeout period.
90 PllLockTimedOut,
91 /// Could not find valid PLL parameters for system clock.
92 InvalidPllParameters,
93 /// Reading the core voltage failed due to an unexpected value in the register.
94 UnexpectedCoreVoltageRead,
95}
96
21struct Clocks { 97struct Clocks {
22 xosc: AtomicU32, 98 xosc: AtomicU32,
23 sys: AtomicU32, 99 sys: AtomicU32,
@@ -26,6 +102,7 @@ struct Clocks {
26 pll_usb: AtomicU32, 102 pll_usb: AtomicU32,
27 usb: AtomicU32, 103 usb: AtomicU32,
28 adc: AtomicU32, 104 adc: AtomicU32,
105 // See above re gpin handling being commented out
29 // gpin0: AtomicU32, 106 // gpin0: AtomicU32,
30 // gpin1: AtomicU32, 107 // gpin1: AtomicU32,
31 rosc: AtomicU32, 108 rosc: AtomicU32,
@@ -42,6 +119,7 @@ static CLOCKS: Clocks = Clocks {
42 pll_usb: AtomicU32::new(0), 119 pll_usb: AtomicU32::new(0),
43 usb: AtomicU32::new(0), 120 usb: AtomicU32::new(0),
44 adc: AtomicU32::new(0), 121 adc: AtomicU32::new(0),
122 // See above re gpin handling being commented out
45 // gpin0: AtomicU32::new(0), 123 // gpin0: AtomicU32::new(0),
46 // gpin1: AtomicU32::new(0), 124 // gpin1: AtomicU32::new(0),
47 rosc: AtomicU32::new(0), 125 rosc: AtomicU32::new(0),
@@ -65,10 +143,132 @@ pub enum PeriClkSrc {
65 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, 143 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
66 /// XOSC. 144 /// XOSC.
67 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, 145 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
146 // See above re gpin handling being commented out
68 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , 147 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
69 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 148 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
70} 149}
71 150
151/// Core voltage regulator settings.
152///
153/// The voltage regulator can be configured for different output voltages.
154/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
155#[cfg(feature = "rp2040")]
156#[repr(u8)]
157#[derive(Clone, Copy, Debug, PartialEq, Eq)]
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
159pub enum CoreVoltage {
160 /// 0.80V
161 V0_80 = 0b0000,
162 /// 0.85V
163 V0_85 = 0b0110,
164 /// 0.90V
165 V0_90 = 0b0111,
166 /// 0.95V
167 V0_95 = 0b1000,
168 /// 1.00V
169 V1_00 = 0b1001,
170 /// 1.05V
171 V1_05 = 0b1010,
172 /// 1.10V - Default voltage level
173 V1_10 = 0b1011,
174 /// 1.15V - Required for overclocking to 133-200MHz
175 V1_15 = 0b1100,
176 /// 1.20V
177 V1_20 = 0b1101,
178 /// 1.25V
179 V1_25 = 0b1110,
180 /// 1.30V
181 V1_30 = 0b1111,
182}
183
184/// Core voltage regulator settings.
185///
186/// The voltage regulator can be configured for different output voltages.
187/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
188///
189/// **Note**: The maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit
190/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this
191/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now.
192#[cfg(feature = "_rp235x")]
193#[repr(u8)]
194#[derive(Clone, Copy, Debug, PartialEq, Eq)]
195#[cfg_attr(feature = "defmt", derive(defmt::Format))]
196pub enum CoreVoltage {
197 /// 0.55V
198 V0_55 = 0b00000,
199 /// 0.60V
200 V0_60 = 0b00001,
201 /// 0.65V
202 V0_65 = 0b00010,
203 /// 0.70V
204 V0_70 = 0b00011,
205 /// 0.75V
206 V0_75 = 0b00100,
207 /// 0.80V
208 V0_80 = 0b00101,
209 /// 0.85V
210 V0_85 = 0b00110,
211 /// 0.90V
212 V0_90 = 0b00111,
213 /// 0.95V
214 V0_95 = 0b01000,
215 /// 1.00V
216 V1_00 = 0b01001,
217 /// 1.05V
218 V1_05 = 0b01010,
219 /// 1.10V - Default voltage level
220 V1_10 = 0b01011,
221 /// 1.15V
222 V1_15 = 0b01100,
223 /// 1.20V
224 V1_20 = 0b01101,
225 /// 1.25V
226 V1_25 = 0b01110,
227 /// 1.30V
228 V1_30 = 0b01111,
229}
230
231impl CoreVoltage {
232 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
233 /// Sets the BOD threshold to approximately 80% of the core voltage.
234 fn recommended_bod(self) -> u8 {
235 #[cfg(feature = "rp2040")]
236 match self {
237 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V)
238 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V)
239 CoreVoltage::V0_90 => 0b0110, // 0.731V (~81% of 0.90V)
240 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V)
241 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V)
242 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V)
243 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default
244 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V)
245 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V)
246 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V)
247 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V)
248 }
249 #[cfg(feature = "_rp235x")]
250 match self {
251 CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V)
252 CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V)
253 CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V)
254 CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V)
255 CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V)
256 CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V)
257 CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V)
258 CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V)
259 CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V)
260 CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V)
261 CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V)
262 CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default
263 CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V)
264 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V)
265 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V)
266 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V)
267 // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point)
268 }
269 }
270}
271
72/// CLock configuration. 272/// CLock configuration.
73#[non_exhaustive] 273#[non_exhaustive]
74pub struct ClockConfig { 274pub struct ClockConfig {
@@ -89,12 +289,59 @@ pub struct ClockConfig {
89 /// RTC clock configuration. 289 /// RTC clock configuration.
90 #[cfg(feature = "rp2040")] 290 #[cfg(feature = "rp2040")]
91 pub rtc_clk: Option<RtcClkConfig>, 291 pub rtc_clk: Option<RtcClkConfig>,
292 /// Core voltage scaling. Defaults to 1.10V.
293 pub core_voltage: CoreVoltage,
294 /// Voltage stabilization delay in microseconds.
295 /// If not set, defaults will be used based on voltage level.
296 pub voltage_stabilization_delay_us: Option<u32>,
297 // See above re gpin handling being commented out
92 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 298 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
93 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 299 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
94} 300}
95 301
302impl Default for ClockConfig {
303 /// Creates a minimal default configuration with safe values.
304 ///
305 /// This configuration uses the ring oscillator (ROSC) as the clock source
306 /// and sets minimal defaults that guarantee a working system. It's intended
307 /// as a starting point for manual configuration.
308 ///
309 /// Most users should use one of the more specific configuration functions:
310 /// - `ClockConfig::crystal()` - Standard configuration with external crystal
311 /// - `ClockConfig::rosc()` - Configuration using only the internal oscillator
312 /// - `ClockConfig::system_freq()` - Configuration for a specific system frequency
313 fn default() -> Self {
314 Self {
315 rosc: None,
316 xosc: None,
317 ref_clk: RefClkConfig {
318 src: RefClkSrc::Rosc,
319 div: 1,
320 },
321 sys_clk: SysClkConfig {
322 src: SysClkSrc::Rosc,
323 div_int: 1,
324 div_frac: 0,
325 },
326 peri_clk_src: None,
327 usb_clk: None,
328 adc_clk: None,
329 #[cfg(feature = "rp2040")]
330 rtc_clk: None,
331 core_voltage: CoreVoltage::V1_10,
332 voltage_stabilization_delay_us: None,
333 // See above re gpin handling being commented out
334 // gpin0: None,
335 // gpin1: None,
336 }
337 }
338}
339
96impl ClockConfig { 340impl ClockConfig {
97 /// Clock configuration derived from external crystal. 341 /// Clock configuration derived from external crystal.
342 ///
343 /// This uses default settings for most parameters, suitable for typical use cases.
344 /// For manual control of PLL parameters, use `new_manual()` or modify the struct fields directly.
98 pub fn crystal(crystal_hz: u32) -> Self { 345 pub fn crystal(crystal_hz: u32) -> Self {
99 Self { 346 Self {
100 rosc: Some(RoscConfig { 347 rosc: Some(RoscConfig {
@@ -152,6 +399,9 @@ impl ClockConfig {
152 div_frac: 0, 399 div_frac: 0,
153 phase: 0, 400 phase: 0,
154 }), 401 }),
402 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
403 voltage_stabilization_delay_us: None,
404 // See above re gpin handling being commented out
155 // gpin0: None, 405 // gpin0: None,
156 // gpin1: None, 406 // gpin1: None,
157 } 407 }
@@ -192,26 +442,183 @@ impl ClockConfig {
192 div_frac: 171, 442 div_frac: 171,
193 phase: 0, 443 phase: 0,
194 }), 444 }),
445 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
446 voltage_stabilization_delay_us: None,
447 // See above re gpin handling being commented out
195 // gpin0: None, 448 // gpin0: None,
196 // gpin1: None, 449 // gpin1: None,
197 } 450 }
198 } 451 }
199 452
200 // pub fn bind_gpin<P: GpinPin>(&mut self, gpin: Gpin<'static, P>, hz: u32) { 453 /// Configure clocks derived from an external crystal with specific system frequency.
201 // match P::NR { 454 ///
202 // 0 => self.gpin0 = Some((hz, gpin.into())), 455 /// This function calculates optimal PLL parameters to achieve the requested system
203 // 1 => self.gpin1 = Some((hz, gpin.into())), 456 /// frequency. This only works for the usual 12MHz crystal. In case a different crystal is used,
204 // _ => unreachable!(), 457 /// You will have to set the PLL parameters manually.
205 // } 458 ///
206 // // pin is now provisionally bound. if the config is applied it must be forgotten, 459 /// # Arguments
207 // // or Gpin::drop will deconfigure the clock input. 460 ///
208 // } 461 /// * `sys_freq_hz` - The desired system clock frequency in Hz
462 ///
463 /// # Returns
464 ///
465 /// A ClockConfig configured to achieve the requested system frequency using the
466 /// the usual 12Mhz crystal, or an error if no valid parameters can be found.
467 ///
468 /// # Note on core voltage:
469 ///
470 /// **For RP2040**:
471 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
472 /// - Up to 133MHz: V1_10 (default)
473 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz
474 /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here.
475 /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution.
476 ///
477 /// **For RP235x**:
478 /// At this point in time there is no official manufacturer endorsement for running the chip on other core voltages and/or other clock speeds than the defaults.
479 /// Using this function is experimental and may not work as expected or even damage the chip.
480 ///
481 /// # Returns
482 ///
483 /// A Result containing either the configured ClockConfig or a ClockError.
484 pub fn system_freq(hz: u32) -> Result<Self, ClockError> {
485 // Start with the standard configuration from crystal()
486 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
487 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
488
489 // No need to modify anything if target frequency is already 125MHz
490 // (which is what crystal() configures by default)
491 #[cfg(feature = "rp2040")]
492 if hz == 125_000_000 {
493 return Ok(config);
494 }
495 #[cfg(feature = "_rp235x")]
496 if hz == 150_000_000 {
497 return Ok(config);
498 }
499
500 // Find optimal PLL parameters for the requested frequency
501 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz).ok_or(ClockError::InvalidPllParameters)?;
502
503 // Replace the sys_pll configuration with our custom parameters
504 if let Some(xosc) = &mut config.xosc {
505 xosc.sys_pll = Some(sys_pll_params);
506 }
507
508 // Set the voltage scale based on the target frequency
509 // Higher frequencies require higher voltage
510 #[cfg(feature = "rp2040")]
511 {
512 config.core_voltage = match hz {
513 freq if freq > 133_000_000 => CoreVoltage::V1_15,
514 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
515 };
516 }
517 #[cfg(feature = "_rp235x")]
518 {
519 config.core_voltage = match hz {
520 // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults.
521 // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information.
522 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
523 };
524 }
525
526 Ok(config)
527 }
528
529 /// Configure with manual PLL settings for full control over system clock
530 ///
531 /// This method provides a simple way to configure the system with custom PLL parameters
532 /// without needing to understand the full nested configuration structure.
533 ///
534 /// # Arguments
535 ///
536 /// * `xosc_hz` - The frequency of the external crystal in Hz
537 /// * `pll_config` - The PLL configuration parameters to achieve desired frequency
538 /// * `core_voltage` - Voltage scaling for overclocking (required for >133MHz)
539 ///
540 /// # Returns
541 ///
542 /// A ClockConfig configured with the specified PLL parameters
543 ///
544 /// # Example
545 ///
546 /// ```rust,ignore
547 /// // Configure for 200MHz operation
548 /// let config = Config::default();
549 /// config.clocks = ClockConfig::manual_pll(
550 /// 12_000_000,
551 /// PllConfig {
552 /// refdiv: 1, // Reference divider (12 MHz / 1 = 12 MHz)
553 /// fbdiv: 100, // Feedback divider (12 MHz * 100 = 1200 MHz VCO)
554 /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz)
555 /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz)
556 /// },
557 /// CoreVoltage::V1_15
558 /// );
559 /// ```
560 #[cfg(feature = "rp2040")]
561 pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, core_voltage: CoreVoltage) -> Self {
562 // Validate PLL parameters
563 assert!(pll_config.is_valid(xosc_hz), "Invalid PLL parameters");
564
565 let mut config = Self::default();
566
567 config.xosc = Some(XoscConfig {
568 hz: xosc_hz,
569 sys_pll: Some(pll_config),
570 usb_pll: Some(PllConfig {
571 refdiv: 1,
572 fbdiv: 120,
573 post_div1: 6,
574 post_div2: 5,
575 }),
576 delay_multiplier: 128,
577 });
578
579 config.ref_clk = RefClkConfig {
580 src: RefClkSrc::Xosc,
581 div: 1,
582 };
583
584 config.sys_clk = SysClkConfig {
585 src: SysClkSrc::PllSys,
586 div_int: 1,
587 div_frac: 0,
588 };
589
590 config.core_voltage = core_voltage;
591 config.peri_clk_src = Some(PeriClkSrc::Sys);
592
593 // Set reasonable defaults for other clocks
594 config.usb_clk = Some(UsbClkConfig {
595 src: UsbClkSrc::PllUsb,
596 div: 1,
597 phase: 0,
598 });
599
600 config.adc_clk = Some(AdcClkConfig {
601 src: AdcClkSrc::PllUsb,
602 div: 1,
603 phase: 0,
604 });
605
606 config.rtc_clk = Some(RtcClkConfig {
607 src: RtcClkSrc::PllUsb,
608 div_int: 1024,
609 div_frac: 0,
610 phase: 0,
611 });
612
613 config
614 }
209} 615}
210 616
211/// ROSC freq range. 617/// ROSC freq range.
212#[repr(u16)] 618#[repr(u16)]
213#[non_exhaustive] 619#[non_exhaustive]
214#[derive(Clone, Copy, Debug, PartialEq, Eq)] 620#[derive(Clone, Copy, Debug, PartialEq, Eq)]
621#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub enum RoscRange { 622pub enum RoscRange {
216 /// Low range. 623 /// Low range.
217 Low = pac::rosc::vals::FreqRange::LOW.0, 624 Low = pac::rosc::vals::FreqRange::LOW.0,
@@ -251,6 +658,7 @@ pub struct XoscConfig {
251} 658}
252 659
253/// PLL configuration. 660/// PLL configuration.
661#[derive(Clone, Copy, Debug)]
254pub struct PllConfig { 662pub struct PllConfig {
255 /// Reference divisor. 663 /// Reference divisor.
256 pub refdiv: u8, 664 pub refdiv: u8,
@@ -262,6 +670,50 @@ pub struct PllConfig {
262 pub post_div2: u8, 670 pub post_div2: u8,
263} 671}
264 672
673impl PllConfig {
674 /// Calculate the output frequency for this PLL configuration
675 /// given an input frequency.
676 pub fn output_frequency(&self, input_hz: u32) -> u32 {
677 let ref_freq = input_hz / self.refdiv as u32;
678 let vco_freq = ref_freq * self.fbdiv as u32;
679 vco_freq / ((self.post_div1 * self.post_div2) as u32)
680 }
681
682 /// Check if this PLL configuration is valid for the given input frequency.
683 pub fn is_valid(&self, input_hz: u32) -> bool {
684 // Check divisor constraints
685 if self.refdiv < 1 || self.refdiv > 63 {
686 return false;
687 }
688 if self.fbdiv < 16 || self.fbdiv > 320 {
689 return false;
690 }
691 if self.post_div1 < 1 || self.post_div1 > 7 {
692 return false;
693 }
694 if self.post_div2 < 1 || self.post_div2 > 7 {
695 return false;
696 }
697 if self.post_div2 > self.post_div1 {
698 return false;
699 }
700
701 // Calculate reference frequency
702 let ref_freq = input_hz / self.refdiv as u32;
703
704 // Check reference frequency range
705 if ref_freq < 5_000_000 || ref_freq > 800_000_000 {
706 return false;
707 }
708
709 // Calculate VCO frequency
710 let vco_freq = ref_freq * self.fbdiv as u32;
711
712 // Check VCO frequency range
713 vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000
714 }
715}
716
265/// Reference clock config. 717/// Reference clock config.
266pub struct RefClkConfig { 718pub struct RefClkConfig {
267 /// Reference clock source. 719 /// Reference clock source.
@@ -273,6 +725,7 @@ pub struct RefClkConfig {
273/// Reference clock source. 725/// Reference clock source.
274#[non_exhaustive] 726#[non_exhaustive]
275#[derive(Clone, Copy, Debug, PartialEq, Eq)] 727#[derive(Clone, Copy, Debug, PartialEq, Eq)]
728#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276pub enum RefClkSrc { 729pub enum RefClkSrc {
277 /// XOSC. 730 /// XOSC.
278 Xosc, 731 Xosc,
@@ -280,6 +733,7 @@ pub enum RefClkSrc {
280 Rosc, 733 Rosc,
281 /// PLL USB. 734 /// PLL USB.
282 PllUsb, 735 PllUsb,
736 // See above re gpin handling being commented out
283 // Gpin0, 737 // Gpin0,
284 // Gpin1, 738 // Gpin1,
285} 739}
@@ -287,6 +741,7 @@ pub enum RefClkSrc {
287/// SYS clock source. 741/// SYS clock source.
288#[non_exhaustive] 742#[non_exhaustive]
289#[derive(Clone, Copy, Debug, PartialEq, Eq)] 743#[derive(Clone, Copy, Debug, PartialEq, Eq)]
744#[cfg_attr(feature = "defmt", derive(defmt::Format))]
290pub enum SysClkSrc { 745pub enum SysClkSrc {
291 /// REF. 746 /// REF.
292 Ref, 747 Ref,
@@ -298,6 +753,7 @@ pub enum SysClkSrc {
298 Rosc, 753 Rosc,
299 /// XOSC. 754 /// XOSC.
300 Xosc, 755 Xosc,
756 // See above re gpin handling being commented out
301 // Gpin0, 757 // Gpin0,
302 // Gpin1, 758 // Gpin1,
303} 759}
@@ -324,6 +780,7 @@ pub struct SysClkConfig {
324#[repr(u8)] 780#[repr(u8)]
325#[non_exhaustive] 781#[non_exhaustive]
326#[derive(Clone, Copy, Debug, PartialEq, Eq)] 782#[derive(Clone, Copy, Debug, PartialEq, Eq)]
783#[cfg_attr(feature = "defmt", derive(defmt::Format))]
327pub enum UsbClkSrc { 784pub enum UsbClkSrc {
328 /// PLL USB. 785 /// PLL USB.
329 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, 786 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -333,6 +790,7 @@ pub enum UsbClkSrc {
333 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, 790 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
334 /// XOSC. 791 /// XOSC.
335 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, 792 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
793 // See above re gpin handling being commented out
336 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , 794 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
337 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , 795 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
338} 796}
@@ -351,6 +809,7 @@ pub struct UsbClkConfig {
351#[repr(u8)] 809#[repr(u8)]
352#[non_exhaustive] 810#[non_exhaustive]
353#[derive(Clone, Copy, Debug, PartialEq, Eq)] 811#[derive(Clone, Copy, Debug, PartialEq, Eq)]
812#[cfg_attr(feature = "defmt", derive(defmt::Format))]
354pub enum AdcClkSrc { 813pub enum AdcClkSrc {
355 /// PLL USB. 814 /// PLL USB.
356 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, 815 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -360,6 +819,7 @@ pub enum AdcClkSrc {
360 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 819 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
361 /// XOSC. 820 /// XOSC.
362 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, 821 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
822 // See above re gpin handling being commented out
363 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 823 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
364 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 824 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
365} 825}
@@ -378,6 +838,7 @@ pub struct AdcClkConfig {
378#[repr(u8)] 838#[repr(u8)]
379#[non_exhaustive] 839#[non_exhaustive]
380#[derive(Clone, Copy, Debug, PartialEq, Eq)] 840#[derive(Clone, Copy, Debug, PartialEq, Eq)]
841#[cfg_attr(feature = "defmt", derive(defmt::Format))]
381#[cfg(feature = "rp2040")] 842#[cfg(feature = "rp2040")]
382pub enum RtcClkSrc { 843pub enum RtcClkSrc {
383 /// PLL USB. 844 /// PLL USB.
@@ -388,6 +849,7 @@ pub enum RtcClkSrc {
388 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 849 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
389 /// XOSC. 850 /// XOSC.
390 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, 851 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
852 // See above re gpin handling being commented out
391 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 853 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
392 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 854 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
393} 855}
@@ -405,6 +867,102 @@ pub struct RtcClkConfig {
405 pub phase: u8, 867 pub phase: u8,
406} 868}
407 869
870/// Find valid PLL parameters (refdiv, fbdiv, post_div1, post_div2) for a target output frequency
871/// based on the input frequency.
872///
873/// This function searches for the best PLL configuration to achieve the requested target frequency
874/// while staying within the VCO frequency range of 750MHz to 1800MHz. It prioritizes stability
875/// over exact frequency matching by using larger divisors where possible.
876///
877/// # Parameters
878///
879/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz for th most common one used on rp2040 boards)
880/// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation)
881///
882/// # Returns
883///
884/// * `Some(PllConfig)` if valid parameters were found
885/// * `None` if no valid parameters could be found for the requested combination
886///
887/// # Example
888///
889/// ```rust,ignore
890/// // Find parameters for 133MHz system clock from 12MHz crystal
891/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
892/// ```
893fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
894 // Fixed reference divider for system PLL
895 const PLL_SYS_REFDIV: u8 = 1;
896
897 // Calculate reference frequency
898 let reference_freq = input_hz as u64 / PLL_SYS_REFDIV as u64;
899
900 // Start from highest fbdiv for better stability (like SDK does)
901 for fbdiv in (16..=320).rev() {
902 let vco_freq = reference_freq * fbdiv;
903
904 // Check VCO frequency is within valid range
905 if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 {
906 continue;
907 }
908
909 // Try all possible postdiv combinations starting from larger values
910 // (more conservative/stable approach)
911 for post_div1 in (1..=7).rev() {
912 for post_div2 in (1..=post_div1).rev() {
913 let out_freq = vco_freq / (post_div1 * post_div2);
914
915 // Check if we get the exact target frequency without remainder
916 if out_freq == target_hz as u64 && (vco_freq % (post_div1 * post_div2) == 0) {
917 return Some(PllConfig {
918 refdiv: PLL_SYS_REFDIV,
919 fbdiv: fbdiv as u16,
920 post_div1: post_div1 as u8,
921 post_div2: post_div2 as u8,
922 });
923 }
924 }
925 }
926 }
927
928 // If we couldn't find an exact match, find the closest match
929 let mut best_config = None;
930 let mut min_diff = u32::MAX;
931
932 for fbdiv in (16..=320).rev() {
933 let vco_freq = reference_freq * fbdiv;
934
935 if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 {
936 continue;
937 }
938
939 for post_div1 in (1..=7).rev() {
940 for post_div2 in (1..=post_div1).rev() {
941 let out_freq = (vco_freq / (post_div1 * post_div2) as u64) as u32;
942 let diff = if out_freq > target_hz {
943 out_freq - target_hz
944 } else {
945 target_hz - out_freq
946 };
947
948 // If this is closer to the target, save it
949 if diff < min_diff {
950 min_diff = diff;
951 best_config = Some(PllConfig {
952 refdiv: PLL_SYS_REFDIV,
953 fbdiv: fbdiv as u16,
954 post_div1: post_div1 as u8,
955 post_div2: post_div2 as u8,
956 });
957 }
958 }
959 }
960 }
961
962 // Return the closest match if we found one
963 best_config
964}
965
408/// safety: must be called exactly once at bootup 966/// safety: must be called exactly once at bootup
409pub(crate) unsafe fn init(config: ClockConfig) { 967pub(crate) unsafe fn init(config: ClockConfig) {
410 // Reset everything except: 968 // Reset everything except:
@@ -447,6 +1005,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
447 reset::reset(peris); 1005 reset::reset(peris);
448 reset::unreset_wait(peris); 1006 reset::unreset_wait(peris);
449 1007
1008 // See above re gpin handling being commented out
450 // let gpin0_freq = config.gpin0.map_or(0, |p| { 1009 // let gpin0_freq = config.gpin0.map_or(0, |p| {
451 // core::mem::forget(p.1); 1010 // core::mem::forget(p.1);
452 // p.0 1011 // p.0
@@ -464,19 +1023,80 @@ pub(crate) unsafe fn init(config: ClockConfig) {
464 }; 1023 };
465 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); 1024 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
466 1025
1026 // Set Core Voltage, if we have config for it and we're not using the default
1027 {
1028 let voltage = config.core_voltage;
1029
1030 #[cfg(feature = "rp2040")]
1031 let vreg = pac::VREG_AND_CHIP_RESET;
1032 #[cfg(feature = "_rp235x")]
1033 let vreg = pac::POWMAN;
1034
1035 let current_vsel = vreg.vreg().read().vsel();
1036 let target_vsel = voltage as u8;
1037
1038 // If the target voltage is different from the current one, we need to change it
1039 if target_vsel != current_vsel {
1040 // Set the voltage regulator to the target voltage
1041 #[cfg(feature = "rp2040")]
1042 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
1043 #[cfg(feature = "_rp235x")]
1044 // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers
1045 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register
1046 vreg.vreg().modify(|w| {
1047 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1048 w.set_vsel(target_vsel);
1049 *w
1050 });
1051
1052 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage
1053 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
1054 match voltage {
1055 CoreVoltage::V1_15 => 1000, // 1ms for 1.15V
1056 CoreVoltage::V1_20 | CoreVoltage::V1_25 | CoreVoltage::V1_30 => 2000, // 2ms for higher voltages
1057 _ => 0, // no delay for all others
1058 }
1059 });
1060
1061 if settling_time_us != 0 {
1062 // Delay in microseconds, using the ROSC frequency to calculate cycles
1063 let cycles_per_us = rosc_freq / 1_000_000;
1064 let delay_cycles = settling_time_us * cycles_per_us;
1065 cortex_m::asm::delay(delay_cycles);
1066 }
1067
1068 // Only now set the BOD level. At this point the voltage is considered stable.
1069 #[cfg(feature = "rp2040")]
1070 vreg.bod().write(|w| {
1071 w.set_vsel(voltage.recommended_bod());
1072 w.set_en(true); // Enable brownout detection
1073 });
1074 #[cfg(feature = "_rp235x")]
1075 vreg.bod().write(|w| {
1076 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1077 w.set_vsel(voltage.recommended_bod());
1078 w.set_en(true); // Enable brownout detection
1079 });
1080 }
1081 }
1082
467 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { 1083 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
468 Some(config) => { 1084 Some(config) => {
469 // start XOSC 1085 // start XOSC
470 // datasheet mentions support for clock inputs into XIN, but doesn't go into
471 // how this is achieved. pico-sdk doesn't support this at all.
472 start_xosc(config.hz, config.delay_multiplier); 1086 start_xosc(config.hz, config.delay_multiplier);
473 1087
474 let pll_sys_freq = match config.sys_pll { 1088 let pll_sys_freq = match config.sys_pll {
475 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), 1089 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
1090 Ok(freq) => freq,
1091 Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e),
1092 },
476 None => 0, 1093 None => 0,
477 }; 1094 };
478 let pll_usb_freq = match config.usb_pll { 1095 let pll_usb_freq = match config.usb_pll {
479 Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config), 1096 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
1097 Ok(freq) => freq,
1098 Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
1099 },
480 None => 0, 1100 None => 0,
481 }; 1101 };
482 1102
@@ -484,6 +1104,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
484 } 1104 }
485 None => (0, 0, 0), 1105 None => (0, 0, 0),
486 }; 1106 };
1107
487 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); 1108 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
488 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); 1109 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);
489 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); 1110 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed);
@@ -496,6 +1117,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
496 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), 1117 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div),
497 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), 1118 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div),
498 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), 1119 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div),
1120 // See above re gpin handling being commented out
499 // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), 1121 // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div),
500 // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), 1122 // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div),
501 } 1123 }
@@ -540,6 +1162,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
540 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), 1162 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq),
541 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), 1163 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq),
542 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), 1164 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq),
1165 // See above re gpin handling being commented out
543 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), 1166 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
544 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), 1167 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
545 }; 1168 };
@@ -583,6 +1206,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
583 PeriClkSrc::PllUsb => pll_usb_freq, 1206 PeriClkSrc::PllUsb => pll_usb_freq,
584 PeriClkSrc::Rosc => rosc_freq, 1207 PeriClkSrc::Rosc => rosc_freq,
585 PeriClkSrc::Xosc => xosc_freq, 1208 PeriClkSrc::Xosc => xosc_freq,
1209 // See above re gpin handling being commented out
586 // PeriClkSrc::Gpin0 => gpin0_freq, 1210 // PeriClkSrc::Gpin0 => gpin0_freq,
587 // PeriClkSrc::Gpin1 => gpin1_freq, 1211 // PeriClkSrc::Gpin1 => gpin1_freq,
588 }; 1212 };
@@ -608,6 +1232,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
608 UsbClkSrc::PllSys => pll_sys_freq, 1232 UsbClkSrc::PllSys => pll_sys_freq,
609 UsbClkSrc::Rosc => rosc_freq, 1233 UsbClkSrc::Rosc => rosc_freq,
610 UsbClkSrc::Xosc => xosc_freq, 1234 UsbClkSrc::Xosc => xosc_freq,
1235 // See above re gpin handling being commented out
611 // UsbClkSrc::Gpin0 => gpin0_freq, 1236 // UsbClkSrc::Gpin0 => gpin0_freq,
612 // UsbClkSrc::Gpin1 => gpin1_freq, 1237 // UsbClkSrc::Gpin1 => gpin1_freq,
613 }; 1238 };
@@ -631,6 +1256,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
631 AdcClkSrc::PllSys => pll_sys_freq, 1256 AdcClkSrc::PllSys => pll_sys_freq,
632 AdcClkSrc::Rosc => rosc_freq, 1257 AdcClkSrc::Rosc => rosc_freq,
633 AdcClkSrc::Xosc => xosc_freq, 1258 AdcClkSrc::Xosc => xosc_freq,
1259 // See above re gpin handling being commented out
634 // AdcClkSrc::Gpin0 => gpin0_freq, 1260 // AdcClkSrc::Gpin0 => gpin0_freq,
635 // AdcClkSrc::Gpin1 => gpin1_freq, 1261 // AdcClkSrc::Gpin1 => gpin1_freq,
636 }; 1262 };
@@ -659,6 +1285,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
659 RtcClkSrc::PllSys => pll_sys_freq, 1285 RtcClkSrc::PllSys => pll_sys_freq,
660 RtcClkSrc::Rosc => rosc_freq, 1286 RtcClkSrc::Rosc => rosc_freq,
661 RtcClkSrc::Xosc => xosc_freq, 1287 RtcClkSrc::Xosc => xosc_freq,
1288 // See above re gpin handling being commented out
662 // RtcClkSrc::Gpin0 => gpin0_freq, 1289 // RtcClkSrc::Gpin0 => gpin0_freq,
663 // RtcClkSrc::Gpin1 => gpin1_freq, 1290 // RtcClkSrc::Gpin1 => gpin1_freq,
664 }; 1291 };
@@ -725,6 +1352,7 @@ pub fn xosc_freq() -> u32 {
725 CLOCKS.xosc.load(Ordering::Relaxed) 1352 CLOCKS.xosc.load(Ordering::Relaxed)
726} 1353}
727 1354
1355// See above re gpin handling being commented out
728// pub fn gpin0_freq() -> u32 { 1356// pub fn gpin0_freq() -> u32 {
729// CLOCKS.gpin0.load(Ordering::Relaxed) 1357// CLOCKS.gpin0.load(Ordering::Relaxed)
730// } 1358// }
@@ -773,6 +1401,58 @@ pub fn clk_rtc_freq() -> u16 {
773 CLOCKS.rtc.load(Ordering::Relaxed) 1401 CLOCKS.rtc.load(Ordering::Relaxed)
774} 1402}
775 1403
1404/// The core voltage of the chip.
1405///
1406/// Returns the current core voltage or an error if the voltage register
1407/// contains an unknown value.
1408pub fn core_voltage() -> Result<CoreVoltage, ClockError> {
1409 #[cfg(feature = "rp2040")]
1410 {
1411 let vreg = pac::VREG_AND_CHIP_RESET;
1412 let vsel = vreg.vreg().read().vsel();
1413 match vsel {
1414 0b0000 => Ok(CoreVoltage::V0_80),
1415 0b0110 => Ok(CoreVoltage::V0_85),
1416 0b0111 => Ok(CoreVoltage::V0_90),
1417 0b1000 => Ok(CoreVoltage::V0_95),
1418 0b1001 => Ok(CoreVoltage::V1_00),
1419 0b1010 => Ok(CoreVoltage::V1_05),
1420 0b1011 => Ok(CoreVoltage::V1_10),
1421 0b1100 => Ok(CoreVoltage::V1_15),
1422 0b1101 => Ok(CoreVoltage::V1_20),
1423 0b1110 => Ok(CoreVoltage::V1_25),
1424 0b1111 => Ok(CoreVoltage::V1_30),
1425 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1426 }
1427 }
1428
1429 #[cfg(feature = "_rp235x")]
1430 {
1431 let vreg = pac::POWMAN;
1432 let vsel = vreg.vreg().read().vsel();
1433 match vsel {
1434 0b00000 => Ok(CoreVoltage::V0_55),
1435 0b00001 => Ok(CoreVoltage::V0_60),
1436 0b00010 => Ok(CoreVoltage::V0_65),
1437 0b00011 => Ok(CoreVoltage::V0_70),
1438 0b00100 => Ok(CoreVoltage::V0_75),
1439 0b00101 => Ok(CoreVoltage::V0_80),
1440 0b00110 => Ok(CoreVoltage::V0_85),
1441 0b00111 => Ok(CoreVoltage::V0_90),
1442 0b01000 => Ok(CoreVoltage::V0_95),
1443 0b01001 => Ok(CoreVoltage::V1_00),
1444 0b01010 => Ok(CoreVoltage::V1_05),
1445 0b01011 => Ok(CoreVoltage::V1_10),
1446 0b01100 => Ok(CoreVoltage::V1_15),
1447 0b01101 => Ok(CoreVoltage::V1_20),
1448 0b01110 => Ok(CoreVoltage::V1_25),
1449 0b01111 => Ok(CoreVoltage::V1_30),
1450 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1451 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
1452 }
1453 }
1454}
1455
776fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { 1456fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
777 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; 1457 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256;
778 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); 1458 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16));
@@ -783,46 +1463,100 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
783 while !pac::XOSC.status().read().stable() {} 1463 while !pac::XOSC.status().read().stable() {}
784} 1464}
785 1465
1466/// PLL (Phase-Locked Loop) configuration
786#[inline(always)] 1467#[inline(always)]
787fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { 1468fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, ClockError> {
1469 // Calculate reference frequency
788 let ref_freq = input_freq / config.refdiv as u32; 1470 let ref_freq = input_freq / config.refdiv as u32;
1471
1472 // Validate PLL parameters
1473 // Feedback divider (FBDIV) must be between 16 and 320
789 assert!(config.fbdiv >= 16 && config.fbdiv <= 320); 1474 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
1475
1476 // Post divider 1 (POSTDIV1) must be between 1 and 7
790 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 1477 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
1478
1479 // Post divider 2 (POSTDIV2) must be between 1 and 7
791 assert!(config.post_div2 >= 1 && config.post_div2 <= 7); 1480 assert!(config.post_div2 >= 1 && config.post_div2 <= 7);
1481
1482 // Post divider 2 (POSTDIV2) must be less than or equal to post divider 1 (POSTDIV1)
1483 assert!(config.post_div2 <= config.post_div1);
1484
1485 // Reference divider (REFDIV) must be between 1 and 63
792 assert!(config.refdiv >= 1 && config.refdiv <= 63); 1486 assert!(config.refdiv >= 1 && config.refdiv <= 63);
1487
1488 // Reference frequency (REF_FREQ) must be between 5MHz and 800MHz
793 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); 1489 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000);
1490
1491 // Calculate VCO frequency
794 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); 1492 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32);
1493
1494 // VCO (Voltage Controlled Oscillator) frequency must be between 750MHz and 1800MHz
795 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); 1495 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
796 1496
797 // Load VCO-related dividers before starting VCO 1497 // We follow the SDK's approach to PLL configuration which is:
1498 // 1. Power down PLL
1499 // 2. Configure the reference divider
1500 // 3. Configure the feedback divider
1501 // 4. Power up PLL and VCO
1502 // 5. Wait for PLL to lock
1503 // 6. Configure post-dividers
1504 // 7. Enable post-divider output
1505
1506 // 1. Power down PLL before configuration
1507 p.pwr().write(|w| {
1508 w.set_pd(true); // Power down the PLL
1509 w.set_vcopd(true); // Power down the VCO
1510 w.set_postdivpd(true); // Power down the post divider
1511 w.set_dsmpd(true); // Disable fractional mode
1512 *w
1513 });
1514
1515 // Short delay after powering down
1516 cortex_m::asm::delay(10);
1517
1518 // 2. Configure reference divider first
798 p.cs().write(|w| w.set_refdiv(config.refdiv as _)); 1519 p.cs().write(|w| w.set_refdiv(config.refdiv as _));
1520
1521 // 3. Configure feedback divider
799 p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); 1522 p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv));
800 1523
801 // Turn on PLL 1524 // 4. Power up PLL and VCO, but keep post divider powered down during initial lock
802 let pwr = p.pwr().write(|w| { 1525 p.pwr().write(|w| {
803 w.set_dsmpd(true); // "nothing is achieved by setting this low" 1526 w.set_pd(false); // Power up the PLL
804 w.set_pd(false); 1527 w.set_vcopd(false); // Power up the VCO
805 w.set_vcopd(false); 1528 w.set_postdivpd(true); // Keep post divider powered down during initial lock
806 w.set_postdivpd(true); 1529 w.set_dsmpd(true); // Disable fractional mode (simpler configuration)
807 *w 1530 *w
808 }); 1531 });
809 1532
810 // Wait for PLL to lock 1533 // 5. Wait for PLL to lock with a timeout
811 while !p.cs().read().lock() {} 1534 let mut timeout = 1_000_000;
1535 while !p.cs().read().lock() {
1536 timeout -= 1;
1537 if timeout == 0 {
1538 // PLL failed to lock, return 0 to indicate failure
1539 return Err(ClockError::PllLockTimedOut);
1540 }
1541 }
812 1542
813 // Set post-dividers 1543 // 6. Configure post dividers after PLL is locked
814 p.prim().write(|w| { 1544 p.prim().write(|w| {
815 w.set_postdiv1(config.post_div1); 1545 w.set_postdiv1(config.post_div1);
816 w.set_postdiv2(config.post_div2); 1546 w.set_postdiv2(config.post_div2);
817 }); 1547 });
818 1548
819 // Turn on post divider 1549 // 7. Enable the post divider output
820 p.pwr().write(|w| { 1550 p.pwr().modify(|w| {
821 *w = pwr; 1551 w.set_postdivpd(false); // Power up post divider
822 w.set_postdivpd(false); 1552 *w
823 }); 1553 });
824 1554
825 vco_freq / ((config.post_div1 * config.post_div2) as u32) 1555 // Final delay to ensure everything is stable
1556 cortex_m::asm::delay(100);
1557
1558 // Calculate and return actual output frequency
1559 Ok(vco_freq / ((config.post_div1 * config.post_div2) as u32))
826} 1560}
827 1561
828/// General purpose input clock pin. 1562/// General purpose input clock pin.
@@ -906,6 +1640,7 @@ impl_gpoutpin!(PIN_25, 3);
906pub enum GpoutSrc { 1640pub enum GpoutSrc {
907 /// Sys PLL. 1641 /// Sys PLL.
908 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, 1642 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
1643 // See above re gpin handling being commented out
909 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , 1644 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
910 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , 1645 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
911 /// USB PLL. 1646 /// USB PLL.
@@ -1001,6 +1736,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
1001 1736
1002 let base = match src { 1737 let base = match src {
1003 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), 1738 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
1739 // See above re gpin handling being commented out
1004 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), 1740 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
1005 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), 1741 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
1006 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), 1742 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
@@ -1009,7 +1745,6 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
1009 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 1745 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
1010 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 1746 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
1011 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 1747 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
1012 //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
1013 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 1748 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
1014 _ => unreachable!(), 1749 _ => unreachable!(),
1015 }; 1750 };
@@ -1069,6 +1804,7 @@ impl rand_core::RngCore for RoscRng {
1069 dest.fill_with(Self::next_u8) 1804 dest.fill_with(Self::next_u8)
1070 } 1805 }
1071} 1806}
1807
1072/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks 1808/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks
1073/// and can only be exited through resets, dormant-wake GPIO interrupts, 1809/// and can only be exited through resets, dormant-wake GPIO interrupts,
1074/// and RTC interrupts. If RTC is clocked from an internal clock source 1810/// and RTC interrupts. If RTC is clocked from an internal clock source
@@ -1197,3 +1933,196 @@ pub fn dormant_sleep() {
1197 } 1933 }
1198 } 1934 }
1199} 1935}
1936
1937#[cfg(test)]
1938mod tests {
1939 use super::*;
1940
1941 #[cfg(feature = "rp2040")]
1942 #[test]
1943 fn test_find_pll_params() {
1944 #[cfg(feature = "rp2040")]
1945 {
1946 // Test standard 125 MHz configuration with 12 MHz crystal
1947 let params = find_pll_params(12_000_000, 125_000_000).unwrap();
1948 assert_eq!(params.refdiv, 1);
1949 assert_eq!(params.fbdiv, 125);
1950
1951 // Test USB PLL configuration for 48MHz
1952 // The algorithm may find different valid parameters than the SDK defaults
1953 // We'll check that it generates a valid configuration that produces 48MHz
1954 let params = find_pll_params(12_000_000, 48_000_000).unwrap();
1955 assert_eq!(params.refdiv, 1);
1956
1957 // Calculate the actual output frequency
1958 let ref_freq = 12_000_000 / params.refdiv as u32;
1959 let vco_freq = ref_freq as u64 * params.fbdiv as u64;
1960 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1961
1962 // Verify the output frequency is correct
1963 assert_eq!(output_freq, 48_000_000);
1964
1965 // Verify VCO frequency is in valid range
1966 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
1967
1968 // Test overclocked configuration for 200 MHz
1969 let params = find_pll_params(12_000_000, 200_000_000).unwrap();
1970 assert_eq!(params.refdiv, 1);
1971 let vco_freq = 12_000_000 as u64 * params.fbdiv as u64;
1972 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1973 assert_eq!(output_freq, 200_000_000);
1974 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); // VCO in valid range
1975
1976 // Test non-standard crystal with 16 MHz
1977 let params = find_pll_params(16_000_000, 125_000_000).unwrap();
1978 let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1979 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1980
1981 // Test non-standard crystal with 15 MHz
1982 let params = find_pll_params(15_000_000, 125_000_000).unwrap();
1983 let vco_freq = (15_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1984 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1985
1986 // With a 15 MHz crystal, we might not get exactly 125 MHz
1987 // Check that it's close enough (within 0.2% margin)
1988 let freq_diff = if output_freq > 125_000_000 {
1989 output_freq - 125_000_000
1990 } else {
1991 125_000_000 - output_freq
1992 };
1993 let error_percentage = (freq_diff as f64 / 125_000_000.0) * 100.0;
1994 assert!(
1995 error_percentage < 0.2,
1996 "Output frequency {} is not close enough to target 125 MHz. Error: {:.2}%",
1997 output_freq,
1998 error_percentage
1999 );
2000
2001 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
2002 }
2003 }
2004
2005 #[cfg(feature = "rp2040")]
2006 #[test]
2007 fn test_pll_config_validation() {
2008 // Test PLL configuration validation logic
2009 let valid_config = PllConfig {
2010 refdiv: 1,
2011 fbdiv: 125,
2012 post_div1: 6,
2013 post_div2: 2,
2014 };
2015
2016 // Valid configuration should pass validation
2017 assert!(valid_config.is_valid(12_000_000));
2018
2019 // Test fbdiv constraints
2020 let mut invalid_config = valid_config;
2021 invalid_config.fbdiv = 15; // Below minimum of 16
2022 assert!(!invalid_config.is_valid(12_000_000));
2023
2024 invalid_config.fbdiv = 321; // Above maximum of 320
2025 assert!(!invalid_config.is_valid(12_000_000));
2026
2027 // Test post_div constraints
2028 invalid_config = valid_config;
2029 invalid_config.post_div1 = 0; // Below minimum of 1
2030 assert!(!invalid_config.is_valid(12_000_000));
2031
2032 invalid_config = valid_config;
2033 invalid_config.post_div1 = 8; // Above maximum of 7
2034 assert!(!invalid_config.is_valid(12_000_000));
2035
2036 // Test post_div2 must be <= post_div1
2037 invalid_config = valid_config;
2038 invalid_config.post_div2 = 7;
2039 invalid_config.post_div1 = 3;
2040 assert!(!invalid_config.is_valid(12_000_000));
2041
2042 // Test reference frequency constraints
2043 invalid_config = valid_config;
2044 assert!(!invalid_config.is_valid(4_000_000)); // Below minimum of 5 MHz
2045 assert!(!invalid_config.is_valid(900_000_000)); // Above maximum of 800 MHz
2046
2047 // Test VCO frequency constraints
2048 invalid_config = valid_config;
2049 invalid_config.fbdiv = 16;
2050 assert!(!invalid_config.is_valid(12_000_000)); // VCO too low: 12MHz * 16 = 192MHz
2051
2052 // Test VCO frequency constraints - too high
2053 invalid_config = valid_config;
2054 invalid_config.fbdiv = 200;
2055 invalid_config.refdiv = 1;
2056 // This should be INVALID: 12MHz * 200 = 2400MHz exceeds max VCO of 1800MHz
2057 assert!(!invalid_config.is_valid(12_000_000));
2058
2059 // Test a valid high VCO configuration
2060 invalid_config.fbdiv = 150; // 12MHz * 150 = 1800MHz, exactly at the limit
2061 assert!(invalid_config.is_valid(12_000_000));
2062 }
2063
2064 #[cfg(feature = "rp2040")]
2065 #[test]
2066 fn test_manual_pll_helper() {
2067 {
2068 // Test the new manual_pll helper method
2069 let config = ClockConfig::manual_pll(
2070 12_000_000,
2071 PllConfig {
2072 refdiv: 1,
2073 fbdiv: 100,
2074 post_div1: 3,
2075 post_div2: 2,
2076 },
2077 CoreVoltage::V1_15,
2078 );
2079
2080 // Check voltage scale was set correctly
2081 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2082
2083 // Check PLL config was set correctly
2084 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1);
2085 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().fbdiv, 100);
2086 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div1, 3);
2087 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div2, 2);
2088
2089 // Check we get the expected frequency
2090 assert_eq!(
2091 config
2092 .xosc
2093 .as_ref()
2094 .unwrap()
2095 .sys_pll
2096 .as_ref()
2097 .unwrap()
2098 .output_frequency(12_000_000),
2099 200_000_000
2100 );
2101 }
2102 }
2103
2104 #[cfg(feature = "rp2040")]
2105 #[test]
2106 fn test_auto_voltage_scaling() {
2107 {
2108 // Test automatic voltage scaling based on frequency
2109 // Under 133 MHz should use default voltage (V1_10)
2110 let config = ClockConfig::system_freq(125_000_000).unwrap();
2111 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2112
2113 // 133-200 MHz should use V1_15
2114 let config = ClockConfig::system_freq(150_000_000).unwrap();
2115 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2116 let config = ClockConfig::system_freq(200_000_000).unwrap();
2117 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2118
2119 // Above 200 MHz should use V1_15
2120 let config = ClockConfig::system_freq(250_000_000).unwrap();
2121 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2122
2123 // Below 125 MHz should use V1_10
2124 let config = ClockConfig::system_freq(100_000_000).unwrap();
2125 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2126 }
2127 }
2128}
diff --git a/embassy-rp/src/pio_programs/clock_divider.rs b/embassy-rp/src/pio_programs/clock_divider.rs
new file mode 100644
index 000000000..02e353f53
--- /dev/null
+++ b/embassy-rp/src/pio_programs/clock_divider.rs
@@ -0,0 +1,25 @@
1//! Helper functions for calculating PIO clock dividers
2
3use fixed::traits::ToFixed;
4use fixed::types::extra::U8;
5
6use crate::clocks::clk_sys_freq;
7
8/// Calculate a PIO clock divider value based on the desired target frequency.
9///
10/// # Arguments
11///
12/// * `target_hz` - The desired PIO clock frequency in Hz
13///
14/// # Returns
15///
16/// A fixed-point divider value suitable for use in a PIO state machine configuration
17#[inline]
18pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> {
19 // Requires a non-zero frequency
20 assert!(target_hz > 0, "PIO clock frequency cannot be zero");
21
22 // Calculate the divider
23 let divider = (clk_sys_freq() + target_hz / 2) / target_hz;
24 divider.to_fixed()
25}
diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs
index 5846a8027..546c85a89 100644
--- a/embassy-rp/src/pio_programs/hd44780.rs
+++ b/embassy-rp/src/pio_programs/hd44780.rs
@@ -5,6 +5,7 @@ use crate::pio::{
5 Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, 5 Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
6 StateMachine, 6 StateMachine,
7}; 7};
8use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
8use crate::Peri; 9use crate::Peri;
9 10
10/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>) 11/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
@@ -134,7 +135,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
134 135
135 let mut cfg = Config::default(); 136 let mut cfg = Config::default();
136 cfg.use_program(&word_prg.prg, &[&e]); 137 cfg.use_program(&word_prg.prg, &[&e]);
137 cfg.clock_divider = 125u8.into(); 138
139 // Target 1 MHz PIO clock (each cycle is 1µs)
140 cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
141
138 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); 142 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
139 cfg.shift_out = ShiftConfig { 143 cfg.shift_out = ShiftConfig {
140 auto_fill: true, 144 auto_fill: true,
@@ -160,7 +164,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
160 164
161 let mut cfg = Config::default(); 165 let mut cfg = Config::default();
162 cfg.use_program(&seq_prg.prg, &[&e]); 166 cfg.use_program(&seq_prg.prg, &[&e]);
163 cfg.clock_divider = 8u8.into(); // ~64ns/insn 167
168 // Target ~15.6 MHz PIO clock (~64ns/insn)
169 cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
170
164 cfg.set_jmp_pin(&db7); 171 cfg.set_jmp_pin(&db7);
165 cfg.set_set_pins(&[&rs, &rw]); 172 cfg.set_set_pins(&[&rs, &rw]);
166 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); 173 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs
index 74537825b..8eac328b3 100644
--- a/embassy-rp/src/pio_programs/mod.rs
+++ b/embassy-rp/src/pio_programs/mod.rs
@@ -1,5 +1,6 @@
1//! Pre-built pio programs for common interfaces 1//! Pre-built pio programs for common interfaces
2 2
3pub mod clock_divider;
3pub mod hd44780; 4pub mod hd44780;
4pub mod i2s; 5pub mod i2s;
5pub mod onewire; 6pub mod onewire;
diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs
index e520da8a3..70b3795e9 100644
--- a/embassy-rp/src/pio_programs/rotary_encoder.rs
+++ b/embassy-rp/src/pio_programs/rotary_encoder.rs
@@ -1,11 +1,10 @@
1//! PIO backed quadrature encoder 1//! PIO backed quadrature encoder
2 2
3use fixed::traits::ToFixed;
4
5use crate::gpio::Pull; 3use crate::gpio::Pull;
6use crate::pio::{ 4use crate::pio::{
7 Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, 5 Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
8}; 6};
7use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
9use crate::Peri; 8use crate::Peri;
10 9
11/// This struct represents an Encoder program loaded into pio instruction memory. 10/// This struct represents an Encoder program loaded into pio instruction memory.
@@ -48,7 +47,10 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
48 cfg.set_in_pins(&[&pin_a, &pin_b]); 47 cfg.set_in_pins(&[&pin_a, &pin_b]);
49 cfg.fifo_join = FifoJoin::RxOnly; 48 cfg.fifo_join = FifoJoin::RxOnly;
50 cfg.shift_in.direction = ShiftDirection::Left; 49 cfg.shift_in.direction = ShiftDirection::Left;
51 cfg.clock_divider = 10_000.to_fixed(); 50
51 // Target 12.5 KHz PIO clock
52 cfg.clock_divider = calculate_pio_clock_divider(12_500);
53
52 cfg.use_program(&program.prg, &[]); 54 cfg.use_program(&program.prg, &[]);
53 sm.set_config(&cfg); 55 sm.set_config(&cfg);
54 sm.set_enable(true); 56 sm.set_enable(true);
diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs
index 495191659..0e9a8daf9 100644
--- a/embassy-rp/src/pio_programs/stepper.rs
+++ b/embassy-rp/src/pio_programs/stepper.rs
@@ -2,11 +2,8 @@
2 2
3use core::mem::{self, MaybeUninit}; 3use core::mem::{self, MaybeUninit};
4 4
5use fixed::traits::ToFixed;
6use fixed::types::extra::U8;
7use fixed::FixedU32;
8
9use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; 5use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
6use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
10use crate::Peri; 7use crate::Peri;
11 8
12/// This struct represents a Stepper driver program loaded into pio instruction memory. 9/// This struct represents a Stepper driver program loaded into pio instruction memory.
@@ -64,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
64 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); 61 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
65 let mut cfg = Config::default(); 62 let mut cfg = Config::default();
66 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); 63 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
67 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); 64
65 cfg.clock_divider = calculate_pio_clock_divider(100 * 136);
66
68 cfg.use_program(&program.prg, &[]); 67 cfg.use_program(&program.prg, &[]);
69 sm.set_config(&cfg); 68 sm.set_config(&cfg);
70 sm.set_enable(true); 69 sm.set_enable(true);
@@ -73,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
73 72
74 /// Set pulse frequency 73 /// Set pulse frequency
75 pub fn set_frequency(&mut self, freq: u32) { 74 pub fn set_frequency(&mut self, freq: u32) {
76 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); 75 let clock_divider = calculate_pio_clock_divider(freq * 136);
77 assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); 76 let divider_f32 = clock_divider.to_num::<f32>();
78 assert!(clock_divider >= 1, "clkdiv must be >= 1"); 77 assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536");
78 assert!(divider_f32 >= 1.0, "clkdiv must be >= 1");
79
79 self.sm.set_clock_divider(clock_divider); 80 self.sm.set_clock_divider(clock_divider);
80 self.sm.clkdiv_restart(); 81 self.sm.clkdiv_restart();
81 } 82 }
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index da18138b5..02649ad81 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -34,28 +34,29 @@ impl State {
34} 34}
35 35
36/// Buffered UART driver. 36/// Buffered UART driver.
37pub struct BufferedUart<'d, T: Instance> { 37pub struct BufferedUart {
38 pub(crate) rx: BufferedUartRx<'d, T>, 38 pub(super) rx: BufferedUartRx,
39 pub(crate) tx: BufferedUartTx<'d, T>, 39 pub(super) tx: BufferedUartTx,
40} 40}
41 41
42/// Buffered UART RX handle. 42/// Buffered UART RX handle.
43pub struct BufferedUartRx<'d, T: Instance> { 43pub struct BufferedUartRx {
44 pub(crate) phantom: PhantomData<&'d mut T>, 44 pub(super) info: &'static Info,
45 pub(super) state: &'static State,
45} 46}
46 47
47/// Buffered UART TX handle. 48/// Buffered UART TX handle.
48pub struct BufferedUartTx<'d, T: Instance> { 49pub struct BufferedUartTx {
49 pub(crate) phantom: PhantomData<&'d mut T>, 50 pub(super) info: &'static Info,
51 pub(super) state: &'static State,
50} 52}
51 53
52pub(crate) fn init_buffers<'d, T: Instance + 'd>( 54pub(super) fn init_buffers<'d>(
53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 55 info: &Info,
56 state: &State,
54 tx_buffer: Option<&'d mut [u8]>, 57 tx_buffer: Option<&'d mut [u8]>,
55 rx_buffer: Option<&'d mut [u8]>, 58 rx_buffer: Option<&'d mut [u8]>,
56) { 59) {
57 let state = T::buffered_state();
58
59 if let Some(tx_buffer) = tx_buffer { 60 if let Some(tx_buffer) = tx_buffer {
60 let len = tx_buffer.len(); 61 let len = tx_buffer.len();
61 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 62 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
@@ -76,61 +77,73 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
76 // This means we can leave the interrupt enabled the whole time as long as 77 // This means we can leave the interrupt enabled the whole time as long as
77 // we clear it after it happens. The downside is that the we manually have 78 // we clear it after it happens. The downside is that the we manually have
78 // to pend the ISR when we want data transmission to start. 79 // to pend the ISR when we want data transmission to start.
79 let regs = T::regs(); 80 info.regs.uartimsc().write(|w| {
80 regs.uartimsc().write(|w| {
81 w.set_rxim(true); 81 w.set_rxim(true);
82 w.set_rtim(true); 82 w.set_rtim(true);
83 w.set_txim(true); 83 w.set_txim(true);
84 }); 84 });
85 85
86 T::Interrupt::unpend(); 86 info.interrupt.unpend();
87 unsafe { T::Interrupt::enable() }; 87 unsafe { info.interrupt.enable() };
88} 88}
89 89
90impl<'d, T: Instance> BufferedUart<'d, T> { 90impl BufferedUart {
91 /// Create a buffered UART instance. 91 /// Create a buffered UART instance.
92 pub fn new( 92 pub fn new<'d, T: Instance>(
93 _uart: Peri<'d, T>, 93 _uart: Peri<'d, T>,
94 tx: Peri<'d, impl TxPin<T>>, 94 tx: Peri<'d, impl TxPin<T>>,
95 rx: Peri<'d, impl RxPin<T>>, 95 rx: Peri<'d, impl RxPin<T>>,
96 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 96 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
97 tx_buffer: &'d mut [u8], 97 tx_buffer: &'d mut [u8],
98 rx_buffer: &'d mut [u8], 98 rx_buffer: &'d mut [u8],
99 config: Config, 99 config: Config,
100 ) -> Self { 100 ) -> Self {
101 super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config); 101 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, config);
102 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 102 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
103 103
104 Self { 104 Self {
105 rx: BufferedUartRx { phantom: PhantomData }, 105 rx: BufferedUartRx {
106 tx: BufferedUartTx { phantom: PhantomData }, 106 info: T::info(),
107 state: T::buffered_state(),
108 },
109 tx: BufferedUartTx {
110 info: T::info(),
111 state: T::buffered_state(),
112 },
107 } 113 }
108 } 114 }
109 115
110 /// Create a buffered UART instance with flow control. 116 /// Create a buffered UART instance with flow control.
111 pub fn new_with_rtscts( 117 pub fn new_with_rtscts<'d, T: Instance>(
112 _uart: Peri<'d, T>, 118 _uart: Peri<'d, T>,
113 tx: Peri<'d, impl TxPin<T>>, 119 tx: Peri<'d, impl TxPin<T>>,
114 rx: Peri<'d, impl RxPin<T>>, 120 rx: Peri<'d, impl RxPin<T>>,
115 rts: Peri<'d, impl RtsPin<T>>, 121 rts: Peri<'d, impl RtsPin<T>>,
116 cts: Peri<'d, impl CtsPin<T>>, 122 cts: Peri<'d, impl CtsPin<T>>,
117 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 123 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
118 tx_buffer: &'d mut [u8], 124 tx_buffer: &'d mut [u8],
119 rx_buffer: &'d mut [u8], 125 rx_buffer: &'d mut [u8],
120 config: Config, 126 config: Config,
121 ) -> Self { 127 ) -> Self {
122 super::Uart::<'d, T, Async>::init( 128 super::Uart::<'d, Async>::init(
129 T::info(),
123 Some(tx.into()), 130 Some(tx.into()),
124 Some(rx.into()), 131 Some(rx.into()),
125 Some(rts.into()), 132 Some(rts.into()),
126 Some(cts.into()), 133 Some(cts.into()),
127 config, 134 config,
128 ); 135 );
129 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 136 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
130 137
131 Self { 138 Self {
132 rx: BufferedUartRx { phantom: PhantomData }, 139 rx: BufferedUartRx {
133 tx: BufferedUartTx { phantom: PhantomData }, 140 info: T::info(),
141 state: T::buffered_state(),
142 },
143 tx: BufferedUartTx {
144 info: T::info(),
145 state: T::buffered_state(),
146 },
134 } 147 }
135 } 148 }
136 149
@@ -160,68 +173,75 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
160 } 173 }
161 174
162 /// sets baudrate on runtime 175 /// sets baudrate on runtime
163 pub fn set_baudrate(&mut self, baudrate: u32) { 176 pub fn set_baudrate<'d>(&mut self, baudrate: u32) {
164 super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate); 177 super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate);
165 } 178 }
166 179
167 /// Split into separate RX and TX handles. 180 /// Split into separate RX and TX handles.
168 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { 181 pub fn split(self) -> (BufferedUartTx, BufferedUartRx) {
169 (self.tx, self.rx) 182 (self.tx, self.rx)
170 } 183 }
171 184
172 /// Split the Uart into a transmitter and receiver by mutable reference, 185 /// Split the Uart into a transmitter and receiver by mutable reference,
173 /// which is particularly useful when having two tasks correlating to 186 /// which is particularly useful when having two tasks correlating to
174 /// transmitting and receiving. 187 /// transmitting and receiving.
175 pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) { 188 pub fn split_ref(&mut self) -> (&mut BufferedUartTx, &mut BufferedUartRx) {
176 (&mut self.tx, &mut self.rx) 189 (&mut self.tx, &mut self.rx)
177 } 190 }
178} 191}
179 192
180impl<'d, T: Instance> BufferedUartRx<'d, T> { 193impl BufferedUartRx {
181 /// Create a new buffered UART RX. 194 /// Create a new buffered UART RX.
182 pub fn new( 195 pub fn new<'d, T: Instance>(
183 _uart: Peri<'d, T>, 196 _uart: Peri<'d, T>,
184 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 197 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
185 rx: Peri<'d, impl RxPin<T>>, 198 rx: Peri<'d, impl RxPin<T>>,
186 rx_buffer: &'d mut [u8], 199 rx_buffer: &'d mut [u8],
187 config: Config, 200 config: Config,
188 ) -> Self { 201 ) -> Self {
189 super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config); 202 super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config);
190 init_buffers::<T>(irq, None, Some(rx_buffer)); 203 init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
191 204
192 Self { phantom: PhantomData } 205 Self {
206 info: T::info(),
207 state: T::buffered_state(),
208 }
193 } 209 }
194 210
195 /// Create a new buffered UART RX with flow control. 211 /// Create a new buffered UART RX with flow control.
196 pub fn new_with_rts( 212 pub fn new_with_rts<'d, T: Instance>(
197 _uart: Peri<'d, T>, 213 _uart: Peri<'d, T>,
198 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 214 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
199 rx: Peri<'d, impl RxPin<T>>, 215 rx: Peri<'d, impl RxPin<T>>,
200 rts: Peri<'d, impl RtsPin<T>>, 216 rts: Peri<'d, impl RtsPin<T>>,
201 rx_buffer: &'d mut [u8], 217 rx_buffer: &'d mut [u8],
202 config: Config, 218 config: Config,
203 ) -> Self { 219 ) -> Self {
204 super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config); 220 super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config);
205 init_buffers::<T>(irq, None, Some(rx_buffer)); 221 init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
206 222
207 Self { phantom: PhantomData } 223 Self {
224 info: T::info(),
225 state: T::buffered_state(),
226 }
208 } 227 }
209 228
210 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a 229 fn read<'a>(
211 where 230 info: &'static Info,
212 T: 'd, 231 state: &'static State,
213 { 232 buf: &'a mut [u8],
233 ) -> impl Future<Output = Result<usize, Error>> + 'a {
214 poll_fn(move |cx| { 234 poll_fn(move |cx| {
215 if let Poll::Ready(r) = Self::try_read(buf) { 235 if let Poll::Ready(r) = Self::try_read(info, state, buf) {
216 return Poll::Ready(r); 236 return Poll::Ready(r);
217 } 237 }
218 T::buffered_state().rx_waker.register(cx.waker()); 238 state.rx_waker.register(cx.waker());
219 Poll::Pending 239 Poll::Pending
220 }) 240 })
221 } 241 }
222 242
223 fn get_rx_error() -> Option<Error> { 243 fn get_rx_error(state: &State) -> Option<Error> {
224 let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed); 244 let errs = state.rx_error.swap(0, Ordering::Relaxed);
225 if errs & RXE_OVERRUN != 0 { 245 if errs & RXE_OVERRUN != 0 {
226 Some(Error::Overrun) 246 Some(Error::Overrun)
227 } else if errs & RXE_BREAK != 0 { 247 } else if errs & RXE_BREAK != 0 {
@@ -235,15 +255,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
235 } 255 }
236 } 256 }
237 257
238 fn try_read(buf: &mut [u8]) -> Poll<Result<usize, Error>> 258 fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
239 where
240 T: 'd,
241 {
242 if buf.is_empty() { 259 if buf.is_empty() {
243 return Poll::Ready(Ok(0)); 260 return Poll::Ready(Ok(0));
244 } 261 }
245 262
246 let state = T::buffered_state();
247 let mut rx_reader = unsafe { state.rx_buf.reader() }; 263 let mut rx_reader = unsafe { state.rx_buf.reader() };
248 let n = rx_reader.pop(|data| { 264 let n = rx_reader.pop(|data| {
249 let n = data.len().min(buf.len()); 265 let n = data.len().min(buf.len());
@@ -252,7 +268,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
252 }); 268 });
253 269
254 let result = if n == 0 { 270 let result = if n == 0 {
255 match Self::get_rx_error() { 271 match Self::get_rx_error(state) {
256 None => return Poll::Pending, 272 None => return Poll::Pending,
257 Some(e) => Err(e), 273 Some(e) => Err(e),
258 } 274 }
@@ -262,8 +278,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
262 278
263 // (Re-)Enable the interrupt to receive more data in case it was 279 // (Re-)Enable the interrupt to receive more data in case it was
264 // disabled because the buffer was full or errors were detected. 280 // disabled because the buffer was full or errors were detected.
265 let regs = T::regs(); 281 info.regs.uartimsc().write_set(|w| {
266 regs.uartimsc().write_set(|w| {
267 w.set_rxim(true); 282 w.set_rxim(true);
268 w.set_rtim(true); 283 w.set_rtim(true);
269 }); 284 });
@@ -274,23 +289,19 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
274 /// Read from UART RX buffer blocking execution until done. 289 /// Read from UART RX buffer blocking execution until done.
275 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 290 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
276 loop { 291 loop {
277 match Self::try_read(buf) { 292 match Self::try_read(self.info, self.state, buf) {
278 Poll::Ready(res) => return res, 293 Poll::Ready(res) => return res,
279 Poll::Pending => continue, 294 Poll::Pending => continue,
280 } 295 }
281 } 296 }
282 } 297 }
283 298
284 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> 299 fn fill_buf<'a>(state: &'static State) -> impl Future<Output = Result<&'a [u8], Error>> {
285 where
286 T: 'd,
287 {
288 poll_fn(move |cx| { 300 poll_fn(move |cx| {
289 let state = T::buffered_state();
290 let mut rx_reader = unsafe { state.rx_buf.reader() }; 301 let mut rx_reader = unsafe { state.rx_buf.reader() };
291 let (p, n) = rx_reader.pop_buf(); 302 let (p, n) = rx_reader.pop_buf();
292 let result = if n == 0 { 303 let result = if n == 0 {
293 match Self::get_rx_error() { 304 match Self::get_rx_error(state) {
294 None => { 305 None => {
295 state.rx_waker.register(cx.waker()); 306 state.rx_waker.register(cx.waker());
296 return Poll::Pending; 307 return Poll::Pending;
@@ -306,64 +317,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
306 }) 317 })
307 } 318 }
308 319
309 fn consume(amt: usize) { 320 fn consume(info: &Info, state: &State, amt: usize) {
310 let state = T::buffered_state();
311 let mut rx_reader = unsafe { state.rx_buf.reader() }; 321 let mut rx_reader = unsafe { state.rx_buf.reader() };
312 rx_reader.pop_done(amt); 322 rx_reader.pop_done(amt);
313 323
314 // (Re-)Enable the interrupt to receive more data in case it was 324 // (Re-)Enable the interrupt to receive more data in case it was
315 // disabled because the buffer was full or errors were detected. 325 // disabled because the buffer was full or errors were detected.
316 let regs = T::regs(); 326 info.regs.uartimsc().write_set(|w| {
317 regs.uartimsc().write_set(|w| {
318 w.set_rxim(true); 327 w.set_rxim(true);
319 w.set_rtim(true); 328 w.set_rtim(true);
320 }); 329 });
321 } 330 }
322 331
323 /// we are ready to read if there is data in the buffer 332 /// we are ready to read if there is data in the buffer
324 fn read_ready() -> Result<bool, Error> { 333 fn read_ready(state: &State) -> Result<bool, Error> {
325 let state = T::buffered_state();
326 Ok(!state.rx_buf.is_empty()) 334 Ok(!state.rx_buf.is_empty())
327 } 335 }
328} 336}
329 337
330impl<'d, T: Instance> BufferedUartTx<'d, T> { 338impl BufferedUartTx {
331 /// Create a new buffered UART TX. 339 /// Create a new buffered UART TX.
332 pub fn new( 340 pub fn new<'d, T: Instance>(
333 _uart: Peri<'d, T>, 341 _uart: Peri<'d, T>,
334 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 342 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
335 tx: Peri<'d, impl TxPin<T>>, 343 tx: Peri<'d, impl TxPin<T>>,
336 tx_buffer: &'d mut [u8], 344 tx_buffer: &'d mut [u8],
337 config: Config, 345 config: Config,
338 ) -> Self { 346 ) -> Self {
339 super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config); 347 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config);
340 init_buffers::<T>(irq, Some(tx_buffer), None); 348 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
341 349
342 Self { phantom: PhantomData } 350 Self {
351 info: T::info(),
352 state: T::buffered_state(),
353 }
343 } 354 }
344 355
345 /// Create a new buffered UART TX with flow control. 356 /// Create a new buffered UART TX with flow control.
346 pub fn new_with_cts( 357 pub fn new_with_cts<'d, T: Instance>(
347 _uart: Peri<'d, T>, 358 _uart: Peri<'d, T>,
348 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 359 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
349 tx: Peri<'d, impl TxPin<T>>, 360 tx: Peri<'d, impl TxPin<T>>,
350 cts: Peri<'d, impl CtsPin<T>>, 361 cts: Peri<'d, impl CtsPin<T>>,
351 tx_buffer: &'d mut [u8], 362 tx_buffer: &'d mut [u8],
352 config: Config, 363 config: Config,
353 ) -> Self { 364 ) -> Self {
354 super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config); 365 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config);
355 init_buffers::<T>(irq, Some(tx_buffer), None); 366 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
356 367
357 Self { phantom: PhantomData } 368 Self {
369 info: T::info(),
370 state: T::buffered_state(),
371 }
358 } 372 }
359 373
360 fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ { 374 fn write<'d>(
375 info: &'static Info,
376 state: &'static State,
377 buf: &'d [u8],
378 ) -> impl Future<Output = Result<usize, Error>> + 'd {
361 poll_fn(move |cx| { 379 poll_fn(move |cx| {
362 if buf.is_empty() { 380 if buf.is_empty() {
363 return Poll::Ready(Ok(0)); 381 return Poll::Ready(Ok(0));
364 } 382 }
365 383
366 let state = T::buffered_state();
367 let mut tx_writer = unsafe { state.tx_buf.writer() }; 384 let mut tx_writer = unsafe { state.tx_buf.writer() };
368 let n = tx_writer.push(|data| { 385 let n = tx_writer.push(|data| {
369 let n = data.len().min(buf.len()); 386 let n = data.len().min(buf.len());
@@ -379,14 +396,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
379 // FIFO and the number of bytes drops below a threshold. When the 396 // FIFO and the number of bytes drops below a threshold. When the
380 // FIFO was empty we have to manually pend the interrupt to shovel 397 // FIFO was empty we have to manually pend the interrupt to shovel
381 // TX data from the buffer into the FIFO. 398 // TX data from the buffer into the FIFO.
382 T::Interrupt::pend(); 399 info.interrupt.pend();
383 Poll::Ready(Ok(n)) 400 Poll::Ready(Ok(n))
384 }) 401 })
385 } 402 }
386 403
387 fn flush() -> impl Future<Output = Result<(), Error>> { 404 fn flush(state: &'static State) -> impl Future<Output = Result<(), Error>> {
388 poll_fn(move |cx| { 405 poll_fn(move |cx| {
389 let state = T::buffered_state();
390 if !state.tx_buf.is_empty() { 406 if !state.tx_buf.is_empty() {
391 state.tx_waker.register(cx.waker()); 407 state.tx_waker.register(cx.waker());
392 return Poll::Pending; 408 return Poll::Pending;
@@ -403,8 +419,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
403 } 419 }
404 420
405 loop { 421 loop {
406 let state = T::buffered_state(); 422 let mut tx_writer = unsafe { self.state.tx_buf.writer() };
407 let mut tx_writer = unsafe { state.tx_buf.writer() };
408 let n = tx_writer.push(|data| { 423 let n = tx_writer.push(|data| {
409 let n = data.len().min(buf.len()); 424 let n = data.len().min(buf.len());
410 data[..n].copy_from_slice(&buf[..n]); 425 data[..n].copy_from_slice(&buf[..n]);
@@ -416,7 +431,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
416 // FIFO and the number of bytes drops below a threshold. When the 431 // FIFO and the number of bytes drops below a threshold. When the
417 // FIFO was empty we have to manually pend the interrupt to shovel 432 // FIFO was empty we have to manually pend the interrupt to shovel
418 // TX data from the buffer into the FIFO. 433 // TX data from the buffer into the FIFO.
419 T::Interrupt::pend(); 434 self.info.interrupt.pend();
420 return Ok(n); 435 return Ok(n);
421 } 436 }
422 } 437 }
@@ -425,8 +440,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
425 /// Flush UART TX blocking execution until done. 440 /// Flush UART TX blocking execution until done.
426 pub fn blocking_flush(&mut self) -> Result<(), Error> { 441 pub fn blocking_flush(&mut self) -> Result<(), Error> {
427 loop { 442 loop {
428 let state = T::buffered_state(); 443 if self.state.tx_buf.is_empty() {
429 if state.tx_buf.is_empty() {
430 return Ok(()); 444 return Ok(());
431 } 445 }
432 } 446 }
@@ -434,7 +448,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
434 448
435 /// Check if UART is busy. 449 /// Check if UART is busy.
436 pub fn busy(&self) -> bool { 450 pub fn busy(&self) -> bool {
437 T::regs().uartfr().read().busy() 451 self.info.regs.uartfr().read().busy()
438 } 452 }
439 453
440 /// Assert a break condition after waiting for the transmit buffers to empty, 454 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -445,7 +459,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
445 /// This method may block for a long amount of time since it has to wait 459 /// This method may block for a long amount of time since it has to wait
446 /// for the transmit fifo to empty, which may take a while on slow links. 460 /// for the transmit fifo to empty, which may take a while on slow links.
447 pub async fn send_break(&mut self, bits: u32) { 461 pub async fn send_break(&mut self, bits: u32) {
448 let regs = T::regs(); 462 let regs = self.info.regs;
449 let bits = bits.max({ 463 let bits = bits.max({
450 let lcr = regs.uartlcr_h().read(); 464 let lcr = regs.uartlcr_h().read();
451 let width = lcr.wlen() as u32 + 5; 465 let width = lcr.wlen() as u32 + 5;
@@ -458,7 +472,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
458 let div_clk = clk_peri_freq() as u64 * 64; 472 let div_clk = clk_peri_freq() as u64 * 64;
459 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 473 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
460 474
461 Self::flush().await.unwrap(); 475 Self::flush(self.state).await.unwrap();
462 while self.busy() {} 476 while self.busy() {}
463 regs.uartlcr_h().write_set(|w| w.set_brk(true)); 477 regs.uartlcr_h().write_set(|w| w.set_brk(true));
464 Timer::after_micros(wait_usecs).await; 478 Timer::after_micros(wait_usecs).await;
@@ -466,28 +480,26 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
466 } 480 }
467} 481}
468 482
469impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 483impl Drop for BufferedUartRx {
470 fn drop(&mut self) { 484 fn drop(&mut self) {
471 let state = T::buffered_state(); 485 unsafe { self.state.rx_buf.deinit() }
472 unsafe { state.rx_buf.deinit() }
473 486
474 // TX is inactive if the buffer is not available. 487 // TX is inactive if the buffer is not available.
475 // We can now unregister the interrupt handler 488 // We can now unregister the interrupt handler
476 if !state.tx_buf.is_available() { 489 if !self.state.tx_buf.is_available() {
477 T::Interrupt::disable(); 490 self.info.interrupt.disable();
478 } 491 }
479 } 492 }
480} 493}
481 494
482impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { 495impl Drop for BufferedUartTx {
483 fn drop(&mut self) { 496 fn drop(&mut self) {
484 let state = T::buffered_state(); 497 unsafe { self.state.tx_buf.deinit() }
485 unsafe { state.tx_buf.deinit() }
486 498
487 // RX is inactive if the buffer is not available. 499 // RX is inactive if the buffer is not available.
488 // We can now unregister the interrupt handler 500 // We can now unregister the interrupt handler
489 if !state.rx_buf.is_available() { 501 if !self.state.rx_buf.is_available() {
490 T::Interrupt::disable(); 502 self.info.interrupt.disable();
491 } 503 }
492 } 504 }
493} 505}
@@ -499,7 +511,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
499 511
500impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> { 512impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
501 unsafe fn on_interrupt() { 513 unsafe fn on_interrupt() {
502 let r = T::regs(); 514 let r = T::info().regs;
503 if r.uartdmacr().read().rxdmae() { 515 if r.uartdmacr().read().rxdmae() {
504 return; 516 return;
505 } 517 }
@@ -603,95 +615,95 @@ impl embedded_io::Error for Error {
603 } 615 }
604} 616}
605 617
606impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> { 618impl embedded_io_async::ErrorType for BufferedUart {
607 type Error = Error; 619 type Error = Error;
608} 620}
609 621
610impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> { 622impl embedded_io_async::ErrorType for BufferedUartRx {
611 type Error = Error; 623 type Error = Error;
612} 624}
613 625
614impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> { 626impl embedded_io_async::ErrorType for BufferedUartTx {
615 type Error = Error; 627 type Error = Error;
616} 628}
617 629
618impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> { 630impl embedded_io_async::Read for BufferedUart {
619 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 631 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
620 BufferedUartRx::<'d, T>::read(buf).await 632 BufferedUartRx::read(self.rx.info, self.rx.state, buf).await
621 } 633 }
622} 634}
623 635
624impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> { 636impl embedded_io_async::Read for BufferedUartRx {
625 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 637 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
626 Self::read(buf).await 638 Self::read(self.info, self.state, buf).await
627 } 639 }
628} 640}
629 641
630impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> { 642impl embedded_io_async::ReadReady for BufferedUart {
631 fn read_ready(&mut self) -> Result<bool, Self::Error> { 643 fn read_ready(&mut self) -> Result<bool, Self::Error> {
632 BufferedUartRx::<'d, T>::read_ready() 644 BufferedUartRx::read_ready(self.rx.state)
633 } 645 }
634} 646}
635 647
636impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> { 648impl embedded_io_async::ReadReady for BufferedUartRx {
637 fn read_ready(&mut self) -> Result<bool, Self::Error> { 649 fn read_ready(&mut self) -> Result<bool, Self::Error> {
638 Self::read_ready() 650 Self::read_ready(self.state)
639 } 651 }
640} 652}
641 653
642impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> { 654impl embedded_io_async::BufRead for BufferedUart {
643 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 655 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
644 BufferedUartRx::<'d, T>::fill_buf().await 656 BufferedUartRx::fill_buf(self.rx.state).await
645 } 657 }
646 658
647 fn consume(&mut self, amt: usize) { 659 fn consume(&mut self, amt: usize) {
648 BufferedUartRx::<'d, T>::consume(amt) 660 BufferedUartRx::consume(self.rx.info, self.rx.state, amt)
649 } 661 }
650} 662}
651 663
652impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> { 664impl embedded_io_async::BufRead for BufferedUartRx {
653 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 665 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
654 Self::fill_buf().await 666 Self::fill_buf(self.state).await
655 } 667 }
656 668
657 fn consume(&mut self, amt: usize) { 669 fn consume(&mut self, amt: usize) {
658 Self::consume(amt) 670 Self::consume(self.info, self.state, amt)
659 } 671 }
660} 672}
661 673
662impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> { 674impl embedded_io_async::Write for BufferedUart {
663 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 675 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
664 BufferedUartTx::<'d, T>::write(buf).await 676 BufferedUartTx::write(self.tx.info, self.tx.state, buf).await
665 } 677 }
666 678
667 async fn flush(&mut self) -> Result<(), Self::Error> { 679 async fn flush(&mut self) -> Result<(), Self::Error> {
668 BufferedUartTx::<'d, T>::flush().await 680 BufferedUartTx::flush(self.tx.state).await
669 } 681 }
670} 682}
671 683
672impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> { 684impl embedded_io_async::Write for BufferedUartTx {
673 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 685 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
674 Self::write(buf).await 686 Self::write(self.info, self.state, buf).await
675 } 687 }
676 688
677 async fn flush(&mut self) -> Result<(), Self::Error> { 689 async fn flush(&mut self) -> Result<(), Self::Error> {
678 Self::flush().await 690 Self::flush(self.state).await
679 } 691 }
680} 692}
681 693
682impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> { 694impl embedded_io::Read for BufferedUart {
683 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 695 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
684 self.rx.blocking_read(buf) 696 self.rx.blocking_read(buf)
685 } 697 }
686} 698}
687 699
688impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> { 700impl embedded_io::Read for BufferedUartRx {
689 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 701 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
690 self.blocking_read(buf) 702 self.blocking_read(buf)
691 } 703 }
692} 704}
693 705
694impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> { 706impl embedded_io::Write for BufferedUart {
695 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 707 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
696 self.tx.blocking_write(buf) 708 self.tx.blocking_write(buf)
697 } 709 }
@@ -701,7 +713,7 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
701 } 713 }
702} 714}
703 715
704impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> { 716impl embedded_io::Write for BufferedUartTx {
705 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 717 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
706 self.blocking_write(buf) 718 self.blocking_write(buf)
707 } 719 }
@@ -711,11 +723,11 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
711 } 723 }
712} 724}
713 725
714impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> { 726impl embedded_hal_02::serial::Read<u8> for BufferedUartRx {
715 type Error = Error; 727 type Error = Error;
716 728
717 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 729 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
718 let r = T::regs(); 730 let r = self.info.regs;
719 if r.uartfr().read().rxfe() { 731 if r.uartfr().read().rxfe() {
720 return Err(nb::Error::WouldBlock); 732 return Err(nb::Error::WouldBlock);
721 } 733 }
@@ -736,7 +748,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T
736 } 748 }
737} 749}
738 750
739impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> { 751impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx {
740 type Error = Error; 752 type Error = Error;
741 753
742 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { 754 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@@ -755,7 +767,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
755 } 767 }
756} 768}
757 769
758impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> { 770impl embedded_hal_02::serial::Read<u8> for BufferedUart {
759 type Error = Error; 771 type Error = Error;
760 772
761 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 773 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@@ -763,7 +775,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T>
763 } 775 }
764} 776}
765 777
766impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> { 778impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUart {
767 type Error = Error; 779 type Error = Error;
768 780
769 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { 781 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@@ -782,25 +794,25 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
782 } 794 }
783} 795}
784 796
785impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { 797impl embedded_hal_nb::serial::ErrorType for BufferedUartRx {
786 type Error = Error; 798 type Error = Error;
787} 799}
788 800
789impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { 801impl embedded_hal_nb::serial::ErrorType for BufferedUartTx {
790 type Error = Error; 802 type Error = Error;
791} 803}
792 804
793impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { 805impl embedded_hal_nb::serial::ErrorType for BufferedUart {
794 type Error = Error; 806 type Error = Error;
795} 807}
796 808
797impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> { 809impl embedded_hal_nb::serial::Read for BufferedUartRx {
798 fn read(&mut self) -> nb::Result<u8, Self::Error> { 810 fn read(&mut self) -> nb::Result<u8, Self::Error> {
799 embedded_hal_02::serial::Read::read(self) 811 embedded_hal_02::serial::Read::read(self)
800 } 812 }
801} 813}
802 814
803impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { 815impl embedded_hal_nb::serial::Write for BufferedUartTx {
804 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 816 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
805 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 817 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
806 } 818 }
@@ -810,13 +822,13 @@ impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
810 } 822 }
811} 823}
812 824
813impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> { 825impl embedded_hal_nb::serial::Read for BufferedUart {
814 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 826 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
815 embedded_hal_02::serial::Read::read(&mut self.rx) 827 embedded_hal_02::serial::Read::read(&mut self.rx)
816 } 828 }
817} 829}
818 830
819impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { 831impl embedded_hal_nb::serial::Write for BufferedUart {
820 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 832 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
821 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 833 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
822 } 834 }
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 7ce074a3f..c3a15fda5 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -13,7 +13,8 @@ use pac::uart::regs::Uartris;
13use crate::clocks::clk_peri_freq; 13use crate::clocks::clk_peri_freq;
14use crate::dma::{AnyChannel, Channel}; 14use crate::dma::{AnyChannel, Channel};
15use crate::gpio::{AnyPin, SealedPin}; 15use crate::gpio::{AnyPin, SealedPin};
16use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt as _};
17use crate::interrupt::{Interrupt, InterruptExt};
17use crate::pac::io::vals::{Inover, Outover}; 18use crate::pac::io::vals::{Inover, Outover};
18use crate::{interrupt, pac, peripherals, RegExt}; 19use crate::{interrupt, pac, peripherals, RegExt};
19 20
@@ -135,37 +136,41 @@ pub struct DmaState {
135} 136}
136 137
137/// UART driver. 138/// UART driver.
138pub struct Uart<'d, T: Instance, M: Mode> { 139pub struct Uart<'d, M: Mode> {
139 tx: UartTx<'d, T, M>, 140 tx: UartTx<'d, M>,
140 rx: UartRx<'d, T, M>, 141 rx: UartRx<'d, M>,
141} 142}
142 143
143/// UART TX driver. 144/// UART TX driver.
144pub struct UartTx<'d, T: Instance, M: Mode> { 145pub struct UartTx<'d, M: Mode> {
146 info: &'static Info,
145 tx_dma: Option<Peri<'d, AnyChannel>>, 147 tx_dma: Option<Peri<'d, AnyChannel>>,
146 phantom: PhantomData<(&'d mut T, M)>, 148 phantom: PhantomData<M>,
147} 149}
148 150
149/// UART RX driver. 151/// UART RX driver.
150pub struct UartRx<'d, T: Instance, M: Mode> { 152pub struct UartRx<'d, M: Mode> {
153 info: &'static Info,
154 dma_state: &'static DmaState,
151 rx_dma: Option<Peri<'d, AnyChannel>>, 155 rx_dma: Option<Peri<'d, AnyChannel>>,
152 phantom: PhantomData<(&'d mut T, M)>, 156 phantom: PhantomData<M>,
153} 157}
154 158
155impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { 159impl<'d, M: Mode> UartTx<'d, M> {
156 /// Create a new DMA-enabled UART which can only send data 160 /// Create a new DMA-enabled UART which can only send data
157 pub fn new( 161 pub fn new<T: Instance>(
158 _uart: Peri<'d, T>, 162 _uart: Peri<'d, T>,
159 tx: Peri<'d, impl TxPin<T>>, 163 tx: Peri<'d, impl TxPin<T>>,
160 tx_dma: Peri<'d, impl Channel>, 164 tx_dma: Peri<'d, impl Channel>,
161 config: Config, 165 config: Config,
162 ) -> Self { 166 ) -> Self {
163 Uart::<T, M>::init(Some(tx.into()), None, None, None, config); 167 Uart::<M>::init(T::info(), Some(tx.into()), None, None, None, config);
164 Self::new_inner(Some(tx_dma.into())) 168 Self::new_inner(T::info(), Some(tx_dma.into()))
165 } 169 }
166 170
167 fn new_inner(tx_dma: Option<Peri<'d, AnyChannel>>) -> Self { 171 fn new_inner(info: &'static Info, tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
168 Self { 172 Self {
173 info,
169 tx_dma, 174 tx_dma,
170 phantom: PhantomData, 175 phantom: PhantomData,
171 } 176 }
@@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
173 178
174 /// Transmit the provided buffer blocking execution until done. 179 /// Transmit the provided buffer blocking execution until done.
175 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 180 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
176 let r = T::regs(); 181 let r = self.info.regs;
177 for &b in buffer { 182 for &b in buffer {
178 while r.uartfr().read().txff() {} 183 while r.uartfr().read().txff() {}
179 r.uartdr().write(|w| w.set_data(b)); 184 r.uartdr().write(|w| w.set_data(b));
@@ -183,14 +188,13 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
183 188
184 /// Flush UART TX blocking execution until done. 189 /// Flush UART TX blocking execution until done.
185 pub fn blocking_flush(&mut self) -> Result<(), Error> { 190 pub fn blocking_flush(&mut self) -> Result<(), Error> {
186 let r = T::regs(); 191 while !self.info.regs.uartfr().read().txfe() {}
187 while !r.uartfr().read().txfe() {}
188 Ok(()) 192 Ok(())
189 } 193 }
190 194
191 /// Check if UART is busy transmitting. 195 /// Check if UART is busy transmitting.
192 pub fn busy(&self) -> bool { 196 pub fn busy(&self) -> bool {
193 T::regs().uartfr().read().busy() 197 self.info.regs.uartfr().read().busy()
194 } 198 }
195 199
196 /// Assert a break condition after waiting for the transmit buffers to empty, 200 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -201,7 +205,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
201 /// This method may block for a long amount of time since it has to wait 205 /// This method may block for a long amount of time since it has to wait
202 /// for the transmit fifo to empty, which may take a while on slow links. 206 /// for the transmit fifo to empty, which may take a while on slow links.
203 pub async fn send_break(&mut self, bits: u32) { 207 pub async fn send_break(&mut self, bits: u32) {
204 let regs = T::regs(); 208 let regs = self.info.regs;
205 let bits = bits.max({ 209 let bits = bits.max({
206 let lcr = regs.uartlcr_h().read(); 210 let lcr = regs.uartlcr_h().read();
207 let width = lcr.wlen() as u32 + 5; 211 let width = lcr.wlen() as u32 + 5;
@@ -222,65 +226,80 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
222 } 226 }
223} 227}
224 228
225impl<'d, T: Instance> UartTx<'d, T, Blocking> { 229impl<'d> UartTx<'d, Blocking> {
226 /// Create a new UART TX instance for blocking mode operations. 230 /// Create a new UART TX instance for blocking mode operations.
227 pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 231 pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
228 Uart::<T, Blocking>::init(Some(tx.into()), None, None, None, config); 232 Uart::<Blocking>::init(T::info(), Some(tx.into()), None, None, None, config);
229 Self::new_inner(None) 233 Self::new_inner(T::info(), None)
230 } 234 }
231 235
232 /// Convert this uart TX instance into a buffered uart using the provided 236 /// Convert this uart TX instance into a buffered uart using the provided
233 /// irq and transmit buffer. 237 /// irq and transmit buffer.
234 pub fn into_buffered( 238 pub fn into_buffered<T: Instance>(
235 self, 239 self,
236 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 240 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
237 tx_buffer: &'d mut [u8], 241 tx_buffer: &'d mut [u8],
238 ) -> BufferedUartTx<'d, T> { 242 ) -> BufferedUartTx {
239 buffered::init_buffers::<T>(irq, Some(tx_buffer), None); 243 buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
240 244
241 BufferedUartTx { phantom: PhantomData } 245 BufferedUartTx {
246 info: T::info(),
247 state: T::buffered_state(),
248 }
242 } 249 }
243} 250}
244 251
245impl<'d, T: Instance> UartTx<'d, T, Async> { 252impl<'d> UartTx<'d, Async> {
246 /// Write to UART TX from the provided buffer using DMA. 253 /// Write to UART TX from the provided buffer using DMA.
247 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 254 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
248 let ch = self.tx_dma.as_mut().unwrap().reborrow(); 255 let ch = self.tx_dma.as_mut().unwrap().reborrow();
249 let transfer = unsafe { 256 let transfer = unsafe {
250 T::regs().uartdmacr().write_set(|reg| { 257 self.info.regs.uartdmacr().write_set(|reg| {
251 reg.set_txdmae(true); 258 reg.set_txdmae(true);
252 }); 259 });
253 // If we don't assign future to a variable, the data register pointer 260 // If we don't assign future to a variable, the data register pointer
254 // is held across an await and makes the future non-Send. 261 // is held across an await and makes the future non-Send.
255 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into()) 262 crate::dma::write(
263 ch,
264 buffer,
265 self.info.regs.uartdr().as_ptr() as *mut _,
266 self.info.tx_dreq.into(),
267 )
256 }; 268 };
257 transfer.await; 269 transfer.await;
258 Ok(()) 270 Ok(())
259 } 271 }
260} 272}
261 273
262impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { 274impl<'d, M: Mode> UartRx<'d, M> {
263 /// Create a new DMA-enabled UART which can only receive data 275 /// Create a new DMA-enabled UART which can only receive data
264 pub fn new( 276 pub fn new<T: Instance>(
265 _uart: Peri<'d, T>, 277 _uart: Peri<'d, T>,
266 rx: Peri<'d, impl RxPin<T>>, 278 rx: Peri<'d, impl RxPin<T>>,
267 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>, 279 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
268 rx_dma: Peri<'d, impl Channel>, 280 rx_dma: Peri<'d, impl Channel>,
269 config: Config, 281 config: Config,
270 ) -> Self { 282 ) -> Self {
271 Uart::<T, M>::init(None, Some(rx.into()), None, None, config); 283 Uart::<M>::init(T::info(), None, Some(rx.into()), None, None, config);
272 Self::new_inner(true, Some(rx_dma.into())) 284 Self::new_inner(T::info(), T::dma_state(), true, Some(rx_dma.into()))
273 } 285 }
274 286
275 fn new_inner(has_irq: bool, rx_dma: Option<Peri<'d, AnyChannel>>) -> Self { 287 fn new_inner(
288 info: &'static Info,
289 dma_state: &'static DmaState,
290 has_irq: bool,
291 rx_dma: Option<Peri<'d, AnyChannel>>,
292 ) -> Self {
276 debug_assert_eq!(has_irq, rx_dma.is_some()); 293 debug_assert_eq!(has_irq, rx_dma.is_some());
277 if has_irq { 294 if has_irq {
278 // disable all error interrupts initially 295 // disable all error interrupts initially
279 T::regs().uartimsc().write(|w| w.0 = 0); 296 info.regs.uartimsc().write(|w| w.0 = 0);
280 T::Interrupt::unpend(); 297 info.interrupt.unpend();
281 unsafe { T::Interrupt::enable() }; 298 unsafe { info.interrupt.enable() };
282 } 299 }
283 Self { 300 Self {
301 info,
302 dma_state,
284 rx_dma, 303 rx_dma,
285 phantom: PhantomData, 304 phantom: PhantomData,
286 } 305 }
@@ -299,7 +318,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
299 /// encountered. in both cases, `len` is the number of *good* bytes copied into 318 /// encountered. in both cases, `len` is the number of *good* bytes copied into
300 /// `buffer`. 319 /// `buffer`.
301 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { 320 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
302 let r = T::regs(); 321 let r = self.info.regs;
303 for (i, b) in buffer.iter_mut().enumerate() { 322 for (i, b) in buffer.iter_mut().enumerate() {
304 if r.uartfr().read().rxfe() { 323 if r.uartfr().read().rxfe() {
305 return Ok(i); 324 return Ok(i);
@@ -323,12 +342,12 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
323 } 342 }
324} 343}
325 344
326impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { 345impl<'d, M: Mode> Drop for UartRx<'d, M> {
327 fn drop(&mut self) { 346 fn drop(&mut self) {
328 if self.rx_dma.is_some() { 347 if self.rx_dma.is_some() {
329 T::Interrupt::disable(); 348 self.info.interrupt.disable();
330 // clear dma flags. irq handlers use these to disambiguate among themselves. 349 // clear dma flags. irq handlers use these to disambiguate among themselves.
331 T::regs().uartdmacr().write_clear(|reg| { 350 self.info.regs.uartdmacr().write_clear(|reg| {
332 reg.set_rxdmae(true); 351 reg.set_rxdmae(true);
333 reg.set_txdmae(true); 352 reg.set_txdmae(true);
334 reg.set_dmaonerr(true); 353 reg.set_dmaonerr(true);
@@ -337,23 +356,26 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
337 } 356 }
338} 357}
339 358
340impl<'d, T: Instance> UartRx<'d, T, Blocking> { 359impl<'d> UartRx<'d, Blocking> {
341 /// Create a new UART RX instance for blocking mode operations. 360 /// Create a new UART RX instance for blocking mode operations.
342 pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 361 pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
343 Uart::<T, Blocking>::init(None, Some(rx.into()), None, None, config); 362 Uart::<Blocking>::init(T::info(), None, Some(rx.into()), None, None, config);
344 Self::new_inner(false, None) 363 Self::new_inner(T::info(), T::dma_state(), false, None)
345 } 364 }
346 365
347 /// Convert this uart RX instance into a buffered uart using the provided 366 /// Convert this uart RX instance into a buffered uart using the provided
348 /// irq and receive buffer. 367 /// irq and receive buffer.
349 pub fn into_buffered( 368 pub fn into_buffered<T: Instance>(
350 self, 369 self,
351 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 370 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
352 rx_buffer: &'d mut [u8], 371 rx_buffer: &'d mut [u8],
353 ) -> BufferedUartRx<'d, T> { 372 ) -> BufferedUartRx {
354 buffered::init_buffers::<T>(irq, None, Some(rx_buffer)); 373 buffered::init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
355 374
356 BufferedUartRx { phantom: PhantomData } 375 BufferedUartRx {
376 info: T::info(),
377 state: T::buffered_state(),
378 }
357 } 379 }
358} 380}
359 381
@@ -364,7 +386,7 @@ pub struct InterruptHandler<T: Instance> {
364 386
365impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 387impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
366 unsafe fn on_interrupt() { 388 unsafe fn on_interrupt() {
367 let uart = T::regs(); 389 let uart = T::info().regs;
368 if !uart.uartdmacr().read().rxdmae() { 390 if !uart.uartdmacr().read().rxdmae() {
369 return; 391 return;
370 } 392 }
@@ -380,13 +402,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
380 } 402 }
381} 403}
382 404
383impl<'d, T: Instance> UartRx<'d, T, Async> { 405impl<'d> UartRx<'d, Async> {
384 /// Read from UART RX into the provided buffer. 406 /// Read from UART RX into the provided buffer.
385 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 407 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
386 // clear error flags before we drain the fifo. errors that have accumulated 408 // clear error flags before we drain the fifo. errors that have accumulated
387 // in the flags will also be present in the fifo. 409 // in the flags will also be present in the fifo.
388 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 410 self.dma_state.rx_errs.store(0, Ordering::Relaxed);
389 T::regs().uarticr().write(|w| { 411 self.info.regs.uarticr().write(|w| {
390 w.set_oeic(true); 412 w.set_oeic(true);
391 w.set_beic(true); 413 w.set_beic(true);
392 w.set_peic(true); 414 w.set_peic(true);
@@ -408,28 +430,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
408 // interrupt flags will have been raised, and those will be picked up immediately 430 // interrupt flags will have been raised, and those will be picked up immediately
409 // by the interrupt handler. 431 // by the interrupt handler.
410 let ch = self.rx_dma.as_mut().unwrap().reborrow(); 432 let ch = self.rx_dma.as_mut().unwrap().reborrow();
411 T::regs().uartimsc().write_set(|w| { 433 self.info.regs.uartimsc().write_set(|w| {
412 w.set_oeim(true); 434 w.set_oeim(true);
413 w.set_beim(true); 435 w.set_beim(true);
414 w.set_peim(true); 436 w.set_peim(true);
415 w.set_feim(true); 437 w.set_feim(true);
416 }); 438 });
417 T::regs().uartdmacr().write_set(|reg| { 439 self.info.regs.uartdmacr().write_set(|reg| {
418 reg.set_rxdmae(true); 440 reg.set_rxdmae(true);
419 reg.set_dmaonerr(true); 441 reg.set_dmaonerr(true);
420 }); 442 });
421 let transfer = unsafe { 443 let transfer = unsafe {
422 // If we don't assign future to a variable, the data register pointer 444 // If we don't assign future to a variable, the data register pointer
423 // is held across an await and makes the future non-Send. 445 // is held across an await and makes the future non-Send.
424 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into()) 446 crate::dma::read(
447 ch,
448 self.info.regs.uartdr().as_ptr() as *const _,
449 buffer,
450 self.info.rx_dreq.into(),
451 )
425 }; 452 };
426 453
427 // wait for either the transfer to complete or an error to happen. 454 // wait for either the transfer to complete or an error to happen.
428 let transfer_result = select( 455 let transfer_result = select(
429 transfer, 456 transfer,
430 poll_fn(|cx| { 457 poll_fn(|cx| {
431 T::dma_state().rx_err_waker.register(cx.waker()); 458 self.dma_state.rx_err_waker.register(cx.waker());
432 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { 459 match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
433 0 => Poll::Pending, 460 0 => Poll::Pending,
434 e => Poll::Ready(Uartris(e as u32)), 461 e => Poll::Ready(Uartris(e as u32)),
435 } 462 }
@@ -441,7 +468,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
441 Either::First(()) => { 468 Either::First(()) => {
442 // We're here because the DMA finished, BUT if an error occurred on the LAST 469 // We're here because the DMA finished, BUT if an error occurred on the LAST
443 // byte, then we may still need to grab the error state! 470 // byte, then we may still need to grab the error state!
444 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) 471 Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
445 } 472 }
446 Either::Second(e) => { 473 Either::Second(e) => {
447 // We're here because we errored, which means this is the error that 474 // We're here because we errored, which means this is the error that
@@ -521,8 +548,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
521 ) -> Result<usize, ReadToBreakError> { 548 ) -> Result<usize, ReadToBreakError> {
522 // clear error flags before we drain the fifo. errors that have accumulated 549 // clear error flags before we drain the fifo. errors that have accumulated
523 // in the flags will also be present in the fifo. 550 // in the flags will also be present in the fifo.
524 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 551 self.dma_state.rx_errs.store(0, Ordering::Relaxed);
525 T::regs().uarticr().write(|w| { 552 self.info.regs.uarticr().write(|w| {
526 w.set_oeic(true); 553 w.set_oeic(true);
527 w.set_beic(true); 554 w.set_beic(true);
528 w.set_peic(true); 555 w.set_peic(true);
@@ -555,13 +582,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
555 // interrupt flags will have been raised, and those will be picked up immediately 582 // interrupt flags will have been raised, and those will be picked up immediately
556 // by the interrupt handler. 583 // by the interrupt handler.
557 let ch = self.rx_dma.as_mut().unwrap(); 584 let ch = self.rx_dma.as_mut().unwrap();
558 T::regs().uartimsc().write_set(|w| { 585 self.info.regs.uartimsc().write_set(|w| {
559 w.set_oeim(true); 586 w.set_oeim(true);
560 w.set_beim(true); 587 w.set_beim(true);
561 w.set_peim(true); 588 w.set_peim(true);
562 w.set_feim(true); 589 w.set_feim(true);
563 }); 590 });
564 T::regs().uartdmacr().write_set(|reg| { 591 self.info.regs.uartdmacr().write_set(|reg| {
565 reg.set_rxdmae(true); 592 reg.set_rxdmae(true);
566 reg.set_dmaonerr(true); 593 reg.set_dmaonerr(true);
567 }); 594 });
@@ -572,9 +599,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
572 // is held across an await and makes the future non-Send. 599 // is held across an await and makes the future non-Send.
573 crate::dma::read( 600 crate::dma::read(
574 ch.reborrow(), 601 ch.reborrow(),
575 T::regs().uartdr().as_ptr() as *const _, 602 self.info.regs.uartdr().as_ptr() as *const _,
576 sbuffer, 603 sbuffer,
577 T::RX_DREQ.into(), 604 self.info.rx_dreq.into(),
578 ) 605 )
579 }; 606 };
580 607
@@ -582,8 +609,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
582 let transfer_result = select( 609 let transfer_result = select(
583 transfer, 610 transfer,
584 poll_fn(|cx| { 611 poll_fn(|cx| {
585 T::dma_state().rx_err_waker.register(cx.waker()); 612 self.dma_state.rx_err_waker.register(cx.waker());
586 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { 613 match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
587 0 => Poll::Pending, 614 0 => Poll::Pending,
588 e => Poll::Ready(Uartris(e as u32)), 615 e => Poll::Ready(Uartris(e as u32)),
589 } 616 }
@@ -596,7 +623,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
596 Either::First(()) => { 623 Either::First(()) => {
597 // We're here because the DMA finished, BUT if an error occurred on the LAST 624 // We're here because the DMA finished, BUT if an error occurred on the LAST
598 // byte, then we may still need to grab the error state! 625 // byte, then we may still need to grab the error state!
599 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) 626 Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
600 } 627 }
601 Either::Second(e) => { 628 Either::Second(e) => {
602 // We're here because we errored, which means this is the error that 629 // We're here because we errored, which means this is the error that
@@ -635,7 +662,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
635 continue; 662 continue;
636 } 663 }
637 664
638 let regs = T::regs(); 665 let regs = self.info.regs;
639 let all_full = next_addr == eval; 666 let all_full = next_addr == eval;
640 667
641 // NOTE: This is off label usage of RSR! See the issue below for 668 // NOTE: This is off label usage of RSR! See the issue below for
@@ -685,9 +712,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
685 } 712 }
686} 713}
687 714
688impl<'d, T: Instance> Uart<'d, T, Blocking> { 715impl<'d> Uart<'d, Blocking> {
689 /// Create a new UART without hardware flow control 716 /// Create a new UART without hardware flow control
690 pub fn new_blocking( 717 pub fn new_blocking<T: Instance>(
691 uart: Peri<'d, T>, 718 uart: Peri<'d, T>,
692 tx: Peri<'d, impl TxPin<T>>, 719 tx: Peri<'d, impl TxPin<T>>,
693 rx: Peri<'d, impl RxPin<T>>, 720 rx: Peri<'d, impl RxPin<T>>,
@@ -697,7 +724,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
697 } 724 }
698 725
699 /// Create a new UART with hardware flow control (RTS/CTS) 726 /// Create a new UART with hardware flow control (RTS/CTS)
700 pub fn new_with_rtscts_blocking( 727 pub fn new_with_rtscts_blocking<T: Instance>(
701 uart: Peri<'d, T>, 728 uart: Peri<'d, T>,
702 tx: Peri<'d, impl TxPin<T>>, 729 tx: Peri<'d, impl TxPin<T>>,
703 rx: Peri<'d, impl RxPin<T>>, 730 rx: Peri<'d, impl RxPin<T>>,
@@ -720,24 +747,30 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
720 747
721 /// Convert this uart instance into a buffered uart using the provided 748 /// Convert this uart instance into a buffered uart using the provided
722 /// irq, transmit and receive buffers. 749 /// irq, transmit and receive buffers.
723 pub fn into_buffered( 750 pub fn into_buffered<T: Instance>(
724 self, 751 self,
725 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 752 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
726 tx_buffer: &'d mut [u8], 753 tx_buffer: &'d mut [u8],
727 rx_buffer: &'d mut [u8], 754 rx_buffer: &'d mut [u8],
728 ) -> BufferedUart<'d, T> { 755 ) -> BufferedUart {
729 buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 756 buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
730 757
731 BufferedUart { 758 BufferedUart {
732 rx: BufferedUartRx { phantom: PhantomData }, 759 rx: BufferedUartRx {
733 tx: BufferedUartTx { phantom: PhantomData }, 760 info: T::info(),
761 state: T::buffered_state(),
762 },
763 tx: BufferedUartTx {
764 info: T::info(),
765 state: T::buffered_state(),
766 },
734 } 767 }
735 } 768 }
736} 769}
737 770
738impl<'d, T: Instance> Uart<'d, T, Async> { 771impl<'d> Uart<'d, Async> {
739 /// Create a new DMA enabled UART without hardware flow control 772 /// Create a new DMA enabled UART without hardware flow control
740 pub fn new( 773 pub fn new<T: Instance>(
741 uart: Peri<'d, T>, 774 uart: Peri<'d, T>,
742 tx: Peri<'d, impl TxPin<T>>, 775 tx: Peri<'d, impl TxPin<T>>,
743 rx: Peri<'d, impl RxPin<T>>, 776 rx: Peri<'d, impl RxPin<T>>,
@@ -760,7 +793,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
760 } 793 }
761 794
762 /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) 795 /// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
763 pub fn new_with_rtscts( 796 pub fn new_with_rtscts<T: Instance>(
764 uart: Peri<'d, T>, 797 uart: Peri<'d, T>,
765 tx: Peri<'d, impl TxPin<T>>, 798 tx: Peri<'d, impl TxPin<T>>,
766 rx: Peri<'d, impl RxPin<T>>, 799 rx: Peri<'d, impl RxPin<T>>,
@@ -785,8 +818,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
785 } 818 }
786} 819}
787 820
788impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { 821impl<'d, M: Mode> Uart<'d, M> {
789 fn new_inner( 822 fn new_inner<T: Instance>(
790 _uart: Peri<'d, T>, 823 _uart: Peri<'d, T>,
791 mut tx: Peri<'d, AnyPin>, 824 mut tx: Peri<'d, AnyPin>,
792 mut rx: Peri<'d, AnyPin>, 825 mut rx: Peri<'d, AnyPin>,
@@ -798,6 +831,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
798 config: Config, 831 config: Config,
799 ) -> Self { 832 ) -> Self {
800 Self::init( 833 Self::init(
834 T::info(),
801 Some(tx.reborrow()), 835 Some(tx.reborrow()),
802 Some(rx.reborrow()), 836 Some(rx.reborrow()),
803 rts.as_mut().map(|x| x.reborrow()), 837 rts.as_mut().map(|x| x.reborrow()),
@@ -806,19 +840,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
806 ); 840 );
807 841
808 Self { 842 Self {
809 tx: UartTx::new_inner(tx_dma), 843 tx: UartTx::new_inner(T::info(), tx_dma),
810 rx: UartRx::new_inner(has_irq, rx_dma), 844 rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
811 } 845 }
812 } 846 }
813 847
814 fn init( 848 fn init(
849 info: &Info,
815 tx: Option<Peri<'_, AnyPin>>, 850 tx: Option<Peri<'_, AnyPin>>,
816 rx: Option<Peri<'_, AnyPin>>, 851 rx: Option<Peri<'_, AnyPin>>,
817 rts: Option<Peri<'_, AnyPin>>, 852 rts: Option<Peri<'_, AnyPin>>,
818 cts: Option<Peri<'_, AnyPin>>, 853 cts: Option<Peri<'_, AnyPin>>,
819 config: Config, 854 config: Config,
820 ) { 855 ) {
821 let r = T::regs(); 856 let r = info.regs;
822 if let Some(pin) = &tx { 857 if let Some(pin) = &tx {
823 let funcsel = { 858 let funcsel = {
824 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; 859 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
@@ -896,7 +931,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
896 }); 931 });
897 } 932 }
898 933
899 Self::set_baudrate_inner(config.baudrate); 934 Self::set_baudrate_inner(info, config.baudrate);
900 935
901 let (pen, eps) = match config.parity { 936 let (pen, eps) = match config.parity {
902 Parity::ParityNone => (false, false), 937 Parity::ParityNone => (false, false),
@@ -926,8 +961,8 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
926 }); 961 });
927 } 962 }
928 963
929 fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R { 964 fn lcr_modify<R>(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
930 let r = T::regs(); 965 let r = info.regs;
931 966
932 // Notes from PL011 reference manual: 967 // Notes from PL011 reference manual:
933 // 968 //
@@ -978,11 +1013,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
978 1013
979 /// sets baudrate on runtime 1014 /// sets baudrate on runtime
980 pub fn set_baudrate(&mut self, baudrate: u32) { 1015 pub fn set_baudrate(&mut self, baudrate: u32) {
981 Self::set_baudrate_inner(baudrate); 1016 Self::set_baudrate_inner(self.tx.info, baudrate);
982 } 1017 }
983 1018
984 fn set_baudrate_inner(baudrate: u32) { 1019 fn set_baudrate_inner(info: &Info, baudrate: u32) {
985 let r = T::regs(); 1020 let r = info.regs;
986 1021
987 let clk_base = crate::clocks::clk_peri_freq(); 1022 let clk_base = crate::clocks::clk_peri_freq();
988 1023
@@ -1002,11 +1037,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
1002 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 1037 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
1003 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); 1038 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
1004 1039
1005 Self::lcr_modify(|_| {}); 1040 Self::lcr_modify(info, |_| {});
1006 } 1041 }
1007} 1042}
1008 1043
1009impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 1044impl<'d, M: Mode> Uart<'d, M> {
1010 /// Transmit the provided buffer blocking execution until done. 1045 /// Transmit the provided buffer blocking execution until done.
1011 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1046 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
1012 self.tx.blocking_write(buffer) 1047 self.tx.blocking_write(buffer)
@@ -1034,19 +1069,19 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
1034 1069
1035 /// Split the Uart into a transmitter and receiver, which is particularly 1070 /// Split the Uart into a transmitter and receiver, which is particularly
1036 /// useful when having two tasks correlating to transmitting and receiving. 1071 /// useful when having two tasks correlating to transmitting and receiving.
1037 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { 1072 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
1038 (self.tx, self.rx) 1073 (self.tx, self.rx)
1039 } 1074 }
1040 1075
1041 /// Split the Uart into a transmitter and receiver by mutable reference, 1076 /// Split the Uart into a transmitter and receiver by mutable reference,
1042 /// which is particularly useful when having two tasks correlating to 1077 /// which is particularly useful when having two tasks correlating to
1043 /// transmitting and receiving. 1078 /// transmitting and receiving.
1044 pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) { 1079 pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) {
1045 (&mut self.tx, &mut self.rx) 1080 (&mut self.tx, &mut self.rx)
1046 } 1081 }
1047} 1082}
1048 1083
1049impl<'d, T: Instance> Uart<'d, T, Async> { 1084impl<'d> Uart<'d, Async> {
1050 /// Write to UART TX from the provided buffer. 1085 /// Write to UART TX from the provided buffer.
1051 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1086 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
1052 self.tx.write(buffer).await 1087 self.tx.write(buffer).await
@@ -1076,10 +1111,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
1076 } 1111 }
1077} 1112}
1078 1113
1079impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 1114impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
1080 type Error = Error; 1115 type Error = Error;
1081 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1116 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1082 let r = T::regs(); 1117 let r = self.info.regs;
1083 if r.uartfr().read().rxfe() { 1118 if r.uartfr().read().rxfe() {
1084 return Err(nb::Error::WouldBlock); 1119 return Err(nb::Error::WouldBlock);
1085 } 1120 }
@@ -1100,11 +1135,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d,
1100 } 1135 }
1101} 1136}
1102 1137
1103impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> { 1138impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, M> {
1104 type Error = Error; 1139 type Error = Error;
1105 1140
1106 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 1141 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
1107 let r = T::regs(); 1142 let r = self.info.regs;
1108 if r.uartfr().read().txff() { 1143 if r.uartfr().read().txff() {
1109 return Err(nb::Error::WouldBlock); 1144 return Err(nb::Error::WouldBlock);
1110 } 1145 }
@@ -1114,7 +1149,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
1114 } 1149 }
1115 1150
1116 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { 1151 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
1117 let r = T::regs(); 1152 let r = self.info.regs;
1118 if !r.uartfr().read().txfe() { 1153 if !r.uartfr().read().txfe() {
1119 return Err(nb::Error::WouldBlock); 1154 return Err(nb::Error::WouldBlock);
1120 } 1155 }
@@ -1122,7 +1157,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
1122 } 1157 }
1123} 1158}
1124 1159
1125impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { 1160impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
1126 type Error = Error; 1161 type Error = Error;
1127 1162
1128 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1163 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1134,7 +1169,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
1134 } 1169 }
1135} 1170}
1136 1171
1137impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { 1172impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
1138 type Error = Error; 1173 type Error = Error;
1139 1174
1140 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1175 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@@ -1142,7 +1177,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T,
1142 } 1177 }
1143} 1178}
1144 1179
1145impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T, M> { 1180impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, M> {
1146 type Error = Error; 1181 type Error = Error;
1147 1182
1148 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 1183 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
@@ -1154,7 +1189,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T
1154 } 1189 }
1155} 1190}
1156 1191
1157impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { 1192impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
1158 type Error = Error; 1193 type Error = Error;
1159 1194
1160 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1195 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1177,21 +1212,21 @@ impl embedded_hal_nb::serial::Error for Error {
1177 } 1212 }
1178} 1213}
1179 1214
1180impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> { 1215impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> {
1181 type Error = Error; 1216 type Error = Error;
1182} 1217}
1183 1218
1184impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> { 1219impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> {
1185 type Error = Error; 1220 type Error = Error;
1186} 1221}
1187 1222
1188impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> { 1223impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> {
1189 type Error = Error; 1224 type Error = Error;
1190} 1225}
1191 1226
1192impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { 1227impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
1193 fn read(&mut self) -> nb::Result<u8, Self::Error> { 1228 fn read(&mut self) -> nb::Result<u8, Self::Error> {
1194 let r = T::regs(); 1229 let r = self.info.regs;
1195 if r.uartfr().read().rxfe() { 1230 if r.uartfr().read().rxfe() {
1196 return Err(nb::Error::WouldBlock); 1231 return Err(nb::Error::WouldBlock);
1197 } 1232 }
@@ -1212,7 +1247,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M
1212 } 1247 }
1213} 1248}
1214 1249
1215impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { 1250impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
1216 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1251 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1217 self.blocking_write(&[char]).map_err(nb::Error::Other) 1252 self.blocking_write(&[char]).map_err(nb::Error::Other)
1218 } 1253 }
@@ -1222,11 +1257,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T,
1222 } 1257 }
1223} 1258}
1224 1259
1225impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { 1260impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> {
1226 type Error = Error; 1261 type Error = Error;
1227} 1262}
1228 1263
1229impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { 1264impl<'d> embedded_io::Write for UartTx<'d, Blocking> {
1230 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1265 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1231 self.blocking_write(buf).map(|_| buf.len()) 1266 self.blocking_write(buf).map(|_| buf.len())
1232 } 1267 }
@@ -1236,13 +1271,13 @@ impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
1236 } 1271 }
1237} 1272}
1238 1273
1239impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { 1274impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
1240 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1275 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1241 embedded_hal_02::serial::Read::read(&mut self.rx) 1276 embedded_hal_02::serial::Read::read(&mut self.rx)
1242 } 1277 }
1243} 1278}
1244 1279
1245impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { 1280impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
1246 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1281 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1247 self.blocking_write(&[char]).map_err(nb::Error::Other) 1282 self.blocking_write(&[char]).map_err(nb::Error::Other)
1248 } 1283 }
@@ -1252,11 +1287,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M>
1252 } 1287 }
1253} 1288}
1254 1289
1255impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { 1290impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> {
1256 type Error = Error; 1291 type Error = Error;
1257} 1292}
1258 1293
1259impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { 1294impl<'d> embedded_io::Write for Uart<'d, Blocking> {
1260 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1295 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1261 self.blocking_write(buf).map(|_| buf.len()) 1296 self.blocking_write(buf).map(|_| buf.len())
1262 } 1297 }
@@ -1266,13 +1301,17 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
1266 } 1301 }
1267} 1302}
1268 1303
1304struct Info {
1305 regs: pac::uart::Uart,
1306 tx_dreq: pac::dma::vals::TreqSel,
1307 rx_dreq: pac::dma::vals::TreqSel,
1308 interrupt: Interrupt,
1309}
1310
1269trait SealedMode {} 1311trait SealedMode {}
1270 1312
1271trait SealedInstance { 1313trait SealedInstance {
1272 const TX_DREQ: pac::dma::vals::TreqSel; 1314 fn info() -> &'static Info;
1273 const RX_DREQ: pac::dma::vals::TreqSel;
1274
1275 fn regs() -> pac::uart::Uart;
1276 1315
1277 fn buffered_state() -> &'static buffered::State; 1316 fn buffered_state() -> &'static buffered::State;
1278 1317
@@ -1308,11 +1347,14 @@ pub trait Instance: SealedInstance + PeripheralType {
1308macro_rules! impl_instance { 1347macro_rules! impl_instance {
1309 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 1348 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
1310 impl SealedInstance for peripherals::$inst { 1349 impl SealedInstance for peripherals::$inst {
1311 const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq; 1350 fn info() -> &'static Info {
1312 const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq; 1351 static INFO: Info = Info {
1313 1352 regs: pac::$inst,
1314 fn regs() -> pac::uart::Uart { 1353 tx_dreq: $tx_dreq,
1315 pac::$inst 1354 rx_dreq: $rx_dreq,
1355 interrupt: crate::interrupt::typelevel::$irq::IRQ,
1356 };
1357 &INFO
1316 } 1358 }
1317 1359
1318 fn buffered_state() -> &'static buffered::State { 1360 fn buffered_state() -> &'static buffered::State {
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index c50ab5294..b6781905e 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9- Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) 9- Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983))
10- Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups are be supported in embassy ([#4125](https://github.com/embassy-rs/embassy/pull/4125))
10 11
11## 0.2.0 - 2025-01-10 12## 0.2.0 - 2025-01-10
12 13
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 54badc8f2..972307bec 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -73,7 +73,7 @@ rand_core = "0.6.3"
73sdio-host = "0.9.0" 73sdio-host = "0.9.0"
74critical-section = "1.1" 74critical-section = "1.1"
75#stm32-metapac = { version = "16" } 75#stm32-metapac = { version = "16" }
76stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78" } 76stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26" }
77 77
78vcell = "0.1.3" 78vcell = "0.1.3"
79nb = "1.0.0" 79nb = "1.0.0"
@@ -102,7 +102,7 @@ proc-macro2 = "1.0.36"
102quote = "1.0.15" 102quote = "1.0.15"
103 103
104#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} 104#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]}
105stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78", default-features = false, features = ["metadata"] } 105stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26", default-features = false, features = ["metadata"] }
106 106
107[features] 107[features]
108default = ["rt"] 108default = ["rt"]
@@ -197,6 +197,9 @@ split-pc2 = ["_split-pins-enabled"]
197## Split PC3 197## Split PC3
198split-pc3 = ["_split-pins-enabled"] 198split-pc3 = ["_split-pins-enabled"]
199 199
200dual-bank = []
201single-bank = []
202
200## internal use only 203## internal use only
201_split-pins-enabled = [] 204_split-pins-enabled = []
202 205
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index f9f03c51b..b00b6a7ac 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -50,6 +50,44 @@ fn main() {
50 } 50 }
51 51
52 // ======== 52 // ========
53 // Select the memory variant to use
54 let memory = {
55 let single_bank_selected = env::var("CARGO_FEATURE_SINGLE_BANK").is_ok();
56 let dual_bank_selected = env::var("CARGO_FEATURE_DUAL_BANK").is_ok();
57
58 let single_bank_memory = METADATA.memory.iter().find(|mem| {
59 mem.iter().any(|region| region.name.contains("BANK_1"))
60 && !mem.iter().any(|region| region.name.contains("BANK_2"))
61 });
62
63 let dual_bank_memory = METADATA.memory.iter().find(|mem| {
64 mem.iter().any(|region| region.name.contains("BANK_1"))
65 && mem.iter().any(|region| region.name.contains("BANK_2"))
66 });
67
68 cfgs.set(
69 "bank_setup_configurable",
70 single_bank_memory.is_some() && dual_bank_memory.is_some(),
71 );
72
73 match (single_bank_selected, dual_bank_selected) {
74 (true, true) => panic!("Both 'single-bank' and 'dual-bank' features enabled"),
75 (true, false) => {
76 single_bank_memory.expect("The 'single-bank' feature is not supported on this dual bank chip")
77 }
78 (false, true) => {
79 dual_bank_memory.expect("The 'dual-bank' feature is not supported on this single bank chip")
80 }
81 (false, false) => {
82 if METADATA.memory.len() != 1 {
83 panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection")
84 }
85 METADATA.memory[0]
86 }
87 }
88 };
89
90 // ========
53 // Generate singletons 91 // Generate singletons
54 92
55 let mut singletons: Vec<String> = Vec::new(); 93 let mut singletons: Vec<String> = Vec::new();
@@ -290,8 +328,7 @@ fn main() {
290 // ======== 328 // ========
291 // Generate FLASH regions 329 // Generate FLASH regions
292 let mut flash_regions = TokenStream::new(); 330 let mut flash_regions = TokenStream::new();
293 let flash_memory_regions: Vec<_> = METADATA 331 let flash_memory_regions: Vec<_> = memory
294 .memory
295 .iter() 332 .iter()
296 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) 333 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some())
297 .collect(); 334 .collect();
@@ -647,6 +684,8 @@ fn main() {
647 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock), 684 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock),
648 }; 685 };
649 686
687 let bus_clock_frequency = clock_gen.gen_clock(p.name, &rcc.bus_clock);
688
650 // A refcount leak can result if the same field is shared by peripherals with different stop modes 689 // A refcount leak can result if the same field is shared by peripherals with different stop modes
651 // This condition should be checked in stm32-data 690 // This condition should be checked in stm32-data
652 let stop_mode = match rcc.stop_mode { 691 let stop_mode = match rcc.stop_mode {
@@ -660,6 +699,9 @@ fn main() {
660 fn frequency() -> crate::time::Hertz { 699 fn frequency() -> crate::time::Hertz {
661 #clock_frequency 700 #clock_frequency
662 } 701 }
702 fn bus_frequency() -> crate::time::Hertz {
703 #bus_clock_frequency
704 }
663 705
664 const RCC_INFO: crate::rcc::RccInfo = unsafe { 706 const RCC_INFO: crate::rcc::RccInfo = unsafe {
665 crate::rcc::RccInfo::new( 707 crate::rcc::RccInfo::new(
@@ -1616,8 +1658,7 @@ fn main() {
1616 let mut pins_table: Vec<Vec<String>> = Vec::new(); 1658 let mut pins_table: Vec<Vec<String>> = Vec::new();
1617 let mut adc_table: Vec<Vec<String>> = Vec::new(); 1659 let mut adc_table: Vec<Vec<String>> = Vec::new();
1618 1660
1619 for m in METADATA 1661 for m in memory
1620 .memory
1621 .iter() 1662 .iter()
1622 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) 1663 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some())
1623 { 1664 {
@@ -1855,8 +1896,7 @@ fn main() {
1855 // ======== 1896 // ========
1856 // Generate flash constants 1897 // Generate flash constants
1857 1898
1858 let flash_regions: Vec<&MemoryRegion> = METADATA 1899 let flash_regions: Vec<&MemoryRegion> = memory
1859 .memory
1860 .iter() 1900 .iter()
1861 .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) 1901 .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_"))
1862 .collect(); 1902 .collect();
@@ -1981,7 +2021,7 @@ fn main() {
1981 println!("cargo:rerun-if-changed=build.rs"); 2021 println!("cargo:rerun-if-changed=build.rs");
1982 2022
1983 if cfg!(feature = "memory-x") { 2023 if cfg!(feature = "memory-x") {
1984 gen_memory_x(out_dir); 2024 gen_memory_x(memory, out_dir);
1985 println!("cargo:rustc-link-search={}", out_dir.display()); 2025 println!("cargo:rustc-link-search={}", out_dir.display());
1986 } 2026 }
1987} 2027}
@@ -2070,11 +2110,11 @@ fn rustfmt(path: impl AsRef<Path>) {
2070 } 2110 }
2071} 2111}
2072 2112
2073fn gen_memory_x(out_dir: &Path) { 2113fn gen_memory_x(memory: &[MemoryRegion], out_dir: &Path) {
2074 let mut memory_x = String::new(); 2114 let mut memory_x = String::new();
2075 2115
2076 let flash = get_memory_range(MemoryRegionKind::Flash); 2116 let flash = get_memory_range(memory, MemoryRegionKind::Flash);
2077 let ram = get_memory_range(MemoryRegionKind::Ram); 2117 let ram = get_memory_range(memory, MemoryRegionKind::Ram);
2078 2118
2079 write!(memory_x, "MEMORY\n{{\n").unwrap(); 2119 write!(memory_x, "MEMORY\n{{\n").unwrap();
2080 writeln!( 2120 writeln!(
@@ -2098,12 +2138,8 @@ fn gen_memory_x(out_dir: &Path) {
2098 std::fs::write(out_dir.join("memory.x"), memory_x.as_bytes()).unwrap(); 2138 std::fs::write(out_dir.join("memory.x"), memory_x.as_bytes()).unwrap();
2099} 2139}
2100 2140
2101fn get_memory_range(kind: MemoryRegionKind) -> (u32, u32, String) { 2141fn get_memory_range(memory: &[MemoryRegion], kind: MemoryRegionKind) -> (u32, u32, String) {
2102 let mut mems: Vec<_> = METADATA 2142 let mut mems: Vec<_> = memory.iter().filter(|m| m.kind == kind && m.size != 0).collect();
2103 .memory
2104 .iter()
2105 .filter(|m| m.kind == kind && m.size != 0)
2106 .collect();
2107 mems.sort_by_key(|m| m.address); 2143 mems.sort_by_key(|m| m.address);
2108 2144
2109 let mut start = u32::MAX; 2145 let mut start = u32::MAX;
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 599b7bb4e..006dcddeb 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -6,8 +6,8 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::mutex::Mutex; 6use embassy_sync::mutex::Mutex;
7 7
8use super::{ 8use super::{
9 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, 9 blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout,
10 WRITE_SIZE, 10 FLASH_BASE, FLASH_SIZE, WRITE_SIZE,
11}; 11};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::peripherals::FLASH; 13use crate::peripherals::FLASH;
@@ -34,7 +34,6 @@ impl<'d> Flash<'d, Async> {
34 /// 34 ///
35 /// See module-level documentation for details on how memory regions work. 35 /// See module-level documentation for details on how memory regions work.
36 pub fn into_regions(self) -> FlashLayout<'d, Async> { 36 pub fn into_regions(self) -> FlashLayout<'d, Async> {
37 assert!(family::is_default_layout());
38 FlashLayout::new(self.inner) 37 FlashLayout::new(self.inner)
39 } 38 }
40 39
@@ -123,7 +122,7 @@ pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, byte
123pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { 122pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> {
124 let start_address = base + from; 123 let start_address = base + from;
125 let end_address = base + to; 124 let end_address = base + to;
126 let regions = family::get_flash_regions(); 125 let regions = get_flash_regions();
127 126
128 ensure_sector_aligned(start_address, end_address, regions)?; 127 ensure_sector_aligned(start_address, end_address, regions)?;
129 128
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 1376ca4b4..10023e637 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -4,8 +4,8 @@ use core::sync::atomic::{fence, Ordering};
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5 5
6use super::{ 6use super::{
7 family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, 7 family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE,
8 READ_SIZE, WRITE_SIZE, 8 MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE,
9}; 9};
10use crate::Peri; 10use crate::Peri;
11use crate::_generated::FLASH_BASE; 11use crate::_generated::FLASH_BASE;
@@ -20,6 +20,10 @@ pub struct Flash<'d, MODE = Async> {
20impl<'d> Flash<'d, Blocking> { 20impl<'d> Flash<'d, Blocking> {
21 /// Create a new flash driver, usable in blocking mode. 21 /// Create a new flash driver, usable in blocking mode.
22 pub fn new_blocking(p: Peri<'d, FLASH>) -> Self { 22 pub fn new_blocking(p: Peri<'d, FLASH>) -> Self {
23 #[cfg(bank_setup_configurable)]
24 // Check if the configuration matches the embassy setup
25 super::check_bank_setup();
26
23 Self { 27 Self {
24 inner: p, 28 inner: p,
25 _mode: PhantomData, 29 _mode: PhantomData,
@@ -32,7 +36,6 @@ impl<'d, MODE> Flash<'d, MODE> {
32 /// 36 ///
33 /// See module-level documentation for details on how memory regions work. 37 /// See module-level documentation for details on how memory regions work.
34 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { 38 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
35 assert!(family::is_default_layout());
36 FlashLayout::new(self.inner) 39 FlashLayout::new(self.inner)
37 } 40 }
38 41
@@ -137,7 +140,7 @@ pub(super) unsafe fn blocking_erase(
137) -> Result<(), Error> { 140) -> Result<(), Error> {
138 let start_address = base + from; 141 let start_address = base + from;
139 let end_address = base + to; 142 let end_address = base + to;
140 let regions = family::get_flash_regions(); 143 let regions = get_flash_regions();
141 144
142 ensure_sector_aligned(start_address, end_address, regions)?; 145 ensure_sector_aligned(start_address, end_address, regions)?;
143 146
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 402312f68..3f9dbe945 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 pac::FLASH.cr().modify(|w| w.set_lock(true)); 9 pac::FLASH.cr().modify(|w| w.set_lock(true));
18} 10}
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index ec237b9ff..bf9ad2893 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 pac::FLASH.cr().modify(|w| w.set_lock(true)); 9 pac::FLASH.cr().modify(|w| w.set_lock(true));
18} 10}
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
index cdab1fd2d..67e380619 100644
--- a/embassy-stm32/src/flash/f2.rs
+++ b/embassy-stm32/src/flash/f2.rs
@@ -3,7 +3,7 @@ use core::sync::atomic::{fence, AtomicBool, Ordering};
3 3
4use pac::flash::regs::Sr; 4use pac::flash::regs::Sr;
5 5
6use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 6use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
@@ -15,14 +15,6 @@ impl FlashSector {
15 } 15 }
16} 16}
17 17
18pub(crate) const fn is_default_layout() -> bool {
19 true
20}
21
22pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
23 &FLASH_REGIONS
24}
25
26pub(crate) unsafe fn lock() { 18pub(crate) unsafe fn lock() {
27 pac::FLASH.cr().modify(|w| w.set_lock(true)); 19 pac::FLASH.cr().modify(|w| w.set_lock(true));
28} 20}
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 687eabaeb..62e0492b5 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -4,177 +4,10 @@ use core::sync::atomic::{fence, AtomicBool, Ordering};
4use embassy_sync::waitqueue::AtomicWaker; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr; 5use pac::flash::regs::Sr;
6 6
7use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 7use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE};
8use crate::_generated::FLASH_SIZE; 8use crate::_generated::FLASH_SIZE;
9use crate::flash::Error; 9use crate::flash::Error;
10use crate::pac; 10use crate::pac;
11#[allow(missing_docs)] // TODO
12#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
13mod alt_regions {
14 use core::marker::PhantomData;
15
16 use crate::Peri;
17 use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
18 use crate::_generated::FLASH_SIZE;
19 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
20 use crate::peripherals::FLASH;
21
22 pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
23 size: 3 * BANK1_REGION3.erase_size,
24 ..BANK1_REGION3
25 };
26 pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion {
27 bank: FlashBank::Bank2,
28 base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2,
29 ..BANK1_REGION1
30 };
31 pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion {
32 bank: FlashBank::Bank2,
33 base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2,
34 ..BANK1_REGION2
35 };
36 pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion {
37 bank: FlashBank::Bank2,
38 base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2,
39 size: 3 * BANK1_REGION3.erase_size,
40 ..BANK1_REGION3
41 };
42
43 pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [
44 &BANK1_REGION1,
45 &BANK1_REGION2,
46 &ALT_BANK1_REGION3,
47 &ALT_BANK2_REGION1,
48 &ALT_BANK2_REGION2,
49 &ALT_BANK2_REGION3,
50 ];
51
52 pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData<MODE>);
53 pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData<MODE>);
54 pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData<MODE>);
55 pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData<MODE>);
56
57 pub struct AltFlashLayout<'d, MODE = Async> {
58 pub bank1_region1: Bank1Region1<'d, MODE>,
59 pub bank1_region2: Bank1Region2<'d, MODE>,
60 pub bank1_region3: AltBank1Region3<'d, MODE>,
61 pub bank2_region1: AltBank2Region1<'d, MODE>,
62 pub bank2_region2: AltBank2Region2<'d, MODE>,
63 pub bank2_region3: AltBank2Region3<'d, MODE>,
64 pub otp_region: OTPRegion<'d, MODE>,
65 }
66
67 impl<'d> Flash<'d> {
68 pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> {
69 assert!(!super::is_default_layout());
70
71 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
72 // Also, all async flash region operations are protected with a mutex.
73 let p = self.inner;
74 AltFlashLayout {
75 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
76 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
77 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
78 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
79 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
80 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
81 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
82 }
83 }
84
85 pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> {
86 assert!(!super::is_default_layout());
87
88 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
89 // Also, all blocking flash region operations are protected with a cs.
90 let p = self.inner;
91 AltFlashLayout {
92 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
93 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
94 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
95 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
96 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
97 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
98 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
99 }
100 }
101 }
102
103 macro_rules! foreach_altflash_region {
104 ($type_name:ident, $region:ident) => {
105 impl<MODE> $type_name<'_, MODE> {
106 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
107 crate::flash::common::blocking_read(self.0.base, self.0.size, offset, bytes)
108 }
109 }
110
111 impl $type_name<'_, Async> {
112 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
113 self.blocking_read(offset, bytes)
114 }
115
116 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
117 let _guard = asynch::REGION_ACCESS.lock().await;
118 unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await }
119 }
120
121 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
122 let _guard = asynch::REGION_ACCESS.lock().await;
123 unsafe { asynch::erase_sectored(self.0.base, from, to).await }
124 }
125 }
126
127 impl<MODE> embedded_storage::nor_flash::ErrorType for $type_name<'_, MODE> {
128 type Error = Error;
129 }
130
131 impl<MODE> embedded_storage::nor_flash::ReadNorFlash for $type_name<'_, MODE> {
132 const READ_SIZE: usize = crate::flash::READ_SIZE;
133
134 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
135 self.blocking_read(offset, bytes)
136 }
137
138 fn capacity(&self) -> usize {
139 self.0.size as usize
140 }
141 }
142
143 impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> {
144 const READ_SIZE: usize = crate::flash::READ_SIZE;
145
146 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
147 self.read(offset, bytes).await
148 }
149
150 fn capacity(&self) -> usize {
151 self.0.size as usize
152 }
153 }
154
155 impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> {
156 const WRITE_SIZE: usize = $region.write_size as usize;
157 const ERASE_SIZE: usize = $region.erase_size as usize;
158
159 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
160 self.write(offset, bytes).await
161 }
162
163 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
164 self.erase(from, to).await
165 }
166 }
167 };
168 }
169
170 foreach_altflash_region!(AltBank1Region3, ALT_BANK1_REGION3);
171 foreach_altflash_region!(AltBank2Region1, ALT_BANK2_REGION1);
172 foreach_altflash_region!(AltBank2Region2, ALT_BANK2_REGION2);
173 foreach_altflash_region!(AltBank2Region3, ALT_BANK2_REGION3);
174}
175
176#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
177pub use alt_regions::*;
178 11
179static WAKER: AtomicWaker = AtomicWaker::new(); 12static WAKER: AtomicWaker = AtomicWaker::new();
180static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); 13static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
@@ -185,30 +18,6 @@ impl FlashSector {
185 } 18 }
186} 19}
187 20
188#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
189pub(crate) fn is_default_layout() -> bool {
190 !pac::FLASH.optcr().read().db1m()
191}
192
193#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
194pub(crate) const fn is_default_layout() -> bool {
195 true
196}
197
198#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
199pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
200 if is_default_layout() {
201 &FLASH_REGIONS
202 } else {
203 &ALT_FLASH_REGIONS
204 }
205}
206
207#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
208pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
209 &FLASH_REGIONS
210}
211
212pub(crate) unsafe fn on_interrupt() { 21pub(crate) unsafe fn on_interrupt() {
213 // Clear IRQ flags 22 // Clear IRQ flags
214 pac::FLASH.sr().write(|w| { 23 pac::FLASH.sr().write(|w| {
@@ -487,71 +296,83 @@ mod tests {
487 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; 296 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
488 const LARGE_SECTOR_SIZE: u32 = 128 * 1024; 297 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
489 298
490 let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { 299 if !cfg!(feature = "dual-bank") {
491 let sector = get_sector(address, &FLASH_REGIONS); 300 let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| {
492 assert_eq!(snb, sector.snb()); 301 let sector = get_sector(address, crate::flash::get_flash_regions());
493 assert_eq!( 302 assert_eq!(snb, sector.snb());
494 FlashSector { 303 assert_eq!(
495 bank: FlashBank::Bank1, 304 FlashSector {
496 index_in_bank, 305 bank: sector.bank,
497 start, 306 index_in_bank,
498 size 307 start,
499 }, 308 size
500 sector 309 },
501 ); 310 sector
502 }; 311 );
503 312 };
504 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); 313
505 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); 314 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
506 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); 315 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
507 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); 316 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
508 317 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
509 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); 318
510 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); 319 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
511 320 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
512 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); 321
513 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); 322 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
514 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); 323 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
515 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 324 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
516 325 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
517 let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { 326 } else {
518 let sector = get_sector(address, &ALT_FLASH_REGIONS); 327 let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| {
519 assert_eq!(snb, sector.snb()); 328 let sector = get_sector(address, crate::flash::get_flash_regions());
520 assert_eq!( 329 assert_eq!(snb, sector.snb());
521 FlashSector { 330 assert_eq!(
522 bank, 331 FlashSector {
523 index_in_bank, 332 bank,
524 start, 333 index_in_bank,
525 size 334 start,
526 }, 335 size
527 sector 336 },
528 ) 337 sector
529 }; 338 )
530 339 };
531 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); 340
532 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); 341 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
533 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); 342 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
534 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); 343 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
535 344 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
536 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); 345
537 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); 346 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
538 347 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
539 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); 348
540 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); 349 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
541 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); 350 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
542 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); 351 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
543 352 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
544 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); 353
545 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); 354 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000);
546 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); 355 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF);
547 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); 356 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000);
548 357 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF);
549 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); 358
550 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); 359 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000);
551 360 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF);
552 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); 361
553 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); 362 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000);
554 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); 363 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF);
555 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 364 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
365 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
366 }
367 }
368}
369
370#[cfg(all(bank_setup_configurable))]
371pub(crate) fn check_bank_setup() {
372 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() {
373 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config");
374 }
375 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() {
376 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config");
556 } 377 }
557} 378}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 09ebe9db9..0547c747a 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -1,16 +1,14 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool { 8impl FlashSector {
9 true 9 const fn snb(&self) -> u8 {
10} 10 ((self.bank as u8) << 4) + self.index_in_bank
11 11 }
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14} 12}
15 13
16pub(crate) unsafe fn lock() { 14pub(crate) unsafe fn lock() {
@@ -53,7 +51,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
53pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 51pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
54 pac::FLASH.cr().modify(|w| { 52 pac::FLASH.cr().modify(|w| {
55 w.set_ser(true); 53 w.set_ser(true);
56 w.set_snb(sector.index_in_bank) 54 w.set_snb(sector.snb())
57 }); 55 });
58 56
59 pac::FLASH.cr().modify(|w| { 57 pac::FLASH.cr().modify(|w| {
@@ -118,7 +116,7 @@ mod tests {
118 start, 116 start,
119 size 117 size
120 }, 118 },
121 get_sector(address, &FLASH_REGIONS) 119 get_sector(address, crate::flash::get_flash_regions())
122 ) 120 )
123 }; 121 };
124 122
@@ -137,7 +135,7 @@ mod tests {
137 } 135 }
138 136
139 #[test] 137 #[test]
140 #[cfg(stm32f769)] 138 #[cfg(all(stm32f769, feature = "single-bank"))]
141 fn can_get_sector() { 139 fn can_get_sector() {
142 const SMALL_SECTOR_SIZE: u32 = 32 * 1024; 140 const SMALL_SECTOR_SIZE: u32 = 32 * 1024;
143 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; 141 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024;
@@ -151,7 +149,7 @@ mod tests {
151 start, 149 start,
152 size 150 size
153 }, 151 },
154 get_sector(address, &FLASH_REGIONS) 152 get_sector(address, crate::flash::get_flash_regions())
155 ) 153 )
156 }; 154 };
157 155
@@ -168,4 +166,61 @@ mod tests {
168 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); 166 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000);
169 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 167 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
170 } 168 }
169
170 #[test]
171 #[cfg(all(stm32f769, feature = "dual-bank"))]
172 fn can_get_sector() {
173 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
174 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
175 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
176
177 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32, snb: u8, bank: FlashBank| {
178 assert_eq!(
179 FlashSector {
180 bank: bank,
181 index_in_bank,
182 start,
183 size
184 },
185 get_sector(address, crate::flash::get_flash_regions())
186 );
187 assert_eq!(get_sector(address, crate::flash::get_flash_regions()).snb(), snb);
188 };
189
190 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000, 0x00, FlashBank::Bank1);
191 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF, 0x00, FlashBank::Bank1);
192 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000, 0x03, FlashBank::Bank1);
193 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF, 0x03, FlashBank::Bank1);
194
195 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000, 0x04, FlashBank::Bank1);
196 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF, 0x04, FlashBank::Bank1);
197
198 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000, 0x05, FlashBank::Bank1);
199 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF, 0x05, FlashBank::Bank1);
200 assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000, 0x0A, FlashBank::Bank1);
201 assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080D_FFFF, 0x0A, FlashBank::Bank1);
202
203 assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_0000, 0x10, FlashBank::Bank2);
204 assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_3FFF, 0x10, FlashBank::Bank2);
205 assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_C000, 0x13, FlashBank::Bank2);
206 assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_FFFF, 0x13, FlashBank::Bank2);
207
208 assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_0000, 0x14, FlashBank::Bank2);
209 assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_FFFF, 0x14, FlashBank::Bank2);
210
211 assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0812_0000, 0x15, FlashBank::Bank2);
212 assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0813_FFFF, 0x15, FlashBank::Bank2);
213 assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081C_0000, 0x1A, FlashBank::Bank2);
214 assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081D_FFFF, 0x1A, FlashBank::Bank2);
215 }
216}
217
218#[cfg(all(bank_setup_configurable))]
219pub(crate) fn check_bank_setup() {
220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() {
221 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config");
222 }
223 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() {
224 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config");
225 }
171} 226}
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index 83663743c..bc1fd360c 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -3,18 +3,10 @@ use core::sync::atomic::{fence, Ordering};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() { 10pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true)); 11 pac::FLASH.cr().modify(|w| w.set_lock(true));
20} 12}
@@ -109,3 +101,23 @@ fn wait_busy() {
109fn wait_busy() { 101fn wait_busy() {
110 while pac::FLASH.sr().read().bsy() {} 102 while pac::FLASH.sr().read().bsy() {}
111} 103}
104
105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))]
106pub(crate) fn check_bank_setup() {
107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
108 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config");
109 }
110 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
111 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config");
112 }
113}
114
115#[cfg(all(bank_setup_configurable, flash_g0x1))]
116pub(crate) fn check_bank_setup() {
117 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() {
118 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config");
119 }
120 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() {
121 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config");
122 }
123}
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
index d95de2e38..fd9bfcc75 100644
--- a/embassy-stm32/src/flash/h5.rs
+++ b/embassy-stm32/src/flash/h5.rs
@@ -1,22 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12// const fn is_dual_bank() -> bool {
13// FLASH_REGIONS.len() >= 2
14// }
15
16pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
17 &FLASH_REGIONS
18}
19
20pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
21 if !pac::FLASH.nscr().read().lock() { 9 if !pac::FLASH.nscr().read().lock() {
22 pac::FLASH.nscr().modify(|r| { 10 pac::FLASH.nscr().modify(|r| {
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index 74cd6cc03..f8e210556 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -8,17 +8,9 @@ use cortex_m::interrupt;
8use pac::flash::regs::Nssr; 8use pac::flash::regs::Nssr;
9use pac::flash::vals::Bksel; 9use pac::flash::vals::Bksel;
10 10
11use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 11use super::{Error, FlashBank, FlashSector, WRITE_SIZE};
12use crate::pac; 12use crate::pac;
13 13
14pub(crate) const fn is_default_layout() -> bool {
15 true
16}
17
18pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
19 &FLASH_REGIONS
20}
21
22pub(crate) unsafe fn lock() { 14pub(crate) unsafe fn lock() {
23 pac::FLASH.nscr().modify(|w| w.set_lock(true)); 15 pac::FLASH.nscr().modify(|w| w.set_lock(true));
24} 16}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 254915381..f1d84101c 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,22 +1,14 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12const fn is_dual_bank() -> bool { 8const fn is_dual_bank() -> bool {
13 FLASH_REGIONS.len() >= 2 9 FLASH_REGIONS.len() >= 2
14} 10}
15 11
16pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
17 &FLASH_REGIONS
18}
19
20pub(crate) unsafe fn lock() { 12pub(crate) unsafe fn lock() {
21 pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); 13 pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true));
22 if is_dual_bank() { 14 if is_dual_bank() {
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index ea00bf499..65cea005c 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 #[cfg(any(flash_wl, flash_wb, flash_l4))] 9 #[cfg(any(flash_wl, flash_wb, flash_l4))]
18 pac::FLASH.cr().modify(|w| w.set_lock(true)); 10 pac::FLASH.cr().modify(|w| w.set_lock(true));
@@ -238,3 +230,23 @@ unsafe fn wait_ready_blocking() -> Result<(), Error> {
238 } 230 }
239 } 231 }
240} 232}
233
234#[cfg(all(bank_setup_configurable, flash_l5))]
235pub(crate) fn check_bank_setup() {
236 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
237 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config");
238 }
239 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
240 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config");
241 }
242}
243
244#[cfg(all(bank_setup_configurable, flash_l4))]
245pub(crate) fn check_bank_setup() {
246 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() {
247 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config");
248 }
249 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() {
250 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config");
251 }
252}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index c7488c8ef..adc45db9c 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -14,17 +14,9 @@ pub use common::*;
14pub use crate::_generated::flash_regions::*; 14pub use crate::_generated::flash_regions::*;
15pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; 15pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE};
16 16
17/// Get whether the default flash layout is being used.
18///
19/// In some chips, dual-bank is not default. This will then return `false`
20/// when dual-bank is enabled.
21pub fn is_default_layout() -> bool {
22 family::is_default_layout()
23}
24
25/// Get all flash regions. 17/// Get all flash regions.
26pub fn get_flash_regions() -> &'static [&'static FlashRegion] { 18pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
27 family::get_flash_regions() 19 &FLASH_REGIONS
28} 20}
29 21
30/// Read size (always 1) 22/// Read size (always 1)
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index 20f84a72f..293a79be3 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -1,14 +1,6 @@
1#![allow(unused)] 1#![allow(unused)]
2 2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 3use super::{Error, FlashSector, WRITE_SIZE};
4
5pub(crate) const fn is_default_layout() -> bool {
6 true
7}
8
9pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12 4
13pub(crate) unsafe fn lock() { 5pub(crate) unsafe fn lock() {
14 unimplemented!(); 6 unimplemented!();
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
index bfdbd15a5..68d847eca 100644
--- a/embassy-stm32/src/flash/u0.rs
+++ b/embassy-stm32/src/flash/u0.rs
@@ -3,18 +3,10 @@ use core::sync::atomic::{fence, Ordering};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() { 10pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true)); 11 pac::FLASH.cr().modify(|w| w.set_lock(true));
20} 12}
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index dad698316..131caa195 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashBank, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 #[cfg(feature = "trustzone-secure")] 9 #[cfg(feature = "trustzone-secure")]
18 pac::FLASH.seccr().modify(|w| w.set_lock(true)); 10 pac::FLASH.seccr().modify(|w| w.set_lock(true));
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 226293a9d..f8d09413d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -173,8 +173,9 @@ pub use crate::_generated::interrupt;
173// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. 173// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
174#[macro_export] 174#[macro_export]
175macro_rules! bind_interrupts { 175macro_rules! bind_interrupts {
176 ($vis:vis struct $name:ident { 176 ($(#[$outer:meta])* $vis:vis struct $name:ident {
177 $( 177 $(
178 $(#[$inner:meta])*
178 $(#[cfg($cond_irq:meta)])? 179 $(#[cfg($cond_irq:meta)])?
179 $irq:ident => $( 180 $irq:ident => $(
180 $(#[cfg($cond_handler:meta)])? 181 $(#[cfg($cond_handler:meta)])?
@@ -183,12 +184,14 @@ macro_rules! bind_interrupts {
183 )* 184 )*
184 }) => { 185 }) => {
185 #[derive(Copy, Clone)] 186 #[derive(Copy, Clone)]
187 $(#[$outer])*
186 $vis struct $name; 188 $vis struct $name;
187 189
188 $( 190 $(
189 #[allow(non_snake_case)] 191 #[allow(non_snake_case)]
190 #[no_mangle] 192 #[no_mangle]
191 $(#[cfg($cond_irq)])? 193 $(#[cfg($cond_irq)])?
194 $(#[$inner])*
192 unsafe extern "C" fn $irq() { 195 unsafe extern "C" fn $irq() {
193 $( 196 $(
194 $(#[cfg($cond_handler)])? 197 $(#[cfg($cond_handler)])?
@@ -600,17 +603,7 @@ fn init_hw(config: Config) -> Peripherals {
600 #[cfg(feature = "exti")] 603 #[cfg(feature = "exti")]
601 exti::init(cs); 604 exti::init(cs);
602 605
603 rcc::init(config.rcc); 606 rcc::init_rcc(cs, config.rcc);
604
605 // must be after rcc init
606 #[cfg(feature = "_time-driver")]
607 time_driver::init(cs);
608
609 #[cfg(feature = "low-power")]
610 {
611 crate::rcc::REFCOUNT_STOP2 = 0;
612 crate::rcc::REFCOUNT_STOP1 = 0;
613 }
614 } 607 }
615 608
616 p 609 p
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index b368df6c3..2eb2e61c1 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -239,7 +239,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
239 239
240 T::regs().csr().modify(|w| { 240 T::regs().csr().modify(|w| {
241 w.set_vp_sel(VpSel::from_bits(pin.channel())); 241 w.set_vp_sel(VpSel::from_bits(pin.channel()));
242 w.set_vm_sel(VmSel::OUTPUT); 242 w.set_vm_sel(VmSel::PGA);
243 w.set_pga_gain(pga_gain); 243 w.set_pga_gain(pga_gain);
244 w.set_opaintoen(true); 244 w.set_opaintoen(true);
245 w.set_opampen(true); 245 w.set_opampen(true);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 4f43d3748..3733fed56 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -97,6 +97,8 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
97 97
98pub(crate) trait SealedRccPeripheral { 98pub(crate) trait SealedRccPeripheral {
99 fn frequency() -> Hertz; 99 fn frequency() -> Hertz;
100 #[allow(dead_code)]
101 fn bus_frequency() -> Hertz;
100 const RCC_INFO: RccInfo; 102 const RCC_INFO: RccInfo;
101} 103}
102 104
@@ -369,3 +371,32 @@ pub fn enable_and_reset<T: RccPeripheral>() {
369pub fn disable<T: RccPeripheral>() { 371pub fn disable<T: RccPeripheral>() {
370 T::RCC_INFO.disable(); 372 T::RCC_INFO.disable();
371} 373}
374
375/// Re-initialize the `embassy-stm32` clock configuration with the provided configuration.
376///
377/// This is useful when you need to alter the CPU clock after configuring peripherals.
378/// For instance, configure an external clock via spi or i2c.
379///
380/// Please not this only re-configures the rcc and the time driver (not GPIO, EXTI, etc).
381///
382/// This should only be called after `init`.
383#[cfg(not(feature = "_dual-core"))]
384pub fn reinit(config: Config) {
385 critical_section::with(|cs| init_rcc(cs, config))
386}
387
388pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
389 unsafe {
390 init(config);
391
392 // must be after rcc init
393 #[cfg(feature = "_time-driver")]
394 crate::time_driver::init(_cs);
395
396 #[cfg(feature = "low-power")]
397 {
398 REFCOUNT_STOP2 = 0;
399 REFCOUNT_STOP1 = 0;
400 }
401 }
402}
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index 08dba04fe..9c42217f0 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -223,7 +223,7 @@ impl<'d, T: Instance> Spdifrx<'d, T> {
223 }; 223 };
224 224
225 for sample in data.as_mut() { 225 for sample in data.as_mut() {
226 if (*sample & (0x0002_u32)) == 0x0001 { 226 if (*sample & (0x0002_u32)) != 0 {
227 // Discard invalid samples, setting them to mute level. 227 // Discard invalid samples, setting them to mute level.
228 *sample = 0; 228 *sample = 0;
229 } else { 229 } else {
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 54ab7d0d5..8fd7e8df4 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> {
31/// PWM pin config 31/// PWM pin config
32/// 32///
33/// This configures the pwm pin settings 33/// This configures the pwm pin settings
34#[derive(Debug, Copy, Clone)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub struct PwmPinConfig { 36pub struct PwmPinConfig {
35 /// PWM Pin output type 37 /// PWM Pin output type
36 pub output_type: OutputType, 38 pub output_type: OutputType,
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 2aca3d929..590d1a427 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -549,7 +549,7 @@ foreach_interrupt!(
549); 549);
550 550
551fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 { 551fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
552 let ahb_freq = T::frequency().0; 552 let ahb_freq = T::bus_frequency().0;
553 match speed { 553 match speed {
554 Dspd::HIGH_SPEED => { 554 Dspd::HIGH_SPEED => {
555 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) 555 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446)
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index a0f4b5a74..e7095401e 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker};
6use crate::blocking_mutex::raw::RawMutex; 6use crate::blocking_mutex::raw::RawMutex;
7use crate::blocking_mutex::Mutex; 7use crate::blocking_mutex::Mutex;
8 8
9/// Single-slot signaling primitive. 9/// Single-slot signaling primitive for a _single_ consumer.
10/// 10///
11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except 11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
12/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead 12/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead
@@ -17,6 +17,7 @@ use crate::blocking_mutex::Mutex;
17/// updates. 17/// updates.
18/// 18///
19/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead. 19/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead.
20/// For multiple consumers, use [`Watch`](crate::watch::Watch) instead.
20/// 21///
21/// Signals are generally declared as `static`s and then borrowed as required. 22/// Signals are generally declared as `static`s and then borrowed as required.
22/// 23///
@@ -106,7 +107,7 @@ where
106 }) 107 })
107 } 108 }
108 109
109 /// Future that completes when this Signal has been signaled. 110 /// Future that completes when this Signal has been signaled, taking the value out of the signal.
110 pub fn wait(&self) -> impl Future<Output = T> + '_ { 111 pub fn wait(&self) -> impl Future<Output = T> + '_ {
111 poll_fn(move |cx| self.poll_wait(cx)) 112 poll_fn(move |cx| self.poll_wait(cx))
112 } 113 }
diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs
index e76646c0b..08d6a833d 100644
--- a/embassy-sync/src/watch.rs
+++ b/embassy-sync/src/watch.rs
@@ -10,7 +10,7 @@ use crate::blocking_mutex::raw::RawMutex;
10use crate::blocking_mutex::Mutex; 10use crate::blocking_mutex::Mutex;
11use crate::waitqueue::MultiWakerRegistration; 11use crate::waitqueue::MultiWakerRegistration;
12 12
13/// The `Watch` is a single-slot signaling primitive that allows multiple receivers to concurrently await 13/// The `Watch` is a single-slot signaling primitive that allows _multiple_ (`N`) receivers to concurrently await
14/// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers, 14/// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers,
15/// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous 15/// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous
16/// value when a new one is sent, without waiting for all receivers to read the previous value. 16/// value when a new one is sent, without waiting for all receivers to read the previous value.
@@ -298,7 +298,7 @@ impl<M: RawMutex, T: Clone, const N: usize> WatchBehavior<T> for Watch<M, T, N>
298} 298}
299 299
300impl<M: RawMutex, T: Clone, const N: usize> Watch<M, T, N> { 300impl<M: RawMutex, T: Clone, const N: usize> Watch<M, T, N> {
301 /// Create a new `Watch` channel. 301 /// Create a new `Watch` channel for `N` receivers.
302 pub const fn new() -> Self { 302 pub const fn new() -> Self {
303 Self { 303 Self {
304 mutex: Mutex::new(RefCell::new(WatchState { 304 mutex: Mutex::new(RefCell::new(WatchState {
diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml
index b709cafc1..16213cb75 100644
--- a/embassy-time-driver/Cargo.toml
+++ b/embassy-time-driver/Cargo.toml
@@ -226,6 +226,8 @@ tick-hz-128_000_000 = []
226tick-hz-130_000_000 = [] 226tick-hz-130_000_000 = []
227## 131.072MHz Tick Rate 227## 131.072MHz Tick Rate
228tick-hz-131_072_000 = [] 228tick-hz-131_072_000 = []
229## 133.0MHz Tick Rate
230tick-hz-133_000_000 = []
229## 140.0MHz Tick Rate 231## 140.0MHz Tick Rate
230tick-hz-140_000_000 = [] 232tick-hz-140_000_000 = []
231## 144.0MHz Tick Rate 233## 144.0MHz Tick Rate
diff --git a/embassy-time-driver/gen_tick.py b/embassy-time-driver/gen_tick.py
index af194c31f..080434457 100644
--- a/embassy-time-driver/gen_tick.py
+++ b/embassy-time-driver/gen_tick.py
@@ -22,6 +22,7 @@ for i in range(1, 30):
22 ticks.append(10 * i * 1_000_000) 22 ticks.append(10 * i * 1_000_000)
23for i in range(15, 50): 23for i in range(15, 50):
24 ticks.append(20 * i * 1_000_000) 24 ticks.append(20 * i * 1_000_000)
25ticks.append(133 * 1_000_000)
25 26
26seen = set() 27seen = set()
27ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) 28ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))])
diff --git a/embassy-time-driver/src/tick.rs b/embassy-time-driver/src/tick.rs
index 916ae9498..5059e1628 100644
--- a/embassy-time-driver/src/tick.rs
+++ b/embassy-time-driver/src/tick.rs
@@ -182,6 +182,8 @@ pub const TICK_HZ: u64 = 128_000_000;
182pub const TICK_HZ: u64 = 130_000_000; 182pub const TICK_HZ: u64 = 130_000_000;
183#[cfg(feature = "tick-hz-131_072_000")] 183#[cfg(feature = "tick-hz-131_072_000")]
184pub const TICK_HZ: u64 = 131_072_000; 184pub const TICK_HZ: u64 = 131_072_000;
185#[cfg(feature = "tick-hz-133_000_000")]
186pub const TICK_HZ: u64 = 133_000_000;
185#[cfg(feature = "tick-hz-140_000_000")] 187#[cfg(feature = "tick-hz-140_000_000")]
186pub const TICK_HZ: u64 = 140_000_000; 188pub const TICK_HZ: u64 = 140_000_000;
187#[cfg(feature = "tick-hz-144_000_000")] 189#[cfg(feature = "tick-hz-144_000_000")]
@@ -410,6 +412,7 @@ pub const TICK_HZ: u64 = 5_242_880_000;
410 feature = "tick-hz-128_000_000", 412 feature = "tick-hz-128_000_000",
411 feature = "tick-hz-130_000_000", 413 feature = "tick-hz-130_000_000",
412 feature = "tick-hz-131_072_000", 414 feature = "tick-hz-131_072_000",
415 feature = "tick-hz-133_000_000",
413 feature = "tick-hz-140_000_000", 416 feature = "tick-hz-140_000_000",
414 feature = "tick-hz-144_000_000", 417 feature = "tick-hz-144_000_000",
415 feature = "tick-hz-150_000_000", 418 feature = "tick-hz-150_000_000",
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 80a39dbf5..dc144ec3c 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -274,6 +274,8 @@ tick-hz-128_000_000 = ["embassy-time-driver/tick-hz-128_000_000"]
274tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] 274tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"]
275## 131.072MHz Tick Rate 275## 131.072MHz Tick Rate
276tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] 276tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"]
277## 133.0MHz Tick Rate
278tick-hz-133_000_000 = ["embassy-time-driver/tick-hz-133_000_000"]
277## 140.0MHz Tick Rate 279## 140.0MHz Tick Rate
278tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] 280tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"]
279## 144.0MHz Tick Rate 281## 144.0MHz Tick Rate
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index f0d7626f6..6ad07a78c 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -1,5 +1,3 @@
1use core::marker::PhantomData;
2
3use embassy_boot::BlockingFirmwareState; 1use embassy_boot::BlockingFirmwareState;
4use embassy_time::{Duration, Instant}; 2use embassy_time::{Duration, Instant};
5use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
@@ -13,31 +11,47 @@ use crate::consts::{
13}; 11};
14use crate::Reset; 12use crate::Reset;
15 13
14/// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot.
15///
16/// By default this trait is implemented for `BlockingFirmwareState<'d, STATE>` but you could also implement this generic
17/// interface yourself instead in more complex situations. This could for instance be when you cannot hand ownership of a
18/// `BlockingFirmwareState` instance over directly to the DFU `Control` instance and need to use a more complex mechanism.
19pub trait DfuMarker {
20 /// Signal to the bootloader that DFU mode should be used on the next boot.
21 fn mark_dfu(&mut self);
22}
23
24impl<'d, STATE: NorFlash> DfuMarker for BlockingFirmwareState<'d, STATE> {
25 fn mark_dfu(&mut self) {
26 self.mark_dfu().expect("Failed to mark DFU mode in bootloader")
27 }
28}
29
16/// Internal state for the DFU class 30/// Internal state for the DFU class
17pub struct Control<'d, STATE: NorFlash, RST: Reset> { 31pub struct Control<MARK: DfuMarker, RST: Reset> {
18 firmware_state: BlockingFirmwareState<'d, STATE>, 32 dfu_marker: MARK,
19 attrs: DfuAttributes, 33 attrs: DfuAttributes,
20 state: State, 34 state: State,
21 timeout: Option<Duration>, 35 timeout: Option<Duration>,
22 detach_start: Option<Instant>, 36 detach_start: Option<Instant>,
23 _rst: PhantomData<RST>, 37 reset: RST,
24} 38}
25 39
26impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { 40impl<MARK: DfuMarker, RST: Reset> Control<MARK, RST> {
27 /// Create a new DFU instance to expose a DFU interface. 41 /// Create a new DFU instance to expose a DFU interface.
28 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { 42 pub fn new(dfu_marker: MARK, attrs: DfuAttributes, reset: RST) -> Self {
29 Control { 43 Control {
30 firmware_state, 44 dfu_marker,
31 attrs, 45 attrs,
32 state: State::AppIdle, 46 state: State::AppIdle,
33 detach_start: None, 47 detach_start: None,
34 timeout: None, 48 timeout: None,
35 _rst: PhantomData, 49 reset,
36 } 50 }
37 } 51 }
38} 52}
39 53
40impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { 54impl<MARK: DfuMarker, RST: Reset> Handler for Control<MARK, RST> {
41 fn reset(&mut self) { 55 fn reset(&mut self) {
42 if let Some(start) = self.detach_start { 56 if let Some(start) = self.detach_start {
43 let delta = Instant::now() - start; 57 let delta = Instant::now() - start;
@@ -48,10 +62,8 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
48 timeout.as_millis() 62 timeout.as_millis()
49 ); 63 );
50 if delta < timeout { 64 if delta < timeout {
51 self.firmware_state 65 self.dfu_marker.mark_dfu();
52 .mark_dfu() 66 self.reset.sys_reset()
53 .expect("Failed to mark DFU mode in bootloader");
54 RST::sys_reset()
55 } 67 }
56 } 68 }
57 } 69 }
@@ -69,10 +81,15 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
69 81
70 match Request::try_from(req.request) { 82 match Request::try_from(req.request) {
71 Ok(Request::Detach) => { 83 Ok(Request::Detach) => {
72 trace!("Received DETACH, awaiting USB reset");
73 self.detach_start = Some(Instant::now()); 84 self.detach_start = Some(Instant::now());
74 self.timeout = Some(Duration::from_millis(req.value as u64)); 85 self.timeout = Some(Duration::from_millis(req.value as u64));
75 self.state = State::AppDetach; 86 self.state = State::AppDetach;
87 if self.attrs.contains(DfuAttributes::WILL_DETACH) {
88 trace!("Received DETACH, performing reset");
89 self.reset();
90 } else {
91 trace!("Received DETACH, awaiting USB reset");
92 }
76 Some(OutResponse::Accepted) 93 Some(OutResponse::Accepted)
77 } 94 }
78 _ => None, 95 _ => None,
@@ -109,9 +126,9 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
109/// it should expose a DFU device, and a software reset will be issued. 126/// it should expose a DFU device, and a software reset will be issued.
110/// 127///
111/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. 128/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host.
112pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( 129pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>(
113 builder: &mut Builder<'d, D>, 130 builder: &mut Builder<'d, D>,
114 handler: &'d mut Control<'d, STATE, RST>, 131 handler: &'d mut Control<MARK, RST>,
115 timeout: Duration, 132 timeout: Duration,
116) { 133) {
117 let mut func = builder.function(0x00, 0x00, 0x00); 134 let mut func = builder.function(0x00, 0x00, 0x00);
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
index c23286cf5..a98d6ab40 100644
--- a/embassy-usb-dfu/src/dfu.rs
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -1,5 +1,3 @@
1use core::marker::PhantomData;
2
3use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; 1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
5use embassy_usb::driver::Driver; 3use embassy_usb::driver::Driver;
@@ -20,12 +18,12 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
20 status: Status, 18 status: Status,
21 offset: usize, 19 offset: usize,
22 buf: AlignedBuffer<BLOCK_SIZE>, 20 buf: AlignedBuffer<BLOCK_SIZE>,
23 _rst: PhantomData<RST>, 21 reset: RST,
24} 22}
25 23
26impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { 24impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
27 /// Create a new DFU instance to handle DFU transfers. 25 /// Create a new DFU instance to handle DFU transfers.
28 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { 26 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, reset: RST) -> Self {
29 Self { 27 Self {
30 updater, 28 updater,
31 attrs, 29 attrs,
@@ -33,7 +31,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co
33 status: Status::Ok, 31 status: Status::Ok,
34 offset: 0, 32 offset: 0,
35 buf: AlignedBuffer([0; BLOCK_SIZE]), 33 buf: AlignedBuffer([0; BLOCK_SIZE]),
36 _rst: PhantomData, 34 reset,
37 } 35 }
38 } 36 }
39 37
@@ -155,14 +153,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
155 } 153 }
156 match Request::try_from(req.request) { 154 match Request::try_from(req.request) {
157 Ok(Request::GetStatus) => { 155 Ok(Request::GetStatus) => {
158 //TODO: Configurable poll timeout, ability to add string for Vendor error
159 buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
160 match self.state { 156 match self.state {
161 State::DlSync => self.state = State::Download, 157 State::DlSync => self.state = State::Download,
162 State::ManifestSync => RST::sys_reset(), 158 State::ManifestSync => self.reset.sys_reset(),
163 _ => {} 159 _ => {}
164 } 160 }
165 161
162 //TODO: Configurable poll timeout, ability to add string for Vendor error
163 buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
166 Some(InResponse::Accepted(&buf[0..6])) 164 Some(InResponse::Accepted(&buf[0..6]))
167 } 165 }
168 Ok(Request::GetState) => { 166 Ok(Request::GetState) => {
diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs
index eaa4b6e33..54ffa7276 100644
--- a/embassy-usb-dfu/src/lib.rs
+++ b/embassy-usb-dfu/src/lib.rs
@@ -26,10 +26,10 @@ compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `applicat
26/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a 26/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
27/// reset request without interfacing with any other peripherals. 27/// reset request without interfacing with any other peripherals.
28/// 28///
29/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. 29/// If alternate behaviour is desired, a custom implementation of Reset can be provided as an argument to the usb_dfu function.
30pub trait Reset { 30pub trait Reset {
31 /// Reset the device. 31 /// Reset the device.
32 fn sys_reset() -> !; 32 fn sys_reset(&self);
33} 33}
34 34
35/// Reset immediately. 35/// Reset immediately.
@@ -38,7 +38,7 @@ pub struct ResetImmediate;
38 38
39#[cfg(feature = "esp32c3-hal")] 39#[cfg(feature = "esp32c3-hal")]
40impl Reset for ResetImmediate { 40impl Reset for ResetImmediate {
41 fn sys_reset() -> ! { 41 fn sys_reset(&self) {
42 esp32c3_hal::reset::software_reset(); 42 esp32c3_hal::reset::software_reset();
43 loop {} 43 loop {}
44 } 44 }
@@ -50,7 +50,7 @@ pub struct ResetImmediate;
50 50
51#[cfg(feature = "cortex-m")] 51#[cfg(feature = "cortex-m")]
52impl Reset for ResetImmediate { 52impl Reset for ResetImmediate {
53 fn sys_reset() -> ! { 53 fn sys_reset(&self) {
54 cortex_m::peripheral::SCB::sys_reset() 54 cortex_m::peripheral::SCB::sys_reset()
55 } 55 }
56} 56}
diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml
index 41493f00d..edb6551b0 100644
--- a/embassy-usb-driver/Cargo.toml
+++ b/embassy-usb-driver/Cargo.toml
@@ -20,3 +20,4 @@ features = ["defmt"]
20 20
21[dependencies] 21[dependencies]
22defmt = { version = "0.3", optional = true } 22defmt = { version = "0.3", optional = true }
23embedded-io-async = "0.6.1"
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index 3b705c8c4..d204e4d85 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -395,3 +395,12 @@ pub enum EndpointError {
395 /// The endpoint is disabled. 395 /// The endpoint is disabled.
396 Disabled, 396 Disabled,
397} 397}
398
399impl embedded_io_async::Error for EndpointError {
400 fn kind(&self) -> embedded_io_async::ErrorKind {
401 match self {
402 Self::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory,
403 Self::Disabled => embedded_io_async::ErrorKind::NotConnected,
404 }
405 }
406}
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 771190c89..4950fbe2a 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -52,6 +52,7 @@ embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
52embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } 52embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
53 53
54defmt = { version = "0.3", optional = true } 54defmt = { version = "0.3", optional = true }
55embedded-io-async = "0.6.1"
55log = { version = "0.4.14", optional = true } 56log = { version = "0.4.14", optional = true }
56heapless = "0.8" 57heapless = "0.8"
57 58
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index ea9d9fb7b..732a433f8 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -410,6 +410,18 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
410 } 410 }
411} 411}
412 412
413impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for Sender<'d, D> {
414 type Error = EndpointError;
415}
416
417impl<'d, D: Driver<'d>> embedded_io_async::Write for Sender<'d, D> {
418 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
419 let len = core::cmp::min(buf.len(), self.max_packet_size() as usize);
420 self.write_packet(&buf[..len]).await?;
421 Ok(len)
422 }
423}
424
413/// CDC ACM class packet receiver. 425/// CDC ACM class packet receiver.
414/// 426///
415/// You can obtain a `Receiver` with [`CdcAcmClass::split`] 427/// You can obtain a `Receiver` with [`CdcAcmClass::split`]
@@ -451,6 +463,93 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
451 pub async fn wait_connection(&mut self) { 463 pub async fn wait_connection(&mut self) {
452 self.read_ep.wait_enabled().await; 464 self.read_ep.wait_enabled().await;
453 } 465 }
466
467 /// Turn the `Receiver` into a [`BufferedReceiver`].
468 ///
469 /// The supplied buffer must be large enough to hold max_packet_size bytes.
470 pub fn into_buffered(self, buf: &'d mut [u8]) -> BufferedReceiver<'d, D> {
471 BufferedReceiver {
472 receiver: self,
473 buffer: buf,
474 start: 0,
475 end: 0,
476 }
477 }
478}
479
480/// CDC ACM class buffered receiver.
481///
482/// It is a requirement of the [`embedded_io_async::Read`] trait that arbitrarily small lengths of
483/// data can be read from the stream. The [`Receiver`] can only read full packets at a time. The
484/// `BufferedReceiver` instead buffers a single packet if the caller does not read all of the data,
485/// so that the remaining data can be returned in subsequent calls.
486///
487/// If you have no requirement to use the [`embedded_io_async::Read`] trait or to read a data length
488/// less than the packet length, then it is more efficient to use the [`Receiver`] directly.
489///
490/// You can obtain a `BufferedReceiver` with [`Receiver::into_buffered`].
491///
492/// [`embedded_io_async::Read`]: https://docs.rs/embedded-io-async/latest/embedded_io_async/trait.Read.html
493pub struct BufferedReceiver<'d, D: Driver<'d>> {
494 receiver: Receiver<'d, D>,
495 buffer: &'d mut [u8],
496 start: usize,
497 end: usize,
498}
499
500impl<'d, D: Driver<'d>> BufferedReceiver<'d, D> {
501 fn read_from_buffer(&mut self, buf: &mut [u8]) -> usize {
502 let available = &self.buffer[self.start..self.end];
503 let len = core::cmp::min(available.len(), buf.len());
504 buf[..len].copy_from_slice(&self.buffer[..len]);
505 self.start += len;
506 len
507 }
508
509 /// Gets the current line coding. The line coding contains information that's mainly relevant
510 /// for USB to UART serial port emulators, and can be ignored if not relevant.
511 pub fn line_coding(&self) -> LineCoding {
512 self.receiver.line_coding()
513 }
514
515 /// Gets the DTR (data terminal ready) state
516 pub fn dtr(&self) -> bool {
517 self.receiver.dtr()
518 }
519
520 /// Gets the RTS (request to send) state
521 pub fn rts(&self) -> bool {
522 self.receiver.rts()
523 }
524
525 /// Waits for the USB host to enable this interface
526 pub async fn wait_connection(&mut self) {
527 self.receiver.wait_connection().await;
528 }
529}
530
531impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for BufferedReceiver<'d, D> {
532 type Error = EndpointError;
533}
534
535impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> {
536 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
537 // If there is a buffered packet, return data from that first
538 if self.start != self.end {
539 return Ok(self.read_from_buffer(buf));
540 }
541
542 // If the caller's buffer is large enough to contain an entire packet, read directly into
543 // that instead of buffering the packet internally.
544 if buf.len() > self.receiver.max_packet_size() as usize {
545 return self.receiver.read_packet(buf).await;
546 }
547
548 // Otherwise read a packet into the internal buffer, and return some of it to the caller
549 self.start = 0;
550 self.end = self.receiver.read_packet(&mut self.buffer).await?;
551 return Ok(self.read_from_buffer(buf));
552 }
454} 553}
455 554
456/// Number of stop bits for LineCoding 555/// Number of stop bits for LineCoding
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 6a5a500de..d62c67742 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index 0ab99ff90..dda2b795b 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
44 let mut config_descriptor = [0; 256]; 44 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256]; 45 let mut bos_descriptor = [0; 256];
46 let mut control_buf = [0; 64]; 46 let mut control_buf = [0; 64];
47 let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD); 47 let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
48 let mut builder = Builder::new( 48 let mut builder = Builder::new(
49 driver, 49 driver,
50 config, 50 config,
@@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) {
54 &mut control_buf, 54 &mut control_buf,
55 ); 55 );
56 56
57 usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500)); 57 usb_dfu(&mut builder, &mut state, Duration::from_millis(2500));
58 58
59 let mut dev = builder.build(); 59 let mut dev = builder.build();
60 dev.run().await 60 dev.run().await
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 127de0237..e4526927f 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -20,7 +20,7 @@ static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))] 20#[cfg(not(feature = "skip-include"))]
21static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
22 22
23#[link_section = ".shared_data"] 23#[unsafe(link_section = ".shared_data")]
24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
25 25
26#[embassy_executor::main] 26#[embassy_executor::main]
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index 768dadf8b..6016a9555 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -11,7 +11,7 @@ use embassy_stm32::SharedData;
11use embassy_time::Timer; 11use embassy_time::Timer;
12use panic_reset as _; 12use panic_reset as _;
13 13
14#[link_section = ".shared_data"] 14#[unsafe(link_section = ".shared_data")]
15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
16 16
17#[embassy_executor::main] 17#[embassy_executor::main]
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index b09d53cf0..28216806e 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -55,7 +55,7 @@ fn main() -> ! {
55 let mut config_descriptor = [0; 256]; 55 let mut config_descriptor = [0; 256];
56 let mut bos_descriptor = [0; 256]; 56 let mut bos_descriptor = [0; 256];
57 let mut control_buf = [0; 4096]; 57 let mut control_buf = [0; 4096];
58 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); 58 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
59 let mut builder = Builder::new( 59 let mut builder = Builder::new(
60 driver, 60 driver,
61 config, 61 config,
@@ -77,7 +77,7 @@ fn main() -> ! {
77 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), 77 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
78 )); 78 ));
79 79
80 usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); 80 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state);
81 81
82 let mut dev = builder.build(); 82 let mut dev = builder.build();
83 embassy_futures::block_on(dev.run()); 83 embassy_futures::block_on(dev.run());
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
index 8fc510c47..b0c56f003 100644
--- a/examples/mimxrt6/Cargo.toml
+++ b/examples/mimxrt6/Cargo.toml
@@ -12,8 +12,8 @@ defmt-rtt = "1.0"
12 12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-rtc"] } 15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] }
16embassy-time = { version = "0.4", path = "../../embassy-time" } 16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0" 19embedded-hal-async = "1.0.0"
diff --git a/examples/mimxrt6/build.rs b/examples/mimxrt6/build.rs
index 9c0ed3213..56010dfd6 100644
--- a/examples/mimxrt6/build.rs
+++ b/examples/mimxrt6/build.rs
@@ -25,7 +25,7 @@ fn main() {
25 .write_all( 25 .write_all(
26 format!( 26 format!(
27 r##" 27 r##"
28#[link_section = ".biv"] 28#[unsafe(link_section = ".biv")]
29#[used] 29#[used]
30static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00; 30static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00;
31"##, 31"##,
diff --git a/examples/mimxrt6/src/bin/crc.rs b/examples/mimxrt6/src/bin/crc.rs
new file mode 100644
index 000000000..005a250e5
--- /dev/null
+++ b/examples/mimxrt6/src/bin/crc.rs
@@ -0,0 +1,175 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_imxrt::crc::{Config, Crc, Polynomial};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let mut p = embassy_imxrt::init(Default::default());
14 let data = b"123456789";
15
16 info!("Initializing CRC");
17
18 // CRC-CCITT
19 let mut crc = Crc::new(p.CRC.reborrow(), Default::default());
20 let output = crc.feed_bytes(data);
21 defmt::assert_eq!(output, 0x29b1);
22
23 // CRC16-ARC
24 let mut crc = Crc::new(
25 p.CRC.reborrow(),
26 Config {
27 polynomial: Polynomial::Crc16,
28 reverse_in: true,
29 reverse_out: true,
30 complement_out: false,
31 seed: 0,
32 ..Default::default()
33 },
34 );
35 let output = crc.feed_bytes(data);
36 defmt::assert_eq!(output, 0xbb3d);
37
38 // CRC16-CMS
39 let mut crc = Crc::new(
40 p.CRC.reborrow(),
41 Config {
42 polynomial: Polynomial::Crc16,
43 reverse_in: false,
44 reverse_out: false,
45 complement_out: false,
46 seed: 0xffff,
47 ..Default::default()
48 },
49 );
50 let output = crc.feed_bytes(data);
51 defmt::assert_eq!(output, 0xaee7);
52
53 // CRC16-DDS-110
54 let mut crc = Crc::new(
55 p.CRC.reborrow(),
56 Config {
57 polynomial: Polynomial::Crc16,
58 reverse_in: false,
59 reverse_out: false,
60 complement_out: false,
61 seed: 0x800d,
62 ..Default::default()
63 },
64 );
65 let output = crc.feed_bytes(data);
66 defmt::assert_eq!(output, 0x9ecf);
67
68 // CRC16-MAXIM-DOW
69 let mut crc = Crc::new(
70 p.CRC.reborrow(),
71 Config {
72 polynomial: Polynomial::Crc16,
73 reverse_in: true,
74 reverse_out: true,
75 complement_out: true,
76 seed: 0,
77 ..Default::default()
78 },
79 );
80 let output = crc.feed_bytes(data);
81 defmt::assert_eq!(output, 0x44c2);
82
83 // CRC16-MODBUS
84 let mut crc = Crc::new(
85 p.CRC.reborrow(),
86 Config {
87 polynomial: Polynomial::Crc16,
88 reverse_in: true,
89 reverse_out: true,
90 complement_out: false,
91 seed: 0xffff,
92 ..Default::default()
93 },
94 );
95 let output = crc.feed_bytes(data);
96 defmt::assert_eq!(output, 0x4b37);
97
98 // CRC32-BZIP2
99 let mut crc = Crc::new(
100 p.CRC.reborrow(),
101 Config {
102 polynomial: Polynomial::Crc32,
103 reverse_in: false,
104 reverse_out: false,
105 complement_out: true,
106 seed: 0xffff_ffff,
107 ..Default::default()
108 },
109 );
110 let output = crc.feed_bytes(data);
111 defmt::assert_eq!(output, 0xfc89_1918);
112
113 // CRC32-CKSUM
114 let mut crc = Crc::new(
115 p.CRC.reborrow(),
116 Config {
117 polynomial: Polynomial::Crc32,
118 reverse_in: false,
119 reverse_out: false,
120 complement_out: true,
121 seed: 0,
122 ..Default::default()
123 },
124 );
125 let output = crc.feed_bytes(data);
126 defmt::assert_eq!(output, 0x765e_7680);
127
128 // CRC32-ISO-HDLC
129 let mut crc = Crc::new(
130 p.CRC.reborrow(),
131 Config {
132 polynomial: Polynomial::Crc32,
133 reverse_in: true,
134 reverse_out: true,
135 complement_out: true,
136 seed: 0xffff_ffff,
137 ..Default::default()
138 },
139 );
140 let output = crc.feed_bytes(data);
141 defmt::assert_eq!(output, 0xcbf4_3926);
142
143 // CRC32-JAMCRC
144 let mut crc = Crc::new(
145 p.CRC.reborrow(),
146 Config {
147 polynomial: Polynomial::Crc32,
148 reverse_in: true,
149 reverse_out: true,
150 complement_out: false,
151 seed: 0xffff_ffff,
152 ..Default::default()
153 },
154 );
155 let output = crc.feed_bytes(data);
156 defmt::assert_eq!(output, 0x340b_c6d9);
157
158 // CRC32-MPEG-2
159 let mut crc = Crc::new(
160 p.CRC.reborrow(),
161 Config {
162 polynomial: Polynomial::Crc32,
163 reverse_in: false,
164 reverse_out: false,
165 complement_out: false,
166 seed: 0xffff_ffff,
167 ..Default::default()
168 },
169 );
170 let output = crc.feed_bytes(data);
171 defmt::assert_eq!(output, 0x0376_e6e7);
172
173 info!("end program");
174 cortex_m::asm::bkpt();
175}
diff --git a/examples/mimxrt6/src/bin/rng.rs b/examples/mimxrt6/src/bin/rng.rs
new file mode 100644
index 000000000..5f64cb96a
--- /dev/null
+++ b/examples/mimxrt6/src/bin/rng.rs
@@ -0,0 +1,40 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_imxrt::rng::Rng;
9use embassy_imxrt::{bind_interrupts, peripherals, rng};
10use rand::RngCore;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 RNG => rng::InterruptHandler<peripherals::RNG>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_imxrt::init(Default::default());
20
21 info!("Initializing RNG");
22 let mut rng = Rng::new(p.RNG, Irqs);
23 let mut buf = [0u8; 65];
24
25 // Async interface
26 unwrap!(rng.async_fill_bytes(&mut buf).await);
27 info!("random bytes: {:02x}", buf);
28
29 // RngCore interface
30 let mut random_bytes = [0; 16];
31
32 let random_u32 = rng.next_u32();
33 let random_u64 = rng.next_u64();
34
35 rng.fill_bytes(&mut random_bytes);
36
37 info!("random_u32 {}", random_u32);
38 info!("random_u64 {}", random_u64);
39 info!("random_bytes {}", random_bytes);
40}
diff --git a/examples/mimxrt6/src/lib.rs b/examples/mimxrt6/src/lib.rs
index da6e14427..3c3ea1981 100644
--- a/examples/mimxrt6/src/lib.rs
+++ b/examples/mimxrt6/src/lib.rs
@@ -6,15 +6,15 @@ use {defmt_rtt as _, panic_probe as _};
6// auto-generated version information from Cargo.toml 6// auto-generated version information from Cargo.toml
7include!(concat!(env!("OUT_DIR"), "/biv.rs")); 7include!(concat!(env!("OUT_DIR"), "/biv.rs"));
8 8
9#[link_section = ".otfad"] 9#[unsafe(link_section = ".otfad")]
10#[used] 10#[used]
11static OTFAD: [u8; 256] = [0; 256]; 11static OTFAD: [u8; 256] = [0; 256];
12 12
13#[rustfmt::skip] 13#[rustfmt::skip]
14#[link_section = ".fcb"] 14#[unsafe(link_section = ".fcb")]
15#[used] 15#[used]
16static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build(); 16static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build();
17 17
18#[link_section = ".keystore"] 18#[unsafe(link_section = ".keystore")]
19#[used] 19#[used]
20static KEYSTORE: [u8; 2048] = [0; 2048]; 20static KEYSTORE: [u8; 2048] = [0; 2048];
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index ceaafd784..e30a3855d 100644
--- a/examples/nrf52840/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -9,6 +9,7 @@ use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_nrf::twim::{self, Twim}; 10use embassy_nrf::twim::{self, Twim};
11use embassy_nrf::{bind_interrupts, peripherals}; 11use embassy_nrf::{bind_interrupts, peripherals};
12use static_cell::ConstStaticCell;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
14const ADDRESS: u8 = 0x50; 15const ADDRESS: u8 = 0x50;
@@ -22,7 +23,8 @@ async fn main(_spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
23 info!("Initializing TWI..."); 24 info!("Initializing TWI...");
24 let config = twim::Config::default(); 25 let config = twim::Config::default();
25 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); 26 static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]);
27 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config, RAM_BUFFER.take());
26 28
27 info!("Reading..."); 29 info!("Reading...");
28 30
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index 8a6f958eb..f7380e20d 100644
--- a/examples/nrf52840/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -30,6 +30,7 @@ async fn main(_p: Spawner) {
30 loop { 30 loop {
31 info!("Initializing TWI..."); 31 info!("Initializing TWI...");
32 let config = twim::Config::default(); 32 let config = twim::Config::default();
33 let mut ram_buffer = [0u8; 16];
33 34
34 // Create the TWIM instance with borrowed singletons, so they're not consumed. 35 // Create the TWIM instance with borrowed singletons, so they're not consumed.
35 let mut twi = Twim::new( 36 let mut twi = Twim::new(
@@ -38,6 +39,7 @@ async fn main(_p: Spawner) {
38 p.P0_03.reborrow(), 39 p.P0_03.reborrow(),
39 p.P0_04.reborrow(), 40 p.P0_04.reborrow(),
40 config, 41 config,
42 &mut ram_buffer,
41 ); 43 );
42 44
43 info!("Reading..."); 45 info!("Reading...");
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs
new file mode 100644
index 000000000..83b17308b
--- /dev/null
+++ b/examples/rp/src/bin/overclock.rs
@@ -0,0 +1,64 @@
1//! # Overclocking the RP2040 to 200 MHz
2//!
3//! This example demonstrates how to configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig};
11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
21 let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap());
22
23 // Initialize the peripherals
24 let p = embassy_rp::init(config);
25
26 // Show CPU frequency for verification
27 let sys_freq = clk_sys_freq();
28 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
29 // Show core voltage for verification
30 let core_voltage = core_voltage().unwrap();
31 info!("Core voltage: {}", core_voltage);
32
33 // LED to indicate the system is running
34 let mut led = Output::new(p.PIN_25, Level::Low);
35
36 loop {
37 // Reset the counter at the start of measurement period
38 let mut counter = 0;
39
40 // Turn LED on while counting
41 led.set_high();
42
43 let start = Instant::now();
44
45 // This is a busy loop that will take some time to complete
46 while counter < COUNT_TO {
47 counter += 1;
48 }
49
50 let elapsed = Instant::now() - start;
51
52 // Report the elapsed time
53 led.set_low();
54 info!(
55 "At {}Mhz: Elapsed time to count to {}: {}ms",
56 sys_freq / 1_000_000,
57 counter,
58 elapsed.as_millis()
59 );
60
61 // Wait 2 seconds before starting the next measurement
62 Timer::after(Duration::from_secs(2)).await;
63 }
64}
diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs
new file mode 100644
index 000000000..dea5cfb3c
--- /dev/null
+++ b/examples/rp/src/bin/overclock_manual.rs
@@ -0,0 +1,81 @@
1//! # Overclocking the RP2040 to 200 MHz manually
2//!
3//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig};
11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings.
19fn configure_manual_overclock() -> Config {
20 // Set the PLL configuration manually, starting from default values
21 let mut config = Config::default();
22
23 // Set the system clock to 200 MHz
24 config.clocks = ClockConfig::manual_pll(
25 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value.
26 PllConfig {
27 refdiv: 1, // Reference divider
28 fbdiv: 100, // Feedback divider
29 post_div1: 3, // Post divider 1
30 post_div2: 2, // Post divider 2
31 },
32 CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz
33 );
34
35 config
36}
37
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) -> ! {
40 // Initialize with our manual overclock configuration
41 let p = embassy_rp::init(configure_manual_overclock());
42
43 // Show CPU frequency for verification
44 let sys_freq = clk_sys_freq();
45 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
46 // Show core voltage for verification
47 let core_voltage = core_voltage().unwrap();
48 info!("Core voltage: {}", core_voltage);
49
50 // LED to indicate the system is running
51 let mut led = Output::new(p.PIN_25, Level::Low);
52
53 loop {
54 // Reset the counter at the start of measurement period
55 let mut counter = 0;
56
57 // Turn LED on while counting
58 led.set_high();
59
60 let start = Instant::now();
61
62 // This is a busy loop that will take some time to complete
63 while counter < COUNT_TO {
64 counter += 1;
65 }
66
67 let elapsed = Instant::now() - start;
68
69 // Report the elapsed time
70 led.set_low();
71 info!(
72 "At {}Mhz: Elapsed time to count to {}: {}ms",
73 sys_freq / 1_000_000,
74 counter,
75 elapsed.as_millis()
76 );
77
78 // Wait 2 seconds before starting the next measurement
79 Timer::after(Duration::from_secs(2)).await;
80 }
81}
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs
index 5416e20ce..497c4f845 100644
--- a/examples/rp/src/bin/sharing.rs
+++ b/examples/rp/src/bin/sharing.rs
@@ -31,7 +31,7 @@ use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell}; 31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
33 33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; 34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
35 35
36struct MyType { 36struct MyType {
37 inner: u32, 37 inner: u32,
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index da7e94139..3adbc18ab 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
52 info!("Reading..."); 52 info!("Reading...");
53 loop { 53 loop {
54 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
index a45f40756..c2c8dfad8 100644
--- a/examples/rp/src/bin/uart_unidir.rs
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
43 info!("Reading..."); 43 info!("Reading...");
44 loop { 44 loop {
45 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/examples/rp235x/src/bin/blinky.rs b/examples/rp235x/src/bin/blinky.rs
index a36029f92..8a2464fbb 100644
--- a/examples/rp235x/src/bin/blinky.rs
+++ b/examples/rp235x/src/bin/blinky.rs
@@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _};
14 14
15// Program metadata for `picotool info`. 15// Program metadata for `picotool info`.
16// This isn't needed, but it's recomended to have these minimal entries. 16// This isn't needed, but it's recomended to have these minimal entries.
17#[link_section = ".bi_entries"] 17#[unsafe(link_section = ".bi_entries")]
18#[used] 18#[used]
19pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 19pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
20 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), 20 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"),
diff --git a/examples/rp235x/src/bin/blinky_wifi.rs b/examples/rp235x/src/bin/blinky_wifi.rs
index ef029867a..8c352ebc4 100644
--- a/examples/rp235x/src/bin/blinky_wifi.rs
+++ b/examples/rp235x/src/bin/blinky_wifi.rs
@@ -18,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _};
18 18
19// Program metadata for `picotool info`. 19// Program metadata for `picotool info`.
20// This isn't needed, but it's recommended to have these minimal entries. 20// This isn't needed, but it's recommended to have these minimal entries.
21#[link_section = ".bi_entries"] 21#[unsafe(link_section = ".bi_entries")]
22#[used] 22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), 24 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"),
diff --git a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs
index 2a919a1ea..0a5bccfb3 100644
--- a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs
+++ b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs
@@ -18,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _};
18 18
19// Program metadata for `picotool info`. 19// Program metadata for `picotool info`.
20// This isn't needed, but it's recomended to have these minimal entries. 20// This isn't needed, but it's recomended to have these minimal entries.
21#[link_section = ".bi_entries"] 21#[unsafe(link_section = ".bi_entries")]
22#[used] 22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), 24 embassy_rp::binary_info::rp_program_name!(c"Blinky Example"),
diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs
new file mode 100644
index 000000000..5fd97ef97
--- /dev/null
+++ b/examples/rp235x/src/bin/overclock.rs
@@ -0,0 +1,74 @@
1//! # Overclocking the RP2350 to 200 MHz
2//!
3//! This example demonstrates how to configure the RP2350 to run at 200 MHz instead of the default 150 MHz.
4//!
5//! ## Note
6//!
7//! As of yet there is no official support for running the RP235x at higher clock frequencies and/or other core voltages than the default.
8//! Doing so may cause unexpected behavior and/or damage the chip.
9
10#![no_std]
11#![no_main]
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage};
16use embassy_rp::config::Config;
17use embassy_rp::gpio::{Level, Output};
18use embassy_time::{Duration, Instant, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21const COUNT_TO: i64 = 10_000_000;
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) -> ! {
25 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
26 let mut config = Config::new(ClockConfig::system_freq(200_000_000).unwrap());
27
28 // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us.
29 // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on
30 // what we know about the RP2040. This is not guaranteed to be correct.
31 config.clocks.core_voltage = CoreVoltage::V1_15;
32
33 // Initialize the peripherals
34 let p = embassy_rp::init(config);
35
36 // Show CPU frequency for verification
37 let sys_freq = clk_sys_freq();
38 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
39 // Show core voltage for verification
40 let core_voltage = core_voltage().unwrap();
41 info!("Core voltage: {}", core_voltage);
42
43 // LED to indicate the system is running
44 let mut led = Output::new(p.PIN_25, Level::Low);
45
46 loop {
47 // Reset the counter at the start of measurement period
48 let mut counter = 0;
49
50 // Turn LED on while counting
51 led.set_high();
52
53 let start = Instant::now();
54
55 // This is a busy loop that will take some time to complete
56 while counter < COUNT_TO {
57 counter += 1;
58 }
59
60 let elapsed = Instant::now() - start;
61
62 // Report the elapsed time
63 led.set_low();
64 info!(
65 "At {}Mhz: Elapsed time to count to {}: {}ms",
66 sys_freq / 1_000_000,
67 counter,
68 elapsed.as_millis()
69 );
70
71 // Wait 2 seconds before starting the next measurement
72 Timer::after(Duration::from_secs(2)).await;
73 }
74}
diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs
index ccc601661..61af94560 100644
--- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs
+++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs
@@ -16,7 +16,7 @@ use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, Shi
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18// Program metadata for `picotool info` 18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"] 19#[unsafe(link_section = ".bi_entries")]
20#[used] 20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"), 22 embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"),
@@ -88,8 +88,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
88 Self { sm } 88 Self { sm }
89 } 89 }
90 90
91 pub async fn read(&mut self) -> u32 { 91 pub async fn read(&mut self) -> i32 {
92 self.sm.get_rxf_entry(0) 92 self.sm.get_rxf_entry(0) as i32
93 } 93 }
94} 94}
95 95
diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs
index 5416e20ce..497c4f845 100644
--- a/examples/rp235x/src/bin/sharing.rs
+++ b/examples/rp235x/src/bin/sharing.rs
@@ -31,7 +31,7 @@ use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell}; 31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
33 33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; 34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
35 35
36struct MyType { 36struct MyType {
37 inner: u32, 37 inner: u32,
diff --git a/examples/rp235x/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs
index f707c4b5e..7cad09f9b 100644
--- a/examples/rp235x/src/bin/uart_buffered_split.rs
+++ b/examples/rp235x/src/bin/uart_buffered_split.rs
@@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
52 info!("Reading..."); 52 info!("Reading...");
53 loop { 53 loop {
54 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp235x/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs
index 4e98f9e1e..45c9c8407 100644
--- a/examples/rp235x/src/bin/uart_unidir.rs
+++ b/examples/rp235x/src/bin/uart_unidir.rs
@@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
43 info!("Reading..."); 43 info!("Reading...");
44 loop { 44 loop {
45 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 9fbe2efc3..1a46931d9 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f777zi to your chip name, if necessary. 8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti", "single-bank"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs
index dc775f18a..f06b5d06e 100644
--- a/examples/stm32h7/src/bin/adc_dma.rs
+++ b/examples/stm32h7/src/bin/adc_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::Config;
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11#[link_section = ".ram_d3"] 11#[unsafe(link_section = ".ram_d3")]
12static mut DMA_BUF: [u16; 2] = [0; 2]; 12static mut DMA_BUF: [u16; 2] = [0; 2];
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
index 95ffe257a..01937593a 100644
--- a/examples/stm32h7/src/bin/sai.rs
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -16,9 +16,9 @@ const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
16const SAMPLE_RATE: u32 = 48000; 16const SAMPLE_RATE: u32 = 48000;
17 17
18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions 18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
19#[link_section = ".sram1_bss"] 19#[unsafe(link_section = ".sram1_bss")]
20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
21#[link_section = ".sram1_bss"] 21#[unsafe(link_section = ".sram1_bss")]
22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23 23
24#[embassy_executor::main] 24#[embassy_executor::main]
@@ -112,8 +112,10 @@ async fn main(_spawner: Spawner) {
112 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; 112 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
113 113
114 loop { 114 loop {
115 sai_receiver.read(&mut buf).await.unwrap(); 115 // write() must be called before read() to start the master (transmitter)
116 // clock used by the receiver
116 sai_transmitter.write(&buf).await.unwrap(); 117 sai_transmitter.write(&buf).await.unwrap();
118 sai_receiver.read(&mut buf).await.unwrap();
117 } 119 }
118} 120}
119 121
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index 9166fe9b6..5a7dff572 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -16,7 +16,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18// Defined in memory.x 18// Defined in memory.x
19#[link_section = ".ram_d3"] 19#[unsafe(link_section = ".ram_d3")]
20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs
index bc8249ced..a04d7cb34 100644
--- a/examples/stm32h723/src/bin/spdifrx.rs
+++ b/examples/stm32h723/src/bin/spdifrx.rs
@@ -24,10 +24,10 @@ const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * CHANNEL_COUNT;
24const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks 24const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
25 25
26// DMA buffers must be in special regions. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions 26// DMA buffers must be in special regions. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
27#[link_section = ".sram1"] 27#[unsafe(link_section = ".sram1")]
28static mut SPDIFRX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 28static mut SPDIFRX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
29 29
30#[link_section = ".sram4"] 30#[unsafe(link_section = ".sram4")]
31static mut SAI_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); 31static mut SAI_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
32 32
33#[embassy_executor::main] 33#[embassy_executor::main]
diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs
index b5c547839..39112c1f5 100644
--- a/examples/stm32h755cm4/src/bin/blinky.rs
+++ b/examples/stm32h755cm4/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".ram_d3.shared_data"] 13#[unsafe(link_section = ".ram_d3.shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs
index 94d2226c0..b30bf4de8 100644
--- a/examples/stm32h755cm7/src/bin/blinky.rs
+++ b/examples/stm32h755cm7/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".ram_d3.shared_data"] 13#[unsafe(link_section = ".ram_d3.shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index b609110af..239bfcd79 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono", "dual-bank"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index fbf68c890..4c372a554 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } 9embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power", "dual-bank"] }
10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs
index ce7d0ec58..a2a90871d 100644
--- a/examples/stm32wl/src/bin/blinky.rs
+++ b/examples/stm32wl/src/bin/blinky.rs
@@ -10,7 +10,7 @@ use embassy_stm32::SharedData;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".shared_data"] 13#[unsafe(link_section = ".shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs
index 8b5204479..21bcd2ac6 100644
--- a/examples/stm32wl/src/bin/button.rs
+++ b/examples/stm32wl/src/bin/button.rs
@@ -9,7 +9,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::SharedData; 9use embassy_stm32::SharedData;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12#[link_section = ".shared_data"] 12#[unsafe(link_section = ".shared_data")]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14 14
15#[entry] 15#[entry]
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index 8dd1a6a5e..0a8aece34 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -10,7 +10,7 @@ use embassy_stm32::gpio::Pull;
10use embassy_stm32::SharedData; 10use embassy_stm32::SharedData;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13#[link_section = ".shared_data"] 13#[unsafe(link_section = ".shared_data")]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 147f5d293..320a9723a 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -9,7 +9,7 @@ use embassy_stm32::flash::Flash;
9use embassy_stm32::SharedData; 9use embassy_stm32::SharedData;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12#[link_section = ".shared_data"] 12#[unsafe(link_section = ".shared_data")]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index df2ed0054..68b9d7d00 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{
14 RNG => rng::InterruptHandler<peripherals::RNG>; 14 RNG => rng::InterruptHandler<peripherals::RNG>;
15}); 15});
16 16
17#[link_section = ".shared_data"] 17#[unsafe(link_section = ".shared_data")]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19 19
20#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index 69a9ddc4c..d3709120f 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -12,7 +12,7 @@ use embassy_stm32::{Config, SharedData};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15#[link_section = ".shared_data"] 15#[unsafe(link_section = ".shared_data")]
16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index ece9b9201..505a85f47 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{
14 LPUART1 => InterruptHandler<peripherals::LPUART1>; 14 LPUART1 => InterruptHandler<peripherals::LPUART1>;
15}); 15});
16 16
17#[link_section = ".shared_data"] 17#[unsafe(link_section = ".shared_data")]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19 19
20/* 20/*
diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs
new file mode 100644
index 000000000..167a26eb2
--- /dev/null
+++ b/tests/rp/src/bin/overclock.rs
@@ -0,0 +1,69 @@
1#![no_std]
2#![no_main]
3
4#[cfg(feature = "rp2040")]
5teleprobe_meta::target!(b"rpi-pico");
6#[cfg(feature = "rp235xb")]
7teleprobe_meta::target!(b"pimoroni-pico-plus-2");
8
9use defmt::info;
10use embassy_executor::Spawner;
11use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage};
12use embassy_rp::config::Config;
13use embassy_time::Instant;
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let mut config = Config::default();
21
22 // Initialize with 200MHz clock configuration
23 config.clocks = ClockConfig::system_freq(200_000_000).unwrap();
24
25 // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically
26 #[cfg(feature = "rp235xb")]
27 {
28 config.clocks.core_voltage = CoreVoltage::V1_15;
29 }
30
31 let _p = embassy_rp::init(config);
32
33 // We should be at core voltage of 1.15V
34 assert_eq!(core_voltage().unwrap(), CoreVoltage::V1_15, "Core voltage is not 1.15V");
35 // We should be at 200MHz
36 assert_eq!(clk_sys_freq(), 200_000_000, "System clock frequency is not 200MHz");
37
38 // Test the system speed
39 let time_elapsed = {
40 let mut counter = 0;
41 let start = Instant::now();
42 while counter < COUNT_TO {
43 counter += 1;
44 }
45 let elapsed = Instant::now() - start;
46
47 elapsed.as_millis()
48 };
49
50 // Tests will fail if unused variables are detected:
51 // Report the elapsed time, so that the compiler doesn't optimize it away for the chip not on test
52 info!(
53 "At {}Mhz: Elapsed time to count to {}: {}ms",
54 clk_sys_freq() / 1_000_000,
55 COUNT_TO,
56 time_elapsed
57 );
58
59 // Check if the elapsed time is within expected limits
60 // for rp2040 we expect about 600ms
61 #[cfg(feature = "rp2040")]
62 // allow 1% error
63 assert!(time_elapsed < 606, "Elapsed time is too long");
64 // for rp235x we expect about 450ms
65 #[cfg(feature = "rp235xb")]
66 assert!(time_elapsed < 455, "Elapsed time is too long");
67
68 cortex_m::asm::bkpt();
69}
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs
index 84744ab77..80230f3fe 100644
--- a/tests/rp/src/bin/uart.rs
+++ b/tests/rp/src/bin/uart.rs
@@ -8,17 +8,17 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2");
8use defmt::{assert_eq, *}; 8use defmt::{assert_eq, *};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx}; 11use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { 15fn read<const N: usize>(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> {
16 let mut buf = [255; N]; 16 let mut buf = [255; N];
17 uart.blocking_read(&mut buf)?; 17 uart.blocking_read(&mut buf)?;
18 Ok(buf) 18 Ok(buf)
19} 19}
20 20
21fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { 21fn read1<const N: usize>(uart: &mut UartRx<'_, Blocking>) -> Result<[u8; N], Error> {
22 let mut buf = [255; N]; 22 let mut buf = [255; N];
23 uart.blocking_read(&mut buf)?; 23 uart.blocking_read(&mut buf)?;
24 Ok(buf) 24 Ok(buf)
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index d5f655e9b..cb78fc142 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -10,7 +10,7 @@ use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::peripherals::UART0; 12use embassy_rp::peripherals::UART0;
13use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity}; 13use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity};
14use embassy_time::Timer; 14use embassy_time::Timer;
15use embedded_io_async::{Read, ReadExactError, Write}; 15use embedded_io_async::{Read, ReadExactError, Write};
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
19 UART0_IRQ => BufferedInterruptHandler<UART0>; 19 UART0_IRQ => BufferedInterruptHandler<UART0>;
20}); 20});
21 21
22async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> { 22async fn read<const N: usize>(uart: &mut BufferedUart) -> Result<[u8; N], Error> {
23 let mut buf = [255; N]; 23 let mut buf = [255; N];
24 match uart.read_exact(&mut buf).await { 24 match uart.read_exact(&mut buf).await {
25 Ok(()) => Ok(buf), 25 Ok(()) => Ok(buf),
@@ -29,7 +29,7 @@ async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Res
29 } 29 }
30} 30}
31 31
32async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> { 32async fn read1<const N: usize>(uart: &mut BufferedUartRx) -> Result<[u8; N], Error> {
33 let mut buf = [255; N]; 33 let mut buf = [255; N];
34 match uart.read_exact(&mut buf).await { 34 match uart.read_exact(&mut buf).await {
35 Ok(()) => Ok(buf), 35 Ok(()) => Ok(buf),
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs
index a09101223..a7af81f5f 100644
--- a/tests/rp/src/bin/uart_dma.rs
+++ b/tests/rp/src/bin/uart_dma.rs
@@ -10,7 +10,7 @@ use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::peripherals::UART0; 12use embassy_rp::peripherals::UART0;
13use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx}; 13use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx};
14use embassy_time::Timer; 14use embassy_time::Timer;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
@@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs {
18 UART0_IRQ => InterruptHandler<UART0>; 18 UART0_IRQ => InterruptHandler<UART0>;
19}); 19});
20 20
21async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> { 21async fn read<const N: usize>(uart: &mut Uart<'_, Async>) -> Result<[u8; N], Error> {
22 let mut buf = [255; N]; 22 let mut buf = [255; N];
23 uart.read(&mut buf).await?; 23 uart.read(&mut buf).await?;
24 Ok(buf) 24 Ok(buf)
25} 25}
26 26
27async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> { 27async fn read1<const N: usize>(uart: &mut UartRx<'_, Async>) -> Result<[u8; N], Error> {
28 let mut buf = [255; N]; 28 let mut buf = [255; N];
29 uart.read(&mut buf).await?; 29 uart.read(&mut buf).await?;
30 Ok(buf) 30 Ok(buf)
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index a676aee53..3a347e279 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -12,7 +12,7 @@ stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "et
12stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] 12stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
13stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] 13stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
14stm32f446re = ["embassy-stm32/stm32f446re", "spi-v1", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "spi-v1", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng", "single-bank"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"]
@@ -23,8 +23,8 @@ stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
23stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"]
24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] 24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] 25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"]
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual-bank"]
27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] 27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash", "dual-bank"]
28stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] 28stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"]
29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash 29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash
30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] 30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"]
@@ -53,6 +53,8 @@ not-gpdma = []
53dac = [] 53dac = []
54ucpd = [] 54ucpd = []
55cordic = ["dep:num-traits"] 55cordic = ["dep:num-traits"]
56dual-bank = ["embassy-stm32/dual-bank"]
57single-bank = ["embassy-stm32/single-bank"]
56 58
57cm0 = ["portable-atomic/unsafe-assume-single-core"] 59cm0 = ["portable-atomic/unsafe-assume-single-core"]
58 60