aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Schulz-Andres <[email protected]>2024-05-23 15:34:16 +0200
committerGitHub <[email protected]>2024-05-23 15:34:16 +0200
commit0a5820e3ed423af1788072a5416e04ab86c44c2d (patch)
tree5a2b8d3d7a88835aebec0914da234d547e3b3dbe
parent27e8ef6e7e720a3c74f7c696ab105915695431c5 (diff)
parentded1f9d33520fc847dce8fe72f2fb80f6fa86350 (diff)
Merge branch 'embassy-rs:main' into add-miso-pullup
-rwxr-xr-x.github/ci/book.sh17
-rw-r--r--.vscode/settings.json9
-rw-r--r--README.md8
-rwxr-xr-xci.sh11
-rw-r--r--cyw43/README.md2
-rw-r--r--cyw43/src/runner.rs18
-rw-r--r--docs/Makefile8
-rw-r--r--docs/README.md9
-rw-r--r--docs/antora.yml5
-rw-r--r--docs/examples/basic/.cargo/config.toml (renamed from docs/modules/ROOT/examples/basic/.cargo/config.toml)0
-rw-r--r--docs/examples/basic/Cargo.toml18
-rw-r--r--docs/examples/basic/build.rs (renamed from docs/modules/ROOT/examples/basic/build.rs)0
-rw-r--r--docs/examples/basic/memory.x (renamed from docs/modules/ROOT/examples/basic/memory.x)0
-rw-r--r--docs/examples/basic/src/main.rs (renamed from docs/modules/ROOT/examples/basic/src/main.rs)0
l---------docs/examples/examples1
-rw-r--r--docs/examples/layer-by-layer/.cargo/config.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/.cargo/config.toml)0
-rw-r--r--docs/examples/layer-by-layer/Cargo.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/Cargo.toml)4
-rw-r--r--docs/examples/layer-by-layer/blinky-async/Cargo.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml)0
-rw-r--r--docs/examples/layer-by-layer/blinky-async/src/main.rs (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs)0
-rw-r--r--docs/examples/layer-by-layer/blinky-hal/Cargo.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml)0
-rw-r--r--docs/examples/layer-by-layer/blinky-hal/src/main.rs (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs)0
-rw-r--r--docs/examples/layer-by-layer/blinky-irq/Cargo.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml)0
-rw-r--r--docs/examples/layer-by-layer/blinky-irq/src/main.rs (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs)0
-rw-r--r--docs/examples/layer-by-layer/blinky-pac/Cargo.toml (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml)0
-rw-r--r--docs/examples/layer-by-layer/blinky-pac/src/main.rs (renamed from docs/modules/ROOT/examples/layer-by-layer/blinky-pac/src/main.rs)0
-rw-r--r--docs/images/bootloader_flash.png (renamed from docs/modules/ROOT/images/bootloader_flash.png)bin32147 -> 32147 bytes
-rw-r--r--docs/images/embassy_executor.drawio (renamed from docs/modules/ROOT/images/embassy_executor.drawio)0
-rw-r--r--docs/images/embassy_executor.png (renamed from docs/modules/ROOT/images/embassy_executor.png)bin121382 -> 121382 bytes
-rw-r--r--docs/images/embassy_irq.drawio (renamed from docs/modules/ROOT/images/embassy_irq.drawio)0
-rw-r--r--docs/images/embassy_irq.png (renamed from docs/modules/ROOT/images/embassy_irq.png)bin134158 -> 134158 bytes
-rw-r--r--docs/index.adoc16
-rw-r--r--docs/modules/ROOT/examples/basic/Cargo.toml18
l---------docs/modules/ROOT/examples/examples1
-rw-r--r--docs/modules/ROOT/nav.adoc19
-rw-r--r--docs/pages/basic_application.adoc (renamed from docs/modules/ROOT/pages/basic_application.adoc)14
-rw-r--r--docs/pages/beginners.adoc11
-rw-r--r--docs/pages/best_practices.adoc (renamed from docs/modules/ROOT/pages/best_practices.adoc)0
-rw-r--r--docs/pages/bootloader.adoc (renamed from docs/modules/ROOT/pages/bootloader.adoc)0
-rw-r--r--docs/pages/developer.adoc (renamed from docs/modules/ROOT/pages/developer.adoc)0
-rw-r--r--docs/pages/developer_stm32.adoc (renamed from docs/modules/ROOT/pages/developer_stm32.adoc)0
-rw-r--r--docs/pages/embassy_in_the_wild.adoc (renamed from docs/modules/ROOT/pages/embassy_in_the_wild.adoc)6
-rw-r--r--docs/pages/examples.adoc (renamed from docs/modules/ROOT/pages/examples.adoc)2
-rw-r--r--docs/pages/faq.adoc (renamed from docs/modules/ROOT/pages/faq.adoc)23
-rw-r--r--docs/pages/getting_started.adoc (renamed from docs/modules/ROOT/pages/getting_started.adoc)8
-rw-r--r--docs/pages/hal.adoc (renamed from docs/modules/ROOT/pages/hal.adoc)2
-rw-r--r--docs/pages/layer_by_layer.adoc (renamed from docs/modules/ROOT/pages/layer_by_layer.adoc)8
-rw-r--r--docs/pages/new_project.adoc (renamed from docs/modules/ROOT/pages/new_project.adoc)21
-rw-r--r--docs/pages/nrf.adoc (renamed from docs/modules/ROOT/pages/nrf.adoc)0
-rw-r--r--docs/pages/overview.adoc (renamed from docs/modules/ROOT/pages/index.adoc)17
-rw-r--r--docs/pages/project_structure.adoc (renamed from docs/modules/ROOT/pages/project_structure.adoc)12
-rw-r--r--docs/pages/runtime.adoc (renamed from docs/modules/ROOT/pages/runtime.adoc)0
-rw-r--r--docs/pages/sharing_peripherals.adoc (renamed from docs/modules/ROOT/pages/sharing_peripherals.adoc)2
-rw-r--r--docs/pages/stm32.adoc (renamed from docs/modules/ROOT/pages/stm32.adoc)0
-rw-r--r--docs/pages/system.adoc13
-rw-r--r--docs/pages/time_keeping.adoc (renamed from docs/modules/ROOT/pages/time_keeping.adoc)0
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs14
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/spi.rs55
-rw-r--r--embassy-hal-internal/src/atomic_ring_buffer.rs5
-rw-r--r--embassy-net-esp-hosted/Cargo.toml4
-rw-r--r--embassy-rp/src/flash.rs5
-rw-r--r--embassy-rp/src/pwm.rs107
-rw-r--r--embassy-rp/src/uart/buffered.rs146
-rw-r--r--embassy-rp/src/uart/mod.rs8
-rw-r--r--embassy-stm32/Cargo.toml5
-rw-r--r--embassy-stm32/build.rs93
-rw-r--r--embassy-stm32/src/adc/f1.rs16
-rw-r--r--embassy-stm32/src/adc/f3.rs16
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs24
-rw-r--r--embassy-stm32/src/adc/g4.rs27
-rw-r--r--embassy-stm32/src/adc/mod.rs56
-rw-r--r--embassy-stm32/src/adc/v1.rs22
-rw-r--r--embassy-stm32/src/adc/v2.rs20
-rw-r--r--embassy-stm32/src/adc/v3.rs34
-rw-r--r--embassy-stm32/src/adc/v4.rs29
-rw-r--r--embassy-stm32/src/dsihost.rs429
-rw-r--r--embassy-stm32/src/hsem/mod.rs182
-rw-r--r--embassy-stm32/src/i2c/mod.rs68
-rw-r--r--embassy-stm32/src/i2c/v1.rs184
-rw-r--r--embassy-stm32/src/i2c/v2.rs129
-rw-r--r--embassy-stm32/src/i2s.rs14
-rw-r--r--embassy-stm32/src/lib.rs8
-rw-r--r--embassy-stm32/src/ltdc.rs142
-rw-r--r--embassy-stm32/src/macros.rs40
-rw-r--r--embassy-stm32/src/opamp.rs8
-rw-r--r--embassy-stm32/src/ospi/mod.rs817
-rw-r--r--embassy-stm32/src/qspi/mod.rs305
-rw-r--r--embassy-stm32/src/rcc/f247.rs31
-rw-r--r--embassy-stm32/src/rcc/h.rs5
-rw-r--r--embassy-stm32/src/rcc/l.rs12
-rw-r--r--embassy-stm32/src/rcc/mod.rs51
-rw-r--r--embassy-stm32/src/rcc/u5.rs4
-rw-r--r--embassy-stm32/src/spi/mod.rs237
-rw-r--r--embassy-stm32/src/timer/input_capture.rs233
-rw-r--r--embassy-stm32/src/timer/low_level.rs5
-rw-r--r--embassy-stm32/src/timer/mod.rs95
-rw-r--r--embassy-stm32/src/tsc/enums.rs238
-rw-r--r--embassy-stm32/src/tsc/mod.rs936
-rw-r--r--embassy-stm32/src/usart/mod.rs50
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs3
-rw-r--r--embassy-sync/CHANGELOG.md6
-rw-r--r--embassy-sync/src/channel.rs29
-rw-r--r--embassy-sync/src/once_lock.rs6
-rw-r--r--embassy-sync/src/pipe.rs2
-rw-r--r--embassy-sync/src/priority_channel.rs54
-rw-r--r--embassy-sync/src/pubsub/mod.rs150
-rw-r--r--embassy-sync/src/pubsub/publisher.rs68
-rw-r--r--embassy-sync/src/pubsub/subscriber.rs36
-rw-r--r--embassy-sync/src/waitqueue/multi_waker.rs2
-rw-r--r--embassy-usb-logger/CHANGELOG.md28
-rw-r--r--embassy-usb-logger/Cargo.toml2
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs24
-rw-r--r--embassy-usb/CHANGELOG.md3
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/interrupt.rs3
-rw-r--r--examples/rp/src/bin/uart_r503.rs158
-rw-r--r--examples/stm32f4/Cargo.toml2
-rw-r--r--examples/stm32f4/src/bin/input_capture.rs52
-rw-r--r--examples/stm32f469/.cargo/config.toml9
-rw-r--r--examples/stm32f469/Cargo.toml22
-rw-r--r--examples/stm32f469/build.rs5
-rw-r--r--examples/stm32f469/src/bin/dsi_bsp.rs694
-rw-r--r--examples/stm32f469/src/bin/ferris.bin70
-rw-r--r--examples/stm32f7/src/bin/qspi.rs13
-rw-r--r--examples/stm32g0/src/bin/i2c_async.rs48
-rw-r--r--examples/stm32h7/Cargo.toml1
-rw-r--r--examples/stm32h7/src/bin/adc.rs2
-rw-r--r--examples/stm32h7/src/bin/i2c_shared.rs111
-rw-r--r--examples/stm32h7/src/bin/spi.rs3
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs4
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs4
-rw-r--r--examples/stm32h7rs/src/bin/spi.rs3
-rw-r--r--examples/stm32h7rs/src/bin/spi_dma.rs4
-rw-r--r--examples/stm32l4/src/bin/can.rs68
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs4
-rw-r--r--tests/stm32/src/bin/spi.rs8
135 files changed, 5574 insertions, 1341 deletions
diff --git a/.github/ci/book.sh b/.github/ci/book.sh
new file mode 100755
index 000000000..285cdc8fa
--- /dev/null
+++ b/.github/ci/book.sh
@@ -0,0 +1,17 @@
1#!/bin/bash
2## on push branch=main
3
4set -euxo pipefail
5
6make -C docs
7
8export KUBECONFIG=/ci/secrets/kubeconfig.yml
9POD=$(kubectl -n embassy get po -l app=website -o jsonpath={.items[0].metadata.name})
10
11mkdir -p build
12mv docs/book build/book
13tar -C build -cf book.tar book
14kubectl exec $POD -- mkdir -p /usr/share/nginx/html
15kubectl cp book.tar $POD:/usr/share/nginx/html/
16kubectl exec $POD -- find /usr/share/nginx/html
17kubectl exec $POD -- tar -C /usr/share/nginx/html -xvf /usr/share/nginx/html/book.tar
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 220d25914..48d0957e6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,12 +9,14 @@
9 "rust-analyzer.check.noDefaultFeatures": true, 9 "rust-analyzer.check.noDefaultFeatures": true,
10 "rust-analyzer.cargo.noDefaultFeatures": true, 10 "rust-analyzer.cargo.noDefaultFeatures": true,
11 "rust-analyzer.showUnlinkedFileNotification": false, 11 "rust-analyzer.showUnlinkedFileNotification": false,
12 // uncomment the target of your chip. 12 // Uncomment the target of your chip.
13 //"rust-analyzer.cargo.target": "thumbv6m-none-eabi", 13 //"rust-analyzer.cargo.target": "thumbv6m-none-eabi",
14 //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", 14 //"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
16 //"rust-analyzer.cargo.target": "thumbv7em-none-eabihf",
16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 17 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
17 "rust-analyzer.cargo.features": [ 18 "rust-analyzer.cargo.features": [
19 // Comment out these features when working on the examples. Most example crates do not have any cargo features.
18 "stm32f446re", 20 "stm32f446re",
19 "time-driver-any", 21 "time-driver-any",
20 "unstable-pac", 22 "unstable-pac",
@@ -22,9 +24,10 @@
22 "rt", 24 "rt",
23 ], 25 ],
24 "rust-analyzer.linkedProjects": [ 26 "rust-analyzer.linkedProjects": [
25 // Uncomment ONE line for the chip you want to work on.
26 // This makes rust-analyzer work on the example crate and all its dependencies.
27 "embassy-stm32/Cargo.toml", 27 "embassy-stm32/Cargo.toml",
28 // To work on the examples, comment the line above and all of the cargo.features lines,
29 // then uncomment ONE line below to select the chip you want to work on.
30 // This makes rust-analyzer work on the example crate and all its dependencies.
28 // "examples/nrf52840-rtic/Cargo.toml", 31 // "examples/nrf52840-rtic/Cargo.toml",
29 // "examples/nrf5340/Cargo.toml", 32 // "examples/nrf5340/Cargo.toml",
30 // "examples/nrf-rtos-trace/Cargo.toml", 33 // "examples/nrf-rtos-trace/Cargo.toml",
diff --git a/README.md b/README.md
index 0bd1ac594..65ccaa967 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
18 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips. 18 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips.
19 - Embassy HAL support for Espressif chips is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. 19 - Embassy HAL support for Espressif chips is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
20 - Async WiFi, Bluetooth and ESP-NOW is being developed in the [esp-rs/esp-wifi](https://github.com/esp-rs/esp-wifi) repository. 20 - Async WiFi, Bluetooth and ESP-NOW is being developed in the [esp-rs/esp-wifi](https://github.com/esp-rs/esp-wifi) repository.
21 - <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips.
21 22
22- **Time that Just Works** - 23- **Time that Just Works** -
23No 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. 24No 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.
@@ -99,12 +100,7 @@ Examples are found in the `examples/` folder separated by the chip manufacturer
99 100
100### Running examples 101### Running examples
101 102
102- Install `probe-rs`. 103- Install `probe-rs` following the instructions at <https://probe.rs>.
103
104```bash
105cargo install probe-rs --features cli
106```
107
108- Change directory to the sample's base directory. For example: 104- Change directory to the sample's base directory. For example:
109 105
110```bash 106```bash
diff --git a/ci.sh b/ci.sh
index 6fff1e68c..0b5308153 100755
--- a/ci.sh
+++ b/ci.sh
@@ -171,11 +171,11 @@ cargo batch \
171 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 171 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
172 --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \ 172 --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \
173 --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 173 --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
174 --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ 174 --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
175 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ 175 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
176 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ 176 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
177 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ 177 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
178 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ 178 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
179 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 179 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
180 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 180 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
181 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ 181 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
@@ -187,6 +187,7 @@ cargo batch \
187 --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \ 187 --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \
188 --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \ 188 --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \
189 --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ 189 --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
190 --- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f469 \
190 --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \ 191 --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \
191 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ 192 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
192 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ 193 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
diff --git a/cyw43/README.md b/cyw43/README.md
index dabdf0471..5b4a5d789 100644
--- a/cyw43/README.md
+++ b/cyw43/README.md
@@ -23,7 +23,7 @@ TODO:
23 23
24## Running the examples 24## Running the examples
25 25
26- `cargo install probe-rs --features cli` 26- Install `probe-rs` following the instructions at <https://probe.rs>.
27- `cd examples/rp` 27- `cd examples/rp`
28### Example 1: Scan the wifi stations 28### Example 1: Scan the wifi stations
29- `cargo run --release --bin wifi_scan` 29- `cargo run --release --bin wifi_scan`
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index c72cf0def..e90316302 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -1,6 +1,5 @@
1use embassy_futures::select::{select3, Either3}; 1use embassy_futures::select::{select3, Either3};
2use embassy_net_driver_channel as ch; 2use embassy_net_driver_channel as ch;
3use embassy_sync::pubsub::PubSubBehavior;
4use embassy_time::{block_for, Duration, Timer}; 3use embassy_time::{block_for, Duration, Timer};
5use embedded_hal_1::digital::OutputPin; 4use embedded_hal_1::digital::OutputPin;
6 5
@@ -438,13 +437,16 @@ where
438 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls 437 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
439 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event 438 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
440 // (if they are actively awaiting the queue) 439 // (if they are actively awaiting the queue)
441 self.events.queue.publish_immediate(events::Message::new( 440 self.events
442 Status { 441 .queue
443 event_type: evt_type, 442 .immediate_publisher()
444 status, 443 .publish_immediate(events::Message::new(
445 }, 444 Status {
446 event_payload, 445 event_type: evt_type,
447 )); 446 status,
447 },
448 event_payload,
449 ));
448 } 450 }
449 } 451 }
450 CHANNEL_TYPE_DATA => { 452 CHANNEL_TYPE_DATA => {
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 000000000..834802d3b
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,8 @@
1all:
2 asciidoctor -d book -D book/ index.adoc
3 cp -r images book
4
5clean:
6 rm -rf book
7
8.PHONY: all clean
diff --git a/docs/README.md b/docs/README.md
index 0bf3a6c89..94ebd7a05 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,4 +1,9 @@
1# embassy docs 1# embassy docs
2 2
3The documentation hosted at [https://embassy.dev/book](https://embassy.dev/book). Building the documentation requires 3The documentation hosted at [https://embassy.dev/book](https://embassy.dev/book). Building the documentation requires the [asciidoctor](https://asciidoctor.org/) tool, and can built running `make` in this folder:
4cloning the [embassy-book](https://github.com/embassy-rs/embassy-book) repository and following the instructions. 4
5```
6make
7```
8
9Then open the generated file `thebook/index.html`.
diff --git a/docs/antora.yml b/docs/antora.yml
deleted file mode 100644
index 9a00fa820..000000000
--- a/docs/antora.yml
+++ /dev/null
@@ -1,5 +0,0 @@
1name: ROOT
2title: Embassy
3version: dev
4nav:
5 - modules/ROOT/nav.adoc
diff --git a/docs/modules/ROOT/examples/basic/.cargo/config.toml b/docs/examples/basic/.cargo/config.toml
index 8ca28df39..8ca28df39 100644
--- a/docs/modules/ROOT/examples/basic/.cargo/config.toml
+++ b/docs/examples/basic/.cargo/config.toml
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
new file mode 100644
index 000000000..d86d4a809
--- /dev/null
+++ b/docs/examples/basic/Cargo.toml
@@ -0,0 +1,18 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-basic-example"
5version = "0.1.0"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.0", path = "../../../embassy-time", features = ["defmt"] }
11embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
12
13defmt = "0.3"
14defmt-rtt = "0.3"
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/docs/modules/ROOT/examples/basic/build.rs b/docs/examples/basic/build.rs
index 30691aa97..30691aa97 100644
--- a/docs/modules/ROOT/examples/basic/build.rs
+++ b/docs/examples/basic/build.rs
diff --git a/docs/modules/ROOT/examples/basic/memory.x b/docs/examples/basic/memory.x
index 9b04edec0..9b04edec0 100644
--- a/docs/modules/ROOT/examples/basic/memory.x
+++ b/docs/examples/basic/memory.x
diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/examples/basic/src/main.rs
index 4412712c8..4412712c8 100644
--- a/docs/modules/ROOT/examples/basic/src/main.rs
+++ b/docs/examples/basic/src/main.rs
diff --git a/docs/examples/examples b/docs/examples/examples
new file mode 120000
index 000000000..d15735c1d
--- /dev/null
+++ b/docs/examples/examples
@@ -0,0 +1 @@
../../examples \ No newline at end of file
diff --git a/docs/modules/ROOT/examples/layer-by-layer/.cargo/config.toml b/docs/examples/layer-by-layer/.cargo/config.toml
index 3012f05dc..3012f05dc 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/.cargo/config.toml
+++ b/docs/examples/layer-by-layer/.cargo/config.toml
diff --git a/docs/modules/ROOT/examples/layer-by-layer/Cargo.toml b/docs/examples/layer-by-layer/Cargo.toml
index 943249a17..0f233eae5 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/Cargo.toml
+++ b/docs/examples/layer-by-layer/Cargo.toml
@@ -8,8 +8,8 @@ members = [
8] 8]
9 9
10[patch.crates-io] 10[patch.crates-io]
11embassy-executor = { path = "../../../../../embassy-executor" } 11embassy-executor = { path = "../../../embassy-executor" }
12embassy-stm32 = { path = "../../../../../embassy-stm32" } 12embassy-stm32 = { path = "../../../embassy-stm32" }
13 13
14[profile.release] 14[profile.release]
15codegen-units = 1 15codegen-units = 1
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
index 64f7e8403..64f7e8403 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs b/docs/examples/layer-by-layer/blinky-async/src/main.rs
index 004602816..004602816 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs
+++ b/docs/examples/layer-by-layer/blinky-async/src/main.rs
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml
index c15de2db2..c15de2db2 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs b/docs/examples/layer-by-layer/blinky-hal/src/main.rs
index d0c9f4907..d0c9f4907 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs
+++ b/docs/examples/layer-by-layer/blinky-hal/src/main.rs
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml
index 9733658b6..9733658b6 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/examples/layer-by-layer/blinky-irq/src/main.rs
index 743c9d99b..743c9d99b 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
+++ b/docs/examples/layer-by-layer/blinky-irq/src/main.rs
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml
index f872b94cb..f872b94cb 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-pac/src/main.rs b/docs/examples/layer-by-layer/blinky-pac/src/main.rs
index 990d46cb6..990d46cb6 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-pac/src/main.rs
+++ b/docs/examples/layer-by-layer/blinky-pac/src/main.rs
diff --git a/docs/modules/ROOT/images/bootloader_flash.png b/docs/images/bootloader_flash.png
index 635783b05..635783b05 100644
--- a/docs/modules/ROOT/images/bootloader_flash.png
+++ b/docs/images/bootloader_flash.png
Binary files differ
diff --git a/docs/modules/ROOT/images/embassy_executor.drawio b/docs/images/embassy_executor.drawio
index b76587d97..b76587d97 100644
--- a/docs/modules/ROOT/images/embassy_executor.drawio
+++ b/docs/images/embassy_executor.drawio
diff --git a/docs/modules/ROOT/images/embassy_executor.png b/docs/images/embassy_executor.png
index 2a83a3adb..2a83a3adb 100644
--- a/docs/modules/ROOT/images/embassy_executor.png
+++ b/docs/images/embassy_executor.png
Binary files differ
diff --git a/docs/modules/ROOT/images/embassy_irq.drawio b/docs/images/embassy_irq.drawio
index aa439a8e6..aa439a8e6 100644
--- a/docs/modules/ROOT/images/embassy_irq.drawio
+++ b/docs/images/embassy_irq.drawio
diff --git a/docs/modules/ROOT/images/embassy_irq.png b/docs/images/embassy_irq.png
index 154d336b6..154d336b6 100644
--- a/docs/modules/ROOT/images/embassy_irq.png
+++ b/docs/images/embassy_irq.png
Binary files differ
diff --git a/docs/index.adoc b/docs/index.adoc
new file mode 100644
index 000000000..9c6150196
--- /dev/null
+++ b/docs/index.adoc
@@ -0,0 +1,16 @@
1:description: Embassy Book
2:sectanchors:
3:doctype: book
4:toc:
5:toc-placement: left
6:toclevels: 2
7:imagesdir: images
8
9# Embassy Book
10
11Welcome to the Embassy Book. The Embassy Book is for everyone who wants to use Embassy and understand how Embassy works.
12
13include::pages/overview.adoc[leveloffset = 1]
14include::pages/beginners.adoc[leveloffset = 1]
15include::pages/system.adoc[leveloffset = 1]
16include::pages/faq.adoc[leveloffset = 1]
diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml
deleted file mode 100644
index 2c282145d..000000000
--- a/docs/modules/ROOT/examples/basic/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-basic-example"
5version = "0.1.0"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9embassy-executor = { version = "0.5.0", path = "../../../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.0", path = "../../../../../embassy-time", features = ["defmt"] }
11embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
12
13defmt = "0.3"
14defmt-rtt = "0.3"
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/docs/modules/ROOT/examples/examples b/docs/modules/ROOT/examples/examples
deleted file mode 120000
index 1929330b0..000000000
--- a/docs/modules/ROOT/examples/examples
+++ /dev/null
@@ -1 +0,0 @@
1../../../../examples \ No newline at end of file
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
deleted file mode 100644
index 44b0eddb9..000000000
--- a/docs/modules/ROOT/nav.adoc
+++ /dev/null
@@ -1,19 +0,0 @@
1* xref:getting_started.adoc[Getting started]
2** xref:basic_application.adoc[Basic application]
3** xref:project_structure.adoc[Project Structure]
4** xref:new_project.adoc[Starting a new Embassy project]
5** xref:best_practices.adoc[Best Practices]
6* xref:runtime.adoc[Executor]
7* xref::time_keeping.adoc[Time-keeping]
8* xref:sharing_peripherals.adoc[Sharing peripherals]
9* xref:hal.adoc[HAL]
10** xref:layer_by_layer.adoc[Anatomy of an async HAL]
11** xref:nrf.adoc[nRF]
12** xref:stm32.adoc[STM32]
13* xref:bootloader.adoc[Bootloader]
14
15* xref:examples.adoc[Examples]
16* xref:developer.adoc[Developer Docs]
17** xref:developer_stm32.adoc[Developer Docs: STM32]
18* xref:embassy_in_the_wild.adoc[Embassy in the wild]
19* xref:faq.adoc[Frequently Asked Questions]
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/pages/basic_application.adoc
index d5aad806d..7b4ebda4f 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/pages/basic_application.adoc
@@ -1,10 +1,10 @@
1= A basic Embassy application 1= A basic Embassy application
2 2
3So you've got one of the xref:examples.adoc[examples] running, but what now? Let's go through a simple Embassy application for the nRF52 DK to understand it better. 3So you've got one of the examples running, but what now? Let's go through a simple Embassy application for the nRF52 DK to understand it better.
4 4
5== Main 5== Main
6 6
7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/modules/ROOT/examples/basic[here]. 7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here].
8 8
9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly. 9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
10 10
@@ -14,7 +14,7 @@ The first thing you’ll notice are two attributes at the top of the file. These
14 14
15[source,rust] 15[source,rust]
16---- 16----
17include::example$basic/src/main.rs[lines="1..2"] 17include::../examples/basic/src/main.rs[lines="1..2"]
18---- 18----
19 19
20=== Dealing with errors 20=== Dealing with errors
@@ -23,7 +23,7 @@ Then, what follows are some declarations on how to deal with panics and faults.
23 23
24[source,rust] 24[source,rust]
25---- 25----
26include::example$basic/src/main.rs[lines="8"] 26include::../examples/basic/src/main.rs[lines="8"]
27---- 27----
28 28
29=== Task declaration 29=== Task declaration
@@ -32,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de
32 32
33[source,rust] 33[source,rust]
34---- 34----
35include::example$basic/src/main.rs[lines="10..18"] 35include::../examples/basic/src/main.rs[lines="10..18"]
36---- 36----
37 37
38An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. 38An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -47,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals`
47 47
48[source,rust] 48[source,rust]
49---- 49----
50include::example$basic/src/main.rs[lines="20..-1"] 50include::../examples/basic/src/main.rs[lines="20..-1"]
51---- 51----
52 52
53What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following: 53What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
@@ -64,7 +64,7 @@ The project definition needs to contain the embassy dependencies:
64 64
65[source,toml] 65[source,toml]
66---- 66----
67include::example$basic/Cargo.toml[lines="9..11"] 67include::../examples/basic/Cargo.toml[lines="9..11"]
68---- 68----
69 69
70Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). 70Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well).
diff --git a/docs/pages/beginners.adoc b/docs/pages/beginners.adoc
new file mode 100644
index 000000000..48c9f4541
--- /dev/null
+++ b/docs/pages/beginners.adoc
@@ -0,0 +1,11 @@
1= For beginners
2
3The articles in this section are primarily aimed at users new to Embassy,
4showing how to get started, how to structure your project and other best practices.
5
6include::getting_started.adoc[leveloffset = 2]
7include::basic_application.adoc[leveloffset = 2]
8include::project_structure.adoc[leveloffset = 2]
9include::new_project.adoc[leveloffset = 2]
10include::best_practices.adoc[leveloffset = 2]
11include::layer_by_layer.adoc[leveloffset = 2]
diff --git a/docs/modules/ROOT/pages/best_practices.adoc b/docs/pages/best_practices.adoc
index bfcedec06..bfcedec06 100644
--- a/docs/modules/ROOT/pages/best_practices.adoc
+++ b/docs/pages/best_practices.adoc
diff --git a/docs/modules/ROOT/pages/bootloader.adoc b/docs/pages/bootloader.adoc
index 3b0cdb182..3b0cdb182 100644
--- a/docs/modules/ROOT/pages/bootloader.adoc
+++ b/docs/pages/bootloader.adoc
diff --git a/docs/modules/ROOT/pages/developer.adoc b/docs/pages/developer.adoc
index e03ee51a8..e03ee51a8 100644
--- a/docs/modules/ROOT/pages/developer.adoc
+++ b/docs/pages/developer.adoc
diff --git a/docs/modules/ROOT/pages/developer_stm32.adoc b/docs/pages/developer_stm32.adoc
index 7c04ab1a4..7c04ab1a4 100644
--- a/docs/modules/ROOT/pages/developer_stm32.adoc
+++ b/docs/pages/developer_stm32.adoc
diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc
index a7d63f990..76b1169bd 100644
--- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
+++ b/docs/pages/embassy_in_the_wild.adoc
@@ -1,6 +1,6 @@
1= Embassy in the wild! 1= Embassy in the wild!
2 2
3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/modules/ROOT/pages/embassy_in_the_wild.adoc[add more]! 3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
4 4
5* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] 5* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
6** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! 6** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
@@ -10,8 +10,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel f
10* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device 10* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device
11** Targets the ESP32-S3 or ESP32-C6 MCU 11** Targets the ESP32-S3 or ESP32-C6 MCU
12* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL 12* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL
13** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] 13* link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system]
14*** Targets nRF52 and uses nrf-softdevice 14** Targets nRF52 and uses nrf-softdevice
15 15
16* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop 16* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop
17firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are: 17firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are:
diff --git a/docs/modules/ROOT/pages/examples.adoc b/docs/pages/examples.adoc
index c852f5205..82381a2c5 100644
--- a/docs/modules/ROOT/pages/examples.adoc
+++ b/docs/pages/examples.adoc
@@ -7,5 +7,5 @@ Main loop example
7 7
8[source,rust] 8[source,rust]
9---- 9----
10include::example$examples/std/src/bin/tick.rs[] 10include::../examples/examples/std/src/bin/tick.rs[]
11---- 11----
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/pages/faq.adoc
index 6c7126cd6..5f50951d8 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/pages/faq.adoc
@@ -2,7 +2,7 @@
2 2
3These are a list of unsorted, commonly asked questions and answers. 3These are a list of unsorted, commonly asked questions and answers.
4 4
5Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/modules/ROOT/pages/faq.adoc[this page], especially if someone in the chat answered a question for you! 5Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/pages/faq.adoc[this page], especially if someone in the chat answered a question for you!
6 6
7== How to deploy to RP2040 without a debugging probe. 7== How to deploy to RP2040 without a debugging probe.
8 8
@@ -291,7 +291,7 @@ General steps:
291 291
292See link:/examples/stm32h7/src/bin/spi_bdma.rs[this example] for more details. 292See link:/examples/stm32h7/src/bin/spi_bdma.rs[this example] for more details.
293 293
294=== How do I switch to the `main` branch? 294== How do I switch to the `main` branch?
295 295
296Sometimes to test new changes or fixes, you'll want to switch your project to using a version from GitHub. 296Sometimes to test new changes or fixes, you'll want to switch your project to using a version from GitHub.
297 297
@@ -314,3 +314,22 @@ embassy-time = { git = "https://github.com/embassy-rs/embassy", rev
314embassy-usb = { git = "https://github.com/embassy-rs/embassy", rev = "4cade64ebd34bf93458f17cfe85c5f710d0ff13c" } 314embassy-usb = { git = "https://github.com/embassy-rs/embassy", rev = "4cade64ebd34bf93458f17cfe85c5f710d0ff13c" }
315embassy-usb-driver = { git = "https://github.com/embassy-rs/embassy", rev = "4cade64ebd34bf93458f17cfe85c5f710d0ff13c" } 315embassy-usb-driver = { git = "https://github.com/embassy-rs/embassy", rev = "4cade64ebd34bf93458f17cfe85c5f710d0ff13c" }
316---- 316----
317
318== How do I add support for a new microcontroller to embassy?
319
320This is particularly for cortex-m, and potentially risc-v, where there is already support for basics like interrupt handling, or even already embassy-executor support for your architecture.
321
322This is a *much harder path* than just using Embassy on an already supported chip. If you are a beginner, consider using embassy on an existing, well supported chip for a while, before you decide to write drivers from scratch. It's also worth reading the existing source of supported Embassy HALs, to get a feel for how drivers are implemented for various chips. You should already be comfortable reading and writing unsafe code, and understanding the responsibilities of writing safe abstractions for users of your HAL.
323
324This is not the only possible approach, but if you are looking for where to start, this is a reasonable way to tackle the task:
325
3261. First, drop by the Matrix room or search around to see if someone has already started writing drivers, either in Embassy or otherwise in Rust. You might not have to start from scratch!
3272. Make sure the target is supported in probe-rs, it likely is, and if not, there is likely a cmsis-pack you can use to add support so that flashing and debugging is possible. You will definitely appreciate being able to debug with SWD or JTAG when writing drivers!
3283. See if there is an SVD (or SVDs, if it's a family) available, if it is, run it through chiptool to create a PAC for low level register access. If not, there are other ways (like scraping the PDF datasheets or existing C header files), but these are more work than starting from the SVD file to define peripheral memory locations necessary for writing drivers.
3294. Either make a fork of embassy repo, and add your target there, or make a repo that just contains the PAC and an empty HAL. It doesn't necessarily have to live in the embassy repo at first.
3305. Get a hello world binary working on your chip, either with minimal HAL or just PAC access, use delays and blink a light or send some raw data on some interface, make sure it works and you can flash, debug with defmt + RTT, write a proper linker script, etc.
3316. Get basic timer operations and timer interrupts working, upgrade your blinking application to use hardware timers and interrupts, and ensure they are accurate (with a logic analyzer or oscilloscope, if possible).
3327. Implement the embassy-time driver API with your timer and timer interrupt code, so that you can use embassy-time operations in your drivers and applications.
3338. Then start implementing whatever peripherals you need, like GPIOs, UART, SPI, I2C, etc. This is the largest part of the work, and will likely continue for a while! Don't feel like you need 100% coverage of all peripherals at first, this is likely to be an ongoing process over time.
3349. Start implementing the embedded-hal, embedded-io, and embedded-hal-async traits on top of your HAL drivers, once you start having more features completed. This will allow users to use standard external device drivers (e.g. sensors, actuators, displays, etc.) with your HAL.
33510. Discuss upstreaming the PAC/HAL for embassy support, or make sure your drivers are added to the awesome-embedded-rust list so that people can find it.
diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/pages/getting_started.adoc
index 73cb5530d..465059922 100644
--- a/docs/modules/ROOT/pages/getting_started.adoc
+++ b/docs/pages/getting_started.adoc
@@ -137,7 +137,7 @@ If you’re still having problems, check the link:https://embassy.dev/book/dev/f
137 137
138Congratulations, you have your first Embassy application running! Here are some suggestions for where to go from here: 138Congratulations, you have your first Embassy application running! Here are some suggestions for where to go from here:
139 139
140* Read more about the xref:runtime.adoc[executor]. 140* Read more about the xref:_embassy_executor[executor].
141* Read more about the xref:hal.adoc[HAL]. 141* Read more about the xref:_hardware_abstraction_layer_hal[HAL].
142* Start xref:basic_application.adoc[writing your application]. 142* Start xref:_a_basic_embassy_application[writing your application].
143* Learn how to xref:new_project.adoc[start a new embassy project by adapting an example]. 143* Learn how to xref:_starting_a_new_project[start a new embassy project by adapting an example].
diff --git a/docs/modules/ROOT/pages/hal.adoc b/docs/pages/hal.adoc
index b1382e8e5..14b85e1f1 100644
--- a/docs/modules/ROOT/pages/hal.adoc
+++ b/docs/pages/hal.adoc
@@ -10,3 +10,5 @@ These HALs implement async/await functionality for most peripherals while also i
10async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor. 10async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor.
11 11
12For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use. 12For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use.
13
14For the WCH 32-bit RISC-V series, there is an link:https://github.com/ch32-rs/ch32-hal[ch32-hal], which you can use.
diff --git a/docs/modules/ROOT/pages/layer_by_layer.adoc b/docs/pages/layer_by_layer.adoc
index fa419f75e..f87291c20 100644
--- a/docs/modules/ROOT/pages/layer_by_layer.adoc
+++ b/docs/pages/layer_by_layer.adoc
@@ -16,7 +16,7 @@ The blinky app using PAC is shown below:
16 16
17[source,rust] 17[source,rust]
18---- 18----
19include::example$layer-by-layer/blinky-pac/src/main.rs[] 19include::../examples/layer-by-layer/blinky-pac/src/main.rs[]
20---- 20----
21 21
22As you can see, a lot of code is needed to enable the peripheral clocks and to configure the input pins and the output pins of the application. 22As you can see, a lot of code is needed to enable the peripheral clocks and to configure the input pins and the output pins of the application.
@@ -35,7 +35,7 @@ The HAL example is shown below:
35 35
36[source,rust] 36[source,rust]
37---- 37----
38include::example$layer-by-layer/blinky-hal/src/main.rs[] 38include::../examples/layer-by-layer/blinky-hal/src/main.rs[]
39---- 39----
40 40
41As you can see, the application becomes a lot simpler, even without using any async code. The `Input` and `Output` types hide all the details of accessing the GPIO registers and allow you to use a much simpler API for querying the state of the button and toggling the LED output. 41As you can see, the application becomes a lot simpler, even without using any async code. The `Input` and `Output` types hide all the details of accessing the GPIO registers and allow you to use a much simpler API for querying the state of the button and toggling the LED output.
@@ -52,7 +52,7 @@ Given Embassy focus on async Rust (which we'll come back to after this example),
52 52
53[source,rust] 53[source,rust]
54---- 54----
55include::example$layer-by-layer/blinky-irq/src/main.rs[lines="1..57"] 55include::../examples/layer-by-layer/blinky-irq/src/main.rs[lines="1..57"]
56---- 56----
57 57
58The simple application is now more complex again, primarily because of the need to keep the button and LED states in the global scope where it is accessible by the main application loop, as well as the interrupt handler. 58The simple application is now more complex again, primarily because of the need to keep the button and LED states in the global scope where it is accessible by the main application loop, as well as the interrupt handler.
@@ -67,7 +67,7 @@ It's time to use the Embassy capabilities to its fullest. At the core, Embassy h
67 67
68[source,rust] 68[source,rust]
69---- 69----
70include::example$layer-by-layer/blinky-async/src/main.rs[] 70include::../examples/layer-by-layer/blinky-async/src/main.rs[]
71---- 71----
72 72
73The async version looks very similar to the HAL version, apart from a few minor details: 73The async version looks very similar to the HAL version, apart from a few minor details:
diff --git a/docs/modules/ROOT/pages/new_project.adoc b/docs/pages/new_project.adoc
index 320966bb6..346d9f0f8 100644
--- a/docs/modules/ROOT/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -1,17 +1,18 @@
1= Starting a new Embassy project 1= Starting a new project
2 2
3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. 3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
4 4
5There are some tools for generating Embassy projects: (WIP) 5== Tools for generating Embassy projects
6 6
7==== CLI 7=== CLI
8- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF) 8- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF)
9 9
10==== cargo-generate 10=== cargo-generate
11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP) 11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP)
12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP) 12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP)
13 13
14But if you want to start from scratch: 14
15== Starting a project from scratch
15 16
16As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes. 17As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes.
17 18
@@ -35,7 +36,7 @@ stm32g474-example
35 36
36Looking in link:https://github.com/embassy-rs/embassy/tree/main/examples[the Embassy examples], we can see there’s a `stm32g4` folder. Find `src/blinky.rs` and copy its contents into our `src/main.rs`. 37Looking in link:https://github.com/embassy-rs/embassy/tree/main/examples[the Embassy examples], we can see there’s a `stm32g4` folder. Find `src/blinky.rs` and copy its contents into our `src/main.rs`.
37 38
38== .cargo/config.toml 39=== The .cargo/config.toml
39 40
40Currently, we’d need to provide cargo with a target triple every time we run `cargo build` or `cargo run`. Let’s spare ourselves that work by copying `.cargo/config.toml` from `examples/stm32g4` into our project. 41Currently, we’d need to provide cargo with a target triple every time we run `cargo build` or `cargo run`. Let’s spare ourselves that work by copying `.cargo/config.toml` from `examples/stm32g4` into our project.
41 42
@@ -66,7 +67,7 @@ and copying `STM32G474RETx` into `.cargo/config.toml` as so:
66runner = "probe-rs run --chip STM32G474RETx" 67runner = "probe-rs run --chip STM32G474RETx"
67---- 68----
68 69
69== Cargo.toml 70=== Cargo.toml
70 71
71Now that cargo knows what target to compile for (and probe-rs knows what chip to run it on), we’re ready to add some dependencies. 72Now that cargo knows what target to compile for (and probe-rs knows what chip to run it on), we’re ready to add some dependencies.
72 73
@@ -117,7 +118,7 @@ Finally, copy the `[profile.release]` section from the example `Cargo.toml` into
117debug = 2 118debug = 2
118---- 119----
119 120
120== rust-toolchain.toml 121=== rust-toolchain.toml
121 122
122Before we can build our project, we need to add an additional file to tell cargo to use the nightly toolchain. Copy the `rust-toolchain.toml` from the embassy repo to ours, and trim the list of targets down to only the target triple relevent for our project — in this case, `thumbv7em-none-eabi`: 123Before we can build our project, we need to add an additional file to tell cargo to use the nightly toolchain. Copy the `rust-toolchain.toml` from the embassy repo to ours, and trim the list of targets down to only the target triple relevent for our project — in this case, `thumbv7em-none-eabi`:
123 124
@@ -142,7 +143,7 @@ components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
142targets = ["thumbv7em-none-eabi"] 143targets = ["thumbv7em-none-eabi"]
143---- 144----
144 145
145== build.rs 146=== build.rs
146 147
147In order to produce a working binary for our target, cargo requires a custom build script. Copy `build.rs` from the example to our project: 148In order to produce a working binary for our target, cargo requires a custom build script. Copy `build.rs` from the example to our project:
148 149
@@ -158,7 +159,7 @@ stm32g474-example
158 └── main.rs 159 └── main.rs
159---- 160----
160 161
161== Building and running 162=== Building and running
162 163
163At this point, we‘re finally ready to build and run our project! Connect your board via a debug probe and run: 164At this point, we‘re finally ready to build and run our project! Connect your board via a debug probe and run:
164 165
diff --git a/docs/modules/ROOT/pages/nrf.adoc b/docs/pages/nrf.adoc
index 1706087ae..1706087ae 100644
--- a/docs/modules/ROOT/pages/nrf.adoc
+++ b/docs/pages/nrf.adoc
diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/pages/overview.adoc
index e17adbbd7..1b9381bfe 100644
--- a/docs/modules/ROOT/pages/index.adoc
+++ b/docs/pages/overview.adoc
@@ -1,4 +1,4 @@
1= Embassy 1= Introduction
2 2
3Embassy is a project to make async/await a first-class option for embedded development. 3Embassy is a project to make async/await a first-class option for embedded development.
4 4
@@ -30,6 +30,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA
30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. 30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. 31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
32* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. 32* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
33* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips.
33 34
34NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async, 35NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
35as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. 36as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
@@ -55,6 +56,20 @@ For most I/O in embedded devices, the peripheral doesn't directly support the tr
55 56
56The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them. 57The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them.
57 58
59== Examples
60
61Embassy provides examples for all HALs supported. You can find them in the `examples/` folder.
62
63
64Main loop example
65
66[source,rust]
67----
68include::../examples/examples/std/src/bin/tick.rs[]
69----
70
71include::embassy_in_the_wild.adoc[leveloffset = 2]
72
58== Resources 73== Resources
59 74
60For more reading material on async Rust and Embassy: 75For more reading material on async Rust and Embassy:
diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/pages/project_structure.adoc
index 2adfcc1df..722ec8d9d 100644
--- a/docs/modules/ROOT/pages/project_structure.adoc
+++ b/docs/pages/project_structure.adoc
@@ -18,6 +18,7 @@ my-project
18|- rust-toolchain.toml 18|- rust-toolchain.toml
19---- 19----
20 20
21[discrete]
21== .cargo/config.toml 22== .cargo/config.toml
22 23
23This directory/file describes what platform you're on, and configures link:https://github.com/probe-rs/probe-rs[probe-rs] to deploy to your device. 24This directory/file describes what platform you're on, and configures link:https://github.com/probe-rs/probe-rs[probe-rs] to deploy to your device.
@@ -36,21 +37,27 @@ target = "thumbv6m-none-eabi" # <-change for your platform
36DEFMT_LOG = "trace" # <- can change to info, warn, or error 37DEFMT_LOG = "trace" # <- can change to info, warn, or error
37---- 38----
38 39
40[discrete]
39== build.rs 41== build.rs
40 42
41This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. 43This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example].
42 44
45[discrete]
43== Cargo.toml 46== Cargo.toml
44 47
45This is your manifest file, where you can configure all of the embassy components to use the features you need. 48This is your manifest file, where you can configure all of the embassy components to use the features you need.
46 49
47==== Features 50[discrete]
48===== Time 51=== Features
52
53[discrete]
54==== Time
49- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes. 55- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes.
50- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds. 56- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds.
51 57
52...more to come 58...more to come
53 59
60[discrete]
54== memory.x 61== memory.x
55 62
56This file outlines the flash/ram usage of your program. It is especially useful when using link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] on an nRF5x. 63This file outlines the flash/ram usage of your program. It is especially useful when using link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] on an nRF5x.
@@ -68,6 +75,7 @@ MEMORY
68} 75}
69---- 76----
70 77
78[discrete]
71== rust-toolchain.toml 79== rust-toolchain.toml
72 80
73This file configures the rust version and configuration to use. 81This file configures the rust version and configuration to use.
diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/pages/runtime.adoc
index f2812dd7c..f2812dd7c 100644
--- a/docs/modules/ROOT/pages/runtime.adoc
+++ b/docs/pages/runtime.adoc
diff --git a/docs/modules/ROOT/pages/sharing_peripherals.adoc b/docs/pages/sharing_peripherals.adoc
index 784239fb1..6bcd56b01 100644
--- a/docs/modules/ROOT/pages/sharing_peripherals.adoc
+++ b/docs/pages/sharing_peripherals.adoc
@@ -125,4 +125,4 @@ async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>,
125---- 125----
126 126
127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure 127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
128that the operation is ecompleted before continuing to do other work in your task. 128that the operation is completed before continuing to do other work in your task.
diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/pages/stm32.adoc
index 7bfc0592b..7bfc0592b 100644
--- a/docs/modules/ROOT/pages/stm32.adoc
+++ b/docs/pages/stm32.adoc
diff --git a/docs/pages/system.adoc b/docs/pages/system.adoc
new file mode 100644
index 000000000..985f92b18
--- /dev/null
+++ b/docs/pages/system.adoc
@@ -0,0 +1,13 @@
1= System description
2
3This section describes different parts of Embassy in more detail.
4
5include::runtime.adoc[leveloffset = 2]
6include::bootloader.adoc[leveloffset = 2]
7include::time_keeping.adoc[leveloffset = 2]
8include::hal.adoc[leveloffset = 2]
9include::nrf.adoc[leveloffset = 2]
10include::stm32.adoc[leveloffset = 2]
11include::sharing_peripherals.adoc[leveloffset = 2]
12include::developer.adoc[leveloffset = 2]
13include::developer_stm32.adoc[leveloffset = 2]
diff --git a/docs/modules/ROOT/pages/time_keeping.adoc b/docs/pages/time_keeping.adoc
index 17492a884..17492a884 100644
--- a/docs/modules/ROOT/pages/time_keeping.adoc
+++ b/docs/pages/time_keeping.adoc
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index 9890f218d..30d4ecc36 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -55,13 +55,14 @@ where
55 type Error = SpiDeviceError<BUS::Error, CS::Error>; 55 type Error = SpiDeviceError<BUS::Error, CS::Error>;
56} 56}
57 57
58impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 58impl<M, BUS, CS, Word> spi::SpiDevice<Word> for SpiDevice<'_, M, BUS, CS>
59where 59where
60 M: RawMutex, 60 M: RawMutex,
61 BUS: spi::SpiBus, 61 BUS: spi::SpiBus<Word>,
62 CS: OutputPin, 62 CS: OutputPin,
63 Word: Copy + 'static,
63{ 64{
64 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> { 65 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
65 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) { 66 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
66 return Err(SpiDeviceError::DelayNotSupported); 67 return Err(SpiDeviceError::DelayNotSupported);
67 } 68 }
@@ -138,13 +139,14 @@ where
138 type Error = SpiDeviceError<BUS::Error, CS::Error>; 139 type Error = SpiDeviceError<BUS::Error, CS::Error>;
139} 140}
140 141
141impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 142impl<M, BUS, CS, Word> spi::SpiDevice<Word> for SpiDeviceWithConfig<'_, M, BUS, CS>
142where 143where
143 M: RawMutex, 144 M: RawMutex,
144 BUS: spi::SpiBus + SetConfig, 145 BUS: spi::SpiBus<Word> + SetConfig,
145 CS: OutputPin, 146 CS: OutputPin,
147 Word: Copy + 'static,
146{ 148{
147 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> { 149 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
148 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) { 150 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
149 return Err(SpiDeviceError::DelayNotSupported); 151 return Err(SpiDeviceError::DelayNotSupported);
150 } 152 }
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index 801899f9f..eb9c0c4f4 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -48,13 +48,14 @@ where
48 type Error = SpiDeviceError<BUS::Error, CS::Error>; 48 type Error = SpiDeviceError<BUS::Error, CS::Error>;
49} 49}
50 50
51impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 51impl<BUS, M, CS, Word> embedded_hal_1::spi::SpiDevice<Word> for SpiDevice<'_, M, BUS, CS>
52where 52where
53 M: RawMutex, 53 M: RawMutex,
54 BUS: SpiBus, 54 BUS: SpiBus<Word>,
55 CS: OutputPin, 55 CS: OutputPin,
56 Word: Copy + 'static,
56{ 57{
57 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> { 58 fn transaction(&mut self, operations: &mut [embedded_hal_1::spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
58 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) { 59 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
59 return Err(SpiDeviceError::DelayNotSupported); 60 return Err(SpiDeviceError::DelayNotSupported);
60 } 61 }
@@ -90,47 +91,6 @@ where
90 } 91 }
91} 92}
92 93
93impl<'d, M, BUS, CS, BusErr, CsErr> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDevice<'_, M, BUS, CS>
94where
95 M: RawMutex,
96 BUS: embedded_hal_02::blocking::spi::Transfer<u8, Error = BusErr>,
97 CS: OutputPin<Error = CsErr>,
98{
99 type Error = SpiDeviceError<BusErr, CsErr>;
100 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
101 self.bus.lock(|bus| {
102 let mut bus = bus.borrow_mut();
103 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
104 let op_res = bus.transfer(words);
105 let cs_res = self.cs.set_high();
106 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
107 cs_res.map_err(SpiDeviceError::Cs)?;
108 Ok(op_res)
109 })
110 }
111}
112
113impl<'d, M, BUS, CS, BusErr, CsErr> embedded_hal_02::blocking::spi::Write<u8> for SpiDevice<'_, M, BUS, CS>
114where
115 M: RawMutex,
116 BUS: embedded_hal_02::blocking::spi::Write<u8, Error = BusErr>,
117 CS: OutputPin<Error = CsErr>,
118{
119 type Error = SpiDeviceError<BusErr, CsErr>;
120
121 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
122 self.bus.lock(|bus| {
123 let mut bus = bus.borrow_mut();
124 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
125 let op_res = bus.write(words);
126 let cs_res = self.cs.set_high();
127 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
128 cs_res.map_err(SpiDeviceError::Cs)?;
129 Ok(op_res)
130 })
131 }
132}
133
134/// SPI device on a shared bus, with its own configuration. 94/// SPI device on a shared bus, with its own configuration.
135/// 95///
136/// This is like [`SpiDevice`], with an additional bus configuration that's applied 96/// This is like [`SpiDevice`], with an additional bus configuration that's applied
@@ -163,13 +123,14 @@ where
163 type Error = SpiDeviceError<BUS::Error, CS::Error>; 123 type Error = SpiDeviceError<BUS::Error, CS::Error>;
164} 124}
165 125
166impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 126impl<BUS, M, CS, Word> embedded_hal_1::spi::SpiDevice<Word> for SpiDeviceWithConfig<'_, M, BUS, CS>
167where 127where
168 M: RawMutex, 128 M: RawMutex,
169 BUS: SpiBus + SetConfig, 129 BUS: SpiBus<Word> + SetConfig,
170 CS: OutputPin, 130 CS: OutputPin,
131 Word: Copy + 'static,
171{ 132{
172 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> { 133 fn transaction(&mut self, operations: &mut [embedded_hal_1::spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
173 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) { 134 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
174 return Err(SpiDeviceError::DelayNotSupported); 135 return Err(SpiDeviceError::DelayNotSupported);
175 } 136 }
diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
index 40ad9dc7a..00b7a1249 100644
--- a/embassy-hal-internal/src/atomic_ring_buffer.rs
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -123,6 +123,11 @@ impl RingBuffer {
123 Some(Writer(self)) 123 Some(Writer(self))
124 } 124 }
125 125
126 /// Return if buffer is available.
127 pub fn is_available(&self) -> bool {
128 !self.buf.load(Ordering::Relaxed).is_null() && self.len.load(Ordering::Relaxed) != 0
129 }
130
126 /// Return length of buffer. 131 /// Return length of buffer.
127 pub fn len(&self) -> usize { 132 pub fn len(&self) -> usize {
128 self.len.load(Ordering::Relaxed) 133 self.len.load(Ordering::Relaxed)
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index dda65dbf9..96f6c8b00 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -9,6 +9,10 @@ license = "MIT OR Apache-2.0"
9repository = "https://github.com/embassy-rs/embassy" 9repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/embassy-net-esp-hosted" 10documentation = "https://docs.embassy.dev/embassy-net-esp-hosted"
11 11
12[features]
13defmt = [ "dep:defmt", "heapless/defmt-03" ]
14log = [ "dep:log" ]
15
12[dependencies] 16[dependencies]
13defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
14log = { version = "0.4.14", optional = true } 18log = { version = "0.4.14", optional = true }
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 45b385cb4..6e2a823d8 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -374,6 +374,11 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'
374 374
375impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {} 375impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {}
376 376
377impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::MultiwriteNorFlash
378 for Flash<'d, T, Async, FLASH_SIZE>
379{
380}
381
377impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> { 382impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> {
378 const WRITE_SIZE: usize = WRITE_SIZE; 383 const WRITE_SIZE: usize = WRITE_SIZE;
379 384
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index a1f400cfb..20b5c4d58 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -81,24 +81,22 @@ impl From<InputMode> for Divmode {
81} 81}
82 82
83/// PWM driver. 83/// PWM driver.
84pub struct Pwm<'d, T: Slice> { 84pub struct Pwm<'d> {
85 inner: PeripheralRef<'d, T>,
86 pin_a: Option<PeripheralRef<'d, AnyPin>>, 85 pin_a: Option<PeripheralRef<'d, AnyPin>>,
87 pin_b: Option<PeripheralRef<'d, AnyPin>>, 86 pin_b: Option<PeripheralRef<'d, AnyPin>>,
87 slice: usize,
88} 88}
89 89
90impl<'d, T: Slice> Pwm<'d, T> { 90impl<'d> Pwm<'d> {
91 fn new_inner( 91 fn new_inner(
92 inner: impl Peripheral<P = T> + 'd, 92 slice: usize,
93 a: Option<PeripheralRef<'d, AnyPin>>, 93 a: Option<PeripheralRef<'d, AnyPin>>,
94 b: Option<PeripheralRef<'d, AnyPin>>, 94 b: Option<PeripheralRef<'d, AnyPin>>,
95 b_pull: Pull, 95 b_pull: Pull,
96 config: Config, 96 config: Config,
97 divmode: Divmode, 97 divmode: Divmode,
98 ) -> Self { 98 ) -> Self {
99 into_ref!(inner); 99 let p = pac::PWM.ch(slice);
100
101 let p = inner.regs();
102 p.csr().modify(|w| { 100 p.csr().modify(|w| {
103 w.set_divmode(divmode); 101 w.set_divmode(divmode);
104 w.set_en(false); 102 w.set_en(false);
@@ -117,51 +115,67 @@ impl<'d, T: Slice> Pwm<'d, T> {
117 }); 115 });
118 } 116 }
119 Self { 117 Self {
120 inner, 118 // inner: p.into(),
121 pin_a: a, 119 pin_a: a,
122 pin_b: b, 120 pin_b: b,
121 slice,
123 } 122 }
124 } 123 }
125 124
126 /// Create PWM driver without any configured pins. 125 /// Create PWM driver without any configured pins.
127 #[inline] 126 #[inline]
128 pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self { 127 pub fn new_free<T: Slice>(slice: impl Peripheral<P = T> + 'd, config: Config) -> Self {
129 Self::new_inner(inner, None, None, Pull::None, config, Divmode::DIV) 128 into_ref!(slice);
129 Self::new_inner(slice.number(), None, None, Pull::None, config, Divmode::DIV)
130 } 130 }
131 131
132 /// Create PWM driver with a single 'a' as output. 132 /// Create PWM driver with a single 'a' as output.
133 #[inline] 133 #[inline]
134 pub fn new_output_a( 134 pub fn new_output_a<T: Slice>(
135 inner: impl Peripheral<P = T> + 'd, 135 slice: impl Peripheral<P = T> + 'd,
136 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, 136 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd,
137 config: Config, 137 config: Config,
138 ) -> Self { 138 ) -> Self {
139 into_ref!(a); 139 into_ref!(slice, a);
140 Self::new_inner(inner, Some(a.map_into()), None, Pull::None, config, Divmode::DIV) 140 Self::new_inner(
141 slice.number(),
142 Some(a.map_into()),
143 None,
144 Pull::None,
145 config,
146 Divmode::DIV,
147 )
141 } 148 }
142 149
143 /// Create PWM driver with a single 'b' pin as output. 150 /// Create PWM driver with a single 'b' pin as output.
144 #[inline] 151 #[inline]
145 pub fn new_output_b( 152 pub fn new_output_b<T: Slice>(
146 inner: impl Peripheral<P = T> + 'd, 153 slice: impl Peripheral<P = T> + 'd,
147 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 154 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
148 config: Config, 155 config: Config,
149 ) -> Self { 156 ) -> Self {
150 into_ref!(b); 157 into_ref!(slice, b);
151 Self::new_inner(inner, None, Some(b.map_into()), Pull::None, config, Divmode::DIV) 158 Self::new_inner(
159 slice.number(),
160 None,
161 Some(b.map_into()),
162 Pull::None,
163 config,
164 Divmode::DIV,
165 )
152 } 166 }
153 167
154 /// Create PWM driver with a 'a' and 'b' pins as output. 168 /// Create PWM driver with a 'a' and 'b' pins as output.
155 #[inline] 169 #[inline]
156 pub fn new_output_ab( 170 pub fn new_output_ab<T: Slice>(
157 inner: impl Peripheral<P = T> + 'd, 171 slice: impl Peripheral<P = T> + 'd,
158 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, 172 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd,
159 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 173 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
160 config: Config, 174 config: Config,
161 ) -> Self { 175 ) -> Self {
162 into_ref!(a, b); 176 into_ref!(slice, a, b);
163 Self::new_inner( 177 Self::new_inner(
164 inner, 178 slice.number(),
165 Some(a.map_into()), 179 Some(a.map_into()),
166 Some(b.map_into()), 180 Some(b.map_into()),
167 Pull::None, 181 Pull::None,
@@ -172,30 +186,30 @@ impl<'d, T: Slice> Pwm<'d, T> {
172 186
173 /// Create PWM driver with a single 'b' as input pin. 187 /// Create PWM driver with a single 'b' as input pin.
174 #[inline] 188 #[inline]
175 pub fn new_input( 189 pub fn new_input<T: Slice>(
176 inner: impl Peripheral<P = T> + 'd, 190 slice: impl Peripheral<P = T> + 'd,
177 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 191 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
178 b_pull: Pull, 192 b_pull: Pull,
179 mode: InputMode, 193 mode: InputMode,
180 config: Config, 194 config: Config,
181 ) -> Self { 195 ) -> Self {
182 into_ref!(b); 196 into_ref!(slice, b);
183 Self::new_inner(inner, None, Some(b.map_into()), b_pull, config, mode.into()) 197 Self::new_inner(slice.number(), None, Some(b.map_into()), b_pull, config, mode.into())
184 } 198 }
185 199
186 /// Create PWM driver with a 'a' and 'b' pins in the desired input mode. 200 /// Create PWM driver with a 'a' and 'b' pins in the desired input mode.
187 #[inline] 201 #[inline]
188 pub fn new_output_input( 202 pub fn new_output_input<T: Slice>(
189 inner: impl Peripheral<P = T> + 'd, 203 slice: impl Peripheral<P = T> + 'd,
190 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, 204 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd,
191 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 205 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
192 b_pull: Pull, 206 b_pull: Pull,
193 mode: InputMode, 207 mode: InputMode,
194 config: Config, 208 config: Config,
195 ) -> Self { 209 ) -> Self {
196 into_ref!(a, b); 210 into_ref!(slice, a, b);
197 Self::new_inner( 211 Self::new_inner(
198 inner, 212 slice.number(),
199 Some(a.map_into()), 213 Some(a.map_into()),
200 Some(b.map_into()), 214 Some(b.map_into()),
201 b_pull, 215 b_pull,
@@ -206,7 +220,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
206 220
207 /// Set the PWM config. 221 /// Set the PWM config.
208 pub fn set_config(&mut self, config: &Config) { 222 pub fn set_config(&mut self, config: &Config) {
209 Self::configure(self.inner.regs(), config); 223 Self::configure(pac::PWM.ch(self.slice), config);
210 } 224 }
211 225
212 fn configure(p: pac::pwm::Channel, config: &Config) { 226 fn configure(p: pac::pwm::Channel, config: &Config) {
@@ -228,22 +242,22 @@ impl<'d, T: Slice> Pwm<'d, T> {
228 }); 242 });
229 } 243 }
230 244
231 /// Advances a slices output phase by one count while it is running 245 /// Advances a slice's output phase by one count while it is running
232 /// by inserting a pulse into the clock enable. The counter 246 /// by inserting a pulse into the clock enable. The counter
233 /// will not count faster than once per cycle. 247 /// will not count faster than once per cycle.
234 #[inline] 248 #[inline]
235 pub fn phase_advance(&mut self) { 249 pub fn phase_advance(&mut self) {
236 let p = self.inner.regs(); 250 let p = pac::PWM.ch(self.slice);
237 p.csr().write_set(|w| w.set_ph_adv(true)); 251 p.csr().write_set(|w| w.set_ph_adv(true));
238 while p.csr().read().ph_adv() {} 252 while p.csr().read().ph_adv() {}
239 } 253 }
240 254
241 /// Retards a slices output phase by one count while it is running 255 /// Retards a slice's output phase by one count while it is running
242 /// by deleting a pulse from the clock enable. The counter will not 256 /// by deleting a pulse from the clock enable. The counter will not
243 /// count backward when clock enable is permenantly low. 257 /// count backward when clock enable is permanently low.
244 #[inline] 258 #[inline]
245 pub fn phase_retard(&mut self) { 259 pub fn phase_retard(&mut self) {
246 let p = self.inner.regs(); 260 let p = pac::PWM.ch(self.slice);
247 p.csr().write_set(|w| w.set_ph_ret(true)); 261 p.csr().write_set(|w| w.set_ph_ret(true));
248 while p.csr().read().ph_ret() {} 262 while p.csr().read().ph_ret() {}
249 } 263 }
@@ -251,13 +265,13 @@ impl<'d, T: Slice> Pwm<'d, T> {
251 /// Read PWM counter. 265 /// Read PWM counter.
252 #[inline] 266 #[inline]
253 pub fn counter(&self) -> u16 { 267 pub fn counter(&self) -> u16 {
254 self.inner.regs().ctr().read().ctr() 268 pac::PWM.ch(self.slice).ctr().read().ctr()
255 } 269 }
256 270
257 /// Write PWM counter. 271 /// Write PWM counter.
258 #[inline] 272 #[inline]
259 pub fn set_counter(&self, ctr: u16) { 273 pub fn set_counter(&self, ctr: u16) {
260 self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) 274 pac::PWM.ch(self.slice).ctr().write(|w| w.set_ctr(ctr))
261 } 275 }
262 276
263 /// Wait for channel interrupt. 277 /// Wait for channel interrupt.
@@ -281,7 +295,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
281 295
282 #[inline] 296 #[inline]
283 fn bit(&self) -> u32 { 297 fn bit(&self) -> u32 {
284 1 << self.inner.number() as usize 298 1 << self.slice as usize
285 } 299 }
286} 300}
287 301
@@ -291,7 +305,7 @@ pub struct PwmBatch(u32);
291impl PwmBatch { 305impl PwmBatch {
292 #[inline] 306 #[inline]
293 /// Enable a PWM slice in this batch. 307 /// Enable a PWM slice in this batch.
294 pub fn enable(&mut self, pwm: &Pwm<'_, impl Slice>) { 308 pub fn enable(&mut self, pwm: &Pwm<'_>) {
295 self.0 |= pwm.bit(); 309 self.0 |= pwm.bit();
296 } 310 }
297 311
@@ -308,9 +322,9 @@ impl PwmBatch {
308 } 322 }
309} 323}
310 324
311impl<'d, T: Slice> Drop for Pwm<'d, T> { 325impl<'d> Drop for Pwm<'d> {
312 fn drop(&mut self) { 326 fn drop(&mut self) {
313 self.inner.regs().csr().write_clear(|w| w.set_en(false)); 327 pac::PWM.ch(self.slice).csr().write_clear(|w| w.set_en(false));
314 if let Some(pin) = &self.pin_a { 328 if let Some(pin) = &self.pin_a {
315 pin.gpio().ctrl().write(|w| w.set_funcsel(31)); 329 pin.gpio().ctrl().write(|w| w.set_funcsel(31));
316 } 330 }
@@ -326,19 +340,14 @@ trait SealedSlice {}
326#[allow(private_bounds)] 340#[allow(private_bounds)]
327pub trait Slice: Peripheral<P = Self> + SealedSlice + Sized + 'static { 341pub trait Slice: Peripheral<P = Self> + SealedSlice + Sized + 'static {
328 /// Slice number. 342 /// Slice number.
329 fn number(&self) -> u8; 343 fn number(&self) -> usize;
330
331 /// Slice register block.
332 fn regs(&self) -> pac::pwm::Channel {
333 pac::PWM.ch(self.number() as _)
334 }
335} 344}
336 345
337macro_rules! slice { 346macro_rules! slice {
338 ($name:ident, $num:expr) => { 347 ($name:ident, $num:expr) => {
339 impl SealedSlice for peripherals::$name {} 348 impl SealedSlice for peripherals::$name {}
340 impl Slice for peripherals::$name { 349 impl Slice for peripherals::$name {
341 fn number(&self) -> u8 { 350 fn number(&self) -> usize {
342 $num 351 $num
343 } 352 }
344 } 353 }
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index da1157984..c94164040 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -51,14 +51,20 @@ pub struct BufferedUartTx<'d, T: Instance> {
51 51
52pub(crate) fn init_buffers<'d, T: Instance + 'd>( 52pub(crate) fn init_buffers<'d, T: Instance + 'd>(
53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
54 tx_buffer: &'d mut [u8], 54 tx_buffer: Option<&'d mut [u8]>,
55 rx_buffer: &'d mut [u8], 55 rx_buffer: Option<&'d mut [u8]>,
56) { 56) {
57 let state = T::buffered_state(); 57 let state = T::buffered_state();
58 let len = tx_buffer.len(); 58
59 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 59 if let Some(tx_buffer) = tx_buffer {
60 let len = rx_buffer.len(); 60 let len = tx_buffer.len();
61 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 61 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
62 }
63
64 if let Some(rx_buffer) = rx_buffer {
65 let len = rx_buffer.len();
66 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
67 }
62 68
63 // From the datasheet: 69 // From the datasheet:
64 // "The transmit interrupt is based on a transition through a level, rather 70 // "The transmit interrupt is based on a transition through a level, rather
@@ -95,7 +101,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
95 into_ref!(tx, rx); 101 into_ref!(tx, rx);
96 102
97 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config); 103 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config);
98 init_buffers::<T>(irq, tx_buffer, rx_buffer); 104 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
99 105
100 Self { 106 Self {
101 rx: BufferedUartRx { phantom: PhantomData }, 107 rx: BufferedUartRx { phantom: PhantomData },
@@ -124,7 +130,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
124 Some(cts.map_into()), 130 Some(cts.map_into()),
125 config, 131 config,
126 ); 132 );
127 init_buffers::<T>(irq, tx_buffer, rx_buffer); 133 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
128 134
129 Self { 135 Self {
130 rx: BufferedUartRx { phantom: PhantomData }, 136 rx: BufferedUartRx { phantom: PhantomData },
@@ -175,7 +181,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
175 into_ref!(rx); 181 into_ref!(rx);
176 182
177 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config); 183 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
178 init_buffers::<T>(irq, &mut [], rx_buffer); 184 init_buffers::<T>(irq, None, Some(rx_buffer));
179 185
180 Self { phantom: PhantomData } 186 Self { phantom: PhantomData }
181 } 187 }
@@ -192,7 +198,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
192 into_ref!(rx, rts); 198 into_ref!(rx, rts);
193 199
194 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config); 200 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config);
195 init_buffers::<T>(irq, &mut [], rx_buffer); 201 init_buffers::<T>(irq, None, Some(rx_buffer));
196 202
197 Self { phantom: PhantomData } 203 Self { phantom: PhantomData }
198 } 204 }
@@ -323,7 +329,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
323 into_ref!(tx); 329 into_ref!(tx);
324 330
325 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config); 331 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
326 init_buffers::<T>(irq, tx_buffer, &mut []); 332 init_buffers::<T>(irq, Some(tx_buffer), None);
327 333
328 Self { phantom: PhantomData } 334 Self { phantom: PhantomData }
329 } 335 }
@@ -340,12 +346,12 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
340 into_ref!(tx, cts); 346 into_ref!(tx, cts);
341 347
342 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config); 348 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config);
343 init_buffers::<T>(irq, tx_buffer, &mut []); 349 init_buffers::<T>(irq, Some(tx_buffer), None);
344 350
345 Self { phantom: PhantomData } 351 Self { phantom: PhantomData }
346 } 352 }
347 353
348 fn write<'a>(buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { 354 fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ {
349 poll_fn(move |cx| { 355 poll_fn(move |cx| {
350 if buf.is_empty() { 356 if buf.is_empty() {
351 return Poll::Ready(Ok(0)); 357 return Poll::Ready(Ok(0));
@@ -459,9 +465,9 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
459 let state = T::buffered_state(); 465 let state = T::buffered_state();
460 unsafe { state.rx_buf.deinit() } 466 unsafe { state.rx_buf.deinit() }
461 467
462 // TX is inactive if the the buffer is not available. 468 // TX is inactive if the buffer is not available.
463 // We can now unregister the interrupt handler 469 // We can now unregister the interrupt handler
464 if state.tx_buf.is_empty() { 470 if !state.tx_buf.is_available() {
465 T::Interrupt::disable(); 471 T::Interrupt::disable();
466 } 472 }
467 } 473 }
@@ -472,9 +478,9 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
472 let state = T::buffered_state(); 478 let state = T::buffered_state();
473 unsafe { state.tx_buf.deinit() } 479 unsafe { state.tx_buf.deinit() }
474 480
475 // RX is inactive if the the buffer is not available. 481 // RX is inactive if the buffer is not available.
476 // We can now unregister the interrupt handler 482 // We can now unregister the interrupt handler
477 if state.rx_buf.is_empty() { 483 if !state.rx_buf.is_available() {
478 T::Interrupt::disable(); 484 T::Interrupt::disable();
479 } 485 }
480 } 486 }
@@ -520,64 +526,68 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
520 } 526 }
521 527
522 // RX 528 // RX
523 let mut rx_writer = unsafe { s.rx_buf.writer() }; 529 if s.rx_buf.is_available() {
524 let rx_buf = rx_writer.push_slice(); 530 let mut rx_writer = unsafe { s.rx_buf.writer() };
525 let mut n_read = 0; 531 let rx_buf = rx_writer.push_slice();
526 let mut error = false; 532 let mut n_read = 0;
527 for rx_byte in rx_buf { 533 let mut error = false;
528 if r.uartfr().read().rxfe() { 534 for rx_byte in rx_buf {
529 break; 535 if r.uartfr().read().rxfe() {
536 break;
537 }
538 let dr = r.uartdr().read();
539 if (dr.0 >> 8) != 0 {
540 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
541 error = true;
542 // only fill the buffer with valid characters. the current character is fine
543 // if the error is an overrun, but if we add it to the buffer we'll report
544 // the overrun one character too late. drop it instead and pretend we were
545 // a bit slower at draining the rx fifo than we actually were.
546 // this is consistent with blocking uart error reporting.
547 break;
548 }
549 *rx_byte = dr.data();
550 n_read += 1;
530 } 551 }
531 let dr = r.uartdr().read(); 552 if n_read > 0 {
532 if (dr.0 >> 8) != 0 { 553 rx_writer.push_done(n_read);
533 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); 554 s.rx_waker.wake();
534 error = true; 555 } else if error {
535 // only fill the buffer with valid characters. the current character is fine 556 s.rx_waker.wake();
536 // if the error is an overrun, but if we add it to the buffer we'll report 557 }
537 // the overrun one character too late. drop it instead and pretend we were 558 // Disable any further RX interrupts when the buffer becomes full or
538 // a bit slower at draining the rx fifo than we actually were. 559 // errors have occurred. This lets us buffer additional errors in the
539 // this is consistent with blocking uart error reporting. 560 // fifo without needing more error storage locations, and most applications
540 break; 561 // will want to do a full reset of their uart state anyway once an error
562 // has happened.
563 if s.rx_buf.is_full() || error {
564 r.uartimsc().write_clear(|w| {
565 w.set_rxim(true);
566 w.set_rtim(true);
567 });
541 } 568 }
542 *rx_byte = dr.data();
543 n_read += 1;
544 }
545 if n_read > 0 {
546 rx_writer.push_done(n_read);
547 s.rx_waker.wake();
548 } else if error {
549 s.rx_waker.wake();
550 }
551 // Disable any further RX interrupts when the buffer becomes full or
552 // errors have occurred. This lets us buffer additional errors in the
553 // fifo without needing more error storage locations, and most applications
554 // will want to do a full reset of their uart state anyway once an error
555 // has happened.
556 if s.rx_buf.is_full() || error {
557 r.uartimsc().write_clear(|w| {
558 w.set_rxim(true);
559 w.set_rtim(true);
560 });
561 } 569 }
562 570
563 // TX 571 // TX
564 let mut tx_reader = unsafe { s.tx_buf.reader() }; 572 if s.tx_buf.is_available() {
565 let tx_buf = tx_reader.pop_slice(); 573 let mut tx_reader = unsafe { s.tx_buf.reader() };
566 let mut n_written = 0; 574 let tx_buf = tx_reader.pop_slice();
567 for tx_byte in tx_buf.iter_mut() { 575 let mut n_written = 0;
568 if r.uartfr().read().txff() { 576 for tx_byte in tx_buf.iter_mut() {
569 break; 577 if r.uartfr().read().txff() {
578 break;
579 }
580 r.uartdr().write(|w| w.set_data(*tx_byte));
581 n_written += 1;
570 } 582 }
571 r.uartdr().write(|w| w.set_data(*tx_byte)); 583 if n_written > 0 {
572 n_written += 1; 584 tx_reader.pop_done(n_written);
573 } 585 s.tx_waker.wake();
574 if n_written > 0 { 586 }
575 tx_reader.pop_done(n_written); 587 // The TX interrupt only triggers once when the FIFO threshold is
576 s.tx_waker.wake(); 588 // crossed. No need to disable it when the buffer becomes empty
589 // as it does re-trigger anymore once we have cleared it.
577 } 590 }
578 // The TX interrupt only triggers once when the FIFO threshold is
579 // crossed. No need to disable it when the buffer becomes empty
580 // as it does re-trigger anymore once we have cleared it.
581 } 591 }
582} 592}
583 593
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index ee2dcb27d..30ece15bd 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -231,7 +231,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
231 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 231 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
232 tx_buffer: &'d mut [u8], 232 tx_buffer: &'d mut [u8],
233 ) -> BufferedUartTx<'d, T> { 233 ) -> BufferedUartTx<'d, T> {
234 buffered::init_buffers::<T>(irq, tx_buffer, &mut []); 234 buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
235 235
236 BufferedUartTx { phantom: PhantomData } 236 BufferedUartTx { phantom: PhantomData }
237 } 237 }
@@ -352,7 +352,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
352 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 352 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
353 rx_buffer: &'d mut [u8], 353 rx_buffer: &'d mut [u8],
354 ) -> BufferedUartRx<'d, T> { 354 ) -> BufferedUartRx<'d, T> {
355 buffered::init_buffers::<T>(irq, &mut [], rx_buffer); 355 buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
356 356
357 BufferedUartRx { phantom: PhantomData } 357 BufferedUartRx { phantom: PhantomData }
358 } 358 }
@@ -690,7 +690,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
690 tx_buffer: &'d mut [u8], 690 tx_buffer: &'d mut [u8],
691 rx_buffer: &'d mut [u8], 691 rx_buffer: &'d mut [u8],
692 ) -> BufferedUart<'d, T> { 692 ) -> BufferedUart<'d, T> {
693 buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer); 693 buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
694 694
695 BufferedUart { 695 BufferedUart {
696 rx: BufferedUartRx { phantom: PhantomData }, 696 rx: BufferedUartRx { phantom: PhantomData },
@@ -860,7 +860,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
860 }); 860 });
861 } 861 }
862 862
863 /// sets baudrate on runtime 863 /// sets baudrate on runtime
864 pub fn set_baudrate(&mut self, baudrate: u32) { 864 pub fn set_baudrate(&mut self, baudrate: u32) {
865 Self::set_baudrate_inner(baudrate); 865 Self::set_baudrate_inner(baudrate);
866 } 866 }
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index a50da1a9e..5ef2366d9 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f1297385e91f061fcb6134bb25f51e12d8abff93" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -89,7 +89,6 @@ volatile-register = { version = "0.2.1" }
89bitflags = "2.4.2" 89bitflags = "2.4.2"
90 90
91 91
92
93[dev-dependencies] 92[dev-dependencies]
94critical-section = { version = "1.1", features = ["std"] } 93critical-section = { version = "1.1", features = ["std"] }
95 94
@@ -98,7 +97,7 @@ proc-macro2 = "1.0.36"
98quote = "1.0.15" 97quote = "1.0.15"
99 98
100#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
101stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f1297385e91f061fcb6134bb25f51e12d8abff93", default-features = false, features = ["metadata"]} 100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]}
102 101
103[features] 102[features]
104default = ["rt"] 103default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index ba118f338..4eed6fe7d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -7,6 +7,7 @@ use std::{env, fs};
7 7
8use proc_macro2::{Ident, TokenStream}; 8use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
10use stm32_metapac::metadata::ir::BitOffset;
10use stm32_metapac::metadata::{ 11use stm32_metapac::metadata::{
11 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, 12 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
12}; 13};
@@ -359,12 +360,17 @@ fn main() {
359 360
360 // ======== 361 // ========
361 // Extract the rcc registers 362 // Extract the rcc registers
363
362 let rcc_registers = METADATA 364 let rcc_registers = METADATA
363 .peripherals 365 .peripherals
364 .iter() 366 .iter()
365 .filter_map(|p| p.registers.as_ref()) 367 .filter_map(|p| p.registers.as_ref())
366 .find(|r| r.kind == "rcc") 368 .find(|r| r.kind == "rcc")
367 .unwrap(); 369 .unwrap();
370 for b in rcc_registers.ir.blocks {
371 eprintln!("{}", b.name);
372 }
373 let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap();
368 374
369 // ======== 375 // ========
370 // Generate RccPeripheral impls 376 // Generate RccPeripheral impls
@@ -540,6 +546,29 @@ fn main() {
540 let pname = format_ident!("{}", p.name); 546 let pname = format_ident!("{}", p.name);
541 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); 547 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
542 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); 548 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
549 let en_reg_offs = rcc_block
550 .items
551 .iter()
552 .find(|i| i.name.eq_ignore_ascii_case(en.register))
553 .unwrap()
554 .byte_offset;
555 let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap();
556
557 let en_bit_offs = &rcc_registers
558 .ir
559 .fieldsets
560 .iter()
561 .find(|i| i.name.eq_ignore_ascii_case(en.register))
562 .unwrap()
563 .fields
564 .iter()
565 .find(|i| i.name.eq_ignore_ascii_case(en.field))
566 .unwrap()
567 .bit_offset;
568 let BitOffset::Regular(en_bit_offs) = en_bit_offs else {
569 panic!("cursed bit offset")
570 };
571 let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
543 572
544 let refcount = 573 let refcount =
545 clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; 574 clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
@@ -624,6 +653,9 @@ fn main() {
624 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); 653 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
625 #decr_stop_refcount 654 #decr_stop_refcount
626 } 655 }
656
657 const ENABLE_BIT: crate::rcc::ClockEnableBit =
658 unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) };
627 } 659 }
628 660
629 impl crate::rcc::RccPeripheral for peripherals::#pname {} 661 impl crate::rcc::RccPeripheral for peripherals::#pname {}
@@ -836,6 +868,35 @@ fn main() {
836 (("dcmi", "HSYNC"), quote!(crate::dcmi::HSyncPin)), 868 (("dcmi", "HSYNC"), quote!(crate::dcmi::HSyncPin)),
837 (("dcmi", "VSYNC"), quote!(crate::dcmi::VSyncPin)), 869 (("dcmi", "VSYNC"), quote!(crate::dcmi::VSyncPin)),
838 (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), 870 (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)),
871 (("dsihost", "TE"), quote!(crate::dsihost::TePin)),
872 (("ltdc", "CLK"), quote!(crate::ltdc::ClkPin)),
873 (("ltdc", "HSYNC"), quote!(crate::ltdc::HsyncPin)),
874 (("ltdc", "VSYNC"), quote!(crate::ltdc::VsyncPin)),
875 (("ltdc", "DE"), quote!(crate::ltdc::DePin)),
876 (("ltdc", "R0"), quote!(crate::ltdc::R0Pin)),
877 (("ltdc", "R1"), quote!(crate::ltdc::R1Pin)),
878 (("ltdc", "R2"), quote!(crate::ltdc::R2Pin)),
879 (("ltdc", "R3"), quote!(crate::ltdc::R3Pin)),
880 (("ltdc", "R4"), quote!(crate::ltdc::R4Pin)),
881 (("ltdc", "R5"), quote!(crate::ltdc::R5Pin)),
882 (("ltdc", "R6"), quote!(crate::ltdc::R6Pin)),
883 (("ltdc", "R7"), quote!(crate::ltdc::R7Pin)),
884 (("ltdc", "G0"), quote!(crate::ltdc::G0Pin)),
885 (("ltdc", "G1"), quote!(crate::ltdc::G1Pin)),
886 (("ltdc", "G2"), quote!(crate::ltdc::G2Pin)),
887 (("ltdc", "G3"), quote!(crate::ltdc::G3Pin)),
888 (("ltdc", "G4"), quote!(crate::ltdc::G4Pin)),
889 (("ltdc", "G5"), quote!(crate::ltdc::G5Pin)),
890 (("ltdc", "G6"), quote!(crate::ltdc::G6Pin)),
891 (("ltdc", "G7"), quote!(crate::ltdc::G7Pin)),
892 (("ltdc", "B0"), quote!(crate::ltdc::B0Pin)),
893 (("ltdc", "B1"), quote!(crate::ltdc::B1Pin)),
894 (("ltdc", "B2"), quote!(crate::ltdc::B2Pin)),
895 (("ltdc", "B3"), quote!(crate::ltdc::B3Pin)),
896 (("ltdc", "B4"), quote!(crate::ltdc::B4Pin)),
897 (("ltdc", "B5"), quote!(crate::ltdc::B5Pin)),
898 (("ltdc", "B6"), quote!(crate::ltdc::B6Pin)),
899 (("ltdc", "B7"), quote!(crate::ltdc::B7Pin)),
839 (("usb", "DP"), quote!(crate::usb::DpPin)), 900 (("usb", "DP"), quote!(crate::usb::DpPin)),
840 (("usb", "DM"), quote!(crate::usb::DmPin)), 901 (("usb", "DM"), quote!(crate::usb::DmPin)),
841 (("otg", "DP"), quote!(crate::usb::DpPin)), 902 (("otg", "DP"), quote!(crate::usb::DpPin)),
@@ -1030,6 +1091,38 @@ fn main() {
1030 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), 1091 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
1031 (("octospi", "CLK"), quote!(crate::ospi::SckPin)), 1092 (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
1032 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), 1093 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
1094 (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)),
1095 (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)),
1096 (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)),
1097 (("tsc", "G1_IO4"), quote!(crate::tsc::G1IO4Pin)),
1098 (("tsc", "G2_IO1"), quote!(crate::tsc::G2IO1Pin)),
1099 (("tsc", "G2_IO2"), quote!(crate::tsc::G2IO2Pin)),
1100 (("tsc", "G2_IO3"), quote!(crate::tsc::G2IO3Pin)),
1101 (("tsc", "G2_IO4"), quote!(crate::tsc::G2IO4Pin)),
1102 (("tsc", "G3_IO1"), quote!(crate::tsc::G3IO1Pin)),
1103 (("tsc", "G3_IO2"), quote!(crate::tsc::G3IO2Pin)),
1104 (("tsc", "G3_IO3"), quote!(crate::tsc::G3IO3Pin)),
1105 (("tsc", "G3_IO4"), quote!(crate::tsc::G3IO4Pin)),
1106 (("tsc", "G4_IO1"), quote!(crate::tsc::G4IO1Pin)),
1107 (("tsc", "G4_IO2"), quote!(crate::tsc::G4IO2Pin)),
1108 (("tsc", "G4_IO3"), quote!(crate::tsc::G4IO3Pin)),
1109 (("tsc", "G4_IO4"), quote!(crate::tsc::G4IO4Pin)),
1110 (("tsc", "G5_IO1"), quote!(crate::tsc::G5IO1Pin)),
1111 (("tsc", "G5_IO2"), quote!(crate::tsc::G5IO2Pin)),
1112 (("tsc", "G5_IO3"), quote!(crate::tsc::G5IO3Pin)),
1113 (("tsc", "G5_IO4"), quote!(crate::tsc::G5IO4Pin)),
1114 (("tsc", "G6_IO1"), quote!(crate::tsc::G6IO1Pin)),
1115 (("tsc", "G6_IO2"), quote!(crate::tsc::G6IO2Pin)),
1116 (("tsc", "G6_IO3"), quote!(crate::tsc::G6IO3Pin)),
1117 (("tsc", "G6_IO4"), quote!(crate::tsc::G6IO4Pin)),
1118 (("tsc", "G7_IO1"), quote!(crate::tsc::G7IO1Pin)),
1119 (("tsc", "G7_IO2"), quote!(crate::tsc::G7IO2Pin)),
1120 (("tsc", "G7_IO3"), quote!(crate::tsc::G7IO3Pin)),
1121 (("tsc", "G7_IO4"), quote!(crate::tsc::G7IO4Pin)),
1122 (("tsc", "G8_IO1"), quote!(crate::tsc::G8IO1Pin)),
1123 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
1124 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
1125 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
1033 ].into(); 1126 ].into();
1034 1127
1035 for p in METADATA.peripherals { 1128 for p in METADATA.peripherals {
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 80eaecc14..3822d5032 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -5,7 +5,7 @@ use core::task::Poll;
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6 6
7use super::blocking_delay_us; 7use super::blocking_delay_us;
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{interrupt, Peripheral}; 10use crate::{interrupt, Peripheral};
11 11
@@ -32,16 +32,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
32} 32}
33 33
34pub struct Vref; 34pub struct Vref;
35impl<T: Instance> AdcPin<T> for Vref {} 35impl<T: Instance> AdcChannel<T> for Vref {}
36impl<T: Instance> super::SealedAdcPin<T> for Vref { 36impl<T: Instance> super::SealedAdcChannel<T> for Vref {
37 fn channel(&self) -> u8 { 37 fn channel(&self) -> u8 {
38 17 38 17
39 } 39 }
40} 40}
41 41
42pub struct Temperature; 42pub struct Temperature;
43impl<T: Instance> AdcPin<T> for Temperature {} 43impl<T: Instance> AdcChannel<T> for Temperature {}
44impl<T: Instance> super::SealedAdcPin<T> for Temperature { 44impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
45 fn channel(&self) -> u8 { 45 fn channel(&self) -> u8 {
46 16 46 16
47 } 47 }
@@ -135,8 +135,8 @@ impl<'d, T: Instance> Adc<'d, T> {
135 T::regs().dr().read().0 as u16 135 T::regs().dr().read().0 as u16
136 } 136 }
137 137
138 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 138 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
139 Self::set_channel_sample_time(pin.channel(), self.sample_time); 139 Self::set_channel_sample_time(channel.channel(), self.sample_time);
140 T::regs().cr1().modify(|reg| { 140 T::regs().cr1().modify(|reg| {
141 reg.set_scan(false); 141 reg.set_scan(false);
142 reg.set_discen(false); 142 reg.set_discen(false);
@@ -151,7 +151,7 @@ impl<'d, T: Instance> Adc<'d, T> {
151 }); 151 });
152 152
153 // Configure the channel to sample 153 // Configure the channel to sample
154 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); 154 T::regs().sqr3().write(|reg| reg.set_sq(0, channel.channel()));
155 self.convert().await 155 self.convert().await
156 } 156 }
157 157
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index c22a3fe4a..3f076d64b 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -5,7 +5,7 @@ use core::task::Poll;
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6 6
7use super::blocking_delay_us; 7use super::blocking_delay_us;
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::time::Hertz; 10use crate::time::Hertz;
11use crate::{interrupt, Peripheral}; 11use crate::{interrupt, Peripheral};
@@ -32,8 +32,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
32} 32}
33 33
34pub struct Vref; 34pub struct Vref;
35impl<T: Instance> AdcPin<T> for Vref {} 35impl<T: Instance> AdcChannel<T> for Vref {}
36impl<T: Instance> super::SealedAdcPin<T> for Vref { 36impl<T: Instance> super::SealedAdcChannel<T> for Vref {
37 fn channel(&self) -> u8 { 37 fn channel(&self) -> u8 {
38 18 38 18
39 } 39 }
@@ -47,8 +47,8 @@ impl Vref {
47} 47}
48 48
49pub struct Temperature; 49pub struct Temperature;
50impl<T: Instance> AdcPin<T> for Temperature {} 50impl<T: Instance> AdcChannel<T> for Temperature {}
51impl<T: Instance> super::SealedAdcPin<T> for Temperature { 51impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
52 fn channel(&self) -> u8 { 52 fn channel(&self) -> u8 {
53 16 53 16
54 } 54 }
@@ -154,11 +154,11 @@ impl<'d, T: Instance> Adc<'d, T> {
154 T::regs().dr().read().rdata() 154 T::regs().dr().read().rdata()
155 } 155 }
156 156
157 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 157 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
158 Self::set_channel_sample_time(pin.channel(), self.sample_time); 158 Self::set_channel_sample_time(channel.channel(), self.sample_time);
159 159
160 // Configure the channel to sample 160 // Configure the channel to sample
161 T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); 161 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel()));
162 self.convert().await 162 self.convert().await
163 } 163 }
164 164
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 672ace04f..106956989 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref;
7use embassy_time::Instant; 7use embassy_time::Instant;
8 8
9use super::Resolution; 9use super::Resolution;
10use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 10use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::time::Hertz; 12use crate::time::Hertz;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, Peripheral};
@@ -64,8 +64,8 @@ fn update_vref<T: Instance>(op: i8) {
64} 64}
65 65
66pub struct Vref<T: Instance>(core::marker::PhantomData<T>); 66pub struct Vref<T: Instance>(core::marker::PhantomData<T>);
67impl<T: Instance> AdcPin<T> for Vref<T> {} 67impl<T: Instance> AdcChannel<T> for Vref<T> {}
68impl<T: Instance> super::SealedAdcPin<T> for Vref<T> { 68impl<T: Instance> super::SealedAdcChannel<T> for Vref<T> {
69 fn channel(&self) -> u8 { 69 fn channel(&self) -> u8 {
70 17 70 17
71 } 71 }
@@ -123,8 +123,8 @@ impl<T: Instance> Drop for Vref<T> {
123} 123}
124 124
125pub struct Temperature<T: Instance>(core::marker::PhantomData<T>); 125pub struct Temperature<T: Instance>(core::marker::PhantomData<T>);
126impl<T: Instance> AdcPin<T> for Temperature<T> {} 126impl<T: Instance> AdcChannel<T> for Temperature<T> {}
127impl<T: Instance> super::SealedAdcPin<T> for Temperature<T> { 127impl<T: Instance> super::SealedAdcChannel<T> for Temperature<T> {
128 fn channel(&self) -> u8 { 128 fn channel(&self) -> u8 {
129 16 129 16
130 } 130 }
@@ -271,8 +271,8 @@ impl<'d, T: Instance> Adc<'d, T> {
271 } 271 }
272 } 272 }
273 273
274 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 274 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
275 self.set_sample_sequence(&[pin.channel()]).await; 275 self.set_sample_sequence(&[channel.channel()]).await;
276 self.convert().await 276 self.convert().await
277 } 277 }
278 278
@@ -283,18 +283,18 @@ impl<'d, T: Instance> Adc<'d, T> {
283 } 283 }
284 } 284 }
285 285
286 pub async fn set_sample_time(&mut self, pin: &mut impl AdcPin<T>, sample_time: SampleTime) { 286 pub async fn set_sample_time(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
287 if Self::get_channel_sample_time(pin.channel()) != sample_time { 287 if Self::get_channel_sample_time(channel.channel()) != sample_time {
288 self.stop_adc().await; 288 self.stop_adc().await;
289 unsafe { 289 unsafe {
290 Self::set_channel_sample_time(pin.channel(), sample_time); 290 Self::set_channel_sample_time(channel.channel(), sample_time);
291 } 291 }
292 self.start_adc().await; 292 self.start_adc().await;
293 } 293 }
294 } 294 }
295 295
296 pub fn get_sample_time(&self, pin: &impl AdcPin<T>) -> SampleTime { 296 pub fn get_sample_time(&self, channel: &impl AdcChannel<T>) -> SampleTime {
297 Self::get_channel_sample_time(pin.channel()) 297 Self::get_channel_sample_time(channel.channel())
298 } 298 }
299 299
300 /// Sets the channel sample time 300 /// Sets the channel sample time
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 221cc2a40..ce7f5db70 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -2,7 +2,7 @@
2use pac::adc::vals::{Adcaldif, Difsel, Exten}; 2use pac::adc::vals::{Adcaldif, Difsel, Exten};
3use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4 4
5use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::{pac, Peripheral}; 7use crate::{pac, Peripheral};
8 8
@@ -33,8 +33,8 @@ const VBAT_CHANNEL: u8 = 17;
33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
34/// Internal voltage reference channel. 34/// Internal voltage reference channel.
35pub struct VrefInt; 35pub struct VrefInt;
36impl<T: Instance> InternalChannel<T> for VrefInt {} 36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> super::SealedInternalChannel<T> for VrefInt { 37impl<T: Instance> super::SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 { 38 fn channel(&self) -> u8 {
39 VREF_CHANNEL 39 VREF_CHANNEL
40 } 40 }
@@ -42,8 +42,8 @@ impl<T: Instance> super::SealedInternalChannel<T> for VrefInt {
42 42
43/// Internal temperature channel. 43/// Internal temperature channel.
44pub struct Temperature; 44pub struct Temperature;
45impl<T: Instance> InternalChannel<T> for Temperature {} 45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> super::SealedInternalChannel<T> for Temperature { 46impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 { 47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL 48 TEMP_CHANNEL
49 } 49 }
@@ -51,8 +51,8 @@ impl<T: Instance> super::SealedInternalChannel<T> for Temperature {
51 51
52/// Internal battery voltage channel. 52/// Internal battery voltage channel.
53pub struct Vbat; 53pub struct Vbat;
54impl<T: Instance> InternalChannel<T> for Vbat {} 54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> super::SealedInternalChannel<T> for Vbat { 55impl<T: Instance> super::SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 { 56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL 57 VBAT_CHANNEL
58 } 58 }
@@ -258,18 +258,9 @@ impl<'d, T: Instance> Adc<'d, T> {
258 } 258 }
259 259
260 /// Read an ADC pin. 260 /// Read an ADC pin.
261 pub fn read<P>(&mut self, pin: &mut P) -> u16 261 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
262 where 262 channel.setup();
263 P: AdcPin<T>,
264 P: crate::gpio::Pin,
265 {
266 pin.set_as_analog();
267
268 self.read_channel(pin.channel())
269 }
270 263
271 /// Read an ADC internal channel.
272 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
273 self.read_channel(channel.channel()) 264 self.read_channel(channel.channel())
274 } 265 }
275 266
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index c753d046c..040ee9c53 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -15,6 +15,8 @@
15#[cfg_attr(adc_g4, path = "g4.rs")] 15#[cfg_attr(adc_g4, path = "g4.rs")]
16mod _version; 16mod _version;
17 17
18use core::marker::PhantomData;
19
18#[allow(unused)] 20#[allow(unused)]
19#[cfg(not(adc_f3_v2))] 21#[cfg(not(adc_f3_v2))]
20pub use _version::*; 22pub use _version::*;
@@ -58,15 +60,10 @@ trait SealedInstance {
58 fn state() -> &'static State; 60 fn state() -> &'static State;
59} 61}
60 62
61pub(crate) trait SealedAdcPin<T: Instance> { 63pub(crate) trait SealedAdcChannel<T> {
62 #[cfg(any(adc_v1, adc_l0, adc_v2))] 64 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))]
63 fn set_as_analog(&mut self) {} 65 fn setup(&mut self) {}
64
65 #[allow(unused)]
66 fn channel(&self) -> u8;
67}
68 66
69trait SealedInternalChannel<T> {
70 #[allow(unused)] 67 #[allow(unused)]
71 fn channel(&self) -> u8; 68 fn channel(&self) -> u8;
72} 69}
@@ -124,12 +121,36 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::R
124 type Interrupt: crate::interrupt::typelevel::Interrupt; 121 type Interrupt: crate::interrupt::typelevel::Interrupt;
125} 122}
126 123
127/// ADC pin. 124/// ADC channel.
128#[allow(private_bounds)]
129pub trait AdcPin<T: Instance>: SealedAdcPin<T> {}
130/// ADC internal channel.
131#[allow(private_bounds)] 125#[allow(private_bounds)]
132pub trait InternalChannel<T>: SealedInternalChannel<T> {} 126pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
127 #[allow(unused_mut)]
128 fn degrade_adc(mut self) -> AnyAdcChannel<T> {
129 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))]
130 self.setup();
131
132 AnyAdcChannel {
133 channel: self.channel(),
134 _phantom: PhantomData,
135 }
136 }
137}
138
139/// A type-erased channel for a given ADC instance.
140///
141/// This is useful in scenarios where you need the ADC channels to have the same type, such as
142/// storing them in an array.
143pub struct AnyAdcChannel<T> {
144 channel: u8,
145 _phantom: PhantomData<T>,
146}
147
148impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {}
149impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
150 fn channel(&self) -> u8 {
151 self.channel
152 }
153}
133 154
134foreach_adc!( 155foreach_adc!(
135 ($inst:ident, $common_inst:ident, $clock:ident) => { 156 ($inst:ident, $common_inst:ident, $clock:ident) => {
@@ -158,11 +179,10 @@ foreach_adc!(
158 179
159macro_rules! impl_adc_pin { 180macro_rules! impl_adc_pin {
160 ($inst:ident, $pin:ident, $ch:expr) => { 181 ($inst:ident, $pin:ident, $ch:expr) => {
161 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} 182 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {}
162 183 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin {
163 impl crate::adc::SealedAdcPin<peripherals::$inst> for crate::peripherals::$pin { 184 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))]
164 #[cfg(any(adc_v1, adc_l0, adc_v2))] 185 fn setup(&mut self) {
165 fn set_as_analog(&mut self) {
166 <Self as crate::gpio::SealedPin>::set_as_analog(self); 186 <Self as crate::gpio::SealedPin>::set_as_analog(self);
167 } 187 }
168 188
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index f17522076..090790c39 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref;
7use stm32_metapac::adc::vals::Ckmode; 7use stm32_metapac::adc::vals::Ckmode;
8 8
9use super::blocking_delay_us; 9use super::blocking_delay_us;
10use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 10use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::peripherals::ADC1; 12use crate::peripherals::ADC1;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, Peripheral};
@@ -36,26 +36,26 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
36pub struct Vbat; 36pub struct Vbat;
37 37
38#[cfg(not(adc_l0))] 38#[cfg(not(adc_l0))]
39impl AdcPin<ADC1> for Vbat {} 39impl AdcChannel<ADC1> for Vbat {}
40 40
41#[cfg(not(adc_l0))] 41#[cfg(not(adc_l0))]
42impl super::SealedAdcPin<ADC1> for Vbat { 42impl super::SealedAdcChannel<ADC1> for Vbat {
43 fn channel(&self) -> u8 { 43 fn channel(&self) -> u8 {
44 18 44 18
45 } 45 }
46} 46}
47 47
48pub struct Vref; 48pub struct Vref;
49impl AdcPin<ADC1> for Vref {} 49impl AdcChannel<ADC1> for Vref {}
50impl super::SealedAdcPin<ADC1> for Vref { 50impl super::SealedAdcChannel<ADC1> for Vref {
51 fn channel(&self) -> u8 { 51 fn channel(&self) -> u8 {
52 17 52 17
53 } 53 }
54} 54}
55 55
56pub struct Temperature; 56pub struct Temperature;
57impl AdcPin<ADC1> for Temperature {} 57impl AdcChannel<ADC1> for Temperature {}
58impl super::SealedAdcPin<ADC1> for Temperature { 58impl super::SealedAdcChannel<ADC1> for Temperature {
59 fn channel(&self) -> u8 { 59 fn channel(&self) -> u8 {
60 16 60 16
61 } 61 }
@@ -155,12 +155,12 @@ impl<'d, T: Instance> Adc<'d, T> {
155 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); 155 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
156 } 156 }
157 157
158 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 158 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
159 let channel = pin.channel(); 159 let ch_num = channel.channel();
160 pin.set_as_analog(); 160 channel.setup();
161 161
162 // A.7.5 Single conversion sequence code example - Software trigger 162 // A.7.5 Single conversion sequence code example - Software trigger
163 T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); 163 T::regs().chselr().write(|reg| reg.set_chselx(ch_num as usize, true));
164 164
165 self.convert().await 165 self.convert().await
166 } 166 }
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 7771cf768..033108195 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,7 +1,7 @@
1use embassy_hal_internal::into_ref; 1use embassy_hal_internal::into_ref;
2 2
3use super::blocking_delay_us; 3use super::blocking_delay_us;
4use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
5use crate::peripherals::ADC1; 5use crate::peripherals::ADC1;
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::Peripheral; 7use crate::Peripheral;
@@ -12,8 +12,8 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
12pub const VREF_CALIB_MV: u32 = 3300; 12pub const VREF_CALIB_MV: u32 = 3300;
13 13
14pub struct VrefInt; 14pub struct VrefInt;
15impl AdcPin<ADC1> for VrefInt {} 15impl AdcChannel<ADC1> for VrefInt {}
16impl super::SealedAdcPin<ADC1> for VrefInt { 16impl super::SealedAdcChannel<ADC1> for VrefInt {
17 fn channel(&self) -> u8 { 17 fn channel(&self) -> u8 {
18 17 18 17
19 } 19 }
@@ -27,8 +27,8 @@ impl VrefInt {
27} 27}
28 28
29pub struct Temperature; 29pub struct Temperature;
30impl AdcPin<ADC1> for Temperature {} 30impl AdcChannel<ADC1> for Temperature {}
31impl super::SealedAdcPin<ADC1> for Temperature { 31impl super::SealedAdcChannel<ADC1> for Temperature {
32 fn channel(&self) -> u8 { 32 fn channel(&self) -> u8 {
33 cfg_if::cfg_if! { 33 cfg_if::cfg_if! {
34 if #[cfg(any(stm32f2, stm32f40, stm32f41))] { 34 if #[cfg(any(stm32f2, stm32f40, stm32f41))] {
@@ -48,8 +48,8 @@ impl Temperature {
48} 48}
49 49
50pub struct Vbat; 50pub struct Vbat;
51impl AdcPin<ADC1> for Vbat {} 51impl AdcChannel<ADC1> for Vbat {}
52impl super::SealedAdcPin<ADC1> for Vbat { 52impl super::SealedAdcChannel<ADC1> for Vbat {
53 fn channel(&self) -> u8 { 53 fn channel(&self) -> u8 {
54 18 54 18
55 } 55 }
@@ -175,11 +175,11 @@ where
175 T::regs().dr().read().0 as u16 175 T::regs().dr().read().0 as u16
176 } 176 }
177 177
178 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 178 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
179 pin.set_as_analog(); 179 channel.setup();
180 180
181 // Configure ADC 181 // Configure ADC
182 let channel = pin.channel(); 182 let channel = channel.channel();
183 183
184 // Select channel 184 // Select channel
185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); 185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index dc418297e..be857f4dd 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -2,7 +2,7 @@ use cfg_if::cfg_if;
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use super::blocking_delay_us; 4use super::blocking_delay_us;
5use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 5use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::Peripheral; 6use crate::Peripheral;
7 7
8/// Default VREF voltage used for sample conversion to millivolts. 8/// Default VREF voltage used for sample conversion to millivolts.
@@ -11,8 +11,8 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
11pub const VREF_CALIB_MV: u32 = 3000; 11pub const VREF_CALIB_MV: u32 = 3000;
12 12
13pub struct VrefInt; 13pub struct VrefInt;
14impl<T: Instance> AdcPin<T> for VrefInt {} 14impl<T: Instance> AdcChannel<T> for VrefInt {}
15impl<T: Instance> super::SealedAdcPin<T> for VrefInt { 15impl<T: Instance> super::SealedAdcChannel<T> for VrefInt {
16 fn channel(&self) -> u8 { 16 fn channel(&self) -> u8 {
17 cfg_if! { 17 cfg_if! {
18 if #[cfg(adc_g0)] { 18 if #[cfg(adc_g0)] {
@@ -30,8 +30,8 @@ impl<T: Instance> super::SealedAdcPin<T> for VrefInt {
30} 30}
31 31
32pub struct Temperature; 32pub struct Temperature;
33impl<T: Instance> AdcPin<T> for Temperature {} 33impl<T: Instance> AdcChannel<T> for Temperature {}
34impl<T: Instance> super::SealedAdcPin<T> for Temperature { 34impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
35 fn channel(&self) -> u8 { 35 fn channel(&self) -> u8 {
36 cfg_if! { 36 cfg_if! {
37 if #[cfg(adc_g0)] { 37 if #[cfg(adc_g0)] {
@@ -49,8 +49,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature {
49} 49}
50 50
51pub struct Vbat; 51pub struct Vbat;
52impl<T: Instance> AdcPin<T> for Vbat {} 52impl<T: Instance> AdcChannel<T> for Vbat {}
53impl<T: Instance> super::SealedAdcPin<T> for Vbat { 53impl<T: Instance> super::SealedAdcChannel<T> for Vbat {
54 fn channel(&self) -> u8 { 54 fn channel(&self) -> u8 {
55 cfg_if! { 55 cfg_if! {
56 if #[cfg(adc_g0)] { 56 if #[cfg(adc_g0)] {
@@ -70,8 +70,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Vbat {
70cfg_if! { 70cfg_if! {
71 if #[cfg(adc_h5)] { 71 if #[cfg(adc_h5)] {
72 pub struct VddCore; 72 pub struct VddCore;
73 impl<T: Instance> AdcPin<T> for VddCore {} 73 impl<T: Instance> AdcChannel<T> for VddCore {}
74 impl<T: Instance> super::SealedAdcPin<T> for VddCore { 74 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
75 fn channel(&self) -> u8 { 75 fn channel(&self) -> u8 {
76 6 76 6
77 } 77 }
@@ -82,8 +82,8 @@ cfg_if! {
82cfg_if! { 82cfg_if! {
83 if #[cfg(adc_u0)] { 83 if #[cfg(adc_u0)] {
84 pub struct DacOut; 84 pub struct DacOut;
85 impl<T: Instance> AdcPin<T> for DacOut {} 85 impl<T: Instance> AdcChannel<T> for DacOut {}
86 impl<T: Instance> super::SealedAdcPin<T> for DacOut { 86 impl<T: Instance> super::SealedAdcChannel<T> for DacOut {
87 fn channel(&self) -> u8 { 87 fn channel(&self) -> u8 {
88 19 88 19
89 } 89 }
@@ -220,7 +220,7 @@ impl<'d, T: Instance> Adc<'d, T> {
220 T::regs().dr().read().0 as u16 220 T::regs().dr().read().0 as u16
221 } 221 }
222 222
223 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 223 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
224 // Make sure bits are off 224 // Make sure bits are off
225 while T::regs().cr().read().addis() { 225 while T::regs().cr().read().addis() {
226 // spin 226 // spin
@@ -241,18 +241,18 @@ impl<'d, T: Instance> Adc<'d, T> {
241 // RM0492, RM0481, etc. 241 // RM0492, RM0481, etc.
242 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 242 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
243 #[cfg(adc_h5)] 243 #[cfg(adc_h5)]
244 if pin.channel() == 0 { 244 if channel.channel() == 0 {
245 T::regs().or().modify(|reg| reg.set_op0(true)); 245 T::regs().or().modify(|reg| reg.set_op0(true));
246 } 246 }
247 247
248 // Configure channel 248 // Configure channel
249 Self::set_channel_sample_time(pin.channel(), self.sample_time); 249 Self::set_channel_sample_time(channel.channel(), self.sample_time);
250 250
251 // Select channel 251 // Select channel
252 #[cfg(not(any(adc_g0, adc_u0)))] 252 #[cfg(not(any(adc_g0, adc_u0)))]
253 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); 253 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel()));
254 #[cfg(any(adc_g0, adc_u0))] 254 #[cfg(any(adc_g0, adc_u0))]
255 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); 255 T::regs().chselr().write(|reg| reg.set_chsel(1 << channel.channel()));
256 256
257 // Some models are affected by an erratum: 257 // Some models are affected by an erratum:
258 // If we perform conversions slower than 1 kHz, the first read ADC value can be 258 // If we perform conversions slower than 1 kHz, the first read ADC value can be
@@ -270,7 +270,7 @@ impl<'d, T: Instance> Adc<'d, T> {
270 // RM0492, RM0481, etc. 270 // RM0492, RM0481, etc.
271 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 271 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
272 #[cfg(adc_h5)] 272 #[cfg(adc_h5)]
273 if pin.channel() == 0 { 273 if channel.channel() == 0 {
274 T::regs().or().modify(|reg| reg.set_op0(false)); 274 T::regs().or().modify(|reg| reg.set_op0(false));
275 } 275 }
276 276
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index ca87b41ee..f564114c2 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -2,7 +2,7 @@
2use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; 2use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
3use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4 4
5use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::{pac, Peripheral}; 7use crate::{pac, Peripheral};
8 8
@@ -33,8 +33,8 @@ const VBAT_CHANNEL: u8 = 17;
33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
34/// Internal voltage reference channel. 34/// Internal voltage reference channel.
35pub struct VrefInt; 35pub struct VrefInt;
36impl<T: Instance> InternalChannel<T> for VrefInt {} 36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> super::SealedInternalChannel<T> for VrefInt { 37impl<T: Instance> super::SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 { 38 fn channel(&self) -> u8 {
39 VREF_CHANNEL 39 VREF_CHANNEL
40 } 40 }
@@ -42,8 +42,8 @@ impl<T: Instance> super::SealedInternalChannel<T> for VrefInt {
42 42
43/// Internal temperature channel. 43/// Internal temperature channel.
44pub struct Temperature; 44pub struct Temperature;
45impl<T: Instance> InternalChannel<T> for Temperature {} 45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> super::SealedInternalChannel<T> for Temperature { 46impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 { 47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL 48 TEMP_CHANNEL
49 } 49 }
@@ -51,8 +51,8 @@ impl<T: Instance> super::SealedInternalChannel<T> for Temperature {
51 51
52/// Internal battery voltage channel. 52/// Internal battery voltage channel.
53pub struct Vbat; 53pub struct Vbat;
54impl<T: Instance> InternalChannel<T> for Vbat {} 54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> super::SealedInternalChannel<T> for Vbat { 55impl<T: Instance> super::SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 { 56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL 57 VBAT_CHANNEL
58 } 58 }
@@ -271,19 +271,10 @@ impl<'d, T: Instance> Adc<'d, T> {
271 T::regs().dr().read().0 as u16 271 T::regs().dr().read().0 as u16
272 } 272 }
273 273
274 /// Read an ADC pin. 274 /// Read an ADC channel.
275 pub fn read<P>(&mut self, pin: &mut P) -> u16 275 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
276 where 276 channel.setup();
277 P: AdcPin<T>,
278 P: crate::gpio::Pin,
279 {
280 pin.set_as_analog();
281 277
282 self.read_channel(pin.channel())
283 }
284
285 /// Read an ADC internal channel.
286 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
287 self.read_channel(channel.channel()) 278 self.read_channel(channel.channel())
288 } 279 }
289 280
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
new file mode 100644
index 000000000..f1c737fdc
--- /dev/null
+++ b/embassy-stm32/src/dsihost.rs
@@ -0,0 +1,429 @@
1//! DSI HOST
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6
7//use crate::gpio::{AnyPin, SealedPin};
8use crate::gpio::{AFType, AnyPin, Pull, Speed};
9use crate::rcc::RccPeripheral;
10use crate::{peripherals, Peripheral};
11
12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(time)]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms));
16 #[cfg(not(time))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms);
18}
19
20/// PacketTypes extracted from CubeMX
21#[repr(u8)]
22#[allow(dead_code)]
23pub enum PacketType {
24 /// DCS short write, no parameters
25 DcsShortPktWriteP0,
26 /// DCS short write, one parameter
27 DcsShortPktWriteP1,
28 /// Generic short write, no parameters
29 GenShortPktWriteP0,
30 /// Generic short write, one parameter
31 GenShortPktWriteP1,
32 /// Generic short write, two parameters
33 GenShortPktWriteP2,
34 /// DCS long write
35 DcsLongPktWrite,
36 /// Generic long write
37 GenLongPktWrite,
38 /// DCS short read
39 DcsShortPktRead(u8),
40 /// Generic short read, no parameters
41 GenShortPktReadP0,
42 /// Generic short read, one parameter
43 GenShortPktReadP1(u8),
44 /// Generic short read, two parameters
45 GenShortPktReadP2(u8, u8),
46 /// Used to set the maximum return packet size for reading data
47 MaxReturnPktSize,
48}
49
50impl From<PacketType> for u8 {
51 fn from(packet_type: PacketType) -> u8 {
52 match packet_type {
53 PacketType::DcsShortPktWriteP0 => 0x05,
54 PacketType::DcsShortPktWriteP1 => 0x15,
55 PacketType::GenShortPktWriteP0 => 0x03,
56 PacketType::GenShortPktWriteP1 => 0x13,
57 PacketType::GenShortPktWriteP2 => 0x23,
58 PacketType::DcsLongPktWrite => 0x39,
59 PacketType::GenLongPktWrite => 0x29,
60 PacketType::DcsShortPktRead(_) => 0x06,
61 PacketType::GenShortPktReadP0 => 0x04,
62 PacketType::GenShortPktReadP1(_) => 0x14,
63 PacketType::GenShortPktReadP2(_, _) => 0x24,
64 PacketType::MaxReturnPktSize => 0x37,
65 }
66 }
67}
68
69/// DSIHOST driver.
70pub struct DsiHost<'d, T: Instance> {
71 _peri: PhantomData<&'d mut T>,
72 _te: PeripheralRef<'d, AnyPin>,
73}
74
75impl<'d, T: Instance> DsiHost<'d, T> {
76 /// Note: Full-Duplex modes are not supported at this time
77 pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self {
78 into_ref!(te);
79
80 T::enable_and_reset();
81
82 // Set Tearing Enable pin according to CubeMx example
83 te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None);
84 te.set_speed(Speed::Low);
85 /*
86 T::regs().wcr().modify(|w| {
87 w.set_dsien(true);
88 });
89 */
90 Self {
91 _peri: PhantomData,
92 _te: te.map_into(),
93 }
94 }
95
96 /// Get the DSIHOST hardware version. Found in the reference manual for comparison.
97 pub fn get_version(&self) -> u32 {
98 T::regs().vr().read().version()
99 }
100
101 /// Set the enable bit in the control register and assert that it has been enabled
102 pub fn enable(&mut self) {
103 T::regs().cr().modify(|w| w.set_en(true));
104 assert!(T::regs().cr().read().en())
105 }
106
107 /// Unset the enable bit in the control register and assert that it has been disabled
108 pub fn disable(&mut self) {
109 T::regs().cr().modify(|w| w.set_en(false));
110 assert!(!T::regs().cr().read().en())
111 }
112
113 /// Set the DSI enable bit in the wrapper control register and assert that it has been enabled
114 pub fn enable_wrapper_dsi(&mut self) {
115 T::regs().wcr().modify(|w| w.set_dsien(true));
116 assert!(T::regs().wcr().read().dsien())
117 }
118
119 /// Unset the DSI enable bit in the wrapper control register and assert that it has been disabled
120 pub fn disable_wrapper_dsi(&mut self) {
121 T::regs().wcr().modify(|w| w.set_dsien(false));
122 assert!(!T::regs().wcr().read().dsien())
123 }
124
125 /// DCS or Generic short/long write command
126 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
127 assert!(data.len() > 0);
128
129 if data.len() == 1 {
130 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0])
131 } else {
132 self.long_write(
133 channel_id,
134 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
135 address,
136 data,
137 )
138 }
139 }
140
141 fn short_write(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) -> Result<(), Error> {
142 #[cfg(feature = "defmt")]
143 defmt::debug!("short_write: BEGIN wait for command fifo empty");
144
145 // Wait for Command FIFO empty
146 self.wait_command_fifo_empty()?;
147 #[cfg(feature = "defmt")]
148 defmt::debug!("short_write: END wait for command fifo empty");
149
150 // Configure the packet to send a short DCS command with 0 or 1 parameters
151 // Update the DSI packet header with new information
152 self.config_packet_header(channel_id, packet_type, param1, param2);
153
154 self.wait_command_fifo_empty()?;
155
156 let status = T::regs().isr1().read().0;
157 if status != 0 {
158 error!("ISR1 after short_write(): {:b}", status);
159 }
160 Ok(())
161 }
162
163 fn config_packet_header(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) {
164 T::regs().ghcr().write(|w| {
165 w.set_dt(packet_type.into());
166 w.set_vcid(channel_id);
167 w.set_wclsb(param1);
168 w.set_wcmsb(param2);
169 });
170 }
171
172 /// Write long DCS or long Generic command.
173 ///
174 /// `params` is expected to contain at least 2 elements. Use [`short_write`] for a single element.
175 fn long_write(&mut self, channel_id: u8, packet_type: PacketType, address: u8, data: &[u8]) -> Result<(), Error> {
176 // Must be a long packet if we do the long write, obviously.
177 assert!(matches!(
178 packet_type,
179 PacketType::DcsLongPktWrite | PacketType::GenLongPktWrite
180 ));
181
182 // params needs to have at least 2 elements, otherwise short_write should be used
183 assert!(data.len() >= 2);
184
185 #[cfg(feature = "defmt")]
186 defmt::debug!("long_write: BEGIN wait for command fifo empty");
187
188 self.wait_command_fifo_empty()?;
189
190 #[cfg(feature = "defmt")]
191 defmt::debug!("long_write: DONE wait for command fifo empty");
192
193 // Note: CubeMX example "NbParams" is always one LESS than params.len()
194 // DCS code (last element of params) must be on payload byte 1 and if we have only 2 more params,
195 // then they must go into data2 and data3
196 T::regs().gpdr().write(|w| {
197 // data[2] may or may not exist.
198 if let Some(x) = data.get(2) {
199 w.set_data4(*x);
200 }
201 // data[0] and [1] have to exist if long_write is called.
202 w.set_data3(data[1]);
203 w.set_data2(data[0]);
204
205 // DCS Code
206 w.set_data1(address);
207 });
208
209 self.wait_command_fifo_empty()?;
210
211 // These steps are only necessary if more than 1x 4 bytes need to go into the FIFO
212 if data.len() >= 4 {
213 // Generate an iterator that iterates over chunks of exactly 4 bytes
214 let iter = data[3..data.len()].chunks_exact(4);
215 // Obtain remainder before consuming iter
216 let remainder = iter.remainder();
217
218 // Keep filling the buffer with remaining data
219 for param in iter {
220 self.wait_command_fifo_not_full()?;
221 T::regs().gpdr().write(|w| {
222 w.set_data4(param[3]);
223 w.set_data3(param[2]);
224 w.set_data2(param[1]);
225 w.set_data1(param[0]);
226 });
227
228 self.wait_command_fifo_empty().unwrap();
229 }
230
231 // If the remaining data was not devisible by 4 we get a remainder
232 if remainder.len() >= 1 {
233 self.wait_command_fifo_not_full()?;
234 T::regs().gpdr().write(|w| {
235 if let Some(x) = remainder.get(2) {
236 w.set_data3(*x);
237 }
238 if let Some(x) = remainder.get(1) {
239 w.set_data2(*x);
240 }
241 w.set_data1(remainder[0]);
242 });
243 self.wait_command_fifo_empty().unwrap();
244 }
245 }
246 // Configure the packet to send a long DCS command
247 self.config_packet_header(
248 channel_id,
249 packet_type,
250 ((data.len() + 1) & 0x00FF) as u8, // +1 to account for address byte
251 (((data.len() + 1) & 0xFF00) >> 8) as u8, // +1 to account for address byte
252 );
253
254 self.wait_command_fifo_empty()?;
255
256 let status = T::regs().isr1().read().0;
257 if status != 0 {
258 error!("ISR1 after long_write(): {:b}", status);
259 }
260 Ok(())
261 }
262
263 /// Read DSI Register
264 pub fn read(
265 &mut self,
266 channel_id: u8,
267 packet_type: PacketType,
268 read_size: u16,
269 data: &mut [u8],
270 ) -> Result<(), Error> {
271 if data.len() != read_size as usize {
272 return Err(Error::InvalidReadSize);
273 }
274
275 // Set the maximum return packet size
276 self.short_write(
277 channel_id,
278 PacketType::MaxReturnPktSize,
279 (read_size & 0xFF) as u8,
280 ((read_size & 0xFF00) >> 8) as u8,
281 )?;
282
283 // Set the packet header according to the packet_type
284 use PacketType::*;
285 match packet_type {
286 DcsShortPktRead(cmd) => self.config_packet_header(channel_id, packet_type, cmd, 0),
287 GenShortPktReadP0 => self.config_packet_header(channel_id, packet_type, 0, 0),
288 GenShortPktReadP1(param1) => self.config_packet_header(channel_id, packet_type, param1, 0),
289 GenShortPktReadP2(param1, param2) => self.config_packet_header(channel_id, packet_type, param1, param2),
290 _ => return Err(Error::InvalidPacketType),
291 }
292
293 self.wait_read_not_busy()?;
294
295 // Obtain chunks of 32-bit so the entire FIFO data register can be read
296 for bytes in data.chunks_exact_mut(4) {
297 self.wait_payload_read_fifo_not_empty()?;
298
299 // Only perform a single read on the entire register to avoid unintended side-effects
300 let gpdr = T::regs().gpdr().read();
301 bytes[0] = gpdr.data1();
302 bytes[1] = gpdr.data2();
303 bytes[2] = gpdr.data3();
304 bytes[3] = gpdr.data4();
305 }
306
307 // Collect the remaining chunks and read the corresponding number of bytes from the FIFO
308 let remainder = data.chunks_exact_mut(4).into_remainder();
309 if !remainder.is_empty() {
310 self.wait_payload_read_fifo_not_empty()?;
311 // Only perform a single read on the entire register to avoid unintended side-effects
312 let gpdr = T::regs().gpdr().read();
313 if let Some(x) = remainder.get_mut(0) {
314 *x = gpdr.data1()
315 }
316 if let Some(x) = remainder.get_mut(1) {
317 *x = gpdr.data2()
318 }
319 if let Some(x) = remainder.get_mut(2) {
320 *x = gpdr.data3()
321 }
322 }
323
324 /*
325 // Used this to check whether there are read errors. Does not seem like it.
326 if !self.read_busy() {
327 defmt::debug!("Read not busy!");
328 if self.packet_size_error() {
329 return Err(Error::ReadError);
330 }
331 }
332 */
333 Ok(())
334 }
335
336 fn wait_command_fifo_empty(&self) -> Result<(), Error> {
337 for _ in 1..1000 {
338 // Wait for Command FIFO empty
339 if T::regs().gpsr().read().cmdfe() {
340 return Ok(());
341 }
342 blocking_delay_ms(1);
343 }
344 Err(Error::FifoTimeout)
345 }
346
347 fn wait_command_fifo_not_full(&self) -> Result<(), Error> {
348 for _ in 1..1000 {
349 // Wait for Command FIFO not empty
350 if !T::regs().gpsr().read().cmdff() {
351 return Ok(());
352 }
353 blocking_delay_ms(1);
354 }
355 Err(Error::FifoTimeout)
356 }
357
358 fn wait_read_not_busy(&self) -> Result<(), Error> {
359 for _ in 1..1000 {
360 // Wait for read not busy
361 if !self.read_busy() {
362 return Ok(());
363 }
364 blocking_delay_ms(1);
365 }
366 Err(Error::ReadTimeout)
367 }
368
369 fn wait_payload_read_fifo_not_empty(&self) -> Result<(), Error> {
370 for _ in 1..1000 {
371 // Wait for payload read FIFO not empty
372 if !T::regs().gpsr().read().prdfe() {
373 return Ok(());
374 }
375 blocking_delay_ms(1);
376 }
377 Err(Error::FifoTimeout)
378 }
379
380 fn _packet_size_error(&self) -> bool {
381 T::regs().isr1().read().pse()
382 }
383
384 fn read_busy(&self) -> bool {
385 T::regs().gpsr().read().rcb()
386 }
387}
388
389/// Possible Error Types for DSI HOST
390#[non_exhaustive]
391#[derive(Debug)]
392pub enum Error {
393 /// Waiting for FIFO empty flag timed out
394 FifoTimeout,
395 /// The specified `PacketType` is invalid for the selected operation
396 InvalidPacketType,
397 /// Provided read size does not match the read buffer length
398 InvalidReadSize,
399 /// Error during read
400 ReadError,
401 /// Read operation timed out
402 ReadTimeout,
403}
404
405impl<'d, T: Instance> Drop for DsiHost<'d, T> {
406 fn drop(&mut self) {}
407}
408
409trait SealedInstance: crate::rcc::SealedRccPeripheral {
410 fn regs() -> &'static crate::pac::dsihost::Dsihost;
411}
412
413/// DSI instance trait.
414#[allow(private_bounds)]
415pub trait Instance: SealedInstance + RccPeripheral + 'static {}
416
417pin_trait!(TePin, Instance);
418
419foreach_peripheral!(
420 (dsihost, $inst:ident) => {
421 impl crate::dsihost::SealedInstance for peripherals::$inst {
422 fn regs() -> &'static crate::pac::dsihost::Dsihost {
423 &crate::pac::$inst
424 }
425 }
426
427 impl crate::dsihost::Instance for peripherals::$inst {}
428 };
429);
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
new file mode 100644
index 000000000..b77a3415b
--- /dev/null
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -0,0 +1,182 @@
1//! Hardware Semaphore (HSEM)
2
3// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs.
4// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
5// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
6// which is not yet supported by this code.
7use embassy_hal_internal::{into_ref, PeripheralRef};
8
9use crate::rcc::RccPeripheral;
10use crate::{pac, Peripheral};
11
12/// HSEM error.
13#[derive(Debug)]
14pub enum HsemError {
15 /// Locking the semaphore failed.
16 LockFailed,
17}
18
19/// CPU core.
20/// The enum values are identical to the bus master IDs / core Ids defined for each
21/// chip family (i.e. stm32h747 see rm0399 table 95)
22#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
23#[repr(u8)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum CoreId {
26 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
27 /// Cortex-M7, core 1.
28 Core0 = 0x3,
29
30 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
31 /// Cortex-M4, core 2.
32 Core1 = 0x1,
33
34 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
35 /// Cortex-M4, core 1
36 Core0 = 0x4,
37
38 #[cfg(any(stm32wb, stm32wl))]
39 /// Cortex-M0+, core 2.
40 Core1 = 0x8,
41}
42
43/// Get the current core id
44/// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core.
45#[inline(always)]
46pub fn get_current_coreid() -> CoreId {
47 let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() };
48 match cpuid & 0x000000F0 {
49 #[cfg(any(stm32wb, stm32wl))]
50 0x0 => CoreId::Core1,
51
52 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
53 0x4 => CoreId::Core0,
54
55 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
56 0x4 => CoreId::Core1,
57
58 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
59 0x7 => CoreId::Core0,
60 _ => panic!("Unknown Cortex-M core"),
61 }
62}
63
64/// Translates the core ID to an index into the interrupt registers.
65#[inline(always)]
66fn core_id_to_index(core: CoreId) -> usize {
67 match core {
68 CoreId::Core0 => 0,
69 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))]
70 CoreId::Core1 => 1,
71 }
72}
73
74/// HSEM driver
75pub struct HardwareSemaphore<'d, T: Instance> {
76 _peri: PeripheralRef<'d, T>,
77}
78
79impl<'d, T: Instance> HardwareSemaphore<'d, T> {
80 /// Creates a new HardwareSemaphore instance.
81 pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self {
82 into_ref!(peripheral);
83 HardwareSemaphore { _peri: peripheral }
84 }
85
86 /// Locks the semaphore.
87 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
88 /// check if the lock has been successful, carried out from the HSEM_Rx register.
89 pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> {
90 T::regs().r(sem_id as usize).write(|w| {
91 w.set_procid(process_id);
92 w.set_coreid(get_current_coreid() as u8);
93 w.set_lock(true);
94 });
95 let reg = T::regs().r(sem_id as usize).read();
96 match (
97 reg.lock(),
98 reg.coreid() == get_current_coreid() as u8,
99 reg.procid() == process_id,
100 ) {
101 (true, true, true) => Ok(()),
102 _ => Err(HsemError::LockFailed),
103 }
104 }
105
106 /// Locks the semaphore.
107 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step,
108 /// carried out from the HSEM_RLRx register.
109 pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> {
110 let reg = T::regs().rlr(sem_id as usize).read();
111 match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) {
112 (false, true, 0) => Ok(()),
113 _ => Err(HsemError::LockFailed),
114 }
115 }
116
117 /// Unlocks the semaphore.
118 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus
119 /// core ID or by a process not having the semaphore lock right.
120 pub fn unlock(&mut self, sem_id: u8, process_id: u8) {
121 T::regs().r(sem_id as usize).write(|w| {
122 w.set_procid(process_id);
123 w.set_coreid(get_current_coreid() as u8);
124 w.set_lock(false);
125 });
126 }
127
128 /// Unlocks all semaphores.
129 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR
130 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a
131 /// matching COREID are unlocked, and may generate an interrupt when enabled.
132 pub fn unlock_all(&mut self, key: u16, core_id: u8) {
133 T::regs().cr().write(|w| {
134 w.set_key(key);
135 w.set_coreid(core_id);
136 });
137 }
138
139 /// Checks if the semaphore is locked.
140 pub fn is_semaphore_locked(&self, sem_id: u8) -> bool {
141 T::regs().r(sem_id as usize).read().lock()
142 }
143
144 /// Sets the clear (unlock) key
145 pub fn set_clear_key(&mut self, key: u16) {
146 T::regs().keyr().modify(|w| w.set_key(key));
147 }
148
149 /// Gets the clear (unlock) key
150 pub fn get_clear_key(&mut self) -> u16 {
151 T::regs().keyr().read().key()
152 }
153
154 /// Sets the interrupt enable bit for the semaphore.
155 pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) {
156 T::regs()
157 .ier(core_id_to_index(core_id))
158 .modify(|w| w.set_ise(sem_x, enable));
159 }
160
161 /// Clears the interrupt flag for the semaphore.
162 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) {
163 T::regs()
164 .icr(core_id_to_index(core_id))
165 .write(|w| w.set_isc(sem_x, false));
166 }
167}
168
169trait SealedInstance {
170 fn regs() -> pac::hsem::Hsem;
171}
172
173/// HSEM instance trait.
174#[allow(private_bounds)]
175pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {}
176
177impl SealedInstance for crate::peripherals::HSEM {
178 fn regs() -> crate::pac::hsem::Hsem {
179 crate::pac::HSEM
180 }
181}
182impl Instance for crate::peripherals::HSEM {}
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 0b2a56305..ef5fd0972 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -9,7 +9,7 @@ use core::future::Future;
9use core::iter; 9use core::iter;
10use core::marker::PhantomData; 10use core::marker::PhantomData;
11 11
12use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 12use embassy_hal_internal::{into_ref, Peripheral};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14#[cfg(feature = "time")] 14#[cfg(feature = "time")]
15use embassy_time::{Duration, Instant}; 15use embassy_time::{Duration, Instant};
@@ -18,6 +18,7 @@ use crate::dma::ChannelAndRequest;
18use crate::gpio::{AFType, Pull}; 18use crate::gpio::{AFType, Pull};
19use crate::interrupt::typelevel::Interrupt; 19use crate::interrupt::typelevel::Interrupt;
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
21use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
21use crate::time::Hertz; 22use crate::time::Hertz;
22use crate::{interrupt, peripherals}; 23use crate::{interrupt, peripherals};
23 24
@@ -72,8 +73,10 @@ impl Default for Config {
72} 73}
73 74
74/// I2C driver. 75/// I2C driver.
75pub struct I2c<'d, T: Instance, M: Mode> { 76pub struct I2c<'d, M: Mode> {
76 _peri: PeripheralRef<'d, T>, 77 info: &'static Info,
78 state: &'static State,
79 kernel_clock: Hertz,
77 tx_dma: Option<ChannelAndRequest<'d>>, 80 tx_dma: Option<ChannelAndRequest<'d>>,
78 rx_dma: Option<ChannelAndRequest<'d>>, 81 rx_dma: Option<ChannelAndRequest<'d>>,
79 #[cfg(feature = "time")] 82 #[cfg(feature = "time")]
@@ -81,9 +84,9 @@ pub struct I2c<'d, T: Instance, M: Mode> {
81 _phantom: PhantomData<M>, 84 _phantom: PhantomData<M>,
82} 85}
83 86
84impl<'d, T: Instance> I2c<'d, T, Async> { 87impl<'d> I2c<'d, Async> {
85 /// Create a new I2C driver. 88 /// Create a new I2C driver.
86 pub fn new( 89 pub fn new<T: Instance>(
87 peri: impl Peripheral<P = T> + 'd, 90 peri: impl Peripheral<P = T> + 'd,
88 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 91 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
89 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 92 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
@@ -99,9 +102,9 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
99 } 102 }
100} 103}
101 104
102impl<'d, T: Instance> I2c<'d, T, Blocking> { 105impl<'d> I2c<'d, Blocking> {
103 /// Create a new blocking I2C driver. 106 /// Create a new blocking I2C driver.
104 pub fn new_blocking( 107 pub fn new_blocking<T: Instance>(
105 peri: impl Peripheral<P = T> + 'd, 108 peri: impl Peripheral<P = T> + 'd,
106 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 109 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
107 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 110 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
@@ -112,10 +115,10 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> {
112 } 115 }
113} 116}
114 117
115impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { 118impl<'d, M: Mode> I2c<'d, M> {
116 /// Create a new I2C driver. 119 /// Create a new I2C driver.
117 fn new_inner( 120 fn new_inner<T: Instance>(
118 peri: impl Peripheral<P = T> + 'd, 121 _peri: impl Peripheral<P = T> + 'd,
119 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 122 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
120 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 123 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
121 tx_dma: Option<ChannelAndRequest<'d>>, 124 tx_dma: Option<ChannelAndRequest<'d>>,
@@ -123,7 +126,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
123 freq: Hertz, 126 freq: Hertz,
124 config: Config, 127 config: Config,
125 ) -> Self { 128 ) -> Self {
126 into_ref!(peri, scl, sda); 129 into_ref!(scl, sda);
127 130
128 T::enable_and_reset(); 131 T::enable_and_reset();
129 132
@@ -148,7 +151,9 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
148 unsafe { T::ErrorInterrupt::enable() }; 151 unsafe { T::ErrorInterrupt::enable() };
149 152
150 let mut this = Self { 153 let mut this = Self {
151 _peri: peri, 154 info: T::info(),
155 state: T::state(),
156 kernel_clock: T::frequency(),
152 tx_dma, 157 tx_dma,
153 rx_dma, 158 rx_dma,
154 #[cfg(feature = "time")] 159 #[cfg(feature = "time")]
@@ -217,19 +222,14 @@ impl State {
217 } 222 }
218} 223}
219 224
220trait SealedInstance: crate::rcc::RccPeripheral { 225struct Info {
221 fn regs() -> crate::pac::i2c::I2c; 226 regs: crate::pac::i2c::I2c,
222 fn state() -> &'static State; 227 pub(crate) enable_bit: ClockEnableBit,
223} 228}
224 229
225/// I2C peripheral instance 230peri_trait!(
226#[allow(private_bounds)] 231 irqs: [EventInterrupt, ErrorInterrupt],
227pub trait Instance: SealedInstance + 'static { 232);
228 /// Event interrupt for this instance
229 type EventInterrupt: interrupt::typelevel::Interrupt;
230 /// Error interrupt for this instance
231 type ErrorInterrupt: interrupt::typelevel::Interrupt;
232}
233 233
234pin_trait!(SclPin, Instance); 234pin_trait!(SclPin, Instance);
235pin_trait!(SdaPin, Instance); 235pin_trait!(SdaPin, Instance);
@@ -260,11 +260,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInte
260 260
261foreach_peripheral!( 261foreach_peripheral!(
262 (i2c, $inst:ident) => { 262 (i2c, $inst:ident) => {
263 #[allow(private_interfaces)]
263 impl SealedInstance for peripherals::$inst { 264 impl SealedInstance for peripherals::$inst {
264 fn regs() -> crate::pac::i2c::I2c { 265 fn info() -> &'static Info {
265 crate::pac::$inst 266 static INFO: Info = Info{
267 regs: crate::pac::$inst,
268 enable_bit: crate::peripherals::$inst::ENABLE_BIT,
269 };
270 &INFO
266 } 271 }
267
268 fn state() -> &'static State { 272 fn state() -> &'static State {
269 static STATE: State = State::new(); 273 static STATE: State = State::new();
270 &STATE 274 &STATE
@@ -278,7 +282,7 @@ foreach_peripheral!(
278 }; 282 };
279); 283);
280 284
281impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { 285impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> {
282 type Error = Error; 286 type Error = Error;
283 287
284 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 288 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
@@ -286,7 +290,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d,
286 } 290 }
287} 291}
288 292
289impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { 293impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> {
290 type Error = Error; 294 type Error = Error;
291 295
292 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { 296 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
@@ -294,7 +298,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d,
294 } 298 }
295} 299}
296 300
297impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { 301impl<'d, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M> {
298 type Error = Error; 302 type Error = Error;
299 303
300 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { 304 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
@@ -318,11 +322,11 @@ impl embedded_hal_1::i2c::Error for Error {
318 } 322 }
319} 323}
320 324
321impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> { 325impl<'d, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, M> {
322 type Error = Error; 326 type Error = Error;
323} 327}
324 328
325impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { 329impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> {
326 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 330 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
327 self.blocking_read(address, read) 331 self.blocking_read(address, read)
328 } 332 }
@@ -344,7 +348,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
344 } 348 }
345} 349}
346 350
347impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> { 351impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> {
348 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 352 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
349 self.read(address, read).await 353 self.read(address, read).await
350 } 354 }
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index ac4fa1b9e..0269e53aa 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -28,7 +28,7 @@ use crate::pac::i2c;
28// There's some more details there, and we might have a fix for you. But please let us know if you 28// There's some more details there, and we might have a fix for you. But please let us know if you
29// hit a case like this! 29// hit a case like this!
30pub unsafe fn on_interrupt<T: Instance>() { 30pub unsafe fn on_interrupt<T: Instance>() {
31 let regs = T::regs(); 31 let regs = T::info().regs;
32 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 32 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
33 // other stuff, so we wake the task on every interrupt. 33 // other stuff, so we wake the task on every interrupt.
34 T::state().waker.wake(); 34 T::state().waker.wake();
@@ -41,9 +41,9 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> { 44impl<'d, M: PeriMode> I2c<'d, M> {
45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
46 T::regs().cr1().modify(|reg| { 46 self.info.regs.cr1().modify(|reg| {
47 reg.set_pe(false); 47 reg.set_pe(false);
48 //reg.set_anfoff(false); 48 //reg.set_anfoff(false);
49 }); 49 });
@@ -67,39 +67,39 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
67 // 67 //
68 // This presents as an ~infinite hang on read or write, as the START condition 68 // This presents as an ~infinite hang on read or write, as the START condition
69 // is never generated, meaning the start event is never generated. 69 // is never generated, meaning the start event is never generated.
70 T::regs().cr1().modify(|reg| { 70 self.info.regs.cr1().modify(|reg| {
71 reg.set_swrst(true); 71 reg.set_swrst(true);
72 }); 72 });
73 T::regs().cr1().modify(|reg| { 73 self.info.regs.cr1().modify(|reg| {
74 reg.set_swrst(false); 74 reg.set_swrst(false);
75 }); 75 });
76 76
77 let timings = Timings::new(T::frequency(), freq); 77 let timings = Timings::new(self.kernel_clock, freq);
78 78
79 T::regs().cr2().modify(|reg| { 79 self.info.regs.cr2().modify(|reg| {
80 reg.set_freq(timings.freq); 80 reg.set_freq(timings.freq);
81 }); 81 });
82 T::regs().ccr().modify(|reg| { 82 self.info.regs.ccr().modify(|reg| {
83 reg.set_f_s(timings.mode.f_s()); 83 reg.set_f_s(timings.mode.f_s());
84 reg.set_duty(timings.duty.duty()); 84 reg.set_duty(timings.duty.duty());
85 reg.set_ccr(timings.ccr); 85 reg.set_ccr(timings.ccr);
86 }); 86 });
87 T::regs().trise().modify(|reg| { 87 self.info.regs.trise().modify(|reg| {
88 reg.set_trise(timings.trise); 88 reg.set_trise(timings.trise);
89 }); 89 });
90 90
91 T::regs().cr1().modify(|reg| { 91 self.info.regs.cr1().modify(|reg| {
92 reg.set_pe(true); 92 reg.set_pe(true);
93 }); 93 });
94 } 94 }
95 95
96 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { 96 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
97 // Note that flags should only be cleared once they have been registered. If flags are 97 // Note that flags should only be cleared once they have been registered. If flags are
98 // cleared otherwise, there may be an inherent race condition and flags may be missed. 98 // cleared otherwise, there may be an inherent race condition and flags may be missed.
99 let sr1 = T::regs().sr1().read(); 99 let sr1 = info.regs.sr1().read();
100 100
101 if sr1.timeout() { 101 if sr1.timeout() {
102 T::regs().sr1().write(|reg| { 102 info.regs.sr1().write(|reg| {
103 reg.0 = !0; 103 reg.0 = !0;
104 reg.set_timeout(false); 104 reg.set_timeout(false);
105 }); 105 });
@@ -107,7 +107,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
107 } 107 }
108 108
109 if sr1.pecerr() { 109 if sr1.pecerr() {
110 T::regs().sr1().write(|reg| { 110 info.regs.sr1().write(|reg| {
111 reg.0 = !0; 111 reg.0 = !0;
112 reg.set_pecerr(false); 112 reg.set_pecerr(false);
113 }); 113 });
@@ -115,7 +115,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
115 } 115 }
116 116
117 if sr1.ovr() { 117 if sr1.ovr() {
118 T::regs().sr1().write(|reg| { 118 info.regs.sr1().write(|reg| {
119 reg.0 = !0; 119 reg.0 = !0;
120 reg.set_ovr(false); 120 reg.set_ovr(false);
121 }); 121 });
@@ -123,7 +123,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
123 } 123 }
124 124
125 if sr1.af() { 125 if sr1.af() {
126 T::regs().sr1().write(|reg| { 126 info.regs.sr1().write(|reg| {
127 reg.0 = !0; 127 reg.0 = !0;
128 reg.set_af(false); 128 reg.set_af(false);
129 }); 129 });
@@ -131,7 +131,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
131 } 131 }
132 132
133 if sr1.arlo() { 133 if sr1.arlo() {
134 T::regs().sr1().write(|reg| { 134 info.regs.sr1().write(|reg| {
135 reg.0 = !0; 135 reg.0 = !0;
136 reg.set_arlo(false); 136 reg.set_arlo(false);
137 }); 137 });
@@ -141,7 +141,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
141 // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and 141 // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and
142 // clearing the BERR bit instead. 142 // clearing the BERR bit instead.
143 if sr1.berr() { 143 if sr1.berr() {
144 T::regs().sr1().write(|reg| { 144 info.regs.sr1().write(|reg| {
145 reg.0 = !0; 145 reg.0 = !0;
146 reg.set_berr(false); 146 reg.set_berr(false);
147 }); 147 });
@@ -154,32 +154,32 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
154 if frame.send_start() { 154 if frame.send_start() {
155 // Send a START condition 155 // Send a START condition
156 156
157 T::regs().cr1().modify(|reg| { 157 self.info.regs.cr1().modify(|reg| {
158 reg.set_start(true); 158 reg.set_start(true);
159 }); 159 });
160 160
161 // Wait until START condition was generated 161 // Wait until START condition was generated
162 while !Self::check_and_clear_error_flags()?.start() { 162 while !Self::check_and_clear_error_flags(self.info)?.start() {
163 timeout.check()?; 163 timeout.check()?;
164 } 164 }
165 165
166 // Check if we were the ones to generate START 166 // Check if we were the ones to generate START
167 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { 167 if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
168 return Err(Error::Arbitration); 168 return Err(Error::Arbitration);
169 } 169 }
170 170
171 // Set up current address we're trying to talk to 171 // Set up current address we're trying to talk to
172 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 172 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1));
173 173
174 // Wait until address was sent 174 // Wait until address was sent
175 // Wait for the address to be acknowledged 175 // Wait for the address to be acknowledged
176 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 176 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
177 while !Self::check_and_clear_error_flags()?.addr() { 177 while !Self::check_and_clear_error_flags(self.info)?.addr() {
178 timeout.check()?; 178 timeout.check()?;
179 } 179 }
180 180
181 // Clear condition by reading SR2 181 // Clear condition by reading SR2
182 let _ = T::regs().sr2().read(); 182 let _ = self.info.regs.sr2().read();
183 } 183 }
184 184
185 // Send bytes 185 // Send bytes
@@ -189,7 +189,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
189 189
190 if frame.send_stop() { 190 if frame.send_stop() {
191 // Send a STOP condition 191 // Send a STOP condition
192 T::regs().cr1().modify(|reg| reg.set_stop(true)); 192 self.info.regs.cr1().modify(|reg| reg.set_stop(true));
193 } 193 }
194 194
195 // Fallthrough is success 195 // Fallthrough is success
@@ -200,18 +200,18 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
200 // Wait until we're ready for sending 200 // Wait until we're ready for sending
201 while { 201 while {
202 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 202 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
203 !Self::check_and_clear_error_flags()?.txe() 203 !Self::check_and_clear_error_flags(self.info)?.txe()
204 } { 204 } {
205 timeout.check()?; 205 timeout.check()?;
206 } 206 }
207 207
208 // Push out a byte of data 208 // Push out a byte of data
209 T::regs().dr().write(|reg| reg.set_dr(byte)); 209 self.info.regs.dr().write(|reg| reg.set_dr(byte));
210 210
211 // Wait until byte is transferred 211 // Wait until byte is transferred
212 while { 212 while {
213 // Check for any potential error conditions. 213 // Check for any potential error conditions.
214 !Self::check_and_clear_error_flags()?.btf() 214 !Self::check_and_clear_error_flags(self.info)?.btf()
215 } { 215 } {
216 timeout.check()?; 216 timeout.check()?;
217 } 217 }
@@ -222,14 +222,14 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
222 fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> { 222 fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> {
223 while { 223 while {
224 // Check for any potential error conditions. 224 // Check for any potential error conditions.
225 Self::check_and_clear_error_flags()?; 225 Self::check_and_clear_error_flags(self.info)?;
226 226
227 !T::regs().sr1().read().rxne() 227 !self.info.regs.sr1().read().rxne()
228 } { 228 } {
229 timeout.check()?; 229 timeout.check()?;
230 } 230 }
231 231
232 let value = T::regs().dr().read().dr(); 232 let value = self.info.regs.dr().read().dr();
233 Ok(value) 233 Ok(value)
234 } 234 }
235 235
@@ -246,32 +246,32 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
246 246
247 if frame.send_start() { 247 if frame.send_start() {
248 // Send a START condition and set ACK bit 248 // Send a START condition and set ACK bit
249 T::regs().cr1().modify(|reg| { 249 self.info.regs.cr1().modify(|reg| {
250 reg.set_start(true); 250 reg.set_start(true);
251 reg.set_ack(true); 251 reg.set_ack(true);
252 }); 252 });
253 253
254 // Wait until START condition was generated 254 // Wait until START condition was generated
255 while !Self::check_and_clear_error_flags()?.start() { 255 while !Self::check_and_clear_error_flags(self.info)?.start() {
256 timeout.check()?; 256 timeout.check()?;
257 } 257 }
258 258
259 // Check if we were the ones to generate START 259 // Check if we were the ones to generate START
260 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { 260 if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
261 return Err(Error::Arbitration); 261 return Err(Error::Arbitration);
262 } 262 }
263 263
264 // Set up current address we're trying to talk to 264 // Set up current address we're trying to talk to
265 T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); 265 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1));
266 266
267 // Wait until address was sent 267 // Wait until address was sent
268 // Wait for the address to be acknowledged 268 // Wait for the address to be acknowledged
269 while !Self::check_and_clear_error_flags()?.addr() { 269 while !Self::check_and_clear_error_flags(self.info)?.addr() {
270 timeout.check()?; 270 timeout.check()?;
271 } 271 }
272 272
273 // Clear condition by reading SR2 273 // Clear condition by reading SR2
274 let _ = T::regs().sr2().read(); 274 let _ = self.info.regs.sr2().read();
275 } 275 }
276 276
277 // Receive bytes into buffer 277 // Receive bytes into buffer
@@ -280,7 +280,7 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
280 } 280 }
281 281
282 // Prepare to send NACK then STOP after next byte 282 // Prepare to send NACK then STOP after next byte
283 T::regs().cr1().modify(|reg| { 283 self.info.regs.cr1().modify(|reg| {
284 if frame.send_nack() { 284 if frame.send_nack() {
285 reg.set_ack(false); 285 reg.set_ack(false);
286 } 286 }
@@ -346,17 +346,17 @@ impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
346 // Async 346 // Async
347 347
348 #[inline] // pretty sure this should always be inlined 348 #[inline] // pretty sure this should always be inlined
349 fn enable_interrupts() -> () { 349 fn enable_interrupts(info: &'static Info) -> () {
350 T::regs().cr2().modify(|w| { 350 info.regs.cr2().modify(|w| {
351 w.set_iterren(true); 351 w.set_iterren(true);
352 w.set_itevten(true); 352 w.set_itevten(true);
353 }); 353 });
354 } 354 }
355} 355}
356 356
357impl<'d, T: Instance> I2c<'d, T, Async> { 357impl<'d> I2c<'d, Async> {
358 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 358 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> {
359 T::regs().cr2().modify(|w| { 359 self.info.regs.cr2().modify(|w| {
360 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 360 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
361 // reception. 361 // reception.
362 w.set_itbufen(false); 362 w.set_itbufen(false);
@@ -370,33 +370,31 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
370 // Sentinel to disable transfer when an error occurs or future is canceled. 370 // Sentinel to disable transfer when an error occurs or future is canceled.
371 // TODO: Generate STOP condition on cancel? 371 // TODO: Generate STOP condition on cancel?
372 let on_drop = OnDrop::new(|| { 372 let on_drop = OnDrop::new(|| {
373 T::regs().cr2().modify(|w| { 373 self.info.regs.cr2().modify(|w| {
374 w.set_dmaen(false); 374 w.set_dmaen(false);
375 w.set_iterren(false); 375 w.set_iterren(false);
376 w.set_itevten(false); 376 w.set_itevten(false);
377 }) 377 })
378 }); 378 });
379 379
380 let state = T::state();
381
382 if frame.send_start() { 380 if frame.send_start() {
383 // Send a START condition 381 // Send a START condition
384 T::regs().cr1().modify(|reg| { 382 self.info.regs.cr1().modify(|reg| {
385 reg.set_start(true); 383 reg.set_start(true);
386 }); 384 });
387 385
388 // Wait until START condition was generated 386 // Wait until START condition was generated
389 poll_fn(|cx| { 387 poll_fn(|cx| {
390 state.waker.register(cx.waker()); 388 self.state.waker.register(cx.waker());
391 389
392 match Self::check_and_clear_error_flags() { 390 match Self::check_and_clear_error_flags(self.info) {
393 Err(e) => Poll::Ready(Err(e)), 391 Err(e) => Poll::Ready(Err(e)),
394 Ok(sr1) => { 392 Ok(sr1) => {
395 if sr1.start() { 393 if sr1.start() {
396 Poll::Ready(Ok(())) 394 Poll::Ready(Ok(()))
397 } else { 395 } else {
398 // When pending, (re-)enable interrupts to wake us up. 396 // When pending, (re-)enable interrupts to wake us up.
399 Self::enable_interrupts(); 397 Self::enable_interrupts(self.info);
400 Poll::Pending 398 Poll::Pending
401 } 399 }
402 } 400 }
@@ -405,25 +403,25 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
405 .await?; 403 .await?;
406 404
407 // Check if we were the ones to generate START 405 // Check if we were the ones to generate START
408 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { 406 if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
409 return Err(Error::Arbitration); 407 return Err(Error::Arbitration);
410 } 408 }
411 409
412 // Set up current address we're trying to talk to 410 // Set up current address we're trying to talk to
413 T::regs().dr().write(|reg| reg.set_dr(address << 1)); 411 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
414 412
415 // Wait for the address to be acknowledged 413 // Wait for the address to be acknowledged
416 poll_fn(|cx| { 414 poll_fn(|cx| {
417 state.waker.register(cx.waker()); 415 self.state.waker.register(cx.waker());
418 416
419 match Self::check_and_clear_error_flags() { 417 match Self::check_and_clear_error_flags(self.info) {
420 Err(e) => Poll::Ready(Err(e)), 418 Err(e) => Poll::Ready(Err(e)),
421 Ok(sr1) => { 419 Ok(sr1) => {
422 if sr1.addr() { 420 if sr1.addr() {
423 Poll::Ready(Ok(())) 421 Poll::Ready(Ok(()))
424 } else { 422 } else {
425 // When pending, (re-)enable interrupts to wake us up. 423 // When pending, (re-)enable interrupts to wake us up.
426 Self::enable_interrupts(); 424 Self::enable_interrupts(self.info);
427 Poll::Pending 425 Poll::Pending
428 } 426 }
429 } 427 }
@@ -432,26 +430,26 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
432 .await?; 430 .await?;
433 431
434 // Clear condition by reading SR2 432 // Clear condition by reading SR2
435 T::regs().sr2().read(); 433 self.info.regs.sr2().read();
436 } 434 }
437 435
438 let dma_transfer = unsafe { 436 let dma_transfer = unsafe {
439 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to 437 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to
440 // this address from the memory after each TxE event. 438 // this address from the memory after each TxE event.
441 let dst = T::regs().dr().as_ptr() as *mut u8; 439 let dst = self.info.regs.dr().as_ptr() as *mut u8;
442 440
443 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 441 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
444 }; 442 };
445 443
446 // Wait for bytes to be sent, or an error to occur. 444 // Wait for bytes to be sent, or an error to occur.
447 let poll_error = poll_fn(|cx| { 445 let poll_error = poll_fn(|cx| {
448 state.waker.register(cx.waker()); 446 self.state.waker.register(cx.waker());
449 447
450 match Self::check_and_clear_error_flags() { 448 match Self::check_and_clear_error_flags(self.info) {
451 Err(e) => Poll::Ready(Err::<(), Error>(e)), 449 Err(e) => Poll::Ready(Err::<(), Error>(e)),
452 Ok(_) => { 450 Ok(_) => {
453 // When pending, (re-)enable interrupts to wake us up. 451 // When pending, (re-)enable interrupts to wake us up.
454 Self::enable_interrupts(); 452 Self::enable_interrupts(self.info);
455 Poll::Pending 453 Poll::Pending
456 } 454 }
457 } 455 }
@@ -463,7 +461,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
463 _ => Ok(()), 461 _ => Ok(()),
464 }?; 462 }?;
465 463
466 T::regs().cr2().modify(|w| { 464 self.info.regs.cr2().modify(|w| {
467 w.set_dmaen(false); 465 w.set_dmaen(false);
468 }); 466 });
469 467
@@ -473,16 +471,16 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
473 // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA 471 // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
474 // requests then wait for a BTF event before programming the Stop condition.” 472 // requests then wait for a BTF event before programming the Stop condition.”
475 poll_fn(|cx| { 473 poll_fn(|cx| {
476 state.waker.register(cx.waker()); 474 self.state.waker.register(cx.waker());
477 475
478 match Self::check_and_clear_error_flags() { 476 match Self::check_and_clear_error_flags(self.info) {
479 Err(e) => Poll::Ready(Err(e)), 477 Err(e) => Poll::Ready(Err(e)),
480 Ok(sr1) => { 478 Ok(sr1) => {
481 if sr1.btf() { 479 if sr1.btf() {
482 Poll::Ready(Ok(())) 480 Poll::Ready(Ok(()))
483 } else { 481 } else {
484 // When pending, (re-)enable interrupts to wake us up. 482 // When pending, (re-)enable interrupts to wake us up.
485 Self::enable_interrupts(); 483 Self::enable_interrupts(self.info);
486 Poll::Pending 484 Poll::Pending
487 } 485 }
488 } 486 }
@@ -490,7 +488,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
490 }) 488 })
491 .await?; 489 .await?;
492 490
493 T::regs().cr1().modify(|w| { 491 self.info.regs.cr1().modify(|w| {
494 w.set_stop(true); 492 w.set_stop(true);
495 }); 493 });
496 } 494 }
@@ -525,7 +523,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
525 // Some branches below depend on whether the buffer contains only a single byte. 523 // Some branches below depend on whether the buffer contains only a single byte.
526 let single_byte = buffer.len() == 1; 524 let single_byte = buffer.len() == 1;
527 525
528 T::regs().cr2().modify(|w| { 526 self.info.regs.cr2().modify(|w| {
529 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 527 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
530 // reception. 528 // reception.
531 w.set_itbufen(false); 529 w.set_itbufen(false);
@@ -541,34 +539,32 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
541 // Sentinel to disable transfer when an error occurs or future is canceled. 539 // Sentinel to disable transfer when an error occurs or future is canceled.
542 // TODO: Generate STOP condition on cancel? 540 // TODO: Generate STOP condition on cancel?
543 let on_drop = OnDrop::new(|| { 541 let on_drop = OnDrop::new(|| {
544 T::regs().cr2().modify(|w| { 542 self.info.regs.cr2().modify(|w| {
545 w.set_dmaen(false); 543 w.set_dmaen(false);
546 w.set_iterren(false); 544 w.set_iterren(false);
547 w.set_itevten(false); 545 w.set_itevten(false);
548 }) 546 })
549 }); 547 });
550 548
551 let state = T::state();
552
553 if frame.send_start() { 549 if frame.send_start() {
554 // Send a START condition and set ACK bit 550 // Send a START condition and set ACK bit
555 T::regs().cr1().modify(|reg| { 551 self.info.regs.cr1().modify(|reg| {
556 reg.set_start(true); 552 reg.set_start(true);
557 reg.set_ack(true); 553 reg.set_ack(true);
558 }); 554 });
559 555
560 // Wait until START condition was generated 556 // Wait until START condition was generated
561 poll_fn(|cx| { 557 poll_fn(|cx| {
562 state.waker.register(cx.waker()); 558 self.state.waker.register(cx.waker());
563 559
564 match Self::check_and_clear_error_flags() { 560 match Self::check_and_clear_error_flags(self.info) {
565 Err(e) => Poll::Ready(Err(e)), 561 Err(e) => Poll::Ready(Err(e)),
566 Ok(sr1) => { 562 Ok(sr1) => {
567 if sr1.start() { 563 if sr1.start() {
568 Poll::Ready(Ok(())) 564 Poll::Ready(Ok(()))
569 } else { 565 } else {
570 // When pending, (re-)enable interrupts to wake us up. 566 // When pending, (re-)enable interrupts to wake us up.
571 Self::enable_interrupts(); 567 Self::enable_interrupts(self.info);
572 Poll::Pending 568 Poll::Pending
573 } 569 }
574 } 570 }
@@ -577,25 +573,25 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
577 .await?; 573 .await?;
578 574
579 // Check if we were the ones to generate START 575 // Check if we were the ones to generate START
580 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { 576 if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
581 return Err(Error::Arbitration); 577 return Err(Error::Arbitration);
582 } 578 }
583 579
584 // Set up current address we're trying to talk to 580 // Set up current address we're trying to talk to
585 T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); 581 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
586 582
587 // Wait for the address to be acknowledged 583 // Wait for the address to be acknowledged
588 poll_fn(|cx| { 584 poll_fn(|cx| {
589 state.waker.register(cx.waker()); 585 self.state.waker.register(cx.waker());
590 586
591 match Self::check_and_clear_error_flags() { 587 match Self::check_and_clear_error_flags(self.info) {
592 Err(e) => Poll::Ready(Err(e)), 588 Err(e) => Poll::Ready(Err(e)),
593 Ok(sr1) => { 589 Ok(sr1) => {
594 if sr1.addr() { 590 if sr1.addr() {
595 Poll::Ready(Ok(())) 591 Poll::Ready(Ok(()))
596 } else { 592 } else {
597 // When pending, (re-)enable interrupts to wake us up. 593 // When pending, (re-)enable interrupts to wake us up.
598 Self::enable_interrupts(); 594 Self::enable_interrupts(self.info);
599 Poll::Pending 595 Poll::Pending
600 } 596 }
601 } 597 }
@@ -606,18 +602,18 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
606 // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 602 // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6
607 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. 603 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag.
608 if frame.send_nack() && single_byte { 604 if frame.send_nack() && single_byte {
609 T::regs().cr1().modify(|w| { 605 self.info.regs.cr1().modify(|w| {
610 w.set_ack(false); 606 w.set_ack(false);
611 }); 607 });
612 } 608 }
613 609
614 // Clear condition by reading SR2 610 // Clear condition by reading SR2
615 T::regs().sr2().read(); 611 self.info.regs.sr2().read();
616 } else { 612 } else {
617 // Before starting reception of single byte (but without START condition, i.e. in case 613 // Before starting reception of single byte (but without START condition, i.e. in case
618 // of continued frame), program NACK to emit at end of this byte. 614 // of continued frame), program NACK to emit at end of this byte.
619 if frame.send_nack() && single_byte { 615 if frame.send_nack() && single_byte {
620 T::regs().cr1().modify(|w| { 616 self.info.regs.cr1().modify(|w| {
621 w.set_ack(false); 617 w.set_ack(false);
622 }); 618 });
623 } 619 }
@@ -627,7 +623,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
627 // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt 623 // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt
628 // routine. 624 // routine.
629 if frame.send_stop() && single_byte { 625 if frame.send_stop() && single_byte {
630 T::regs().cr1().modify(|w| { 626 self.info.regs.cr1().modify(|w| {
631 w.set_stop(true); 627 w.set_stop(true);
632 }); 628 });
633 } 629 }
@@ -635,20 +631,20 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
635 let dma_transfer = unsafe { 631 let dma_transfer = unsafe {
636 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved 632 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved
637 // from this address from the memory after each RxE event. 633 // from this address from the memory after each RxE event.
638 let src = T::regs().dr().as_ptr() as *mut u8; 634 let src = self.info.regs.dr().as_ptr() as *mut u8;
639 635
640 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 636 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
641 }; 637 };
642 638
643 // Wait for bytes to be received, or an error to occur. 639 // Wait for bytes to be received, or an error to occur.
644 let poll_error = poll_fn(|cx| { 640 let poll_error = poll_fn(|cx| {
645 state.waker.register(cx.waker()); 641 self.state.waker.register(cx.waker());
646 642
647 match Self::check_and_clear_error_flags() { 643 match Self::check_and_clear_error_flags(self.info) {
648 Err(e) => Poll::Ready(Err::<(), Error>(e)), 644 Err(e) => Poll::Ready(Err::<(), Error>(e)),
649 _ => { 645 _ => {
650 // When pending, (re-)enable interrupts to wake us up. 646 // When pending, (re-)enable interrupts to wake us up.
651 Self::enable_interrupts(); 647 Self::enable_interrupts(self.info);
652 Poll::Pending 648 Poll::Pending
653 } 649 }
654 } 650 }
@@ -659,12 +655,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
659 _ => Ok(()), 655 _ => Ok(()),
660 }?; 656 }?;
661 657
662 T::regs().cr2().modify(|w| { 658 self.info.regs.cr2().modify(|w| {
663 w.set_dmaen(false); 659 w.set_dmaen(false);
664 }); 660 });
665 661
666 if frame.send_stop() && !single_byte { 662 if frame.send_stop() && !single_byte {
667 T::regs().cr1().modify(|w| { 663 self.info.regs.cr1().modify(|w| {
668 w.set_stop(true); 664 w.set_stop(true);
669 }); 665 });
670 } 666 }
@@ -704,9 +700,9 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
704 } 700 }
705} 701}
706 702
707impl<'d, T: Instance, M: PeriMode> Drop for I2c<'d, T, M> { 703impl<'d, M: PeriMode> Drop for I2c<'d, M> {
708 fn drop(&mut self) { 704 fn drop(&mut self) {
709 T::disable(); 705 self.info.enable_bit.disable()
710 } 706 }
711} 707}
712 708
@@ -810,20 +806,20 @@ impl Timings {
810 } 806 }
811} 807}
812 808
813impl<'d, T: Instance, M: PeriMode> SetConfig for I2c<'d, T, M> { 809impl<'d, M: PeriMode> SetConfig for I2c<'d, M> {
814 type Config = Hertz; 810 type Config = Hertz;
815 type ConfigError = (); 811 type ConfigError = ();
816 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 812 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
817 let timings = Timings::new(T::frequency(), *config); 813 let timings = Timings::new(self.kernel_clock, *config);
818 T::regs().cr2().modify(|reg| { 814 self.info.regs.cr2().modify(|reg| {
819 reg.set_freq(timings.freq); 815 reg.set_freq(timings.freq);
820 }); 816 });
821 T::regs().ccr().modify(|reg| { 817 self.info.regs.ccr().modify(|reg| {
822 reg.set_f_s(timings.mode.f_s()); 818 reg.set_f_s(timings.mode.f_s());
823 reg.set_duty(timings.duty.duty()); 819 reg.set_duty(timings.duty.duty());
824 reg.set_ccr(timings.ccr); 820 reg.set_ccr(timings.ccr);
825 }); 821 });
826 T::regs().trise().modify(|reg| { 822 self.info.regs.trise().modify(|reg| {
827 reg.set_trise(timings.trise); 823 reg.set_trise(timings.trise);
828 }); 824 });
829 825
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 12df98534..aa6daf786 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -10,7 +10,7 @@ use super::*;
10use crate::pac::i2c; 10use crate::pac::i2c;
11 11
12pub(crate) unsafe fn on_interrupt<T: Instance>() { 12pub(crate) unsafe fn on_interrupt<T: Instance>() {
13 let regs = T::regs(); 13 let regs = T::info().regs;
14 let isr = regs.isr().read(); 14 let isr = regs.isr().read();
15 15
16 if isr.tcr() || isr.tc() { 16 if isr.tcr() || isr.tc() {
@@ -23,16 +23,16 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
23 }); 23 });
24} 24}
25 25
26impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { 26impl<'d, M: Mode> I2c<'d, M> {
27 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 27 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
28 T::regs().cr1().modify(|reg| { 28 self.info.regs.cr1().modify(|reg| {
29 reg.set_pe(false); 29 reg.set_pe(false);
30 reg.set_anfoff(false); 30 reg.set_anfoff(false);
31 }); 31 });
32 32
33 let timings = Timings::new(T::frequency(), freq.into()); 33 let timings = Timings::new(self.kernel_clock, freq.into());
34 34
35 T::regs().timingr().write(|reg| { 35 self.info.regs.timingr().write(|reg| {
36 reg.set_presc(timings.prescale); 36 reg.set_presc(timings.prescale);
37 reg.set_scll(timings.scll); 37 reg.set_scll(timings.scll);
38 reg.set_sclh(timings.sclh); 38 reg.set_sclh(timings.sclh);
@@ -40,16 +40,17 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
40 reg.set_scldel(timings.scldel); 40 reg.set_scldel(timings.scldel);
41 }); 41 });
42 42
43 T::regs().cr1().modify(|reg| { 43 self.info.regs.cr1().modify(|reg| {
44 reg.set_pe(true); 44 reg.set_pe(true);
45 }); 45 });
46 } 46 }
47 47
48 fn master_stop(&mut self) { 48 fn master_stop(&mut self) {
49 T::regs().cr2().write(|w| w.set_stop(true)); 49 self.info.regs.cr2().write(|w| w.set_stop(true));
50 } 50 }
51 51
52 fn master_read( 52 fn master_read(
53 info: &'static Info,
53 address: u8, 54 address: u8,
54 length: usize, 55 length: usize,
55 stop: Stop, 56 stop: Stop,
@@ -63,7 +64,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
63 // Wait for any previous address sequence to end 64 // Wait for any previous address sequence to end
64 // automatically. This could be up to 50% of a bus 65 // automatically. This could be up to 50% of a bus
65 // cycle (ie. up to 0.5/freq) 66 // cycle (ie. up to 0.5/freq)
66 while T::regs().cr2().read().start() { 67 while info.regs.cr2().read().start() {
67 timeout.check()?; 68 timeout.check()?;
68 } 69 }
69 } 70 }
@@ -78,7 +79,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
78 i2c::vals::Reload::COMPLETED 79 i2c::vals::Reload::COMPLETED
79 }; 80 };
80 81
81 T::regs().cr2().modify(|w| { 82 info.regs.cr2().modify(|w| {
82 w.set_sadd((address << 1 | 0) as u16); 83 w.set_sadd((address << 1 | 0) as u16);
83 w.set_add10(i2c::vals::Addmode::BIT7); 84 w.set_add10(i2c::vals::Addmode::BIT7);
84 w.set_dir(i2c::vals::Dir::READ); 85 w.set_dir(i2c::vals::Dir::READ);
@@ -91,13 +92,20 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
91 Ok(()) 92 Ok(())
92 } 93 }
93 94
94 fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> { 95 fn master_write(
96 info: &'static Info,
97 address: u8,
98 length: usize,
99 stop: Stop,
100 reload: bool,
101 timeout: Timeout,
102 ) -> Result<(), Error> {
95 assert!(length < 256); 103 assert!(length < 256);
96 104
97 // Wait for any previous address sequence to end 105 // Wait for any previous address sequence to end
98 // automatically. This could be up to 50% of a bus 106 // automatically. This could be up to 50% of a bus
99 // cycle (ie. up to 0.5/freq) 107 // cycle (ie. up to 0.5/freq)
100 while T::regs().cr2().read().start() { 108 while info.regs.cr2().read().start() {
101 timeout.check()?; 109 timeout.check()?;
102 } 110 }
103 111
@@ -110,7 +118,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
110 // Set START and prepare to send `bytes`. The 118 // Set START and prepare to send `bytes`. The
111 // START bit can be set even if the bus is BUSY or 119 // START bit can be set even if the bus is BUSY or
112 // I2C is in slave mode. 120 // I2C is in slave mode.
113 T::regs().cr2().modify(|w| { 121 info.regs.cr2().modify(|w| {
114 w.set_sadd((address << 1 | 0) as u16); 122 w.set_sadd((address << 1 | 0) as u16);
115 w.set_add10(i2c::vals::Addmode::BIT7); 123 w.set_add10(i2c::vals::Addmode::BIT7);
116 w.set_dir(i2c::vals::Dir::WRITE); 124 w.set_dir(i2c::vals::Dir::WRITE);
@@ -123,10 +131,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
123 Ok(()) 131 Ok(())
124 } 132 }
125 133
126 fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { 134 fn master_continue(info: &'static Info, length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> {
127 assert!(length < 256 && length > 0); 135 assert!(length < 256 && length > 0);
128 136
129 while !T::regs().isr().read().tcr() { 137 while !info.regs.isr().read().tcr() {
130 timeout.check()?; 138 timeout.check()?;
131 } 139 }
132 140
@@ -136,7 +144,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
136 i2c::vals::Reload::COMPLETED 144 i2c::vals::Reload::COMPLETED
137 }; 145 };
138 146
139 T::regs().cr2().modify(|w| { 147 info.regs.cr2().modify(|w| {
140 w.set_nbytes(length as u8); 148 w.set_nbytes(length as u8);
141 w.set_reload(reload); 149 w.set_reload(reload);
142 }); 150 });
@@ -145,27 +153,27 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
145 } 153 }
146 154
147 fn flush_txdr(&self) { 155 fn flush_txdr(&self) {
148 if T::regs().isr().read().txis() { 156 if self.info.regs.isr().read().txis() {
149 T::regs().txdr().write(|w| w.set_txdata(0)); 157 self.info.regs.txdr().write(|w| w.set_txdata(0));
150 } 158 }
151 if !T::regs().isr().read().txe() { 159 if !self.info.regs.isr().read().txe() {
152 T::regs().isr().modify(|w| w.set_txe(true)) 160 self.info.regs.isr().modify(|w| w.set_txe(true))
153 } 161 }
154 } 162 }
155 163
156 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { 164 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> {
157 loop { 165 loop {
158 let isr = T::regs().isr().read(); 166 let isr = self.info.regs.isr().read();
159 if isr.txe() { 167 if isr.txe() {
160 return Ok(()); 168 return Ok(());
161 } else if isr.berr() { 169 } else if isr.berr() {
162 T::regs().icr().write(|reg| reg.set_berrcf(true)); 170 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
163 return Err(Error::Bus); 171 return Err(Error::Bus);
164 } else if isr.arlo() { 172 } else if isr.arlo() {
165 T::regs().icr().write(|reg| reg.set_arlocf(true)); 173 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
166 return Err(Error::Arbitration); 174 return Err(Error::Arbitration);
167 } else if isr.nackf() { 175 } else if isr.nackf() {
168 T::regs().icr().write(|reg| reg.set_nackcf(true)); 176 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
169 self.flush_txdr(); 177 self.flush_txdr();
170 return Err(Error::Nack); 178 return Err(Error::Nack);
171 } 179 }
@@ -176,17 +184,17 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
176 184
177 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { 185 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> {
178 loop { 186 loop {
179 let isr = T::regs().isr().read(); 187 let isr = self.info.regs.isr().read();
180 if isr.rxne() { 188 if isr.rxne() {
181 return Ok(()); 189 return Ok(());
182 } else if isr.berr() { 190 } else if isr.berr() {
183 T::regs().icr().write(|reg| reg.set_berrcf(true)); 191 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
184 return Err(Error::Bus); 192 return Err(Error::Bus);
185 } else if isr.arlo() { 193 } else if isr.arlo() {
186 T::regs().icr().write(|reg| reg.set_arlocf(true)); 194 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
187 return Err(Error::Arbitration); 195 return Err(Error::Arbitration);
188 } else if isr.nackf() { 196 } else if isr.nackf() {
189 T::regs().icr().write(|reg| reg.set_nackcf(true)); 197 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
190 self.flush_txdr(); 198 self.flush_txdr();
191 return Err(Error::Nack); 199 return Err(Error::Nack);
192 } 200 }
@@ -197,17 +205,17 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
197 205
198 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { 206 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
199 loop { 207 loop {
200 let isr = T::regs().isr().read(); 208 let isr = self.info.regs.isr().read();
201 if isr.tc() { 209 if isr.tc() {
202 return Ok(()); 210 return Ok(());
203 } else if isr.berr() { 211 } else if isr.berr() {
204 T::regs().icr().write(|reg| reg.set_berrcf(true)); 212 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
205 return Err(Error::Bus); 213 return Err(Error::Bus);
206 } else if isr.arlo() { 214 } else if isr.arlo() {
207 T::regs().icr().write(|reg| reg.set_arlocf(true)); 215 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
208 return Err(Error::Arbitration); 216 return Err(Error::Arbitration);
209 } else if isr.nackf() { 217 } else if isr.nackf() {
210 T::regs().icr().write(|reg| reg.set_nackcf(true)); 218 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
211 self.flush_txdr(); 219 self.flush_txdr();
212 return Err(Error::Nack); 220 return Err(Error::Nack);
213 } 221 }
@@ -226,6 +234,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
226 let last_chunk_idx = total_chunks.saturating_sub(1); 234 let last_chunk_idx = total_chunks.saturating_sub(1);
227 235
228 Self::master_read( 236 Self::master_read(
237 self.info,
229 address, 238 address,
230 read.len().min(255), 239 read.len().min(255),
231 Stop::Automatic, 240 Stop::Automatic,
@@ -236,14 +245,14 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
236 245
237 for (number, chunk) in read.chunks_mut(255).enumerate() { 246 for (number, chunk) in read.chunks_mut(255).enumerate() {
238 if number != 0 { 247 if number != 0 {
239 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; 248 Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
240 } 249 }
241 250
242 for byte in chunk { 251 for byte in chunk {
243 // Wait until we have received something 252 // Wait until we have received something
244 self.wait_rxne(timeout)?; 253 self.wait_rxne(timeout)?;
245 254
246 *byte = T::regs().rxdr().read().rxdata(); 255 *byte = self.info.regs.rxdr().read().rxdata();
247 } 256 }
248 } 257 }
249 Ok(()) 258 Ok(())
@@ -262,6 +271,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
262 // 271 //
263 // ST SAD+W 272 // ST SAD+W
264 if let Err(err) = Self::master_write( 273 if let Err(err) = Self::master_write(
274 self.info,
265 address, 275 address,
266 write.len().min(255), 276 write.len().min(255),
267 Stop::Software, 277 Stop::Software,
@@ -276,7 +286,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
276 286
277 for (number, chunk) in write.chunks(255).enumerate() { 287 for (number, chunk) in write.chunks(255).enumerate() {
278 if number != 0 { 288 if number != 0 {
279 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; 289 Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
280 } 290 }
281 291
282 for byte in chunk { 292 for byte in chunk {
@@ -290,7 +300,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
290 return Err(err); 300 return Err(err);
291 } 301 }
292 302
293 T::regs().txdr().write(|w| w.set_txdata(*byte)); 303 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
294 } 304 }
295 } 305 }
296 // Wait until the write finishes 306 // Wait until the write finishes
@@ -348,6 +358,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
348 let last_slice_index = write.len() - 1; 358 let last_slice_index = write.len() - 1;
349 359
350 if let Err(err) = Self::master_write( 360 if let Err(err) = Self::master_write(
361 self.info,
351 address, 362 address,
352 first_length.min(255), 363 first_length.min(255),
353 Stop::Software, 364 Stop::Software,
@@ -370,6 +381,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
370 381
371 if idx != 0 { 382 if idx != 0 {
372 if let Err(err) = Self::master_continue( 383 if let Err(err) = Self::master_continue(
384 self.info,
373 slice_len.min(255), 385 slice_len.min(255),
374 (idx != last_slice_index) || (slice_len > 255), 386 (idx != last_slice_index) || (slice_len > 255),
375 timeout, 387 timeout,
@@ -382,6 +394,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
382 for (number, chunk) in slice.chunks(255).enumerate() { 394 for (number, chunk) in slice.chunks(255).enumerate() {
383 if number != 0 { 395 if number != 0 {
384 if let Err(err) = Self::master_continue( 396 if let Err(err) = Self::master_continue(
397 self.info,
385 chunk.len(), 398 chunk.len(),
386 (number != last_chunk_idx) || (idx != last_slice_index), 399 (number != last_chunk_idx) || (idx != last_slice_index),
387 timeout, 400 timeout,
@@ -402,7 +415,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
402 415
403 // Put byte on the wire 416 // Put byte on the wire
404 //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); 417 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
405 T::regs().txdr().write(|w| w.set_txdata(*byte)); 418 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
406 } 419 }
407 } 420 }
408 } 421 }
@@ -413,7 +426,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
413 } 426 }
414} 427}
415 428
416impl<'d, T: Instance> I2c<'d, T, Async> { 429impl<'d> I2c<'d, Async> {
417 async fn write_dma_internal( 430 async fn write_dma_internal(
418 &mut self, 431 &mut self,
419 address: u8, 432 address: u8,
@@ -425,7 +438,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
425 let total_len = write.len(); 438 let total_len = write.len();
426 439
427 let dma_transfer = unsafe { 440 let dma_transfer = unsafe {
428 let regs = T::regs(); 441 let regs = self.info.regs;
429 regs.cr1().modify(|w| { 442 regs.cr1().modify(|w| {
430 w.set_txdmaen(true); 443 w.set_txdmaen(true);
431 if first_slice { 444 if first_slice {
@@ -437,11 +450,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
437 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 450 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
438 }; 451 };
439 452
440 let state = T::state();
441 let mut remaining_len = total_len; 453 let mut remaining_len = total_len;
442 454
443 let on_drop = OnDrop::new(|| { 455 let on_drop = OnDrop::new(|| {
444 let regs = T::regs(); 456 let regs = self.info.regs;
445 regs.cr1().modify(|w| { 457 regs.cr1().modify(|w| {
446 if last_slice { 458 if last_slice {
447 w.set_txdmaen(false); 459 w.set_txdmaen(false);
@@ -451,12 +463,13 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
451 }); 463 });
452 464
453 poll_fn(|cx| { 465 poll_fn(|cx| {
454 state.waker.register(cx.waker()); 466 self.state.waker.register(cx.waker());
455 467
456 let isr = T::regs().isr().read(); 468 let isr = self.info.regs.isr().read();
457 if remaining_len == total_len { 469 if remaining_len == total_len {
458 if first_slice { 470 if first_slice {
459 Self::master_write( 471 Self::master_write(
472 self.info,
460 address, 473 address,
461 total_len.min(255), 474 total_len.min(255),
462 Stop::Software, 475 Stop::Software,
@@ -464,8 +477,8 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
464 timeout, 477 timeout,
465 )?; 478 )?;
466 } else { 479 } else {
467 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?; 480 Self::master_continue(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
468 T::regs().cr1().modify(|w| w.set_tcie(true)); 481 self.info.regs.cr1().modify(|w| w.set_tcie(true));
469 } 482 }
470 } else if !(isr.tcr() || isr.tc()) { 483 } else if !(isr.tcr() || isr.tc()) {
471 // poll_fn was woken without an interrupt present 484 // poll_fn was woken without an interrupt present
@@ -475,10 +488,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
475 } else { 488 } else {
476 let last_piece = (remaining_len <= 255) && last_slice; 489 let last_piece = (remaining_len <= 255) && last_slice;
477 490
478 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { 491 if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) {
479 return Poll::Ready(Err(e)); 492 return Poll::Ready(Err(e));
480 } 493 }
481 T::regs().cr1().modify(|w| w.set_tcie(true)); 494 self.info.regs.cr1().modify(|w| w.set_tcie(true));
482 } 495 }
483 496
484 remaining_len = remaining_len.saturating_sub(255); 497 remaining_len = remaining_len.saturating_sub(255);
@@ -509,7 +522,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
509 let total_len = buffer.len(); 522 let total_len = buffer.len();
510 523
511 let dma_transfer = unsafe { 524 let dma_transfer = unsafe {
512 let regs = T::regs(); 525 let regs = self.info.regs;
513 regs.cr1().modify(|w| { 526 regs.cr1().modify(|w| {
514 w.set_rxdmaen(true); 527 w.set_rxdmaen(true);
515 w.set_tcie(true); 528 w.set_tcie(true);
@@ -519,11 +532,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
519 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 532 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
520 }; 533 };
521 534
522 let state = T::state();
523 let mut remaining_len = total_len; 535 let mut remaining_len = total_len;
524 536
525 let on_drop = OnDrop::new(|| { 537 let on_drop = OnDrop::new(|| {
526 let regs = T::regs(); 538 let regs = self.info.regs;
527 regs.cr1().modify(|w| { 539 regs.cr1().modify(|w| {
528 w.set_rxdmaen(false); 540 w.set_rxdmaen(false);
529 w.set_tcie(false); 541 w.set_tcie(false);
@@ -531,11 +543,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
531 }); 543 });
532 544
533 poll_fn(|cx| { 545 poll_fn(|cx| {
534 state.waker.register(cx.waker()); 546 self.state.waker.register(cx.waker());
535 547
536 let isr = T::regs().isr().read(); 548 let isr = self.info.regs.isr().read();
537 if remaining_len == total_len { 549 if remaining_len == total_len {
538 Self::master_read( 550 Self::master_read(
551 self.info,
539 address, 552 address,
540 total_len.min(255), 553 total_len.min(255),
541 Stop::Software, 554 Stop::Software,
@@ -551,10 +564,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
551 } else { 564 } else {
552 let last_piece = remaining_len <= 255; 565 let last_piece = remaining_len <= 255;
553 566
554 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { 567 if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) {
555 return Poll::Ready(Err(e)); 568 return Poll::Ready(Err(e));
556 } 569 }
557 T::regs().cr1().modify(|w| w.set_tcie(true)); 570 self.info.regs.cr1().modify(|w| w.set_tcie(true));
558 } 571 }
559 572
560 remaining_len = remaining_len.saturating_sub(255); 573 remaining_len = remaining_len.saturating_sub(255);
@@ -658,9 +671,9 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
658 } 671 }
659} 672}
660 673
661impl<'d, T: Instance, M: Mode> Drop for I2c<'d, T, M> { 674impl<'d, M: Mode> Drop for I2c<'d, M> {
662 fn drop(&mut self) { 675 fn drop(&mut self) {
663 T::disable(); 676 self.info.enable_bit.disable();
664 } 677 }
665} 678}
666 679
@@ -788,12 +801,12 @@ impl Timings {
788 } 801 }
789} 802}
790 803
791impl<'d, T: Instance, M: Mode> SetConfig for I2c<'d, T, M> { 804impl<'d, M: Mode> SetConfig for I2c<'d, M> {
792 type Config = Hertz; 805 type Config = Hertz;
793 type ConfigError = (); 806 type ConfigError = ();
794 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 807 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
795 let timings = Timings::new(T::frequency(), *config); 808 let timings = Timings::new(self.kernel_clock, *config);
796 T::regs().timingr().write(|reg| { 809 self.info.regs.timingr().write(|reg| {
797 reg.set_presc(timings.prescale); 810 reg.set_presc(timings.prescale);
798 reg.set_scll(timings.scll); 811 reg.set_scll(timings.scll);
799 reg.set_sclh(timings.sclh); 812 reg.set_sclh(timings.sclh);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 9b80dc1d0..c78810a38 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -153,17 +153,17 @@ impl Default for Config {
153} 153}
154 154
155/// I2S driver. 155/// I2S driver.
156pub struct I2S<'d, T: Instance> { 156pub struct I2S<'d> {
157 _peri: Spi<'d, T, Async>, 157 _peri: Spi<'d, Async>,
158 sd: Option<PeripheralRef<'d, AnyPin>>, 158 sd: Option<PeripheralRef<'d, AnyPin>>,
159 ws: Option<PeripheralRef<'d, AnyPin>>, 159 ws: Option<PeripheralRef<'d, AnyPin>>,
160 ck: Option<PeripheralRef<'d, AnyPin>>, 160 ck: Option<PeripheralRef<'d, AnyPin>>,
161 mck: Option<PeripheralRef<'d, AnyPin>>, 161 mck: Option<PeripheralRef<'d, AnyPin>>,
162} 162}
163 163
164impl<'d, T: Instance> I2S<'d, T> { 164impl<'d> I2S<'d> {
165 /// Note: Full-Duplex modes are not supported at this time 165 /// Note: Full-Duplex modes are not supported at this time
166 pub fn new( 166 pub fn new<T: Instance>(
167 peri: impl Peripheral<P = T> + 'd, 167 peri: impl Peripheral<P = T> + 'd,
168 sd: impl Peripheral<P = impl MosiPin<T>> + 'd, 168 sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
169 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 169 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
@@ -208,7 +208,7 @@ impl<'d, T: Instance> I2S<'d, T> {
208 // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR 208 // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
209 // register also has to be defined. 209 // register also has to be defined.
210 210
211 T::REGS.i2spr().modify(|w| { 211 spi.info.regs.i2spr().modify(|w| {
212 w.set_i2sdiv(div); 212 w.set_i2sdiv(div);
213 w.set_odd(match odd { 213 w.set_odd(match odd {
214 true => Odd::ODD, 214 true => Odd::ODD,
@@ -235,7 +235,7 @@ impl<'d, T: Instance> I2S<'d, T> {
235 235
236 // 5. The I2SE bit in SPI_I2SCFGR register must be set. 236 // 5. The I2SE bit in SPI_I2SCFGR register must be set.
237 237
238 T::REGS.i2scfgr().modify(|w| { 238 spi.info.regs.i2scfgr().modify(|w| {
239 w.set_ckpol(config.clock_polarity.ckpol()); 239 w.set_ckpol(config.clock_polarity.ckpol());
240 240
241 w.set_i2smod(true); 241 w.set_i2smod(true);
@@ -276,7 +276,7 @@ impl<'d, T: Instance> I2S<'d, T> {
276 } 276 }
277} 277}
278 278
279impl<'d, T: Instance> Drop for I2S<'d, T> { 279impl<'d> Drop for I2S<'d> {
280 fn drop(&mut self) { 280 fn drop(&mut self) {
281 self.sd.as_ref().map(|x| x.set_as_disconnected()); 281 self.sd.as_ref().map(|x| x.set_as_disconnected());
282 self.ws.as_ref().map(|x| x.set_as_disconnected()); 282 self.ws.as_ref().map(|x| x.set_as_disconnected());
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 1f4e9ab1e..81ee60c1c 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -66,6 +66,8 @@ pub mod cryp;
66pub mod dac; 66pub mod dac;
67#[cfg(dcmi)] 67#[cfg(dcmi)]
68pub mod dcmi; 68pub mod dcmi;
69#[cfg(dsihost)]
70pub mod dsihost;
69#[cfg(eth)] 71#[cfg(eth)]
70pub mod eth; 72pub mod eth;
71#[cfg(feature = "exti")] 73#[cfg(feature = "exti")]
@@ -77,6 +79,8 @@ pub mod fmc;
77pub mod hash; 79pub mod hash;
78#[cfg(hrtim)] 80#[cfg(hrtim)]
79pub mod hrtim; 81pub mod hrtim;
82#[cfg(hsem)]
83pub mod hsem;
80#[cfg(i2c)] 84#[cfg(i2c)]
81pub mod i2c; 85pub mod i2c;
82#[cfg(all(spi_v1, rcc_f4))] 86#[cfg(all(spi_v1, rcc_f4))]
@@ -85,6 +89,8 @@ pub mod i2s;
85pub mod ipcc; 89pub mod ipcc;
86#[cfg(feature = "low-power")] 90#[cfg(feature = "low-power")]
87pub mod low_power; 91pub mod low_power;
92#[cfg(ltdc)]
93pub mod ltdc;
88#[cfg(opamp)] 94#[cfg(opamp)]
89pub mod opamp; 95pub mod opamp;
90#[cfg(octospi)] 96#[cfg(octospi)]
@@ -101,6 +107,8 @@ pub mod sai;
101pub mod sdmmc; 107pub mod sdmmc;
102#[cfg(spi)] 108#[cfg(spi)]
103pub mod spi; 109pub mod spi;
110#[cfg(tsc)]
111pub mod tsc;
104#[cfg(ucpd)] 112#[cfg(ucpd)]
105pub mod ucpd; 113pub mod ucpd;
106#[cfg(uid)] 114#[cfg(uid)]
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
new file mode 100644
index 000000000..0cc8a0557
--- /dev/null
+++ b/embassy-stm32/src/ltdc.rs
@@ -0,0 +1,142 @@
1//! LTDC
2use core::marker::PhantomData;
3
4use crate::rcc::RccPeripheral;
5use crate::{peripherals, Peripheral};
6
7/// LTDC driver.
8pub struct Ltdc<'d, T: Instance> {
9 _peri: PhantomData<&'d mut T>,
10}
11
12impl<'d, T: Instance> Ltdc<'d, T> {
13 /// Note: Full-Duplex modes are not supported at this time
14 pub fn new(
15 _peri: impl Peripheral<P = T> + 'd,
16 /*
17 clk: impl Peripheral<P = impl ClkPin<T>> + 'd,
18 hsync: impl Peripheral<P = impl HsyncPin<T>> + 'd,
19 vsync: impl Peripheral<P = impl VsyncPin<T>> + 'd,
20 b0: impl Peripheral<P = impl B0Pin<T>> + 'd,
21 b1: impl Peripheral<P = impl B1Pin<T>> + 'd,
22 b2: impl Peripheral<P = impl B2Pin<T>> + 'd,
23 b3: impl Peripheral<P = impl B3Pin<T>> + 'd,
24 b4: impl Peripheral<P = impl B4Pin<T>> + 'd,
25 b5: impl Peripheral<P = impl B5Pin<T>> + 'd,
26 b6: impl Peripheral<P = impl B6Pin<T>> + 'd,
27 b7: impl Peripheral<P = impl B7Pin<T>> + 'd,
28 g0: impl Peripheral<P = impl G0Pin<T>> + 'd,
29 g1: impl Peripheral<P = impl G1Pin<T>> + 'd,
30 g2: impl Peripheral<P = impl G2Pin<T>> + 'd,
31 g3: impl Peripheral<P = impl G3Pin<T>> + 'd,
32 g4: impl Peripheral<P = impl G4Pin<T>> + 'd,
33 g5: impl Peripheral<P = impl G5Pin<T>> + 'd,
34 g6: impl Peripheral<P = impl G6Pin<T>> + 'd,
35 g7: impl Peripheral<P = impl G7Pin<T>> + 'd,
36 r0: impl Peripheral<P = impl R0Pin<T>> + 'd,
37 r1: impl Peripheral<P = impl R1Pin<T>> + 'd,
38 r2: impl Peripheral<P = impl R2Pin<T>> + 'd,
39 r3: impl Peripheral<P = impl R3Pin<T>> + 'd,
40 r4: impl Peripheral<P = impl R4Pin<T>> + 'd,
41 r5: impl Peripheral<P = impl R5Pin<T>> + 'd,
42 r6: impl Peripheral<P = impl R6Pin<T>> + 'd,
43 r7: impl Peripheral<P = impl R7Pin<T>> + 'd,
44 */
45 ) -> Self {
46 //into_ref!(clk);
47
48 critical_section::with(|_cs| {
49 // RM says the pllsaidivr should only be changed when pllsai is off. But this could have other unintended side effects. So let's just give it a try like this.
50 // According to the debugger, this bit gets set, anyway.
51 #[cfg(stm32f7)]
52 stm32_metapac::RCC
53 .dckcfgr1()
54 .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
55
56 // It is set to RCC_PLLSAIDIVR_2 in ST's BSP example for the STM32469I-DISCO.
57 #[cfg(not(any(stm32f7, stm32u5)))]
58 stm32_metapac::RCC
59 .dckcfgr()
60 .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
61 });
62
63 T::enable_and_reset();
64
65 //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None);
66
67 // Set Tearing Enable pin according to CubeMx example
68 //te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None);
69 //te.set_speed(Speed::Low);
70 /*
71 T::regs().wcr().modify(|w| {
72 w.set_dsien(true);
73 });
74 */
75 Self { _peri: PhantomData }
76 }
77
78 /// Set the enable bit in the control register and assert that it has been enabled
79 pub fn enable(&mut self) {
80 T::regs().gcr().modify(|w| w.set_ltdcen(true));
81 assert!(T::regs().gcr().read().ltdcen())
82 }
83
84 /// Unset the enable bit in the control register and assert that it has been disabled
85 pub fn disable(&mut self) {
86 T::regs().gcr().modify(|w| w.set_ltdcen(false));
87 assert!(!T::regs().gcr().read().ltdcen())
88 }
89}
90
91impl<'d, T: Instance> Drop for Ltdc<'d, T> {
92 fn drop(&mut self) {}
93}
94
95trait SealedInstance: crate::rcc::SealedRccPeripheral {
96 fn regs() -> &'static crate::pac::ltdc::Ltdc;
97}
98
99/// DSI instance trait.
100#[allow(private_bounds)]
101pub trait Instance: SealedInstance + RccPeripheral + 'static {}
102
103pin_trait!(ClkPin, Instance);
104pin_trait!(HsyncPin, Instance);
105pin_trait!(VsyncPin, Instance);
106pin_trait!(DePin, Instance);
107pin_trait!(R0Pin, Instance);
108pin_trait!(R1Pin, Instance);
109pin_trait!(R2Pin, Instance);
110pin_trait!(R3Pin, Instance);
111pin_trait!(R4Pin, Instance);
112pin_trait!(R5Pin, Instance);
113pin_trait!(R6Pin, Instance);
114pin_trait!(R7Pin, Instance);
115pin_trait!(G0Pin, Instance);
116pin_trait!(G1Pin, Instance);
117pin_trait!(G2Pin, Instance);
118pin_trait!(G3Pin, Instance);
119pin_trait!(G4Pin, Instance);
120pin_trait!(G5Pin, Instance);
121pin_trait!(G6Pin, Instance);
122pin_trait!(G7Pin, Instance);
123pin_trait!(B0Pin, Instance);
124pin_trait!(B1Pin, Instance);
125pin_trait!(B2Pin, Instance);
126pin_trait!(B3Pin, Instance);
127pin_trait!(B4Pin, Instance);
128pin_trait!(B5Pin, Instance);
129pin_trait!(B6Pin, Instance);
130pin_trait!(B7Pin, Instance);
131
132foreach_peripheral!(
133 (ltdc, $inst:ident) => {
134 impl crate::ltdc::SealedInstance for peripherals::$inst {
135 fn regs() -> &'static crate::pac::ltdc::Ltdc {
136 &crate::pac::$inst
137 }
138 }
139
140 impl crate::ltdc::Instance for peripherals::$inst {}
141 };
142);
diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs
index 02dce1266..7f8076043 100644
--- a/embassy-stm32/src/macros.rs
+++ b/embassy-stm32/src/macros.rs
@@ -1,5 +1,45 @@
1#![macro_use] 1#![macro_use]
2 2
3macro_rules! peri_trait {
4 (
5 $(irqs: [$($irq:ident),*],)?
6 ) => {
7 #[allow(private_interfaces)]
8 pub(crate) trait SealedInstance {
9 #[allow(unused)]
10 fn info() -> &'static Info;
11 #[allow(unused)]
12 fn state() -> &'static State;
13 }
14
15 /// Peripheral instance trait.
16 #[allow(private_bounds)]
17 pub trait Instance: crate::Peripheral<P = Self> + SealedInstance + crate::rcc::RccPeripheral {
18 $($(
19 /// Interrupt for this peripheral.
20 type $irq: crate::interrupt::typelevel::Interrupt;
21 )*)?
22 }
23 };
24}
25
26macro_rules! peri_trait_impl {
27 ($instance:ident, $info:expr) => {
28 #[allow(private_interfaces)]
29 impl SealedInstance for crate::peripherals::$instance {
30 fn info() -> &'static Info {
31 static INFO: Info = $info;
32 &INFO
33 }
34 fn state() -> &'static State {
35 static STATE: State = State::new();
36 &STATE
37 }
38 }
39 impl Instance for crate::peripherals::$instance {}
40 };
41}
42
3macro_rules! pin_trait { 43macro_rules! pin_trait {
4 ($signal:ident, $instance:path $(, $mode:path)?) => { 44 ($signal:ident, $instance:path $(, $mode:path)?) => {
5 #[doc = concat!(stringify!($signal), " pin trait")] 45 #[doc = concat!(stringify!($signal), " pin trait")]
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index a3b4352c0..487902959 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -198,7 +198,7 @@ macro_rules! impl_opamp_external_output {
198 ($inst:ident, $adc:ident, $ch:expr) => { 198 ($inst:ident, $adc:ident, $ch:expr) => {
199 foreach_adc!( 199 foreach_adc!(
200 ($adc, $common_inst:ident, $adc_clock:ident) => { 200 ($adc, $common_inst:ident, $adc_clock:ident) => {
201 impl<'d> crate::adc::SealedAdcPin<crate::peripherals::$adc> 201 impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
202 for OpAmpOutput<'d, crate::peripherals::$inst> 202 for OpAmpOutput<'d, crate::peripherals::$inst>
203 { 203 {
204 fn channel(&self) -> u8 { 204 fn channel(&self) -> u8 {
@@ -206,7 +206,7 @@ macro_rules! impl_opamp_external_output {
206 } 206 }
207 } 207 }
208 208
209 impl<'d> crate::adc::AdcPin<crate::peripherals::$adc> 209 impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
210 for OpAmpOutput<'d, crate::peripherals::$inst> 210 for OpAmpOutput<'d, crate::peripherals::$inst>
211 { 211 {
212 } 212 }
@@ -244,7 +244,7 @@ macro_rules! impl_opamp_internal_output {
244 ($inst:ident, $adc:ident, $ch:expr) => { 244 ($inst:ident, $adc:ident, $ch:expr) => {
245 foreach_adc!( 245 foreach_adc!(
246 ($adc, $common_inst:ident, $adc_clock:ident) => { 246 ($adc, $common_inst:ident, $adc_clock:ident) => {
247 impl<'d> crate::adc::SealedAdcPin<crate::peripherals::$adc> 247 impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
248 for OpAmpInternalOutput<'d, crate::peripherals::$inst> 248 for OpAmpInternalOutput<'d, crate::peripherals::$inst>
249 { 249 {
250 fn channel(&self) -> u8 { 250 fn channel(&self) -> u8 {
@@ -252,7 +252,7 @@ macro_rules! impl_opamp_internal_output {
252 } 252 }
253 } 253 }
254 254
255 impl<'d> crate::adc::AdcPin<crate::peripherals::$adc> 255 impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
256 for OpAmpInternalOutput<'d, crate::peripherals::$inst> 256 for OpAmpInternalOutput<'d, crate::peripherals::$inst>
257 { 257 {
258 } 258 }
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index c25ac4d24..536da4ca0 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -5,13 +5,16 @@
5 5
6pub mod enums; 6pub mod enums;
7 7
8use core::marker::PhantomData;
9
8use embassy_embedded_hal::{GetConfig, SetConfig}; 10use embassy_embedded_hal::{GetConfig, SetConfig};
9use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
10pub use enums::*; 12pub use enums::*;
11use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; 13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
12 14
13use crate::dma::{word, Transfer}; 15use crate::dma::{word, ChannelAndRequest};
14use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; 16use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{vals, Octospi as Regs};
16use crate::rcc::RccPeripheral; 19use crate::rcc::RccPeripheral;
17use crate::{peripherals, Peripheral}; 20use crate::{peripherals, Peripheral};
@@ -154,7 +157,7 @@ pub enum OspiError {
154} 157}
155 158
156/// OSPI driver. 159/// OSPI driver.
157pub struct Ospi<'d, T: Instance, Dma> { 160pub struct Ospi<'d, T: Instance, M: PeriMode> {
158 _peri: PeripheralRef<'d, T>, 161 _peri: PeripheralRef<'d, T>,
159 sck: Option<PeripheralRef<'d, AnyPin>>, 162 sck: Option<PeripheralRef<'d, AnyPin>>,
160 d0: Option<PeripheralRef<'d, AnyPin>>, 163 d0: Option<PeripheralRef<'d, AnyPin>>,
@@ -167,259 +170,13 @@ pub struct Ospi<'d, T: Instance, Dma> {
167 d7: Option<PeripheralRef<'d, AnyPin>>, 170 d7: Option<PeripheralRef<'d, AnyPin>>,
168 nss: Option<PeripheralRef<'d, AnyPin>>, 171 nss: Option<PeripheralRef<'d, AnyPin>>,
169 dqs: Option<PeripheralRef<'d, AnyPin>>, 172 dqs: Option<PeripheralRef<'d, AnyPin>>,
170 dma: PeripheralRef<'d, Dma>, 173 dma: Option<ChannelAndRequest<'d>>,
174 _phantom: PhantomData<M>,
171 config: Config, 175 config: Config,
172 width: OspiWidth, 176 width: OspiWidth,
173} 177}
174 178
175impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { 179impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
176 /// Create new OSPI driver for a single spi external chip
177 pub fn new_singlespi(
178 peri: impl Peripheral<P = T> + 'd,
179 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
180 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
181 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
182 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
183 dma: impl Peripheral<P = Dma> + 'd,
184 config: Config,
185 ) -> Self {
186 into_ref!(peri, sck, d0, d1, nss);
187
188 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
189 sck.set_speed(crate::gpio::Speed::VeryHigh);
190 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
191 nss.set_speed(crate::gpio::Speed::VeryHigh);
192 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
193 d0.set_speed(crate::gpio::Speed::VeryHigh);
194 d1.set_as_af_pull(d1.af_num(), AFType::Input, Pull::None);
195 d1.set_speed(crate::gpio::Speed::VeryHigh);
196
197 Self::new_inner(
198 peri,
199 Some(d0.map_into()),
200 Some(d1.map_into()),
201 None,
202 None,
203 None,
204 None,
205 None,
206 None,
207 Some(sck.map_into()),
208 Some(nss.map_into()),
209 None,
210 dma,
211 config,
212 OspiWidth::SING,
213 false,
214 )
215 }
216
217 /// Create new OSPI driver for a dualspi external chip
218 pub fn new_dualspi(
219 peri: impl Peripheral<P = T> + 'd,
220 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
221 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
222 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
223 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
224 dma: impl Peripheral<P = Dma> + 'd,
225 config: Config,
226 ) -> Self {
227 into_ref!(peri, sck, d0, d1, nss);
228
229 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
230 sck.set_speed(crate::gpio::Speed::VeryHigh);
231 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
232 nss.set_speed(crate::gpio::Speed::VeryHigh);
233 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
234 d0.set_speed(crate::gpio::Speed::VeryHigh);
235 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
236 d1.set_speed(crate::gpio::Speed::VeryHigh);
237
238 Self::new_inner(
239 peri,
240 Some(d0.map_into()),
241 Some(d1.map_into()),
242 None,
243 None,
244 None,
245 None,
246 None,
247 None,
248 Some(sck.map_into()),
249 Some(nss.map_into()),
250 None,
251 dma,
252 config,
253 OspiWidth::DUAL,
254 false,
255 )
256 }
257
258 /// Create new OSPI driver for a quadspi external chip
259 pub fn new_quadspi(
260 peri: impl Peripheral<P = T> + 'd,
261 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
262 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
263 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
264 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
265 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
266 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
267 dma: impl Peripheral<P = Dma> + 'd,
268 config: Config,
269 ) -> Self {
270 into_ref!(peri, sck, d0, d1, d2, d3, nss);
271
272 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
273 sck.set_speed(crate::gpio::Speed::VeryHigh);
274 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
275 nss.set_speed(crate::gpio::Speed::VeryHigh);
276 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
277 d0.set_speed(crate::gpio::Speed::VeryHigh);
278 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
279 d1.set_speed(crate::gpio::Speed::VeryHigh);
280 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
281 d2.set_speed(crate::gpio::Speed::VeryHigh);
282 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
283 d3.set_speed(crate::gpio::Speed::VeryHigh);
284
285 Self::new_inner(
286 peri,
287 Some(d0.map_into()),
288 Some(d1.map_into()),
289 Some(d2.map_into()),
290 Some(d3.map_into()),
291 None,
292 None,
293 None,
294 None,
295 Some(sck.map_into()),
296 Some(nss.map_into()),
297 None,
298 dma,
299 config,
300 OspiWidth::QUAD,
301 false,
302 )
303 }
304
305 /// Create new OSPI driver for two quadspi external chips
306 pub fn new_dualquadspi(
307 peri: impl Peripheral<P = T> + 'd,
308 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
309 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
310 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
311 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
312 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
313 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
314 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
315 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
316 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
317 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
318 dma: impl Peripheral<P = Dma> + 'd,
319 config: Config,
320 ) -> Self {
321 into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss);
322
323 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
324 sck.set_speed(crate::gpio::Speed::VeryHigh);
325 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
326 nss.set_speed(crate::gpio::Speed::VeryHigh);
327 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
328 d0.set_speed(crate::gpio::Speed::VeryHigh);
329 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
330 d1.set_speed(crate::gpio::Speed::VeryHigh);
331 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
332 d2.set_speed(crate::gpio::Speed::VeryHigh);
333 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
334 d3.set_speed(crate::gpio::Speed::VeryHigh);
335 d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None);
336 d4.set_speed(crate::gpio::Speed::VeryHigh);
337 d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None);
338 d5.set_speed(crate::gpio::Speed::VeryHigh);
339 d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None);
340 d6.set_speed(crate::gpio::Speed::VeryHigh);
341 d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None);
342 d7.set_speed(crate::gpio::Speed::VeryHigh);
343
344 Self::new_inner(
345 peri,
346 Some(d0.map_into()),
347 Some(d1.map_into()),
348 Some(d2.map_into()),
349 Some(d3.map_into()),
350 Some(d4.map_into()),
351 Some(d5.map_into()),
352 Some(d6.map_into()),
353 Some(d7.map_into()),
354 Some(sck.map_into()),
355 Some(nss.map_into()),
356 None,
357 dma,
358 config,
359 OspiWidth::QUAD,
360 true,
361 )
362 }
363
364 /// Create new OSPI driver for octospi external chips
365 pub fn new_octospi(
366 peri: impl Peripheral<P = T> + 'd,
367 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
368 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
369 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
370 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
371 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
372 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
373 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
374 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
375 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
376 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
377 dma: impl Peripheral<P = Dma> + 'd,
378 config: Config,
379 ) -> Self {
380 into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss);
381
382 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
383 sck.set_speed(crate::gpio::Speed::VeryHigh);
384 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
385 nss.set_speed(crate::gpio::Speed::VeryHigh);
386 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
387 d0.set_speed(crate::gpio::Speed::VeryHigh);
388 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
389 d1.set_speed(crate::gpio::Speed::VeryHigh);
390 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
391 d2.set_speed(crate::gpio::Speed::VeryHigh);
392 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
393 d3.set_speed(crate::gpio::Speed::VeryHigh);
394 d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None);
395 d4.set_speed(crate::gpio::Speed::VeryHigh);
396 d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None);
397 d5.set_speed(crate::gpio::Speed::VeryHigh);
398 d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None);
399 d6.set_speed(crate::gpio::Speed::VeryHigh);
400 d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None);
401 d7.set_speed(crate::gpio::Speed::VeryHigh);
402
403 Self::new_inner(
404 peri,
405 Some(d0.map_into()),
406 Some(d1.map_into()),
407 Some(d2.map_into()),
408 Some(d3.map_into()),
409 Some(d4.map_into()),
410 Some(d5.map_into()),
411 Some(d6.map_into()),
412 Some(d7.map_into()),
413 Some(sck.map_into()),
414 Some(nss.map_into()),
415 None,
416 dma,
417 config,
418 OspiWidth::OCTO,
419 false,
420 )
421 }
422
423 fn new_inner( 180 fn new_inner(
424 peri: impl Peripheral<P = T> + 'd, 181 peri: impl Peripheral<P = T> + 'd,
425 d0: Option<PeripheralRef<'d, AnyPin>>, 182 d0: Option<PeripheralRef<'d, AnyPin>>,
@@ -433,12 +190,12 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
433 sck: Option<PeripheralRef<'d, AnyPin>>, 190 sck: Option<PeripheralRef<'d, AnyPin>>,
434 nss: Option<PeripheralRef<'d, AnyPin>>, 191 nss: Option<PeripheralRef<'d, AnyPin>>,
435 dqs: Option<PeripheralRef<'d, AnyPin>>, 192 dqs: Option<PeripheralRef<'d, AnyPin>>,
436 dma: impl Peripheral<P = Dma> + 'd, 193 dma: Option<ChannelAndRequest<'d>>,
437 config: Config, 194 config: Config,
438 width: OspiWidth, 195 width: OspiWidth,
439 dual_quad: bool, 196 dual_quad: bool,
440 ) -> Self { 197 ) -> Self {
441 into_ref!(peri, dma); 198 into_ref!(peri);
442 199
443 // System configuration 200 // System configuration
444 T::enable_and_reset(); 201 T::enable_and_reset();
@@ -519,6 +276,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
519 nss, 276 nss,
520 dqs, 277 dqs,
521 dma, 278 dma,
279 _phantom: PhantomData,
522 config, 280 config,
523 width, 281 width,
524 } 282 }
@@ -702,11 +460,410 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
702 Ok(()) 460 Ok(())
703 } 461 }
704 462
463 /// Set new bus configuration
464 pub fn set_config(&mut self, config: &Config) {
465 // Wait for busy flag to clear
466 while T::REGS.sr().read().busy() {}
467
468 // Disable DMA channel while configuring the peripheral
469 T::REGS.cr().modify(|w| {
470 w.set_dmaen(false);
471 });
472
473 // Device configuration
474 T::REGS.dcr1().modify(|w| {
475 w.set_devsize(config.device_size.into());
476 w.set_mtyp(vals::MemType::from_bits(config.memory_type.into()));
477 w.set_csht(config.chip_select_high_time.into());
478 w.set_dlybyp(config.delay_block_bypass);
479 w.set_frck(false);
480 w.set_ckmode(config.clock_mode);
481 });
482
483 T::REGS.dcr2().modify(|w| {
484 w.set_wrapsize(config.wrap_size.into());
485 });
486
487 T::REGS.dcr3().modify(|w| {
488 w.set_csbound(config.chip_select_boundary);
489 #[cfg(octospi_v1)]
490 {
491 w.set_maxtran(config.max_transfer);
492 }
493 });
494
495 T::REGS.dcr4().modify(|w| {
496 w.set_refresh(config.refresh);
497 });
498
499 T::REGS.cr().modify(|w| {
500 w.set_fthres(vals::Threshold(config.fifo_threshold.into()));
501 });
502
503 // Wait for busy flag to clear
504 while T::REGS.sr().read().busy() {}
505
506 T::REGS.dcr2().modify(|w| {
507 w.set_prescaler(config.clock_prescaler);
508 });
509
510 T::REGS.tcr().modify(|w| {
511 w.set_sshift(match config.sample_shifting {
512 true => vals::SampleShift::HALFCYCLE,
513 false => vals::SampleShift::NONE,
514 });
515 w.set_dhqc(config.delay_hold_quarter_cycle);
516 });
517
518 // Enable peripheral
519 T::REGS.cr().modify(|w| {
520 w.set_en(true);
521 });
522
523 // Free running clock needs to be set after peripheral enable
524 if config.free_running_clock {
525 T::REGS.dcr1().modify(|w| {
526 w.set_frck(config.free_running_clock);
527 });
528 }
529
530 self.config = *config;
531 }
532
533 /// Get current configuration
534 pub fn get_config(&self) -> Config {
535 self.config
536 }
537}
538
539impl<'d, T: Instance> Ospi<'d, T, Blocking> {
540 /// Create new blocking OSPI driver for a single spi external chip
541 pub fn new_blocking_singlespi(
542 peri: impl Peripheral<P = T> + 'd,
543 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
544 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
545 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
546 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
547 config: Config,
548 ) -> Self {
549 Self::new_inner(
550 peri,
551 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
552 new_pin!(d1, AFType::Input, Speed::VeryHigh),
553 None,
554 None,
555 None,
556 None,
557 None,
558 None,
559 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
560 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
561 None,
562 None,
563 config,
564 OspiWidth::SING,
565 false,
566 )
567 }
568
569 /// Create new blocking OSPI driver for a dualspi external chip
570 pub fn new_blocking_dualspi(
571 peri: impl Peripheral<P = T> + 'd,
572 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
573 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
574 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
575 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
576 config: Config,
577 ) -> Self {
578 Self::new_inner(
579 peri,
580 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
581 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
582 None,
583 None,
584 None,
585 None,
586 None,
587 None,
588 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
589 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
590 None,
591 None,
592 config,
593 OspiWidth::DUAL,
594 false,
595 )
596 }
597
598 /// Create new blocking OSPI driver for a quadspi external chip
599 pub fn new_blocking_quadspi(
600 peri: impl Peripheral<P = T> + 'd,
601 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
602 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
603 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
604 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
605 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
606 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
607 config: Config,
608 ) -> Self {
609 Self::new_inner(
610 peri,
611 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
612 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
613 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
614 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
615 None,
616 None,
617 None,
618 None,
619 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
620 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
621 None,
622 None,
623 config,
624 OspiWidth::QUAD,
625 false,
626 )
627 }
628
629 /// Create new blocking OSPI driver for two quadspi external chips
630 pub fn new_blocking_dualquadspi(
631 peri: impl Peripheral<P = T> + 'd,
632 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
633 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
634 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
635 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
636 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
637 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
638 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
639 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
640 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
641 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
642 config: Config,
643 ) -> Self {
644 Self::new_inner(
645 peri,
646 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
647 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
648 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
649 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
650 new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh),
651 new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh),
652 new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh),
653 new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh),
654 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
655 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
656 None,
657 None,
658 config,
659 OspiWidth::QUAD,
660 true,
661 )
662 }
663
664 /// Create new blocking OSPI driver for octospi external chips
665 pub fn new_blocking_octospi(
666 peri: impl Peripheral<P = T> + 'd,
667 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
668 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
669 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
670 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
671 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
672 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
673 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
674 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
675 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
676 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
677 config: Config,
678 ) -> Self {
679 Self::new_inner(
680 peri,
681 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
682 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
683 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
684 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
685 new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh),
686 new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh),
687 new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh),
688 new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh),
689 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
690 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
691 None,
692 None,
693 config,
694 OspiWidth::OCTO,
695 false,
696 )
697 }
698}
699
700impl<'d, T: Instance> Ospi<'d, T, Async> {
701 /// Create new blocking OSPI driver for a single spi external chip
702 pub fn new_singlespi(
703 peri: impl Peripheral<P = T> + 'd,
704 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
705 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
706 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
707 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
708 dma: impl Peripheral<P = impl OctoDma<T>> + 'd,
709 config: Config,
710 ) -> Self {
711 Self::new_inner(
712 peri,
713 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
714 new_pin!(d1, AFType::Input, Speed::VeryHigh),
715 None,
716 None,
717 None,
718 None,
719 None,
720 None,
721 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
722 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
723 None,
724 new_dma!(dma),
725 config,
726 OspiWidth::SING,
727 false,
728 )
729 }
730
731 /// Create new blocking OSPI driver for a dualspi external chip
732 pub fn new_dualspi(
733 peri: impl Peripheral<P = T> + 'd,
734 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
735 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
736 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
737 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
738 dma: impl Peripheral<P = impl OctoDma<T>> + 'd,
739 config: Config,
740 ) -> Self {
741 Self::new_inner(
742 peri,
743 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
744 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
745 None,
746 None,
747 None,
748 None,
749 None,
750 None,
751 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
752 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
753 None,
754 new_dma!(dma),
755 config,
756 OspiWidth::DUAL,
757 false,
758 )
759 }
760
761 /// Create new blocking OSPI driver for a quadspi external chip
762 pub fn new_quadspi(
763 peri: impl Peripheral<P = T> + 'd,
764 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
765 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
766 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
767 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
768 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
769 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
770 dma: impl Peripheral<P = impl OctoDma<T>> + 'd,
771 config: Config,
772 ) -> Self {
773 Self::new_inner(
774 peri,
775 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
776 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
777 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
778 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
779 None,
780 None,
781 None,
782 None,
783 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
784 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
785 None,
786 new_dma!(dma),
787 config,
788 OspiWidth::QUAD,
789 false,
790 )
791 }
792
793 /// Create new blocking OSPI driver for two quadspi external chips
794 pub fn new_dualquadspi(
795 peri: impl Peripheral<P = T> + 'd,
796 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
797 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
798 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
799 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
800 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
801 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
802 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
803 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
804 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
805 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
806 dma: impl Peripheral<P = impl OctoDma<T>> + 'd,
807 config: Config,
808 ) -> Self {
809 Self::new_inner(
810 peri,
811 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
812 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
813 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
814 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
815 new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh),
816 new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh),
817 new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh),
818 new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh),
819 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
820 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
821 None,
822 new_dma!(dma),
823 config,
824 OspiWidth::QUAD,
825 true,
826 )
827 }
828
829 /// Create new blocking OSPI driver for octospi external chips
830 pub fn new_octospi(
831 peri: impl Peripheral<P = T> + 'd,
832 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
833 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
834 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
835 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
836 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
837 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
838 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
839 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
840 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
841 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
842 dma: impl Peripheral<P = impl OctoDma<T>> + 'd,
843 config: Config,
844 ) -> Self {
845 Self::new_inner(
846 peri,
847 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
848 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
849 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
850 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
851 new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh),
852 new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh),
853 new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh),
854 new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh),
855 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
856 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
857 None,
858 new_dma!(dma),
859 config,
860 OspiWidth::OCTO,
861 false,
862 )
863 }
864
705 /// Blocking read with DMA transfer 865 /// Blocking read with DMA transfer
706 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> 866 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> {
707 where
708 Dma: OctoDma<T>,
709 {
710 if buf.is_empty() { 867 if buf.is_empty() {
711 return Err(OspiError::EmptyBuffer); 868 return Err(OspiError::EmptyBuffer);
712 } 869 }
@@ -727,15 +884,11 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
727 T::REGS.ar().write(|v| v.set_address(current_address)); 884 T::REGS.ar().write(|v| v.set_address(current_address));
728 } 885 }
729 886
730 let request = self.dma.request();
731 let transfer = unsafe { 887 let transfer = unsafe {
732 Transfer::new_read( 888 self.dma
733 &mut self.dma, 889 .as_mut()
734 request, 890 .unwrap()
735 T::REGS.dr().as_ptr() as *mut W, 891 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
736 buf,
737 Default::default(),
738 )
739 }; 892 };
740 893
741 T::REGS.cr().modify(|w| w.set_dmaen(true)); 894 T::REGS.cr().modify(|w| w.set_dmaen(true));
@@ -748,10 +901,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
748 } 901 }
749 902
750 /// Blocking write with DMA transfer 903 /// Blocking write with DMA transfer
751 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> 904 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> {
752 where
753 Dma: OctoDma<T>,
754 {
755 if buf.is_empty() { 905 if buf.is_empty() {
756 return Err(OspiError::EmptyBuffer); 906 return Err(OspiError::EmptyBuffer);
757 } 907 }
@@ -764,15 +914,11 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
764 .cr() 914 .cr()
765 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); 915 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
766 916
767 let request = self.dma.request();
768 let transfer = unsafe { 917 let transfer = unsafe {
769 Transfer::new_write( 918 self.dma
770 &mut self.dma, 919 .as_mut()
771 request, 920 .unwrap()
772 buf, 921 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
773 T::REGS.dr().as_ptr() as *mut W,
774 Default::default(),
775 )
776 }; 922 };
777 923
778 T::REGS.cr().modify(|w| w.set_dmaen(true)); 924 T::REGS.cr().modify(|w| w.set_dmaen(true));
@@ -785,10 +931,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
785 } 931 }
786 932
787 /// Asynchronous read from external device 933 /// Asynchronous read from external device
788 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> 934 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> {
789 where
790 Dma: OctoDma<T>,
791 {
792 if buf.is_empty() { 935 if buf.is_empty() {
793 return Err(OspiError::EmptyBuffer); 936 return Err(OspiError::EmptyBuffer);
794 } 937 }
@@ -809,15 +952,11 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
809 T::REGS.ar().write(|v| v.set_address(current_address)); 952 T::REGS.ar().write(|v| v.set_address(current_address));
810 } 953 }
811 954
812 let request = self.dma.request();
813 let transfer = unsafe { 955 let transfer = unsafe {
814 Transfer::new_read( 956 self.dma
815 &mut self.dma, 957 .as_mut()
816 request, 958 .unwrap()
817 T::REGS.dr().as_ptr() as *mut W, 959 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
818 buf,
819 Default::default(),
820 )
821 }; 960 };
822 961
823 T::REGS.cr().modify(|w| w.set_dmaen(true)); 962 T::REGS.cr().modify(|w| w.set_dmaen(true));
@@ -830,10 +969,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
830 } 969 }
831 970
832 /// Asynchronous write to external device 971 /// Asynchronous write to external device
833 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> 972 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> {
834 where
835 Dma: OctoDma<T>,
836 {
837 if buf.is_empty() { 973 if buf.is_empty() {
838 return Err(OspiError::EmptyBuffer); 974 return Err(OspiError::EmptyBuffer);
839 } 975 }
@@ -846,15 +982,11 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
846 .cr() 982 .cr()
847 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); 983 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
848 984
849 let request = self.dma.request();
850 let transfer = unsafe { 985 let transfer = unsafe {
851 Transfer::new_write( 986 self.dma
852 &mut self.dma, 987 .as_mut()
853 request, 988 .unwrap()
854 buf, 989 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
855 T::REGS.dr().as_ptr() as *mut W,
856 Default::default(),
857 )
858 }; 990 };
859 991
860 T::REGS.cr().modify(|w| w.set_dmaen(true)); 992 T::REGS.cr().modify(|w| w.set_dmaen(true));
@@ -865,84 +997,9 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
865 997
866 Ok(()) 998 Ok(())
867 } 999 }
868
869 /// Set new bus configuration
870 pub fn set_config(&mut self, config: &Config) {
871 // Wait for busy flag to clear
872 while T::REGS.sr().read().busy() {}
873
874 // Disable DMA channel while configuring the peripheral
875 T::REGS.cr().modify(|w| {
876 w.set_dmaen(false);
877 });
878
879 // Device configuration
880 T::REGS.dcr1().modify(|w| {
881 w.set_devsize(config.device_size.into());
882 w.set_mtyp(vals::MemType::from_bits(config.memory_type.into()));
883 w.set_csht(config.chip_select_high_time.into());
884 w.set_dlybyp(config.delay_block_bypass);
885 w.set_frck(false);
886 w.set_ckmode(config.clock_mode);
887 });
888
889 T::REGS.dcr2().modify(|w| {
890 w.set_wrapsize(config.wrap_size.into());
891 });
892
893 T::REGS.dcr3().modify(|w| {
894 w.set_csbound(config.chip_select_boundary);
895 #[cfg(octospi_v1)]
896 {
897 w.set_maxtran(config.max_transfer);
898 }
899 });
900
901 T::REGS.dcr4().modify(|w| {
902 w.set_refresh(config.refresh);
903 });
904
905 T::REGS.cr().modify(|w| {
906 w.set_fthres(vals::Threshold(config.fifo_threshold.into()));
907 });
908
909 // Wait for busy flag to clear
910 while T::REGS.sr().read().busy() {}
911
912 T::REGS.dcr2().modify(|w| {
913 w.set_prescaler(config.clock_prescaler);
914 });
915
916 T::REGS.tcr().modify(|w| {
917 w.set_sshift(match config.sample_shifting {
918 true => vals::SampleShift::HALFCYCLE,
919 false => vals::SampleShift::NONE,
920 });
921 w.set_dhqc(config.delay_hold_quarter_cycle);
922 });
923
924 // Enable peripheral
925 T::REGS.cr().modify(|w| {
926 w.set_en(true);
927 });
928
929 // Free running clock needs to be set after peripheral enable
930 if config.free_running_clock {
931 T::REGS.dcr1().modify(|w| {
932 w.set_frck(config.free_running_clock);
933 });
934 }
935
936 self.config = *config;
937 }
938
939 /// Get current configuration
940 pub fn get_config(&self) -> Config {
941 self.config
942 }
943} 1000}
944 1001
945impl<'d, T: Instance, Dma> Drop for Ospi<'d, T, Dma> { 1002impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> {
946 fn drop(&mut self) { 1003 fn drop(&mut self) {
947 self.sck.as_ref().map(|x| x.set_as_disconnected()); 1004 self.sck.as_ref().map(|x| x.set_as_disconnected());
948 self.d0.as_ref().map(|x| x.set_as_disconnected()); 1005 self.d0.as_ref().map(|x| x.set_as_disconnected());
@@ -1005,7 +1062,7 @@ foreach_peripheral!(
1005 }; 1062 };
1006); 1063);
1007 1064
1008impl<'d, T: Instance, Dma> SetConfig for Ospi<'d, T, Dma> { 1065impl<'d, T: Instance, M: PeriMode> SetConfig for Ospi<'d, T, M> {
1009 type Config = Config; 1066 type Config = Config;
1010 type ConfigError = (); 1067 type ConfigError = ();
1011 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1068 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
@@ -1014,7 +1071,7 @@ impl<'d, T: Instance, Dma> SetConfig for Ospi<'d, T, Dma> {
1014 } 1071 }
1015} 1072}
1016 1073
1017impl<'d, T: Instance, Dma> GetConfig for Ospi<'d, T, Dma> { 1074impl<'d, T: Instance, M: PeriMode> GetConfig for Ospi<'d, T, M> {
1018 type Config = Config; 1075 type Config = Config;
1019 fn get_config(&self) -> Self::Config { 1076 fn get_config(&self) -> Self::Config {
1020 self.get_config() 1077 self.get_config()
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 0a4b4f074..a82e93b5b 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -4,11 +4,14 @@
4 4
5pub mod enums; 5pub mod enums;
6 6
7use core::marker::PhantomData;
8
7use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::{into_ref, PeripheralRef};
8use enums::*; 10use enums::*;
9 11
10use crate::dma::Transfer; 12use crate::dma::ChannelAndRequest;
11use crate::gpio::{AFType, AnyPin, Pull}; 13use crate::gpio::{AFType, AnyPin, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode};
12use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
13use crate::rcc::RccPeripheral; 16use crate::rcc::RccPeripheral;
14use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peripheral};
@@ -71,7 +74,7 @@ impl Default for Config {
71 74
72/// QSPI driver. 75/// QSPI driver.
73#[allow(dead_code)] 76#[allow(dead_code)]
74pub struct Qspi<'d, T: Instance, Dma> { 77pub struct Qspi<'d, T: Instance, M: PeriMode> {
75 _peri: PeripheralRef<'d, T>, 78 _peri: PeripheralRef<'d, T>,
76 sck: Option<PeripheralRef<'d, AnyPin>>, 79 sck: Option<PeripheralRef<'d, AnyPin>>,
77 d0: Option<PeripheralRef<'d, AnyPin>>, 80 d0: Option<PeripheralRef<'d, AnyPin>>,
@@ -79,93 +82,12 @@ pub struct Qspi<'d, T: Instance, Dma> {
79 d2: Option<PeripheralRef<'d, AnyPin>>, 82 d2: Option<PeripheralRef<'d, AnyPin>>,
80 d3: Option<PeripheralRef<'d, AnyPin>>, 83 d3: Option<PeripheralRef<'d, AnyPin>>,
81 nss: Option<PeripheralRef<'d, AnyPin>>, 84 nss: Option<PeripheralRef<'d, AnyPin>>,
82 dma: PeripheralRef<'d, Dma>, 85 dma: Option<ChannelAndRequest<'d>>,
86 _phantom: PhantomData<M>,
83 config: Config, 87 config: Config,
84} 88}
85 89
86impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 90impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
87 /// Create a new QSPI driver for bank 1.
88 pub fn new_bk1(
89 peri: impl Peripheral<P = T> + 'd,
90 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
91 d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd,
92 d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd,
93 d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd,
94 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
95 nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd,
96 dma: impl Peripheral<P = Dma> + 'd,
97 config: Config,
98 ) -> Self {
99 into_ref!(peri, d0, d1, d2, d3, sck, nss);
100
101 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
102 sck.set_speed(crate::gpio::Speed::VeryHigh);
103 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
104 nss.set_speed(crate::gpio::Speed::VeryHigh);
105 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
106 d0.set_speed(crate::gpio::Speed::VeryHigh);
107 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
108 d1.set_speed(crate::gpio::Speed::VeryHigh);
109 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
110 d2.set_speed(crate::gpio::Speed::VeryHigh);
111 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
112 d3.set_speed(crate::gpio::Speed::VeryHigh);
113
114 Self::new_inner(
115 peri,
116 Some(d0.map_into()),
117 Some(d1.map_into()),
118 Some(d2.map_into()),
119 Some(d3.map_into()),
120 Some(sck.map_into()),
121 Some(nss.map_into()),
122 dma,
123 config,
124 FlashSelection::Flash1,
125 )
126 }
127
128 /// Create a new QSPI driver for bank 2.
129 pub fn new_bk2(
130 peri: impl Peripheral<P = T> + 'd,
131 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
132 d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd,
133 d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd,
134 d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd,
135 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
136 nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd,
137 dma: impl Peripheral<P = Dma> + 'd,
138 config: Config,
139 ) -> Self {
140 into_ref!(peri, d0, d1, d2, d3, sck, nss);
141
142 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
143 sck.set_speed(crate::gpio::Speed::VeryHigh);
144 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
145 nss.set_speed(crate::gpio::Speed::VeryHigh);
146 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
147 d0.set_speed(crate::gpio::Speed::VeryHigh);
148 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
149 d1.set_speed(crate::gpio::Speed::VeryHigh);
150 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
151 d2.set_speed(crate::gpio::Speed::VeryHigh);
152 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
153 d3.set_speed(crate::gpio::Speed::VeryHigh);
154
155 Self::new_inner(
156 peri,
157 Some(d0.map_into()),
158 Some(d1.map_into()),
159 Some(d2.map_into()),
160 Some(d3.map_into()),
161 Some(sck.map_into()),
162 Some(nss.map_into()),
163 dma,
164 config,
165 FlashSelection::Flash2,
166 )
167 }
168
169 fn new_inner( 91 fn new_inner(
170 peri: impl Peripheral<P = T> + 'd, 92 peri: impl Peripheral<P = T> + 'd,
171 d0: Option<PeripheralRef<'d, AnyPin>>, 93 d0: Option<PeripheralRef<'d, AnyPin>>,
@@ -174,11 +96,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
174 d3: Option<PeripheralRef<'d, AnyPin>>, 96 d3: Option<PeripheralRef<'d, AnyPin>>,
175 sck: Option<PeripheralRef<'d, AnyPin>>, 97 sck: Option<PeripheralRef<'d, AnyPin>>,
176 nss: Option<PeripheralRef<'d, AnyPin>>, 98 nss: Option<PeripheralRef<'d, AnyPin>>,
177 dma: impl Peripheral<P = Dma> + 'd, 99 dma: Option<ChannelAndRequest<'d>>,
178 config: Config, 100 config: Config,
179 fsel: FlashSelection, 101 fsel: FlashSelection,
180 ) -> Self { 102 ) -> Self {
181 into_ref!(peri, dma); 103 into_ref!(peri);
182 104
183 T::enable_and_reset(); 105 T::enable_and_reset();
184 106
@@ -220,6 +142,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
220 d3, 142 d3,
221 nss, 143 nss,
222 dma, 144 dma,
145 _phantom: PhantomData,
223 config, 146 config,
224 } 147 }
225 } 148 }
@@ -278,11 +201,146 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
278 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 201 T::REGS.fcr().modify(|v| v.set_ctcf(true));
279 } 202 }
280 203
204 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) {
205 T::REGS.fcr().modify(|v| {
206 v.set_csmf(true);
207 v.set_ctcf(true);
208 v.set_ctef(true);
209 v.set_ctof(true);
210 });
211
212 while T::REGS.sr().read().busy() {}
213
214 if let Some(len) = data_len {
215 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
216 }
217
218 T::REGS.ccr().write(|v| {
219 v.set_fmode(fmode.into());
220 v.set_imode(transaction.iwidth.into());
221 v.set_instruction(transaction.instruction);
222 v.set_admode(transaction.awidth.into());
223 v.set_adsize(self.config.address_size.into());
224 v.set_dmode(transaction.dwidth.into());
225 v.set_abmode(QspiWidth::NONE.into());
226 v.set_dcyc(transaction.dummy.into());
227 });
228
229 if let Some(addr) = transaction.address {
230 T::REGS.ar().write(|v| {
231 v.set_address(addr);
232 });
233 }
234 }
235}
236
237impl<'d, T: Instance> Qspi<'d, T, Blocking> {
238 /// Create a new QSPI driver for bank 1, in blocking mode.
239 pub fn new_blocking_bank1(
240 peri: impl Peripheral<P = T> + 'd,
241 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
242 d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd,
243 d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd,
244 d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd,
245 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
246 nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd,
247 config: Config,
248 ) -> Self {
249 Self::new_inner(
250 peri,
251 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
252 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
253 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
254 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
255 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
256 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
257 None,
258 config,
259 FlashSelection::Flash1,
260 )
261 }
262
263 /// Create a new QSPI driver for bank 2, in blocking mode.
264 pub fn new_blocking_bank2(
265 peri: impl Peripheral<P = T> + 'd,
266 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
267 d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd,
268 d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd,
269 d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd,
270 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
271 nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd,
272 config: Config,
273 ) -> Self {
274 Self::new_inner(
275 peri,
276 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
277 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
278 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
279 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
280 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
281 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
282 None,
283 config,
284 FlashSelection::Flash2,
285 )
286 }
287}
288
289impl<'d, T: Instance> Qspi<'d, T, Async> {
290 /// Create a new QSPI driver for bank 1.
291 pub fn new_bank1(
292 peri: impl Peripheral<P = T> + 'd,
293 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
294 d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd,
295 d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd,
296 d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd,
297 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
298 nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd,
299 dma: impl Peripheral<P = impl QuadDma<T>> + 'd,
300 config: Config,
301 ) -> Self {
302 Self::new_inner(
303 peri,
304 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
305 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
306 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
307 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
308 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
309 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
310 new_dma!(dma),
311 config,
312 FlashSelection::Flash1,
313 )
314 }
315
316 /// Create a new QSPI driver for bank 2.
317 pub fn new_bank2(
318 peri: impl Peripheral<P = T> + 'd,
319 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
320 d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd,
321 d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd,
322 d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd,
323 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
324 nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd,
325 dma: impl Peripheral<P = impl QuadDma<T>> + 'd,
326 config: Config,
327 ) -> Self {
328 Self::new_inner(
329 peri,
330 new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh),
331 new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh),
332 new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh),
333 new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh),
334 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh),
335 new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up),
336 new_dma!(dma),
337 config,
338 FlashSelection::Flash2,
339 )
340 }
341
281 /// Blocking read data, using DMA. 342 /// Blocking read data, using DMA.
282 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 343 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) {
283 where
284 Dma: QuadDma<T>,
285 {
286 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); 344 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
287 345
288 T::REGS.ccr().modify(|v| { 346 T::REGS.ccr().modify(|v| {
@@ -293,15 +351,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
293 v.set_address(current_ar); 351 v.set_address(current_ar);
294 }); 352 });
295 353
296 let request = self.dma.request();
297 let transfer = unsafe { 354 let transfer = unsafe {
298 Transfer::new_read( 355 self.dma
299 &mut self.dma, 356 .as_mut()
300 request, 357 .unwrap()
301 T::REGS.dr().as_ptr() as *mut u8, 358 .read(T::REGS.dr().as_ptr() as *mut u8, buf, Default::default())
302 buf,
303 Default::default(),
304 )
305 }; 359 };
306 360
307 // STM32H7 does not have dmaen 361 // STM32H7 does not have dmaen
@@ -312,25 +366,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
312 } 366 }
313 367
314 /// Blocking write data, using DMA. 368 /// Blocking write data, using DMA.
315 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 369 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) {
316 where
317 Dma: QuadDma<T>,
318 {
319 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); 370 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
320 371
321 T::REGS.ccr().modify(|v| { 372 T::REGS.ccr().modify(|v| {
322 v.set_fmode(QspiMode::IndirectWrite.into()); 373 v.set_fmode(QspiMode::IndirectWrite.into());
323 }); 374 });
324 375
325 let request = self.dma.request();
326 let transfer = unsafe { 376 let transfer = unsafe {
327 Transfer::new_write( 377 self.dma
328 &mut self.dma, 378 .as_mut()
329 request, 379 .unwrap()
330 buf, 380 .write(buf, T::REGS.dr().as_ptr() as *mut u8, Default::default())
331 T::REGS.dr().as_ptr() as *mut u8,
332 Default::default(),
333 )
334 }; 381 };
335 382
336 // STM32H7 does not have dmaen 383 // STM32H7 does not have dmaen
@@ -339,38 +386,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
339 386
340 transfer.blocking_wait(); 387 transfer.blocking_wait();
341 } 388 }
342
343 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) {
344 T::REGS.fcr().modify(|v| {
345 v.set_csmf(true);
346 v.set_ctcf(true);
347 v.set_ctef(true);
348 v.set_ctof(true);
349 });
350
351 while T::REGS.sr().read().busy() {}
352
353 if let Some(len) = data_len {
354 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
355 }
356
357 T::REGS.ccr().write(|v| {
358 v.set_fmode(fmode.into());
359 v.set_imode(transaction.iwidth.into());
360 v.set_instruction(transaction.instruction);
361 v.set_admode(transaction.awidth.into());
362 v.set_adsize(self.config.address_size.into());
363 v.set_dmode(transaction.dwidth.into());
364 v.set_abmode(QspiWidth::NONE.into());
365 v.set_dcyc(transaction.dummy.into());
366 });
367
368 if let Some(addr) = transaction.address {
369 T::REGS.ar().write(|v| {
370 v.set_address(addr);
371 });
372 }
373 }
374} 389}
375 390
376trait SealedInstance { 391trait SealedInstance {
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index e3ee9a039..61f687d30 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -146,17 +146,18 @@ pub(crate) unsafe fn init(config: Config) {
146 while !PWR.csr1().read().odswrdy() {} 146 while !PWR.csr1().read().odswrdy() {}
147 } 147 }
148 148
149 // Turn on the HSI
150 RCC.cr().modify(|w| w.set_hsion(true));
151 while !RCC.cr().read().hsirdy() {}
152
153 // Use the HSI clock as system clock during the actual clock setup
154 RCC.cfgr().modify(|w| w.set_sw(Sysclk::HSI));
155 while RCC.cfgr().read().sws() != Sysclk::HSI {}
156
149 // Configure HSI 157 // Configure HSI
150 let hsi = match config.hsi { 158 let hsi = match config.hsi {
151 false => { 159 false => None,
152 RCC.cr().modify(|w| w.set_hsion(false)); 160 true => Some(HSI_FREQ),
153 None
154 }
155 true => {
156 RCC.cr().modify(|w| w.set_hsion(true));
157 while !RCC.cr().read().hsirdy() {}
158 Some(HSI_FREQ)
159 }
160 }; 161 };
161 162
162 // Configure HSE 163 // Configure HSE
@@ -260,6 +261,11 @@ pub(crate) unsafe fn init(config: Config) {
260 }); 261 });
261 while RCC.cfgr().read().sws() != config.sys {} 262 while RCC.cfgr().read().sws() != config.sys {}
262 263
264 // Disable HSI if not used
265 if !config.hsi {
266 RCC.cr().modify(|w| w.set_hsion(false));
267 }
268
263 config.mux.init(); 269 config.mux.init();
264 270
265 set_clocks!( 271 set_clocks!(
@@ -277,7 +283,7 @@ pub(crate) unsafe fn init(config: Config) {
277 pclk2_tim: Some(pclk2_tim), 283 pclk2_tim: Some(pclk2_tim),
278 rtc: rtc, 284 rtc: rtc,
279 pll1_q: pll.q, 285 pll1_q: pll.q,
280 pll1_r: None, // TODO 286 pll1_r: pll.r,
281 287
282 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] 288 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
283 plli2s1_p: plli2s.p, 289 plli2s1_p: plli2s.p,
@@ -297,11 +303,12 @@ pub(crate) unsafe fn init(config: Config) {
297 #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))] 303 #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
298 pllsai1_q: None, 304 pllsai1_q: None,
299 305
306 #[cfg(dsihost)]
307 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
308
300 hsi_div488: hsi.map(|hsi| hsi/488u32), 309 hsi_div488: hsi.map(|hsi| hsi/488u32),
301 hsi_hse: None, 310 hsi_hse: None,
302 afif: None, 311 afif: None,
303 #[cfg(any(stm32f4, stm32f7))]
304 dsi_phy: None, // TODO
305 ); 312 );
306} 313}
307 314
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 5d47d400c..4d7004872 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -677,11 +677,12 @@ pub(crate) unsafe fn init(config: Config) {
677 #[cfg(rcc_h50)] 677 #[cfg(rcc_h50)]
678 pll3_r: None, 678 pll3_r: None,
679 679
680 #[cfg(dsihost)]
681 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
682
680 #[cfg(stm32h5)] 683 #[cfg(stm32h5)]
681 audioclk: None, 684 audioclk: None,
682 i2s_ckin: None, 685 i2s_ckin: None,
683 #[cfg(any(stm32h7, stm32h7rs))]
684 dsi_phy: None, // TODO
685 #[cfg(stm32h7rs)] 686 #[cfg(stm32h7rs)]
686 spdifrx_symb: None, // TODO 687 spdifrx_symb: None, // TODO
687 #[cfg(stm32h7rs)] 688 #[cfg(stm32h7rs)]
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index c625948fb..e9266c65b 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -159,6 +159,13 @@ pub(crate) unsafe fn init(config: Config) {
159 while RCC.cfgr().read().sws() != Sysclk::MSI {} 159 while RCC.cfgr().read().sws() != Sysclk::MSI {}
160 } 160 }
161 161
162 #[cfg(stm32wl)]
163 {
164 // Set max latency
165 FLASH.acr().modify(|w| w.set_prften(true));
166 FLASH.acr().modify(|w| w.set_latency(2));
167 }
168
162 // Set voltage scale 169 // Set voltage scale
163 #[cfg(any(stm32l0, stm32l1))] 170 #[cfg(any(stm32l0, stm32l1))]
164 { 171 {
@@ -413,6 +420,9 @@ pub(crate) unsafe fn init(config: Config) {
413 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] 420 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
414 pllsai2_r: pllsai2.r, 421 pllsai2_r: pllsai2.r,
415 422
423 #[cfg(dsihost)]
424 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
425
416 rtc: rtc, 426 rtc: rtc,
417 427
418 // TODO 428 // TODO
@@ -420,8 +430,6 @@ pub(crate) unsafe fn init(config: Config) {
420 sai2_extclk: None, 430 sai2_extclk: None,
421 lsi: None, 431 lsi: None,
422 lse: None, 432 lse: None,
423 #[cfg(stm32l4)]
424 dsi_phy: None,
425 ); 433 );
426} 434}
427 435
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index a585940bc..28816256c 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -31,6 +31,7 @@ pub use hsi48::*;
31mod _version; 31mod _version;
32 32
33pub use _version::*; 33pub use _version::*;
34use stm32_metapac::RCC;
34 35
35pub use crate::_generated::{mux, Clocks}; 36pub use crate::_generated::{mux, Clocks};
36use crate::time::Hertz; 37use crate::time::Hertz;
@@ -66,7 +67,9 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
66} 67}
67 68
68pub(crate) trait SealedRccPeripheral { 69pub(crate) trait SealedRccPeripheral {
69 fn frequency() -> crate::time::Hertz; 70 const ENABLE_BIT: ClockEnableBit;
71
72 fn frequency() -> Hertz;
70 fn enable_and_reset_with_cs(cs: CriticalSection); 73 fn enable_and_reset_with_cs(cs: CriticalSection);
71 fn disable_with_cs(cs: CriticalSection); 74 fn disable_with_cs(cs: CriticalSection);
72 75
@@ -137,3 +140,49 @@ pub unsafe fn enable_and_reset<T: RccPeripheral>() {
137pub unsafe fn disable<T: RccPeripheral>() { 140pub unsafe fn disable<T: RccPeripheral>() {
138 T::disable(); 141 T::disable();
139} 142}
143
144/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime.
145#[derive(Clone, Copy)]
146pub(crate) struct ClockEnableBit {
147 /// offset in 32bit words of the xxxENR register into the RCC register block.
148 offset: u8,
149 /// bit within the register (0..=31)
150 bit: u8,
151}
152
153impl ClockEnableBit {
154 /// Safety: offset+bit must correspond to a valid xxxEN bit.
155 pub(crate) const unsafe fn new(offset: u8, bit: u8) -> Self {
156 Self { offset, bit }
157 }
158
159 fn ptr(self) -> *mut u32 {
160 unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) }
161 }
162
163 #[allow(unused)]
164 pub(crate) fn enable_with_cs(self, _cs: CriticalSection) {
165 let p = self.ptr();
166 unsafe {
167 let val = p.read_volatile();
168 p.write_volatile(val | 1u32 << self.bit);
169 }
170 }
171
172 pub(crate) fn disable_with_cs(self, _cs: CriticalSection) {
173 let p = self.ptr();
174 unsafe {
175 let val = p.read_volatile();
176 p.write_volatile(val & !(1u32 << self.bit));
177 }
178 }
179
180 #[allow(unused)]
181 pub(crate) fn enable(self) {
182 critical_section::with(|cs| self.enable_with_cs(cs))
183 }
184
185 pub(crate) fn disable(self) {
186 critical_section::with(|cs| self.disable_with_cs(cs))
187 }
188}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 4013d0a46..d6331f512 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -289,6 +289,9 @@ pub(crate) unsafe fn init(config: Config) {
289 pll3_q: pll3.q, 289 pll3_q: pll3.q,
290 pll3_r: pll3.r, 290 pll3_r: pll3.r,
291 291
292 #[cfg(dsihost)]
293 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
294
292 // TODO 295 // TODO
293 audioclk: None, 296 audioclk: None,
294 hsi48_div_2: None, 297 hsi48_div_2: None,
@@ -297,7 +300,6 @@ pub(crate) unsafe fn init(config: Config) {
297 msik: None, 300 msik: None,
298 shsi: None, 301 shsi: None,
299 shsi_div_2: None, 302 shsi_div_2: None,
300 dsi_phy: None,
301 ); 303 );
302} 304}
303 305
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 24159adce..be8cfcecf 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,16 +6,16 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::PeripheralRef;
10pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 10pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
11 11
12use crate::dma::{slice_ptr_parts, word, ChannelAndRequest}; 12use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{regs, vals, Spi as Regs};
16use crate::rcc::RccPeripheral; 16use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{peripherals, Peripheral}; 18use crate::Peripheral;
19 19
20/// SPI error. 20/// SPI error.
21#[derive(Debug, PartialEq, Eq)] 21#[derive(Debug, PartialEq, Eq)]
@@ -98,8 +98,9 @@ impl Config {
98 } 98 }
99} 99}
100/// SPI driver. 100/// SPI driver.
101pub struct Spi<'d, T: Instance, M: PeriMode> { 101pub struct Spi<'d, M: PeriMode> {
102 _peri: PeripheralRef<'d, T>, 102 pub(crate) info: &'static Info,
103 kernel_clock: Hertz,
103 sck: Option<PeripheralRef<'d, AnyPin>>, 104 sck: Option<PeripheralRef<'d, AnyPin>>,
104 mosi: Option<PeripheralRef<'d, AnyPin>>, 105 mosi: Option<PeripheralRef<'d, AnyPin>>,
105 miso: Option<PeripheralRef<'d, AnyPin>>, 106 miso: Option<PeripheralRef<'d, AnyPin>>,
@@ -109,9 +110,9 @@ pub struct Spi<'d, T: Instance, M: PeriMode> {
109 current_word_size: word_impl::Config, 110 current_word_size: word_impl::Config,
110} 111}
111 112
112impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { 113impl<'d, M: PeriMode> Spi<'d, M> {
113 fn new_inner( 114 fn new_inner<T: Instance>(
114 peri: impl Peripheral<P = T> + 'd, 115 _peri: impl Peripheral<P = T> + 'd,
115 sck: Option<PeripheralRef<'d, AnyPin>>, 116 sck: Option<PeripheralRef<'d, AnyPin>>,
116 mosi: Option<PeripheralRef<'d, AnyPin>>, 117 mosi: Option<PeripheralRef<'d, AnyPin>>,
117 miso: Option<PeripheralRef<'d, AnyPin>>, 118 miso: Option<PeripheralRef<'d, AnyPin>>,
@@ -119,11 +120,9 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
119 rx_dma: Option<ChannelAndRequest<'d>>, 120 rx_dma: Option<ChannelAndRequest<'d>>,
120 config: Config, 121 config: Config,
121 ) -> Self { 122 ) -> Self {
122 into_ref!(peri); 123 let regs = T::info().regs;
123 124 let kernel_clock = T::frequency();
124 let pclk = T::frequency(); 125 let br = compute_baud_rate(kernel_clock, config.frequency);
125 let freq = config.frequency;
126 let br = compute_baud_rate(pclk, freq);
127 126
128 let cpha = config.raw_phase(); 127 let cpha = config.raw_phase();
129 let cpol = config.raw_polarity(); 128 let cpol = config.raw_polarity();
@@ -134,10 +133,10 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
134 133
135 #[cfg(any(spi_v1, spi_f1))] 134 #[cfg(any(spi_v1, spi_f1))]
136 { 135 {
137 T::REGS.cr2().modify(|w| { 136 regs.cr2().modify(|w| {
138 w.set_ssoe(false); 137 w.set_ssoe(false);
139 }); 138 });
140 T::REGS.cr1().modify(|w| { 139 regs.cr1().modify(|w| {
141 w.set_cpha(cpha); 140 w.set_cpha(cpha);
142 w.set_cpol(cpol); 141 w.set_cpol(cpol);
143 142
@@ -157,13 +156,13 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
157 } 156 }
158 #[cfg(spi_v2)] 157 #[cfg(spi_v2)]
159 { 158 {
160 T::REGS.cr2().modify(|w| { 159 regs.cr2().modify(|w| {
161 let (ds, frxth) = <u8 as SealedWord>::CONFIG; 160 let (ds, frxth) = <u8 as SealedWord>::CONFIG;
162 w.set_frxth(frxth); 161 w.set_frxth(frxth);
163 w.set_ds(ds); 162 w.set_ds(ds);
164 w.set_ssoe(false); 163 w.set_ssoe(false);
165 }); 164 });
166 T::REGS.cr1().modify(|w| { 165 regs.cr1().modify(|w| {
167 w.set_cpha(cpha); 166 w.set_cpha(cpha);
168 w.set_cpol(cpol); 167 w.set_cpol(cpol);
169 168
@@ -179,8 +178,8 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
179 } 178 }
180 #[cfg(any(spi_v3, spi_v4, spi_v5))] 179 #[cfg(any(spi_v3, spi_v4, spi_v5))]
181 { 180 {
182 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); 181 regs.ifcr().write(|w| w.0 = 0xffff_ffff);
183 T::REGS.cfg2().modify(|w| { 182 regs.cfg2().modify(|w| {
184 //w.set_ssoe(true); 183 //w.set_ssoe(true);
185 w.set_ssoe(false); 184 w.set_ssoe(false);
186 w.set_cpha(cpha); 185 w.set_cpha(cpha);
@@ -195,23 +194,24 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
195 w.set_afcntr(true); 194 w.set_afcntr(true);
196 w.set_ssiop(vals::Ssiop::ACTIVEHIGH); 195 w.set_ssiop(vals::Ssiop::ACTIVEHIGH);
197 }); 196 });
198 T::REGS.cfg1().modify(|w| { 197 regs.cfg1().modify(|w| {
199 w.set_crcen(false); 198 w.set_crcen(false);
200 w.set_mbr(br); 199 w.set_mbr(br);
201 w.set_dsize(<u8 as SealedWord>::CONFIG); 200 w.set_dsize(<u8 as SealedWord>::CONFIG);
202 w.set_fthlv(vals::Fthlv::ONEFRAME); 201 w.set_fthlv(vals::Fthlv::ONEFRAME);
203 }); 202 });
204 T::REGS.cr2().modify(|w| { 203 regs.cr2().modify(|w| {
205 w.set_tsize(0); 204 w.set_tsize(0);
206 }); 205 });
207 T::REGS.cr1().modify(|w| { 206 regs.cr1().modify(|w| {
208 w.set_ssi(false); 207 w.set_ssi(false);
209 w.set_spe(true); 208 w.set_spe(true);
210 }); 209 });
211 } 210 }
212 211
213 Self { 212 Self {
214 _peri: peri, 213 info: T::info(),
214 kernel_clock,
215 sck, 215 sck,
216 mosi, 216 mosi,
217 miso, 217 miso,
@@ -229,12 +229,10 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
229 229
230 let lsbfirst = config.raw_byte_order(); 230 let lsbfirst = config.raw_byte_order();
231 231
232 let pclk = T::frequency(); 232 let br = compute_baud_rate(self.kernel_clock, config.frequency);
233 let freq = config.frequency;
234 let br = compute_baud_rate(pclk, freq);
235 233
236 #[cfg(any(spi_v1, spi_f1, spi_v2))] 234 #[cfg(any(spi_v1, spi_f1, spi_v2))]
237 T::REGS.cr1().modify(|w| { 235 self.info.regs.cr1().modify(|w| {
238 w.set_cpha(cpha); 236 w.set_cpha(cpha);
239 w.set_cpol(cpol); 237 w.set_cpol(cpol);
240 w.set_br(br); 238 w.set_br(br);
@@ -243,12 +241,12 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
243 241
244 #[cfg(any(spi_v3, spi_v4, spi_v5))] 242 #[cfg(any(spi_v3, spi_v4, spi_v5))]
245 { 243 {
246 T::REGS.cfg2().modify(|w| { 244 self.info.regs.cfg2().modify(|w| {
247 w.set_cpha(cpha); 245 w.set_cpha(cpha);
248 w.set_cpol(cpol); 246 w.set_cpol(cpol);
249 w.set_lsbfirst(lsbfirst); 247 w.set_lsbfirst(lsbfirst);
250 }); 248 });
251 T::REGS.cfg1().modify(|w| { 249 self.info.regs.cfg1().modify(|w| {
252 w.set_mbr(br); 250 w.set_mbr(br);
253 }); 251 });
254 } 252 }
@@ -258,11 +256,11 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
258 /// Get current SPI configuration. 256 /// Get current SPI configuration.
259 pub fn get_current_config(&self) -> Config { 257 pub fn get_current_config(&self) -> Config {
260 #[cfg(any(spi_v1, spi_f1, spi_v2))] 258 #[cfg(any(spi_v1, spi_f1, spi_v2))]
261 let cfg = T::REGS.cr1().read(); 259 let cfg = self.info.regs.cr1().read();
262 #[cfg(any(spi_v3, spi_v4, spi_v5))] 260 #[cfg(any(spi_v3, spi_v4, spi_v5))]
263 let cfg = T::REGS.cfg2().read(); 261 let cfg = self.info.regs.cfg2().read();
264 #[cfg(any(spi_v3, spi_v4, spi_v5))] 262 #[cfg(any(spi_v3, spi_v4, spi_v5))]
265 let cfg1 = T::REGS.cfg1().read(); 263 let cfg1 = self.info.regs.cfg1().read();
266 264
267 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { 265 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
268 Polarity::IdleLow 266 Polarity::IdleLow
@@ -297,8 +295,7 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
297 #[cfg(any(spi_v3, spi_v4, spi_v5))] 295 #[cfg(any(spi_v3, spi_v4, spi_v5))]
298 let br = cfg1.mbr(); 296 let br = cfg1.mbr();
299 297
300 let pclk = T::frequency(); 298 let frequency = compute_frequency(self.kernel_clock, br);
301 let frequency = compute_frequency(pclk, br);
302 299
303 Config { 300 Config {
304 mode: Mode { polarity, phase }, 301 mode: Mode { polarity, phase },
@@ -315,40 +312,40 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
315 312
316 #[cfg(any(spi_v1, spi_f1))] 313 #[cfg(any(spi_v1, spi_f1))]
317 { 314 {
318 T::REGS.cr1().modify(|reg| { 315 self.info.regs.cr1().modify(|reg| {
319 reg.set_spe(false); 316 reg.set_spe(false);
320 reg.set_dff(word_size) 317 reg.set_dff(word_size)
321 }); 318 });
322 T::REGS.cr1().modify(|reg| { 319 self.info.regs.cr1().modify(|reg| {
323 reg.set_spe(true); 320 reg.set_spe(true);
324 }); 321 });
325 } 322 }
326 #[cfg(spi_v2)] 323 #[cfg(spi_v2)]
327 { 324 {
328 T::REGS.cr1().modify(|w| { 325 self.info.regs.cr1().modify(|w| {
329 w.set_spe(false); 326 w.set_spe(false);
330 }); 327 });
331 T::REGS.cr2().modify(|w| { 328 self.info.regs.cr2().modify(|w| {
332 w.set_frxth(word_size.1); 329 w.set_frxth(word_size.1);
333 w.set_ds(word_size.0); 330 w.set_ds(word_size.0);
334 }); 331 });
335 T::REGS.cr1().modify(|w| { 332 self.info.regs.cr1().modify(|w| {
336 w.set_spe(true); 333 w.set_spe(true);
337 }); 334 });
338 } 335 }
339 #[cfg(any(spi_v3, spi_v4, spi_v5))] 336 #[cfg(any(spi_v3, spi_v4, spi_v5))]
340 { 337 {
341 T::REGS.cr1().modify(|w| { 338 self.info.regs.cr1().modify(|w| {
342 w.set_csusp(true); 339 w.set_csusp(true);
343 }); 340 });
344 while T::REGS.sr().read().eot() {} 341 while self.info.regs.sr().read().eot() {}
345 T::REGS.cr1().modify(|w| { 342 self.info.regs.cr1().modify(|w| {
346 w.set_spe(false); 343 w.set_spe(false);
347 }); 344 });
348 T::REGS.cfg1().modify(|w| { 345 self.info.regs.cfg1().modify(|w| {
349 w.set_dsize(word_size); 346 w.set_dsize(word_size);
350 }); 347 });
351 T::REGS.cr1().modify(|w| { 348 self.info.regs.cr1().modify(|w| {
352 w.set_csusp(false); 349 w.set_csusp(false);
353 w.set_spe(true); 350 w.set_spe(true);
354 }); 351 });
@@ -359,22 +356,22 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
359 356
360 /// Blocking write. 357 /// Blocking write.
361 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 358 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
362 T::REGS.cr1().modify(|w| w.set_spe(true)); 359 self.info.regs.cr1().modify(|w| w.set_spe(true));
363 flush_rx_fifo(T::REGS); 360 flush_rx_fifo(self.info.regs);
364 self.set_word_size(W::CONFIG); 361 self.set_word_size(W::CONFIG);
365 for word in words.iter() { 362 for word in words.iter() {
366 let _ = transfer_word(T::REGS, *word)?; 363 let _ = transfer_word(self.info.regs, *word)?;
367 } 364 }
368 Ok(()) 365 Ok(())
369 } 366 }
370 367
371 /// Blocking read. 368 /// Blocking read.
372 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 369 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
373 T::REGS.cr1().modify(|w| w.set_spe(true)); 370 self.info.regs.cr1().modify(|w| w.set_spe(true));
374 flush_rx_fifo(T::REGS); 371 flush_rx_fifo(self.info.regs);
375 self.set_word_size(W::CONFIG); 372 self.set_word_size(W::CONFIG);
376 for word in words.iter_mut() { 373 for word in words.iter_mut() {
377 *word = transfer_word(T::REGS, W::default())?; 374 *word = transfer_word(self.info.regs, W::default())?;
378 } 375 }
379 Ok(()) 376 Ok(())
380 } 377 }
@@ -383,11 +380,11 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
383 /// 380 ///
384 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 381 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
385 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 382 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
386 T::REGS.cr1().modify(|w| w.set_spe(true)); 383 self.info.regs.cr1().modify(|w| w.set_spe(true));
387 flush_rx_fifo(T::REGS); 384 flush_rx_fifo(self.info.regs);
388 self.set_word_size(W::CONFIG); 385 self.set_word_size(W::CONFIG);
389 for word in words.iter_mut() { 386 for word in words.iter_mut() {
390 *word = transfer_word(T::REGS, *word)?; 387 *word = transfer_word(self.info.regs, *word)?;
391 } 388 }
392 Ok(()) 389 Ok(())
393 } 390 }
@@ -399,13 +396,13 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
399 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 396 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
400 /// If `write` is shorter it is padded with zero bytes. 397 /// If `write` is shorter it is padded with zero bytes.
401 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 398 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
402 T::REGS.cr1().modify(|w| w.set_spe(true)); 399 self.info.regs.cr1().modify(|w| w.set_spe(true));
403 flush_rx_fifo(T::REGS); 400 flush_rx_fifo(self.info.regs);
404 self.set_word_size(W::CONFIG); 401 self.set_word_size(W::CONFIG);
405 let len = read.len().max(write.len()); 402 let len = read.len().max(write.len());
406 for i in 0..len { 403 for i in 0..len {
407 let wb = write.get(i).copied().unwrap_or_default(); 404 let wb = write.get(i).copied().unwrap_or_default();
408 let rb = transfer_word(T::REGS, wb)?; 405 let rb = transfer_word(self.info.regs, wb)?;
409 if let Some(r) = read.get_mut(i) { 406 if let Some(r) = read.get_mut(i) {
410 *r = rb; 407 *r = rb;
411 } 408 }
@@ -414,9 +411,9 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
414 } 411 }
415} 412}
416 413
417impl<'d, T: Instance> Spi<'d, T, Blocking> { 414impl<'d> Spi<'d, Blocking> {
418 /// Create a new blocking SPI driver. 415 /// Create a new blocking SPI driver.
419 pub fn new_blocking( 416 pub fn new_blocking<T: Instance>(
420 peri: impl Peripheral<P = T> + 'd, 417 peri: impl Peripheral<P = T> + 'd,
421 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 418 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
422 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 419 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -443,7 +440,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
443 } 440 }
444 441
445 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI). 442 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
446 pub fn new_blocking_rxonly( 443 pub fn new_blocking_rxonly<T: Instance>(
447 peri: impl Peripheral<P = T> + 'd, 444 peri: impl Peripheral<P = T> + 'd,
448 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 445 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
449 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 446 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
@@ -469,7 +466,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
469 } 466 }
470 467
471 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO). 468 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
472 pub fn new_blocking_txonly( 469 pub fn new_blocking_txonly<T: Instance>(
473 peri: impl Peripheral<P = T> + 'd, 470 peri: impl Peripheral<P = T> + 'd,
474 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 471 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
475 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 472 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -489,7 +486,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
489 /// Create a new SPI driver, in TX-only mode, without SCK pin. 486 /// Create a new SPI driver, in TX-only mode, without SCK pin.
490 /// 487 ///
491 /// This can be useful for bit-banging non-SPI protocols. 488 /// This can be useful for bit-banging non-SPI protocols.
492 pub fn new_blocking_txonly_nosck( 489 pub fn new_blocking_txonly_nosck<T: Instance>(
493 peri: impl Peripheral<P = T> + 'd, 490 peri: impl Peripheral<P = T> + 'd,
494 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 491 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
495 config: Config, 492 config: Config,
@@ -506,9 +503,9 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
506 } 503 }
507} 504}
508 505
509impl<'d, T: Instance> Spi<'d, T, Async> { 506impl<'d> Spi<'d, Async> {
510 /// Create a new SPI driver. 507 /// Create a new SPI driver.
511 pub fn new( 508 pub fn new<T: Instance>(
512 peri: impl Peripheral<P = T> + 'd, 509 peri: impl Peripheral<P = T> + 'd,
513 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 510 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
514 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 511 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -529,7 +526,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
529 } 526 }
530 527
531 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). 528 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
532 pub fn new_rxonly( 529 pub fn new_rxonly<T: Instance>(
533 peri: impl Peripheral<P = T> + 'd, 530 peri: impl Peripheral<P = T> + 'd,
534 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 531 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
535 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 532 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
@@ -548,7 +545,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
548 } 545 }
549 546
550 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). 547 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
551 pub fn new_txonly( 548 pub fn new_txonly<T: Instance>(
552 peri: impl Peripheral<P = T> + 'd, 549 peri: impl Peripheral<P = T> + 'd,
553 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 550 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
554 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 551 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -569,7 +566,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
569 /// Create a new SPI driver, in TX-only mode, without SCK pin. 566 /// Create a new SPI driver, in TX-only mode, without SCK pin.
570 /// 567 ///
571 /// This can be useful for bit-banging non-SPI protocols. 568 /// This can be useful for bit-banging non-SPI protocols.
572 pub fn new_txonly_nosck( 569 pub fn new_txonly_nosck<T: Instance>(
573 peri: impl Peripheral<P = T> + 'd, 570 peri: impl Peripheral<P = T> + 'd,
574 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 571 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
575 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 572 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
@@ -588,7 +585,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
588 585
589 #[cfg(stm32wl)] 586 #[cfg(stm32wl)]
590 /// Useful for on chip peripherals like SUBGHZ which are hardwired. 587 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
591 pub fn new_subghz( 588 pub fn new_subghz<T: Instance>(
592 peri: impl Peripheral<P = T> + 'd, 589 peri: impl Peripheral<P = T> + 'd,
593 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 590 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
594 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 591 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
@@ -596,7 +593,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
596 // see RM0453 rev 1 section 7.2.13 page 291 593 // see RM0453 rev 1 section 7.2.13 page 291
597 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. 594 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
598 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. 595 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
599 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0; 596 let pclk3_freq = <crate::peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
600 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); 597 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
601 let mut config = Config::default(); 598 let mut config = Config::default();
602 config.mode = MODE_0; 599 config.mode = MODE_0;
@@ -607,7 +604,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
607 } 604 }
608 605
609 #[allow(dead_code)] 606 #[allow(dead_code)]
610 pub(crate) fn new_internal( 607 pub(crate) fn new_internal<T: Instance>(
611 peri: impl Peripheral<P = T> + 'd, 608 peri: impl Peripheral<P = T> + 'd,
612 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 609 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
613 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 610 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
@@ -623,25 +620,25 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
623 } 620 }
624 621
625 self.set_word_size(W::CONFIG); 622 self.set_word_size(W::CONFIG);
626 T::REGS.cr1().modify(|w| { 623 self.info.regs.cr1().modify(|w| {
627 w.set_spe(false); 624 w.set_spe(false);
628 }); 625 });
629 626
630 let tx_dst = T::REGS.tx_ptr(); 627 let tx_dst = self.info.regs.tx_ptr();
631 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; 628 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
632 629
633 set_txdmaen(T::REGS, true); 630 set_txdmaen(self.info.regs, true);
634 T::REGS.cr1().modify(|w| { 631 self.info.regs.cr1().modify(|w| {
635 w.set_spe(true); 632 w.set_spe(true);
636 }); 633 });
637 #[cfg(any(spi_v3, spi_v4, spi_v5))] 634 #[cfg(any(spi_v3, spi_v4, spi_v5))]
638 T::REGS.cr1().modify(|w| { 635 self.info.regs.cr1().modify(|w| {
639 w.set_cstart(true); 636 w.set_cstart(true);
640 }); 637 });
641 638
642 tx_f.await; 639 tx_f.await;
643 640
644 finish_dma(T::REGS); 641 finish_dma(self.info.regs);
645 642
646 Ok(()) 643 Ok(())
647 } 644 }
@@ -653,22 +650,22 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
653 } 650 }
654 651
655 self.set_word_size(W::CONFIG); 652 self.set_word_size(W::CONFIG);
656 T::REGS.cr1().modify(|w| { 653 self.info.regs.cr1().modify(|w| {
657 w.set_spe(false); 654 w.set_spe(false);
658 }); 655 });
659 656
660 // SPIv3 clears rxfifo on SPE=0 657 // SPIv3 clears rxfifo on SPE=0
661 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 658 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
662 flush_rx_fifo(T::REGS); 659 flush_rx_fifo(self.info.regs);
663 660
664 set_rxdmaen(T::REGS, true); 661 set_rxdmaen(self.info.regs, true);
665 662
666 let clock_byte_count = data.len(); 663 let clock_byte_count = data.len();
667 664
668 let rx_src = T::REGS.rx_ptr(); 665 let rx_src = self.info.regs.rx_ptr();
669 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; 666 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
670 667
671 let tx_dst = T::REGS.tx_ptr(); 668 let tx_dst = self.info.regs.tx_ptr();
672 let clock_byte = 0x00u8; 669 let clock_byte = 0x00u8;
673 let tx_f = unsafe { 670 let tx_f = unsafe {
674 self.tx_dma 671 self.tx_dma
@@ -677,18 +674,18 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
677 .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default()) 674 .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
678 }; 675 };
679 676
680 set_txdmaen(T::REGS, true); 677 set_txdmaen(self.info.regs, true);
681 T::REGS.cr1().modify(|w| { 678 self.info.regs.cr1().modify(|w| {
682 w.set_spe(true); 679 w.set_spe(true);
683 }); 680 });
684 #[cfg(any(spi_v3, spi_v4, spi_v5))] 681 #[cfg(any(spi_v3, spi_v4, spi_v5))]
685 T::REGS.cr1().modify(|w| { 682 self.info.regs.cr1().modify(|w| {
686 w.set_cstart(true); 683 w.set_cstart(true);
687 }); 684 });
688 685
689 join(tx_f, rx_f).await; 686 join(tx_f, rx_f).await;
690 687
691 finish_dma(T::REGS); 688 finish_dma(self.info.regs);
692 689
693 Ok(()) 690 Ok(())
694 } 691 }
@@ -702,20 +699,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
702 } 699 }
703 700
704 self.set_word_size(W::CONFIG); 701 self.set_word_size(W::CONFIG);
705 T::REGS.cr1().modify(|w| { 702 self.info.regs.cr1().modify(|w| {
706 w.set_spe(false); 703 w.set_spe(false);
707 }); 704 });
708 705
709 // SPIv3 clears rxfifo on SPE=0 706 // SPIv3 clears rxfifo on SPE=0
710 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 707 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
711 flush_rx_fifo(T::REGS); 708 flush_rx_fifo(self.info.regs);
712 709
713 set_rxdmaen(T::REGS, true); 710 set_rxdmaen(self.info.regs, true);
714 711
715 let rx_src = T::REGS.rx_ptr(); 712 let rx_src = self.info.regs.rx_ptr();
716 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; 713 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
717 714
718 let tx_dst = T::REGS.tx_ptr(); 715 let tx_dst = self.info.regs.tx_ptr();
719 let tx_f = unsafe { 716 let tx_f = unsafe {
720 self.tx_dma 717 self.tx_dma
721 .as_mut() 718 .as_mut()
@@ -723,18 +720,18 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
723 .write_raw(write, tx_dst, Default::default()) 720 .write_raw(write, tx_dst, Default::default())
724 }; 721 };
725 722
726 set_txdmaen(T::REGS, true); 723 set_txdmaen(self.info.regs, true);
727 T::REGS.cr1().modify(|w| { 724 self.info.regs.cr1().modify(|w| {
728 w.set_spe(true); 725 w.set_spe(true);
729 }); 726 });
730 #[cfg(any(spi_v3, spi_v4, spi_v5))] 727 #[cfg(any(spi_v3, spi_v4, spi_v5))]
731 T::REGS.cr1().modify(|w| { 728 self.info.regs.cr1().modify(|w| {
732 w.set_cstart(true); 729 w.set_cstart(true);
733 }); 730 });
734 731
735 join(tx_f, rx_f).await; 732 join(tx_f, rx_f).await;
736 733
737 finish_dma(T::REGS); 734 finish_dma(self.info.regs);
738 735
739 Ok(()) 736 Ok(())
740 } 737 }
@@ -757,13 +754,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
757 } 754 }
758} 755}
759 756
760impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> { 757impl<'d, M: PeriMode> Drop for Spi<'d, M> {
761 fn drop(&mut self) { 758 fn drop(&mut self) {
762 self.sck.as_ref().map(|x| x.set_as_disconnected()); 759 self.sck.as_ref().map(|x| x.set_as_disconnected());
763 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 760 self.mosi.as_ref().map(|x| x.set_as_disconnected());
764 self.miso.as_ref().map(|x| x.set_as_disconnected()); 761 self.miso.as_ref().map(|x| x.set_as_disconnected());
765 762
766 T::disable(); 763 self.info.enable_bit.disable();
767 } 764 }
768} 765}
769 766
@@ -772,8 +769,8 @@ use vals::Br;
772#[cfg(any(spi_v3, spi_v4, spi_v5))] 769#[cfg(any(spi_v3, spi_v4, spi_v5))]
773use vals::Mbr as Br; 770use vals::Mbr as Br;
774 771
775fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { 772fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br {
776 let val = match clocks.0 / freq.0 { 773 let val = match kernel_clock.0 / freq.0 {
777 0 => panic!("You are trying to reach a frequency higher than the clock"), 774 0 => panic!("You are trying to reach a frequency higher than the clock"),
778 1..=2 => 0b000, 775 1..=2 => 0b000,
779 3..=5 => 0b001, 776 3..=5 => 0b001,
@@ -788,7 +785,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
788 Br::from_bits(val) 785 Br::from_bits(val)
789} 786}
790 787
791fn compute_frequency(clocks: Hertz, br: Br) -> Hertz { 788fn compute_frequency(kernel_clock: Hertz, br: Br) -> Hertz {
792 let div: u16 = match br { 789 let div: u16 = match br {
793 Br::DIV2 => 2, 790 Br::DIV2 => 2,
794 Br::DIV4 => 4, 791 Br::DIV4 => 4,
@@ -800,7 +797,7 @@ fn compute_frequency(clocks: Hertz, br: Br) -> Hertz {
800 Br::DIV256 => 256, 797 Br::DIV256 => 256,
801 }; 798 };
802 799
803 clocks / div 800 kernel_clock / div
804} 801}
805 802
806trait RegsExt { 803trait RegsExt {
@@ -975,7 +972,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
975// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 972// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
976macro_rules! impl_blocking { 973macro_rules! impl_blocking {
977 ($w:ident) => { 974 ($w:ident) => {
978 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> { 975 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> {
979 type Error = Error; 976 type Error = Error;
980 977
981 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 978 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -983,7 +980,7 @@ macro_rules! impl_blocking {
983 } 980 }
984 } 981 }
985 982
986 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> { 983 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> {
987 type Error = Error; 984 type Error = Error;
988 985
989 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 986 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -997,11 +994,11 @@ macro_rules! impl_blocking {
997impl_blocking!(u8); 994impl_blocking!(u8);
998impl_blocking!(u16); 995impl_blocking!(u16);
999 996
1000impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> { 997impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> {
1001 type Error = Error; 998 type Error = Error;
1002} 999}
1003 1000
1004impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, M> { 1001impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> {
1005 fn flush(&mut self) -> Result<(), Self::Error> { 1002 fn flush(&mut self) -> Result<(), Self::Error> {
1006 Ok(()) 1003 Ok(())
1007 } 1004 }
@@ -1034,7 +1031,7 @@ impl embedded_hal_1::spi::Error for Error {
1034 } 1031 }
1035} 1032}
1036 1033
1037impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Async> { 1034impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> {
1038 async fn flush(&mut self) -> Result<(), Self::Error> { 1035 async fn flush(&mut self) -> Result<(), Self::Error> {
1039 Ok(()) 1036 Ok(())
1040 } 1037 }
@@ -1056,10 +1053,6 @@ impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T,
1056 } 1053 }
1057} 1054}
1058 1055
1059pub(crate) trait SealedInstance {
1060 const REGS: Regs;
1061}
1062
1063trait SealedWord { 1056trait SealedWord {
1064 const CONFIG: word_impl::Config; 1057 const CONFIG: word_impl::Config;
1065} 1058}
@@ -1145,9 +1138,20 @@ mod word_impl {
1145 impl_word!(u32, 32 - 1); 1138 impl_word!(u32, 32 - 1);
1146} 1139}
1147 1140
1148/// SPI instance trait. 1141pub(crate) struct Info {
1149#[allow(private_bounds)] 1142 pub(crate) regs: Regs,
1150pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} 1143 pub(crate) enable_bit: ClockEnableBit,
1144}
1145
1146struct State {}
1147
1148impl State {
1149 const fn new() -> Self {
1150 Self {}
1151 }
1152}
1153
1154peri_trait!();
1151 1155
1152pin_trait!(SckPin, Instance); 1156pin_trait!(SckPin, Instance);
1153pin_trait!(MosiPin, Instance); 1157pin_trait!(MosiPin, Instance);
@@ -1161,15 +1165,14 @@ dma_trait!(TxDma, Instance);
1161 1165
1162foreach_peripheral!( 1166foreach_peripheral!(
1163 (spi, $inst:ident) => { 1167 (spi, $inst:ident) => {
1164 impl SealedInstance for peripherals::$inst { 1168 peri_trait_impl!($inst, Info {
1165 const REGS: Regs = crate::pac::$inst; 1169 regs: crate::pac::$inst,
1166 } 1170 enable_bit: crate::peripherals::$inst::ENABLE_BIT,
1167 1171 });
1168 impl Instance for peripherals::$inst {}
1169 }; 1172 };
1170); 1173);
1171 1174
1172impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> { 1175impl<'d, M: PeriMode> SetConfig for Spi<'d, M> {
1173 type Config = Config; 1176 type Config = Config;
1174 type ConfigError = (); 1177 type ConfigError = ();
1175 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1178 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
new file mode 100644
index 000000000..a1c1486f9
--- /dev/null
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -0,0 +1,233 @@
1//! Input capture driver.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{into_ref, PeripheralRef};
9
10use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer};
11use super::{
12 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin,
13 GeneralInstance4Channel,
14};
15use crate::gpio::{AFType, AnyPin, Pull};
16use crate::interrupt::typelevel::{Binding, Interrupt};
17use crate::time::Hertz;
18use crate::Peripheral;
19
20/// Channel 1 marker type.
21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
24/// Channel 3 marker type.
25pub enum Ch3 {}
26/// Channel 4 marker type.
27pub enum Ch4 {}
28
29/// Capture pin wrapper.
30///
31/// This wraps a pin to make it usable with capture.
32pub struct CapturePin<'d, T, C> {
33 _pin: PeripheralRef<'d, AnyPin>,
34 phantom: PhantomData<(T, C)>,
35}
36
37macro_rules! channel_impl {
38 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
39 impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> {
40 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")]
41 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull_type: Pull) -> Self {
42 into_ref!(pin);
43 critical_section::with(|_| {
44 pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
45 #[cfg(gpio_v2)]
46 pin.set_speed(crate::gpio::Speed::VeryHigh);
47 });
48 CapturePin {
49 _pin: pin.map_into(),
50 phantom: PhantomData,
51 }
52 }
53 }
54 };
55}
56
57channel_impl!(new_ch1, Ch1, Channel1Pin);
58channel_impl!(new_ch2, Ch2, Channel2Pin);
59channel_impl!(new_ch3, Ch3, Channel3Pin);
60channel_impl!(new_ch4, Ch4, Channel4Pin);
61
62/// Input capture driver.
63pub struct InputCapture<'d, T: GeneralInstance4Channel> {
64 inner: Timer<'d, T>,
65}
66
67impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
68 /// Create a new input capture driver.
69 pub fn new(
70 tim: impl Peripheral<P = T> + 'd,
71 _ch1: Option<CapturePin<'d, T, Ch1>>,
72 _ch2: Option<CapturePin<'d, T, Ch2>>,
73 _ch3: Option<CapturePin<'d, T, Ch3>>,
74 _ch4: Option<CapturePin<'d, T, Ch4>>,
75 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
76 freq: Hertz,
77 counting_mode: CountingMode,
78 ) -> Self {
79 Self::new_inner(tim, freq, counting_mode)
80 }
81
82 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
83 let mut this = Self { inner: Timer::new(tim) };
84
85 this.inner.set_counting_mode(counting_mode);
86 this.set_tick_freq(freq);
87 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
88 this.inner.start();
89
90 // enable NVIC interrupt
91 T::CaptureCompareInterrupt::unpend();
92 unsafe { T::CaptureCompareInterrupt::enable() };
93
94 this
95 }
96
97 /// Enable the given channel.
98 pub fn enable(&mut self, channel: Channel) {
99 self.inner.enable_channel(channel, true);
100 }
101
102 /// Disable the given channel.
103 pub fn disable(&mut self, channel: Channel) {
104 self.inner.enable_channel(channel, false);
105 }
106
107 /// Check whether given channel is enabled
108 pub fn is_enabled(&self, channel: Channel) -> bool {
109 self.inner.get_channel_enable_state(channel)
110 }
111
112 /// Set tick frequency.
113 ///
114 /// Note: when you call this, the max period value changes
115 pub fn set_tick_freq(&mut self, freq: Hertz) {
116 let f = freq;
117 assert!(f.0 > 0);
118 let timer_f = self.inner.get_clock_frequency();
119
120 let pclk_ticks_per_timer_period = timer_f / f;
121 let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
122
123 let regs = self.inner.regs_core();
124 regs.psc().write_value(psc);
125
126 // Generate an Update Request
127 regs.egr().write(|r| r.set_ug(true));
128 }
129
130 /// Set the input capture mode for a given channel.
131 pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
132 self.inner.set_input_capture_mode(channel, mode);
133 }
134
135 /// Set input TI selection.
136 pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
137 self.inner.set_input_ti_selection(channel, tisel)
138 }
139
140 /// Get capture value for a channel.
141 pub fn get_capture_value(&self, channel: Channel) -> u32 {
142 self.inner.get_capture_value(channel)
143 }
144
145 /// Get input interrupt.
146 pub fn get_input_interrupt(&self, channel: Channel) -> bool {
147 self.inner.get_input_interrupt(channel)
148 }
149
150 fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
151 self.inner.enable_channel(channel, true);
152 self.inner.set_input_capture_mode(channel, mode);
153 self.inner.set_input_ti_selection(channel, tisel);
154 self.inner.clear_input_interrupt(channel);
155 self.inner.enable_input_interrupt(channel, true);
156
157 InputCaptureFuture {
158 channel,
159 phantom: PhantomData,
160 }
161 }
162
163 /// Asynchronously wait until the pin sees a rising edge.
164 pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> u32 {
165 self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal)
166 .await
167 }
168
169 /// Asynchronously wait until the pin sees a falling edge.
170 pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> u32 {
171 self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal)
172 .await
173 }
174
175 /// Asynchronously wait until the pin sees any edge.
176 pub async fn wait_for_any_edge(&mut self, channel: Channel) -> u32 {
177 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal)
178 .await
179 }
180
181 /// Asynchronously wait until the (alternate) pin sees a rising edge.
182 pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> u32 {
183 self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate)
184 .await
185 }
186
187 /// Asynchronously wait until the (alternate) pin sees a falling edge.
188 pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> u32 {
189 self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate)
190 .await
191 }
192
193 /// Asynchronously wait until the (alternate) pin sees any edge.
194 pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> u32 {
195 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
196 .await
197 }
198}
199
200#[must_use = "futures do nothing unless you `.await` or poll them"]
201struct InputCaptureFuture<T: GeneralInstance4Channel> {
202 channel: Channel,
203 phantom: PhantomData<T>,
204}
205
206impl<T: GeneralInstance4Channel> Drop for InputCaptureFuture<T> {
207 fn drop(&mut self) {
208 critical_section::with(|_| {
209 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
210
211 // disable interrupt enable
212 regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
213 });
214 }
215}
216
217impl<T: GeneralInstance4Channel> Future for InputCaptureFuture<T> {
218 type Output = u32;
219
220 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
221 T::state().cc_waker[self.channel.index()].register(cx.waker());
222
223 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
224
225 let dier = regs.dier().read();
226 if !dier.ccie(self.channel.index()) {
227 let val = regs.ccr(self.channel.index()).read().0;
228 Poll::Ready(val)
229 } else {
230 Poll::Pending
231 }
232 }
233}
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index aa73986ea..7f533b75c 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -448,6 +448,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
448 self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); 448 self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
449 } 449 }
450 450
451 /// Get input interrupt.
452 pub fn get_input_interrupt(&self, channel: Channel) -> bool {
453 self.regs_gp16().sr().read().ccif(channel.index())
454 }
455
451 /// Enable input interrupt. 456 /// Enable input interrupt.
452 pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) { 457 pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
453 self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); 458 self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 346127005..314b6006b 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,7 +1,12 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2 2
3use core::marker::PhantomData;
4
5use embassy_sync::waitqueue::AtomicWaker;
6
3#[cfg(not(stm32l0))] 7#[cfg(not(stm32l0))]
4pub mod complementary_pwm; 8pub mod complementary_pwm;
9pub mod input_capture;
5pub mod low_level; 10pub mod low_level;
6pub mod qei; 11pub mod qei;
7pub mod simple_pwm; 12pub mod simple_pwm;
@@ -45,8 +50,29 @@ pub enum TimerBits {
45 Bits32, 50 Bits32,
46} 51}
47 52
53struct State {
54 up_waker: AtomicWaker,
55 cc_waker: [AtomicWaker; 4],
56}
57
58impl State {
59 const fn new() -> Self {
60 const NEW_AW: AtomicWaker = AtomicWaker::new();
61 Self {
62 up_waker: NEW_AW,
63 cc_waker: [NEW_AW; 4],
64 }
65 }
66}
67
68trait SealedInstance: RccPeripheral {
69 /// Async state for this timer
70 fn state() -> &'static State;
71}
72
48/// Core timer instance. 73/// Core timer instance.
49pub trait CoreInstance: RccPeripheral + 'static { 74#[allow(private_bounds)]
75pub trait CoreInstance: SealedInstance + 'static {
50 /// Update Interrupt for this timer. 76 /// Update Interrupt for this timer.
51 type UpdateInterrupt: interrupt::typelevel::Interrupt; 77 type UpdateInterrupt: interrupt::typelevel::Interrupt;
52 78
@@ -143,6 +169,13 @@ dma_trait!(Ch4Dma, GeneralInstance4Channel);
143#[allow(unused)] 169#[allow(unused)]
144macro_rules! impl_core_timer { 170macro_rules! impl_core_timer {
145 ($inst:ident, $bits:expr) => { 171 ($inst:ident, $bits:expr) => {
172 impl SealedInstance for crate::peripherals::$inst {
173 fn state() -> &'static State {
174 static STATE: State = State::new();
175 &STATE
176 }
177 }
178
146 impl CoreInstance for crate::peripherals::$inst { 179 impl CoreInstance for crate::peripherals::$inst {
147 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; 180 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
148 181
@@ -285,3 +318,63 @@ foreach_interrupt! {
285 impl AdvancedInstance4Channel for crate::peripherals::$inst {} 318 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
286 }; 319 };
287} 320}
321
322/// Update interrupt handler.
323pub struct UpdateInterruptHandler<T: CoreInstance> {
324 _phantom: PhantomData<T>,
325}
326
327impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
328 unsafe fn on_interrupt() {
329 #[cfg(feature = "low-power")]
330 crate::low_power::on_wakeup_irq();
331
332 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
333
334 // Read TIM interrupt flags.
335 let sr = regs.sr().read();
336
337 // Mask relevant interrupts (UIE).
338 let bits = sr.0 & 0x00000001;
339
340 // Mask all the channels that fired.
341 regs.dier().modify(|w| w.0 &= !bits);
342
343 // Wake the tasks
344 if sr.uif() {
345 T::state().up_waker.wake();
346 }
347 }
348}
349
350/// Capture/Compare interrupt handler.
351pub struct CaptureCompareInterruptHandler<T: GeneralInstance1Channel> {
352 _phantom: PhantomData<T>,
353}
354
355impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompareInterrupt>
356 for CaptureCompareInterruptHandler<T>
357{
358 unsafe fn on_interrupt() {
359 #[cfg(feature = "low-power")]
360 crate::low_power::on_wakeup_irq();
361
362 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
363
364 // Read TIM interrupt flags.
365 let sr = regs.sr().read();
366
367 // Mask relevant interrupts (CCIE).
368 let bits = sr.0 & 0x0000001E;
369
370 // Mask all the channels that fired.
371 regs.dier().modify(|w| w.0 &= !bits);
372
373 // Wake the tasks
374 for ch in 0..4 {
375 if sr.ccif(ch) {
376 T::state().cc_waker[ch].wake();
377 }
378 }
379 }
380}
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
new file mode 100644
index 000000000..0d34a43ec
--- /dev/null
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -0,0 +1,238 @@
1use core::ops::BitOr;
2
3/// Pin defines
4#[allow(missing_docs)]
5pub enum TscIOPin {
6 Group1Io1,
7 Group1Io2,
8 Group1Io3,
9 Group1Io4,
10 Group2Io1,
11 Group2Io2,
12 Group2Io3,
13 Group2Io4,
14 Group3Io1,
15 Group3Io2,
16 Group3Io3,
17 Group3Io4,
18 Group4Io1,
19 Group4Io2,
20 Group4Io3,
21 Group4Io4,
22 Group5Io1,
23 Group5Io2,
24 Group5Io3,
25 Group5Io4,
26 Group6Io1,
27 Group6Io2,
28 Group6Io3,
29 Group6Io4,
30 #[cfg(any(tsc_v2, tsc_v3))]
31 Group7Io1,
32 #[cfg(any(tsc_v2, tsc_v3))]
33 Group7Io2,
34 #[cfg(any(tsc_v2, tsc_v3))]
35 Group7Io3,
36 #[cfg(any(tsc_v2, tsc_v3))]
37 Group7Io4,
38 #[cfg(tsc_v3)]
39 Group8Io1,
40 #[cfg(tsc_v3)]
41 Group8Io2,
42 #[cfg(tsc_v3)]
43 Group8Io3,
44 #[cfg(tsc_v3)]
45 Group8Io4,
46}
47
48impl BitOr<TscIOPin> for u32 {
49 type Output = u32;
50 fn bitor(self, rhs: TscIOPin) -> Self::Output {
51 let rhs: u32 = rhs.into();
52 self | rhs
53 }
54}
55
56impl BitOr<u32> for TscIOPin {
57 type Output = u32;
58 fn bitor(self, rhs: u32) -> Self::Output {
59 let val: u32 = self.into();
60 val | rhs
61 }
62}
63
64impl BitOr for TscIOPin {
65 type Output = u32;
66 fn bitor(self, rhs: Self) -> Self::Output {
67 let val: u32 = self.into();
68 let rhs: u32 = rhs.into();
69 val | rhs
70 }
71}
72
73impl Into<u32> for TscIOPin {
74 fn into(self) -> u32 {
75 match self {
76 TscIOPin::Group1Io1 => 0x00000001,
77 TscIOPin::Group1Io2 => 0x00000002,
78 TscIOPin::Group1Io3 => 0x00000004,
79 TscIOPin::Group1Io4 => 0x00000008,
80 TscIOPin::Group2Io1 => 0x00000010,
81 TscIOPin::Group2Io2 => 0x00000020,
82 TscIOPin::Group2Io3 => 0x00000040,
83 TscIOPin::Group2Io4 => 0x00000080,
84 TscIOPin::Group3Io1 => 0x00000100,
85 TscIOPin::Group3Io2 => 0x00000200,
86 TscIOPin::Group3Io3 => 0x00000400,
87 TscIOPin::Group3Io4 => 0x00000800,
88 TscIOPin::Group4Io1 => 0x00001000,
89 TscIOPin::Group4Io2 => 0x00002000,
90 TscIOPin::Group4Io3 => 0x00004000,
91 TscIOPin::Group4Io4 => 0x00008000,
92 TscIOPin::Group5Io1 => 0x00010000,
93 TscIOPin::Group5Io2 => 0x00020000,
94 TscIOPin::Group5Io3 => 0x00040000,
95 TscIOPin::Group5Io4 => 0x00080000,
96 TscIOPin::Group6Io1 => 0x00100000,
97 TscIOPin::Group6Io2 => 0x00200000,
98 TscIOPin::Group6Io3 => 0x00400000,
99 TscIOPin::Group6Io4 => 0x00800000,
100 #[cfg(any(tsc_v2, tsc_v3))]
101 TscIOPin::Group7Io1 => 0x01000000,
102 #[cfg(any(tsc_v2, tsc_v3))]
103 TscIOPin::Group7Io2 => 0x02000000,
104 #[cfg(any(tsc_v2, tsc_v3))]
105 TscIOPin::Group7Io3 => 0x04000000,
106 #[cfg(any(tsc_v2, tsc_v3))]
107 TscIOPin::Group7Io4 => 0x08000000,
108 #[cfg(tsc_v3)]
109 TscIOPin::Group8Io1 => 0x10000000,
110 #[cfg(tsc_v3)]
111 TscIOPin::Group8Io2 => 0x20000000,
112 #[cfg(tsc_v3)]
113 TscIOPin::Group8Io3 => 0x40000000,
114 #[cfg(tsc_v3)]
115 TscIOPin::Group8Io4 => 0x80000000,
116 }
117 }
118}
119
120/// Spread Spectrum Deviation
121#[derive(Copy, Clone)]
122pub struct SSDeviation(u8);
123impl SSDeviation {
124 /// Create new deviation value, acceptable inputs are 1-128
125 pub fn new(val: u8) -> Result<Self, ()> {
126 if val == 0 || val > 128 {
127 return Err(());
128 }
129 Ok(Self(val - 1))
130 }
131}
132
133impl Into<u8> for SSDeviation {
134 fn into(self) -> u8 {
135 self.0
136 }
137}
138
139/// Charge transfer pulse cycles
140#[allow(missing_docs)]
141#[derive(Copy, Clone, PartialEq)]
142pub enum ChargeTransferPulseCycle {
143 _1,
144 _2,
145 _3,
146 _4,
147 _5,
148 _6,
149 _7,
150 _8,
151 _9,
152 _10,
153 _11,
154 _12,
155 _13,
156 _14,
157 _15,
158 _16,
159}
160
161impl Into<u8> for ChargeTransferPulseCycle {
162 fn into(self) -> u8 {
163 match self {
164 ChargeTransferPulseCycle::_1 => 0,
165 ChargeTransferPulseCycle::_2 => 1,
166 ChargeTransferPulseCycle::_3 => 2,
167 ChargeTransferPulseCycle::_4 => 3,
168 ChargeTransferPulseCycle::_5 => 4,
169 ChargeTransferPulseCycle::_6 => 5,
170 ChargeTransferPulseCycle::_7 => 6,
171 ChargeTransferPulseCycle::_8 => 7,
172 ChargeTransferPulseCycle::_9 => 8,
173 ChargeTransferPulseCycle::_10 => 9,
174 ChargeTransferPulseCycle::_11 => 10,
175 ChargeTransferPulseCycle::_12 => 11,
176 ChargeTransferPulseCycle::_13 => 12,
177 ChargeTransferPulseCycle::_14 => 13,
178 ChargeTransferPulseCycle::_15 => 14,
179 ChargeTransferPulseCycle::_16 => 15,
180 }
181 }
182}
183
184/// Prescaler divider
185#[allow(missing_docs)]
186#[derive(Copy, Clone, PartialEq)]
187pub enum PGPrescalerDivider {
188 _1,
189 _2,
190 _4,
191 _8,
192 _16,
193 _32,
194 _64,
195 _128,
196}
197
198impl Into<u8> for PGPrescalerDivider {
199 fn into(self) -> u8 {
200 match self {
201 PGPrescalerDivider::_1 => 0,
202 PGPrescalerDivider::_2 => 1,
203 PGPrescalerDivider::_4 => 2,
204 PGPrescalerDivider::_8 => 3,
205 PGPrescalerDivider::_16 => 4,
206 PGPrescalerDivider::_32 => 5,
207 PGPrescalerDivider::_64 => 6,
208 PGPrescalerDivider::_128 => 7,
209 }
210 }
211}
212
213/// Max count
214#[allow(missing_docs)]
215#[derive(Copy, Clone)]
216pub enum MaxCount {
217 _255,
218 _511,
219 _1023,
220 _2047,
221 _4095,
222 _8191,
223 _16383,
224}
225
226impl Into<u8> for MaxCount {
227 fn into(self) -> u8 {
228 match self {
229 MaxCount::_255 => 0,
230 MaxCount::_511 => 1,
231 MaxCount::_1023 => 2,
232 MaxCount::_2047 => 3,
233 MaxCount::_4095 => 4,
234 MaxCount::_8191 => 5,
235 MaxCount::_16383 => 6,
236 }
237 }
238}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
new file mode 100644
index 000000000..bf583f04c
--- /dev/null
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -0,0 +1,936 @@
1//! TSC Peripheral Interface
2//!
3//!
4//! # Example (stm32)
5//! ``` rust, ignore
6//!
7//! let mut device_config = embassy_stm32::Config::default();
8//! {
9//! device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ);
10//! }
11//!
12//! let context = embassy_stm32::init(device_config);
13//!
14//! let config = tsc::Config {
15//! ct_pulse_high_length: ChargeTransferPulseCycle::_2,
16//! ct_pulse_low_length: ChargeTransferPulseCycle::_2,
17//! spread_spectrum: false,
18//! spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
19//! spread_spectrum_prescaler: false,
20//! pulse_generator_prescaler: PGPrescalerDivider::_4,
21//! max_count_value: MaxCount::_8191,
22//! io_default_mode: false,
23//! synchro_pin_polarity: false,
24//! acquisition_mode: false,
25//! max_count_interrupt: false,
26//! channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3,
27//! shield_ios: TscIOPin::Group1Io3.into(),
28//! sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2,
29//! };
30//!
31//! let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
32//! g1.set_io2(context.PB13, PinType::Sample);
33//! g1.set_io3(context.PB14, PinType::Shield);
34//!
35//! let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new();
36//! g2.set_io1(context.PB4, PinType::Sample);
37//! g2.set_io2(context.PB5, PinType::Channel);
38//!
39//! let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new();
40//! g7.set_io2(context.PE3, PinType::Sample);
41//! g7.set_io3(context.PE4, PinType::Channel);
42//!
43//! let mut touch_controller = tsc::Tsc::new(
44//! context.TSC,
45//! Some(g1),
46//! Some(g2),
47//! None,
48//! None,
49//! None,
50//! None,
51//! Some(g7),
52//! None,
53//! config,
54//! );
55//!
56//! touch_controller.discharge_io(true);
57//! Timer::after_millis(1).await;
58//!
59//! touch_controller.start();
60//!
61//! ```
62
63#![macro_use]
64
65/// Enums defined for peripheral parameters
66pub mod enums;
67
68use core::marker::PhantomData;
69
70use embassy_hal_internal::{into_ref, PeripheralRef};
71pub use enums::*;
72
73use crate::gpio::{AFType, AnyPin};
74use crate::pac::tsc::Tsc as Regs;
75use crate::rcc::RccPeripheral;
76use crate::{peripherals, Peripheral};
77
78#[cfg(tsc_v1)]
79const TSC_NUM_GROUPS: u32 = 6;
80#[cfg(tsc_v2)]
81const TSC_NUM_GROUPS: u32 = 7;
82#[cfg(tsc_v3)]
83const TSC_NUM_GROUPS: u32 = 8;
84
85/// Error type defined for TSC
86#[derive(Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum Error {
89 /// Test error for TSC
90 Test,
91}
92
93/// Pin type definition to control IO parameters
94pub enum PinType {
95 /// Sensing channel pin connected to an electrode
96 Channel,
97 /// Sampling capacitor pin, one required for every pin group
98 Sample,
99 /// Shield pin connected to capacitive sensing shield
100 Shield,
101}
102
103/// Peripheral state
104#[derive(PartialEq, Clone, Copy)]
105pub enum State {
106 /// Peripheral is being setup or reconfigured
107 Reset,
108 /// Ready to start acquisition
109 Ready,
110 /// In process of sensor acquisition
111 Busy,
112 /// Error occured during acquisition
113 Error,
114}
115
116/// Individual group status checked after acquisition reported as complete
117/// For groups with multiple channel pins, may take longer because acquisitions
118/// are done sequentially. Check this status before pulling count for each
119/// sampled channel
120#[derive(PartialEq)]
121pub enum GroupStatus {
122 /// Acquisition for channel still in progress
123 Ongoing,
124 /// Acquisition either not started or complete
125 Complete,
126}
127
128/// Group identifier used to interrogate status
129#[allow(missing_docs)]
130pub enum Group {
131 One,
132 Two,
133 Three,
134 Four,
135 Five,
136 Six,
137 #[cfg(any(tsc_v2, tsc_v3))]
138 Seven,
139 #[cfg(tsc_v3)]
140 Eight,
141}
142
143impl Into<usize> for Group {
144 fn into(self) -> usize {
145 match self {
146 Group::One => 0,
147 Group::Two => 1,
148 Group::Three => 2,
149 Group::Four => 3,
150 Group::Five => 4,
151 Group::Six => 5,
152 #[cfg(any(tsc_v2, tsc_v3))]
153 Group::Seven => 6,
154 #[cfg(tsc_v3)]
155 Group::Eight => 7,
156 }
157 }
158}
159
160/// Peripheral configuration
161#[derive(Clone, Copy)]
162pub struct Config {
163 /// Duration of high state of the charge transfer pulse
164 pub ct_pulse_high_length: ChargeTransferPulseCycle,
165 /// Duration of the low state of the charge transfer pulse
166 pub ct_pulse_low_length: ChargeTransferPulseCycle,
167 /// Enable/disable of spread spectrum feature
168 pub spread_spectrum: bool,
169 /// Adds variable number of periods of the SS clk to pulse high state
170 pub spread_spectrum_deviation: SSDeviation,
171 /// Selects AHB clock divider used to generate SS clk
172 pub spread_spectrum_prescaler: bool,
173 /// Selects AHB clock divider used to generate pulse generator clk
174 pub pulse_generator_prescaler: PGPrescalerDivider,
175 /// Maximum number of charge tranfer pulses that can be generated before error
176 pub max_count_value: MaxCount,
177 /// Defines config of all IOs when no ongoing acquisition
178 pub io_default_mode: bool,
179 /// Polarity of sync input pin
180 pub synchro_pin_polarity: bool,
181 /// Acquisition starts when start bit is set or with sync pin input
182 pub acquisition_mode: bool,
183 /// Enable max count interrupt
184 pub max_count_interrupt: bool,
185 /// Channel IO mask
186 pub channel_ios: u32,
187 /// Shield IO mask
188 pub shield_ios: u32,
189 /// Sampling IO mask
190 pub sampling_ios: u32,
191}
192
193impl Default for Config {
194 fn default() -> Self {
195 Self {
196 ct_pulse_high_length: ChargeTransferPulseCycle::_1,
197 ct_pulse_low_length: ChargeTransferPulseCycle::_1,
198 spread_spectrum: false,
199 spread_spectrum_deviation: SSDeviation::new(1).unwrap(),
200 spread_spectrum_prescaler: false,
201 pulse_generator_prescaler: PGPrescalerDivider::_1,
202 max_count_value: MaxCount::_255,
203 io_default_mode: false,
204 synchro_pin_polarity: false,
205 acquisition_mode: false,
206 max_count_interrupt: false,
207 channel_ios: 0,
208 shield_ios: 0,
209 sampling_ios: 0,
210 }
211 }
212}
213
214/// Pin struct that maintains usage
215#[allow(missing_docs)]
216pub struct TscPin<'d, T, C> {
217 _pin: PeripheralRef<'d, AnyPin>,
218 role: PinType,
219 phantom: PhantomData<(T, C)>,
220}
221
222enum GroupError {
223 NoSample,
224 ChannelShield,
225}
226
227/// Pin group definition
228/// Pins are organized into groups of four IOs, all groups with a
229/// sampling channel must also have a sampling capacitor channel.
230#[allow(missing_docs)]
231#[derive(Default)]
232pub struct PinGroup<'d, T, C> {
233 d1: Option<TscPin<'d, T, C>>,
234 d2: Option<TscPin<'d, T, C>>,
235 d3: Option<TscPin<'d, T, C>>,
236 d4: Option<TscPin<'d, T, C>>,
237}
238
239impl<'d, T: Instance, C> PinGroup<'d, T, C> {
240 /// Create new sensing group
241 pub fn new() -> Self {
242 Self {
243 d1: None,
244 d2: None,
245 d3: None,
246 d4: None,
247 }
248 }
249
250 fn contains_shield(&self) -> bool {
251 let mut shield_count = 0;
252
253 if let Some(pin) = &self.d1 {
254 if let PinType::Shield = pin.role {
255 shield_count += 1;
256 }
257 }
258
259 if let Some(pin) = &self.d2 {
260 if let PinType::Shield = pin.role {
261 shield_count += 1;
262 }
263 }
264
265 if let Some(pin) = &self.d3 {
266 if let PinType::Shield = pin.role {
267 shield_count += 1;
268 }
269 }
270
271 if let Some(pin) = &self.d4 {
272 if let PinType::Shield = pin.role {
273 shield_count += 1;
274 }
275 }
276
277 shield_count == 1
278 }
279
280 fn check_group(&self) -> Result<(), GroupError> {
281 let mut channel_count = 0;
282 let mut shield_count = 0;
283 let mut sample_count = 0;
284 if let Some(pin) = &self.d1 {
285 match pin.role {
286 PinType::Channel => {
287 channel_count += 1;
288 }
289 PinType::Shield => {
290 shield_count += 1;
291 }
292 PinType::Sample => {
293 sample_count += 1;
294 }
295 }
296 }
297
298 if let Some(pin) = &self.d2 {
299 match pin.role {
300 PinType::Channel => {
301 channel_count += 1;
302 }
303 PinType::Shield => {
304 shield_count += 1;
305 }
306 PinType::Sample => {
307 sample_count += 1;
308 }
309 }
310 }
311
312 if let Some(pin) = &self.d3 {
313 match pin.role {
314 PinType::Channel => {
315 channel_count += 1;
316 }
317 PinType::Shield => {
318 shield_count += 1;
319 }
320 PinType::Sample => {
321 sample_count += 1;
322 }
323 }
324 }
325
326 if let Some(pin) = &self.d4 {
327 match pin.role {
328 PinType::Channel => {
329 channel_count += 1;
330 }
331 PinType::Shield => {
332 shield_count += 1;
333 }
334 PinType::Sample => {
335 sample_count += 1;
336 }
337 }
338 }
339
340 // Every group requires one sampling capacitor
341 if sample_count != 1 {
342 return Err(GroupError::NoSample);
343 }
344
345 // Each group must have at least one shield or channel IO
346 if shield_count == 0 && channel_count == 0 {
347 return Err(GroupError::ChannelShield);
348 }
349
350 // Any group can either contain channel ios or a shield IO
351 if shield_count != 0 && channel_count != 0 {
352 return Err(GroupError::ChannelShield);
353 }
354
355 // No more than one shield IO is allow per group and amongst all groups
356 if shield_count > 1 {
357 return Err(GroupError::ChannelShield);
358 }
359
360 Ok(())
361 }
362}
363
364macro_rules! group_impl {
365 ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
366 impl<'d, T: Instance> PinGroup<'d, T, $group> {
367 #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
368 pub fn set_io1(&mut self, pin: impl Peripheral<P = impl $trait1<T>> + 'd, role: PinType) {
369 into_ref!(pin);
370 critical_section::with(|_| {
371 pin.set_low();
372 pin.set_as_af(
373 pin.af_num(),
374 match role {
375 PinType::Channel => AFType::OutputPushPull,
376 PinType::Sample => AFType::OutputOpenDrain,
377 PinType::Shield => AFType::OutputPushPull,
378 },
379 );
380 self.d1 = Some(TscPin {
381 _pin: pin.map_into(),
382 role: role,
383 phantom: PhantomData,
384 })
385 })
386 }
387
388 #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")]
389 pub fn set_io2(&mut self, pin: impl Peripheral<P = impl $trait2<T>> + 'd, role: PinType) {
390 into_ref!(pin);
391 critical_section::with(|_| {
392 pin.set_low();
393 pin.set_as_af(
394 pin.af_num(),
395 match role {
396 PinType::Channel => AFType::OutputPushPull,
397 PinType::Sample => AFType::OutputOpenDrain,
398 PinType::Shield => AFType::OutputPushPull,
399 },
400 );
401 self.d2 = Some(TscPin {
402 _pin: pin.map_into(),
403 role: role,
404 phantom: PhantomData,
405 })
406 })
407 }
408
409 #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")]
410 pub fn set_io3(&mut self, pin: impl Peripheral<P = impl $trait3<T>> + 'd, role: PinType) {
411 into_ref!(pin);
412 critical_section::with(|_| {
413 pin.set_low();
414 pin.set_as_af(
415 pin.af_num(),
416 match role {
417 PinType::Channel => AFType::OutputPushPull,
418 PinType::Sample => AFType::OutputOpenDrain,
419 PinType::Shield => AFType::OutputPushPull,
420 },
421 );
422 self.d3 = Some(TscPin {
423 _pin: pin.map_into(),
424 role: role,
425 phantom: PhantomData,
426 })
427 })
428 }
429
430 #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")]
431 pub fn set_io4(&mut self, pin: impl Peripheral<P = impl $trait4<T>> + 'd, role: PinType) {
432 into_ref!(pin);
433 critical_section::with(|_| {
434 pin.set_low();
435 pin.set_as_af(
436 pin.af_num(),
437 match role {
438 PinType::Channel => AFType::OutputPushPull,
439 PinType::Sample => AFType::OutputOpenDrain,
440 PinType::Shield => AFType::OutputPushPull,
441 },
442 );
443 self.d4 = Some(TscPin {
444 _pin: pin.map_into(),
445 role: role,
446 phantom: PhantomData,
447 })
448 })
449 }
450 }
451 };
452}
453
454group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
455group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
456group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
457group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
458group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
459group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
460group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
461group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
462
463/// Group 1 marker type.
464pub enum G1 {}
465/// Group 2 marker type.
466pub enum G2 {}
467/// Group 3 marker type.
468pub enum G3 {}
469/// Group 4 marker type.
470pub enum G4 {}
471/// Group 5 marker type.
472pub enum G5 {}
473/// Group 6 marker type.
474pub enum G6 {}
475/// Group 7 marker type.
476pub enum G7 {}
477/// Group 8 marker type.
478pub enum G8 {}
479
480/// TSC driver
481pub struct Tsc<'d, T: Instance> {
482 _peri: PeripheralRef<'d, T>,
483 _g1: Option<PinGroup<'d, T, G1>>,
484 _g2: Option<PinGroup<'d, T, G2>>,
485 _g3: Option<PinGroup<'d, T, G3>>,
486 _g4: Option<PinGroup<'d, T, G4>>,
487 _g5: Option<PinGroup<'d, T, G5>>,
488 _g6: Option<PinGroup<'d, T, G6>>,
489 #[cfg(any(tsc_v2, tsc_v3))]
490 _g7: Option<PinGroup<'d, T, G7>>,
491 #[cfg(tsc_v3)]
492 _g8: Option<PinGroup<'d, T, G8>>,
493 state: State,
494 config: Config,
495}
496
497impl<'d, T: Instance> Tsc<'d, T> {
498 /// Create new TSC driver
499 pub fn new(
500 peri: impl Peripheral<P = T> + 'd,
501 g1: Option<PinGroup<'d, T, G1>>,
502 g2: Option<PinGroup<'d, T, G2>>,
503 g3: Option<PinGroup<'d, T, G3>>,
504 g4: Option<PinGroup<'d, T, G4>>,
505 g5: Option<PinGroup<'d, T, G5>>,
506 g6: Option<PinGroup<'d, T, G6>>,
507 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
508 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
509 config: Config,
510 ) -> Self {
511 // Need to check valid pin configuration input
512 let g1 = g1.filter(|b| b.check_group().is_ok());
513 let g2 = g2.filter(|b| b.check_group().is_ok());
514 let g3 = g3.filter(|b| b.check_group().is_ok());
515 let g4 = g4.filter(|b| b.check_group().is_ok());
516 let g5 = g5.filter(|b| b.check_group().is_ok());
517 let g6 = g6.filter(|b| b.check_group().is_ok());
518 #[cfg(any(tsc_v2, tsc_v3))]
519 let g7 = g7.filter(|b| b.check_group().is_ok());
520 #[cfg(tsc_v3)]
521 let g8 = g8.filter(|b| b.check_group().is_ok());
522
523 match Self::check_shields(
524 &g1,
525 &g2,
526 &g3,
527 &g4,
528 &g5,
529 &g6,
530 #[cfg(any(tsc_v2, tsc_v3))]
531 &g7,
532 #[cfg(tsc_v3)]
533 &g8,
534 ) {
535 Ok(()) => Self::new_inner(
536 peri,
537 g1,
538 g2,
539 g3,
540 g4,
541 g5,
542 g6,
543 #[cfg(any(tsc_v2, tsc_v3))]
544 g7,
545 #[cfg(tsc_v3)]
546 g8,
547 config,
548 ),
549 Err(_) => Self::new_inner(
550 peri,
551 None,
552 None,
553 None,
554 None,
555 None,
556 None,
557 #[cfg(any(tsc_v2, tsc_v3))]
558 None,
559 #[cfg(tsc_v3)]
560 None,
561 config,
562 ),
563 }
564 }
565
566 fn check_shields(
567 g1: &Option<PinGroup<'d, T, G1>>,
568 g2: &Option<PinGroup<'d, T, G2>>,
569 g3: &Option<PinGroup<'d, T, G3>>,
570 g4: &Option<PinGroup<'d, T, G4>>,
571 g5: &Option<PinGroup<'d, T, G5>>,
572 g6: &Option<PinGroup<'d, T, G6>>,
573 #[cfg(any(tsc_v2, tsc_v3))] g7: &Option<PinGroup<'d, T, G7>>,
574 #[cfg(tsc_v3)] g8: &Option<PinGroup<'d, T, G8>>,
575 ) -> Result<(), GroupError> {
576 let mut shield_count = 0;
577
578 if let Some(pin_group) = g1 {
579 if pin_group.contains_shield() {
580 shield_count += 1;
581 }
582 };
583 if let Some(pin_group) = g2 {
584 if pin_group.contains_shield() {
585 shield_count += 1;
586 }
587 };
588 if let Some(pin_group) = g3 {
589 if pin_group.contains_shield() {
590 shield_count += 1;
591 }
592 };
593 if let Some(pin_group) = g4 {
594 if pin_group.contains_shield() {
595 shield_count += 1;
596 }
597 };
598 if let Some(pin_group) = g5 {
599 if pin_group.contains_shield() {
600 shield_count += 1;
601 }
602 };
603 if let Some(pin_group) = g6 {
604 if pin_group.contains_shield() {
605 shield_count += 1;
606 }
607 };
608 #[cfg(any(tsc_v2, tsc_v3))]
609 if let Some(pin_group) = g7 {
610 if pin_group.contains_shield() {
611 shield_count += 1;
612 }
613 };
614 #[cfg(tsc_v3)]
615 if let Some(pin_group) = g8 {
616 if pin_group.contains_shield() {
617 shield_count += 1;
618 }
619 };
620
621 if shield_count > 1 {
622 return Err(GroupError::ChannelShield);
623 }
624
625 Ok(())
626 }
627
628 fn extract_groups(io_mask: u32) -> u32 {
629 let mut groups: u32 = 0;
630 for idx in 0..TSC_NUM_GROUPS {
631 if io_mask & (0x0F << idx * 4) != 0 {
632 groups |= 1 << idx
633 }
634 }
635 groups
636 }
637
638 fn new_inner(
639 peri: impl Peripheral<P = T> + 'd,
640 g1: Option<PinGroup<'d, T, G1>>,
641 g2: Option<PinGroup<'d, T, G2>>,
642 g3: Option<PinGroup<'d, T, G3>>,
643 g4: Option<PinGroup<'d, T, G4>>,
644 g5: Option<PinGroup<'d, T, G5>>,
645 g6: Option<PinGroup<'d, T, G6>>,
646 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
647 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
648 config: Config,
649 ) -> Self {
650 into_ref!(peri);
651
652 T::enable_and_reset();
653
654 T::REGS.cr().modify(|w| {
655 w.set_tsce(true);
656 w.set_ctph(config.ct_pulse_high_length.into());
657 w.set_ctpl(config.ct_pulse_low_length.into());
658 w.set_sse(config.spread_spectrum);
659 // Prevent invalid configuration for pulse generator prescaler
660 if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1
661 && (config.pulse_generator_prescaler == PGPrescalerDivider::_1
662 || config.pulse_generator_prescaler == PGPrescalerDivider::_2)
663 {
664 w.set_pgpsc(PGPrescalerDivider::_4.into());
665 } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2
666 && config.pulse_generator_prescaler == PGPrescalerDivider::_1
667 {
668 w.set_pgpsc(PGPrescalerDivider::_2.into());
669 } else {
670 w.set_pgpsc(config.pulse_generator_prescaler.into());
671 }
672 w.set_ssd(config.spread_spectrum_deviation.into());
673 w.set_sspsc(config.spread_spectrum_prescaler);
674
675 w.set_mcv(config.max_count_value.into());
676 w.set_syncpol(config.synchro_pin_polarity);
677 w.set_am(config.acquisition_mode);
678 });
679
680 // Set IO configuration
681 // Disable Schmitt trigger hysteresis on all used TSC IOs
682 T::REGS
683 .iohcr()
684 .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios));
685
686 // Set channel and shield IOs
687 T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios);
688
689 // Set sampling IOs
690 T::REGS.ioscr().write(|w| w.0 = config.sampling_ios);
691
692 // Set the groups to be acquired
693 T::REGS
694 .iogcsr()
695 .write(|w| w.0 = Self::extract_groups(config.channel_ios));
696
697 // Disable interrupts
698 T::REGS.ier().modify(|w| {
699 w.set_eoaie(false);
700 w.set_mceie(false);
701 });
702
703 // Clear flags
704 T::REGS.icr().modify(|w| {
705 w.set_eoaic(true);
706 w.set_mceic(true);
707 });
708
709 Self {
710 _peri: peri,
711 _g1: g1,
712 _g2: g2,
713 _g3: g3,
714 _g4: g4,
715 _g5: g5,
716 _g6: g6,
717 #[cfg(any(tsc_v2, tsc_v3))]
718 _g7: g7,
719 #[cfg(tsc_v3)]
720 _g8: g8,
721 state: State::Ready,
722 config,
723 }
724 }
725
726 /// Start charge transfer acquisition
727 pub fn start(&mut self) {
728 self.state = State::Busy;
729
730 // Disable interrupts
731 T::REGS.ier().modify(|w| {
732 w.set_eoaie(false);
733 w.set_mceie(false);
734 });
735
736 // Clear flags
737 T::REGS.icr().modify(|w| {
738 w.set_eoaic(true);
739 w.set_mceic(true);
740 });
741
742 // Set the touch sensing IOs not acquired to the default mode
743 T::REGS.cr().modify(|w| {
744 w.set_iodef(self.config.io_default_mode);
745 });
746
747 // Start the acquisition
748 T::REGS.cr().modify(|w| {
749 w.set_start(true);
750 });
751 }
752
753 /// Start charge transfer acquisition with interrupts enabled
754 pub fn start_it(&mut self) {
755 self.state = State::Busy;
756
757 // Enable interrupts
758 T::REGS.ier().modify(|w| {
759 w.set_eoaie(true);
760 w.set_mceie(self.config.max_count_interrupt);
761 });
762
763 // Clear flags
764 T::REGS.icr().modify(|w| {
765 w.set_eoaic(true);
766 w.set_mceic(true);
767 });
768
769 // Set the touch sensing IOs not acquired to the default mode
770 T::REGS.cr().modify(|w| {
771 w.set_iodef(self.config.io_default_mode);
772 });
773
774 // Start the acquisition
775 T::REGS.cr().modify(|w| {
776 w.set_start(true);
777 });
778 }
779
780 /// Stop charge transfer acquisition
781 pub fn stop(&mut self) {
782 T::REGS.cr().modify(|w| {
783 w.set_start(false);
784 });
785
786 // Set the touch sensing IOs in low power mode
787 T::REGS.cr().modify(|w| {
788 w.set_iodef(false);
789 });
790
791 // Clear flags
792 T::REGS.icr().modify(|w| {
793 w.set_eoaic(true);
794 w.set_mceic(true);
795 });
796
797 self.state = State::Ready;
798 }
799
800 /// Stop charge transfer acquisition and clear interrupts
801 pub fn stop_it(&mut self) {
802 T::REGS.cr().modify(|w| {
803 w.set_start(false);
804 });
805
806 // Set the touch sensing IOs in low power mode
807 T::REGS.cr().modify(|w| {
808 w.set_iodef(false);
809 });
810
811 // Disable interrupts
812 T::REGS.ier().modify(|w| {
813 w.set_eoaie(false);
814 w.set_mceie(false);
815 });
816
817 // Clear flags
818 T::REGS.icr().modify(|w| {
819 w.set_eoaic(true);
820 w.set_mceic(true);
821 });
822
823 self.state = State::Ready;
824 }
825
826 /// Wait for end of acquisition
827 pub fn poll_for_acquisition(&mut self) {
828 while self.get_state() == State::Busy {}
829 }
830
831 /// Get current state of acquisition
832 pub fn get_state(&mut self) -> State {
833 if self.state == State::Busy {
834 if T::REGS.isr().read().eoaf() {
835 if T::REGS.isr().read().mcef() {
836 self.state = State::Error
837 } else {
838 self.state = State::Ready
839 }
840 }
841 }
842 self.state
843 }
844
845 /// Get the individual group status to check acquisition complete
846 pub fn group_get_status(&mut self, index: Group) -> GroupStatus {
847 // Status bits are set by hardware when the acquisition on the corresponding
848 // enabled analog IO group is complete, cleared when new acquisition is started
849 let status = match index {
850 Group::One => T::REGS.iogcsr().read().g1s(),
851 Group::Two => T::REGS.iogcsr().read().g2s(),
852 Group::Three => T::REGS.iogcsr().read().g3s(),
853 Group::Four => T::REGS.iogcsr().read().g4s(),
854 Group::Five => T::REGS.iogcsr().read().g5s(),
855 Group::Six => T::REGS.iogcsr().read().g6s(),
856 #[cfg(any(tsc_v2, tsc_v3))]
857 Group::Seven => T::REGS.iogcsr().read().g7s(),
858 #[cfg(tsc_v3)]
859 Group::Eight => T::REGS.iogcsr().read().g8s(),
860 };
861 match status {
862 true => GroupStatus::Complete,
863 false => GroupStatus::Ongoing,
864 }
865 }
866
867 /// Get the count for the acquisiton, valid once group status is set
868 pub fn group_get_value(&mut self, index: Group) -> u16 {
869 T::REGS.iogcr(index.into()).read().cnt()
870 }
871
872 /// Discharge the IOs for subsequent acquisition
873 pub fn discharge_io(&mut self, status: bool) {
874 // Set the touch sensing IOs in low power mode
875 T::REGS.cr().modify(|w| {
876 w.set_iodef(!status);
877 });
878 }
879}
880
881impl<'d, T: Instance> Drop for Tsc<'d, T> {
882 fn drop(&mut self) {
883 T::disable();
884 }
885}
886
887pub(crate) trait SealedInstance {
888 const REGS: Regs;
889}
890
891/// TSC instance trait
892#[allow(private_bounds)]
893pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
894
895foreach_peripheral!(
896 (tsc, $inst:ident) => {
897 impl SealedInstance for peripherals::$inst {
898 const REGS: Regs = crate::pac::$inst;
899 }
900
901 impl Instance for peripherals::$inst {}
902 };
903);
904
905pin_trait!(G1IO1Pin, Instance);
906pin_trait!(G1IO2Pin, Instance);
907pin_trait!(G1IO3Pin, Instance);
908pin_trait!(G1IO4Pin, Instance);
909pin_trait!(G2IO1Pin, Instance);
910pin_trait!(G2IO2Pin, Instance);
911pin_trait!(G2IO3Pin, Instance);
912pin_trait!(G2IO4Pin, Instance);
913pin_trait!(G3IO1Pin, Instance);
914pin_trait!(G3IO2Pin, Instance);
915pin_trait!(G3IO3Pin, Instance);
916pin_trait!(G3IO4Pin, Instance);
917pin_trait!(G4IO1Pin, Instance);
918pin_trait!(G4IO2Pin, Instance);
919pin_trait!(G4IO3Pin, Instance);
920pin_trait!(G4IO4Pin, Instance);
921pin_trait!(G5IO1Pin, Instance);
922pin_trait!(G5IO2Pin, Instance);
923pin_trait!(G5IO3Pin, Instance);
924pin_trait!(G5IO4Pin, Instance);
925pin_trait!(G6IO1Pin, Instance);
926pin_trait!(G6IO2Pin, Instance);
927pin_trait!(G6IO3Pin, Instance);
928pin_trait!(G6IO4Pin, Instance);
929pin_trait!(G7IO1Pin, Instance);
930pin_trait!(G7IO2Pin, Instance);
931pin_trait!(G7IO3Pin, Instance);
932pin_trait!(G7IO4Pin, Instance);
933pin_trait!(G8IO1Pin, Instance);
934pin_trait!(G8IO2Pin, Instance);
935pin_trait!(G8IO3Pin, Instance);
936pin_trait!(G8IO4Pin, Instance);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 68899bfff..a6dfbd482 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -359,16 +359,32 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
359 359
360 /// Initiate an asynchronous UART write 360 /// Initiate an asynchronous UART write
361 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 361 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
362 let r = T::regs();
363
364 // Disable Receiver for Half-Duplex mode
365 if r.cr3().read().hdsel() {
366 r.cr1().modify(|reg| reg.set_re(false));
367 }
368
362 let ch = self.tx_dma.as_mut().unwrap(); 369 let ch = self.tx_dma.as_mut().unwrap();
363 T::regs().cr3().modify(|reg| { 370 r.cr3().modify(|reg| {
364 reg.set_dmat(true); 371 reg.set_dmat(true);
365 }); 372 });
366 // If we don't assign future to a variable, the data register pointer 373 // If we don't assign future to a variable, the data register pointer
367 // is held across an await and makes the future non-Send. 374 // is held across an await and makes the future non-Send.
368 let transfer = unsafe { ch.write(buffer, tdr(T::regs()), Default::default()) }; 375 let transfer = unsafe { ch.write(buffer, tdr(r), Default::default()) };
369 transfer.await; 376 transfer.await;
370 Ok(()) 377 Ok(())
371 } 378 }
379
380 async fn flush_inner() -> Result<(), Error> {
381 Self::blocking_flush_inner()
382 }
383
384 /// Wait until transmission complete
385 pub async fn flush(&mut self) -> Result<(), Error> {
386 Self::flush_inner().await
387 }
372} 388}
373 389
374impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> { 390impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
@@ -436,6 +452,12 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
436 /// Perform a blocking UART write 452 /// Perform a blocking UART write
437 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 453 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
438 let r = T::regs(); 454 let r = T::regs();
455
456 // Disable Receiver for Half-Duplex mode
457 if r.cr3().read().hdsel() {
458 r.cr1().modify(|reg| reg.set_re(false));
459 }
460
439 for &b in buffer { 461 for &b in buffer {
440 while !sr(r).read().txe() {} 462 while !sr(r).read().txe() {}
441 unsafe { tdr(r).write_volatile(b) }; 463 unsafe { tdr(r).write_volatile(b) };
@@ -443,12 +465,21 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
443 Ok(()) 465 Ok(())
444 } 466 }
445 467
446 /// Block until transmission complete 468 fn blocking_flush_inner() -> Result<(), Error> {
447 pub fn blocking_flush(&mut self) -> Result<(), Error> {
448 let r = T::regs(); 469 let r = T::regs();
449 while !sr(r).read().tc() {} 470 while !sr(r).read().tc() {}
471
472 // Enable Receiver after transmission complete for Half-Duplex mode
473 if r.cr3().read().hdsel() {
474 r.cr1().modify(|reg| reg.set_re(true));
475 }
450 Ok(()) 476 Ok(())
451 } 477 }
478
479 /// Block until transmission complete
480 pub fn blocking_flush(&mut self) -> Result<(), Error> {
481 Self::blocking_flush_inner()
482 }
452} 483}
453 484
454impl<'d, T: BasicInstance> UartRx<'d, T, Async> { 485impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
@@ -502,6 +533,11 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
502 ) -> Result<ReadCompletionEvent, Error> { 533 ) -> Result<ReadCompletionEvent, Error> {
503 let r = T::regs(); 534 let r = T::regs();
504 535
536 // Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
537 if r.cr3().read().hdsel() {
538 UartTx::<'d, T, Async>::flush_inner().await?;
539 }
540
505 // make sure USART state is restored to neutral state when this future is dropped 541 // make sure USART state is restored to neutral state when this future is dropped
506 let on_drop = OnDrop::new(move || { 542 let on_drop = OnDrop::new(move || {
507 // defmt::trace!("Clear all USART interrupts and DMA Read Request"); 543 // defmt::trace!("Clear all USART interrupts and DMA Read Request");
@@ -825,6 +861,12 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
825 /// Perform a blocking read into `buffer` 861 /// Perform a blocking read into `buffer`
826 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 862 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
827 let r = T::regs(); 863 let r = T::regs();
864
865 // Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
866 if r.cr3().read().hdsel() {
867 UartTx::<'d, T, M>::blocking_flush_inner()?;
868 }
869
828 for b in buffer { 870 for b in buffer {
829 while !self.check_rx_flags()? {} 871 while !self.check_rx_flags()? {}
830 unsafe { *b = rdr(r).read_volatile() } 872 unsafe { *b = rdr(r).read_volatile() }
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 7ab6cbda7..0a6491bd5 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -72,9 +72,8 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
72 Err(err) 72 Err(err)
73 } 73 }
74 74
75 /// Cleanly stop and reconfigure the driver 75 /// Reconfigure the driver
76 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 76 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
77 self.teardown_uart();
78 reconfigure::<T>(config) 77 reconfigure::<T>(config)
79 } 78 }
80 79
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index 3f6b39d8b..e5c453ce2 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -7,7 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- Add `len`, `is_empty` and `is_full` functions to `Channel`. 10- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel`.
11- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `PriorityChannel`.
12- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `PubSubChannel`.
13- Made `PubSubBehavior` sealed
14 - If you called `.publish_immediate(...)` on the queue directly before, then now call `.immediate_publisher().publish_immediate(...)`
11 15
12## 0.5.0 - 2023-12-04 16## 0.5.0 - 2023-12-04
13 17
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index c4267064c..55ac5fb66 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -42,7 +42,7 @@ where
42 M: RawMutex, 42 M: RawMutex,
43{ 43{
44 fn clone(&self) -> Self { 44 fn clone(&self) -> Self {
45 Sender { channel: self.channel } 45 *self
46 } 46 }
47} 47}
48 48
@@ -81,7 +81,7 @@ pub struct DynamicSender<'ch, T> {
81 81
82impl<'ch, T> Clone for DynamicSender<'ch, T> { 82impl<'ch, T> Clone for DynamicSender<'ch, T> {
83 fn clone(&self) -> Self { 83 fn clone(&self) -> Self {
84 DynamicSender { channel: self.channel } 84 *self
85 } 85 }
86} 86}
87 87
@@ -135,7 +135,7 @@ where
135 M: RawMutex, 135 M: RawMutex,
136{ 136{
137 fn clone(&self) -> Self { 137 fn clone(&self) -> Self {
138 Receiver { channel: self.channel } 138 *self
139 } 139 }
140} 140}
141 141
@@ -188,7 +188,7 @@ pub struct DynamicReceiver<'ch, T> {
188 188
189impl<'ch, T> Clone for DynamicReceiver<'ch, T> { 189impl<'ch, T> Clone for DynamicReceiver<'ch, T> {
190 fn clone(&self) -> Self { 190 fn clone(&self) -> Self {
191 DynamicReceiver { channel: self.channel } 191 *self
192 } 192 }
193} 193}
194 194
@@ -477,6 +477,10 @@ impl<T, const N: usize> ChannelState<T, N> {
477 } 477 }
478 } 478 }
479 479
480 fn clear(&mut self) {
481 self.queue.clear();
482 }
483
480 fn len(&self) -> usize { 484 fn len(&self) -> usize {
481 self.queue.len() 485 self.queue.len()
482 } 486 }
@@ -620,6 +624,23 @@ where
620 self.lock(|c| c.try_receive()) 624 self.lock(|c| c.try_receive())
621 } 625 }
622 626
627 /// Returns the maximum number of elements the channel can hold.
628 pub const fn capacity(&self) -> usize {
629 N
630 }
631
632 /// Returns the free capacity of the channel.
633 ///
634 /// This is equivalent to `capacity() - len()`
635 pub fn free_capacity(&self) -> usize {
636 N - self.len()
637 }
638
639 /// Clears all elements in the channel.
640 pub fn clear(&self) {
641 self.lock(|c| c.clear());
642 }
643
623 /// Returns the number of elements currently in the channel. 644 /// Returns the number of elements currently in the channel.
624 pub fn len(&self) -> usize { 645 pub fn len(&self) -> usize {
625 self.lock(|c| c.len()) 646 self.lock(|c| c.len())
diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs
index 9332ecfaf..55608ba32 100644
--- a/embassy-sync/src/once_lock.rs
+++ b/embassy-sync/src/once_lock.rs
@@ -1,4 +1,4 @@
1//! Syncronization primitive for initializing a value once, allowing others to await a reference to the value. 1//! Synchronization primitive for initializing a value once, allowing others to await a reference to the value.
2 2
3use core::cell::Cell; 3use core::cell::Cell;
4use core::future::poll_fn; 4use core::future::poll_fn;
@@ -78,7 +78,7 @@ impl<T> OnceLock<T> {
78 /// Set the underlying value. If the value is already set, this will return an error with the given value. 78 /// Set the underlying value. If the value is already set, this will return an error with the given value.
79 pub fn init(&self, value: T) -> Result<(), T> { 79 pub fn init(&self, value: T) -> Result<(), T> {
80 // Critical section is required to ensure that the value is 80 // Critical section is required to ensure that the value is
81 // not simultaniously initialized elsewhere at the same time. 81 // not simultaneously initialized elsewhere at the same time.
82 critical_section::with(|_| { 82 critical_section::with(|_| {
83 // If the value is not set, set it and return Ok. 83 // If the value is not set, set it and return Ok.
84 if !self.init.load(Ordering::Relaxed) { 84 if !self.init.load(Ordering::Relaxed) {
@@ -99,7 +99,7 @@ impl<T> OnceLock<T> {
99 F: FnOnce() -> T, 99 F: FnOnce() -> T,
100 { 100 {
101 // Critical section is required to ensure that the value is 101 // Critical section is required to ensure that the value is
102 // not simultaniously initialized elsewhere at the same time. 102 // not simultaneously initialized elsewhere at the same time.
103 critical_section::with(|_| { 103 critical_section::with(|_| {
104 // If the value is not set, set it. 104 // If the value is not set, set it.
105 if !self.init.load(Ordering::Relaxed) { 105 if !self.init.load(Ordering::Relaxed) {
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index 42fe8ebd0..cd5b8ed75 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -25,7 +25,7 @@ where
25 M: RawMutex, 25 M: RawMutex,
26{ 26{
27 fn clone(&self) -> Self { 27 fn clone(&self) -> Self {
28 Writer { pipe: self.pipe } 28 *self
29 } 29 }
30} 30}
31 31
diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs
index e77678c24..24c6c5a7f 100644
--- a/embassy-sync/src/priority_channel.rs
+++ b/embassy-sync/src/priority_channel.rs
@@ -33,7 +33,7 @@ where
33 M: RawMutex, 33 M: RawMutex,
34{ 34{
35 fn clone(&self) -> Self { 35 fn clone(&self) -> Self {
36 Sender { channel: self.channel } 36 *self
37 } 37 }
38} 38}
39 39
@@ -101,7 +101,7 @@ where
101 M: RawMutex, 101 M: RawMutex,
102{ 102{
103 fn clone(&self) -> Self { 103 fn clone(&self) -> Self {
104 Receiver { channel: self.channel } 104 *self
105 } 105 }
106} 106}
107 107
@@ -314,6 +314,22 @@ where
314 Poll::Pending 314 Poll::Pending
315 } 315 }
316 } 316 }
317
318 fn clear(&mut self) {
319 self.queue.clear();
320 }
321
322 fn len(&self) -> usize {
323 self.queue.len()
324 }
325
326 fn is_empty(&self) -> bool {
327 self.queue.is_empty()
328 }
329
330 fn is_full(&self) -> bool {
331 self.queue.len() == self.queue.capacity()
332 }
317} 333}
318 334
319/// A bounded channel for communicating between asynchronous tasks 335/// A bounded channel for communicating between asynchronous tasks
@@ -323,7 +339,7 @@ where
323/// buffer is full, attempts to `send` new messages will wait until a message is 339/// buffer is full, attempts to `send` new messages will wait until a message is
324/// received from the channel. 340/// received from the channel.
325/// 341///
326/// Sent data may be reordered based on their priorty within the channel. 342/// Sent data may be reordered based on their priority within the channel.
327/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`] 343/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`]
328/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`. 344/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`.
329pub struct PriorityChannel<M, T, K, const N: usize> 345pub struct PriorityChannel<M, T, K, const N: usize>
@@ -433,6 +449,38 @@ where
433 pub fn try_receive(&self) -> Result<T, TryReceiveError> { 449 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
434 self.lock(|c| c.try_receive()) 450 self.lock(|c| c.try_receive())
435 } 451 }
452
453 /// Returns the maximum number of elements the channel can hold.
454 pub const fn capacity(&self) -> usize {
455 N
456 }
457
458 /// Returns the free capacity of the channel.
459 ///
460 /// This is equivalent to `capacity() - len()`
461 pub fn free_capacity(&self) -> usize {
462 N - self.len()
463 }
464
465 /// Clears all elements in the channel.
466 pub fn clear(&self) {
467 self.lock(|c| c.clear());
468 }
469
470 /// Returns the number of elements currently in the channel.
471 pub fn len(&self) -> usize {
472 self.lock(|c| c.len())
473 }
474
475 /// Returns whether the channel is empty.
476 pub fn is_empty(&self) -> bool {
477 self.lock(|c| c.is_empty())
478 }
479
480 /// Returns whether the channel is full.
481 pub fn is_full(&self) -> bool {
482 self.lock(|c| c.is_full())
483 }
436} 484}
437 485
438/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the 486/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the
diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs
index 6afd54af5..66c9b0017 100644
--- a/embassy-sync/src/pubsub/mod.rs
+++ b/embassy-sync/src/pubsub/mod.rs
@@ -160,9 +160,41 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
160 pub fn dyn_immediate_publisher(&self) -> DynImmediatePublisher<T> { 160 pub fn dyn_immediate_publisher(&self) -> DynImmediatePublisher<T> {
161 DynImmediatePublisher(ImmediatePub::new(self)) 161 DynImmediatePublisher(ImmediatePub::new(self))
162 } 162 }
163
164 /// Returns the maximum number of elements the channel can hold.
165 pub const fn capacity(&self) -> usize {
166 CAP
167 }
168
169 /// Returns the free capacity of the channel.
170 ///
171 /// This is equivalent to `capacity() - len()`
172 pub fn free_capacity(&self) -> usize {
173 CAP - self.len()
174 }
175
176 /// Clears all elements in the channel.
177 pub fn clear(&self) {
178 self.inner.lock(|inner| inner.borrow_mut().clear());
179 }
180
181 /// Returns the number of elements currently in the channel.
182 pub fn len(&self) -> usize {
183 self.inner.lock(|inner| inner.borrow().len())
184 }
185
186 /// Returns whether the channel is empty.
187 pub fn is_empty(&self) -> bool {
188 self.inner.lock(|inner| inner.borrow().is_empty())
189 }
190
191 /// Returns whether the channel is full.
192 pub fn is_full(&self) -> bool {
193 self.inner.lock(|inner| inner.borrow().is_full())
194 }
163} 195}
164 196
165impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> PubSubBehavior<T> 197impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> SealedPubSubBehavior<T>
166 for PubSubChannel<M, T, CAP, SUBS, PUBS> 198 for PubSubChannel<M, T, CAP, SUBS, PUBS>
167{ 199{
168 fn get_message_with_context(&self, next_message_id: &mut u64, cx: Option<&mut Context<'_>>) -> Poll<WaitResult<T>> { 200 fn get_message_with_context(&self, next_message_id: &mut u64, cx: Option<&mut Context<'_>>) -> Poll<WaitResult<T>> {
@@ -221,13 +253,6 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
221 }) 253 })
222 } 254 }
223 255
224 fn space(&self) -> usize {
225 self.inner.lock(|s| {
226 let s = s.borrow();
227 s.queue.capacity() - s.queue.len()
228 })
229 }
230
231 fn unregister_subscriber(&self, subscriber_next_message_id: u64) { 256 fn unregister_subscriber(&self, subscriber_next_message_id: u64) {
232 self.inner.lock(|s| { 257 self.inner.lock(|s| {
233 let mut s = s.borrow_mut(); 258 let mut s = s.borrow_mut();
@@ -241,6 +266,30 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
241 s.unregister_publisher() 266 s.unregister_publisher()
242 }) 267 })
243 } 268 }
269
270 fn capacity(&self) -> usize {
271 self.capacity()
272 }
273
274 fn free_capacity(&self) -> usize {
275 self.free_capacity()
276 }
277
278 fn clear(&self) {
279 self.clear();
280 }
281
282 fn len(&self) -> usize {
283 self.len()
284 }
285
286 fn is_empty(&self) -> bool {
287 self.is_empty()
288 }
289
290 fn is_full(&self) -> bool {
291 self.is_full()
292 }
244} 293}
245 294
246/// Internal state for the PubSub channel 295/// Internal state for the PubSub channel
@@ -366,6 +415,22 @@ impl<T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> PubSubSta
366 fn unregister_publisher(&mut self) { 415 fn unregister_publisher(&mut self) {
367 self.publisher_count -= 1; 416 self.publisher_count -= 1;
368 } 417 }
418
419 fn clear(&mut self) {
420 self.queue.clear();
421 }
422
423 fn len(&self) -> usize {
424 self.queue.len()
425 }
426
427 fn is_empty(&self) -> bool {
428 self.queue.is_empty()
429 }
430
431 fn is_full(&self) -> bool {
432 self.queue.is_full()
433 }
369} 434}
370 435
371/// Error type for the [PubSubChannel] 436/// Error type for the [PubSubChannel]
@@ -382,10 +447,10 @@ pub enum Error {
382 447
383/// 'Middle level' behaviour of the pubsub channel. 448/// 'Middle level' behaviour of the pubsub channel.
384/// This trait is used so that Sub and Pub can be generic over the channel. 449/// This trait is used so that Sub and Pub can be generic over the channel.
385pub trait PubSubBehavior<T> { 450trait SealedPubSubBehavior<T> {
386 /// Try to get a message from the queue with the given message id. 451 /// Try to get a message from the queue with the given message id.
387 /// 452 ///
388 /// If the message is not yet present and a context is given, then its waker is registered in the subsriber wakers. 453 /// If the message is not yet present and a context is given, then its waker is registered in the subscriber wakers.
389 fn get_message_with_context(&self, next_message_id: &mut u64, cx: Option<&mut Context<'_>>) -> Poll<WaitResult<T>>; 454 fn get_message_with_context(&self, next_message_id: &mut u64, cx: Option<&mut Context<'_>>) -> Poll<WaitResult<T>>;
390 455
391 /// Get the amount of messages that are between the given the next_message_id and the most recent message. 456 /// Get the amount of messages that are between the given the next_message_id and the most recent message.
@@ -400,8 +465,25 @@ pub trait PubSubBehavior<T> {
400 /// Publish a message immediately 465 /// Publish a message immediately
401 fn publish_immediate(&self, message: T); 466 fn publish_immediate(&self, message: T);
402 467
403 /// The amount of messages that can still be published without having to wait or without having to lag the subscribers 468 /// Returns the maximum number of elements the channel can hold.
404 fn space(&self) -> usize; 469 fn capacity(&self) -> usize;
470
471 /// Returns the free capacity of the channel.
472 ///
473 /// This is equivalent to `capacity() - len()`
474 fn free_capacity(&self) -> usize;
475
476 /// Clears all elements in the channel.
477 fn clear(&self);
478
479 /// Returns the number of elements currently in the channel.
480 fn len(&self) -> usize;
481
482 /// Returns whether the channel is empty.
483 fn is_empty(&self) -> bool;
484
485 /// Returns whether the channel is full.
486 fn is_full(&self) -> bool;
405 487
406 /// Let the channel know that a subscriber has dropped 488 /// Let the channel know that a subscriber has dropped
407 fn unregister_subscriber(&self, subscriber_next_message_id: u64); 489 fn unregister_subscriber(&self, subscriber_next_message_id: u64);
@@ -410,6 +492,13 @@ pub trait PubSubBehavior<T> {
410 fn unregister_publisher(&self); 492 fn unregister_publisher(&self);
411} 493}
412 494
495/// 'Middle level' behaviour of the pubsub channel.
496/// This trait is used so that Sub and Pub can be generic over the channel.
497#[allow(private_bounds)]
498pub trait PubSubBehavior<T>: SealedPubSubBehavior<T> {}
499
500impl<T, C: SealedPubSubBehavior<T>> PubSubBehavior<T> for C {}
501
413/// The result of the subscriber wait procedure 502/// The result of the subscriber wait procedure
414#[derive(Debug, Clone, PartialEq, Eq)] 503#[derive(Debug, Clone, PartialEq, Eq)]
415#[cfg_attr(feature = "defmt", derive(defmt::Format))] 504#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -542,6 +631,7 @@ mod tests {
542 assert_eq!(pub0.try_publish(0), Ok(())); 631 assert_eq!(pub0.try_publish(0), Ok(()));
543 assert_eq!(pub0.try_publish(0), Ok(())); 632 assert_eq!(pub0.try_publish(0), Ok(()));
544 assert_eq!(pub0.try_publish(0), Ok(())); 633 assert_eq!(pub0.try_publish(0), Ok(()));
634 assert!(pub0.is_full());
545 assert_eq!(pub0.try_publish(0), Err(0)); 635 assert_eq!(pub0.try_publish(0), Err(0));
546 636
547 drop(sub0); 637 drop(sub0);
@@ -574,32 +664,42 @@ mod tests {
574 } 664 }
575 665
576 #[futures_test::test] 666 #[futures_test::test]
577 async fn correct_space() { 667 async fn correct_len() {
578 let channel = PubSubChannel::<NoopRawMutex, u32, 4, 4, 4>::new(); 668 let channel = PubSubChannel::<NoopRawMutex, u32, 4, 4, 4>::new();
579 669
580 let mut sub0 = channel.subscriber().unwrap(); 670 let mut sub0 = channel.subscriber().unwrap();
581 let mut sub1 = channel.subscriber().unwrap(); 671 let mut sub1 = channel.subscriber().unwrap();
582 let pub0 = channel.publisher().unwrap(); 672 let pub0 = channel.publisher().unwrap();
583 673
584 assert_eq!(pub0.space(), 4); 674 assert!(sub0.is_empty());
675 assert!(sub1.is_empty());
676 assert!(pub0.is_empty());
677 assert_eq!(pub0.free_capacity(), 4);
678 assert_eq!(pub0.len(), 0);
585 679
586 pub0.publish(42).await; 680 pub0.publish(42).await;
587 681
588 assert_eq!(pub0.space(), 3); 682 assert_eq!(pub0.free_capacity(), 3);
683 assert_eq!(pub0.len(), 1);
589 684
590 pub0.publish(42).await; 685 pub0.publish(42).await;
591 686
592 assert_eq!(pub0.space(), 2); 687 assert_eq!(pub0.free_capacity(), 2);
688 assert_eq!(pub0.len(), 2);
593 689
594 sub0.next_message().await; 690 sub0.next_message().await;
595 sub0.next_message().await; 691 sub0.next_message().await;
596 692
597 assert_eq!(pub0.space(), 2); 693 assert_eq!(pub0.free_capacity(), 2);
694 assert_eq!(pub0.len(), 2);
598 695
599 sub1.next_message().await; 696 sub1.next_message().await;
600 assert_eq!(pub0.space(), 3); 697 assert_eq!(pub0.free_capacity(), 3);
698 assert_eq!(pub0.len(), 1);
699
601 sub1.next_message().await; 700 sub1.next_message().await;
602 assert_eq!(pub0.space(), 4); 701 assert_eq!(pub0.free_capacity(), 4);
702 assert_eq!(pub0.len(), 0);
603 } 703 }
604 704
605 #[futures_test::test] 705 #[futures_test::test]
@@ -610,29 +710,29 @@ mod tests {
610 let mut sub0 = channel.subscriber().unwrap(); 710 let mut sub0 = channel.subscriber().unwrap();
611 let mut sub1 = channel.subscriber().unwrap(); 711 let mut sub1 = channel.subscriber().unwrap();
612 712
613 assert_eq!(4, pub0.space()); 713 assert_eq!(4, pub0.free_capacity());
614 714
615 pub0.publish(1).await; 715 pub0.publish(1).await;
616 pub0.publish(2).await; 716 pub0.publish(2).await;
617 717
618 assert_eq!(2, channel.space()); 718 assert_eq!(2, channel.free_capacity());
619 719
620 assert_eq!(1, sub0.try_next_message_pure().unwrap()); 720 assert_eq!(1, sub0.try_next_message_pure().unwrap());
621 assert_eq!(2, sub0.try_next_message_pure().unwrap()); 721 assert_eq!(2, sub0.try_next_message_pure().unwrap());
622 722
623 assert_eq!(2, channel.space()); 723 assert_eq!(2, channel.free_capacity());
624 724
625 drop(sub0); 725 drop(sub0);
626 726
627 assert_eq!(2, channel.space()); 727 assert_eq!(2, channel.free_capacity());
628 728
629 assert_eq!(1, sub1.try_next_message_pure().unwrap()); 729 assert_eq!(1, sub1.try_next_message_pure().unwrap());
630 730
631 assert_eq!(3, channel.space()); 731 assert_eq!(3, channel.free_capacity());
632 732
633 drop(sub1); 733 drop(sub1);
634 734
635 assert_eq!(4, channel.space()); 735 assert_eq!(4, channel.free_capacity());
636 } 736 }
637 737
638 struct CloneCallCounter(usize); 738 struct CloneCallCounter(usize);
diff --git a/embassy-sync/src/pubsub/publisher.rs b/embassy-sync/src/pubsub/publisher.rs
index e1edc9eb9..e66b3b1db 100644
--- a/embassy-sync/src/pubsub/publisher.rs
+++ b/embassy-sync/src/pubsub/publisher.rs
@@ -43,12 +43,36 @@ impl<'a, PSB: PubSubBehavior<T> + ?Sized, T: Clone> Pub<'a, PSB, T> {
43 self.channel.publish_with_context(message, None) 43 self.channel.publish_with_context(message, None)
44 } 44 }
45 45
46 /// The amount of messages that can still be published without having to wait or without having to lag the subscribers 46 /// Returns the maximum number of elements the ***channel*** can hold.
47 pub fn capacity(&self) -> usize {
48 self.channel.capacity()
49 }
50
51 /// Returns the free capacity of the ***channel***.
47 /// 52 ///
48 /// *Note: In the time between checking this and a publish action, other publishers may have had time to publish something. 53 /// This is equivalent to `capacity() - len()`
49 /// So checking doesn't give any guarantees.* 54 pub fn free_capacity(&self) -> usize {
50 pub fn space(&self) -> usize { 55 self.channel.free_capacity()
51 self.channel.space() 56 }
57
58 /// Clears all elements in the ***channel***.
59 pub fn clear(&self) {
60 self.channel.clear();
61 }
62
63 /// Returns the number of elements currently in the ***channel***.
64 pub fn len(&self) -> usize {
65 self.channel.len()
66 }
67
68 /// Returns whether the ***channel*** is empty.
69 pub fn is_empty(&self) -> bool {
70 self.channel.is_empty()
71 }
72
73 /// Returns whether the ***channel*** is full.
74 pub fn is_full(&self) -> bool {
75 self.channel.is_full()
52 } 76 }
53} 77}
54 78
@@ -124,12 +148,36 @@ impl<'a, PSB: PubSubBehavior<T> + ?Sized, T: Clone> ImmediatePub<'a, PSB, T> {
124 self.channel.publish_with_context(message, None) 148 self.channel.publish_with_context(message, None)
125 } 149 }
126 150
127 /// The amount of messages that can still be published without having to wait or without having to lag the subscribers 151 /// Returns the maximum number of elements the ***channel*** can hold.
152 pub fn capacity(&self) -> usize {
153 self.channel.capacity()
154 }
155
156 /// Returns the free capacity of the ***channel***.
128 /// 157 ///
129 /// *Note: In the time between checking this and a publish action, other publishers may have had time to publish something. 158 /// This is equivalent to `capacity() - len()`
130 /// So checking doesn't give any guarantees.* 159 pub fn free_capacity(&self) -> usize {
131 pub fn space(&self) -> usize { 160 self.channel.free_capacity()
132 self.channel.space() 161 }
162
163 /// Clears all elements in the ***channel***.
164 pub fn clear(&self) {
165 self.channel.clear();
166 }
167
168 /// Returns the number of elements currently in the ***channel***.
169 pub fn len(&self) -> usize {
170 self.channel.len()
171 }
172
173 /// Returns whether the ***channel*** is empty.
174 pub fn is_empty(&self) -> bool {
175 self.channel.is_empty()
176 }
177
178 /// Returns whether the ***channel*** is full.
179 pub fn is_full(&self) -> bool {
180 self.channel.is_full()
133 } 181 }
134} 182}
135 183
diff --git a/embassy-sync/src/pubsub/subscriber.rs b/embassy-sync/src/pubsub/subscriber.rs
index f420a75f0..6ad660cb3 100644
--- a/embassy-sync/src/pubsub/subscriber.rs
+++ b/embassy-sync/src/pubsub/subscriber.rs
@@ -65,10 +65,44 @@ impl<'a, PSB: PubSubBehavior<T> + ?Sized, T: Clone> Sub<'a, PSB, T> {
65 } 65 }
66 } 66 }
67 67
68 /// The amount of messages this subscriber hasn't received yet 68 /// The amount of messages this subscriber hasn't received yet. This is like [Self::len] but specifically
69 /// for this subscriber.
69 pub fn available(&self) -> u64 { 70 pub fn available(&self) -> u64 {
70 self.channel.available(self.next_message_id) 71 self.channel.available(self.next_message_id)
71 } 72 }
73
74 /// Returns the maximum number of elements the ***channel*** can hold.
75 pub fn capacity(&self) -> usize {
76 self.channel.capacity()
77 }
78
79 /// Returns the free capacity of the ***channel***.
80 ///
81 /// This is equivalent to `capacity() - len()`
82 pub fn free_capacity(&self) -> usize {
83 self.channel.free_capacity()
84 }
85
86 /// Clears all elements in the ***channel***.
87 pub fn clear(&self) {
88 self.channel.clear();
89 }
90
91 /// Returns the number of elements currently in the ***channel***.
92 /// See [Self::available] for how many messages are available for this subscriber.
93 pub fn len(&self) -> usize {
94 self.channel.len()
95 }
96
97 /// Returns whether the ***channel*** is empty.
98 pub fn is_empty(&self) -> bool {
99 self.channel.is_empty()
100 }
101
102 /// Returns whether the ***channel*** is full.
103 pub fn is_full(&self) -> bool {
104 self.channel.is_full()
105 }
72} 106}
73 107
74impl<'a, PSB: PubSubBehavior<T> + ?Sized, T: Clone> Drop for Sub<'a, PSB, T> { 108impl<'a, PSB: PubSubBehavior<T> + ?Sized, T: Clone> Drop for Sub<'a, PSB, T> {
diff --git a/embassy-sync/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs
index 824d192da..0e520bf40 100644
--- a/embassy-sync/src/waitqueue/multi_waker.rs
+++ b/embassy-sync/src/waitqueue/multi_waker.rs
@@ -14,7 +14,7 @@ impl<const N: usize> MultiWakerRegistration<N> {
14 } 14 }
15 15
16 /// Register a waker. If the buffer is full the function returns it in the error 16 /// Register a waker. If the buffer is full the function returns it in the error
17 pub fn register<'a>(&mut self, w: &'a Waker) { 17 pub fn register(&mut self, w: &Waker) {
18 // If we already have some waker that wakes the same task as `w`, do nothing. 18 // If we already have some waker that wakes the same task as `w`, do nothing.
19 // This avoids cloning wakers, and avoids unnecessary mass-wakes. 19 // This avoids cloning wakers, and avoids unnecessary mass-wakes.
20 for w2 in &self.wakers { 20 for w2 in &self.wakers {
diff --git a/embassy-usb-logger/CHANGELOG.md b/embassy-usb-logger/CHANGELOG.md
new file mode 100644
index 000000000..4cd84b8be
--- /dev/null
+++ b/embassy-usb-logger/CHANGELOG.md
@@ -0,0 +1,28 @@
1# Changelog
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10## 0.2.0 - 2024-05-20
11
12### Added
13
14- [#2414](https://github.com/embassy-rs/embassy/pull/2414) USB logger can now use an existing USB device (@JomerDev)
15
16### Changed
17
18- Update `embassy-usb` to 0.2.0
19
20### Fixed
21
22- No more data loss at `Pipe` wraparound
23- [#2414](https://github.com/embassy-rs/embassy/pull/2414) Messages that are exactly `MAX_PACKET_SIZE` long are no
24longer delayed (@JomerDev)
25
26## 0.1.0 - 2024-01-14
27
28- Initial Release
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
index 81bcfc0da..d58fd7a34 100644
--- a/embassy-usb-logger/Cargo.toml
+++ b/embassy-usb-logger/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-usb-logger" 2name = "embassy-usb-logger"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "`log` implementation for USB serial using `embassy-usb`." 6description = "`log` implementation for USB serial using `embassy-usb`."
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index 42cdfb6e1..b90e059f6 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -221,6 +221,12 @@ struct EpState {
221 out_size: AtomicU16, 221 out_size: AtomicU16,
222} 222}
223 223
224// SAFETY: The EndpointAllocator ensures that the buffer points to valid memory exclusive for each endpoint and is
225// large enough to hold the maximum packet size. Access to the buffer is synchronized between the USB interrupt and the
226// EndpointOut impl using the out_size atomic variable.
227unsafe impl Send for EpState {}
228unsafe impl Sync for EpState {}
229
224struct ControlPipeSetupState { 230struct ControlPipeSetupState {
225 /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true. 231 /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true.
226 setup_data: UnsafeCell<[u8; 8]>, 232 setup_data: UnsafeCell<[u8; 8]>,
@@ -287,11 +293,22 @@ pub struct Config {
287 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a 293 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
288 /// voltage divider. See ST application note AN4879 and the reference manual for more details. 294 /// voltage divider. See ST application note AN4879 and the reference manual for more details.
289 pub vbus_detection: bool, 295 pub vbus_detection: bool,
296
297 /// Enable transceiver delay.
298 ///
299 /// Some ULPI PHYs like the Microchip USB334x series require a delay between the ULPI register write that initiates
300 /// the HS Chirp and the subsequent transmit command, otherwise the HS Chirp does not get executed and the deivce
301 /// enumerates in FS mode. Some USB Link IP like those in the STM32H7 series support adding this delay to work with
302 /// the affected PHYs.
303 pub xcvrdly: bool,
290} 304}
291 305
292impl Default for Config { 306impl Default for Config {
293 fn default() -> Self { 307 fn default() -> Self {
294 Self { vbus_detection: false } 308 Self {
309 vbus_detection: false,
310 xcvrdly: false,
311 }
295 } 312 }
296} 313}
297 314
@@ -575,6 +592,9 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
575 r.dcfg().write(|w| { 592 r.dcfg().write(|w| {
576 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); 593 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
577 w.set_dspd(phy_type.to_dspd()); 594 w.set_dspd(phy_type.to_dspd());
595 if self.config.xcvrdly {
596 w.set_xcvrdly(true);
597 }
578 }); 598 });
579 599
580 // Unmask transfer complete EP interrupt 600 // Unmask transfer complete EP interrupt
@@ -1034,7 +1054,7 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1034 return Poll::Ready(Err(EndpointError::BufferOverflow)); 1054 return Poll::Ready(Err(EndpointError::BufferOverflow));
1035 } 1055 }
1036 1056
1037 // SAFETY: exclusive access ensured by `ep_out_size` atomic variable 1057 // SAFETY: exclusive access ensured by `out_size` atomic variable
1038 let data = unsafe { core::slice::from_raw_parts(*self.state.out_buffer.get(), len as usize) }; 1058 let data = unsafe { core::slice::from_raw_parts(*self.state.out_buffer.get(), len as usize) };
1039 buf[..len as usize].copy_from_slice(data); 1059 buf[..len as usize].copy_from_slice(data);
1040 1060
diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md
index 00f3be06c..5f665ed25 100644
--- a/embassy-usb/CHANGELOG.md
+++ b/embassy-usb/CHANGELOG.md
@@ -7,8 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.2.0 - 2024-04-23 10## 0.2.0 - 2024-05-20
11 11
12- [#2862](https://github.com/embassy-rs/embassy/pull/2862) WebUSB implementation by @chmanie
12- Removed dynamically sized `device_descriptor` fields 13- Removed dynamically sized `device_descriptor` fields
13 14
14## 0.1.0 - 2024-01-11 15## 0.1.0 - 2024-01-11
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 73d19c28b..5178a690f 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -15,7 +15,7 @@ embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defm
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] }
20cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } 20cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] }
21 21
diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs
index d334d35d7..5b9d7027e 100644
--- a/examples/rp/src/bin/interrupt.rs
+++ b/examples/rp/src/bin/interrupt.rs
@@ -15,7 +15,6 @@ use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking}; 15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::gpio::Pull; 16use embassy_rp::gpio::Pull;
17use embassy_rp::interrupt; 17use embassy_rp::interrupt;
18use embassy_rp::peripherals::PWM_SLICE4;
19use embassy_rp::pwm::{Config, Pwm}; 18use embassy_rp::pwm::{Config, Pwm};
20use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 19use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
21use embassy_sync::blocking_mutex::Mutex; 20use embassy_sync::blocking_mutex::Mutex;
@@ -26,7 +25,7 @@ use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
27 26
28static COUNTER: AtomicU32 = AtomicU32::new(0); 27static COUNTER: AtomicU32 = AtomicU32::new(0);
29static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm<PWM_SLICE4>>>> = Mutex::new(RefCell::new(None)); 28static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
30static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> = 29static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
31 Mutex::new(RefCell::new(None)); 30 Mutex::new(RefCell::new(None));
32static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new(); 31static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs
new file mode 100644
index 000000000..085be280b
--- /dev/null
+++ b/examples/rp/src/bin/uart_r503.rs
@@ -0,0 +1,158 @@
1#![no_std]
2#![no_main]
3
4use defmt::{debug, error, info};
5use embassy_executor::Spawner;
6use embassy_rp::bind_interrupts;
7use embassy_rp::peripherals::UART0;
8use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart};
9use embassy_time::{with_timeout, Duration, Timer};
10use heapless::Vec;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(pub struct Irqs {
14 UART0_IRQ => UARTInterruptHandler<UART0>;
15});
16
17const START: u16 = 0xEF01;
18const ADDRESS: u32 = 0xFFFFFFFF;
19
20// ================================================================================
21
22// Data package format
23// Name Length Description
24// ==========================================================================================================
25// Start 2 bytes Fixed value of 0xEF01; High byte transferred first.
26// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command.
27// High byte transferred first and at wrong adder value, module
28// will reject to transfer.
29// PID 1 byte 01H Command packet;
30// 02H Data packet; Data packet shall not appear alone in executing
31// processs, must follow command packet or acknowledge packet.
32// 07H Acknowledge packet;
33// 08H End of Data packet.
34// LENGTH 2 bytes Refers to the length of package content (command packets and data packets)
35// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes.
36// And high byte is transferred first.
37// DATA - It can be commands, data, command’s parameters, acknowledge result, etc.
38// (fingerprint character value, template are all deemed as data);
39// SUM 2 bytes The arithmetic sum of package identifier, package length and all package
40// contens. Overflowing bits are omitted. high byte is transferred first.
41
42// ================================================================================
43
44// Checksum is calculated on 'length (2 bytes) + data (??)'.
45fn compute_checksum(buf: Vec<u8, 32>) -> u16 {
46 let mut checksum = 0u16;
47
48 let check_end = buf.len();
49 let checked_bytes = &buf[6..check_end];
50 for byte in checked_bytes {
51 checksum += (*byte) as u16;
52 }
53 return checksum;
54}
55
56#[embassy_executor::main]
57async fn main(_spawner: Spawner) {
58 info!("Start");
59
60 let p = embassy_rp::init(Default::default());
61
62 // Initialize the fingerprint scanner.
63 let mut config = Config::default();
64 config.baudrate = 57600;
65 config.stop_bits = StopBits::STOP1;
66 config.data_bits = DataBits::DataBits8;
67 config.parity = Parity::ParityNone;
68
69 let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1);
70 let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config);
71 let (mut tx, mut rx) = uart.split();
72
73 let mut vec_buf: Vec<u8, 32> = heapless::Vec::new();
74 let mut data: Vec<u8, 32> = heapless::Vec::new();
75
76 let mut speeds: Vec<u8, 3> = heapless::Vec::new();
77 let _ = speeds.push(0xC8); // Slow
78 let _ = speeds.push(0x20); // Medium
79 let _ = speeds.push(0x02); // Fast
80
81 // Cycle through the three colours Red, Blue and Purple forever.
82 loop {
83 for colour in 1..=3 {
84 for speed in &speeds {
85 // Set the data first, because the length is dependent on that.
86 // However, we write the length bits before we do the data.
87 data.clear();
88 let _ = data.push(0x01); // ctrl=Breathing light
89 let _ = data.push(*speed);
90 let _ = data.push(colour as u8); // colour=Red, Blue, Purple
91 let _ = data.push(0x00); // times=Infinite
92
93 // Clear buffers
94 vec_buf.clear();
95
96 // START
97 let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]);
98
99 // ADDRESS
100 let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]);
101
102 // PID
103 let _ = vec_buf.extend_from_slice(&[0x01]);
104
105 // LENGTH
106 let len: u16 = (1 + data.len() + 2).try_into().unwrap();
107 let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]);
108
109 // COMMAND
110 let _ = vec_buf.push(0x35); // Command: AuraLedConfig
111
112 // DATA
113 let _ = vec_buf.extend_from_slice(&data);
114
115 // SUM
116 let chk = compute_checksum(vec_buf.clone());
117 let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]);
118
119 // =====
120
121 // Send command buffer.
122 let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap();
123 debug!(" write='{:?}'", data_write[..]);
124 match tx.write(&data_write).await {
125 Ok(..) => info!("Write successful."),
126 Err(e) => error!("Write error: {:?}", e),
127 }
128
129 // =====
130
131 // Read command buffer.
132 let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time!
133 let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer.
134
135 info!("Attempting read.");
136 loop {
137 // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms
138 // for this command.
139 match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await {
140 Ok(..) => {
141 // Extract and save read byte.
142 debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]);
143 let _ = data_read.push(read_buf[0]).unwrap();
144 }
145 Err(..) => break, // TimeoutError -> Ignore.
146 }
147 }
148 info!("Read successful");
149 debug!(" read='{:?}'", data_read[..]);
150
151 Timer::after_secs(3).await;
152 info!("Changing speed.");
153 }
154
155 info!("Changing colour.");
156 }
157 }
158}
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 64ac50818..1eb1ae6db 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs
new file mode 100644
index 000000000..49de33d2b
--- /dev/null
+++ b/examples/stm32f4/src/bin/input_capture.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14/// Connect PB2 and PB10 with a 1k Ohm resistor
15
16#[embassy_executor::task]
17async fn blinky(led: peripherals::PB2) {
18 let mut led = Output::new(led, Level::High, Speed::Low);
19
20 loop {
21 info!("high");
22 led.set_high();
23 Timer::after_millis(300).await;
24
25 info!("low");
26 led.set_low();
27 Timer::after_millis(300).await;
28 }
29}
30
31bind_interrupts!(struct Irqs {
32 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
33});
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_stm32::init(Default::default());
38 info!("Hello World!");
39
40 unwrap!(spawner.spawn(blinky(p.PB2)));
41
42 let ch3 = CapturePin::new_ch3(p.PB10, Pull::None);
43 let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
44
45 loop {
46 info!("wait for risign edge");
47 ic.wait_for_rising_edge(Channel::Ch3).await;
48
49 let capture_value = ic.get_capture_value(Channel::Ch3);
50 info!("new capture! {}", capture_value);
51 }
52}
diff --git a/examples/stm32f469/.cargo/config.toml b/examples/stm32f469/.cargo/config.toml
new file mode 100644
index 000000000..05250954f
--- /dev/null
+++ b/examples/stm32f469/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32F469NIHx"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml
new file mode 100644
index 000000000..7718a46c1
--- /dev/null
+++ b/examples/stm32f469/Cargo.toml
@@ -0,0 +1,22 @@
1[package]
2edition = "2021"
3name = "embassy-stm32f469-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Specific examples only for stm32f469
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12
13defmt = "0.3"
14defmt-rtt = "0.4"
15
16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18embedded-hal = "1.0.0"
19panic-probe = { version = "0.3", features = ["print-defmt"] }
20
21[profile.release]
22debug = 2
diff --git a/examples/stm32f469/build.rs b/examples/stm32f469/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32f469/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs
new file mode 100644
index 000000000..e4e9e9c01
--- /dev/null
+++ b/examples/stm32f469/src/bin/dsi_bsp.rs
@@ -0,0 +1,694 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType};
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::ltdc::Ltdc;
9use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1};
10use embassy_stm32::pac::ltdc::vals::{Bf1, Bf2, Depol, Hspol, Imr, Pcpol, Pf, Vspol};
11use embassy_stm32::pac::{DSIHOST, LTDC};
12use embassy_stm32::rcc::{
13 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk,
14};
15use embassy_stm32::time::mhz;
16use embassy_time::Timer;
17use {defmt_rtt as _, panic_probe as _};
18
19enum _Orientation {
20 Landscape,
21 Portrait,
22}
23
24const _LCD_ORIENTATION: _Orientation = _Orientation::Landscape;
25const LCD_X_SIZE: u16 = 800;
26const LCD_Y_SIZE: u16 = 480;
27
28static FERRIS_IMAGE: &[u8; 1536000] = include_bytes!("ferris.bin");
29
30// This example allows to display an image on the STM32F469NI-DISCO boards
31// with the Revision C, that is at least the boards marked DK32F469I$AU1.
32// These boards have the NT35510 display driver. This example does not work
33// for the older revisions with OTM8009A, though there are lots of C-examples
34// available online where the correct config for the OTM8009A could be gotten from.
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let mut config = embassy_stm32::Config::default();
38 config.rcc.sys = Sysclk::PLL1_P;
39 config.rcc.ahb_pre = AHBPrescaler::DIV1;
40 config.rcc.apb1_pre = APBPrescaler::DIV4;
41 config.rcc.apb2_pre = APBPrescaler::DIV2;
42
43 // HSE is on and ready
44 config.rcc.hse = Some(Hse {
45 freq: mhz(8),
46 mode: HseMode::Oscillator,
47 });
48 config.rcc.pll_src = PllSource::HSE;
49
50 config.rcc.pll = Some(Pll {
51 prediv: PllPreDiv::DIV8, // PLLM
52 mul: PllMul::MUL360, // PLLN
53 divp: Some(PllPDiv::DIV2),
54 divq: Some(PllQDiv::DIV7), // was DIV4, but STM BSP example uses 7
55 divr: Some(PllRDiv::DIV6),
56 });
57
58 // This seems to be working, the values in the RCC.PLLSAICFGR are correct according to the debugger. Also on and ready according to CR
59 config.rcc.pllsai = Some(Pll {
60 prediv: PllPreDiv::DIV8, // Actually ignored
61 mul: PllMul::MUL384, // PLLN
62 divp: None, // PLLP
63 divq: None, // PLLQ
64 divr: Some(PllRDiv::DIV7), // PLLR (Sai actually has special clockdiv register)
65 });
66
67 let p = embassy_stm32::init(config);
68 info!("Starting...");
69
70 let mut led = Output::new(p.PG6, Level::High, Speed::Low);
71
72 // According to UM for the discovery kit, PH7 is an active-low reset for the LCD and touchsensor
73 let mut reset = Output::new(p.PH7, Level::Low, Speed::High);
74
75 // CubeMX example waits 20 ms before de-asserting reset
76 embassy_time::block_for(embassy_time::Duration::from_millis(20));
77
78 // Disable the reset signal and wait 140ms as in the Linux driver (CubeMX waits only 20)
79 reset.set_high();
80 embassy_time::block_for(embassy_time::Duration::from_millis(140));
81
82 let mut ltdc = Ltdc::new(p.LTDC);
83 let mut dsi = DsiHost::new(p.DSIHOST, p.PJ2);
84 let version = dsi.get_version();
85 defmt::warn!("en: {:x}", version);
86
87 // Disable the DSI wrapper
88 dsi.disable_wrapper_dsi();
89
90 // Disable the DSI host
91 dsi.disable();
92
93 // D-PHY clock and digital disable
94 DSIHOST.pctlr().modify(|w| {
95 w.set_cke(false);
96 w.set_den(false)
97 });
98
99 // Turn off the DSI PLL
100 DSIHOST.wrpcr().modify(|w| w.set_pllen(false));
101
102 // Disable the regulator
103 DSIHOST.wrpcr().write(|w| w.set_regen(false));
104
105 // Enable regulator
106 info!("DSIHOST: enabling regulator");
107 DSIHOST.wrpcr().write(|w| w.set_regen(true));
108
109 for _ in 1..1000 {
110 // The regulator status (ready or not) can be monitored with the RRS flag in the DSI_WISR register.
111 // Once it is set, we stop waiting.
112 if DSIHOST.wisr().read().rrs() {
113 info!("DSIHOST Regulator ready");
114 break;
115 }
116 embassy_time::block_for(embassy_time::Duration::from_millis(1));
117 }
118
119 if !DSIHOST.wisr().read().rrs() {
120 defmt::panic!("DSIHOST: enabling regulator FAILED");
121 }
122
123 // Set up PLL and enable it
124 DSIHOST.wrpcr().modify(|w| {
125 w.set_pllen(true);
126 w.set_ndiv(125); // PLL loop division factor set to 125
127 w.set_idf(2); // PLL input divided by 2
128 w.set_odf(0); // PLL output divided by 1
129 });
130
131 /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */
132 const LANE_BYTE_CLK_K_HZ: u16 = 62500; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L224C21-L224C26
133
134 const _LCD_CLOCK: u16 = 27429; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L183
135
136 /* TX_ESCAPE_CKDIV = f(LaneByteClk)/15.62 = 4 */
137 const TX_ESCAPE_CKDIV: u8 = (LANE_BYTE_CLK_K_HZ / 15620) as u8; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L230
138
139 for _ in 1..1000 {
140 embassy_time::block_for(embassy_time::Duration::from_millis(1));
141 // The PLL status (lock or unlock) can be monitored with the PLLLS flag in the DSI_WISR register.
142 // Once it is set, we stop waiting.
143 if DSIHOST.wisr().read().pllls() {
144 info!("DSIHOST PLL locked");
145 break;
146 }
147 }
148
149 if !DSIHOST.wisr().read().pllls() {
150 defmt::panic!("DSIHOST: enabling PLL FAILED");
151 }
152
153 // Set the PHY parameters
154
155 // D-PHY clock and digital enable
156 DSIHOST.pctlr().write(|w| {
157 w.set_cke(true);
158 w.set_den(true);
159 });
160
161 // Set Clock lane to high-speed mode and disable automatic clock lane control
162 DSIHOST.clcr().modify(|w| {
163 w.set_dpcc(true);
164 w.set_acr(false);
165 });
166
167 // Set number of active data lanes to two (lanes 0 and 1)
168 DSIHOST.pconfr().modify(|w| w.set_nl(1));
169
170 // Set the DSI clock parameters
171
172 // Set the TX escape clock division factor to 4
173 DSIHOST.ccr().modify(|w| w.set_txeckdiv(TX_ESCAPE_CKDIV));
174
175 // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4)
176 // The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 )
177 // Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF)
178 // Set the bit period in high-speed mode
179 DSIHOST.wpcr0().modify(|w| w.set_uix4(8)); // 8 is set in the BSP example (confirmed with Debugger)
180
181 // Disable all error interrupts and reset the Error Mask
182 DSIHOST.ier0().write_value(Ier0(0));
183 DSIHOST.ier1().write_value(Ier1(0));
184
185 // Enable this to fix read timeout
186 DSIHOST.pcr().modify(|w| w.set_btae(true));
187
188 const DSI_PIXEL_FORMAT_RGB888: u8 = 0x05;
189 const _DSI_PIXEL_FORMAT_ARGB888: u8 = 0x00;
190
191 const HACT: u16 = LCD_X_SIZE;
192 const VACT: u16 = LCD_Y_SIZE;
193
194 const VSA: u16 = 120;
195 const VBP: u16 = 150;
196 const VFP: u16 = 150;
197 const HSA: u16 = 2;
198 const HBP: u16 = 34;
199 const HFP: u16 = 34;
200
201 const VIRTUAL_CHANNEL_ID: u8 = 0;
202
203 const COLOR_CODING: u8 = DSI_PIXEL_FORMAT_RGB888;
204 const VS_POLARITY: bool = false; // DSI_VSYNC_ACTIVE_HIGH == 0
205 const HS_POLARITY: bool = false; // DSI_HSYNC_ACTIVE_HIGH == 0
206 const DE_POLARITY: bool = false; // DSI_DATA_ENABLE_ACTIVE_HIGH == 0
207 const MODE: u8 = 2; // DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
208 const NULL_PACKET_SIZE: u16 = 0xFFF;
209 const NUMBER_OF_CHUNKS: u16 = 0;
210 const PACKET_SIZE: u16 = HACT; /* Value depending on display orientation choice portrait/landscape */
211 const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16;
212 const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16;
213 const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */
214 // FIXME: Make depend on orientation
215 const VERTICAL_SYNC_ACTIVE: u16 = VSA;
216 const VERTICAL_BACK_PORCH: u16 = VBP;
217 const VERTICAL_FRONT_PORCH: u16 = VFP;
218 const VERTICAL_ACTIVE: u16 = VACT;
219 const LP_COMMAND_ENABLE: bool = true; /* Enable sending commands in mode LP (Low Power) */
220
221 /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */
222 /* Only useful when sending LP packets is allowed while streaming is active in video mode */
223 const LP_LARGEST_PACKET_SIZE: u8 = 16;
224
225 /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
226 /* Only useful when sending LP packets is allowed while streaming is active in video mode */
227 const LPVACT_LARGEST_PACKET_SIZE: u8 = 0;
228
229 const LPHORIZONTAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HFP period */
230 const LPHORIZONTAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HBP period */
231 const LPVERTICAL_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VACT period */
232 const LPVERTICAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VFP period */
233 const LPVERTICAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VBP period */
234 const LPVERTICAL_SYNC_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VSync = VSA period */
235 const FRAME_BTAACKNOWLEDGE_ENABLE: bool = false; /* Frame bus-turn-around acknowledge enable => false according to debugger */
236
237 /* Select video mode by resetting CMDM and DSIM bits */
238 DSIHOST.mcr().modify(|w| w.set_cmdm(false));
239 DSIHOST.wcfgr().modify(|w| w.set_dsim(false));
240
241 /* Configure the video mode transmission type */
242 DSIHOST.vmcr().modify(|w| w.set_vmt(MODE));
243
244 /* Configure the video packet size */
245 DSIHOST.vpcr().modify(|w| w.set_vpsize(PACKET_SIZE));
246
247 /* Set the chunks number to be transmitted through the DSI link */
248 DSIHOST.vccr().modify(|w| w.set_numc(NUMBER_OF_CHUNKS));
249
250 /* Set the size of the null packet */
251 DSIHOST.vnpcr().modify(|w| w.set_npsize(NULL_PACKET_SIZE));
252
253 /* Select the virtual channel for the LTDC interface traffic */
254 DSIHOST.lvcidr().modify(|w| w.set_vcid(VIRTUAL_CHANNEL_ID));
255
256 /* Configure the polarity of control signals */
257 DSIHOST.lpcr().modify(|w| {
258 w.set_dep(DE_POLARITY);
259 w.set_hsp(HS_POLARITY);
260 w.set_vsp(VS_POLARITY);
261 });
262
263 /* Select the color coding for the host */
264 DSIHOST.lcolcr().modify(|w| w.set_colc(COLOR_CODING));
265
266 /* Select the color coding for the wrapper */
267 DSIHOST.wcfgr().modify(|w| w.set_colmux(COLOR_CODING));
268
269 /* Set the Horizontal Synchronization Active (HSA) in lane byte clock cycles */
270 DSIHOST.vhsacr().modify(|w| w.set_hsa(HORIZONTAL_SYNC_ACTIVE));
271
272 /* Set the Horizontal Back Porch (HBP) in lane byte clock cycles */
273 DSIHOST.vhbpcr().modify(|w| w.set_hbp(HORIZONTAL_BACK_PORCH));
274
275 /* Set the total line time (HLINE=HSA+HBP+HACT+HFP) in lane byte clock cycles */
276 DSIHOST.vlcr().modify(|w| w.set_hline(HORIZONTAL_LINE));
277
278 /* Set the Vertical Synchronization Active (VSA) */
279 DSIHOST.vvsacr().modify(|w| w.set_vsa(VERTICAL_SYNC_ACTIVE));
280
281 /* Set the Vertical Back Porch (VBP)*/
282 DSIHOST.vvbpcr().modify(|w| w.set_vbp(VERTICAL_BACK_PORCH));
283
284 /* Set the Vertical Front Porch (VFP)*/
285 DSIHOST.vvfpcr().modify(|w| w.set_vfp(VERTICAL_FRONT_PORCH));
286
287 /* Set the Vertical Active period*/
288 DSIHOST.vvacr().modify(|w| w.set_va(VERTICAL_ACTIVE));
289
290 /* Configure the command transmission mode */
291 DSIHOST.vmcr().modify(|w| w.set_lpce(LP_COMMAND_ENABLE));
292
293 /* Low power largest packet size */
294 DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
295
296 /* Low power VACT largest packet size */
297 DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
298 DSIHOST.lpmcr().modify(|w| w.set_vlpsize(LPVACT_LARGEST_PACKET_SIZE));
299
300 /* Enable LP transition in HFP period */
301 DSIHOST.vmcr().modify(|w| w.set_lphfpe(LPHORIZONTAL_FRONT_PORCH_ENABLE));
302
303 /* Enable LP transition in HBP period */
304 DSIHOST.vmcr().modify(|w| w.set_lphbpe(LPHORIZONTAL_BACK_PORCH_ENABLE));
305
306 /* Enable LP transition in VACT period */
307 DSIHOST.vmcr().modify(|w| w.set_lpvae(LPVERTICAL_ACTIVE_ENABLE));
308
309 /* Enable LP transition in VFP period */
310 DSIHOST.vmcr().modify(|w| w.set_lpvfpe(LPVERTICAL_FRONT_PORCH_ENABLE));
311
312 /* Enable LP transition in VBP period */
313 DSIHOST.vmcr().modify(|w| w.set_lpvbpe(LPVERTICAL_BACK_PORCH_ENABLE));
314
315 /* Enable LP transition in vertical sync period */
316 DSIHOST.vmcr().modify(|w| w.set_lpvsae(LPVERTICAL_SYNC_ACTIVE_ENABLE));
317
318 /* Enable the request for an acknowledge response at the end of a frame */
319 DSIHOST.vmcr().modify(|w| w.set_fbtaae(FRAME_BTAACKNOWLEDGE_ENABLE));
320
321 /* Configure DSI PHY HS2LP and LP2HS timings */
322 const CLOCK_LANE_HS2_LPTIME: u16 = 35;
323 const CLOCK_LANE_LP2_HSTIME: u16 = 35;
324 const DATA_LANE_HS2_LPTIME: u8 = 35;
325 const DATA_LANE_LP2_HSTIME: u8 = 35;
326 const DATA_LANE_MAX_READ_TIME: u16 = 0;
327 const STOP_WAIT_TIME: u8 = 10;
328
329 const MAX_TIME: u16 = if CLOCK_LANE_HS2_LPTIME > CLOCK_LANE_LP2_HSTIME {
330 CLOCK_LANE_HS2_LPTIME
331 } else {
332 CLOCK_LANE_LP2_HSTIME
333 };
334
335 /* Clock lane timer configuration */
336
337 /* In Automatic Clock Lane control mode, the DSI Host can turn off the clock lane between two
338 High-Speed transmission.
339 To do so, the DSI Host calculates the time required for the clock lane to change from HighSpeed
340 to Low-Power and from Low-Power to High-Speed.
341 This timings are configured by the HS2LP_TIME and LP2HS_TIME in the DSI Host Clock Lane Timer Configuration
342 Register (DSI_CLTCR).
343 But the DSI Host is not calculating LP2HS_TIME + HS2LP_TIME but 2 x HS2LP_TIME.
344
345 Workaround : Configure HS2LP_TIME and LP2HS_TIME with the same value being the max of HS2LP_TIME or LP2HS_TIME.
346 */
347
348 DSIHOST.cltcr().modify(|w| {
349 w.set_hs2lp_time(MAX_TIME);
350 w.set_lp2hs_time(MAX_TIME)
351 });
352
353 // Data lane timer configuration
354 DSIHOST.dltcr().modify(|w| {
355 w.set_hs2lp_time(DATA_LANE_HS2_LPTIME);
356 w.set_lp2hs_time(DATA_LANE_LP2_HSTIME);
357 w.set_mrd_time(DATA_LANE_MAX_READ_TIME);
358 });
359
360 // Configure the wait period to request HS transmission after a stop state
361 DSIHOST.pconfr().modify(|w| w.set_sw_time(STOP_WAIT_TIME));
362
363 const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0
364
365 const LTDC_DE_POLARITY: Depol = if !DE_POLARITY {
366 Depol::ACTIVELOW
367 } else {
368 Depol::ACTIVEHIGH
369 };
370 const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY {
371 Vspol::ACTIVEHIGH
372 } else {
373 Vspol::ACTIVELOW
374 };
375
376 const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY {
377 Hspol::ACTIVEHIGH
378 } else {
379 Hspol::ACTIVELOW
380 };
381
382 /* Timing Configuration */
383 const HORIZONTAL_SYNC: u16 = HSA - 1;
384 const VERTICAL_SYNC: u16 = VERTICAL_SYNC_ACTIVE - 1;
385 const ACCUMULATED_HBP: u16 = HSA + HBP - 1;
386 const ACCUMULATED_VBP: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH - 1;
387 const ACCUMULATED_ACTIVE_W: u16 = LCD_X_SIZE + HSA + HBP - 1;
388 const ACCUMULATED_ACTIVE_H: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE - 1;
389 const TOTAL_WIDTH: u16 = LCD_X_SIZE + HSA + HBP + HFP - 1;
390 const TOTAL_HEIGHT: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE + VERTICAL_FRONT_PORCH - 1;
391
392 // DISABLE LTDC before making changes
393 ltdc.disable();
394
395 // Configure the HS, VS, DE and PC polarity
396 LTDC.gcr().modify(|w| {
397 w.set_hspol(LTDC_HS_POLARITY);
398 w.set_vspol(LTDC_VS_POLARITY);
399 w.set_depol(LTDC_DE_POLARITY);
400 w.set_pcpol(Pcpol::RISINGEDGE);
401 });
402
403 // Set Synchronization size
404 LTDC.sscr().modify(|w| {
405 w.set_hsw(HORIZONTAL_SYNC);
406 w.set_vsh(VERTICAL_SYNC)
407 });
408
409 // Set Accumulated Back porch
410 LTDC.bpcr().modify(|w| {
411 w.set_ahbp(ACCUMULATED_HBP);
412 w.set_avbp(ACCUMULATED_VBP);
413 });
414
415 // Set Accumulated Active Width
416 LTDC.awcr().modify(|w| {
417 w.set_aah(ACCUMULATED_ACTIVE_H);
418 w.set_aaw(ACCUMULATED_ACTIVE_W);
419 });
420
421 // Set Total Width
422 LTDC.twcr().modify(|w| {
423 w.set_totalh(TOTAL_HEIGHT);
424 w.set_totalw(TOTAL_WIDTH);
425 });
426
427 // Set the background color value
428 LTDC.bccr().modify(|w| {
429 w.set_bcred(0);
430 w.set_bcgreen(0);
431 w.set_bcblue(0)
432 });
433
434 // Enable the Transfer Error and FIFO underrun interrupts
435 LTDC.ier().modify(|w| {
436 w.set_terrie(true);
437 w.set_fuie(true);
438 });
439
440 // ENABLE LTDC after making changes
441 ltdc.enable();
442
443 dsi.enable();
444 dsi.enable_wrapper_dsi();
445
446 // First, delay 120 ms (reason unknown, STM32 Cube Example does it)
447 blocking_delay_ms(120);
448
449 // 1 to 26
450 dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap();
451 dsi.write_cmd(0, NT35510_WRITES_1[0], &NT35510_WRITES_1[1..]).unwrap();
452 dsi.write_cmd(0, NT35510_WRITES_2[0], &NT35510_WRITES_2[1..]).unwrap();
453 dsi.write_cmd(0, NT35510_WRITES_3[0], &NT35510_WRITES_3[1..]).unwrap();
454 dsi.write_cmd(0, NT35510_WRITES_4[0], &NT35510_WRITES_4[1..]).unwrap();
455 dsi.write_cmd(0, NT35510_WRITES_5[0], &NT35510_WRITES_5[1..]).unwrap();
456 dsi.write_cmd(0, NT35510_WRITES_6[0], &NT35510_WRITES_6[1..]).unwrap();
457 dsi.write_cmd(0, NT35510_WRITES_7[0], &NT35510_WRITES_7[1..]).unwrap();
458 dsi.write_cmd(0, NT35510_WRITES_8[0], &NT35510_WRITES_8[1..]).unwrap();
459 dsi.write_cmd(0, NT35510_WRITES_9[0], &NT35510_WRITES_9[1..]).unwrap();
460 dsi.write_cmd(0, NT35510_WRITES_10[0], &NT35510_WRITES_10[1..]).unwrap();
461 // 11 missing
462 dsi.write_cmd(0, NT35510_WRITES_12[0], &NT35510_WRITES_12[1..]).unwrap();
463 dsi.write_cmd(0, NT35510_WRITES_13[0], &NT35510_WRITES_13[1..]).unwrap();
464 dsi.write_cmd(0, NT35510_WRITES_14[0], &NT35510_WRITES_14[1..]).unwrap();
465 dsi.write_cmd(0, NT35510_WRITES_15[0], &NT35510_WRITES_15[1..]).unwrap();
466 dsi.write_cmd(0, NT35510_WRITES_16[0], &NT35510_WRITES_16[1..]).unwrap();
467 dsi.write_cmd(0, NT35510_WRITES_17[0], &NT35510_WRITES_17[1..]).unwrap();
468 dsi.write_cmd(0, NT35510_WRITES_18[0], &NT35510_WRITES_18[1..]).unwrap();
469 dsi.write_cmd(0, NT35510_WRITES_19[0], &NT35510_WRITES_19[1..]).unwrap();
470 dsi.write_cmd(0, NT35510_WRITES_20[0], &NT35510_WRITES_20[1..]).unwrap();
471 dsi.write_cmd(0, NT35510_WRITES_21[0], &NT35510_WRITES_21[1..]).unwrap();
472 dsi.write_cmd(0, NT35510_WRITES_22[0], &NT35510_WRITES_22[1..]).unwrap();
473 dsi.write_cmd(0, NT35510_WRITES_23[0], &NT35510_WRITES_23[1..]).unwrap();
474 dsi.write_cmd(0, NT35510_WRITES_24[0], &NT35510_WRITES_24[1..]).unwrap();
475
476 // Tear on
477 dsi.write_cmd(0, NT35510_WRITES_26[0], &NT35510_WRITES_26[1..]).unwrap();
478
479 // Set Pixel color format to RGB888
480 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
481
482 // Add a delay, otherwise MADCTL not taken
483 blocking_delay_ms(200);
484
485 // Configure orientation as landscape
486 dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..])
487 .unwrap();
488 dsi.write_cmd(0, NT35510_CASET_LANDSCAPE[0], &NT35510_CASET_LANDSCAPE[1..])
489 .unwrap();
490 dsi.write_cmd(0, NT35510_RASET_LANDSCAPE[0], &NT35510_RASET_LANDSCAPE[1..])
491 .unwrap();
492
493 // Sleep out
494 dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap();
495
496 // Wait for sleep out exit
497 blocking_delay_ms(120);
498
499 // Configure COLOR_CODING
500 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
501
502 /* CABC : Content Adaptive Backlight Control section start >> */
503 /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */
504 dsi.write_cmd(0, NT35510_WRITES_31[0], &NT35510_WRITES_31[1..]).unwrap();
505 /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */
506 dsi.write_cmd(0, NT35510_WRITES_32[0], &NT35510_WRITES_32[1..]).unwrap();
507 /* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */
508 dsi.write_cmd(0, NT35510_WRITES_33[0], &NT35510_WRITES_33[1..]).unwrap();
509 /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */
510 dsi.write_cmd(0, NT35510_WRITES_34[0], &NT35510_WRITES_34[1..]).unwrap();
511 /* CABC : Content Adaptive Backlight Control section end << */
512 /* Display on */
513 dsi.write_cmd(0, NT35510_WRITES_30[0], &NT35510_WRITES_30[1..]).unwrap();
514
515 /* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */
516 /* DSI host from LTDC incoming pixels in video mode */
517 dsi.write_cmd(0, NT35510_WRITES_35[0], &NT35510_WRITES_35[1..]).unwrap();
518
519 /* Initialize the LCD pixel width and pixel height */
520 const WINDOW_X0: u16 = 0;
521 const WINDOW_X1: u16 = LCD_X_SIZE; // 480 for ferris
522 const WINDOW_Y0: u16 = 0;
523 const WINDOW_Y1: u16 = LCD_Y_SIZE; // 800 for ferris
524 const PIXEL_FORMAT: Pf = Pf::ARGB8888;
525 //const FBStartAdress: u16 = FB_Address;
526 const ALPHA: u8 = 255;
527 const ALPHA0: u8 = 0;
528 const BACKCOLOR_BLUE: u8 = 0;
529 const BACKCOLOR_GREEN: u8 = 0;
530 const BACKCOLOR_RED: u8 = 0;
531 const IMAGE_WIDTH: u16 = LCD_X_SIZE; // 480 for ferris
532 const IMAGE_HEIGHT: u16 = LCD_Y_SIZE; // 800 for ferris
533
534 const PIXEL_SIZE: u8 = match PIXEL_FORMAT {
535 Pf::ARGB8888 => 4,
536 Pf::RGB888 => 3,
537 Pf::ARGB4444 | Pf::RGB565 | Pf::ARGB1555 | Pf::AL88 => 2,
538 _ => 1,
539 };
540
541 // Configure the horizontal start and stop position
542 LTDC.layer(0).whpcr().write(|w| {
543 w.set_whstpos(LTDC.bpcr().read().ahbp() + 1 + WINDOW_X0);
544 w.set_whsppos(LTDC.bpcr().read().ahbp() + WINDOW_X1);
545 });
546
547 // Configures the vertical start and stop position
548 LTDC.layer(0).wvpcr().write(|w| {
549 w.set_wvstpos(LTDC.bpcr().read().avbp() + 1 + WINDOW_Y0);
550 w.set_wvsppos(LTDC.bpcr().read().avbp() + WINDOW_Y1);
551 });
552
553 // Specify the pixel format
554 LTDC.layer(0).pfcr().write(|w| w.set_pf(PIXEL_FORMAT));
555
556 // Configures the default color values as zero
557 LTDC.layer(0).dccr().modify(|w| {
558 w.set_dcblue(BACKCOLOR_BLUE);
559 w.set_dcgreen(BACKCOLOR_GREEN);
560 w.set_dcred(BACKCOLOR_RED);
561 w.set_dcalpha(ALPHA0);
562 });
563
564 // Specifies the constant ALPHA value
565 LTDC.layer(0).cacr().write(|w| w.set_consta(ALPHA));
566
567 // Specifies the blending factors
568 LTDC.layer(0).bfcr().write(|w| {
569 w.set_bf1(Bf1::CONSTANT);
570 w.set_bf2(Bf2::CONSTANT);
571 });
572
573 // Configure the color frame buffer start address
574 let fb_start_address: u32 = &FERRIS_IMAGE[0] as *const _ as u32;
575 info!("Setting Framebuffer Start Address: {:010x}", fb_start_address);
576 LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(fb_start_address));
577
578 // Configures the color frame buffer pitch in byte
579 LTDC.layer(0).cfblr().write(|w| {
580 w.set_cfbp(IMAGE_WIDTH * PIXEL_SIZE as u16);
581 w.set_cfbll(((WINDOW_X1 - WINDOW_X0) * PIXEL_SIZE as u16) + 3);
582 });
583
584 // Configures the frame buffer line number
585 LTDC.layer(0).cfblnr().write(|w| w.set_cfblnbr(IMAGE_HEIGHT));
586
587 // Enable LTDC_Layer by setting LEN bit
588 LTDC.layer(0).cr().modify(|w| w.set_len(true));
589
590 //LTDC->SRCR = LTDC_SRCR_IMR;
591 LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD));
592
593 blocking_delay_ms(5000);
594
595 const READ_SIZE: u16 = 1;
596 let mut data = [1u8; READ_SIZE as usize];
597 dsi.read(0, PacketType::DcsShortPktRead(0xDA), READ_SIZE, &mut data)
598 .unwrap();
599 info!("Display ID1: {:#04x}", data);
600
601 dsi.read(0, PacketType::DcsShortPktRead(0xDB), READ_SIZE, &mut data)
602 .unwrap();
603 info!("Display ID2: {:#04x}", data);
604
605 dsi.read(0, PacketType::DcsShortPktRead(0xDC), READ_SIZE, &mut data)
606 .unwrap();
607 info!("Display ID3: {:#04x}", data);
608
609 blocking_delay_ms(500);
610
611 info!("Config done, start blinking LED");
612 loop {
613 led.set_high();
614 Timer::after_millis(1000).await;
615
616 // Increase screen brightness
617 dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0xFF]).unwrap();
618
619 led.set_low();
620 Timer::after_millis(1000).await;
621
622 // Reduce screen brightness
623 dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0x50]).unwrap();
624 }
625}
626
627const NT35510_WRITES_0: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01]; // LV2: Page 1 enable
628const NT35510_WRITES_1: &[u8] = &[0xB0, 0x03, 0x03, 0x03]; // AVDD: 5.2V
629const NT35510_WRITES_2: &[u8] = &[0xB6, 0x46, 0x46, 0x46]; // AVDD: Ratio
630const NT35510_WRITES_3: &[u8] = &[0xB1, 0x03, 0x03, 0x03]; // AVEE: -5.2V
631const NT35510_WRITES_4: &[u8] = &[0xB7, 0x36, 0x36, 0x36]; // AVEE: Ratio
632const NT35510_WRITES_5: &[u8] = &[0xB2, 0x00, 0x00, 0x02]; // VCL: -2.5V
633const NT35510_WRITES_6: &[u8] = &[0xB8, 0x26, 0x26, 0x26]; // VCL: Ratio
634const NT35510_WRITES_7: &[u8] = &[0xBF, 0x01]; // VGH: 15V (Free Pump)
635const NT35510_WRITES_8: &[u8] = &[0xB3, 0x09, 0x09, 0x09];
636const NT35510_WRITES_9: &[u8] = &[0xB9, 0x36, 0x36, 0x36]; // VGH: Ratio
637const NT35510_WRITES_10: &[u8] = &[0xB5, 0x08, 0x08, 0x08]; // VGL_REG: -10V
638const NT35510_WRITES_12: &[u8] = &[0xBA, 0x26, 0x26, 0x26]; // VGLX: Ratio
639const NT35510_WRITES_13: &[u8] = &[0xBC, 0x00, 0x80, 0x00]; // VGMP/VGSP: 4.5V/0V
640const NT35510_WRITES_14: &[u8] = &[0xBD, 0x00, 0x80, 0x00]; // VGMN/VGSN:-4.5V/0V
641const NT35510_WRITES_15: &[u8] = &[0xBE, 0x00, 0x50]; // VCOM: -1.325V
642const NT35510_WRITES_16: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00]; // LV2: Page 0 enable
643const NT35510_WRITES_17: &[u8] = &[0xB1, 0xFC, 0x00]; // Display control
644const NT35510_WRITES_18: &[u8] = &[0xB6, 0x03]; // Src hold time
645const NT35510_WRITES_19: &[u8] = &[0xB5, 0x51];
646const NT35510_WRITES_20: &[u8] = &[0x00, 0x00, 0xB7]; // Gate EQ control
647const NT35510_WRITES_21: &[u8] = &[0xB8, 0x01, 0x02, 0x02, 0x02]; // Src EQ control(Mode2)
648const NT35510_WRITES_22: &[u8] = &[0xBC, 0x00, 0x00, 0x00]; // Inv. mode(2-dot)
649const NT35510_WRITES_23: &[u8] = &[0xCC, 0x03, 0x00, 0x00];
650const NT35510_WRITES_24: &[u8] = &[0xBA, 0x01];
651
652const _NT35510_MADCTL_PORTRAIT: &[u8] = &[NT35510_CMD_MADCTL, 0x00];
653const _NT35510_CASET_PORTRAIT: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x01, 0xDF];
654const _NT35510_RASET_PORTRAIT: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x03, 0x1F];
655const NT35510_MADCTL_LANDSCAPE: &[u8] = &[NT35510_CMD_MADCTL, 0x60];
656const NT35510_CASET_LANDSCAPE: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x03, 0x1F];
657const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0xDF];
658
659const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on
660const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out
661 // 28,29 missing
662const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on
663
664const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F];
665const NT35510_WRITES_32: &[u8] = &[NT35510_CMD_WRCTRLD, 0x2C];
666const NT35510_WRITES_33: &[u8] = &[NT35510_CMD_WRCABC, 0x02];
667const NT35510_WRITES_34: &[u8] = &[NT35510_CMD_WRCABCMB, 0xFF];
668const NT35510_WRITES_35: &[u8] = &[NT35510_CMD_RAMWR, 0x00];
669
670//const NT35510_WRITES_36: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB565]; // FIXME: Example sets it to 888 but rest of the code seems to configure DSI for 565
671const NT35510_WRITES_37: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB888];
672
673// More of these: https://elixir.bootlin.com/linux/latest/source/include/video/mipi_display.h#L83
674const _NT35510_CMD_TEEON_GET_DISPLAY_ID: u8 = 0x04;
675
676const NT35510_CMD_TEEON: u8 = 0x35;
677const NT35510_CMD_MADCTL: u8 = 0x36;
678
679const NT35510_CMD_SLPOUT: u8 = 0x11;
680const NT35510_CMD_DISPON: u8 = 0x29;
681const NT35510_CMD_CASET: u8 = 0x2A;
682const NT35510_CMD_RASET: u8 = 0x2B;
683const NT35510_CMD_RAMWR: u8 = 0x2C; /* Memory write */
684const NT35510_CMD_COLMOD: u8 = 0x3A;
685
686const NT35510_CMD_WRDISBV: u8 = 0x51; /* Write display brightness */
687const _NT35510_CMD_RDDISBV: u8 = 0x52; /* Read display brightness */
688const NT35510_CMD_WRCTRLD: u8 = 0x53; /* Write CTRL display */
689const _NT35510_CMD_RDCTRLD: u8 = 0x54; /* Read CTRL display value */
690const NT35510_CMD_WRCABC: u8 = 0x55; /* Write content adaptative brightness control */
691const NT35510_CMD_WRCABCMB: u8 = 0x5E; /* Write CABC minimum brightness */
692
693const _NT35510_COLMOD_RGB565: u8 = 0x55;
694const NT35510_COLMOD_RGB888: u8 = 0x77;
diff --git a/examples/stm32f469/src/bin/ferris.bin b/examples/stm32f469/src/bin/ferris.bin
new file mode 100644
index 000000000..ae1c466be
--- /dev/null
+++ b/examples/stm32f469/src/bin/ferris.bin
@@ -0,0 +1,70 @@
1��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������f���2���
2���
3���
4�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������=���
5�������������������������������������������������������������������������������������������������������������������������������I���
6���
7�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%���
8���
9���
10���
11���������������������������������������������������������������������������������������������������������������������������T���
12���������������������������������������������������������������������������������������������������2���
13���=���c�����������������������������������G���
14
15
16
17e��
18
19
20�������������������������������������������������������������������������������������������������������������������������hhh�
21_��
22_��
23
24(�
25
26.�
271�
28-�
29
30.��
31.��Yb��������������
32M��
33.��S]����������������������������������
34.��
35.��
36-�
37.��
38.��
39.��v{������������������������������_f��%9��,��
405�
41.��
42L����������������������������������������������������������������������������������������������
43.��|������������������������������������������������������������������
44-�
45.��
46
47
48M��
493�
50-�
510�
522�
53.�
54'�
55.����������������������������������������������������������������������������������������������%T��
56M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������lx��
576�
58M��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fu��
593�
60M��
61/�
622�
63J��
64.��
65.����������������������������������������������������������������������������������������������������������Sl��
66H��
67M��
68.��
69M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������q|��O��
70M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(T��
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs
index 005694db3..90d319b7a 100644
--- a/examples/stm32f7/src/bin/qspi.rs
+++ b/examples/stm32f7/src/bin/qspi.rs
@@ -4,8 +4,9 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::mode::Async;
7use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; 8use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *};
8use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, QuadDma, TransferConfig}; 9use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig};
9use embassy_stm32::time::mhz; 10use embassy_stm32::time::mhz;
10use embassy_stm32::Config as StmCfg; 11use embassy_stm32::Config as StmCfg;
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -43,12 +44,12 @@ const MEMORY_ADDR: u32 = 0x00000000u32;
43/// Implementation of access to flash chip. 44/// Implementation of access to flash chip.
44/// Chip commands are hardcoded as it depends on used chip. 45/// Chip commands are hardcoded as it depends on used chip.
45/// This implementation is using chip GD25Q64C from Giga Device 46/// This implementation is using chip GD25Q64C from Giga Device
46pub struct FlashMemory<I: Instance, D: QuadDma<I>> { 47pub struct FlashMemory<I: Instance> {
47 qspi: Qspi<'static, I, D>, 48 qspi: Qspi<'static, I, Async>,
48} 49}
49 50
50impl<I: Instance, D: QuadDma<I>> FlashMemory<I, D> { 51impl<I: Instance> FlashMemory<I> {
51 pub fn new(qspi: Qspi<'static, I, D>) -> Self { 52 pub fn new(qspi: Qspi<'static, I, Async>) -> Self {
52 let mut memory = Self { qspi }; 53 let mut memory = Self { qspi };
53 54
54 memory.reset_memory(); 55 memory.reset_memory();
@@ -279,7 +280,7 @@ async fn main(_spawner: Spawner) -> ! {
279 cs_high_time: ChipSelectHighTime::_1Cycle, 280 cs_high_time: ChipSelectHighTime::_1Cycle,
280 fifo_threshold: FIFOThresholdLevel::_16Bytes, 281 fifo_threshold: FIFOThresholdLevel::_16Bytes,
281 }; 282 };
282 let driver = Qspi::new_bk1( 283 let driver = Qspi::new_bank1(
283 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, 284 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config,
284 ); 285 );
285 let mut flash = FlashMemory::new(driver); 286 let mut flash = FlashMemory::new(driver);
diff --git a/examples/stm32g0/src/bin/i2c_async.rs b/examples/stm32g0/src/bin/i2c_async.rs
new file mode 100644
index 000000000..7e3189b05
--- /dev/null
+++ b/examples/stm32g0/src/bin/i2c_async.rs
@@ -0,0 +1,48 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::{self, I2c};
7use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
14});
15
16const TMP117_ADDR: u8 = 0x48;
17const TMP117_TEMP_RESULT: u8 = 0x00;
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello world");
22
23 let p = embassy_stm32::init(Default::default());
24
25 let mut data = [0u8; 2];
26 let mut i2c = I2c::new(
27 p.I2C1,
28 p.PB8,
29 p.PB9,
30 Irqs,
31 p.DMA1_CH1,
32 p.DMA1_CH2,
33 Hertz(100_000),
34 Default::default(),
35 );
36
37 loop {
38 match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data).await {
39 Ok(()) => {
40 let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0;
41 info!("Temperature {}", temp);
42 }
43 Err(_) => error!("I2C Error"),
44 }
45
46 Timer::after(Duration::from_millis(1000)).await;
47 }
48}
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index a09af4b97..c6c2d1354 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -8,6 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index 0009103d1..e9a857a74 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) {
51 let mut vrefint_channel = adc.enable_vrefint(); 51 let mut vrefint_channel = adc.enable_vrefint();
52 52
53 loop { 53 loop {
54 let vrefint = adc.read_internal(&mut vrefint_channel); 54 let vrefint = adc.read(&mut vrefint_channel);
55 info!("vrefint: {}", vrefint); 55 info!("vrefint: {}", vrefint);
56 let measured = adc.read(&mut p.PC0); 56 let measured = adc.read(&mut p.PC0);
57 info!("measured: {}", measured); 57 info!("measured: {}", measured);
diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs
new file mode 100644
index 000000000..6f4815582
--- /dev/null
+++ b/examples/stm32h7/src/bin/i2c_shared.rs
@@ -0,0 +1,111 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
8use embassy_executor::Spawner;
9use embassy_stm32::i2c::{self, I2c};
10use embassy_stm32::mode::Async;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, peripherals};
13use embassy_sync::blocking_mutex::NoopMutex;
14use embassy_time::{Duration, Timer};
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18const TMP117_ADDR: u8 = 0x48;
19const TMP117_TEMP_RESULT: u8 = 0x00;
20
21const SHTC3_ADDR: u8 = 0x70;
22const SHTC3_WAKEUP: [u8; 2] = [0x35, 0x17];
23const SHTC3_MEASURE_RH_FIRST: [u8; 2] = [0x5c, 0x24];
24const SHTC3_SLEEP: [u8; 2] = [0xb0, 0x98];
25
26static I2C_BUS: StaticCell<NoopMutex<RefCell<I2c<'static, Async>>>> = StaticCell::new();
27
28bind_interrupts!(struct Irqs {
29 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
30 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
31});
32
33#[embassy_executor::task]
34async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) {
35 let mut data = [0u8; 2];
36
37 loop {
38 match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data) {
39 Ok(()) => {
40 let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0;
41 info!("Temperature {}", temp);
42 }
43 Err(_) => error!("I2C Error"),
44 }
45
46 Timer::after(Duration::from_millis(1000)).await;
47 }
48}
49
50#[embassy_executor::task]
51async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) {
52 let mut data = [0u8; 6];
53
54 loop {
55 // Wakeup
56 match i2c.write(SHTC3_ADDR, &SHTC3_WAKEUP) {
57 Ok(()) => Timer::after(Duration::from_millis(20)).await,
58 Err(_) => error!("I2C Error"),
59 }
60
61 // Measurement
62 match i2c.write(SHTC3_ADDR, &SHTC3_MEASURE_RH_FIRST) {
63 Ok(()) => Timer::after(Duration::from_millis(5)).await,
64 Err(_) => error!("I2C Error"),
65 }
66
67 // Result
68 match i2c.read(SHTC3_ADDR, &mut data) {
69 Ok(()) => Timer::after(Duration::from_millis(5)).await,
70 Err(_) => error!("I2C Error"),
71 }
72
73 // Sleep
74 match i2c.write(SHTC3_ADDR, &SHTC3_SLEEP) {
75 Ok(()) => {
76 let (bytes, _) = data.split_at(core::mem::size_of::<i16>());
77 let rh = f32::from(u16::from_be_bytes(bytes.try_into().unwrap())) * 100.0 / 65536.0;
78 info!("Humidity: {}", rh);
79 }
80 Err(_) => error!("I2C Error"),
81 }
82
83 Timer::after(Duration::from_millis(1000)).await;
84 }
85}
86
87#[embassy_executor::main]
88async fn main(spawner: Spawner) {
89 let p = embassy_stm32::init(Default::default());
90
91 let i2c = I2c::new(
92 p.I2C1,
93 p.PB8,
94 p.PB9,
95 Irqs,
96 p.DMA1_CH4,
97 p.DMA1_CH5,
98 Hertz(100_000),
99 Default::default(),
100 );
101 let i2c_bus = NoopMutex::new(RefCell::new(i2c));
102 let i2c_bus = I2C_BUS.init(i2c_bus);
103
104 // Device 1, using embedded-hal-async compatible driver for TMP117
105 let i2c_dev1 = I2cDevice::new(i2c_bus);
106 spawner.spawn(temperature(i2c_dev1)).unwrap();
107
108 // Device 2, using embedded-hal-async compatible driver for SHTC3
109 let i2c_dev2 = I2cDevice::new(i2c_bus);
110 spawner.spawn(humidity(i2c_dev2)).unwrap();
111}
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index aaebdc346..ad4a8aaf7 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -8,7 +8,6 @@ use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::mode::Blocking; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
13use embassy_stm32::{spi, Config}; 12use embassy_stm32::{spi, Config};
14use heapless::String; 13use heapless::String;
@@ -16,7 +15,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18#[embassy_executor::task] 17#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking>) {
20 for n in 0u32.. { 19 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index f968df4a7..b2e941078 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -9,7 +9,7 @@ use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{peripherals, spi, Config}; 12use embassy_stm32::{spi, Config};
13use heapless::String; 13use heapless::String;
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _};
19static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; 19static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024];
20 20
21#[embassy_executor::task] 21#[embassy_executor::task]
22async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) { 22async fn main_task(mut spi: spi::Spi<'static, Async>) {
23 let read_buffer = unsafe { &mut RAM_D3[0..128] }; 23 let read_buffer = unsafe { &mut RAM_D3[0..128] };
24 let write_buffer = unsafe { &mut RAM_D3[128..256] }; 24 let write_buffer = unsafe { &mut RAM_D3[128..256] };
25 25
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 3d3c724eb..731c7fef5 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -9,13 +9,13 @@ use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{peripherals, spi, Config}; 12use embassy_stm32::{spi, Config};
13use heapless::String; 13use heapless::String;
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs
index a7767876d..8d6ccc58b 100644
--- a/examples/stm32h7rs/src/bin/spi.rs
+++ b/examples/stm32h7rs/src/bin/spi.rs
@@ -8,7 +8,6 @@ use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::mode::Blocking; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::spi; 11use embassy_stm32::spi;
13use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
14use heapless::String; 13use heapless::String;
@@ -16,7 +15,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18#[embassy_executor::task] 17#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking>) {
20 for n in 0u32.. { 19 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs
index 26b5d6751..cb305351b 100644
--- a/examples/stm32h7rs/src/bin/spi_dma.rs
+++ b/examples/stm32h7rs/src/bin/spi_dma.rs
@@ -8,14 +8,14 @@ use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::spi;
11use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
12use embassy_stm32::{peripherals, spi};
13use heapless::String; 13use heapless::String;
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs
new file mode 100644
index 000000000..3c4cdac24
--- /dev/null
+++ b/examples/stm32l4/src/bin/can.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::can::filter::Mask32;
7use embassy_stm32::can::{
8 Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
9};
10use embassy_stm32::peripherals::CAN1;
11use embassy_stm32::{bind_interrupts, Config};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
17 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
18 CAN1_SCE => SceInterruptHandler<CAN1>;
19 CAN1_TX => TxInterruptHandler<CAN1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_stm32::init(Config::default());
25
26 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
27
28 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
29
30 can.modify_config()
31 .set_loopback(true) // Receive own frames
32 .set_silent(true)
33 .set_bitrate(250_000);
34
35 can.enable().await;
36 println!("CAN enabled");
37
38 let mut i = 0;
39 let mut last_read_ts = embassy_time::Instant::now();
40 loop {
41 let frame = Frame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame");
43
44 _ = can.write(&frame).await;
45
46 match can.read().await {
47 Ok(envelope) => {
48 let (ts, rx_frame) = (envelope.ts, envelope.frame);
49 let delta = (ts - last_read_ts).as_millis();
50 last_read_ts = ts;
51 info!(
52 "Rx: {} {:02x} --- {}ms",
53 rx_frame.header().len(),
54 rx_frame.data()[0..rx_frame.header().len() as usize],
55 delta,
56 )
57 }
58 Err(err) => error!("Error in frame: {}", err),
59 }
60
61 Timer::after_millis(250).await;
62
63 i += 1;
64 if i > 2 {
65 break;
66 }
67 }
68}
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 694629ede..33149144c 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -55,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
55// Listen port for the webserver 55// Listen port for the webserver
56const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
57 57
58pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>; 58pub type SpeSpi = Spi<'static, Async>;
59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
60pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
61pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
62pub type Adin1110T = ADIN1110<SpeSpiCs>; 62pub type Adin1110T = ADIN1110<SpeSpiCs>;
63pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>; 63pub type TempSensI2c = I2c<'static, Async>;
64 64
65static TEMP: AtomicI32 = AtomicI32::new(0); 65static TEMP: AtomicI32 = AtomicI32::new(0);
66 66
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 59cb0cfd3..c1576bfeb 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -58,6 +58,14 @@ async fn main(_spawner: Spawner) {
58 spi.blocking_read::<u8>(&mut []).unwrap(); 58 spi.blocking_read::<u8>(&mut []).unwrap();
59 spi.blocking_write::<u8>(&[]).unwrap(); 59 spi.blocking_write::<u8>(&[]).unwrap();
60 60
61 // Assert the RCC bit gets disabled on drop.
62 #[cfg(feature = "stm32f429zi")]
63 {
64 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en());
65 drop(spi);
66 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
67 }
68
61 info!("Test OK"); 69 info!("Test OK");
62 cortex_m::asm::bkpt(); 70 cortex_m::asm::bkpt();
63} 71}