aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/build.sh2
-rwxr-xr-x.github/ci/test-nightly.sh1
-rwxr-xr-x.github/ci/test.sh7
-rw-r--r--.vscode/settings.json3
-rw-r--r--NOTICE.md2
-rw-r--r--README.md8
-rwxr-xr-xci.sh7
-rw-r--r--cyw43/src/control.rs10
-rw-r--r--docs/modules/ROOT/pages/faq.adoc31
-rw-r--r--docs/modules/ROOT/pages/layer_by_layer.adoc2
-rw-r--r--embassy-boot-nrf/README.md2
-rw-r--r--embassy-boot/README.md2
-rw-r--r--embassy-futures/src/yield_now.rs8
-rw-r--r--embassy-net/Cargo.toml6
-rw-r--r--embassy-net/README.md4
-rw-r--r--embassy-net/src/lib.rs2
-rw-r--r--embassy-net/src/raw.rs120
-rw-r--r--embassy-nrf/CHANGELOG.md40
-rw-r--r--embassy-nrf/src/pdm.rs2
-rw-r--r--embassy-stm32/Cargo.toml41
-rw-r--r--embassy-stm32/build.rs3
-rw-r--r--embassy-stm32/src/adc/f1.rs12
-rw-r--r--embassy-stm32/src/adc/f3.rs11
-rw-r--r--embassy-stm32/src/adc/g4.rs304
-rw-r--r--embassy-stm32/src/adc/mod.rs47
-rw-r--r--embassy-stm32/src/adc/v1.rs15
-rw-r--r--embassy-stm32/src/adc/v2.rs9
-rw-r--r--embassy-stm32/src/adc/v3.rs56
-rw-r--r--embassy-stm32/src/adc/v4.rs13
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs1
-rw-r--r--embassy-stm32/src/can/fdcan.rs60
-rw-r--r--embassy-stm32/src/crc/v1.rs12
-rw-r--r--embassy-stm32/src/crc/v2v3.rs18
-rw-r--r--embassy-stm32/src/dac/tsel.rs17
-rw-r--r--embassy-stm32/src/dma/mod.rs3
-rw-r--r--embassy-stm32/src/dma/util.rs60
-rw-r--r--embassy-stm32/src/exti.rs16
-rw-r--r--embassy-stm32/src/flash/f4.rs5
-rw-r--r--embassy-stm32/src/flash/h50.rs52
-rw-r--r--embassy-stm32/src/flash/mod.rs5
-rw-r--r--embassy-stm32/src/flash/u0.rs96
-rw-r--r--embassy-stm32/src/flash/u5.rs39
-rw-r--r--embassy-stm32/src/i2c/mod.rs61
-rw-r--r--embassy-stm32/src/i2c/v1.rs50
-rw-r--r--embassy-stm32/src/i2c/v2.rs276
-rw-r--r--embassy-stm32/src/i2s.rs24
-rw-r--r--embassy-stm32/src/lib.rs25
-rw-r--r--embassy-stm32/src/macros.rs (renamed from embassy-stm32/src/traits.rs)26
-rw-r--r--embassy-stm32/src/rcc/l.rs28
-rw-r--r--embassy-stm32/src/rcc/mco.rs2
-rw-r--r--embassy-stm32/src/rcc/mod.rs20
-rw-r--r--embassy-stm32/src/spi/mod.rs556
-rw-r--r--embassy-stm32/src/usart/mod.rs861
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs20
-rw-r--r--embassy-stm32/src/usb/mod.rs2
-rw-r--r--embassy-stm32/src/usb/otg.rs168
-rw-r--r--embassy-stm32/src/usb/usb.rs14
-rw-r--r--embassy-sync/src/mutex.rs133
-rw-r--r--embassy-time-queue-driver/README.md2
-rw-r--r--embassy-time/README.md2
-rw-r--r--embassy-usb/README.md4
-rw-r--r--embassy-usb/src/builder.rs9
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/README.md8
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/stm32f0/src/bin/adc.rs6
-rw-r--r--examples/stm32f1/src/bin/adc.rs6
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f334/.cargo/config.toml2
-rw-r--r--examples/stm32f334/src/bin/adc.rs6
-rw-r--r--examples/stm32f334/src/bin/opamp.rs6
-rw-r--r--examples/stm32f4/src/bin/adc.rs2
-rw-r--r--examples/stm32f4/src/bin/i2c.rs18
-rw-r--r--examples/stm32f4/src/bin/spi.rs3
-rw-r--r--examples/stm32f4/src/bin/usart.rs3
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/ws2812_spi.rs6
-rw-r--r--examples/stm32f7/src/bin/adc.rs4
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs3
-rw-r--r--examples/stm32g4/src/bin/adc.rs6
-rw-r--r--examples/stm32h5/src/bin/usart.rs8
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs18
-rw-r--r--examples/stm32h7/src/bin/adc.rs4
-rw-r--r--examples/stm32h7/src/bin/spi.rs6
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs6
-rw-r--r--examples/stm32h7/src/bin/usart.rs8
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs18
-rw-r--r--examples/stm32l0/src/bin/adc.rs6
-rw-r--r--examples/stm32l0/src/bin/spi.rs3
-rw-r--r--examples/stm32l1/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/.cargo/config.toml2
-rw-r--r--examples/stm32l4/src/bin/adc.rs3
-rw-r--r--examples/stm32l4/src/bin/i2c.rs18
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs18
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs26
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs3
-rw-r--r--examples/stm32l4/src/bin/usart.rs3
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32u0/.cargo/config.toml9
-rw-r--r--examples/stm32u0/Cargo.toml29
-rw-r--r--examples/stm32u0/build.rs5
-rw-r--r--examples/stm32u0/src/bin/adc.rs30
-rw-r--r--examples/stm32u0/src/bin/blinky.rs26
-rw-r--r--examples/stm32u0/src/bin/button.rs24
-rw-r--r--examples/stm32u0/src/bin/button_exti.rs25
-rw-r--r--examples/stm32u0/src/bin/crc.rs31
-rw-r--r--examples/stm32u0/src/bin/dac.rs35
-rw-r--r--examples/stm32u0/src/bin/flash.rs43
-rw-r--r--examples/stm32u0/src/bin/i2c.rs21
-rw-r--r--examples/stm32u0/src/bin/rng.rs43
-rw-r--r--examples/stm32u0/src/bin/rtc.rs49
-rw-r--r--examples/stm32u0/src/bin/spi.rs30
-rw-r--r--examples/stm32u0/src/bin/usart.rs25
-rw-r--r--examples/stm32u0/src/bin/usb_serial.rs109
-rw-r--r--examples/stm32u0/src/bin/wdt.rs41
-rw-r--r--examples/stm32u5/Cargo.toml4
-rw-r--r--examples/stm32u5/src/bin/i2c.rs18
-rw-r--r--examples/stm32wb/.cargo/config.toml2
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--tests/stm32/src/bin/dac.rs4
-rw-r--r--tests/stm32/src/bin/spi.rs5
-rw-r--r--tests/stm32/src/bin/usart.rs8
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs3
126 files changed, 3045 insertions, 1268 deletions
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index 77d2b3cab..68a7c0c34 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -7,7 +7,7 @@ set -euo pipefail
7export RUSTUP_HOME=/ci/cache/rustup 7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10if [ -f /ci/secrets/teleprobe-token.txt ]; then 10if [ -f /ci/secrets/teleprobe-token.txt ]; then
11 echo Got teleprobe token! 11 echo Got teleprobe token!
12 export TELEPROBE_HOST=https://teleprobe.embassy.dev 12 export TELEPROBE_HOST=https://teleprobe.embassy.dev
13 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) 13 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt)
diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh
index d6e5dc574..1724ffe89 100755
--- a/.github/ci/test-nightly.sh
+++ b/.github/ci/test-nightly.sh
@@ -11,3 +11,4 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml
11 11
12MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml 12MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
13MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly 13MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly
14MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-sync/Cargo.toml
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 8a58939f6..41da644fc 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -8,9 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10 10
11cargo test --manifest-path ./embassy-sync/Cargo.toml 11cargo test --manifest-path ./embassy-futures/Cargo.toml
12cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml 12cargo test --manifest-path ./embassy-sync/Cargo.toml
13cargo test --manifest-path ./embassy-hal-internal/Cargo.toml 13cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
14cargo test --manifest-path ./embassy-hal-internal/Cargo.toml
14cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver 15cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver
15cargo test --manifest-path ./embassy-time-driver/Cargo.toml 16cargo test --manifest-path ./embassy-time-driver/Cargo.toml
16 17
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 0c195a13b..220d25914 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,10 +15,11 @@
15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
17 "rust-analyzer.cargo.features": [ 17 "rust-analyzer.cargo.features": [
18 "stm32f103c8", 18 "stm32f446re",
19 "time-driver-any", 19 "time-driver-any",
20 "unstable-pac", 20 "unstable-pac",
21 "exti", 21 "exti",
22 "rt",
22 ], 23 ],
23 "rust-analyzer.linkedProjects": [ 24 "rust-analyzer.linkedProjects": [
24 // Uncomment ONE line for the chip you want to work on. 25 // Uncomment ONE line for the chip you want to work on.
diff --git a/NOTICE.md b/NOTICE.md
index 868bec08f..a50b39494 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -12,5 +12,5 @@ listed source code repository logs.
12 12
13This program and the accompanying materials are made available under the terms 13This program and the accompanying materials are made available under the terms
14of the Apache Software License 2.0 which is available at 14of the Apache Software License 2.0 which is available at
15https://www.apache.org/licenses/LICENSE-2.0, or the MIT license which is 15https://www.apache.org/licenses/LICENSE-2.0, or the MIT license which is
16available at https://opensource.org/licenses/MIT 16available at https://opensource.org/licenses/MIT
diff --git a/README.md b/README.md
index b6f667f75..0bd1ac594 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Embassy is the next-generation framework for embedded applications. Write safe,
7 7
8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. 8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
9 9
10Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedently easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a> 10Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a>
11 11
12## Batteries included 12## Batteries included
13 13
@@ -89,7 +89,7 @@ async fn main(spawner: Spawner) {
89 89
90## Examples 90## Examples
91 91
92Examples are found in the `examples/` folder seperated by the chip manufacturer they are designed to run on. For example: 92Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example:
93 93
94* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. 94* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards.
95* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). 95* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095).
@@ -130,8 +130,8 @@ For more help getting started, see [Getting Started][1] and [Running the Example
130## Developing Embassy with Rust Analyzer based editors 130## Developing Embassy with Rust Analyzer based editors
131 131
132The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/) 132The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/)
133and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer 133and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer
134must be told of the target project to work with. In the case of Visual Studio Code, 134must be told of the target project to work with. In the case of Visual Studio Code,
135please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects`setting. 135please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects`setting.
136 136
137## Minimum supported Rust version (MSRV) 137## Minimum supported Rust version (MSRV)
diff --git a/ci.sh b/ci.sh
index d17f4e13e..e95714b65 100755
--- a/ci.sh
+++ b/ci.sh
@@ -149,6 +149,9 @@ cargo batch \
149 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \ 149 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \
150 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \ 150 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \
151 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \ 151 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \
152 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \
153 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
154 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
152 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ 155 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
153 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ 156 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
154 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 157 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
@@ -186,6 +189,7 @@ cargo batch \
186 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ 189 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
187 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ 190 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
188 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ 191 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
192 --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32u0 \
189 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ 193 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
190 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ 194 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \
191 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ 195 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
@@ -250,6 +254,9 @@ rm out/tests/stm32f207zg/eth
250# doesn't work, gives "noise error", no idea why. usart_dma does pass. 254# doesn't work, gives "noise error", no idea why. usart_dma does pass.
251rm out/tests/stm32u5a5zj/usart 255rm out/tests/stm32u5a5zj/usart
252 256
257# flaky, perhaps bad wire
258rm out/tests/stm32l152re/usart_rx_ringbuffered
259
253if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 260if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
254 echo No teleprobe token found, skipping running HIL tests 261 echo No teleprobe token found, skipping running HIL tests
255 exit 262 exit
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 135b8c245..a3808f56f 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -124,8 +124,7 @@ impl<'a> Control<'a> {
124 self.set_iovar_u32("apsta", 1).await; 124 self.set_iovar_u32("apsta", 1).await;
125 125
126 // read MAC addr. 126 // read MAC addr.
127 let mut mac_addr = [0; 6]; 127 let mac_addr = self.address().await;
128 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
129 debug!("mac addr: {:02x}", Bytes(&mac_addr)); 128 debug!("mac addr: {:02x}", Bytes(&mac_addr));
130 129
131 let country = countries::WORLD_WIDE_XX; 130 let country = countries::WORLD_WIDE_XX;
@@ -574,6 +573,13 @@ impl<'a> Control<'a> {
574 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; 573 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
575 info!("Disassociated") 574 info!("Disassociated")
576 } 575 }
576
577 /// Gets the MAC address of the device
578 pub async fn address(&mut self) -> [u8; 6] {
579 let mut mac_addr = [0; 6];
580 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
581 mac_addr
582 }
577} 583}
578 584
579/// WiFi network scanner. 585/// WiFi network scanner.
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index c6b893de5..0944127a5 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -231,3 +231,34 @@ Please refer to the STM32 documentation for the specific values suitable for you
231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start. 231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start.
232 232
233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise. 233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise.
234
235== Known issues (details and/or mitigations)
236
237These are issues that are commonly reported. Help wanted fixing them, or improving the UX when possible!
238
239=== STM32H5 and STM32H7 power issues
240
241STM32 chips with built-in power management (SMPS and LDO) settings often cause user problems when the configuration does not match how the board was designed.
242
243Settings from the examples, or even from other working boards, may not work on YOUR board, because they are wired differently.
244
245Additionally, some PWR settings require a full device reboot (and enough time to discharge any power capacitors!), making this hard to troubleshoot. Also, some
246"wrong" power settings will ALMOST work, meaning it will sometimes work on some boots, or for a while, but crash unexpectedly.
247
248There is not a fix for this yet, as it is board/hardware dependant. See link:https://github.com/embassy-rs/embassy/issues/2806[this tracking issue] for more details
249
250=== STM32 BDMA only work out of some RAM regions
251
252The STM32 BDMA controller included in some chips (TODO: list which ones) has a limitation in that it only works out of certain regions of RAM (TODO: list which ones), otherwise the transfer
253will fail.
254
255If you see errors that look like this:
256
257[source,plain]
258----
259DMA: error on BDMA@1234ABCD channel 4
260----
261
262You likely need to set up your linker script to define a special region for this area, and copy data to that region before using with BDMA.
263
264TODO: show how to do that
diff --git a/docs/modules/ROOT/pages/layer_by_layer.adoc b/docs/modules/ROOT/pages/layer_by_layer.adoc
index 1d7bdc89b..fa419f75e 100644
--- a/docs/modules/ROOT/pages/layer_by_layer.adoc
+++ b/docs/modules/ROOT/pages/layer_by_layer.adoc
@@ -63,7 +63,7 @@ Luckily, there is an elegant solution to this problem when using Embassy.
63 63
64== Async version 64== Async version
65 65
66It's time to use the Embassy capabilities to its fullest. At the core, Embassy has an async excecutor, or a runtime for async tasks if you will. The executor polls a set of tasks (defined at compile time), and whenever a task `blocks`, the executor will run another task, or put the microcontroller to sleep. 66It's time to use the Embassy capabilities to its fullest. At the core, Embassy has an async executor, or a runtime for async tasks if you will. The executor polls a set of tasks (defined at compile time), and whenever a task `blocks`, the executor will run another task, or put the microcontroller to sleep.
67 67
68[source,rust] 68[source,rust]
69---- 69----
diff --git a/embassy-boot-nrf/README.md b/embassy-boot-nrf/README.md
index 9dc5b0eb9..f0d87e18c 100644
--- a/embassy-boot-nrf/README.md
+++ b/embassy-boot-nrf/README.md
@@ -2,7 +2,7 @@
2 2
3An [Embassy](https://embassy.dev) project. 3An [Embassy](https://embassy.dev) project.
4 4
5An adaptation of `embassy-boot` for nRF. 5An adaptation of `embassy-boot` for nRF.
6 6
7## Features 7## Features
8 8
diff --git a/embassy-boot/README.md b/embassy-boot/README.md
index 3c2d45e96..812c43524 100644
--- a/embassy-boot/README.md
+++ b/embassy-boot/README.md
@@ -15,7 +15,7 @@ The bootloader divides the storage into 4 main partitions, configurable when cre
15* BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash, but if you need to debug it and have space available, increasing this to 24kB will allow you to run the bootloader with probe-rs. 15* BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash, but if you need to debug it and have space available, increasing this to 24kB will allow you to run the bootloader with probe-rs.
16* ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. The minimum size required for this partition is the size of your application. 16* ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. The minimum size required for this partition is the size of your application.
17* DFU - Where the application-to-be-swapped is placed. This partition is written to by the application. This partition must be at least 1 page bigger than the ACTIVE partition. 17* DFU - Where the application-to-be-swapped is placed. This partition is written to by the application. This partition must be at least 1 page bigger than the ACTIVE partition.
18* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped. 18* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped.
19 19
20For any partition, the following preconditions are required: 20For any partition, the following preconditions are required:
21 21
diff --git a/embassy-futures/src/yield_now.rs b/embassy-futures/src/yield_now.rs
index bb3c67d17..4d4e535f2 100644
--- a/embassy-futures/src/yield_now.rs
+++ b/embassy-futures/src/yield_now.rs
@@ -9,10 +9,16 @@ use core::task::{Context, Poll};
9/// hold, while still allowing other tasks to run concurrently (not monopolizing 9/// hold, while still allowing other tasks to run concurrently (not monopolizing
10/// the executor thread). 10/// the executor thread).
11/// 11///
12/// ```rust,no_run 12/// ```rust
13/// # use embassy_futures::{block_on, yield_now};
14/// # async fn test_fn() {
15/// # let mut iter_count: u32 = 0;
16/// # let mut some_condition = || { iter_count += 1; iter_count > 10 };
13/// while !some_condition() { 17/// while !some_condition() {
14/// yield_now().await; 18/// yield_now().await;
15/// } 19/// }
20/// # }
21/// # block_on(test_fn());
16/// ``` 22/// ```
17/// 23///
18/// The downside is this will spin in a busy loop, using 100% of the CPU, while 24/// The downside is this will spin in a busy loop, using 100% of the CPU, while
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index be9f1d784..ee7289ad8 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -16,11 +16,11 @@ categories = [
16[package.metadata.embassy_docs] 16[package.metadata.embassy_docs]
17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" 18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
19features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 19features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
20target = "thumbv7em-none-eabi" 20target = "thumbv7em-none-eabi"
21 21
22[package.metadata.docs.rs] 22[package.metadata.docs.rs]
23features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 23features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
24 24
25[features] 25[features]
26default = [] 26default = []
@@ -38,6 +38,8 @@ packet-trace = []
38 38
39## Enable UDP support 39## Enable UDP support
40udp = ["smoltcp/socket-udp"] 40udp = ["smoltcp/socket-udp"]
41## Enable Raw support
42raw = ["smoltcp/socket-raw"]
41## Enable TCP support 43## Enable TCP support
42tcp = ["smoltcp/socket-tcp"] 44tcp = ["smoltcp/socket-tcp"]
43## Enable DNS support 45## Enable DNS support
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 94aa6f550..ce59ea34a 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -13,8 +13,8 @@ memory management designed to work well for embedded systems, aiming for a more
13- TCP, UDP, DNS, DHCPv4, IGMPv4 13- TCP, UDP, DNS, DHCPv4, IGMPv4
14- TCP sockets implement the `embedded-io` async traits. 14- TCP sockets implement the `embedded-io` async traits.
15 15
16See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and 16See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and
17unimplemented features of the network protocols. 17unimplemented features of the network protocols.
18 18
19## Hardware support 19## Hardware support
20 20
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 1c0cf1a12..86ced1ded 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -15,6 +15,8 @@ pub(crate) mod fmt;
15mod device; 15mod device;
16#[cfg(feature = "dns")] 16#[cfg(feature = "dns")]
17pub mod dns; 17pub mod dns;
18#[cfg(feature = "raw")]
19pub mod raw;
18#[cfg(feature = "tcp")] 20#[cfg(feature = "tcp")]
19pub mod tcp; 21pub mod tcp;
20mod time; 22mod time;
diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs
new file mode 100644
index 000000000..7ecd913e7
--- /dev/null
+++ b/embassy-net/src/raw.rs
@@ -0,0 +1,120 @@
1//! Raw sockets.
2
3use core::cell::RefCell;
4use core::future::poll_fn;
5use core::mem;
6use core::task::{Context, Poll};
7
8use embassy_net_driver::Driver;
9use smoltcp::iface::{Interface, SocketHandle};
10use smoltcp::socket::raw;
11pub use smoltcp::socket::raw::PacketMetadata;
12use smoltcp::wire::{IpProtocol, IpVersion};
13
14use crate::{SocketStack, Stack};
15
16/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`].
17#[derive(PartialEq, Eq, Clone, Copy, Debug)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum RecvError {
20 /// Provided buffer was smaller than the received packet.
21 Truncated,
22}
23
24/// An Raw socket.
25pub struct RawSocket<'a> {
26 stack: &'a RefCell<SocketStack>,
27 handle: SocketHandle,
28}
29
30impl<'a> RawSocket<'a> {
31 /// Create a new Raw socket using the provided stack and buffers.
32 pub fn new<D: Driver>(
33 stack: &'a Stack<D>,
34 ip_version: IpVersion,
35 ip_protocol: IpProtocol,
36 rx_meta: &'a mut [PacketMetadata],
37 rx_buffer: &'a mut [u8],
38 tx_meta: &'a mut [PacketMetadata],
39 tx_buffer: &'a mut [u8],
40 ) -> Self {
41 let s = &mut *stack.socket.borrow_mut();
42
43 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
44 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
45 let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
46 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
47 let handle = s.sockets.add(raw::Socket::new(
48 ip_version,
49 ip_protocol,
50 raw::PacketBuffer::new(rx_meta, rx_buffer),
51 raw::PacketBuffer::new(tx_meta, tx_buffer),
52 ));
53
54 Self {
55 stack: &stack.socket,
56 handle,
57 }
58 }
59
60 fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R {
61 let s = &mut *self.stack.borrow_mut();
62 let socket = s.sockets.get_mut::<raw::Socket>(self.handle);
63 let res = f(socket, &mut s.iface);
64 s.waker.wake();
65 res
66 }
67
68 /// Receive a datagram.
69 ///
70 /// This method will wait until a datagram is received.
71 pub async fn recv(&self, buf: &mut [u8]) -> Result<usize, RecvError> {
72 poll_fn(move |cx| self.poll_recv(buf, cx)).await
73 }
74
75 /// Receive a datagram.
76 ///
77 /// When no datagram is available, this method will return `Poll::Pending` and
78 /// register the current task to be notified when a datagram is received.
79 pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<usize, RecvError>> {
80 self.with_mut(|s, _| match s.recv_slice(buf) {
81 Ok(n) => Poll::Ready(Ok(n)),
82 // No data ready
83 Err(raw::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)),
84 Err(raw::RecvError::Exhausted) => {
85 s.register_recv_waker(cx.waker());
86 Poll::Pending
87 }
88 })
89 }
90
91 /// Send a datagram.
92 ///
93 /// This method will wait until the datagram has been sent.`
94 pub async fn send(&self, buf: &[u8]) {
95 poll_fn(move |cx| self.poll_send(buf, cx)).await
96 }
97
98 /// Send a datagram.
99 ///
100 /// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
101 ///
102 /// When the socket's send buffer is full, this method will return `Poll::Pending`
103 /// and register the current task to be notified when the buffer has space available.
104 pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll<()> {
105 self.with_mut(|s, _| match s.send_slice(buf) {
106 // Entire datagram has been sent
107 Ok(()) => Poll::Ready(()),
108 Err(raw::SendError::BufferFull) => {
109 s.register_send_waker(cx.waker());
110 Poll::Pending
111 }
112 })
113 }
114}
115
116impl Drop for RawSocket<'_> {
117 fn drop(&mut self) {
118 self.stack.borrow_mut().sockets.remove(self.handle);
119 }
120}
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
new file mode 100644
index 000000000..773a1a108
--- /dev/null
+++ b/embassy-nrf/CHANGELOG.md
@@ -0,0 +1,40 @@
1# Changelog for embassy-nrf
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- Drop `sealed` mod
11- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
12- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral
13- spim: Reduce trace-level messages ("Copying SPIM tx buffer..")
14- uart: Add support for rx- or tx-only BufferedUart
15- uart: Implement splitting Rx/Tx
16- spi: Allow specifying OutputDrive for SPI spins
17- pdm: Fix gain register value derivation
18- spim: Implement chunked DMA transfers
19- spi: Add bounds checks for EasyDMA buffer size
20- uarte: Add support for handling RX errors
21- nrf51: Implement support for nrf51 chip
22- pwm: Expose `duty` method
23- pwm: Fix infinite loop
24- spi: Add support for configuring bit order for bus
25- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
26- gpio: Drop GPIO Pin generics (API break)
27
28## 0.1.0 - 2024-01-12
29
30- First release with support for following NRF chips:
31 - nrf52805
32 - nrf52810
33 - nrf52811
34 - nrf52820
35 - nrf52832
36 - nrf52833
37 - nrf52840
38 - nrf5340
39 - nrf9160
40
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index ef2662c85..c1501e02e 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,4 +1,4 @@
1//! Pulse Density Modulation (PDM) mirophone driver 1//! Pulse Density Modulation (PDM) microphone driver
2 2
3#![macro_use] 3#![macro_use]
4 4
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 89b24f0eb..095427171 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -30,6 +30,7 @@ flavors = [
30 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, 30 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
31 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, 31 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
32 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, 32 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] },
33 { regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" },
33 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, 34 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
34 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, 35 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
35 { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, 36 { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
@@ -70,7 +71,7 @@ rand_core = "0.6.3"
70sdio-host = "0.5.0" 71sdio-host = "0.5.0"
71critical-section = "1.1" 72critical-section = "1.1"
72#stm32-metapac = { version = "15" } 73#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9" } 74stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c" }
74 75
75vcell = "0.1.3" 76vcell = "0.1.3"
76nb = "1.0.0" 77nb = "1.0.0"
@@ -96,7 +97,7 @@ proc-macro2 = "1.0.36"
96quote = "1.0.15" 97quote = "1.0.15"
97 98
98#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
99stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9", default-features = false, features = ["metadata"]} 100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c", default-features = false, features = ["metadata"]}
100 101
101[features] 102[features]
102default = ["rt"] 103default = ["rt"]
@@ -114,6 +115,9 @@ low-power-debug-with-sleep = []
114## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) 115## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/)
115memory-x = ["stm32-metapac/memory-x"] 116memory-x = ["stm32-metapac/memory-x"]
116 117
118## Use secure registers when TrustZone is enabled
119trustzone-secure = []
120
117## Re-export stm32-metapac at `embassy_stm32::pac`. 121## Re-export stm32-metapac at `embassy_stm32::pac`.
118## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. 122## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
119## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 123## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
@@ -1419,6 +1423,38 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
1419stm32l562re = [ "stm32-metapac/stm32l562re" ] 1423stm32l562re = [ "stm32-metapac/stm32l562re" ]
1420stm32l562ve = [ "stm32-metapac/stm32l562ve" ] 1424stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
1421stm32l562ze = [ "stm32-metapac/stm32l562ze" ] 1425stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
1426stm32u031c6 = [ "stm32-metapac/stm32u031c6" ]
1427stm32u031c8 = [ "stm32-metapac/stm32u031c8" ]
1428stm32u031f4 = [ "stm32-metapac/stm32u031f4" ]
1429stm32u031f6 = [ "stm32-metapac/stm32u031f6" ]
1430stm32u031f8 = [ "stm32-metapac/stm32u031f8" ]
1431stm32u031g6 = [ "stm32-metapac/stm32u031g6" ]
1432stm32u031g8 = [ "stm32-metapac/stm32u031g8" ]
1433stm32u031k4 = [ "stm32-metapac/stm32u031k4" ]
1434stm32u031k6 = [ "stm32-metapac/stm32u031k6" ]
1435stm32u031k8 = [ "stm32-metapac/stm32u031k8" ]
1436stm32u031r6 = [ "stm32-metapac/stm32u031r6" ]
1437stm32u031r8 = [ "stm32-metapac/stm32u031r8" ]
1438stm32u073c8 = [ "stm32-metapac/stm32u073c8" ]
1439stm32u073cb = [ "stm32-metapac/stm32u073cb" ]
1440stm32u073cc = [ "stm32-metapac/stm32u073cc" ]
1441stm32u073h8 = [ "stm32-metapac/stm32u073h8" ]
1442stm32u073hb = [ "stm32-metapac/stm32u073hb" ]
1443stm32u073hc = [ "stm32-metapac/stm32u073hc" ]
1444stm32u073k8 = [ "stm32-metapac/stm32u073k8" ]
1445stm32u073kb = [ "stm32-metapac/stm32u073kb" ]
1446stm32u073kc = [ "stm32-metapac/stm32u073kc" ]
1447stm32u073m8 = [ "stm32-metapac/stm32u073m8" ]
1448stm32u073mb = [ "stm32-metapac/stm32u073mb" ]
1449stm32u073mc = [ "stm32-metapac/stm32u073mc" ]
1450stm32u073r8 = [ "stm32-metapac/stm32u073r8" ]
1451stm32u073rb = [ "stm32-metapac/stm32u073rb" ]
1452stm32u073rc = [ "stm32-metapac/stm32u073rc" ]
1453stm32u083cc = [ "stm32-metapac/stm32u083cc" ]
1454stm32u083hc = [ "stm32-metapac/stm32u083hc" ]
1455stm32u083kc = [ "stm32-metapac/stm32u083kc" ]
1456stm32u083mc = [ "stm32-metapac/stm32u083mc" ]
1457stm32u083rc = [ "stm32-metapac/stm32u083rc" ]
1422stm32u535cb = [ "stm32-metapac/stm32u535cb" ] 1458stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
1423stm32u535cc = [ "stm32-metapac/stm32u535cc" ] 1459stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
1424stm32u535ce = [ "stm32-metapac/stm32u535ce" ] 1460stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
@@ -1474,6 +1510,7 @@ stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
1474stm32u599zi = [ "stm32-metapac/stm32u599zi" ] 1510stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
1475stm32u599zj = [ "stm32-metapac/stm32u599zj" ] 1511stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
1476stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] 1512stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
1513stm32u5a5qi = [ "stm32-metapac/stm32u5a5qi" ]
1477stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] 1514stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
1478stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] 1515stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
1479stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] 1516stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 38b6c480c..67fceda56 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -272,8 +272,6 @@ fn main() {
272 "Bank1" 272 "Bank1"
273 } else if region.name.starts_with("BANK_2") { 273 } else if region.name.starts_with("BANK_2") {
274 "Bank2" 274 "Bank2"
275 } else if region.name == "OTP" {
276 "Otp"
277 } else { 275 } else {
278 continue; 276 continue;
279 } 277 }
@@ -664,6 +662,7 @@ fn main() {
664 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* 662 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
665 663
666 #[derive(Clone, Copy)] 664 #[derive(Clone, Copy)]
665 #[non_exhaustive]
667 pub struct ClockMux { 666 pub struct ClockMux {
668 #( #struct_fields, )* 667 #( #struct_fields, )*
669 } 668 }
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index cecf67947..80eaecc14 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -3,8 +3,8 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs;
7 6
7use super::blocking_delay_us;
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{interrupt, Peripheral}; 10use crate::{interrupt, Peripheral};
@@ -48,14 +48,14 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature {
48} 48}
49 49
50impl<'d, T: Instance> Adc<'d, T> { 50impl<'d, T: Instance> Adc<'d, T> {
51 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 51 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
52 into_ref!(adc); 52 into_ref!(adc);
53 T::enable_and_reset(); 53 T::enable_and_reset();
54 T::regs().cr2().modify(|reg| reg.set_adon(true)); 54 T::regs().cr2().modify(|reg| reg.set_adon(true));
55 55
56 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 56 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
57 // for at least two ADC clock cycles 57 // for at least two ADC clock cycles.
58 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); 58 blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1);
59 59
60 // Reset calibration 60 // Reset calibration
61 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 61 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -70,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
70 } 70 }
71 71
72 // One cycle after calibration 72 // One cycle after calibration
73 delay.delay_us((1_000_000) / Self::freq().0 + 1); 73 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1);
74 74
75 Self { 75 Self {
76 adc, 76 adc,
@@ -95,7 +95,7 @@ impl<'d, T: Instance> Adc<'d, T> {
95 } 95 }
96 } 96 }
97 97
98 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { 98 pub fn enable_vref(&self) -> Vref {
99 T::regs().cr2().modify(|reg| { 99 T::regs().cr2().modify(|reg| {
100 reg.set_tsvrefe(true); 100 reg.set_tsvrefe(true);
101 }); 101 });
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index c5581dba1..c22a3fe4a 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -3,8 +3,8 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs;
7 6
7use super::blocking_delay_us;
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::time::Hertz; 10use crate::time::Hertz;
@@ -58,7 +58,6 @@ impl<'d, T: Instance> Adc<'d, T> {
58 pub fn new( 58 pub fn new(
59 adc: impl Peripheral<P = T> + 'd, 59 adc: impl Peripheral<P = T> + 'd,
60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 delay: &mut impl DelayUs<u32>,
62 ) -> Self { 61 ) -> Self {
63 use crate::pac::adc::vals; 62 use crate::pac::adc::vals;
64 63
@@ -71,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
71 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); 70 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
72 71
73 // Wait for the regulator to stabilize 72 // Wait for the regulator to stabilize
74 delay.delay_us(10); 73 blocking_delay_us(10);
75 74
76 assert!(!T::regs().cr().read().aden()); 75 assert!(!T::regs().cr().read().aden());
77 76
@@ -81,8 +80,8 @@ impl<'d, T: Instance> Adc<'d, T> {
81 80
82 while T::regs().cr().read().adcal() {} 81 while T::regs().cr().read().adcal() {}
83 82
84 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) 83 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
85 delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0)); 84 blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1);
86 85
87 // Enable the adc 86 // Enable the adc
88 T::regs().cr().modify(|w| w.set_aden(true)); 87 T::regs().cr().modify(|w| w.set_aden(true));
@@ -117,7 +116,7 @@ impl<'d, T: Instance> Adc<'d, T> {
117 } 116 }
118 } 117 }
119 118
120 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { 119 pub fn enable_vref(&self) -> Vref {
121 T::common_regs().ccr().modify(|w| w.set_vrefen(true)); 120 T::common_regs().ccr().modify(|w| w.set_vrefen(true));
122 121
123 Vref {} 122 Vref {}
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
new file mode 100644
index 000000000..221cc2a40
--- /dev/null
+++ b/embassy-stm32/src/adc/g4.rs
@@ -0,0 +1,304 @@
1#[allow(unused)]
2use pac::adc::vals::{Adcaldif, Difsel, Exten};
3use pac::adccommon::vals::Presc;
4
5use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
6use crate::time::Hertz;
7use crate::{pac, Peripheral};
8
9/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300;
11/// VREF voltage used for factory calibration of VREFINTCAL register.
12pub const VREF_CALIB_MV: u32 = 3300;
13
14/// Max single ADC operation clock frequency
15#[cfg(stm32g4)]
16const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
17#[cfg(stm32h7)]
18const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
19
20#[cfg(stm32g4)]
21const VREF_CHANNEL: u8 = 18;
22#[cfg(stm32g4)]
23const TEMP_CHANNEL: u8 = 16;
24
25#[cfg(stm32h7)]
26const VREF_CHANNEL: u8 = 19;
27#[cfg(stm32h7)]
28const TEMP_CHANNEL: u8 = 18;
29
30// TODO this should be 14 for H7a/b/35
31const VBAT_CHANNEL: u8 = 17;
32
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.
35pub struct VrefInt;
36impl<T: Instance> InternalChannel<T> for VrefInt {}
37impl<T: Instance> super::SealedInternalChannel<T> for VrefInt {
38 fn channel(&self) -> u8 {
39 VREF_CHANNEL
40 }
41}
42
43/// Internal temperature channel.
44pub struct Temperature;
45impl<T: Instance> InternalChannel<T> for Temperature {}
46impl<T: Instance> super::SealedInternalChannel<T> for Temperature {
47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL
49 }
50}
51
52/// Internal battery voltage channel.
53pub struct Vbat;
54impl<T: Instance> InternalChannel<T> for Vbat {}
55impl<T: Instance> super::SealedInternalChannel<T> for Vbat {
56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL
58 }
59}
60
61// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
62// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
63#[allow(unused)]
64enum Prescaler {
65 NotDivided,
66 DividedBy2,
67 DividedBy4,
68 DividedBy6,
69 DividedBy8,
70 DividedBy10,
71 DividedBy12,
72 DividedBy16,
73 DividedBy32,
74 DividedBy64,
75 DividedBy128,
76 DividedBy256,
77}
78
79impl Prescaler {
80 fn from_ker_ck(frequency: Hertz) -> Self {
81 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
82 match raw_prescaler {
83 0 => Self::NotDivided,
84 1 => Self::DividedBy2,
85 2..=3 => Self::DividedBy4,
86 4..=5 => Self::DividedBy6,
87 6..=7 => Self::DividedBy8,
88 8..=9 => Self::DividedBy10,
89 10..=11 => Self::DividedBy12,
90 _ => unimplemented!(),
91 }
92 }
93
94 fn divisor(&self) -> u32 {
95 match self {
96 Prescaler::NotDivided => 1,
97 Prescaler::DividedBy2 => 2,
98 Prescaler::DividedBy4 => 4,
99 Prescaler::DividedBy6 => 6,
100 Prescaler::DividedBy8 => 8,
101 Prescaler::DividedBy10 => 10,
102 Prescaler::DividedBy12 => 12,
103 Prescaler::DividedBy16 => 16,
104 Prescaler::DividedBy32 => 32,
105 Prescaler::DividedBy64 => 64,
106 Prescaler::DividedBy128 => 128,
107 Prescaler::DividedBy256 => 256,
108 }
109 }
110
111 fn presc(&self) -> Presc {
112 match self {
113 Prescaler::NotDivided => Presc::DIV1,
114 Prescaler::DividedBy2 => Presc::DIV2,
115 Prescaler::DividedBy4 => Presc::DIV4,
116 Prescaler::DividedBy6 => Presc::DIV6,
117 Prescaler::DividedBy8 => Presc::DIV8,
118 Prescaler::DividedBy10 => Presc::DIV10,
119 Prescaler::DividedBy12 => Presc::DIV12,
120 Prescaler::DividedBy16 => Presc::DIV16,
121 Prescaler::DividedBy32 => Presc::DIV32,
122 Prescaler::DividedBy64 => Presc::DIV64,
123 Prescaler::DividedBy128 => Presc::DIV128,
124 Prescaler::DividedBy256 => Presc::DIV256,
125 }
126 }
127}
128
129impl<'d, T: Instance> Adc<'d, T> {
130 /// Create a new ADC driver.
131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
132 embassy_hal_internal::into_ref!(adc);
133 T::enable_and_reset();
134
135 let prescaler = Prescaler::from_ker_ck(T::frequency());
136
137 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
138
139 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
140 info!("ADC frequency set to {} Hz", frequency.0);
141
142 if frequency > MAX_ADC_CLK_FREQ {
143 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
144 }
145
146 let mut s = Self {
147 adc,
148 sample_time: SampleTime::from_bits(0),
149 };
150 s.power_up();
151 s.configure_differential_inputs();
152
153 s.calibrate();
154 blocking_delay_us(1);
155
156 s.enable();
157 s.configure();
158
159 s
160 }
161
162 fn power_up(&mut self) {
163 T::regs().cr().modify(|reg| {
164 reg.set_deeppwd(false);
165 reg.set_advregen(true);
166 });
167
168 blocking_delay_us(10);
169 }
170
171 fn configure_differential_inputs(&mut self) {
172 T::regs().difsel().modify(|w| {
173 for n in 0..18 {
174 w.set_difsel(n, Difsel::SINGLEENDED);
175 }
176 });
177 }
178
179 fn calibrate(&mut self) {
180 T::regs().cr().modify(|w| {
181 w.set_adcaldif(Adcaldif::SINGLEENDED);
182 });
183
184 T::regs().cr().modify(|w| w.set_adcal(true));
185
186 while T::regs().cr().read().adcal() {}
187 }
188
189 fn enable(&mut self) {
190 T::regs().isr().write(|w| w.set_adrdy(true));
191 T::regs().cr().modify(|w| w.set_aden(true));
192 while !T::regs().isr().read().adrdy() {}
193 T::regs().isr().write(|w| w.set_adrdy(true));
194 }
195
196 fn configure(&mut self) {
197 // single conversion mode, software trigger
198 T::regs().cfgr().modify(|w| {
199 w.set_cont(false);
200 w.set_exten(Exten::DISABLED);
201 });
202 }
203
204 /// Enable reading the voltage reference internal channel.
205 pub fn enable_vrefint(&self) -> VrefInt {
206 T::common_regs().ccr().modify(|reg| {
207 reg.set_vrefen(true);
208 });
209
210 VrefInt {}
211 }
212
213 /// Enable reading the temperature internal channel.
214 pub fn enable_temperature(&self) -> Temperature {
215 T::common_regs().ccr().modify(|reg| {
216 reg.set_vsenseen(true);
217 });
218
219 Temperature {}
220 }
221
222 /// Enable reading the vbat internal channel.
223 pub fn enable_vbat(&self) -> Vbat {
224 T::common_regs().ccr().modify(|reg| {
225 reg.set_vbaten(true);
226 });
227
228 Vbat {}
229 }
230
231 /// Set the ADC sample time.
232 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
233 self.sample_time = sample_time;
234 }
235
236 /// Set the ADC resolution.
237 pub fn set_resolution(&mut self, resolution: Resolution) {
238 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
239 }
240
241 /// Perform a single conversion.
242 fn convert(&mut self) -> u16 {
243 T::regs().isr().modify(|reg| {
244 reg.set_eos(true);
245 reg.set_eoc(true);
246 });
247
248 // Start conversion
249 T::regs().cr().modify(|reg| {
250 reg.set_adstart(true);
251 });
252
253 while !T::regs().isr().read().eos() {
254 // spin
255 }
256
257 T::regs().dr().read().0 as u16
258 }
259
260 /// Read an ADC pin.
261 pub fn read<P>(&mut self, pin: &mut P) -> u16
262 where
263 P: AdcPin<T>,
264 P: crate::gpio::Pin,
265 {
266 pin.set_as_analog();
267
268 self.read_channel(pin.channel())
269 }
270
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())
274 }
275
276 fn read_channel(&mut self, channel: u8) -> u16 {
277 // Configure channel
278 Self::set_channel_sample_time(channel, self.sample_time);
279
280 #[cfg(stm32h7)]
281 {
282 T::regs().cfgr2().modify(|w| w.set_lshift(0));
283 T::regs()
284 .pcsel()
285 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
286 }
287
288 T::regs().sqr1().write(|reg| {
289 reg.set_sq(0, channel);
290 reg.set_l(0);
291 });
292
293 self.convert()
294 }
295
296 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
297 let sample_time = sample_time.into();
298 if ch <= 9 {
299 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
300 } else {
301 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
302 }
303 }
304}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ead2357ce..8ef68490b 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -10,8 +10,9 @@
10#[cfg_attr(adc_v1, path = "v1.rs")] 10#[cfg_attr(adc_v1, path = "v1.rs")]
11#[cfg_attr(adc_l0, path = "v1.rs")] 11#[cfg_attr(adc_l0, path = "v1.rs")]
12#[cfg_attr(adc_v2, path = "v2.rs")] 12#[cfg_attr(adc_v2, path = "v2.rs")]
13#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")] 13#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
14#[cfg_attr(adc_v4, path = "v4.rs")] 14#[cfg_attr(adc_v4, path = "v4.rs")]
15#[cfg_attr(adc_g4, path = "g4.rs")]
15mod _version; 16mod _version;
16 17
17#[allow(unused)] 18#[allow(unused)]
@@ -69,14 +70,54 @@ trait SealedInternalChannel<T> {
69 fn channel(&self) -> u8; 70 fn channel(&self) -> u8;
70} 71}
71 72
73/// Performs a busy-wait delay for a specified number of microseconds.
74#[allow(unused)]
75pub(crate) fn blocking_delay_us(us: u32) {
76 #[cfg(time)]
77 embassy_time::block_for(embassy_time::Duration::from_micros(us));
78 #[cfg(not(time))]
79 {
80 let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64;
81 let us = us as u64;
82 let cycles = freq * us / 1_000_000;
83 cortex_m::asm::delay(cycles as u32);
84 }
85}
86
72/// ADC instance. 87/// ADC instance.
73#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))] 88#[cfg(not(any(
89 adc_f1,
90 adc_v1,
91 adc_l0,
92 adc_v2,
93 adc_v3,
94 adc_v4,
95 adc_g4,
96 adc_f3,
97 adc_f3_v1_1,
98 adc_g0,
99 adc_u0,
100 adc_h5
101)))]
74#[allow(private_bounds)] 102#[allow(private_bounds)]
75pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { 103pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
76 type Interrupt: crate::interrupt::typelevel::Interrupt; 104 type Interrupt: crate::interrupt::typelevel::Interrupt;
77} 105}
78/// ADC instance. 106/// ADC instance.
79#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))] 107#[cfg(any(
108 adc_f1,
109 adc_v1,
110 adc_l0,
111 adc_v2,
112 adc_v3,
113 adc_v4,
114 adc_g4,
115 adc_f3,
116 adc_f3_v1_1,
117 adc_g0,
118 adc_u0,
119 adc_h5
120))]
80#[allow(private_bounds)] 121#[allow(private_bounds)]
81pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { 122pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {
82 type Interrupt: crate::interrupt::typelevel::Interrupt; 123 type Interrupt: crate::interrupt::typelevel::Interrupt;
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index e9b46be80..1dda28cf2 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -3,10 +3,10 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs;
7#[cfg(adc_l0)] 6#[cfg(adc_l0)]
8use stm32_metapac::adc::vals::Ckmode; 7use stm32_metapac::adc::vals::Ckmode;
9 8
9use super::blocking_delay_us;
10use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 10use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::peripherals::ADC; 12use crate::peripherals::ADC;
@@ -65,7 +65,6 @@ impl<'d, T: Instance> Adc<'d, T> {
65 pub fn new( 65 pub fn new(
66 adc: impl Peripheral<P = T> + 'd, 66 adc: impl Peripheral<P = T> + 'd,
67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
68 delay: &mut impl DelayUs<u32>,
69 ) -> Self { 68 ) -> Self {
70 into_ref!(adc); 69 into_ref!(adc);
71 T::enable_and_reset(); 70 T::enable_and_reset();
@@ -74,7 +73,7 @@ impl<'d, T: Instance> Adc<'d, T> {
74 // 73 //
75 // Table 57. ADC characteristics 74 // Table 57. ADC characteristics
76 // tstab = 14 * 1/fadc 75 // tstab = 14 * 1/fadc
77 delay.delay_us(1); 76 blocking_delay_us(1);
78 77
79 // set default PCKL/2 on L0s because HSI is disabled in the default clock config 78 // set default PCKL/2 on L0s because HSI is disabled in the default clock config
80 #[cfg(adc_l0)] 79 #[cfg(adc_l0)]
@@ -114,7 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
114 } 113 }
115 114
116 #[cfg(not(adc_l0))] 115 #[cfg(not(adc_l0))]
117 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { 116 pub fn enable_vbat(&self) -> Vbat {
118 // SMP must be ≥ 56 ADC clock cycles when using HSI14. 117 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
119 // 118 //
120 // 6.3.20 Vbat monitoring characteristics 119 // 6.3.20 Vbat monitoring characteristics
@@ -123,22 +122,22 @@ impl<'d, T: Instance> Adc<'d, T> {
123 Vbat 122 Vbat
124 } 123 }
125 124
126 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { 125 pub fn enable_vref(&self) -> Vref {
127 // Table 28. Embedded internal reference voltage 126 // Table 28. Embedded internal reference voltage
128 // tstart = 10μs 127 // tstart = 10μs
129 T::regs().ccr().modify(|reg| reg.set_vrefen(true)); 128 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
130 delay.delay_us(10); 129 blocking_delay_us(10);
131 Vref 130 Vref
132 } 131 }
133 132
134 pub fn enable_temperature(&self, delay: &mut impl DelayUs<u32>) -> Temperature { 133 pub fn enable_temperature(&self) -> Temperature {
135 // SMP must be ≥ 56 ADC clock cycles when using HSI14. 134 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
136 // 135 //
137 // 6.3.19 Temperature sensor characteristics 136 // 6.3.19 Temperature sensor characteristics
138 // tstart ≤ 10μs 137 // tstart ≤ 10μs
139 // ts_temp ≥ 4μs 138 // ts_temp ≥ 4μs
140 T::regs().ccr().modify(|reg| reg.set_tsen(true)); 139 T::regs().ccr().modify(|reg| reg.set_tsen(true));
141 delay.delay_us(10); 140 blocking_delay_us(10);
142 Temperature 141 Temperature
143 } 142 }
144 143
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index a43eb72db..7771cf768 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::into_ref; 1use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs;
3 2
3use super::blocking_delay_us;
4use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
5use crate::peripherals::ADC1; 5use crate::peripherals::ADC1;
6use crate::time::Hertz; 6use crate::time::Hertz;
@@ -11,9 +11,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
11/// VREF voltage used for factory calibration of VREFINTCAL register. 11/// VREF voltage used for factory calibration of VREFINTCAL register.
12pub const VREF_CALIB_MV: u32 = 3300; 12pub const VREF_CALIB_MV: u32 = 3300;
13 13
14/// ADC turn-on time
15pub const ADC_POWERUP_TIME_US: u32 = 3;
16
17pub struct VrefInt; 14pub struct VrefInt;
18impl AdcPin<ADC1> for VrefInt {} 15impl AdcPin<ADC1> for VrefInt {}
19impl super::SealedAdcPin<ADC1> for VrefInt { 16impl super::SealedAdcPin<ADC1> for VrefInt {
@@ -97,7 +94,7 @@ impl<'d, T> Adc<'d, T>
97where 94where
98 T: Instance, 95 T: Instance,
99{ 96{
100 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 97 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
101 into_ref!(adc); 98 into_ref!(adc);
102 T::enable_and_reset(); 99 T::enable_and_reset();
103 100
@@ -107,7 +104,7 @@ where
107 reg.set_adon(true); 104 reg.set_adon(true);
108 }); 105 });
109 106
110 delay.delay_us(ADC_POWERUP_TIME_US); 107 blocking_delay_us(3);
111 108
112 Self { 109 Self {
113 adc, 110 adc,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index e25630be2..dc418297e 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,7 +1,7 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3use embedded_hal_02::blocking::delay::DelayUs;
4 3
4use super::blocking_delay_us;
5use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 5use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
6use crate::Peripheral; 6use crate::Peripheral;
7 7
@@ -19,6 +19,8 @@ impl<T: Instance> super::SealedAdcPin<T> for VrefInt {
19 let val = 13; 19 let val = 13;
20 } else if #[cfg(adc_h5)] { 20 } else if #[cfg(adc_h5)] {
21 let val = 17; 21 let val = 17;
22 } else if #[cfg(adc_u0)] {
23 let val = 12;
22 } else { 24 } else {
23 let val = 0; 25 let val = 0;
24 } 26 }
@@ -36,6 +38,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature {
36 let val = 12; 38 let val = 12;
37 } else if #[cfg(adc_h5)] { 39 } else if #[cfg(adc_h5)] {
38 let val = 16; 40 let val = 16;
41 } else if #[cfg(adc_u0)] {
42 let val = 11;
39 } else { 43 } else {
40 let val = 17; 44 let val = 17;
41 } 45 }
@@ -53,6 +57,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Vbat {
53 let val = 14; 57 let val = 14;
54 } else if #[cfg(adc_h5)] { 58 } else if #[cfg(adc_h5)] {
55 let val = 2; 59 let val = 2;
60 } else if #[cfg(adc_h5)] {
61 let val = 13;
56 } else { 62 } else {
57 let val = 18; 63 let val = 18;
58 } 64 }
@@ -73,22 +79,34 @@ cfg_if! {
73 } 79 }
74} 80}
75 81
82cfg_if! {
83 if #[cfg(adc_u0)] {
84 pub struct DacOut;
85 impl<T: Instance> AdcPin<T> for DacOut {}
86 impl<T: Instance> super::SealedAdcPin<T> for DacOut {
87 fn channel(&self) -> u8 {
88 19
89 }
90 }
91 }
92}
93
76impl<'d, T: Instance> Adc<'d, T> { 94impl<'d, T: Instance> Adc<'d, T> {
77 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 95 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
78 into_ref!(adc); 96 into_ref!(adc);
79 T::enable_and_reset(); 97 T::enable_and_reset();
80 T::regs().cr().modify(|reg| { 98 T::regs().cr().modify(|reg| {
81 #[cfg(not(adc_g0))] 99 #[cfg(not(any(adc_g0, adc_u0)))]
82 reg.set_deeppwd(false); 100 reg.set_deeppwd(false);
83 reg.set_advregen(true); 101 reg.set_advregen(true);
84 }); 102 });
85 103
86 #[cfg(adc_g0)] 104 #[cfg(any(adc_g0, adc_u0))]
87 T::regs().cfgr1().modify(|reg| { 105 T::regs().cfgr1().modify(|reg| {
88 reg.set_chselrmod(false); 106 reg.set_chselrmod(false);
89 }); 107 });
90 108
91 delay.delay_us(20); 109 blocking_delay_us(20);
92 110
93 T::regs().cr().modify(|reg| { 111 T::regs().cr().modify(|reg| {
94 reg.set_adcal(true); 112 reg.set_adcal(true);
@@ -98,7 +116,7 @@ impl<'d, T: Instance> Adc<'d, T> {
98 // spin 116 // spin
99 } 117 }
100 118
101 delay.delay_us(1); 119 blocking_delay_us(1);
102 120
103 Self { 121 Self {
104 adc, 122 adc,
@@ -106,28 +124,26 @@ impl<'d, T: Instance> Adc<'d, T> {
106 } 124 }
107 } 125 }
108 126
109 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { 127 pub fn enable_vrefint(&self) -> VrefInt {
110 #[cfg(not(adc_g0))] 128 #[cfg(not(any(adc_g0, adc_u0)))]
111 T::common_regs().ccr().modify(|reg| { 129 T::common_regs().ccr().modify(|reg| {
112 reg.set_vrefen(true); 130 reg.set_vrefen(true);
113 }); 131 });
114 #[cfg(adc_g0)] 132 #[cfg(any(adc_g0, adc_u0))]
115 T::regs().ccr().modify(|reg| { 133 T::regs().ccr().modify(|reg| {
116 reg.set_vrefen(true); 134 reg.set_vrefen(true);
117 }); 135 });
118 136
119 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us 137 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
120 // to stabilize the internal voltage reference, we wait a little more. 138 // to stabilize the internal voltage reference.
121 // TODO: delay 15us 139 blocking_delay_us(15);
122 //cortex_m::asm::delay(20_000_000);
123 delay.delay_us(15);
124 140
125 VrefInt {} 141 VrefInt {}
126 } 142 }
127 143
128 pub fn enable_temperature(&self) -> Temperature { 144 pub fn enable_temperature(&self) -> Temperature {
129 cfg_if! { 145 cfg_if! {
130 if #[cfg(adc_g0)] { 146 if #[cfg(any(adc_g0, adc_u0))] {
131 T::regs().ccr().modify(|reg| { 147 T::regs().ccr().modify(|reg| {
132 reg.set_tsen(true); 148 reg.set_tsen(true);
133 }); 149 });
@@ -147,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> {
147 163
148 pub fn enable_vbat(&self) -> Vbat { 164 pub fn enable_vbat(&self) -> Vbat {
149 cfg_if! { 165 cfg_if! {
150 if #[cfg(adc_g0)] { 166 if #[cfg(any(adc_g0, adc_u0))] {
151 T::regs().ccr().modify(|reg| { 167 T::regs().ccr().modify(|reg| {
152 reg.set_vbaten(true); 168 reg.set_vbaten(true);
153 }); 169 });
@@ -170,9 +186,9 @@ impl<'d, T: Instance> Adc<'d, T> {
170 } 186 }
171 187
172 pub fn set_resolution(&mut self, resolution: Resolution) { 188 pub fn set_resolution(&mut self, resolution: Resolution) {
173 #[cfg(not(adc_g0))] 189 #[cfg(not(any(adc_g0, adc_u0)))]
174 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 190 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
175 #[cfg(adc_g0)] 191 #[cfg(any(adc_g0, adc_u0))]
176 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 192 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
177 } 193 }
178 194
@@ -233,9 +249,9 @@ impl<'d, T: Instance> Adc<'d, T> {
233 Self::set_channel_sample_time(pin.channel(), self.sample_time); 249 Self::set_channel_sample_time(pin.channel(), self.sample_time);
234 250
235 // Select channel 251 // Select channel
236 #[cfg(not(adc_g0))] 252 #[cfg(not(any(adc_g0, adc_u0)))]
237 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); 253 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
238 #[cfg(adc_g0)] 254 #[cfg(any(adc_g0, adc_u0))]
239 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); 255 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
240 256
241 // Some models are affected by an erratum: 257 // Some models are affected by an erratum:
@@ -263,7 +279,7 @@ impl<'d, T: Instance> Adc<'d, T> {
263 279
264 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 280 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
265 cfg_if! { 281 cfg_if! {
266 if #[cfg(adc_g0)] { 282 if #[cfg(any(adc_g0, adc_u0))] {
267 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 283 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
268 } else if #[cfg(adc_h5)] { 284 } else if #[cfg(adc_h5)] {
269 match _ch { 285 match _ch {
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 1ae25bea2..ca87b41ee 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,9 +1,8 @@
1use embedded_hal_02::blocking::delay::DelayUs;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; 2use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
5 4
6use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 5use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
7use crate::time::Hertz; 6use crate::time::Hertz;
8use crate::{pac, Peripheral}; 7use crate::{pac, Peripheral};
9 8
@@ -129,7 +128,7 @@ impl Prescaler {
129 128
130impl<'d, T: Instance> Adc<'d, T> { 129impl<'d, T: Instance> Adc<'d, T> {
131 /// Create a new ADC driver. 130 /// Create a new ADC driver.
132 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { 131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
133 embassy_hal_internal::into_ref!(adc); 132 embassy_hal_internal::into_ref!(adc);
134 T::enable_and_reset(); 133 T::enable_and_reset();
135 134
@@ -161,11 +160,11 @@ impl<'d, T: Instance> Adc<'d, T> {
161 adc, 160 adc,
162 sample_time: SampleTime::from_bits(0), 161 sample_time: SampleTime::from_bits(0),
163 }; 162 };
164 s.power_up(delay); 163 s.power_up();
165 s.configure_differential_inputs(); 164 s.configure_differential_inputs();
166 165
167 s.calibrate(); 166 s.calibrate();
168 delay.delay_us(1); 167 blocking_delay_us(1);
169 168
170 s.enable(); 169 s.enable();
171 s.configure(); 170 s.configure();
@@ -173,13 +172,13 @@ impl<'d, T: Instance> Adc<'d, T> {
173 s 172 s
174 } 173 }
175 174
176 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { 175 fn power_up(&mut self) {
177 T::regs().cr().modify(|reg| { 176 T::regs().cr().modify(|reg| {
178 reg.set_deeppwd(false); 177 reg.set_deeppwd(false);
179 reg.set_advregen(true); 178 reg.set_advregen(true);
180 }); 179 });
181 180
182 delay.delay_us(10); 181 blocking_delay_us(10);
183 } 182 }
184 183
185 fn configure_differential_inputs(&mut self) { 184 fn configure_differential_inputs(&mut self) {
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index e32f19d91..e5cfee528 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -368,6 +368,7 @@ impl Registers {
368 w.set_rfne(0, true); // Rx Fifo 0 New Msg 368 w.set_rfne(0, true); // Rx Fifo 0 New Msg
369 w.set_rfne(1, true); // Rx Fifo 1 New Msg 369 w.set_rfne(1, true); // Rx Fifo 1 New Msg
370 w.set_tce(true); // Tx Complete 370 w.set_tce(true); // Tx Complete
371 w.set_boe(true); // Bus-Off Status Changed
371 }); 372 });
372 self.regs.ile().modify(|w| { 373 self.regs.ile().modify(|w| {
373 w.set_eint0(true); // Interrupt Line 0 374 w.set_eint0(true); // Interrupt Line 0
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index e31821ca2..563f542d4 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -44,53 +44,51 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
44 44
45 let ir = regs.ir().read(); 45 let ir = regs.ir().read();
46 46
47 { 47 if ir.tc() {
48 if ir.tc() { 48 regs.ir().write(|w| w.set_tc(true));
49 regs.ir().write(|w| w.set_tc(true)); 49 }
50 } 50 if ir.tefn() {
51 if ir.tefn() { 51 regs.ir().write(|w| w.set_tefn(true));
52 regs.ir().write(|w| w.set_tefn(true)); 52 }
53 }
54 53
55 match &T::state().tx_mode { 54 match &T::state().tx_mode {
56 TxMode::NonBuffered(waker) => waker.wake(), 55 TxMode::NonBuffered(waker) => waker.wake(),
57 TxMode::ClassicBuffered(buf) => { 56 TxMode::ClassicBuffered(buf) => {
58 if !T::registers().tx_queue_is_full() { 57 if !T::registers().tx_queue_is_full() {
59 match buf.tx_receiver.try_receive() { 58 match buf.tx_receiver.try_receive() {
60 Ok(frame) => { 59 Ok(frame) => {
61 _ = T::registers().write(&frame); 60 _ = T::registers().write(&frame);
62 }
63 Err(_) => {}
64 } 61 }
62 Err(_) => {}
65 } 63 }
66 } 64 }
67 TxMode::FdBuffered(buf) => { 65 }
68 if !T::registers().tx_queue_is_full() { 66 TxMode::FdBuffered(buf) => {
69 match buf.tx_receiver.try_receive() { 67 if !T::registers().tx_queue_is_full() {
70 Ok(frame) => { 68 match buf.tx_receiver.try_receive() {
71 _ = T::registers().write(&frame); 69 Ok(frame) => {
72 } 70 _ = T::registers().write(&frame);
73 Err(_) => {}
74 } 71 }
72 Err(_) => {}
75 } 73 }
76 } 74 }
77 } 75 }
78 } 76 }
79 77
80 if ir.ped() || ir.pea() {
81 regs.ir().write(|w| {
82 w.set_ped(true);
83 w.set_pea(true);
84 });
85 }
86
87 if ir.rfn(0) { 78 if ir.rfn(0) {
88 T::state().rx_mode.on_interrupt::<T>(0); 79 T::state().rx_mode.on_interrupt::<T>(0);
89 } 80 }
90
91 if ir.rfn(1) { 81 if ir.rfn(1) {
92 T::state().rx_mode.on_interrupt::<T>(1); 82 T::state().rx_mode.on_interrupt::<T>(1);
93 } 83 }
84
85 if ir.bo() {
86 regs.ir().write(|w| w.set_bo(true));
87 if regs.psr().read().bo() {
88 // Initiate bus-off recovery sequence by resetting CCCR.INIT
89 regs.cccr().modify(|w| w.set_init(false));
90 }
91 }
94 } 92 }
95} 93}
96 94
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index f8909d438..e8e0270af 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -32,6 +32,9 @@ impl<'d> Crc<'d> {
32 /// Feeds a word to the peripheral and returns the current CRC value 32 /// Feeds a word to the peripheral and returns the current CRC value
33 pub fn feed_word(&mut self, word: u32) -> u32 { 33 pub fn feed_word(&mut self, word: u32) -> u32 {
34 // write a single byte to the device, and return the result 34 // write a single byte to the device, and return the result
35 #[cfg(not(crc_v1))]
36 PAC_CRC.dr32().write_value(word);
37 #[cfg(crc_v1)]
35 PAC_CRC.dr().write_value(word); 38 PAC_CRC.dr().write_value(word);
36 self.read() 39 self.read()
37 } 40 }
@@ -39,6 +42,9 @@ impl<'d> Crc<'d> {
39 /// Feed a slice of words to the peripheral and return the result. 42 /// Feed a slice of words to the peripheral and return the result.
40 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 43 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
41 for word in words { 44 for word in words {
45 #[cfg(not(crc_v1))]
46 PAC_CRC.dr32().write_value(*word);
47 #[cfg(crc_v1)]
42 PAC_CRC.dr().write_value(*word); 48 PAC_CRC.dr().write_value(*word);
43 } 49 }
44 50
@@ -46,6 +52,12 @@ impl<'d> Crc<'d> {
46 } 52 }
47 53
48 /// Read the CRC result value. 54 /// Read the CRC result value.
55 #[cfg(not(crc_v1))]
56 pub fn read(&self) -> u32 {
57 PAC_CRC.dr32().read()
58 }
59 /// Read the CRC result value.
60 #[cfg(crc_v1)]
49 pub fn read(&self) -> u32 { 61 pub fn read(&self) -> u32 {
50 PAC_CRC.dr().read() 62 PAC_CRC.dr().read()
51 } 63 }
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 46f5ea1be..ad7c79f12 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -13,6 +13,8 @@ pub struct Crc<'d> {
13} 13}
14 14
15/// CRC configuration errlr 15/// CRC configuration errlr
16#[derive(Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum ConfigError { 18pub enum ConfigError {
17 /// The selected polynomial is invalid. 19 /// The selected polynomial is invalid.
18 InvalidPolynomial, 20 InvalidPolynomial,
@@ -136,7 +138,7 @@ impl<'d> Crc<'d> {
136 /// Feeds a byte into the CRC peripheral. Returns the computed checksum. 138 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
137 pub fn feed_byte(&mut self, byte: u8) -> u32 { 139 pub fn feed_byte(&mut self, byte: u8) -> u32 {
138 PAC_CRC.dr8().write_value(byte); 140 PAC_CRC.dr8().write_value(byte);
139 PAC_CRC.dr().read() 141 PAC_CRC.dr32().read()
140 } 142 }
141 143
142 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. 144 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
@@ -144,30 +146,30 @@ impl<'d> Crc<'d> {
144 for byte in bytes { 146 for byte in bytes {
145 PAC_CRC.dr8().write_value(*byte); 147 PAC_CRC.dr8().write_value(*byte);
146 } 148 }
147 PAC_CRC.dr().read() 149 PAC_CRC.dr32().read()
148 } 150 }
149 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. 151 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
150 pub fn feed_halfword(&mut self, halfword: u16) -> u32 { 152 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
151 PAC_CRC.dr16().write_value(halfword); 153 PAC_CRC.dr16().write_value(halfword);
152 PAC_CRC.dr().read() 154 PAC_CRC.dr32().read()
153 } 155 }
154 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. 156 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
155 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { 157 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
156 for halfword in halfwords { 158 for halfword in halfwords {
157 PAC_CRC.dr16().write_value(*halfword); 159 PAC_CRC.dr16().write_value(*halfword);
158 } 160 }
159 PAC_CRC.dr().read() 161 PAC_CRC.dr32().read()
160 } 162 }
161 /// Feeds a words into the CRC peripheral. Returns the computed checksum. 163 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
162 pub fn feed_word(&mut self, word: u32) -> u32 { 164 pub fn feed_word(&mut self, word: u32) -> u32 {
163 PAC_CRC.dr().write_value(word as u32); 165 PAC_CRC.dr32().write_value(word as u32);
164 PAC_CRC.dr().read() 166 PAC_CRC.dr32().read()
165 } 167 }
166 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. 168 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
167 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 169 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
168 for word in words { 170 for word in words {
169 PAC_CRC.dr().write_value(*word as u32); 171 PAC_CRC.dr32().write_value(*word as u32);
170 } 172 }
171 PAC_CRC.dr().read() 173 PAC_CRC.dr32().read()
172 } 174 }
173} 175}
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs
index 22d8d3dfa..1877954b9 100644
--- a/embassy-stm32/src/dac/tsel.rs
+++ b/embassy-stm32/src/dac/tsel.rs
@@ -235,6 +235,23 @@ pub enum TriggerSel {
235 Exti9 = 13, 235 Exti9 = 13,
236} 236}
237 237
238/// Trigger selection for U0.
239#[cfg(stm32u0)]
240#[derive(Debug, Copy, Clone, Eq, PartialEq)]
241#[cfg_attr(feature = "defmt", derive(defmt::Format))]
242pub enum TriggerSel {
243 Software = 0,
244 Tim1 = 1,
245 Tim2 = 2,
246 Tim3 = 3,
247 Tim6 = 5,
248 Tim7 = 6,
249 Tim15 = 8,
250 Lptim1 = 11,
251 Lptim2 = 12,
252 Exti9 = 14,
253}
254
238/// Trigger selection for G4. 255/// Trigger selection for G4.
239#[cfg(stm32g4)] 256#[cfg(stm32g4)]
240#[derive(Debug, Copy, Clone, Eq, PartialEq)] 257#[derive(Debug, Copy, Clone, Eq, PartialEq)]
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 7e3681469..8766d0a60 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -16,6 +16,9 @@ mod dmamux;
16#[cfg(dmamux)] 16#[cfg(dmamux)]
17pub use dmamux::*; 17pub use dmamux::*;
18 18
19mod util;
20pub(crate) use util::*;
21
19pub(crate) mod ringbuffer; 22pub(crate) mod ringbuffer;
20pub mod word; 23pub mod word;
21 24
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
new file mode 100644
index 000000000..962ea2501
--- /dev/null
+++ b/embassy-stm32/src/dma/util.rs
@@ -0,0 +1,60 @@
1use embassy_hal_internal::PeripheralRef;
2
3use super::word::Word;
4use super::{AnyChannel, Request, Transfer, TransferOptions};
5
6/// Convenience wrapper, contains a channel and a request number.
7///
8/// Commonly used in peripheral drivers that own DMA channels.
9pub(crate) struct ChannelAndRequest<'d> {
10 pub channel: PeripheralRef<'d, AnyChannel>,
11 pub request: Request,
12}
13
14impl<'d> ChannelAndRequest<'d> {
15 pub unsafe fn read<'a, W: Word>(
16 &'a mut self,
17 peri_addr: *mut W,
18 buf: &'a mut [W],
19 options: TransferOptions,
20 ) -> Transfer<'a> {
21 Transfer::new_read(&mut self.channel, self.request, peri_addr, buf, options)
22 }
23
24 pub unsafe fn read_raw<'a, W: Word>(
25 &'a mut self,
26 peri_addr: *mut W,
27 buf: *mut [W],
28 options: TransferOptions,
29 ) -> Transfer<'a> {
30 Transfer::new_read_raw(&mut self.channel, self.request, peri_addr, buf, options)
31 }
32
33 pub unsafe fn write<'a, W: Word>(
34 &'a mut self,
35 buf: &'a [W],
36 peri_addr: *mut W,
37 options: TransferOptions,
38 ) -> Transfer<'a> {
39 Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options)
40 }
41
42 pub unsafe fn write_raw<'a, W: Word>(
43 &'a mut self,
44 buf: *const [W],
45 peri_addr: *mut W,
46 options: TransferOptions,
47 ) -> Transfer<'a> {
48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
49 }
50
51 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self,
53 repeated: &'a W,
54 count: usize,
55 peri_addr: *mut W,
56 options: TransferOptions,
57 ) -> Transfer<'a> {
58 Transfer::new_write_repeated(&mut self.channel, self.request, repeated, count, peri_addr, options)
59 }
60}
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 8d5dae436..224d51b84 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -27,11 +27,11 @@ fn cpu_regs() -> pac::exti::Exti {
27 EXTI 27 EXTI
28} 28}
29 29
30#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] 30#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
31fn exticr_regs() -> pac::syscfg::Syscfg { 31fn exticr_regs() -> pac::syscfg::Syscfg {
32 pac::SYSCFG 32 pac::SYSCFG
33} 33}
34#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] 34#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
35fn exticr_regs() -> pac::exti::Exti { 35fn exticr_regs() -> pac::exti::Exti {
36 EXTI 36 EXTI
37} 37}
@@ -44,9 +44,9 @@ unsafe fn on_irq() {
44 #[cfg(feature = "low-power")] 44 #[cfg(feature = "low-power")]
45 crate::low_power::on_wakeup_irq(); 45 crate::low_power::on_wakeup_irq();
46 46
47 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] 47 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
48 let bits = EXTI.pr(0).read().0; 48 let bits = EXTI.pr(0).read().0;
49 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] 49 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
50 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; 50 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
51 51
52 // We don't handle or change any EXTI lines above 16. 52 // We don't handle or change any EXTI lines above 16.
@@ -61,9 +61,9 @@ unsafe fn on_irq() {
61 } 61 }
62 62
63 // Clear pending 63 // Clear pending
64 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] 64 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
65 EXTI.pr(0).write_value(Lines(bits)); 65 EXTI.pr(0).write_value(Lines(bits));
66 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] 66 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
67 { 67 {
68 EXTI.rpr(0).write_value(Lines(bits)); 68 EXTI.rpr(0).write_value(Lines(bits));
69 EXTI.fpr(0).write_value(Lines(bits)); 69 EXTI.fpr(0).write_value(Lines(bits));
@@ -241,9 +241,9 @@ impl<'a> ExtiInputFuture<'a> {
241 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); 241 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
242 242
243 // clear pending bit 243 // clear pending bit
244 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] 244 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
245 EXTI.pr(0).write(|w| w.set_line(pin, true)); 245 EXTI.pr(0).write(|w| w.set_line(pin, true));
246 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] 246 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
247 { 247 {
248 EXTI.rpr(0).write(|w| w.set_line(pin, true)); 248 EXTI.rpr(0).write(|w| w.set_line(pin, true));
249 EXTI.fpr(0).write(|w| w.set_line(pin, true)); 249 EXTI.fpr(0).write(|w| w.set_line(pin, true));
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 00e61f2d2..90f13ff29 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -16,7 +16,7 @@ mod alt_regions {
16 use embassy_hal_internal::PeripheralRef; 16 use embassy_hal_internal::PeripheralRef;
17 use stm32_metapac::FLASH_SIZE; 17 use stm32_metapac::FLASH_SIZE;
18 18
19 use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; 19 use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
20 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; 20 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
21 use crate::peripherals::FLASH; 21 use crate::peripherals::FLASH;
22 22
@@ -62,7 +62,6 @@ mod alt_regions {
62 pub bank2_region1: AltBank2Region1<'d, MODE>, 62 pub bank2_region1: AltBank2Region1<'d, MODE>,
63 pub bank2_region2: AltBank2Region2<'d, MODE>, 63 pub bank2_region2: AltBank2Region2<'d, MODE>,
64 pub bank2_region3: AltBank2Region3<'d, MODE>, 64 pub bank2_region3: AltBank2Region3<'d, MODE>,
65 pub otp_region: OTPRegion<'d, MODE>,
66 } 65 }
67 66
68 impl<'d> Flash<'d> { 67 impl<'d> Flash<'d> {
@@ -79,7 +78,6 @@ mod alt_regions {
79 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), 78 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
80 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), 79 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
81 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), 80 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
82 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
83 } 81 }
84 } 82 }
85 83
@@ -96,7 +94,6 @@ mod alt_regions {
96 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), 94 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
97 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), 95 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
98 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), 96 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
99 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
100 } 97 }
101 } 98 }
102 } 99 }
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index db05bef5d..56ea7a421 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -55,17 +55,18 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
55} 55}
56 56
57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
58 assert!(sector.bank != FlashBank::Otp);
59 assert!(sector.index_in_bank < 8); 58 assert!(sector.index_in_bank < 8);
60 59
61 while busy() {} 60 while busy() {}
62 61
63 interrupt::free(|_| { 62 interrupt::free(|_| {
64 pac::FLASH.nscr().modify(|w| { 63 pac::FLASH.nscr().modify(|w| {
65 w.set_bksel(match sector.bank { 64 // BKSEL ignores SWAP_BANK, so we must take it into account here
66 FlashBank::Bank1 => Bksel::B_0X0, 65 w.set_bksel(match (sector.bank, banks_swapped()) {
67 FlashBank::Bank2 => Bksel::B_0X1, 66 (FlashBank::Bank1, false) => Bksel::BANK1,
68 _ => unreachable!(), 67 (FlashBank::Bank2, true) => Bksel::BANK1,
68 (FlashBank::Bank2, false) => Bksel::BANK2,
69 (FlashBank::Bank1, true) => Bksel::BANK2,
69 }); 70 });
70 w.set_snb(sector.index_in_bank); 71 w.set_snb(sector.index_in_bank);
71 w.set_ser(true); 72 w.set_ser(true);
@@ -113,6 +114,47 @@ pub(crate) unsafe fn clear_all_err() {
113 }) 114 })
114} 115}
115 116
117/// Get the current SWAP_BANK option.
118///
119/// This value is only loaded on system or power-on reset. `perform_bank_swap()`
120/// will not reflect here.
121pub fn banks_swapped() -> bool {
122 pac::FLASH.optcr().read().swap_bank()
123}
124
125/// Logical, persistent swap of flash banks 1 and 2.
126///
127/// This allows the application to write a new firmware blob into bank 2, then
128/// swap the banks and perform a reset, loading the new firmware.
129///
130/// Swap does not take effect until system or power-on reset.
131///
132/// PLEASE READ THE REFERENCE MANUAL - there are nuances to this feature. For
133/// instance, erase commands and interrupt enables which take a flash bank as a
134/// parameter ignore the swap!
135pub fn perform_bank_swap() {
136 while busy() {}
137
138 unsafe {
139 clear_all_err();
140 }
141
142 // unlock OPTLOCK
143 pac::FLASH.optkeyr().write(|w| *w = 0x0819_2A3B);
144 pac::FLASH.optkeyr().write(|w| *w = 0x4C5D_6E7F);
145 while pac::FLASH.optcr().read().optlock() {}
146
147 // toggle SWAP_BANK option
148 pac::FLASH.optsr_prg().modify(|w| w.set_swap_bank(!banks_swapped()));
149
150 // load option bytes
151 pac::FLASH.optcr().modify(|w| w.set_optstrt(true));
152 while pac::FLASH.optcr().read().optstrt() {}
153
154 // re-lock OPTLOCK
155 pac::FLASH.optcr().modify(|w| w.set_optlock(true));
156}
157
116fn sr_busy(sr: Nssr) -> bool { 158fn sr_busy(sr: Nssr) -> bool {
117 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE 159 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE
118 sr.bsy() || sr.dbne() || sr.wbne() 160 sr.bsy() || sr.dbne() || sr.wbne()
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 1d8031e82..8c6ca2471 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -89,8 +89,6 @@ pub enum FlashBank {
89 Bank1 = 0, 89 Bank1 = 0,
90 /// Bank 2 90 /// Bank 2
91 Bank2 = 1, 91 Bank2 = 1,
92 /// OTP region
93 Otp,
94} 92}
95 93
96#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] 94#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
@@ -103,10 +101,11 @@ pub enum FlashBank {
103#[cfg_attr(flash_h7ab, path = "h7.rs")] 101#[cfg_attr(flash_h7ab, path = "h7.rs")]
104#[cfg_attr(flash_u5, path = "u5.rs")] 102#[cfg_attr(flash_u5, path = "u5.rs")]
105#[cfg_attr(flash_h50, path = "h50.rs")] 103#[cfg_attr(flash_h50, path = "h50.rs")]
104#[cfg_attr(flash_u0, path = "u0.rs")]
106#[cfg_attr( 105#[cfg_attr(
107 not(any( 106 not(any(
108 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0,
109 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 108 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
110 )), 109 )),
111 path = "other.rs" 110 path = "other.rs"
112)] 111)]
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
new file mode 100644
index 000000000..dfc5a2f76
--- /dev/null
+++ b/embassy-stm32/src/flash/u0.rs
@@ -0,0 +1,96 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering};
3
4use cortex_m::interrupt;
5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true));
20}
21pub(crate) unsafe fn unlock() {
22 // Wait, while the memory interface is busy.
23 while pac::FLASH.sr().read().bsy1() {}
24
25 // Unlock flash
26 if pac::FLASH.cr().read().lock() {
27 pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
28 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
29 }
30}
31
32pub(crate) unsafe fn enable_blocking_write() {
33 assert_eq!(0, WRITE_SIZE % 4);
34 pac::FLASH.cr().write(|w| w.set_pg(true));
35}
36
37pub(crate) unsafe fn disable_blocking_write() {
38 pac::FLASH.cr().write(|w| w.set_pg(false));
39}
40
41pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
42 let mut address = start_address;
43 for val in buf.chunks(4) {
44 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
45 address += val.len() as u32;
46
47 // prevents parallelism errors
48 fence(Ordering::SeqCst);
49 }
50
51 wait_ready_blocking()
52}
53
54pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
55 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
56 while pac::FLASH.sr().read().bsy1() {}
57 clear_all_err();
58
59 interrupt::free(|_| {
60 pac::FLASH.cr().modify(|w| {
61 w.set_per(true);
62 w.set_pnb(idx as u8);
63 w.set_strt(true);
64 });
65 });
66
67 let ret: Result<(), Error> = wait_ready_blocking();
68 pac::FLASH.cr().modify(|w| w.set_per(false));
69 ret
70}
71
72pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
73 while pac::FLASH.sr().read().bsy1() {}
74
75 let sr = pac::FLASH.sr().read();
76
77 if sr.progerr() {
78 return Err(Error::Prog);
79 }
80
81 if sr.wrperr() {
82 return Err(Error::Protected);
83 }
84
85 if sr.pgaerr() {
86 return Err(Error::Unaligned);
87 }
88
89 Ok(())
90}
91
92pub(crate) unsafe fn clear_all_err() {
93 // read and write back the same value.
94 // This clears all "write 1 to clear" bits.
95 pac::FLASH.sr().modify(|_| {});
96}
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 580c490da..ddd4d73ff 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -14,26 +14,43 @@ pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14} 14}
15 15
16pub(crate) unsafe fn lock() { 16pub(crate) unsafe fn lock() {
17 #[cfg(feature = "trustzone-secure")]
17 pac::FLASH.seccr().modify(|w| w.set_lock(true)); 18 pac::FLASH.seccr().modify(|w| w.set_lock(true));
19 #[cfg(not(feature = "trustzone-secure"))]
20 pac::FLASH.nscr().modify(|w| w.set_lock(true));
18} 21}
19 22
20pub(crate) unsafe fn unlock() { 23pub(crate) unsafe fn unlock() {
24 #[cfg(feature = "trustzone-secure")]
21 if pac::FLASH.seccr().read().lock() { 25 if pac::FLASH.seccr().read().lock() {
22 pac::FLASH.seckeyr().write_value(0x4567_0123); 26 pac::FLASH.seckeyr().write_value(0x4567_0123);
23 pac::FLASH.seckeyr().write_value(0xCDEF_89AB); 27 pac::FLASH.seckeyr().write_value(0xCDEF_89AB);
24 } 28 }
29 #[cfg(not(feature = "trustzone-secure"))]
30 if pac::FLASH.nscr().read().lock() {
31 pac::FLASH.nskeyr().write_value(0x4567_0123);
32 pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
33 }
25} 34}
26 35
27pub(crate) unsafe fn enable_blocking_write() { 36pub(crate) unsafe fn enable_blocking_write() {
28 assert_eq!(0, WRITE_SIZE % 4); 37 assert_eq!(0, WRITE_SIZE % 4);
29 38
39 #[cfg(feature = "trustzone-secure")]
30 pac::FLASH.seccr().write(|w| { 40 pac::FLASH.seccr().write(|w| {
31 w.set_pg(pac::flash::vals::SeccrPg::B_0X1); 41 w.set_pg(pac::flash::vals::SeccrPg::B_0X1);
32 }); 42 });
43 #[cfg(not(feature = "trustzone-secure"))]
44 pac::FLASH.nscr().write(|w| {
45 w.set_pg(pac::flash::vals::NscrPg::B_0X1);
46 });
33} 47}
34 48
35pub(crate) unsafe fn disable_blocking_write() { 49pub(crate) unsafe fn disable_blocking_write() {
50 #[cfg(feature = "trustzone-secure")]
36 pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0)); 51 pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0));
52 #[cfg(not(feature = "trustzone-secure"))]
53 pac::FLASH.nscr().write(|w| w.set_pg(pac::flash::vals::NscrPg::B_0X0));
37} 54}
38 55
39pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 56pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
@@ -50,19 +67,35 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
50} 67}
51 68
52pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 69pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
70 #[cfg(feature = "trustzone-secure")]
53 pac::FLASH.seccr().modify(|w| { 71 pac::FLASH.seccr().modify(|w| {
54 w.set_per(pac::flash::vals::SeccrPer::B_0X1); 72 w.set_per(pac::flash::vals::SeccrPer::B_0X1);
55 w.set_pnb(sector.index_in_bank) 73 w.set_pnb(sector.index_in_bank)
56 }); 74 });
75 #[cfg(not(feature = "trustzone-secure"))]
76 pac::FLASH.nscr().modify(|w| {
77 w.set_per(pac::flash::vals::NscrPer::B_0X1);
78 w.set_pnb(sector.index_in_bank)
79 });
57 80
81 #[cfg(feature = "trustzone-secure")]
58 pac::FLASH.seccr().modify(|w| { 82 pac::FLASH.seccr().modify(|w| {
59 w.set_strt(true); 83 w.set_strt(true);
60 }); 84 });
85 #[cfg(not(feature = "trustzone-secure"))]
86 pac::FLASH.nscr().modify(|w| {
87 w.set_strt(true);
88 });
61 89
62 let ret: Result<(), Error> = blocking_wait_ready(); 90 let ret: Result<(), Error> = blocking_wait_ready();
91 #[cfg(feature = "trustzone-secure")]
63 pac::FLASH 92 pac::FLASH
64 .seccr() 93 .seccr()
65 .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0)); 94 .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0));
95 #[cfg(not(feature = "trustzone-secure"))]
96 pac::FLASH
97 .nscr()
98 .modify(|w| w.set_per(pac::flash::vals::NscrPer::B_0X0));
66 clear_all_err(); 99 clear_all_err();
67 ret 100 ret
68} 101}
@@ -70,12 +103,18 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
70pub(crate) unsafe fn clear_all_err() { 103pub(crate) unsafe fn clear_all_err() {
71 // read and write back the same value. 104 // read and write back the same value.
72 // This clears all "write 1 to clear" bits. 105 // This clears all "write 1 to clear" bits.
106 #[cfg(feature = "trustzone-secure")]
73 pac::FLASH.secsr().modify(|_| {}); 107 pac::FLASH.secsr().modify(|_| {});
108 #[cfg(not(feature = "trustzone-secure"))]
109 pac::FLASH.nssr().modify(|_| {});
74} 110}
75 111
76unsafe fn blocking_wait_ready() -> Result<(), Error> { 112unsafe fn blocking_wait_ready() -> Result<(), Error> {
77 loop { 113 loop {
114 #[cfg(feature = "trustzone-secure")]
78 let sr = pac::FLASH.secsr().read(); 115 let sr = pac::FLASH.secsr().read();
116 #[cfg(not(feature = "trustzone-secure"))]
117 let sr = pac::FLASH.nssr().read();
79 118
80 if !sr.bsy() { 119 if !sr.bsy() {
81 if sr.pgserr() { 120 if sr.pgserr() {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index a46061d54..ccbea9831 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -14,9 +14,10 @@ use embassy_sync::waitqueue::AtomicWaker;
14#[cfg(feature = "time")] 14#[cfg(feature = "time")]
15use embassy_time::{Duration, Instant}; 15use embassy_time::{Duration, Instant};
16 16
17use crate::dma::NoDma; 17use 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::time::Hertz; 21use crate::time::Hertz;
21use crate::{interrupt, peripherals}; 22use crate::{interrupt, peripherals};
22 23
@@ -71,17 +72,16 @@ impl Default for Config {
71} 72}
72 73
73/// I2C driver. 74/// I2C driver.
74pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { 75pub struct I2c<'d, T: Instance, M: Mode> {
75 _peri: PeripheralRef<'d, T>, 76 _peri: PeripheralRef<'d, T>,
76 #[allow(dead_code)] 77 tx_dma: Option<ChannelAndRequest<'d>>,
77 tx_dma: PeripheralRef<'d, TXDMA>, 78 rx_dma: Option<ChannelAndRequest<'d>>,
78 #[allow(dead_code)]
79 rx_dma: PeripheralRef<'d, RXDMA>,
80 #[cfg(feature = "time")] 79 #[cfg(feature = "time")]
81 timeout: Duration, 80 timeout: Duration,
81 _phantom: PhantomData<M>,
82} 82}
83 83
84impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 84impl<'d, T: Instance> I2c<'d, T, Async> {
85 /// Create a new I2C driver. 85 /// Create a new I2C driver.
86 pub fn new( 86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd, 87 peri: impl Peripheral<P = T> + 'd,
@@ -90,12 +90,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
92 + 'd, 92 + 'd,
93 tx_dma: impl Peripheral<P = TXDMA> + 'd, 93 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
94 rx_dma: impl Peripheral<P = RXDMA> + 'd, 94 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
95 freq: Hertz, 95 freq: Hertz,
96 config: Config, 96 config: Config,
97 ) -> Self { 97 ) -> Self {
98 into_ref!(peri, scl, sda, tx_dma, rx_dma); 98 Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config)
99 }
100}
101
102impl<'d, T: Instance> I2c<'d, T, Blocking> {
103 /// Create a new blocking I2C driver.
104 pub fn new_blocking(
105 peri: impl Peripheral<P = T> + 'd,
106 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
107 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
108 freq: Hertz,
109 config: Config,
110 ) -> Self {
111 Self::new_inner(peri, scl, sda, None, None, freq, config)
112 }
113}
114
115impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
116 /// Create a new I2C driver.
117 fn new_inner(
118 peri: impl Peripheral<P = T> + 'd,
119 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
120 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
121 tx_dma: Option<ChannelAndRequest<'d>>,
122 rx_dma: Option<ChannelAndRequest<'d>>,
123 freq: Hertz,
124 config: Config,
125 ) -> Self {
126 into_ref!(peri, scl, sda);
99 127
100 T::enable_and_reset(); 128 T::enable_and_reset();
101 129
@@ -125,6 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
125 rx_dma, 153 rx_dma,
126 #[cfg(feature = "time")] 154 #[cfg(feature = "time")]
127 timeout: config.timeout, 155 timeout: config.timeout,
156 _phantom: PhantomData,
128 }; 157 };
129 158
130 this.init(freq, config); 159 this.init(freq, config);
@@ -249,7 +278,7 @@ foreach_peripheral!(
249 }; 278 };
250); 279);
251 280
252impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 281impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
253 type Error = Error; 282 type Error = Error;
254 283
255 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 284 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
@@ -257,7 +286,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
257 } 286 }
258} 287}
259 288
260impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { 289impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
261 type Error = Error; 290 type Error = Error;
262 291
263 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { 292 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
@@ -265,7 +294,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
265 } 294 }
266} 295}
267 296
268impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { 297impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
269 type Error = Error; 298 type Error = Error;
270 299
271 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { 300 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
@@ -289,11 +318,11 @@ impl embedded_hal_1::i2c::Error for Error {
289 } 318 }
290} 319}
291 320
292impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> { 321impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> {
293 type Error = Error; 322 type Error = Error;
294} 323}
295 324
296impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { 325impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
297 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 326 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
298 self.blocking_read(address, read) 327 self.blocking_read(address, read)
299 } 328 }
@@ -315,7 +344,7 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
315 } 344 }
316} 345}
317 346
318impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { 347impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> {
319 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 348 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
320 self.read(address, read).await 349 self.read(address, read).await
321 } 350 }
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index d45c48b24..13a473344 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -13,7 +13,7 @@ use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation; 13use embedded_hal_1::i2c::Operation;
14 14
15use super::*; 15use super::*;
16use crate::dma::Transfer; 16use crate::mode::Mode as PeriMode;
17use crate::pac::i2c; 17use crate::pac::i2c;
18 18
19// /!\ /!\ 19// /!\ /!\
@@ -41,7 +41,7 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, M: PeriMode> I2c<'d, T, 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 T::regs().cr1().modify(|reg| {
47 reg.set_pe(false); 47 reg.set_pe(false);
@@ -326,11 +326,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
326 w.set_itevten(true); 326 w.set_itevten(true);
327 }); 327 });
328 } 328 }
329}
329 330
330 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> 331impl<'d, T: Instance> I2c<'d, T, Async> {
331 where 332 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> {
332 TXDMA: crate::i2c::TxDma<T>,
333 {
334 T::regs().cr2().modify(|w| { 333 T::regs().cr2().modify(|w| {
335 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 334 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
336 // reception. 335 // reception.
@@ -415,9 +414,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
415 // this address from the memory after each TxE event. 414 // this address from the memory after each TxE event.
416 let dst = T::regs().dr().as_ptr() as *mut u8; 415 let dst = T::regs().dr().as_ptr() as *mut u8;
417 416
418 let ch = &mut self.tx_dma; 417 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
419 let request = ch.request();
420 Transfer::new_write(ch, request, write, dst, Default::default())
421 }; 418 };
422 419
423 // Wait for bytes to be sent, or an error to occur. 420 // Wait for bytes to be sent, or an error to occur.
@@ -479,10 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
479 } 476 }
480 477
481 /// Write. 478 /// Write.
482 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 479 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
483 where
484 TXDMA: crate::i2c::TxDma<T>,
485 {
486 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 480 self.write_frame(address, write, FrameOptions::FirstAndLastFrame)
487 .await?; 481 .await?;
488 482
@@ -490,20 +484,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
490 } 484 }
491 485
492 /// Read. 486 /// Read.
493 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 487 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
494 where
495 RXDMA: crate::i2c::RxDma<T>,
496 {
497 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 488 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame)
498 .await?; 489 .await?;
499 490
500 Ok(()) 491 Ok(())
501 } 492 }
502 493
503 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> 494 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
504 where
505 RXDMA: crate::i2c::RxDma<T>,
506 {
507 if buffer.is_empty() { 495 if buffer.is_empty() {
508 return Err(Error::Overrun); 496 return Err(Error::Overrun);
509 } 497 }
@@ -623,9 +611,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
623 // from this address from the memory after each RxE event. 611 // from this address from the memory after each RxE event.
624 let src = T::regs().dr().as_ptr() as *mut u8; 612 let src = T::regs().dr().as_ptr() as *mut u8;
625 613
626 let ch = &mut self.rx_dma; 614 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
627 let request = ch.request();
628 Transfer::new_read(ch, request, src, buffer, Default::default())
629 }; 615 };
630 616
631 // Wait for bytes to be received, or an error to occur. 617 // Wait for bytes to be received, or an error to occur.
@@ -664,11 +650,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
664 } 650 }
665 651
666 /// Write, restart, read. 652 /// Write, restart, read.
667 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 653 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
668 where
669 RXDMA: crate::i2c::RxDma<T>,
670 TXDMA: crate::i2c::TxDma<T>,
671 {
672 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 654 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
673 // stop condition below. 655 // stop condition below.
674 if read.is_empty() { 656 if read.is_empty() {
@@ -684,11 +666,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
684 /// Consecutive operations of same type are merged. See [transaction contract] for details. 666 /// Consecutive operations of same type are merged. See [transaction contract] for details.
685 /// 667 ///
686 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 668 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
687 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> 669 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
688 where
689 RXDMA: crate::i2c::RxDma<T>,
690 TXDMA: crate::i2c::TxDma<T>,
691 {
692 for (op, frame) in operation_frames(operations)? { 670 for (op, frame) in operation_frames(operations)? {
693 match op { 671 match op {
694 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 672 Operation::Read(read) => self.read_frame(addr, read, frame).await?,
@@ -700,7 +678,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
700 } 678 }
701} 679}
702 680
703impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 681impl<'d, T: Instance, M: PeriMode> Drop for I2c<'d, T, M> {
704 fn drop(&mut self) { 682 fn drop(&mut self) {
705 T::disable(); 683 T::disable();
706 } 684 }
@@ -806,7 +784,7 @@ impl Timings {
806 } 784 }
807} 785}
808 786
809impl<'d, T: Instance> SetConfig for I2c<'d, T> { 787impl<'d, T: Instance, M: PeriMode> SetConfig for I2c<'d, T, M> {
810 type Config = Hertz; 788 type Config = Hertz;
811 type ConfigError = (); 789 type ConfigError = ();
812 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 790 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index da3b0ee30..12df98534 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -7,7 +7,6 @@ use embassy_hal_internal::drop::OnDrop;
7use embedded_hal_1::i2c::Operation; 7use embedded_hal_1::i2c::Operation;
8 8
9use super::*; 9use super::*;
10use crate::dma::Transfer;
11use crate::pac::i2c; 10use crate::pac::i2c;
12 11
13pub(crate) unsafe fn on_interrupt<T: Instance>() { 12pub(crate) unsafe fn on_interrupt<T: Instance>() {
@@ -24,7 +23,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
24 }); 23 });
25} 24}
26 25
27impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 26impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
28 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 27 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
29 T::regs().cr1().modify(|reg| { 28 T::regs().cr1().modify(|reg| {
30 reg.set_pe(false); 29 reg.set_pe(false);
@@ -302,6 +301,119 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
302 result 301 result
303 } 302 }
304 303
304 // =========================
305 // Blocking public API
306
307 /// Blocking read.
308 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
309 self.read_internal(address, read, false, self.timeout())
310 // Automatic Stop
311 }
312
313 /// Blocking write.
314 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
315 self.write_internal(address, write, true, self.timeout())
316 }
317
318 /// Blocking write, restart, read.
319 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
320 let timeout = self.timeout();
321 self.write_internal(address, write, false, timeout)?;
322 self.read_internal(address, read, true, timeout)
323 // Automatic Stop
324 }
325
326 /// Blocking transaction with operations.
327 ///
328 /// Consecutive operations of same type are merged. See [transaction contract] for details.
329 ///
330 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
331 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
332 let _ = addr;
333 let _ = operations;
334 todo!()
335 }
336
337 /// Blocking write multiple buffers.
338 ///
339 /// The buffers are concatenated in a single write transaction.
340 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
341 if write.is_empty() {
342 return Err(Error::ZeroLengthTransfer);
343 }
344
345 let timeout = self.timeout();
346
347 let first_length = write[0].len();
348 let last_slice_index = write.len() - 1;
349
350 if let Err(err) = Self::master_write(
351 address,
352 first_length.min(255),
353 Stop::Software,
354 (first_length > 255) || (last_slice_index != 0),
355 timeout,
356 ) {
357 self.master_stop();
358 return Err(err);
359 }
360
361 for (idx, slice) in write.iter().enumerate() {
362 let slice_len = slice.len();
363 let completed_chunks = slice_len / 255;
364 let total_chunks = if completed_chunks * 255 == slice_len {
365 completed_chunks
366 } else {
367 completed_chunks + 1
368 };
369 let last_chunk_idx = total_chunks.saturating_sub(1);
370
371 if idx != 0 {
372 if let Err(err) = Self::master_continue(
373 slice_len.min(255),
374 (idx != last_slice_index) || (slice_len > 255),
375 timeout,
376 ) {
377 self.master_stop();
378 return Err(err);
379 }
380 }
381
382 for (number, chunk) in slice.chunks(255).enumerate() {
383 if number != 0 {
384 if let Err(err) = Self::master_continue(
385 chunk.len(),
386 (number != last_chunk_idx) || (idx != last_slice_index),
387 timeout,
388 ) {
389 self.master_stop();
390 return Err(err);
391 }
392 }
393
394 for byte in chunk {
395 // Wait until we are allowed to send data
396 // (START has been ACKed or last byte when
397 // through)
398 if let Err(err) = self.wait_txe(timeout) {
399 self.master_stop();
400 return Err(err);
401 }
402
403 // Put byte on the wire
404 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
405 T::regs().txdr().write(|w| w.set_txdata(*byte));
406 }
407 }
408 }
409 // Wait until the write finishes
410 let result = self.wait_tc(timeout);
411 self.master_stop();
412 result
413 }
414}
415
416impl<'d, T: Instance> I2c<'d, T, Async> {
305 async fn write_dma_internal( 417 async fn write_dma_internal(
306 &mut self, 418 &mut self,
307 address: u8, 419 address: u8,
@@ -309,10 +421,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
309 first_slice: bool, 421 first_slice: bool,
310 last_slice: bool, 422 last_slice: bool,
311 timeout: Timeout, 423 timeout: Timeout,
312 ) -> Result<(), Error> 424 ) -> Result<(), Error> {
313 where
314 TXDMA: crate::i2c::TxDma<T>,
315 {
316 let total_len = write.len(); 425 let total_len = write.len();
317 426
318 let dma_transfer = unsafe { 427 let dma_transfer = unsafe {
@@ -325,9 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
325 }); 434 });
326 let dst = regs.txdr().as_ptr() as *mut u8; 435 let dst = regs.txdr().as_ptr() as *mut u8;
327 436
328 let ch = &mut self.tx_dma; 437 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
329 let request = ch.request();
330 Transfer::new_write(ch, request, write, dst, Default::default())
331 }; 438 };
332 439
333 let state = T::state(); 440 let state = T::state();
@@ -398,10 +505,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
398 buffer: &mut [u8], 505 buffer: &mut [u8],
399 restart: bool, 506 restart: bool,
400 timeout: Timeout, 507 timeout: Timeout,
401 ) -> Result<(), Error> 508 ) -> Result<(), Error> {
402 where
403 RXDMA: crate::i2c::RxDma<T>,
404 {
405 let total_len = buffer.len(); 509 let total_len = buffer.len();
406 510
407 let dma_transfer = unsafe { 511 let dma_transfer = unsafe {
@@ -412,9 +516,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
412 }); 516 });
413 let src = regs.rxdr().as_ptr() as *mut u8; 517 let src = regs.rxdr().as_ptr() as *mut u8;
414 518
415 let ch = &mut self.rx_dma; 519 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
416 let request = ch.request();
417 Transfer::new_read(ch, request, src, buffer, Default::default())
418 }; 520 };
419 521
420 let state = T::state(); 522 let state = T::state();
@@ -475,10 +577,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
475 // Async public API 577 // Async public API
476 578
477 /// Write. 579 /// Write.
478 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 580 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
479 where
480 TXDMA: crate::i2c::TxDma<T>,
481 {
482 let timeout = self.timeout(); 581 let timeout = self.timeout();
483 if write.is_empty() { 582 if write.is_empty() {
484 self.write_internal(address, write, true, timeout) 583 self.write_internal(address, write, true, timeout)
@@ -492,10 +591,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
492 /// Write multiple buffers. 591 /// Write multiple buffers.
493 /// 592 ///
494 /// The buffers are concatenated in a single write transaction. 593 /// The buffers are concatenated in a single write transaction.
495 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> 594 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
496 where
497 TXDMA: crate::i2c::TxDma<T>,
498 {
499 let timeout = self.timeout(); 595 let timeout = self.timeout();
500 596
501 if write.is_empty() { 597 if write.is_empty() {
@@ -518,10 +614,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
518 } 614 }
519 615
520 /// Read. 616 /// Read.
521 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 617 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
522 where
523 RXDMA: crate::i2c::RxDma<T>,
524 {
525 let timeout = self.timeout(); 618 let timeout = self.timeout();
526 619
527 if buffer.is_empty() { 620 if buffer.is_empty() {
@@ -533,11 +626,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
533 } 626 }
534 627
535 /// Write, restart, read. 628 /// Write, restart, read.
536 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 629 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
537 where
538 TXDMA: super::TxDma<T>,
539 RXDMA: super::RxDma<T>,
540 {
541 let timeout = self.timeout(); 630 let timeout = self.timeout();
542 631
543 if write.is_empty() { 632 if write.is_empty() {
@@ -562,129 +651,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
562 /// Consecutive operations of same type are merged. See [transaction contract] for details. 651 /// Consecutive operations of same type are merged. See [transaction contract] for details.
563 /// 652 ///
564 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 653 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
565 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> 654 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
566 where
567 RXDMA: crate::i2c::RxDma<T>,
568 TXDMA: crate::i2c::TxDma<T>,
569 {
570 let _ = addr;
571 let _ = operations;
572 todo!()
573 }
574
575 // =========================
576 // Blocking public API
577
578 /// Blocking read.
579 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
580 self.read_internal(address, read, false, self.timeout())
581 // Automatic Stop
582 }
583
584 /// Blocking write.
585 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
586 self.write_internal(address, write, true, self.timeout())
587 }
588
589 /// Blocking write, restart, read.
590 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
591 let timeout = self.timeout();
592 self.write_internal(address, write, false, timeout)?;
593 self.read_internal(address, read, true, timeout)
594 // Automatic Stop
595 }
596
597 /// Blocking transaction with operations.
598 ///
599 /// Consecutive operations of same type are merged. See [transaction contract] for details.
600 ///
601 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
602 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
603 let _ = addr; 655 let _ = addr;
604 let _ = operations; 656 let _ = operations;
605 todo!() 657 todo!()
606 } 658 }
607
608 /// Blocking write multiple buffers.
609 ///
610 /// The buffers are concatenated in a single write transaction.
611 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
612 if write.is_empty() {
613 return Err(Error::ZeroLengthTransfer);
614 }
615
616 let timeout = self.timeout();
617
618 let first_length = write[0].len();
619 let last_slice_index = write.len() - 1;
620
621 if let Err(err) = Self::master_write(
622 address,
623 first_length.min(255),
624 Stop::Software,
625 (first_length > 255) || (last_slice_index != 0),
626 timeout,
627 ) {
628 self.master_stop();
629 return Err(err);
630 }
631
632 for (idx, slice) in write.iter().enumerate() {
633 let slice_len = slice.len();
634 let completed_chunks = slice_len / 255;
635 let total_chunks = if completed_chunks * 255 == slice_len {
636 completed_chunks
637 } else {
638 completed_chunks + 1
639 };
640 let last_chunk_idx = total_chunks.saturating_sub(1);
641
642 if idx != 0 {
643 if let Err(err) = Self::master_continue(
644 slice_len.min(255),
645 (idx != last_slice_index) || (slice_len > 255),
646 timeout,
647 ) {
648 self.master_stop();
649 return Err(err);
650 }
651 }
652
653 for (number, chunk) in slice.chunks(255).enumerate() {
654 if number != 0 {
655 if let Err(err) = Self::master_continue(
656 chunk.len(),
657 (number != last_chunk_idx) || (idx != last_slice_index),
658 timeout,
659 ) {
660 self.master_stop();
661 return Err(err);
662 }
663 }
664
665 for byte in chunk {
666 // Wait until we are allowed to send data
667 // (START has been ACKed or last byte when
668 // through)
669 if let Err(err) = self.wait_txe(timeout) {
670 self.master_stop();
671 return Err(err);
672 }
673
674 // Put byte on the wire
675 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
676 T::regs().txdr().write(|w| w.set_txdata(*byte));
677 }
678 }
679 }
680 // Wait until the write finishes
681 let result = self.wait_tc(timeout);
682 self.master_stop();
683 result
684 }
685} 659}
686 660
687impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 661impl<'d, T: Instance, M: Mode> Drop for I2c<'d, T, M> {
688 fn drop(&mut self) { 662 fn drop(&mut self) {
689 T::disable(); 663 T::disable();
690 } 664 }
@@ -814,7 +788,7 @@ impl Timings {
814 } 788 }
815} 789}
816 790
817impl<'d, T: Instance> SetConfig for I2c<'d, T> { 791impl<'d, T: Instance, M: Mode> SetConfig for I2c<'d, T, M> {
818 type Config = Hertz; 792 type Config = Hertz;
819 type ConfigError = (); 793 type ConfigError = ();
820 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 794 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c5a606b21..9b80dc1d0 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -2,6 +2,7 @@
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use crate::gpio::{AFType, AnyPin, SealedPin}; 4use crate::gpio::{AFType, AnyPin, SealedPin};
5use crate::mode::Async;
5use crate::pac::spi::vals; 6use crate::pac::spi::vals;
6use crate::spi::{Config as SpiConfig, *}; 7use crate::spi::{Config as SpiConfig, *};
7use crate::time::Hertz; 8use crate::time::Hertz;
@@ -152,15 +153,15 @@ impl Default for Config {
152} 153}
153 154
154/// I2S driver. 155/// I2S driver.
155pub struct I2S<'d, T: Instance, Tx, Rx> { 156pub struct I2S<'d, T: Instance> {
156 _peri: Spi<'d, T, Tx, Rx>, 157 _peri: Spi<'d, T, Async>,
157 sd: Option<PeripheralRef<'d, AnyPin>>, 158 sd: Option<PeripheralRef<'d, AnyPin>>,
158 ws: Option<PeripheralRef<'d, AnyPin>>, 159 ws: Option<PeripheralRef<'d, AnyPin>>,
159 ck: Option<PeripheralRef<'d, AnyPin>>, 160 ck: Option<PeripheralRef<'d, AnyPin>>,
160 mck: Option<PeripheralRef<'d, AnyPin>>, 161 mck: Option<PeripheralRef<'d, AnyPin>>,
161} 162}
162 163
163impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { 164impl<'d, T: Instance> I2S<'d, T> {
164 /// Note: Full-Duplex modes are not supported at this time 165 /// Note: Full-Duplex modes are not supported at this time
165 pub fn new( 166 pub fn new(
166 peri: impl Peripheral<P = T> + 'd, 167 peri: impl Peripheral<P = T> + 'd,
@@ -168,8 +169,8 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
168 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 169 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
169 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 170 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
170 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 171 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
171 txdma: impl Peripheral<P = Tx> + 'd, 172 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
172 rxdma: impl Peripheral<P = Rx> + 'd, 173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
173 freq: Hertz, 174 freq: Hertz,
174 config: Config, 175 config: Config,
175 ) -> Self { 176 ) -> Self {
@@ -265,24 +266,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
265 } 266 }
266 267
267 /// Write audio data. 268 /// Write audio data.
268 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 269 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
269 where
270 Tx: TxDma<T>,
271 {
272 self._peri.write(data).await 270 self._peri.write(data).await
273 } 271 }
274 272
275 /// Read audio data. 273 /// Read audio data.
276 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 274 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
277 where
278 Tx: TxDma<T>,
279 Rx: RxDma<T>,
280 {
281 self._peri.read(data).await 275 self._peri.read(data).await
282 } 276 }
283} 277}
284 278
285impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { 279impl<'d, T: Instance> Drop for I2S<'d, T> {
286 fn drop(&mut self) { 280 fn drop(&mut self) {
287 self.sd.as_ref().map(|x| x.set_as_disconnected()); 281 self.sd.as_ref().map(|x| x.set_as_disconnected());
288 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 ea17f8477..7d2b49ff4 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -15,8 +15,31 @@ mod fmt;
15include!(concat!(env!("OUT_DIR"), "/_macros.rs")); 15include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
16 16
17// Utilities 17// Utilities
18mod macros;
18pub mod time; 19pub mod time;
19mod traits; 20/// Operating modes for peripherals.
21pub mod mode {
22 trait SealedMode {}
23
24 /// Operating mode for a peripheral.
25 #[allow(private_bounds)]
26 pub trait Mode: SealedMode {}
27
28 macro_rules! impl_mode {
29 ($name:ident) => {
30 impl SealedMode for $name {}
31 impl Mode for $name {}
32 };
33 }
34
35 /// Blocking mode.
36 pub struct Blocking;
37 /// Async mode.
38 pub struct Async;
39
40 impl_mode!(Blocking);
41 impl_mode!(Async);
42}
20 43
21// Always-present hardware 44// Always-present hardware
22pub mod dma; 45pub mod dma;
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/macros.rs
index 13f695821..14137bc37 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/macros.rs
@@ -69,3 +69,29 @@ macro_rules! dma_trait_impl {
69 } 69 }
70 }; 70 };
71} 71}
72
73macro_rules! new_dma {
74 ($name:ident) => {{
75 let dma = $name.into_ref();
76 let request = dma.request();
77 Some(crate::dma::ChannelAndRequest {
78 channel: dma.map_into(),
79 request,
80 })
81 }};
82}
83
84macro_rules! new_pin {
85 ($name:ident, $aftype:expr) => {{
86 new_pin!($name, $aftype, crate::gpio::Speed::Medium, crate::gpio::Pull::None)
87 }};
88 ($name:ident, $aftype:expr, $speed:expr) => {
89 new_pin!($name, $aftype, $speed, crate::gpio::Pull::None)
90 };
91 ($name:ident, $aftype:expr, $speed:expr, $pull:expr) => {{
92 let pin = $name.into_ref();
93 pin.set_as_af_pull(pin.af_num(), $aftype, $pull);
94 pin.set_speed($speed);
95 Some(pin.map_into())
96 }};
97}
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 9079ddd41..d7235ac7f 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -49,6 +49,7 @@ pub struct Config {
49 pub sys: Sysclk, 49 pub sys: Sysclk,
50 pub ahb_pre: AHBPrescaler, 50 pub ahb_pre: AHBPrescaler,
51 pub apb1_pre: APBPrescaler, 51 pub apb1_pre: APBPrescaler,
52 #[cfg(not(stm32u0))]
52 pub apb2_pre: APBPrescaler, 53 pub apb2_pre: APBPrescaler,
53 #[cfg(any(stm32wl5x, stm32wb))] 54 #[cfg(any(stm32wl5x, stm32wb))]
54 pub core2_ahb_pre: AHBPrescaler, 55 pub core2_ahb_pre: AHBPrescaler,
@@ -75,6 +76,7 @@ impl Default for Config {
75 sys: Sysclk::MSI, 76 sys: Sysclk::MSI,
76 ahb_pre: AHBPrescaler::DIV1, 77 ahb_pre: AHBPrescaler::DIV1,
77 apb1_pre: APBPrescaler::DIV1, 78 apb1_pre: APBPrescaler::DIV1,
79 #[cfg(not(stm32u0))]
78 apb2_pre: APBPrescaler::DIV1, 80 apb2_pre: APBPrescaler::DIV1,
79 #[cfg(any(stm32wl5x, stm32wb))] 81 #[cfg(any(stm32wl5x, stm32wb))]
80 core2_ahb_pre: AHBPrescaler::DIV1, 82 core2_ahb_pre: AHBPrescaler::DIV1,
@@ -130,7 +132,7 @@ pub const WPAN_DEFAULT: Config = Config {
130}; 132};
131 133
132fn msi_enable(range: MSIRange) { 134fn msi_enable(range: MSIRange) {
133 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 135 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
134 RCC.cr().modify(|w| { 136 RCC.cr().modify(|w| {
135 #[cfg(not(stm32wb))] 137 #[cfg(not(stm32wb))]
136 w.set_msirgsel(crate::pac::rcc::vals::Msirgsel::CR); 138 w.set_msirgsel(crate::pac::rcc::vals::Msirgsel::CR);
@@ -240,7 +242,7 @@ pub(crate) unsafe fn init(config: Config) {
240 let pll_input = PllInput { 242 let pll_input = PllInput {
241 hse, 243 hse,
242 hsi, 244 hsi,
243 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 245 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
244 msi, 246 msi,
245 }; 247 };
246 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); 248 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
@@ -254,6 +256,10 @@ pub(crate) unsafe fn init(config: Config) {
254 Sysclk::HSI => hsi.unwrap(), 256 Sysclk::HSI => hsi.unwrap(),
255 Sysclk::MSI => msi.unwrap(), 257 Sysclk::MSI => msi.unwrap(),
256 Sysclk::PLL1_R => pll.r.unwrap(), 258 Sysclk::PLL1_R => pll.r.unwrap(),
259 #[cfg(stm32u0)]
260 Sysclk::LSI | Sysclk::LSE => todo!(),
261 #[cfg(stm32u0)]
262 Sysclk::_RESERVED_6 | Sysclk::_RESERVED_7 => unreachable!(),
257 }; 263 };
258 264
259 #[cfg(rcc_l4plus)] 265 #[cfg(rcc_l4plus)]
@@ -263,6 +269,7 @@ pub(crate) unsafe fn init(config: Config) {
263 269
264 let hclk1 = sys_clk / config.ahb_pre; 270 let hclk1 = sys_clk / config.ahb_pre;
265 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); 271 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
272 #[cfg(not(stm32u0))]
266 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); 273 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
267 #[cfg(any(stm32l4, stm32l5, stm32wlex))] 274 #[cfg(any(stm32l4, stm32l5, stm32wlex))]
268 let hclk2 = hclk1; 275 let hclk2 = hclk1;
@@ -315,6 +322,13 @@ pub(crate) unsafe fn init(config: Config) {
315 ..=64_000_000 => 3, 322 ..=64_000_000 => 3,
316 _ => 4, 323 _ => 4,
317 }; 324 };
325 #[cfg(stm32u0)]
326 let latency = match hclk1.0 {
327 // VOS RANGE1, others TODO.
328 ..=24_000_000 => 0,
329 ..=48_000_000 => 1,
330 _ => 2,
331 };
318 332
319 #[cfg(stm32l1)] 333 #[cfg(stm32l1)]
320 FLASH.acr().write(|w| w.set_acc64(true)); 334 FLASH.acr().write(|w| w.set_acc64(true));
@@ -326,7 +340,11 @@ pub(crate) unsafe fn init(config: Config) {
326 RCC.cfgr().modify(|w| { 340 RCC.cfgr().modify(|w| {
327 w.set_sw(config.sys); 341 w.set_sw(config.sys);
328 w.set_hpre(config.ahb_pre); 342 w.set_hpre(config.ahb_pre);
343 #[cfg(stm32u0)]
344 w.set_ppre(config.apb1_pre);
345 #[cfg(not(stm32u0))]
329 w.set_ppre1(config.apb1_pre); 346 w.set_ppre1(config.apb1_pre);
347 #[cfg(not(stm32u0))]
330 w.set_ppre2(config.apb2_pre); 348 w.set_ppre2(config.apb2_pre);
331 }); 349 });
332 while RCC.cfgr().read().sws() != config.sys {} 350 while RCC.cfgr().read().sws() != config.sys {}
@@ -353,8 +371,10 @@ pub(crate) unsafe fn init(config: Config) {
353 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 371 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
354 hclk3: Some(hclk3), 372 hclk3: Some(hclk3),
355 pclk1: Some(pclk1), 373 pclk1: Some(pclk1),
374 #[cfg(not(stm32u0))]
356 pclk2: Some(pclk2), 375 pclk2: Some(pclk2),
357 pclk1_tim: Some(pclk1_tim), 376 pclk1_tim: Some(pclk1_tim),
377 #[cfg(not(stm32u0))]
358 pclk2_tim: Some(pclk2_tim), 378 pclk2_tim: Some(pclk2_tim),
359 #[cfg(stm32wl)] 379 #[cfg(stm32wl)]
360 pclk3: Some(hclk3), 380 pclk3: Some(hclk3),
@@ -408,7 +428,7 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz {
408 Hertz(32_768 * (1 << (range as u8 + 1))) 428 Hertz(32_768 * (1 << (range as u8 + 1)))
409} 429}
410 430
411#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 431#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
412fn msirange_to_hertz(range: MSIRange) -> Hertz { 432fn msirange_to_hertz(range: MSIRange) -> Hertz {
413 match range { 433 match range {
414 MSIRange::RANGE100K => Hertz(100_000), 434 MSIRange::RANGE100K => Hertz(100_000),
@@ -521,7 +541,7 @@ mod pll {
521 } 541 }
522} 542}
523 543
524#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 544#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
525mod pll { 545mod pll {
526 use super::{pll_enable, PllInstance}; 546 use super::{pll_enable, PllInstance};
527 pub use crate::pac::rcc::vals::{ 547 pub use crate::pac::rcc::vals::{
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index d8604e07e..4b22a099d 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -52,7 +52,7 @@ macro_rules! impl_peri {
52 }; 52 };
53} 53}
54 54
55#[cfg(any(rcc_c0, rcc_g0))] 55#[cfg(any(rcc_c0, rcc_g0, rcc_u0))]
56#[allow(unused_imports)] 56#[allow(unused_imports)]
57use self::{McoSource as Mco1Source, McoSource as Mco2Source}; 57use self::{McoSource as Mco1Source, McoSource as Mco2Source};
58 58
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c328344aa..a4e497fe7 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -25,7 +25,7 @@ pub use hsi48::*;
25#[cfg_attr(stm32g0, path = "g0.rs")] 25#[cfg_attr(stm32g0, path = "g0.rs")]
26#[cfg_attr(stm32g4, path = "g4.rs")] 26#[cfg_attr(stm32g4, path = "g4.rs")]
27#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] 27#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")]
28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] 28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
29#[cfg_attr(stm32u5, path = "u5.rs")] 29#[cfg_attr(stm32u5, path = "u5.rs")]
30#[cfg_attr(stm32wba, path = "wba.rs")] 30#[cfg_attr(stm32wba, path = "wba.rs")]
31mod _version; 31mod _version;
@@ -119,3 +119,21 @@ mod util {
119pub fn frequency<T: RccPeripheral>() -> Hertz { 119pub fn frequency<T: RccPeripheral>() -> Hertz {
120 T::frequency() 120 T::frequency()
121} 121}
122
123/// Enables and resets peripheral `T`.
124///
125/// # Safety
126///
127/// Peripheral must not be in use.
128pub unsafe fn enable_and_reset<T: RccPeripheral>() {
129 T::enable_and_reset();
130}
131
132/// Disables peripheral `T`.
133///
134/// # Safety
135///
136/// Peripheral must not be in use.
137pub unsafe fn disable<T: RccPeripheral>() {
138 T::disable();
139}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 0b38c4288..c39ef1913 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,6 +1,7 @@
1//! Serial Peripheral Interface (SPI) 1//! Serial Peripheral Interface (SPI)
2#![macro_use] 2#![macro_use]
3 3
4use core::marker::PhantomData;
4use core::ptr; 5use core::ptr;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -8,8 +9,9 @@ use embassy_futures::join::join;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::{into_ref, PeripheralRef};
9pub 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};
10 11
11use crate::dma::{slice_ptr_parts, word, Transfer}; 12use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
12use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; 13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode};
13use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{regs, vals, Spi as Regs};
14use crate::rcc::RccPeripheral; 16use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 17use crate::time::Hertz;
@@ -81,163 +83,37 @@ impl Config {
81 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 83 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
82 } 84 }
83 } 85 }
84}
85 86
87 fn sck_pull_mode(&self) -> Pull {
88 match self.mode.polarity {
89 Polarity::IdleLow => Pull::Down,
90 Polarity::IdleHigh => Pull::Up,
91 }
92 }
93}
86/// SPI driver. 94/// SPI driver.
87pub struct Spi<'d, T: Instance, Tx, Rx> { 95pub struct Spi<'d, T: Instance, M: PeriMode> {
88 _peri: PeripheralRef<'d, T>, 96 _peri: PeripheralRef<'d, T>,
89 sck: Option<PeripheralRef<'d, AnyPin>>, 97 sck: Option<PeripheralRef<'d, AnyPin>>,
90 mosi: Option<PeripheralRef<'d, AnyPin>>, 98 mosi: Option<PeripheralRef<'d, AnyPin>>,
91 miso: Option<PeripheralRef<'d, AnyPin>>, 99 miso: Option<PeripheralRef<'d, AnyPin>>,
92 txdma: PeripheralRef<'d, Tx>, 100 tx_dma: Option<ChannelAndRequest<'d>>,
93 rxdma: PeripheralRef<'d, Rx>, 101 rx_dma: Option<ChannelAndRequest<'d>>,
102 _phantom: PhantomData<M>,
94 current_word_size: word_impl::Config, 103 current_word_size: word_impl::Config,
95} 104}
96 105
97impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 106impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
98 /// Create a new SPI driver.
99 pub fn new(
100 peri: impl Peripheral<P = T> + 'd,
101 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
102 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
103 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
104 txdma: impl Peripheral<P = Tx> + 'd,
105 rxdma: impl Peripheral<P = Rx> + 'd,
106 config: Config,
107 ) -> Self {
108 into_ref!(peri, sck, mosi, miso);
109
110 let sck_pull_mode = match config.mode.polarity {
111 Polarity::IdleLow => Pull::Down,
112 Polarity::IdleHigh => Pull::Up,
113 };
114
115 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
116 sck.set_speed(crate::gpio::Speed::VeryHigh);
117 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
118 mosi.set_speed(crate::gpio::Speed::VeryHigh);
119 miso.set_as_af(miso.af_num(), AFType::Input);
120 miso.set_speed(crate::gpio::Speed::VeryHigh);
121
122 Self::new_inner(
123 peri,
124 Some(sck.map_into()),
125 Some(mosi.map_into()),
126 Some(miso.map_into()),
127 txdma,
128 rxdma,
129 config,
130 )
131 }
132
133 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
134 pub fn new_rxonly(
135 peri: impl Peripheral<P = T> + 'd,
136 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
137 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
138 txdma: impl Peripheral<P = Tx> + 'd, // TODO remove
139 rxdma: impl Peripheral<P = Rx> + 'd,
140 config: Config,
141 ) -> Self {
142 into_ref!(sck, miso);
143 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
144 sck.set_speed(crate::gpio::Speed::VeryHigh);
145 miso.set_as_af(miso.af_num(), AFType::Input);
146 miso.set_speed(crate::gpio::Speed::VeryHigh);
147
148 Self::new_inner(
149 peri,
150 Some(sck.map_into()),
151 None,
152 Some(miso.map_into()),
153 txdma,
154 rxdma,
155 config,
156 )
157 }
158
159 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
160 pub fn new_txonly(
161 peri: impl Peripheral<P = T> + 'd,
162 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
163 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
164 txdma: impl Peripheral<P = Tx> + 'd,
165 rxdma: impl Peripheral<P = Rx> + 'd, // TODO remove
166 config: Config,
167 ) -> Self {
168 into_ref!(sck, mosi);
169 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
170 sck.set_speed(crate::gpio::Speed::VeryHigh);
171 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
172 mosi.set_speed(crate::gpio::Speed::VeryHigh);
173
174 Self::new_inner(
175 peri,
176 Some(sck.map_into()),
177 Some(mosi.map_into()),
178 None,
179 txdma,
180 rxdma,
181 config,
182 )
183 }
184
185 /// Create a new SPI driver, in TX-only mode, without SCK pin.
186 ///
187 /// This can be useful for bit-banging non-SPI protocols.
188 pub fn new_txonly_nosck(
189 peri: impl Peripheral<P = T> + 'd,
190 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
191 txdma: impl Peripheral<P = Tx> + 'd,
192 rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
193 config: Config,
194 ) -> Self {
195 into_ref!(mosi);
196 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
197 mosi.set_speed(crate::gpio::Speed::Medium);
198
199 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, config)
200 }
201
202 #[cfg(stm32wl)]
203 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
204 pub fn new_subghz(
205 peri: impl Peripheral<P = T> + 'd,
206 txdma: impl Peripheral<P = Tx> + 'd,
207 rxdma: impl Peripheral<P = Rx> + 'd,
208 ) -> Self {
209 // see RM0453 rev 1 section 7.2.13 page 291
210 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
211 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
212 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
213 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
214 let mut config = Config::default();
215 config.mode = MODE_0;
216 config.bit_order = BitOrder::MsbFirst;
217 config.frequency = freq;
218 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
219 }
220
221 #[allow(dead_code)]
222 pub(crate) fn new_internal(
223 peri: impl Peripheral<P = T> + 'd,
224 txdma: impl Peripheral<P = Tx> + 'd,
225 rxdma: impl Peripheral<P = Rx> + 'd,
226 config: Config,
227 ) -> Self {
228 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
229 }
230
231 fn new_inner( 107 fn new_inner(
232 peri: impl Peripheral<P = T> + 'd, 108 peri: impl Peripheral<P = T> + 'd,
233 sck: Option<PeripheralRef<'d, AnyPin>>, 109 sck: Option<PeripheralRef<'d, AnyPin>>,
234 mosi: Option<PeripheralRef<'d, AnyPin>>, 110 mosi: Option<PeripheralRef<'d, AnyPin>>,
235 miso: Option<PeripheralRef<'d, AnyPin>>, 111 miso: Option<PeripheralRef<'d, AnyPin>>,
236 txdma: impl Peripheral<P = Tx> + 'd, 112 tx_dma: Option<ChannelAndRequest<'d>>,
237 rxdma: impl Peripheral<P = Rx> + 'd, 113 rx_dma: Option<ChannelAndRequest<'d>>,
238 config: Config, 114 config: Config,
239 ) -> Self { 115 ) -> Self {
240 into_ref!(peri, txdma, rxdma); 116 into_ref!(peri);
241 117
242 let pclk = T::frequency(); 118 let pclk = T::frequency();
243 let freq = config.frequency; 119 let freq = config.frequency;
@@ -333,9 +209,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
333 sck, 209 sck,
334 mosi, 210 mosi,
335 miso, 211 miso,
336 txdma, 212 tx_dma,
337 rxdma, 213 rx_dma,
338 current_word_size: <u8 as SealedWord>::CONFIG, 214 current_word_size: <u8 as SealedWord>::CONFIG,
215 _phantom: PhantomData,
339 } 216 }
340 } 217 }
341 218
@@ -462,11 +339,251 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
462 self.current_word_size = word_size; 339 self.current_word_size = word_size;
463 } 340 }
464 341
342 /// Blocking write.
343 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
344 T::REGS.cr1().modify(|w| w.set_spe(true));
345 flush_rx_fifo(T::REGS);
346 self.set_word_size(W::CONFIG);
347 for word in words.iter() {
348 let _ = transfer_word(T::REGS, *word)?;
349 }
350 Ok(())
351 }
352
353 /// Blocking read.
354 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
355 T::REGS.cr1().modify(|w| w.set_spe(true));
356 flush_rx_fifo(T::REGS);
357 self.set_word_size(W::CONFIG);
358 for word in words.iter_mut() {
359 *word = transfer_word(T::REGS, W::default())?;
360 }
361 Ok(())
362 }
363
364 /// Blocking in-place bidirectional transfer.
365 ///
366 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
367 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
368 T::REGS.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(T::REGS);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter_mut() {
372 *word = transfer_word(T::REGS, *word)?;
373 }
374 Ok(())
375 }
376
377 /// Blocking bidirectional transfer.
378 ///
379 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
380 ///
381 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
382 /// If `write` is shorter it is padded with zero bytes.
383 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
384 T::REGS.cr1().modify(|w| w.set_spe(true));
385 flush_rx_fifo(T::REGS);
386 self.set_word_size(W::CONFIG);
387 let len = read.len().max(write.len());
388 for i in 0..len {
389 let wb = write.get(i).copied().unwrap_or_default();
390 let rb = transfer_word(T::REGS, wb)?;
391 if let Some(r) = read.get_mut(i) {
392 *r = rb;
393 }
394 }
395 Ok(())
396 }
397}
398
399impl<'d, T: Instance> Spi<'d, T, Blocking> {
400 /// Create a new blocking SPI driver.
401 pub fn new_blocking(
402 peri: impl Peripheral<P = T> + 'd,
403 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
404 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
405 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
406 config: Config,
407 ) -> Self {
408 Self::new_inner(
409 peri,
410 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
411 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
412 new_pin!(miso, AFType::Input, Speed::VeryHigh),
413 None,
414 None,
415 config,
416 )
417 }
418
419 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
420 pub fn new_blocking_rxonly(
421 peri: impl Peripheral<P = T> + 'd,
422 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
423 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
424 config: Config,
425 ) -> Self {
426 Self::new_inner(
427 peri,
428 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
429 None,
430 new_pin!(miso, AFType::Input, Speed::VeryHigh),
431 None,
432 None,
433 config,
434 )
435 }
436
437 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
438 pub fn new_blocking_txonly(
439 peri: impl Peripheral<P = T> + 'd,
440 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
441 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
442 config: Config,
443 ) -> Self {
444 Self::new_inner(
445 peri,
446 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
447 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
448 None,
449 None,
450 None,
451 config,
452 )
453 }
454
455 /// Create a new SPI driver, in TX-only mode, without SCK pin.
456 ///
457 /// This can be useful for bit-banging non-SPI protocols.
458 pub fn new_blocking_txonly_nosck(
459 peri: impl Peripheral<P = T> + 'd,
460 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
461 config: Config,
462 ) -> Self {
463 Self::new_inner(
464 peri,
465 None,
466 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
467 None,
468 None,
469 None,
470 config,
471 )
472 }
473}
474
475impl<'d, T: Instance> Spi<'d, T, Async> {
476 /// Create a new SPI driver.
477 pub fn new(
478 peri: impl Peripheral<P = T> + 'd,
479 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
480 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
481 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
482 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
483 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
484 config: Config,
485 ) -> Self {
486 Self::new_inner(
487 peri,
488 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
489 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
490 new_pin!(miso, AFType::Input, Speed::VeryHigh),
491 new_dma!(tx_dma),
492 new_dma!(rx_dma),
493 config,
494 )
495 }
496
497 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
498 pub fn new_rxonly(
499 peri: impl Peripheral<P = T> + 'd,
500 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
501 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
502 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
503 config: Config,
504 ) -> Self {
505 Self::new_inner(
506 peri,
507 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
508 None,
509 new_pin!(miso, AFType::Input, Speed::VeryHigh),
510 None,
511 new_dma!(rx_dma),
512 config,
513 )
514 }
515
516 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
517 pub fn new_txonly(
518 peri: impl Peripheral<P = T> + 'd,
519 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
520 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
521 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
522 config: Config,
523 ) -> Self {
524 Self::new_inner(
525 peri,
526 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
527 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
528 None,
529 new_dma!(tx_dma),
530 None,
531 config,
532 )
533 }
534
535 /// Create a new SPI driver, in TX-only mode, without SCK pin.
536 ///
537 /// This can be useful for bit-banging non-SPI protocols.
538 pub fn new_txonly_nosck(
539 peri: impl Peripheral<P = T> + 'd,
540 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
541 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
542 config: Config,
543 ) -> Self {
544 Self::new_inner(
545 peri,
546 None,
547 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
548 None,
549 new_dma!(tx_dma),
550 None,
551 config,
552 )
553 }
554
555 #[cfg(stm32wl)]
556 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
557 pub fn new_subghz(
558 peri: impl Peripheral<P = T> + 'd,
559 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
560 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
561 ) -> Self {
562 // see RM0453 rev 1 section 7.2.13 page 291
563 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
564 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
565 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
566 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
567 let mut config = Config::default();
568 config.mode = MODE_0;
569 config.bit_order = BitOrder::MsbFirst;
570 config.frequency = freq;
571
572 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
573 }
574
575 #[allow(dead_code)]
576 pub(crate) fn new_internal(
577 peri: impl Peripheral<P = T> + 'd,
578 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
579 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
580 config: Config,
581 ) -> Self {
582 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
583 }
584
465 /// SPI write, using DMA. 585 /// SPI write, using DMA.
466 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 586 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
467 where
468 Tx: TxDma<T>,
469 {
470 if data.is_empty() { 587 if data.is_empty() {
471 return Ok(()); 588 return Ok(());
472 } 589 }
@@ -476,9 +593,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
476 w.set_spe(false); 593 w.set_spe(false);
477 }); 594 });
478 595
479 let tx_request = self.txdma.request();
480 let tx_dst = T::REGS.tx_ptr(); 596 let tx_dst = T::REGS.tx_ptr();
481 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; 597 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
482 598
483 set_txdmaen(T::REGS, true); 599 set_txdmaen(T::REGS, true);
484 T::REGS.cr1().modify(|w| { 600 T::REGS.cr1().modify(|w| {
@@ -497,11 +613,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
497 } 613 }
498 614
499 /// SPI read, using DMA. 615 /// SPI read, using DMA.
500 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 616 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
501 where
502 Tx: TxDma<T>,
503 Rx: RxDma<T>,
504 {
505 if data.is_empty() { 617 if data.is_empty() {
506 return Ok(()); 618 return Ok(());
507 } 619 }
@@ -519,22 +631,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
519 631
520 let clock_byte_count = data.len(); 632 let clock_byte_count = data.len();
521 633
522 let rx_request = self.rxdma.request();
523 let rx_src = T::REGS.rx_ptr(); 634 let rx_src = T::REGS.rx_ptr();
524 let rx_f = unsafe { Transfer::new_read(&mut self.rxdma, rx_request, rx_src, data, Default::default()) }; 635 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
525 636
526 let tx_request = self.txdma.request();
527 let tx_dst = T::REGS.tx_ptr(); 637 let tx_dst = T::REGS.tx_ptr();
528 let clock_byte = 0x00u8; 638 let clock_byte = 0x00u8;
529 let tx_f = unsafe { 639 let tx_f = unsafe {
530 Transfer::new_write_repeated( 640 self.tx_dma
531 &mut self.txdma, 641 .as_mut()
532 tx_request, 642 .unwrap()
533 &clock_byte, 643 .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
534 clock_byte_count,
535 tx_dst,
536 Default::default(),
537 )
538 }; 644 };
539 645
540 set_txdmaen(T::REGS, true); 646 set_txdmaen(T::REGS, true);
@@ -553,11 +659,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
553 Ok(()) 659 Ok(())
554 } 660 }
555 661
556 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> 662 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
557 where
558 Tx: TxDma<T>,
559 Rx: RxDma<T>,
560 {
561 let (_, rx_len) = slice_ptr_parts(read); 663 let (_, rx_len) = slice_ptr_parts(read);
562 let (_, tx_len) = slice_ptr_parts(write); 664 let (_, tx_len) = slice_ptr_parts(write);
563 assert_eq!(rx_len, tx_len); 665 assert_eq!(rx_len, tx_len);
@@ -576,13 +678,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
576 678
577 set_rxdmaen(T::REGS, true); 679 set_rxdmaen(T::REGS, true);
578 680
579 let rx_request = self.rxdma.request();
580 let rx_src = T::REGS.rx_ptr(); 681 let rx_src = T::REGS.rx_ptr();
581 let rx_f = unsafe { Transfer::new_read_raw(&mut self.rxdma, rx_request, rx_src, read, Default::default()) }; 682 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
582 683
583 let tx_request = self.txdma.request();
584 let tx_dst = T::REGS.tx_ptr(); 684 let tx_dst = T::REGS.tx_ptr();
585 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; 685 let tx_f = unsafe {
686 self.tx_dma
687 .as_mut()
688 .unwrap()
689 .write_raw(write, tx_dst, Default::default())
690 };
586 691
587 set_txdmaen(T::REGS, true); 692 set_txdmaen(T::REGS, true);
588 T::REGS.cr1().modify(|w| { 693 T::REGS.cr1().modify(|w| {
@@ -606,83 +711,19 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
606 /// 711 ///
607 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 712 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
608 /// If `write` is shorter it is padded with zero bytes. 713 /// If `write` is shorter it is padded with zero bytes.
609 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 714 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
610 where
611 Tx: TxDma<T>,
612 Rx: RxDma<T>,
613 {
614 self.transfer_inner(read, write).await 715 self.transfer_inner(read, write).await
615 } 716 }
616 717
617 /// In-place bidirectional transfer, using DMA. 718 /// In-place bidirectional transfer, using DMA.
618 /// 719 ///
619 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 720 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
620 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 721 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
621 where
622 Tx: TxDma<T>,
623 Rx: RxDma<T>,
624 {
625 self.transfer_inner(data, data).await 722 self.transfer_inner(data, data).await
626 } 723 }
627
628 /// Blocking write.
629 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
630 T::REGS.cr1().modify(|w| w.set_spe(true));
631 flush_rx_fifo(T::REGS);
632 self.set_word_size(W::CONFIG);
633 for word in words.iter() {
634 let _ = transfer_word(T::REGS, *word)?;
635 }
636 Ok(())
637 }
638
639 /// Blocking read.
640 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
641 T::REGS.cr1().modify(|w| w.set_spe(true));
642 flush_rx_fifo(T::REGS);
643 self.set_word_size(W::CONFIG);
644 for word in words.iter_mut() {
645 *word = transfer_word(T::REGS, W::default())?;
646 }
647 Ok(())
648 }
649
650 /// Blocking in-place bidirectional transfer.
651 ///
652 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
653 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
654 T::REGS.cr1().modify(|w| w.set_spe(true));
655 flush_rx_fifo(T::REGS);
656 self.set_word_size(W::CONFIG);
657 for word in words.iter_mut() {
658 *word = transfer_word(T::REGS, *word)?;
659 }
660 Ok(())
661 }
662
663 /// Blocking bidirectional transfer.
664 ///
665 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
666 ///
667 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
668 /// If `write` is shorter it is padded with zero bytes.
669 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
670 T::REGS.cr1().modify(|w| w.set_spe(true));
671 flush_rx_fifo(T::REGS);
672 self.set_word_size(W::CONFIG);
673 let len = read.len().max(write.len());
674 for i in 0..len {
675 let wb = write.get(i).copied().unwrap_or_default();
676 let rb = transfer_word(T::REGS, wb)?;
677 if let Some(r) = read.get_mut(i) {
678 *r = rb;
679 }
680 }
681 Ok(())
682 }
683} 724}
684 725
685impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 726impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> {
686 fn drop(&mut self) { 727 fn drop(&mut self) {
687 self.sck.as_ref().map(|x| x.set_as_disconnected()); 728 self.sck.as_ref().map(|x| x.set_as_disconnected());
688 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 729 self.mosi.as_ref().map(|x| x.set_as_disconnected());
@@ -735,18 +776,22 @@ trait RegsExt {
735 776
736impl RegsExt for Regs { 777impl RegsExt for Regs {
737 fn tx_ptr<W>(&self) -> *mut W { 778 fn tx_ptr<W>(&self) -> *mut W {
738 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 779 #[cfg(any(spi_v1, spi_f1))]
739 let dr = self.dr(); 780 let dr = self.dr();
781 #[cfg(spi_v2)]
782 let dr = self.dr16();
740 #[cfg(any(spi_v3, spi_v4, spi_v5))] 783 #[cfg(any(spi_v3, spi_v4, spi_v5))]
741 let dr = self.txdr(); 784 let dr = self.txdr32();
742 dr.as_ptr() as *mut W 785 dr.as_ptr() as *mut W
743 } 786 }
744 787
745 fn rx_ptr<W>(&self) -> *mut W { 788 fn rx_ptr<W>(&self) -> *mut W {
746 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 789 #[cfg(any(spi_v1, spi_f1))]
747 let dr = self.dr(); 790 let dr = self.dr();
791 #[cfg(spi_v2)]
792 let dr = self.dr16();
748 #[cfg(any(spi_v3, spi_v4, spi_v5))] 793 #[cfg(any(spi_v3, spi_v4, spi_v5))]
749 let dr = self.rxdr(); 794 let dr = self.rxdr32();
750 dr.as_ptr() as *mut W 795 dr.as_ptr() as *mut W
751 } 796 }
752} 797}
@@ -815,11 +860,14 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
815fn flush_rx_fifo(regs: Regs) { 860fn flush_rx_fifo(regs: Regs) {
816 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 861 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
817 while regs.sr().read().rxne() { 862 while regs.sr().read().rxne() {
863 #[cfg(not(spi_v2))]
818 let _ = regs.dr().read(); 864 let _ = regs.dr().read();
865 #[cfg(spi_v2)]
866 let _ = regs.dr16().read();
819 } 867 }
820 #[cfg(any(spi_v3, spi_v4, spi_v5))] 868 #[cfg(any(spi_v3, spi_v4, spi_v5))]
821 while regs.sr().read().rxp() { 869 while regs.sr().read().rxp() {
822 let _ = regs.rxdr().read(); 870 let _ = regs.rxdr32().read();
823 } 871 }
824} 872}
825 873
@@ -893,7 +941,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
893// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 941// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
894macro_rules! impl_blocking { 942macro_rules! impl_blocking {
895 ($w:ident) => { 943 ($w:ident) => {
896 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> { 944 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> {
897 type Error = Error; 945 type Error = Error;
898 946
899 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 947 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -901,7 +949,7 @@ macro_rules! impl_blocking {
901 } 949 }
902 } 950 }
903 951
904 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> { 952 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> {
905 type Error = Error; 953 type Error = Error;
906 954
907 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 955 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -915,11 +963,11 @@ macro_rules! impl_blocking {
915impl_blocking!(u8); 963impl_blocking!(u8);
916impl_blocking!(u16); 964impl_blocking!(u16);
917 965
918impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> { 966impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
919 type Error = Error; 967 type Error = Error;
920} 968}
921 969
922impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 970impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, M> {
923 fn flush(&mut self) -> Result<(), Self::Error> { 971 fn flush(&mut self) -> Result<(), Self::Error> {
924 Ok(()) 972 Ok(())
925 } 973 }
@@ -952,7 +1000,7 @@ impl embedded_hal_1::spi::Error for Error {
952 } 1000 }
953} 1001}
954 1002
955impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 1003impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Async> {
956 async fn flush(&mut self) -> Result<(), Self::Error> { 1004 async fn flush(&mut self) -> Result<(), Self::Error> {
957 Ok(()) 1005 Ok(())
958 } 1006 }
@@ -1087,7 +1135,7 @@ foreach_peripheral!(
1087 }; 1135 };
1088); 1136);
1089 1137
1090impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { 1138impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> {
1091 type Config = Config; 1139 type Config = Config;
1092 type ConfigError = (); 1140 type ConfigError = ();
1093 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1141 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 7c0523a25..d21e5c47c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -13,9 +13,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures::future::{select, Either}; 14use futures::future::{select, Either};
15 15
16use crate::dma::{NoDma, Transfer}; 16use crate::dma::ChannelAndRequest;
17use crate::gpio::AFType; 17use crate::gpio::{AFType, AnyPin, SealedPin};
18use crate::interrupt::typelevel::Interrupt; 18use crate::interrupt::typelevel::Interrupt;
19use crate::mode::{Async, Blocking, Mode};
19#[allow(unused_imports)] 20#[allow(unused_imports)]
20#[cfg(not(any(usart_v1, usart_v2)))] 21#[cfg(not(any(usart_v1, usart_v2)))]
21use crate::pac::usart::regs::Isr as Sr; 22use crate::pac::usart::regs::Isr as Sr;
@@ -162,6 +163,26 @@ pub struct Config {
162 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle). 163 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
163 #[cfg(any(usart_v3, usart_v4))] 164 #[cfg(any(usart_v3, usart_v4))]
164 pub invert_rx: bool, 165 pub invert_rx: bool,
166
167 // private: set by new_half_duplex, not by the user.
168 half_duplex: bool,
169}
170
171impl Config {
172 fn tx_af(&self) -> AFType {
173 #[cfg(any(usart_v3, usart_v4))]
174 if self.swap_rx_tx {
175 return AFType::Input;
176 };
177 AFType::OutputPushPull
178 }
179 fn rx_af(&self) -> AFType {
180 #[cfg(any(usart_v3, usart_v4))]
181 if self.swap_rx_tx {
182 return AFType::OutputPushPull;
183 };
184 AFType::Input
185 }
165} 186}
166 187
167impl Default for Config { 188impl Default for Config {
@@ -181,6 +202,7 @@ impl Default for Config {
181 invert_tx: false, 202 invert_tx: false,
182 #[cfg(any(usart_v3, usart_v4))] 203 #[cfg(any(usart_v3, usart_v4))]
183 invert_rx: false, 204 invert_rx: false,
205 half_duplex: false,
184 } 206 }
185 } 207 }
186} 208}
@@ -217,12 +239,12 @@ enum ReadCompletionEvent {
217/// 239///
218/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] 240/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
219/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. 241/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
220pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 242pub struct Uart<'d, T: BasicInstance, M: Mode> {
221 tx: UartTx<'d, T, TxDma>, 243 tx: UartTx<'d, T, M>,
222 rx: UartRx<'d, T, RxDma>, 244 rx: UartRx<'d, T, M>,
223} 245}
224 246
225impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { 247impl<'d, T: BasicInstance, M: Mode> SetConfig for Uart<'d, T, M> {
226 type Config = Config; 248 type Config = Config;
227 type ConfigError = ConfigError; 249 type ConfigError = ConfigError;
228 250
@@ -236,12 +258,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma>
236/// 258///
237/// Can be obtained from [`Uart::split`], or can be constructed independently, 259/// Can be obtained from [`Uart::split`], or can be constructed independently,
238/// if you do not need the receiving half of the driver. 260/// if you do not need the receiving half of the driver.
239pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 261pub struct UartTx<'d, T: BasicInstance, M: Mode> {
240 phantom: PhantomData<&'d mut T>, 262 _phantom: PhantomData<(T, M)>,
241 tx_dma: PeripheralRef<'d, TxDma>, 263 tx: Option<PeripheralRef<'d, AnyPin>>,
264 cts: Option<PeripheralRef<'d, AnyPin>>,
265 de: Option<PeripheralRef<'d, AnyPin>>,
266 tx_dma: Option<ChannelAndRequest<'d>>,
242} 267}
243 268
244impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { 269impl<'d, T: BasicInstance, M: Mode> SetConfig for UartTx<'d, T, M> {
245 type Config = Config; 270 type Config = Config;
246 type ConfigError = ConfigError; 271 type ConfigError = ConfigError;
247 272
@@ -279,15 +304,17 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
279/// store data received between calls. 304/// store data received between calls.
280/// 305///
281/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043). 306/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043).
282pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 307pub struct UartRx<'d, T: BasicInstance, M: Mode> {
283 _peri: PeripheralRef<'d, T>, 308 _phantom: PhantomData<(T, M)>,
284 rx_dma: PeripheralRef<'d, RxDma>, 309 rx: Option<PeripheralRef<'d, AnyPin>>,
310 rts: Option<PeripheralRef<'d, AnyPin>>,
311 rx_dma: Option<ChannelAndRequest<'d>>,
285 detect_previous_overrun: bool, 312 detect_previous_overrun: bool,
286 #[cfg(any(usart_v1, usart_v2))] 313 #[cfg(any(usart_v1, usart_v2))]
287 buffered_sr: stm32_metapac::usart::regs::Sr, 314 buffered_sr: stm32_metapac::usart::regs::Sr,
288} 315}
289 316
290impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { 317impl<'d, T: BasicInstance, M: Mode> SetConfig for UartRx<'d, T, M> {
291 type Config = Config; 318 type Config = Config;
292 type ConfigError = ConfigError; 319 type ConfigError = ConfigError;
293 320
@@ -296,17 +323,21 @@ impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> {
296 } 323 }
297} 324}
298 325
299impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { 326impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
300 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 327 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
301 pub fn new( 328 pub fn new(
302 peri: impl Peripheral<P = T> + 'd, 329 peri: impl Peripheral<P = T> + 'd,
303 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 330 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
304 tx_dma: impl Peripheral<P = TxDma> + 'd, 331 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
305 config: Config, 332 config: Config,
306 ) -> Result<Self, ConfigError> { 333 ) -> Result<Self, ConfigError> {
307 T::enable_and_reset(); 334 Self::new_inner(
308 335 peri,
309 Self::new_inner(peri, tx, tx_dma, config) 336 new_pin!(tx, AFType::OutputPushPull),
337 None,
338 new_dma!(tx_dma),
339 config,
340 )
310 } 341 }
311 342
312 /// Create a new tx-only UART with a clear-to-send pin 343 /// Create a new tx-only UART with a clear-to-send pin
@@ -314,40 +345,86 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
314 peri: impl Peripheral<P = T> + 'd, 345 peri: impl Peripheral<P = T> + 'd,
315 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 346 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
316 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 347 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
317 tx_dma: impl Peripheral<P = TxDma> + 'd, 348 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
318 config: Config, 349 config: Config,
319 ) -> Result<Self, ConfigError> { 350 ) -> Result<Self, ConfigError> {
320 into_ref!(cts); 351 Self::new_inner(
321 352 peri,
322 T::enable_and_reset(); 353 new_pin!(tx, AFType::OutputPushPull),
354 new_pin!(cts, AFType::Input),
355 new_dma!(tx_dma),
356 config,
357 )
358 }
323 359
324 cts.set_as_af(cts.af_num(), AFType::Input); 360 /// Initiate an asynchronous UART write
325 T::regs().cr3().write(|w| { 361 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
326 w.set_ctse(true); 362 let ch = self.tx_dma.as_mut().unwrap();
363 T::regs().cr3().modify(|reg| {
364 reg.set_dmat(true);
327 }); 365 });
328 Self::new_inner(peri, tx, tx_dma, config) 366 // 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.
368 let transfer = unsafe { ch.write(buffer, tdr(T::regs()), Default::default()) };
369 transfer.await;
370 Ok(())
329 } 371 }
372}
330 373
331 fn new_inner( 374impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
332 _peri: impl Peripheral<P = T> + 'd, 375 /// Create a new blocking tx-only UART with no hardware flow control.
376 ///
377 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
378 pub fn new_blocking(
379 peri: impl Peripheral<P = T> + 'd,
333 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 380 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
334 tx_dma: impl Peripheral<P = TxDma> + 'd,
335 config: Config, 381 config: Config,
336 ) -> Result<Self, ConfigError> { 382 ) -> Result<Self, ConfigError> {
337 into_ref!(_peri, tx, tx_dma); 383 Self::new_inner(peri, new_pin!(tx, AFType::OutputPushPull), None, None, config)
384 }
338 385
339 let r = T::regs(); 386 /// Create a new blocking tx-only UART with a clear-to-send pin
387 pub fn new_blocking_with_cts(
388 peri: impl Peripheral<P = T> + 'd,
389 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
390 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
391 config: Config,
392 ) -> Result<Self, ConfigError> {
393 Self::new_inner(
394 peri,
395 new_pin!(tx, AFType::OutputPushPull),
396 new_pin!(cts, AFType::Input),
397 None,
398 config,
399 )
400 }
401}
340 402
341 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 403impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
404 fn new_inner(
405 _peri: impl Peripheral<P = T> + 'd,
406 tx: Option<PeripheralRef<'d, AnyPin>>,
407 cts: Option<PeripheralRef<'d, AnyPin>>,
408 tx_dma: Option<ChannelAndRequest<'d>>,
409 config: Config,
410 ) -> Result<Self, ConfigError> {
411 T::enable_and_reset();
342 412
413 let r = T::regs();
414 r.cr3().modify(|w| {
415 w.set_ctse(cts.is_some());
416 });
343 configure(r, &config, T::frequency(), T::KIND, false, true)?; 417 configure(r, &config, T::frequency(), T::KIND, false, true)?;
344 418
345 // create state once! 419 // create state once!
346 let _s = T::state(); 420 let _s = T::state();
347 421
348 Ok(Self { 422 Ok(Self {
423 tx,
424 cts,
425 de: None,
349 tx_dma, 426 tx_dma,
350 phantom: PhantomData, 427 _phantom: PhantomData,
351 }) 428 })
352 } 429 }
353 430
@@ -356,23 +433,6 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
356 reconfigure::<T>(config) 433 reconfigure::<T>(config)
357 } 434 }
358 435
359 /// Initiate an asynchronous UART write
360 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
361 where
362 TxDma: crate::usart::TxDma<T>,
363 {
364 let ch = &mut self.tx_dma;
365 let request = ch.request();
366 T::regs().cr3().modify(|reg| {
367 reg.set_dmat(true);
368 });
369 // If we don't assign future to a variable, the data register pointer
370 // is held across an await and makes the future non-Send.
371 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
372 transfer.await;
373 Ok(())
374 }
375
376 /// Perform a blocking UART write 436 /// Perform a blocking UART write
377 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 437 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
378 let r = T::regs(); 438 let r = T::regs();
@@ -391,18 +451,18 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
391 } 451 }
392} 452}
393 453
394impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { 454impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
455 /// Create a new rx-only UART with no hardware flow control.
456 ///
395 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 457 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
396 pub fn new( 458 pub fn new(
397 peri: impl Peripheral<P = T> + 'd, 459 peri: impl Peripheral<P = T> + 'd,
398 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 460 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
399 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 461 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
400 rx_dma: impl Peripheral<P = RxDma> + 'd, 462 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
401 config: Config, 463 config: Config,
402 ) -> Result<Self, ConfigError> { 464 ) -> Result<Self, ConfigError> {
403 T::enable_and_reset(); 465 Self::new_inner(peri, new_pin!(rx, AFType::Input), None, new_dma!(rx_dma), config)
404
405 Self::new_inner(peri, rx, rx_dma, config)
406 } 466 }
407 467
408 /// Create a new rx-only UART with a request-to-send pin 468 /// Create a new rx-only UART with a request-to-send pin
@@ -411,143 +471,27 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
411 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 471 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
412 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 472 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
413 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 473 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
414 rx_dma: impl Peripheral<P = RxDma> + 'd, 474 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
415 config: Config,
416 ) -> Result<Self, ConfigError> {
417 into_ref!(rts);
418
419 T::enable_and_reset();
420
421 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
422 T::regs().cr3().write(|w| {
423 w.set_rtse(true);
424 });
425
426 Self::new_inner(peri, rx, rx_dma, config)
427 }
428
429 fn new_inner(
430 peri: impl Peripheral<P = T> + 'd,
431 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
432 rx_dma: impl Peripheral<P = RxDma> + 'd,
433 config: Config, 475 config: Config,
434 ) -> Result<Self, ConfigError> { 476 ) -> Result<Self, ConfigError> {
435 into_ref!(peri, rx, rx_dma); 477 Self::new_inner(
436 478 peri,
437 let r = T::regs(); 479 new_pin!(rx, AFType::Input),
438 480 new_pin!(rts, AFType::OutputPushPull),
439 rx.set_as_af(rx.af_num(), AFType::Input); 481 new_dma!(rx_dma),
440 482 config,
441 configure(r, &config, T::frequency(), T::KIND, true, false)?; 483 )
442
443 T::Interrupt::unpend();
444 unsafe { T::Interrupt::enable() };
445
446 // create state once!
447 let _s = T::state();
448
449 Ok(Self {
450 _peri: peri,
451 rx_dma,
452 detect_previous_overrun: config.detect_previous_overrun,
453 #[cfg(any(usart_v1, usart_v2))]
454 buffered_sr: stm32_metapac::usart::regs::Sr(0),
455 })
456 }
457
458 /// Reconfigure the driver
459 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
460 reconfigure::<T>(config)
461 }
462
463 #[cfg(any(usart_v1, usart_v2))]
464 fn check_rx_flags(&mut self) -> Result<bool, Error> {
465 let r = T::regs();
466 loop {
467 // Handle all buffered error flags.
468 if self.buffered_sr.pe() {
469 self.buffered_sr.set_pe(false);
470 return Err(Error::Parity);
471 } else if self.buffered_sr.fe() {
472 self.buffered_sr.set_fe(false);
473 return Err(Error::Framing);
474 } else if self.buffered_sr.ne() {
475 self.buffered_sr.set_ne(false);
476 return Err(Error::Noise);
477 } else if self.buffered_sr.ore() {
478 self.buffered_sr.set_ore(false);
479 return Err(Error::Overrun);
480 } else if self.buffered_sr.rxne() {
481 self.buffered_sr.set_rxne(false);
482 return Ok(true);
483 } else {
484 // No error flags from previous iterations were set: Check the actual status register
485 let sr = r.sr().read();
486 if !sr.rxne() {
487 return Ok(false);
488 }
489
490 // Buffer the status register and let the loop handle the error flags.
491 self.buffered_sr = sr;
492 }
493 }
494 }
495
496 #[cfg(any(usart_v3, usart_v4))]
497 fn check_rx_flags(&mut self) -> Result<bool, Error> {
498 let r = T::regs();
499 let sr = r.isr().read();
500 if sr.pe() {
501 r.icr().write(|w| w.set_pe(true));
502 return Err(Error::Parity);
503 } else if sr.fe() {
504 r.icr().write(|w| w.set_fe(true));
505 return Err(Error::Framing);
506 } else if sr.ne() {
507 r.icr().write(|w| w.set_ne(true));
508 return Err(Error::Noise);
509 } else if sr.ore() {
510 r.icr().write(|w| w.set_ore(true));
511 return Err(Error::Overrun);
512 }
513 Ok(sr.rxne())
514 } 484 }
515 485
516 /// Initiate an asynchronous UART read 486 /// Initiate an asynchronous UART read
517 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 487 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
518 where
519 RxDma: crate::usart::RxDma<T>,
520 {
521 self.inner_read(buffer, false).await?; 488 self.inner_read(buffer, false).await?;
522 489
523 Ok(()) 490 Ok(())
524 } 491 }
525 492
526 /// Read a single u8 if there is one available, otherwise return WouldBlock
527 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
528 let r = T::regs();
529 if self.check_rx_flags()? {
530 Ok(unsafe { rdr(r).read_volatile() })
531 } else {
532 Err(nb::Error::WouldBlock)
533 }
534 }
535
536 /// Perform a blocking read into `buffer`
537 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
538 let r = T::regs();
539 for b in buffer {
540 while !self.check_rx_flags()? {}
541 unsafe { *b = rdr(r).read_volatile() }
542 }
543 Ok(())
544 }
545
546 /// Initiate an asynchronous read with idle line detection enabled 493 /// Initiate an asynchronous read with idle line detection enabled
547 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 494 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
548 where
549 RxDma: crate::usart::RxDma<T>,
550 {
551 self.inner_read(buffer, true).await 495 self.inner_read(buffer, true).await
552 } 496 }
553 497
@@ -555,10 +499,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
555 &mut self, 499 &mut self,
556 buffer: &mut [u8], 500 buffer: &mut [u8],
557 enable_idle_line_detection: bool, 501 enable_idle_line_detection: bool,
558 ) -> Result<ReadCompletionEvent, Error> 502 ) -> Result<ReadCompletionEvent, Error> {
559 where
560 RxDma: crate::usart::RxDma<T>,
561 {
562 let r = T::regs(); 503 let r = T::regs();
563 504
564 // make sure USART state is restored to neutral state when this future is dropped 505 // make sure USART state is restored to neutral state when this future is dropped
@@ -581,15 +522,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
581 }); 522 });
582 }); 523 });
583 524
584 let ch = &mut self.rx_dma; 525 let ch = self.rx_dma.as_mut().unwrap();
585 let request = ch.request();
586 526
587 let buffer_len = buffer.len(); 527 let buffer_len = buffer.len();
588 528
589 // Start USART DMA 529 // Start USART DMA
590 // will not do anything yet because DMAR is not yet set 530 // will not do anything yet because DMAR is not yet set
591 // future which will complete when DMA Read request completes 531 // future which will complete when DMA Read request completes
592 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; 532 let transfer = unsafe { ch.read(rdr(T::regs()), buffer, Default::default()) };
593 533
594 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer 534 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
595 if !self.detect_previous_overrun { 535 if !self.detect_previous_overrun {
@@ -732,10 +672,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
732 r 672 r
733 } 673 }
734 674
735 async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> 675 async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> {
736 where
737 RxDma: crate::usart::RxDma<T>,
738 {
739 if buffer.is_empty() { 676 if buffer.is_empty() {
740 return Ok(0); 677 return Ok(0);
741 } else if buffer.len() > 0xFFFF { 678 } else if buffer.len() > 0xFFFF {
@@ -755,34 +692,186 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
755 } 692 }
756} 693}
757 694
758impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { 695impl<'d, T: BasicInstance> UartRx<'d, T, Blocking> {
696 /// Create a new rx-only UART with no hardware flow control.
697 ///
698 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
699 pub fn new_blocking(
700 peri: impl Peripheral<P = T> + 'd,
701 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
702 config: Config,
703 ) -> Result<Self, ConfigError> {
704 Self::new_inner(peri, new_pin!(rx, AFType::Input), None, None, config)
705 }
706
707 /// Create a new rx-only UART with a request-to-send pin
708 pub fn new_blocking_with_rts(
709 peri: impl Peripheral<P = T> + 'd,
710 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
711 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
712 config: Config,
713 ) -> Result<Self, ConfigError> {
714 Self::new_inner(
715 peri,
716 new_pin!(rx, AFType::Input),
717 new_pin!(rts, AFType::OutputPushPull),
718 None,
719 config,
720 )
721 }
722}
723
724impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
725 fn new_inner(
726 _peri: impl Peripheral<P = T> + 'd,
727 rx: Option<PeripheralRef<'d, AnyPin>>,
728 rts: Option<PeripheralRef<'d, AnyPin>>,
729 rx_dma: Option<ChannelAndRequest<'d>>,
730 config: Config,
731 ) -> Result<Self, ConfigError> {
732 T::enable_and_reset();
733
734 let r = T::regs();
735 r.cr3().write(|w| {
736 w.set_rtse(rts.is_some());
737 });
738 configure(r, &config, T::frequency(), T::KIND, true, false)?;
739
740 T::Interrupt::unpend();
741 unsafe { T::Interrupt::enable() };
742
743 // create state once!
744 let _s = T::state();
745
746 Ok(Self {
747 _phantom: PhantomData,
748 rx,
749 rts,
750 rx_dma,
751 detect_previous_overrun: config.detect_previous_overrun,
752 #[cfg(any(usart_v1, usart_v2))]
753 buffered_sr: stm32_metapac::usart::regs::Sr(0),
754 })
755 }
756
757 /// Reconfigure the driver
758 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
759 reconfigure::<T>(config)
760 }
761
762 #[cfg(any(usart_v1, usart_v2))]
763 fn check_rx_flags(&mut self) -> Result<bool, Error> {
764 let r = T::regs();
765 loop {
766 // Handle all buffered error flags.
767 if self.buffered_sr.pe() {
768 self.buffered_sr.set_pe(false);
769 return Err(Error::Parity);
770 } else if self.buffered_sr.fe() {
771 self.buffered_sr.set_fe(false);
772 return Err(Error::Framing);
773 } else if self.buffered_sr.ne() {
774 self.buffered_sr.set_ne(false);
775 return Err(Error::Noise);
776 } else if self.buffered_sr.ore() {
777 self.buffered_sr.set_ore(false);
778 return Err(Error::Overrun);
779 } else if self.buffered_sr.rxne() {
780 self.buffered_sr.set_rxne(false);
781 return Ok(true);
782 } else {
783 // No error flags from previous iterations were set: Check the actual status register
784 let sr = r.sr().read();
785 if !sr.rxne() {
786 return Ok(false);
787 }
788
789 // Buffer the status register and let the loop handle the error flags.
790 self.buffered_sr = sr;
791 }
792 }
793 }
794
795 #[cfg(any(usart_v3, usart_v4))]
796 fn check_rx_flags(&mut self) -> Result<bool, Error> {
797 let r = T::regs();
798 let sr = r.isr().read();
799 if sr.pe() {
800 r.icr().write(|w| w.set_pe(true));
801 return Err(Error::Parity);
802 } else if sr.fe() {
803 r.icr().write(|w| w.set_fe(true));
804 return Err(Error::Framing);
805 } else if sr.ne() {
806 r.icr().write(|w| w.set_ne(true));
807 return Err(Error::Noise);
808 } else if sr.ore() {
809 r.icr().write(|w| w.set_ore(true));
810 return Err(Error::Overrun);
811 }
812 Ok(sr.rxne())
813 }
814
815 /// Read a single u8 if there is one available, otherwise return WouldBlock
816 pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
817 let r = T::regs();
818 if self.check_rx_flags()? {
819 Ok(unsafe { rdr(r).read_volatile() })
820 } else {
821 Err(nb::Error::WouldBlock)
822 }
823 }
824
825 /// Perform a blocking read into `buffer`
826 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
827 let r = T::regs();
828 for b in buffer {
829 while !self.check_rx_flags()? {}
830 unsafe { *b = rdr(r).read_volatile() }
831 }
832 Ok(())
833 }
834}
835
836impl<'d, T: BasicInstance, M: Mode> Drop for UartTx<'d, T, M> {
759 fn drop(&mut self) { 837 fn drop(&mut self) {
838 self.tx.as_ref().map(|x| x.set_as_disconnected());
839 self.cts.as_ref().map(|x| x.set_as_disconnected());
840 self.de.as_ref().map(|x| x.set_as_disconnected());
760 T::disable(); 841 T::disable();
761 } 842 }
762} 843}
763 844
764impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { 845impl<'d, T: BasicInstance, M: Mode> Drop for UartRx<'d, T, M> {
765 fn drop(&mut self) { 846 fn drop(&mut self) {
847 self.rx.as_ref().map(|x| x.set_as_disconnected());
848 self.rts.as_ref().map(|x| x.set_as_disconnected());
766 T::disable(); 849 T::disable();
767 } 850 }
768} 851}
769 852
770impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { 853impl<'d, T: BasicInstance> Uart<'d, T, Async> {
771 /// Create a new bidirectional UART 854 /// Create a new bidirectional UART
772 pub fn new( 855 pub fn new(
773 peri: impl Peripheral<P = T> + 'd, 856 peri: impl Peripheral<P = T> + 'd,
774 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 857 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
775 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 858 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
776 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 859 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
777 tx_dma: impl Peripheral<P = TxDma> + 'd, 860 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
778 rx_dma: impl Peripheral<P = RxDma> + 'd, 861 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
779 config: Config, 862 config: Config,
780 ) -> Result<Self, ConfigError> { 863 ) -> Result<Self, ConfigError> {
781 // UartRx and UartTx have one refcount ea. 864 Self::new_inner(
782 T::enable_and_reset(); 865 peri,
783 T::enable_and_reset(); 866 new_pin!(rx, config.rx_af()),
784 867 new_pin!(tx, config.tx_af()),
785 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) 868 None,
869 None,
870 None,
871 new_dma!(tx_dma),
872 new_dma!(rx_dma),
873 config,
874 )
786 } 875 }
787 876
788 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 877 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
@@ -793,23 +882,21 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
793 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 882 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
794 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 883 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
795 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 884 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
796 tx_dma: impl Peripheral<P = TxDma> + 'd, 885 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
797 rx_dma: impl Peripheral<P = RxDma> + 'd, 886 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
798 config: Config, 887 config: Config,
799 ) -> Result<Self, ConfigError> { 888 ) -> Result<Self, ConfigError> {
800 into_ref!(cts, rts); 889 Self::new_inner(
801 890 peri,
802 // UartRx and UartTx have one refcount ea. 891 new_pin!(rx, config.rx_af()),
803 T::enable_and_reset(); 892 new_pin!(tx, config.tx_af()),
804 T::enable_and_reset(); 893 new_pin!(rts, AFType::OutputPushPull),
805 894 new_pin!(cts, AFType::Input),
806 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 895 None,
807 cts.set_as_af(cts.af_num(), AFType::Input); 896 new_dma!(tx_dma),
808 T::regs().cr3().write(|w| { 897 new_dma!(rx_dma),
809 w.set_rtse(true); 898 config,
810 w.set_ctse(true); 899 )
811 });
812 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
813 } 900 }
814 901
815 #[cfg(not(any(usart_v1, usart_v2)))] 902 #[cfg(not(any(usart_v1, usart_v2)))]
@@ -820,21 +907,21 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
820 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 907 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
821 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 908 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
822 de: impl Peripheral<P = impl DePin<T>> + 'd, 909 de: impl Peripheral<P = impl DePin<T>> + 'd,
823 tx_dma: impl Peripheral<P = TxDma> + 'd, 910 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
824 rx_dma: impl Peripheral<P = RxDma> + 'd, 911 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
825 config: Config, 912 config: Config,
826 ) -> Result<Self, ConfigError> { 913 ) -> Result<Self, ConfigError> {
827 into_ref!(de); 914 Self::new_inner(
828 915 peri,
829 // UartRx and UartTx have one refcount ea. 916 new_pin!(rx, config.rx_af()),
830 T::enable_and_reset(); 917 new_pin!(tx, config.tx_af()),
831 T::enable_and_reset(); 918 None,
832 919 None,
833 de.set_as_af(de.af_num(), AFType::OutputPushPull); 920 new_pin!(de, AFType::OutputPushPull),
834 T::regs().cr3().write(|w| { 921 new_dma!(tx_dma),
835 w.set_dem(true); 922 new_dma!(rx_dma),
836 }); 923 config,
837 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) 924 )
838 } 925 }
839 926
840 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin. 927 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
@@ -846,28 +933,32 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
846 /// I/O in idle or in reception. 933 /// I/O in idle or in reception.
847 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 934 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
848 /// on the line must be managed by software (for instance by using a centralized arbiter). 935 /// on the line must be managed by software (for instance by using a centralized arbiter).
849 #[cfg(not(any(usart_v1, usart_v2)))]
850 #[doc(alias("HDSEL"))] 936 #[doc(alias("HDSEL"))]
851 pub fn new_half_duplex( 937 pub fn new_half_duplex(
852 peri: impl Peripheral<P = T> + 'd, 938 peri: impl Peripheral<P = T> + 'd,
853 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 939 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
854 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 940 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
855 tx_dma: impl Peripheral<P = TxDma> + 'd, 941 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
856 rx_dma: impl Peripheral<P = RxDma> + 'd, 942 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
857 mut config: Config, 943 mut config: Config,
858 ) -> Result<Self, ConfigError> { 944 ) -> Result<Self, ConfigError> {
859 // UartRx and UartTx have one refcount ea. 945 #[cfg(not(any(usart_v1, usart_v2)))]
860 T::enable_and_reset(); 946 {
861 T::enable_and_reset(); 947 config.swap_rx_tx = false;
862 948 }
863 config.swap_rx_tx = false; 949 config.half_duplex = true;
864
865 into_ref!(peri, tx, tx_dma, rx_dma);
866
867 T::regs().cr3().write(|w| w.set_hdsel(true));
868 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
869 950
870 Self::new_inner(peri, tx_dma, rx_dma, config) 951 Self::new_inner(
952 peri,
953 None,
954 new_pin!(tx, AFType::OutputPushPull),
955 None,
956 None,
957 None,
958 new_dma!(tx_dma),
959 new_dma!(rx_dma),
960 config,
961 )
871 } 962 }
872 963
873 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin. 964 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
@@ -885,62 +976,198 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
885 peri: impl Peripheral<P = T> + 'd, 976 peri: impl Peripheral<P = T> + 'd,
886 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 977 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
887 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 978 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
888 tx_dma: impl Peripheral<P = TxDma> + 'd, 979 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
889 rx_dma: impl Peripheral<P = RxDma> + 'd, 980 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
890 mut config: Config, 981 mut config: Config,
891 ) -> Result<Self, ConfigError> { 982 ) -> Result<Self, ConfigError> {
892 // UartRx and UartTx have one refcount ea.
893 T::enable_and_reset();
894 T::enable_and_reset();
895
896 config.swap_rx_tx = true; 983 config.swap_rx_tx = true;
984 config.half_duplex = true;
985
986 Self::new_inner(
987 peri,
988 None,
989 None,
990 new_pin!(rx, AFType::OutputPushPull),
991 None,
992 None,
993 new_dma!(tx_dma),
994 new_dma!(rx_dma),
995 config,
996 )
997 }
998
999 /// Perform an asynchronous write
1000 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
1001 self.tx.write(buffer).await
1002 }
897 1003
898 into_ref!(peri, rx, tx_dma, rx_dma); 1004 /// Perform an asynchronous read into `buffer`
1005 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
1006 self.rx.read(buffer).await
1007 }
1008
1009 /// Perform an an asynchronous read with idle line detection enabled
1010 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1011 self.rx.read_until_idle(buffer).await
1012 }
1013}
899 1014
900 T::regs().cr3().write(|w| w.set_hdsel(true)); 1015impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
901 rx.set_as_af(rx.af_num(), AFType::OutputPushPull); 1016 /// Create a new blocking bidirectional UART.
1017 pub fn new_blocking(
1018 peri: impl Peripheral<P = T> + 'd,
1019 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1020 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1021 config: Config,
1022 ) -> Result<Self, ConfigError> {
1023 Self::new_inner(
1024 peri,
1025 new_pin!(rx, config.rx_af()),
1026 new_pin!(tx, config.tx_af()),
1027 None,
1028 None,
1029 None,
1030 None,
1031 None,
1032 config,
1033 )
1034 }
902 1035
903 Self::new_inner(peri, tx_dma, rx_dma, config) 1036 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
1037 pub fn new_blocking_with_rtscts(
1038 peri: impl Peripheral<P = T> + 'd,
1039 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1040 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1041 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
1042 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
1043 config: Config,
1044 ) -> Result<Self, ConfigError> {
1045 Self::new_inner(
1046 peri,
1047 new_pin!(rx, config.rx_af()),
1048 new_pin!(tx, config.tx_af()),
1049 new_pin!(rts, AFType::OutputPushPull),
1050 new_pin!(cts, AFType::Input),
1051 None,
1052 None,
1053 None,
1054 config,
1055 )
904 } 1056 }
905 1057
906 fn new_inner_configure( 1058 #[cfg(not(any(usart_v1, usart_v2)))]
1059 /// Create a new bidirectional UART with a driver-enable pin
1060 pub fn new_blocking_with_de(
907 peri: impl Peripheral<P = T> + 'd, 1061 peri: impl Peripheral<P = T> + 'd,
908 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1062 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
909 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1063 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
910 tx_dma: impl Peripheral<P = TxDma> + 'd, 1064 de: impl Peripheral<P = impl DePin<T>> + 'd,
911 rx_dma: impl Peripheral<P = RxDma> + 'd,
912 config: Config, 1065 config: Config,
913 ) -> Result<Self, ConfigError> { 1066 ) -> Result<Self, ConfigError> {
914 into_ref!(peri, rx, tx, tx_dma, rx_dma); 1067 Self::new_inner(
915 1068 peri,
916 // Some chips do not have swap_rx_tx bit 1069 new_pin!(rx, config.rx_af()),
917 cfg_if::cfg_if! { 1070 new_pin!(tx, config.tx_af()),
918 if #[cfg(any(usart_v3, usart_v4))] { 1071 None,
919 if config.swap_rx_tx { 1072 None,
920 let (rx, tx) = (tx, rx); 1073 new_pin!(de, AFType::OutputPushPull),
921 rx.set_as_af(rx.af_num(), AFType::Input); 1074 None,
922 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1075 None,
923 } else { 1076 config,
924 rx.set_as_af(rx.af_num(), AFType::Input); 1077 )
925 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1078 }
926 } 1079
927 } else { 1080 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
928 rx.set_as_af(rx.af_num(), AFType::Input); 1081 ///
929 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1082 /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin.
930 } 1083 /// There is no functional difference between these methods, as both allow bidirectional communication.
1084 ///
1085 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
1086 /// I/O in idle or in reception.
1087 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1088 /// on the line must be managed by software (for instance by using a centralized arbiter).
1089 #[doc(alias("HDSEL"))]
1090 pub fn new_blocking_half_duplex(
1091 peri: impl Peripheral<P = T> + 'd,
1092 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1093 mut config: Config,
1094 ) -> Result<Self, ConfigError> {
1095 #[cfg(not(any(usart_v1, usart_v2)))]
1096 {
1097 config.swap_rx_tx = false;
931 } 1098 }
1099 config.half_duplex = true;
1100
1101 Self::new_inner(
1102 peri,
1103 None,
1104 new_pin!(tx, AFType::OutputPushPull),
1105 None,
1106 None,
1107 None,
1108 None,
1109 None,
1110 config,
1111 )
1112 }
932 1113
933 Self::new_inner(peri, tx_dma, rx_dma, config) 1114 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
1115 ///
1116 /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
1117 /// There is no functional difference between these methods, as both allow bidirectional communication.
1118 ///
1119 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
1120 /// I/O in idle or in reception.
1121 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1122 /// on the line must be managed by software (for instance by using a centralized arbiter).
1123 #[cfg(not(any(usart_v1, usart_v2)))]
1124 #[doc(alias("HDSEL"))]
1125 pub fn new_blocking_half_duplex_on_rx(
1126 peri: impl Peripheral<P = T> + 'd,
1127 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1128 mut config: Config,
1129 ) -> Result<Self, ConfigError> {
1130 config.swap_rx_tx = true;
1131 config.half_duplex = true;
1132
1133 Self::new_inner(
1134 peri,
1135 None,
1136 None,
1137 new_pin!(rx, AFType::OutputPushPull),
1138 None,
1139 None,
1140 None,
1141 None,
1142 config,
1143 )
934 } 1144 }
1145}
935 1146
1147impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
936 fn new_inner( 1148 fn new_inner(
937 peri: PeripheralRef<'d, T>, 1149 _peri: impl Peripheral<P = T> + 'd,
938 tx_dma: PeripheralRef<'d, TxDma>, 1150 rx: Option<PeripheralRef<'d, AnyPin>>,
939 rx_dma: PeripheralRef<'d, RxDma>, 1151 tx: Option<PeripheralRef<'d, AnyPin>>,
1152 rts: Option<PeripheralRef<'d, AnyPin>>,
1153 cts: Option<PeripheralRef<'d, AnyPin>>,
1154 de: Option<PeripheralRef<'d, AnyPin>>,
1155 tx_dma: Option<ChannelAndRequest<'d>>,
1156 rx_dma: Option<ChannelAndRequest<'d>>,
940 config: Config, 1157 config: Config,
941 ) -> Result<Self, ConfigError> { 1158 ) -> Result<Self, ConfigError> {
1159 // UartRx and UartTx have one refcount each.
1160 T::enable_and_reset();
1161 T::enable_and_reset();
1162
942 let r = T::regs(); 1163 let r = T::regs();
943 1164
1165 r.cr3().write(|w| {
1166 w.set_rtse(rts.is_some());
1167 w.set_ctse(cts.is_some());
1168 #[cfg(not(any(usart_v1, usart_v2)))]
1169 w.set_dem(de.is_some());
1170 });
944 configure(r, &config, T::frequency(), T::KIND, true, true)?; 1171 configure(r, &config, T::frequency(), T::KIND, true, true)?;
945 1172
946 T::Interrupt::unpend(); 1173 T::Interrupt::unpend();
@@ -951,11 +1178,16 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
951 1178
952 Ok(Self { 1179 Ok(Self {
953 tx: UartTx { 1180 tx: UartTx {
1181 _phantom: PhantomData,
1182 tx,
1183 cts,
1184 de,
954 tx_dma, 1185 tx_dma,
955 phantom: PhantomData,
956 }, 1186 },
957 rx: UartRx { 1187 rx: UartRx {
958 _peri: peri, 1188 _phantom: PhantomData,
1189 rx,
1190 rts,
959 rx_dma, 1191 rx_dma,
960 detect_previous_overrun: config.detect_previous_overrun, 1192 detect_previous_overrun: config.detect_previous_overrun,
961 #[cfg(any(usart_v1, usart_v2))] 1193 #[cfg(any(usart_v1, usart_v2))]
@@ -964,14 +1196,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
964 }) 1196 })
965 } 1197 }
966 1198
967 /// Initiate an asynchronous write
968 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
969 where
970 TxDma: crate::usart::TxDma<T>,
971 {
972 self.tx.write(buffer).await
973 }
974
975 /// Perform a blocking write 1199 /// Perform a blocking write
976 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1200 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
977 self.tx.blocking_write(buffer) 1201 self.tx.blocking_write(buffer)
@@ -982,16 +1206,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
982 self.tx.blocking_flush() 1206 self.tx.blocking_flush()
983 } 1207 }
984 1208
985 /// Initiate an asynchronous read into `buffer`
986 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
987 where
988 RxDma: crate::usart::RxDma<T>,
989 {
990 self.rx.read(buffer).await
991 }
992
993 /// Read a single `u8` or return `WouldBlock` 1209 /// Read a single `u8` or return `WouldBlock`
994 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 1210 pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
995 self.rx.nb_read() 1211 self.rx.nb_read()
996 } 1212 }
997 1213
@@ -1000,18 +1216,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
1000 self.rx.blocking_read(buffer) 1216 self.rx.blocking_read(buffer)
1001 } 1217 }
1002 1218
1003 /// Initiate an an asynchronous read with idle line detection enabled
1004 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
1005 where
1006 RxDma: crate::usart::RxDma<T>,
1007 {
1008 self.rx.read_until_idle(buffer).await
1009 }
1010
1011 /// Split the Uart into a transmitter and receiver, which is 1219 /// Split the Uart into a transmitter and receiver, which is
1012 /// particularly useful when having two tasks correlating to 1220 /// particularly useful when having two tasks correlating to
1013 /// transmitting and receiving. 1221 /// transmitting and receiving.
1014 pub fn split(self) -> (UartTx<'d, T, TxDma>, UartRx<'d, T, RxDma>) { 1222 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
1015 (self.tx, self.rx) 1223 (self.tx, self.rx)
1016 } 1224 }
1017} 1225}
@@ -1150,9 +1358,10 @@ fn configure(
1150 } 1358 }
1151 }); 1359 });
1152 1360
1153 #[cfg(not(usart_v1))]
1154 r.cr3().modify(|w| { 1361 r.cr3().modify(|w| {
1362 #[cfg(not(usart_v1))]
1155 w.set_onebit(config.assume_noise_free); 1363 w.set_onebit(config.assume_noise_free);
1364 w.set_hdsel(config.half_duplex);
1156 }); 1365 });
1157 1366
1158 r.cr1().write(|w| { 1367 r.cr1().write(|w| {
@@ -1185,14 +1394,14 @@ fn configure(
1185 Ok(()) 1394 Ok(())
1186} 1395}
1187 1396
1188impl<'d, T: BasicInstance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> { 1397impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
1189 type Error = Error; 1398 type Error = Error;
1190 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1399 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1191 self.nb_read() 1400 self.nb_read()
1192 } 1401 }
1193} 1402}
1194 1403
1195impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> { 1404impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
1196 type Error = Error; 1405 type Error = Error;
1197 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1406 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1198 self.blocking_write(buffer) 1407 self.blocking_write(buffer)
@@ -1202,14 +1411,14 @@ impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> f
1202 } 1411 }
1203} 1412}
1204 1413
1205impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> { 1414impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
1206 type Error = Error; 1415 type Error = Error;
1207 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1416 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1208 self.nb_read() 1417 self.nb_read()
1209 } 1418 }
1210} 1419}
1211 1420
1212impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> { 1421impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
1213 type Error = Error; 1422 type Error = Error;
1214 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1423 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1215 self.blocking_write(buffer) 1424 self.blocking_write(buffer)
@@ -1231,25 +1440,25 @@ impl embedded_hal_nb::serial::Error for Error {
1231 } 1440 }
1232} 1441}
1233 1442
1234impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { 1443impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
1235 type Error = Error; 1444 type Error = Error;
1236} 1445}
1237 1446
1238impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> { 1447impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
1239 type Error = Error; 1448 type Error = Error;
1240} 1449}
1241 1450
1242impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> { 1451impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
1243 type Error = Error; 1452 type Error = Error;
1244} 1453}
1245 1454
1246impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::Read for UartRx<'d, T, RxDma> { 1455impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
1247 fn read(&mut self) -> nb::Result<u8, Self::Error> { 1456 fn read(&mut self) -> nb::Result<u8, Self::Error> {
1248 self.nb_read() 1457 self.nb_read()
1249 } 1458 }
1250} 1459}
1251 1460
1252impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { 1461impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
1253 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1462 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1254 self.blocking_write(&[char]).map_err(nb::Error::Other) 1463 self.blocking_write(&[char]).map_err(nb::Error::Other)
1255 } 1464 }
@@ -1259,13 +1468,13 @@ impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d,
1259 } 1468 }
1260} 1469}
1261 1470
1262impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Read for Uart<'d, T, TxDma, RxDma> { 1471impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
1263 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1472 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1264 self.nb_read() 1473 self.nb_read()
1265 } 1474 }
1266} 1475}
1267 1476
1268impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { 1477impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
1269 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1478 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1270 self.blocking_write(&[char]).map_err(nb::Error::Other) 1479 self.blocking_write(&[char]).map_err(nb::Error::Other)
1271 } 1480 }
@@ -1281,21 +1490,21 @@ impl embedded_io::Error for Error {
1281 } 1490 }
1282} 1491}
1283 1492
1284impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> 1493impl<T, M: Mode> embedded_io::ErrorType for Uart<'_, T, M>
1285where 1494where
1286 T: BasicInstance, 1495 T: BasicInstance,
1287{ 1496{
1288 type Error = Error; 1497 type Error = Error;
1289} 1498}
1290 1499
1291impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma> 1500impl<T, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M>
1292where 1501where
1293 T: BasicInstance, 1502 T: BasicInstance,
1294{ 1503{
1295 type Error = Error; 1504 type Error = Error;
1296} 1505}
1297 1506
1298impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> 1507impl<T, M: Mode> embedded_io::Write for Uart<'_, T, M>
1299where 1508where
1300 T: BasicInstance, 1509 T: BasicInstance,
1301{ 1510{
@@ -1309,7 +1518,7 @@ where
1309 } 1518 }
1310} 1519}
1311 1520
1312impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> 1521impl<T, M: Mode> embedded_io::Write for UartTx<'_, T, M>
1313where 1522where
1314 T: BasicInstance, 1523 T: BasicInstance,
1315{ 1524{
@@ -1323,10 +1532,9 @@ where
1323 } 1532 }
1324} 1533}
1325 1534
1326impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> 1535impl<T> embedded_io_async::Write for Uart<'_, T, Async>
1327where 1536where
1328 T: BasicInstance, 1537 T: BasicInstance,
1329 TxDma: self::TxDma<T>,
1330{ 1538{
1331 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1539 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1332 self.write(buf).await?; 1540 self.write(buf).await?;
@@ -1338,10 +1546,9 @@ where
1338 } 1546 }
1339} 1547}
1340 1548
1341impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma> 1549impl<T> embedded_io_async::Write for UartTx<'_, T, Async>
1342where 1550where
1343 T: BasicInstance, 1551 T: BasicInstance,
1344 TxDma: self::TxDma<T>,
1345{ 1552{
1346 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1553 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1347 self.write(buf).await?; 1554 self.write(buf).await?;
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b852f0176..8eb18fe5b 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,21 +1,22 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData;
2use core::mem; 3use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralRef;
8use futures::future::{select, Either}; 8use futures::future::{select, Either};
9 9
10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; 10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
11use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::mode::Async;
12use crate::usart::{Regs, Sr}; 13use crate::usart::{Regs, Sr};
13 14
14/// Rx-only Ring-buffered UART Driver 15/// Rx-only Ring-buffered UART Driver
15/// 16///
16/// Created with [UartRx::into_ring_buffered] 17/// Created with [UartRx::into_ring_buffered]
17pub struct RingBufferedUartRx<'d, T: BasicInstance> { 18pub struct RingBufferedUartRx<'d, T: BasicInstance> {
18 _peri: PeripheralRef<'d, T>, 19 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u8>, 20 ring_buf: ReadableRingBuffer<'d, u8>,
20} 21}
21 22
@@ -28,26 +29,29 @@ impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
28 } 29 }
29} 30}
30 31
31impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { 32impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
32 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 33 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
33 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the 34 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
34 /// DMA controller, and must be large enough to prevent overflows. 35 /// DMA controller, and must be large enough to prevent overflows.
35 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> { 36 pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
36 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 37 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
37 38
38 let request = self.rx_dma.request();
39 let opts = Default::default(); 39 let opts = Default::default();
40 40
41 // Safety: we forget the struct before this function returns. 41 // Safety: we forget the struct before this function returns.
42 let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; 42 let rx_dma = self.rx_dma.as_mut().unwrap();
43 let _peri = unsafe { self._peri.clone_unchecked() }; 43 let request = rx_dma.request;
44 let rx_dma = unsafe { rx_dma.channel.clone_unchecked() };
44 45
45 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 46 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
46 47
47 // Don't disable the clock 48 // Don't disable the clock
48 mem::forget(self); 49 mem::forget(self);
49 50
50 RingBufferedUartRx { _peri, ring_buf } 51 RingBufferedUartRx {
52 _phantom: PhantomData,
53 ring_buf,
54 }
51 } 55 }
52} 56}
53 57
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index 1e3c44167..349438ec5 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -23,7 +23,7 @@ fn common_init<T: Instance>() {
23 ) 23 )
24 } 24 }
25 25
26 #[cfg(any(stm32l4, stm32l5, stm32wb))] 26 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))]
27 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); 27 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
28 28
29 #[cfg(pwr_h5)] 29 #[cfg(pwr_h5)]
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index b0e7067bd..b386c6977 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -317,7 +317,7 @@ impl<'d, T: Instance> Driver<'d, T> {
317 /// 317 ///
318 /// # Arguments 318 /// # Arguments
319 /// 319 ///
320 /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. 320 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
321 /// Must be large enough to fit all OUT endpoint max packet sizes. 321 /// Must be large enough to fit all OUT endpoint max packet sizes.
322 /// Endpoint allocation will fail if it is too small. 322 /// Endpoint allocation will fail if it is too small.
323 pub fn new_fs( 323 pub fn new_fs(
@@ -348,7 +348,7 @@ impl<'d, T: Instance> Driver<'d, T> {
348 /// 348 ///
349 /// # Arguments 349 /// # Arguments
350 /// 350 ///
351 /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. 351 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
352 /// Must be large enough to fit all OUT endpoint max packet sizes. 352 /// Must be large enough to fit all OUT endpoint max packet sizes.
353 /// Endpoint allocation will fail if it is too small. 353 /// Endpoint allocation will fail if it is too small.
354 pub fn new_hs_ulpi( 354 pub fn new_hs_ulpi(
@@ -562,51 +562,29 @@ impl<'d, T: Instance> Bus<'d, T> {
562 fn init(&mut self) { 562 fn init(&mut self) {
563 super::common_init::<T>(); 563 super::common_init::<T>();
564 564
565 #[cfg(stm32f7)] 565 // Enable ULPI clock if external PHY is used
566 { 566 let _ulpien = !self.phy_type.internal();
567 // Enable ULPI clock if external PHY is used
568 let ulpien = !self.phy_type.internal();
569 critical_section::with(|_| {
570 crate::pac::RCC.ahb1enr().modify(|w| {
571 if T::HIGH_SPEED {
572 w.set_usb_otg_hsulpien(ulpien);
573 } else {
574 w.set_usb_otg_hsen(ulpien);
575 }
576 });
577 567
578 // Low power mode 568 #[cfg(any(stm32f2, stm32f4, stm32f7))]
579 crate::pac::RCC.ahb1lpenr().modify(|w| { 569 if T::HIGH_SPEED {
580 if T::HIGH_SPEED { 570 critical_section::with(|_| {
581 w.set_usb_otg_hsulpilpen(ulpien); 571 let rcc = crate::pac::RCC;
582 } else { 572 rcc.ahb1enr().modify(|w| w.set_usb_otg_hsulpien(_ulpien));
583 w.set_usb_otg_hslpen(ulpien); 573 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hsulpilpen(_ulpien));
584 }
585 });
586 }); 574 });
587 } 575 }
588 576
589 #[cfg(stm32h7)] 577 #[cfg(stm32h7)]
590 { 578 critical_section::with(|_| {
591 // Enable ULPI clock if external PHY is used 579 let rcc = crate::pac::RCC;
592 let ulpien = !self.phy_type.internal(); 580 if T::HIGH_SPEED {
593 critical_section::with(|_| { 581 rcc.ahb1enr().modify(|w| w.set_usb_otg_hs_ulpien(_ulpien));
594 crate::pac::RCC.ahb1enr().modify(|w| { 582 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hs_ulpilpen(_ulpien));
595 if T::HIGH_SPEED { 583 } else {
596 w.set_usb_otg_hs_ulpien(ulpien); 584 rcc.ahb1enr().modify(|w| w.set_usb_otg_fs_ulpien(_ulpien));
597 } else { 585 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_fs_ulpilpen(_ulpien));
598 w.set_usb_otg_fs_ulpien(ulpien); 586 }
599 } 587 });
600 });
601 crate::pac::RCC.ahb1lpenr().modify(|w| {
602 if T::HIGH_SPEED {
603 w.set_usb_otg_hs_ulpilpen(ulpien);
604 } else {
605 w.set_usb_otg_fs_ulpilpen(ulpien);
606 }
607 });
608 });
609 }
610 588
611 let r = T::regs(); 589 let r = T::regs();
612 let core_id = r.cid().read().0; 590 let core_id = r.cid().read().0;
@@ -694,45 +672,51 @@ impl<'d, T: Instance> Bus<'d, T> {
694 672
695 let r = T::regs(); 673 let r = T::regs();
696 674
697 // Configure RX fifo size. All endpoints share the same FIFO area. 675 // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
698 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); 676 // handler COULD interrupt us here and do FIFO operations, so ensure
699 trace!("configuring rx fifo size={}", rx_fifo_size_words); 677 // the interrupt does not occur.
700 678 critical_section::with(|_| {
701 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); 679 // Configure RX fifo size. All endpoints share the same FIFO area.
702 680 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
703 // Configure TX (USB in direction) fifo size for each endpoint 681 trace!("configuring rx fifo size={}", rx_fifo_size_words);
704 let mut fifo_top = rx_fifo_size_words; 682
705 for i in 0..T::ENDPOINT_COUNT { 683 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
706 if let Some(ep) = self.ep_in[i] { 684
707 trace!( 685 // Configure TX (USB in direction) fifo size for each endpoint
708 "configuring tx fifo ep={}, offset={}, size={}", 686 let mut fifo_top = rx_fifo_size_words;
709 i, 687 for i in 0..T::ENDPOINT_COUNT {
710 fifo_top, 688 if let Some(ep) = self.ep_in[i] {
711 ep.fifo_size_words 689 trace!(
712 ); 690 "configuring tx fifo ep={}, offset={}, size={}",
713 691 i,
714 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; 692 fifo_top,
715 693 ep.fifo_size_words
716 dieptxf.write(|w| { 694 );
717 w.set_fd(ep.fifo_size_words); 695
718 w.set_sa(fifo_top); 696 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
719 }); 697
698 dieptxf.write(|w| {
699 w.set_fd(ep.fifo_size_words);
700 w.set_sa(fifo_top);
701 });
720 702
721 fifo_top += ep.fifo_size_words; 703 fifo_top += ep.fifo_size_words;
704 }
722 } 705 }
723 }
724 706
725 assert!( 707 assert!(
726 fifo_top <= T::FIFO_DEPTH_WORDS, 708 fifo_top <= T::FIFO_DEPTH_WORDS,
727 "FIFO allocations exceeded maximum capacity" 709 "FIFO allocations exceeded maximum capacity"
728 ); 710 );
729 711
730 // Flush fifos 712 // Flush fifos
731 r.grstctl().write(|w| { 713 r.grstctl().write(|w| {
732 w.set_rxfflsh(true); 714 w.set_rxfflsh(true);
733 w.set_txfflsh(true); 715 w.set_txfflsh(true);
734 w.set_txfnum(0x10); 716 w.set_txfnum(0x10);
717 });
735 }); 718 });
719
736 loop { 720 loop {
737 let x = r.grstctl().read(); 721 let x = r.grstctl().read();
738 if !x.rxfflsh() && !x.txfflsh() { 722 if !x.rxfflsh() && !x.txfflsh() {
@@ -1230,27 +1214,31 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1230 .await 1214 .await
1231 } 1215 }
1232 1216
1233 // Setup transfer size 1217 // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
1234 r.dieptsiz(index).write(|w| { 1218 // accesses to certain OTG_FS registers.
1235 w.set_mcnt(1); 1219 //
1236 w.set_pktcnt(1); 1220 // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
1237 w.set_xfrsiz(buf.len() as _);
1238 });
1239
1240 critical_section::with(|_| { 1221 critical_section::with(|_| {
1222 // Setup transfer size
1223 r.dieptsiz(index).write(|w| {
1224 w.set_mcnt(1);
1225 w.set_pktcnt(1);
1226 w.set_xfrsiz(buf.len() as _);
1227 });
1228
1241 // Enable endpoint 1229 // Enable endpoint
1242 r.diepctl(index).modify(|w| { 1230 r.diepctl(index).modify(|w| {
1243 w.set_cnak(true); 1231 w.set_cnak(true);
1244 w.set_epena(true); 1232 w.set_epena(true);
1245 }); 1233 });
1246 });
1247 1234
1248 // Write data to FIFO 1235 // Write data to FIFO
1249 for chunk in buf.chunks(4) { 1236 for chunk in buf.chunks(4) {
1250 let mut tmp = [0u8; 4]; 1237 let mut tmp = [0u8; 4];
1251 tmp[0..chunk.len()].copy_from_slice(chunk); 1238 tmp[0..chunk.len()].copy_from_slice(chunk);
1252 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); 1239 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
1253 } 1240 }
1241 });
1254 1242
1255 trace!("write done ep={:?}", self.info.addr); 1243 trace!("write done ep={:?}", self.info.addr);
1256 1244
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index f48808cb3..81a2d2623 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -107,14 +107,14 @@ const EP_COUNT: usize = 8;
107 107
108#[cfg(any(usbram_16x1_512, usbram_16x2_512))] 108#[cfg(any(usbram_16x1_512, usbram_16x2_512))]
109const USBRAM_SIZE: usize = 512; 109const USBRAM_SIZE: usize = 512;
110#[cfg(usbram_16x2_1024)] 110#[cfg(any(usbram_16x2_1024, usbram_32_1024))]
111const USBRAM_SIZE: usize = 1024; 111const USBRAM_SIZE: usize = 1024;
112#[cfg(usbram_32_2048)] 112#[cfg(usbram_32_2048)]
113const USBRAM_SIZE: usize = 2048; 113const USBRAM_SIZE: usize = 2048;
114 114
115#[cfg(not(usbram_32_2048))] 115#[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
116const USBRAM_ALIGN: usize = 2; 116const USBRAM_ALIGN: usize = 2;
117#[cfg(usbram_32_2048)] 117#[cfg(any(usbram_32_2048, usbram_32_1024))]
118const USBRAM_ALIGN: usize = 4; 118const USBRAM_ALIGN: usize = 4;
119 119
120const NEW_AW: AtomicWaker = AtomicWaker::new(); 120const NEW_AW: AtomicWaker = AtomicWaker::new();
@@ -159,7 +159,7 @@ fn calc_out_len(len: u16) -> (u16, u16) {
159 } 159 }
160} 160}
161 161
162#[cfg(not(usbram_32_2048))] 162#[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
163mod btable { 163mod btable {
164 use super::*; 164 use super::*;
165 165
@@ -180,7 +180,7 @@ mod btable {
180 USBRAM.mem(index * 4 + 3).read() 180 USBRAM.mem(index * 4 + 3).read()
181 } 181 }
182} 182}
183#[cfg(usbram_32_2048)] 183#[cfg(any(usbram_32_2048, usbram_32_1024))]
184mod btable { 184mod btable {
185 use super::*; 185 use super::*;
186 186
@@ -224,9 +224,9 @@ impl<T: Instance> EndpointBuffer<T> {
224 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); 224 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
225 val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); 225 val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]);
226 226
227 #[cfg(not(usbram_32_2048))] 227 #[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
228 let val = u16::from_le_bytes(val); 228 let val = u16::from_le_bytes(val);
229 #[cfg(usbram_32_2048)] 229 #[cfg(any(usbram_32_2048, usbram_32_1024))]
230 let val = u32::from_le_bytes(val); 230 let val = u32::from_le_bytes(val);
231 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); 231 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
232 } 232 }
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 72459d660..b48a408c4 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -3,6 +3,7 @@
3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks. 3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
4use core::cell::{RefCell, UnsafeCell}; 4use core::cell::{RefCell, UnsafeCell};
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::mem;
6use core::ops::{Deref, DerefMut}; 7use core::ops::{Deref, DerefMut};
7use core::task::Poll; 8use core::task::Poll;
8 9
@@ -134,6 +135,7 @@ where
134/// successfully locked the mutex, and grants access to the contents. 135/// successfully locked the mutex, and grants access to the contents.
135/// 136///
136/// Dropping it unlocks the mutex. 137/// Dropping it unlocks the mutex.
138#[clippy::has_significant_drop]
137pub struct MutexGuard<'a, M, T> 139pub struct MutexGuard<'a, M, T>
138where 140where
139 M: RawMutex, 141 M: RawMutex,
@@ -142,6 +144,25 @@ where
142 mutex: &'a Mutex<M, T>, 144 mutex: &'a Mutex<M, T>,
143} 145}
144 146
147impl<'a, M, T> MutexGuard<'a, M, T>
148where
149 M: RawMutex,
150 T: ?Sized,
151{
152 /// Returns a locked view over a portion of the locked data.
153 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
154 let mutex = this.mutex;
155 let value = fun(unsafe { &mut *this.mutex.inner.get() });
156 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
157 // locked state is being moved to the returned MappedMutexGuard.
158 mem::forget(this);
159 MappedMutexGuard {
160 state: &mutex.state,
161 value,
162 }
163 }
164}
165
145impl<'a, M, T> Drop for MutexGuard<'a, M, T> 166impl<'a, M, T> Drop for MutexGuard<'a, M, T>
146where 167where
147 M: RawMutex, 168 M: RawMutex,
@@ -180,3 +201,115 @@ where
180 unsafe { &mut *(self.mutex.inner.get()) } 201 unsafe { &mut *(self.mutex.inner.get()) }
181 } 202 }
182} 203}
204
205/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or
206/// [`MappedMutexGuard::map`].
207///
208/// This can be used to hold a subfield of the protected data.
209#[clippy::has_significant_drop]
210pub struct MappedMutexGuard<'a, M, T>
211where
212 M: RawMutex,
213 T: ?Sized,
214{
215 state: &'a BlockingMutex<M, RefCell<State>>,
216 value: *mut T,
217}
218
219impl<'a, M, T> MappedMutexGuard<'a, M, T>
220where
221 M: RawMutex,
222 T: ?Sized,
223{
224 /// Returns a locked view over a portion of the locked data.
225 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
226 let state = this.state;
227 let value = fun(unsafe { &mut *this.value });
228 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
229 // locked state is being moved to the returned MappedMutexGuard.
230 mem::forget(this);
231 MappedMutexGuard { state, value }
232 }
233}
234
235impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T>
236where
237 M: RawMutex,
238 T: ?Sized,
239{
240 type Target = T;
241 fn deref(&self) -> &Self::Target {
242 // Safety: the MutexGuard represents exclusive access to the contents
243 // of the mutex, so it's OK to get it.
244 unsafe { &*self.value }
245 }
246}
247
248impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T>
249where
250 M: RawMutex,
251 T: ?Sized,
252{
253 fn deref_mut(&mut self) -> &mut Self::Target {
254 // Safety: the MutexGuard represents exclusive access to the contents
255 // of the mutex, so it's OK to get it.
256 unsafe { &mut *self.value }
257 }
258}
259
260impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T>
261where
262 M: RawMutex,
263 T: ?Sized,
264{
265 fn drop(&mut self) {
266 self.state.lock(|s| {
267 let mut s = unwrap!(s.try_borrow_mut());
268 s.locked = false;
269 s.waker.wake();
270 })
271 }
272}
273
274unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T>
275where
276 M: RawMutex + Sync,
277 T: Send + ?Sized,
278{
279}
280
281unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T>
282where
283 M: RawMutex + Sync,
284 T: Sync + ?Sized,
285{
286}
287
288#[cfg(test)]
289mod tests {
290 use crate::blocking_mutex::raw::NoopRawMutex;
291 use crate::mutex::{Mutex, MutexGuard};
292
293 #[futures_test::test]
294 async fn mapped_guard_releases_lock_when_dropped() {
295 let mutex: Mutex<NoopRawMutex, [i32; 2]> = Mutex::new([0, 1]);
296
297 {
298 let guard = mutex.lock().await;
299 assert_eq!(*guard, [0, 1]);
300 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
301 assert_eq!(*mapped, 1);
302 *mapped = 2;
303 }
304
305 {
306 let guard = mutex.lock().await;
307 assert_eq!(*guard, [0, 2]);
308 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
309 assert_eq!(*mapped, 2);
310 *mapped = 3;
311 }
312
313 assert_eq!(*mutex.lock().await, [0, 3]);
314 }
315}
diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md
index 8852b0358..b9fb12d94 100644
--- a/embassy-time-queue-driver/README.md
+++ b/embassy-time-queue-driver/README.md
@@ -4,5 +4,5 @@ This crate contains the driver trait used by the [`embassy-time`](https://crates
4 4
5You should rarely need to use this crate directly. Only use it when implementing your own timer queue. 5You should rarely need to use this crate directly. Only use it when implementing your own timer queue.
6 6
7There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and 7There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and
8another in `embassy-executor` enabled by the `integrated-timers` feature. 8another in `embassy-executor` enabled by the `integrated-timers` feature.
diff --git a/embassy-time/README.md b/embassy-time/README.md
index f5d46df7b..6a4b049b4 100644
--- a/embassy-time/README.md
+++ b/embassy-time/README.md
@@ -5,7 +5,7 @@ Timekeeping, delays and timeouts.
5Timekeeping is done with elapsed time since system boot. Time is represented in 5Timekeeping is done with elapsed time since system boot. Time is represented in
6ticks, where the tick rate is defined either by the driver (in the case of a fixed-rate 6ticks, where the tick rate is defined either by the driver (in the case of a fixed-rate
7tick) or chosen by the user with a [tick rate](#tick-rate) feature. The chosen 7tick) or chosen by the user with a [tick rate](#tick-rate) feature. The chosen
8tick rate applies to everything in `embassy-time` and thus determines the maximum 8tick rate applies to everything in `embassy-time` and thus determines the maximum
9timing resolution of <code>(1 / tick_rate) seconds</code>. 9timing resolution of <code>(1 / tick_rate) seconds</code>.
10 10
11Tick counts are 64 bits. The default tick rate of 1Mhz supports 11Tick counts are 64 bits. The default tick rate of 1Mhz supports
diff --git a/embassy-usb/README.md b/embassy-usb/README.md
index d2adae4f5..400fc6695 100644
--- a/embassy-usb/README.md
+++ b/embassy-usb/README.md
@@ -34,8 +34,8 @@ They can be set in two ways:
34- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and 34- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and
35use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values 35use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values
36is available, check `Cargo.toml` for the list. 36is available, check `Cargo.toml` for the list.
37- Via environment variables at build time: set the variable named `EMBASSY_USB_<value>`. For example 37- Via environment variables at build time: set the variable named `EMBASSY_USB_<value>`. For example
38`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. 38`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
39Any value can be set, unlike with Cargo features. 39Any value can be set, unlike with Cargo features.
40 40
41Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting 41Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index c06107396..387b780de 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -38,11 +38,12 @@ pub struct Config<'a> {
38 38
39 /// Maximum packet size in bytes for the control endpoint 0. 39 /// Maximum packet size in bytes for the control endpoint 0.
40 /// 40 ///
41 /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default 41 /// Valid values depend on the speed at which the bus is enumerated.
42 /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in 42 /// - low speed: 8
43 /// which case using a larger packet size may be more efficient. 43 /// - full speed: 8, 16, 32, or 64
44 /// - high speed: 64
44 /// 45 ///
45 /// Default: 8 bytes 46 /// Default: 64 bytes
46 pub max_packet_size_0: u8, 47 pub max_packet_size_0: u8,
47 48
48 /// Manufacturer name string descriptor. 49 /// Manufacturer name string descriptor.
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
index 3de3171cd..cd6c0bc84 100644
--- a/examples/boot/bootloader/stm32-dual-bank/README.md
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -2,16 +2,16 @@
2 2
3## Overview 3## Overview
4 4
5This bootloader leverages `embassy-boot` to interact with the flash. 5This bootloader leverages `embassy-boot` to interact with the flash.
6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. 6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. 7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
8 8
9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. 9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
10 10
11## Memory Configuration 11## Memory Configuration
12 12
13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. 13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. 14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
15 15
16### Symbol Definitions 16### Symbol Definitions
17 17
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 585349506..0f58f143c 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "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.1.0", path = "../../embassy-usb-logger" }
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index c2fb143cd..a5a4186ea 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC; 7use embassy_stm32::peripherals::ADC;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); 21 let mut adc = Adc::new(p.ADC, Irqs);
22 adc.set_sample_time(SampleTime::CYCLES71_5); 22 adc.set_sample_time(SampleTime::CYCLES71_5);
23 let mut pin = p.PA1; 23 let mut pin = p.PA1;
24 24
25 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref();
26 let vrefint_sample = adc.read(&mut vrefint).await; 26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| { 27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf 28 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 1440460a9..541ff159e 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
6use embassy_stm32::adc::Adc; 6use embassy_stm32::adc::Adc;
7use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 21 let mut adc = Adc::new(p.ADC1);
22 let mut pin = p.PB1; 22 let mut pin = p.PB1;
23 23
24 let mut vrefint = adc.enable_vref(&mut Delay); 24 let mut vrefint = adc.enable_vref();
25 let vrefint_sample = adc.read(&mut vrefint).await; 25 let vrefint_sample = adc.read(&mut vrefint).await;
26 let convert_to_millivolts = |sample| { 26 let convert_to_millivolts = |sample| {
27 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf 27 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 5234e53b9..573a49f19 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml
index caf947be6..f38c90a31 100644
--- a/examples/stm32f334/.cargo/config.toml
+++ b/examples/stm32f334/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list`
3runner = "probe-run --chip STM32F334R8" 3runner = "probe-rs run --chip STM32F334R8"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
index bd126ce68..0528a9637 100644
--- a/examples/stm32f334/src/bin/adc.rs
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{adc, bind_interrupts, Config}; 9use embassy_stm32::{adc, bind_interrupts, Config};
10use embassy_time::{Delay, Timer}; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13bind_interrupts!(struct Irqs { 13bind_interrupts!(struct Irqs {
@@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! {
38 38
39 info!("create adc..."); 39 info!("create adc...");
40 40
41 let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); 41 let mut adc = Adc::new(p.ADC1, Irqs);
42 42
43 adc.set_sample_time(SampleTime::CYCLES601_5); 43 adc.set_sample_time(SampleTime::CYCLES601_5);
44 44
45 info!("enable vrefint..."); 45 info!("enable vrefint...");
46 46
47 let mut vrefint = adc.enable_vref(&mut Delay); 47 let mut vrefint = adc.enable_vref();
48 let mut temperature = adc.enable_temperature(); 48 let mut temperature = adc.enable_temperature();
49 49
50 loop { 50 loop {
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index a5c710aa2..2dbf1bdab 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain};
8use embassy_stm32::peripherals::ADC2; 8use embassy_stm32::peripherals::ADC2;
9use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
10use embassy_stm32::{adc, bind_interrupts, Config}; 10use embassy_stm32::{adc, bind_interrupts, Config};
11use embassy_time::{Delay, Timer}; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! {
39 39
40 info!("create adc..."); 40 info!("create adc...");
41 41
42 let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); 42 let mut adc = Adc::new(p.ADC2, Irqs);
43 let mut opamp = OpAmp::new(p.OPAMP2); 43 let mut opamp = OpAmp::new(p.OPAMP2);
44 44
45 adc.set_sample_time(SampleTime::CYCLES601_5); 45 adc.set_sample_time(SampleTime::CYCLES601_5);
46 46
47 info!("enable vrefint..."); 47 info!("enable vrefint...");
48 48
49 let mut vrefint = adc.enable_vref(&mut Delay); 49 let mut vrefint = adc.enable_vref();
50 let mut temperature = adc.enable_temperature(); 50 let mut temperature = adc.enable_temperature();
51 let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); 51 let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1);
52 52
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 699c29c05..9473b7b7f 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let mut delay = Delay; 16 let mut delay = Delay;
17 let mut adc = Adc::new(p.ADC1, &mut delay); 17 let mut adc = Adc::new(p.ADC1);
18 let mut pin = p.PC1; 18 let mut pin = p.PC1;
19 19
20 let mut vrefint = adc.enable_vrefint(); 20 let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
index 4b5da774d..4a96357a4 100644
--- a/examples/stm32f4/src/bin/i2c.rs
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -3,35 +3,19 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::{Error, I2c}; 6use embassy_stm32::i2c::{Error, I2c};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 info!("Hello world!"); 15 info!("Hello world!");
23 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
24 17
25 let mut i2c = I2c::new( 18 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 19
36 let mut data = [0u8; 1]; 20 let mut data = [0u8; 1];
37 21
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index dc9141c62..970d819fc 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let mut spi_config = Config::default(); 17 let mut spi_config = Config::default();
19 spi_config.frequency = Hertz(1_000_000); 18 spi_config.frequency = Hertz(1_000_000);
20 19
21 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 20 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
22 21
23 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
24 23
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 40d9d70f1..991bf6673 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::usart::{Config, Uart}; 6use embassy_stm32::usart::{Config, Uart};
8use embassy_stm32::{bind_interrupts, peripherals, usart}; 7use embassy_stm32::{bind_interrupts, peripherals, usart};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +18,7 @@ fn main() -> ! {
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
20 19
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); 21 let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap();
23 22
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 24 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index dd6de599c..aaf8d6c4f 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
index a280a3b77..e00d14327 100644
--- a/examples/stm32f4/src/bin/ws2812_spi.rs
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -8,13 +8,13 @@
8// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. 8// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA.
9// 9//
10// Warning: 10// Warning:
11// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. 11// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
12 12
13#![no_std] 13#![no_std]
14#![no_main] 14#![no_main]
15 15
16use embassy_stm32::spi;
16use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
17use embassy_stm32::{dma, spi};
18use embassy_time::{Duration, Ticker, Timer}; 18use embassy_time::{Duration, Ticker, Timer};
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
@@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
78 spi_config.frequency = khz(12_800); 78 spi_config.frequency = khz(12_800);
79 79
80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered 80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered
81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); 81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config);
82 82
83 // flip color at 2 Hz 83 // flip color at 2 Hz
84 let mut ticker = Ticker::every(Duration::from_millis(500)); 84 let mut ticker = Ticker::every(Duration::from_millis(500));
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index f8d7b691f..641157960 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::Adc; 6use embassy_stm32::adc::Adc;
7use embassy_time::{Delay, Timer}; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let mut adc = Adc::new(p.ADC1, &mut Delay); 15 let mut adc = Adc::new(p.ADC1);
16 let mut pin = p.PA3; 16 let mut pin = p.PA3;
17 17
18 let mut vrefint = adc.enable_vrefint(); 18 let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index fb604b34f..47456adf2 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs {
19async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); 21 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap();
23 22
24 for n in 0u32.. { 23 for n in 0u32.. {
25 let mut s: String<128> = String::new(); 24 let mut s: String<128> = String::new();
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index c5ea51721..2deee271d 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::word::U5; 6use embassy_stm32::dma::word::U5;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
77 76
78 let mut config = Config::default(); 77 let mut config = Config::default();
79 config.frequency = Hertz(4_000_000); 78 config.frequency = Hertz(4_000_000);
80 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); 79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config);
81 80
82 let mut neopixels = Ws2812::new(); 81 let mut neopixels = Ws2812::new();
83 82
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index ae64bc8e4..3de38cbd6 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -5,7 +5,7 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::Config; 7use embassy_stm32::Config;
8use embassy_time::{Delay, Timer}; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
@@ -28,8 +28,8 @@ async fn main(_spawner: Spawner) {
28 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
29 info!("Hello World!"); 29 info!("Hello World!");
30 30
31 let mut adc = Adc::new(p.ADC2, &mut Delay); 31 let mut adc = Adc::new(p.ADC2);
32 adc.set_sample_time(SampleTime::CYCLES32_5); 32 adc.set_sample_time(SampleTime::CYCLES24_5);
33 33
34 loop { 34 loop {
35 let measured = adc.read(&mut p.PA7); 35 let measured = adc.read(&mut p.PA7);
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h5/src/bin/usart.rs
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
index caae0dd18..c644e84bd 100644
--- a/examples/stm32h5/src/bin/usart_dma.rs
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index 92047de8d..77b4caa9e 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; 7use embassy_stm32::peripherals::UART7;
8use embassy_stm32::usart::{Config, Uart, UartRx}; 8use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 16});
17 17
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 18static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 19
32#[embassy_executor::main] 20#[embassy_executor::main]
@@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
50} 38}
51 39
52#[embassy_executor::task] 40#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { 41async fn reader(mut rx: UartRx<'static, UART7, Async>) {
54 let mut buf = [0; 8]; 42 let mut buf = [0; 8];
55 loop { 43 loop {
56 info!("reading..."); 44 info!("reading...");
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index a5594d10c..0009103d1 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -5,7 +5,7 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::Config; 7use embassy_stm32::Config;
8use embassy_time::{Delay, Timer}; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
44 44
45 info!("Hello World!"); 45 info!("Hello World!");
46 46
47 let mut adc = Adc::new(p.ADC3, &mut Delay); 47 let mut adc = Adc::new(p.ADC3);
48 48
49 adc.set_sample_time(SampleTime::CYCLES32_5); 49 adc.set_sample_time(SampleTime::CYCLES32_5);
50 50
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index aed27723a..aaebdc346 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -7,7 +7,7 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3; 11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
13use embassy_stm32::{spi, Config}; 13use embassy_stm32::{spi, Config};
@@ -16,7 +16,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18#[embassy_executor::task] 18#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { 19async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) {
20 for n in 0u32.. { 20 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 21 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
@@ -62,7 +62,7 @@ fn main() -> ! {
62 let mut spi_config = spi::Config::default(); 62 let mut spi_config = spi::Config::default();
63 spi_config.frequency = mhz(1); 63 spi_config.frequency = mhz(1);
64 64
65 let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); 65 let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
66 66
67 let executor = EXECUTOR.init(Executor::new()); 67 let executor = EXECUTOR.init(Executor::new());
68 68
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 54d4d7656..3d3c724eb 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -7,15 +7,15 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config}; 12use embassy_stm32::{peripherals, 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, SPI3, DMA1_CH3, DMA1_CH4>) { 18async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, 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/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index ae1f3a2e9..6f340d40a 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index b98c40877..4ad8e77ce 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{DMA1_CH1, UART7}; 7use embassy_stm32::peripherals::UART7;
8use embassy_stm32::usart::{Config, Uart, UartRx}; 8use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 16});
17 17
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 18static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 19
32#[embassy_executor::main] 20#[embassy_executor::main]
@@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
50} 38}
51 39
52#[embassy_executor::task] 40#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { 41async fn reader(mut rx: UartRx<'static, UART7, Async>) {
54 let mut buf = [0; 8]; 42 let mut buf = [0; 8];
55 loop { 43 loop {
56 info!("reading..."); 44 info!("reading...");
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
index 97d41ca4b..507c3204a 100644
--- a/examples/stm32l0/src/bin/adc.rs
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC; 7use embassy_stm32::peripherals::ADC;
8use embassy_stm32::{adc, bind_interrupts}; 8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer}; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); 21 let mut adc = Adc::new(p.ADC, Irqs);
22 adc.set_sample_time(SampleTime::CYCLES79_5); 22 adc.set_sample_time(SampleTime::CYCLES79_5);
23 let mut pin = p.PA1; 23 let mut pin = p.PA1;
24 24
25 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref();
26 let vrefint_sample = adc.read(&mut vrefint).await; 26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| { 27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf 28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index f23a537b8..8e0cfdedb 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs
index 8be686c5a..eabf1bac2 100644
--- a/examples/stm32l1/src/bin/spi.rs
+++ b/examples/stm32l1/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index db3a7ceff..83fc6d6f8 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,7 @@
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-run --chip STM32L4S5QI" 5runner = "probe-rs run --chip STM32L4S5QI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index a9f4604aa..7a89334e0 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution}; 5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::Config; 6use embassy_stm32::Config;
7use embassy_time::Delay;
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
9 8
10#[cortex_m_rt::entry] 9#[cortex_m_rt::entry]
@@ -18,7 +17,7 @@ fn main() -> ! {
18 } 17 }
19 let p = embassy_stm32::init(config); 18 let p = embassy_stm32::init(config);
20 19
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 20 let mut adc = Adc::new(p.ADC1);
22 //adc.enable_vref(); 21 //adc.enable_vref();
23 adc.set_resolution(Resolution::BITS8); 22 adc.set_resolution(Resolution::BITS8);
24 let mut channel = p.PC0; 23 let mut channel = p.PC0;
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index f553deb82..2861bc091 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -3,33 +3,17 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c; 6use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new( 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
24 p.I2C2,
25 p.PB10,
26 p.PB11,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33 17
34 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index 1b8652bcc..a014b23e0 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -4,34 +4,18 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::I2c; 7use embassy_stm32::i2c::I2c;
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_stm32::{bind_interrupts, i2c, peripherals};
11use embedded_hal_async::i2c::I2c as I2cTrait; 9use embedded_hal_async::i2c::I2c as I2cTrait;
12use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
13 11
14const ADDRESS: u8 = 0x5F; 12const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
16 14
17bind_interrupts!(struct Irqs {
18 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
19 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
20});
21
22#[embassy_executor::main] 15#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
24 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
25 let i2c = I2c::new( 18 let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 let mut i2c = BlockingAsync::new(i2c); 19 let mut i2c = BlockingAsync::new(i2c);
36 20
37 let mut data = [0u8; 1]; 21 let mut data = [0u8; 1];
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 77aa929ab..694629ede 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
23use embassy_futures::yield_now; 23use embassy_futures::yield_now;
24use embassy_net::tcp::TcpSocket; 24use embassy_net::tcp::TcpSocket;
25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; 25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
26use embassy_net_adin1110::{Device, Runner, ADIN1110};
27use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
26use embassy_time::{Delay, Duration, Ticker, Timer}; 34use embassy_time::{Delay, Duration, Ticker, Timer};
27use embedded_hal_async::i2c::I2c as I2cBus; 35use embedded_hal_async::i2c::I2c as I2cBus;
36use embedded_hal_bus::spi::ExclusiveDevice;
28use embedded_io::Write as bWrite; 37use embedded_io::Write as bWrite;
29use embedded_io_async::Write; 38use embedded_io_async::Write;
30use hal::gpio::{Input, Level, Output, Speed};
31use hal::i2c::{self, I2c};
32use hal::rng::{self, Rng};
33use hal::{bind_interrupts, exti, pac, peripherals};
34use heapless::Vec; 39use heapless::Vec;
40use panic_probe as _;
35use rand::RngCore; 41use rand::RngCore;
36use static_cell::StaticCell; 42use static_cell::StaticCell;
37use {embassy_stm32 as hal, panic_probe as _};
38 43
39bind_interrupts!(struct Irqs { 44bind_interrupts!(struct Irqs {
40 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; 45 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
@@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
42 RNG => rng::InterruptHandler<peripherals::RNG>; 47 RNG => rng::InterruptHandler<peripherals::RNG>;
43}); 48});
44 49
45use embassy_net_adin1110::{Device, Runner, ADIN1110};
46use embedded_hal_bus::spi::ExclusiveDevice;
47use hal::gpio::Pull;
48use hal::i2c::Config as I2C_Config;
49use hal::spi::{Config as SPI_Config, Spi};
50use hal::time::Hertz;
51
52// Basic settings 50// Basic settings
53// MAC-address used by the adin1110 51// MAC-address used by the adin1110
54const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; 52const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
@@ -57,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
57// Listen port for the webserver 55// Listen port for the webserver
58const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
59 57
60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; 58pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>;
61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
62pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
63pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
64pub type Adin1110T = ADIN1110<SpeSpiCs>; 62pub type Adin1110T = ADIN1110<SpeSpiCs>;
65pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; 63pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>;
66 64
67static TEMP: AtomicI32 = AtomicI32::new(0); 65static TEMP: AtomicI32 = AtomicI32::new(0);
68 66
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 6653e4516..5693a3765 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::gpio::{Level, Output, Speed}; 5use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::spi::{Config, Spi}; 6use embassy_stm32::spi::{Config, Spi};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ fn main() -> ! {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
21 20
22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
index 68dbb70ad..1f1089101 100644
--- a/examples/stm32l4/src/bin/spi_blocking_async.rs
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 7use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::spi::{Config, Spi}; 8use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
19 let mut spi_config = Config::default(); 18 let mut spi_config = Config::default();
20 spi_config.frequency = Hertz(1_000_000); 19 spi_config.frequency = Hertz(1_000_000);
21 20
22 let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 21 let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
23 22
24 let mut spi = BlockingAsync::new(spi); 23 let mut spi = BlockingAsync::new(spi);
25 24
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 7bab23950..d9b388026 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::usart::{Config, Uart}; 5use embassy_stm32::usart::{Config, Uart};
7use embassy_stm32::{bind_interrupts, peripherals, usart}; 6use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
19 18
20 let config = Config::default(); 19 let config = Config::default();
21 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); 20 let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap();
22 21
23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
24 info!("wrote Hello, starting echo"); 23 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 031888f70..b4f7a1643 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml
new file mode 100644
index 000000000..688347084
--- /dev/null
+++ b/examples/stm32u0/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip stm32u083rctx"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
new file mode 100644
index 000000000..5868372dd
--- /dev/null
+++ b/examples/stm32u0/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2edition = "2021"
3name = "embassy-stm32u0-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23heapless = { version = "0.8", default-features = false }
24
25micromath = "2.0.0"
26chrono = { version = "0.4.38", default-features = false }
27
28[profile.release]
29debug = 2
diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32u0/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/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
new file mode 100644
index 000000000..4410448f1
--- /dev/null
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::Config;
7use embassy_time::Duration;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 }
19 let p = embassy_stm32::init(config);
20
21 let mut adc = Adc::new(p.ADC1);
22 adc.set_resolution(Resolution::BITS8);
23 let mut channel = p.PC0;
24
25 loop {
26 let v = adc.read(&mut channel);
27 info!("--> {}", v);
28 embassy_time::block_for(Duration::from_millis(200));
29 }
30}
diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs
new file mode 100644
index 000000000..90e479aae
--- /dev/null
+++ b/examples/stm32u0/src/bin/blinky.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
16
17 loop {
18 info!("high");
19 led.set_high();
20 Timer::after_millis(300).await;
21
22 info!("low");
23 led.set_low();
24 Timer::after_millis(300).await;
25 }
26}
diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs
new file mode 100644
index 000000000..8017f0274
--- /dev/null
+++ b/examples/stm32u0/src/bin/button.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::entry;
5use defmt::*;
6use embassy_stm32::gpio::{Input, Pull};
7use {defmt_rtt as _, panic_probe as _};
8
9#[entry]
10fn main() -> ! {
11 info!("Hello World!");
12
13 let p = embassy_stm32::init(Default::default());
14
15 let button = Input::new(p.PC13, Pull::Up);
16
17 loop {
18 if button.is_high() {
19 info!("high");
20 } else {
21 info!("low");
22 }
23 }
24}
diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs
new file mode 100644
index 000000000..34a08bbc6
--- /dev/null
+++ b/examples/stm32u0/src/bin/button_exti.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16
17 info!("Press the USER button...");
18
19 loop {
20 button.wait_for_falling_edge().await;
21 info!("Pressed!");
22 button.wait_for_rising_edge().await;
23 info!("Released!");
24 }
25}
diff --git a/examples/stm32u0/src/bin/crc.rs b/examples/stm32u0/src/bin/crc.rs
new file mode 100644
index 000000000..d1b545d5b
--- /dev/null
+++ b/examples/stm32u0/src/bin/crc.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0
15 let mut crc = Crc::new(
16 p.CRC,
17 unwrap!(Config::new(
18 InputReverseConfig::Byte,
19 true,
20 PolySize::Width32,
21 0xFFFFFFFF,
22 0x04C11DB7
23 )),
24 );
25
26 let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF;
27
28 defmt::assert_eq!(output, 0x33F0E26B);
29
30 cortex_m::asm::bkpt();
31}
diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs
new file mode 100644
index 000000000..fdbf1d374
--- /dev/null
+++ b/examples/stm32u0/src/bin/dac.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::dac::{DacCh1, Value};
6use embassy_stm32::dma::NoDma;
7use {defmt_rtt as _, panic_probe as _};
8
9#[cortex_m_rt::entry]
10fn main() -> ! {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
15
16 loop {
17 for v in 0..=255 {
18 dac.set(Value::Bit8(to_sine_wave(v)));
19 }
20 }
21}
22
23use micromath::F32Ext;
24
25fn to_sine_wave(v: u8) -> u8 {
26 if v >= 128 {
27 // top half
28 let r = 3.14 * ((v - 128) as f32 / 128.0);
29 (r.sin() * 128.0 + 127.0) as u8
30 } else {
31 // bottom half
32 let r = 3.14 + 3.14 * (v as f32 / 128.0);
33 (r.sin() * 128.0 + 127.0) as u8
34 }
35}
diff --git a/examples/stm32u0/src/bin/flash.rs b/examples/stm32u0/src/bin/flash.rs
new file mode 100644
index 000000000..01b80a76b
--- /dev/null
+++ b/examples/stm32u0/src/bin/flash.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let addr: u32 = 0x40000 - 2 * 1024;
15
16 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
17
18 info!("Reading...");
19 let mut buf = [0u8; 32];
20 unwrap!(f.blocking_read(addr, &mut buf));
21 info!("Read: {=[u8]:x}", buf);
22 info!("Erasing...");
23 unwrap!(f.blocking_erase(addr, addr + 2 * 1024));
24
25 info!("Reading...");
26 let mut buf = [0u8; 32];
27 unwrap!(f.blocking_read(addr, &mut buf));
28 info!("Read after erase: {=[u8]:x}", buf);
29
30 info!("Writing...");
31 unwrap!(f.blocking_write(
32 addr,
33 &[
34 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
35 30, 31, 32
36 ]
37 ));
38
39 info!("Reading...");
40 let mut buf = [0u8; 32];
41 unwrap!(f.blocking_read(addr, &mut buf));
42 info!("Read: {=[u8]:x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/i2c.rs b/examples/stm32u0/src/bin/i2c.rs
new file mode 100644
index 000000000..2861bc091
--- /dev/null
+++ b/examples/stm32u0/src/bin/i2c.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::I2c;
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10const ADDRESS: u8 = 0x5F;
11const WHOAMI: u8 = 0x0F;
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default());
16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
17
18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
20 info!("Whoami: {}", data[0]);
21}
diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs
new file mode 100644
index 000000000..89445b042
--- /dev/null
+++ b/examples/stm32u0/src/bin/rng.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rcc::mux::Clk48sel;
7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 RNG_CRYP => rng::InterruptHandler<peripherals::RNG>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let mut config = Config::default();
18 {
19 use embassy_stm32::rcc::*;
20 config.rcc.hsi = true;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI, // 16 MHz
23 prediv: PllPreDiv::DIV1,
24 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
25 divp: None,
26 divq: None,
27 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
28 });
29 config.rcc.sys = Sysclk::PLL1_R;
30 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG
31 config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want)
32 }
33
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 let mut rng = Rng::new(p.RNG, Irqs);
39
40 let mut buf = [0u8; 16];
41 unwrap!(rng.async_fill_bytes(&mut buf).await);
42 info!("random bytes: {:02x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs
new file mode 100644
index 000000000..72fa0fde4
--- /dev/null
+++ b/examples/stm32u0/src/bin/rtc.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3
4use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::Config;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.sys = Sysclk::PLL1_R;
18 config.rcc.hsi = true;
19 config.rcc.pll = Some(Pll {
20 source: PllSource::HSI, // 16 MHz
21 prediv: PllPreDiv::DIV1,
22 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
23 divp: None,
24 divq: None,
25 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
26 });
27 config.rcc.ls = LsConfig::default();
28 }
29
30 let p = embassy_stm32::init(config);
31
32 info!("Hello World!");
33
34 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
35 .unwrap()
36 .and_hms_opt(10, 30, 15)
37 .unwrap();
38
39 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
40 info!("Got RTC! {:?}", now.and_utc().timestamp());
41
42 rtc.set_datetime(now.into()).expect("datetime not set");
43
44 // In reality the delay would be much longer
45 Timer::after_millis(20000).await;
46
47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.and_utc().timestamp());
49}
diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs
new file mode 100644
index 000000000..5693a3765
--- /dev/null
+++ b/examples/stm32u0/src/bin/spi.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::gpio::{Level, Output, Speed};
6use embassy_stm32::spi::{Config, Spi};
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let p = embassy_stm32::init(Default::default());
15
16 let mut spi_config = Config::default();
17 spi_config.frequency = Hertz(1_000_000);
18
19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
20
21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
22
23 loop {
24 let mut buf = [0x0Au8; 4];
25 cs.set_low();
26 unwrap!(spi.blocking_transfer_in_place(&mut buf));
27 cs.set_high();
28 info!("xfer {=[u8]:x}", buf);
29 }
30}
diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs
new file mode 100644
index 000000000..037a5c833
--- /dev/null
+++ b/examples/stm32u0/src/bin/usart.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::usart::{Config, Uart};
6use {defmt_rtt as _, panic_probe as _};
7
8#[cortex_m_rt::entry]
9fn main() -> ! {
10 info!("Hello World!");
11
12 let p = embassy_stm32::init(Default::default());
13
14 let config = Config::default();
15 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
16
17 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
18 info!("wrote Hello, starting echo");
19
20 let mut buf = [0u8; 1];
21 loop {
22 unwrap!(usart.blocking_read(&mut buf));
23 unwrap!(usart.blocking_write(&buf));
24 }
25}
diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs
new file mode 100644
index 000000000..9b38fd5dc
--- /dev/null
+++ b/examples/stm32u0/src/bin/usb_serial.rs
@@ -0,0 +1,109 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner;
7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder;
12use futures::future::join;
13use panic_probe as _;
14
15bind_interrupts!(struct Irqs {
16 USB_DRD_FS => usb::InterruptHandler<peripherals::USB>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let mut config = Config::default();
22 {
23 use embassy_stm32::rcc::*;
24 config.rcc.hsi = true;
25 config.rcc.pll = Some(Pll {
26 source: PllSource::HSI, // 16 MHz
27 prediv: PllPreDiv::DIV1,
28 mul: PllMul::MUL7,
29 divp: None,
30 divq: None,
31 divr: Some(PllRDiv::DIV2), // 56 MHz
32 });
33 config.rcc.sys = Sysclk::PLL1_R;
34 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
35 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK
36 }
37
38 let p = embassy_stm32::init(config);
39
40 info!("Hello World!");
41
42 // Create the driver, from the HAL.
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44
45 // Create embassy-usb Config
46 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
47 //config.max_packet_size_0 = 64;
48
49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors.
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 7];
54
55 let mut state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut config_descriptor,
61 &mut bos_descriptor,
62 &mut [], // no msos descriptors
63 &mut control_buf,
64 );
65
66 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
68
69 // Build the builder.
70 let mut usb = builder.build();
71
72 // Run the USB device.
73 let usb_fut = usb.run();
74
75 // Do stuff with the class!
76 let echo_fut = async {
77 loop {
78 class.wait_connection().await;
79 info!("Connected");
80 let _ = echo(&mut class).await;
81 info!("Disconnected");
82 }
83 };
84
85 // Run everything concurrently.
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
87 join(usb_fut, echo_fut).await;
88}
89
90struct Disconnected {}
91
92impl From<EndpointError> for Disconnected {
93 fn from(val: EndpointError) -> Self {
94 match val {
95 EndpointError::BufferOverflow => panic!("Buffer overflow"),
96 EndpointError::Disabled => Disconnected {},
97 }
98 }
99}
100
101async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
102 let mut buf = [0; 64];
103 loop {
104 let n = class.read_packet(&mut buf).await?;
105 let data = &buf[..n];
106 info!("data: {:x}", data);
107 class.write_packet(data).await?;
108 }
109}
diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs
new file mode 100644
index 000000000..f6276e2e9
--- /dev/null
+++ b/examples/stm32u0/src/bin/wdt.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
17
18 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
19 wdt.unleash();
20
21 let mut i = 0;
22
23 loop {
24 info!("high");
25 led.set_high();
26 Timer::after_millis(300).await;
27
28 info!("low");
29 led.set_low();
30 Timer::after_millis(300).await;
31
32 // Pet watchdog for 5 iterations and then stop.
33 // MCU should restart in 1 second after the last pet.
34 if i < 5 {
35 info!("Petting watchdog");
36 wdt.pet();
37 }
38
39 i += 1;
40 }
41}
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 03294339d..01320b88d 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -24,5 +24,9 @@ heapless = { version = "0.8", default-features = false }
24 24
25micromath = "2.0.0" 25micromath = "2.0.0"
26 26
27[features]
28## Use secure registers when TrustZone is enabled
29trustzone-secure = ["embassy-stm32/trustzone-secure"]
30
27[profile.release] 31[profile.release]
28debug = 2 32debug = 2
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
index e376c6bc8..19a78eac9 100644
--- a/examples/stm32u5/src/bin/i2c.rs
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -3,33 +3,17 @@
3 3
4use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c; 6use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const HTS221_ADDRESS: u8 = 0x5F; 10const HTS221_ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new( 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default());
24 p.I2C2,
25 p.PH4,
26 p.PH5,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33 17
34 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 51c499ee7..8b6d6d754 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index 98696fd2b..ac160b995 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2024-03-20" 2channel = "nightly-2024-04-14"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs
index 9d64742df..06501ab14 100644
--- a/tests/stm32/src/bin/dac.rs
+++ b/tests/stm32/src/bin/dac.rs
@@ -13,7 +13,7 @@ use embassy_executor::Spawner;
13use embassy_stm32::adc::Adc; 13use embassy_stm32::adc::Adc;
14use embassy_stm32::dac::{DacCh1, Value}; 14use embassy_stm32::dac::{DacCh1, Value};
15use embassy_stm32::dma::NoDma; 15use embassy_stm32::dma::NoDma;
16use embassy_time::{Delay, Timer}; 16use embassy_time::Timer;
17use micromath::F32Ext; 17use micromath::F32Ext;
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; 28 let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
29 29
30 let mut dac = DacCh1::new(dac, NoDma, dac_pin); 30 let mut dac = DacCh1::new(dac, NoDma, dac_pin);
31 let mut adc = Adc::new(adc, &mut Delay); 31 let mut adc = Adc::new(adc);
32 32
33 #[cfg(feature = "stm32h755zi")] 33 #[cfg(feature = "stm32h755zi")]
34 let normalization_factor = 256; 34 let normalization_factor = 256;
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index b0bdd477f..59cb0cfd3 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -6,7 +6,6 @@ mod common;
6use common::*; 6use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::spi::{self, Spi}; 9use embassy_stm32::spi::{self, Spi};
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
12 11
@@ -23,11 +22,11 @@ async fn main(_spawner: Spawner) {
23 let mut spi_config = spi::Config::default(); 22 let mut spi_config = spi::Config::default();
24 spi_config.frequency = Hertz(1_000_000); 23 spi_config.frequency = Hertz(1_000_000);
25 24
26 let mut spi = Spi::new( 25 let mut spi = Spi::new_blocking(
27 spi, sck, // Arduino D13 26 spi, sck, // Arduino D13
28 mosi, // Arduino D11 27 mosi, // Arduino D11
29 miso, // Arduino D12 28 miso, // Arduino D12
30 NoDma, NoDma, spi_config, 29 spi_config,
31 ); 30 );
32 31
33 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 32 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 9b20eb784..a6e34674d 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -6,7 +6,6 @@ mod common;
6use common::*; 6use common::*;
7use defmt::{assert, assert_eq, unreachable}; 7use defmt::{assert, assert_eq, unreachable};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; 9use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
11use embassy_time::{block_for, Duration, Instant}; 10use embassy_time::{block_for, Duration, Instant};
12 11
@@ -20,11 +19,10 @@ async fn main(_spawner: Spawner) {
20 let mut usart = peri!(p, UART); 19 let mut usart = peri!(p, UART);
21 let mut rx = peri!(p, UART_RX); 20 let mut rx = peri!(p, UART_RX);
22 let mut tx = peri!(p, UART_TX); 21 let mut tx = peri!(p, UART_TX);
23 let irq = irqs!(UART);
24 22
25 { 23 {
26 let config = Config::default(); 24 let config = Config::default();
27 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); 25 let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
28 26
29 // We can't send too many bytes, they have to fit in the FIFO. 27 // We can't send too many bytes, they have to fit in the FIFO.
30 // This is because we aren't sending+receiving at the same time. 28 // This is because we aren't sending+receiving at the same time.
@@ -40,7 +38,7 @@ async fn main(_spawner: Spawner) {
40 // Test error handling with with an overflow error 38 // Test error handling with with an overflow error
41 { 39 {
42 let config = Config::default(); 40 let config = Config::default();
43 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); 41 let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
44 42
45 // Send enough bytes to fill the RX FIFOs off all USART versions. 43 // Send enough bytes to fill the RX FIFOs off all USART versions.
46 let data = [0; 64]; 44 let data = [0; 64];
@@ -70,7 +68,7 @@ async fn main(_spawner: Spawner) {
70 68
71 let mut config = Config::default(); 69 let mut config = Config::default();
72 config.baudrate = baudrate; 70 config.baudrate = baudrate;
73 let mut usart = match Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config) { 71 let mut usart = match Uart::new_blocking(&mut usart, &mut rx, &mut tx, config) {
74 Ok(x) => x, 72 Ok(x) => x,
75 Err(ConfigError::BaudrateTooHigh) => { 73 Err(ConfigError::BaudrateTooHigh) => {
76 info!("baudrate too high"); 74 info!("baudrate too high");
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index 0c110421d..908452eaf 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -8,6 +8,7 @@ mod common;
8use common::*; 8use common::*;
9use defmt::{assert_eq, panic}; 9use defmt::{assert_eq, panic};
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_stm32::mode::Async;
11use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; 12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
12use embassy_time::Timer; 13use embassy_time::Timer;
13use rand_chacha::ChaCha8Rng; 14use rand_chacha::ChaCha8Rng;
@@ -51,7 +52,7 @@ async fn main(spawner: Spawner) {
51} 52}
52 53
53#[embassy_executor::task] 54#[embassy_executor::task]
54async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) { 55async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
55 // workaround https://github.com/embassy-rs/embassy/issues/1426 56 // workaround https://github.com/embassy-rs/embassy/issues/1426
56 Timer::after_millis(100).await; 57 Timer::after_millis(100).await;
57 58