aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-11 07:36:23 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-11 07:36:23 +0200
commitd8c92c53d647b170cb49ede1b608e58c2dd676d2 (patch)
treed4fb6ee79087b598cad5d5fe5ce023626d4a21be
parent05b2b2fb5f0f8d52689057c22dd2fa026d6cc796 (diff)
parent1f25d2ba8335300368b32f9ceedf163376dfdb6f (diff)
Merge remote-tracking branch 'upstream/master' into u32-partition
-rwxr-xr-xci.sh5
-rw-r--r--embassy-boot/boot/Cargo.toml4
-rw-r--r--embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs30
-rw-r--r--embassy-boot/boot/src/digest_adapters/mod.rs5
-rw-r--r--embassy-boot/boot/src/digest_adapters/salty.rs29
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs128
-rw-r--r--embassy-boot/boot/src/lib.rs1
-rw-r--r--embassy-embedded-hal/Cargo.toml4
-rw-r--r--embassy-embedded-hal/src/adapter.rs23
-rw-r--r--embassy-embedded-hal/src/lib.rs2
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/i2c.rs42
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs171
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/i2c.rs56
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/spi.rs153
-rw-r--r--embassy-executor/Cargo.toml19
-rw-r--r--embassy-executor/src/raw/mod.rs28
-rw-r--r--embassy-executor/src/raw/run_queue.rs18
-rw-r--r--embassy-lora/Cargo.toml12
-rw-r--r--embassy-nrf/Cargo.toml4
-rw-r--r--embassy-nrf/src/twim.rs47
-rw-r--r--embassy-rp/Cargo.toml6
-rw-r--r--embassy-rp/src/gpio.rs59
-rw-r--r--embassy-rp/src/i2c.rs107
-rw-r--r--embassy-rp/src/spi.rs1
-rw-r--r--embassy-stm32/Cargo.toml94
-rw-r--r--embassy-stm32/build.rs130
-rw-r--r--embassy-stm32/src/adc/mod.rs11
-rw-r--r--embassy-stm32/src/adc/resolution.rs8
-rw-r--r--embassy-stm32/src/adc/sample_time.rs2
-rw-r--r--embassy-stm32/src/adc/v1.rs170
-rw-r--r--embassy-stm32/src/dma/gpdma.rs11
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs25
-rw-r--r--embassy-stm32/src/exti.rs18
-rw-r--r--embassy-stm32/src/flash/common.rs211
-rw-r--r--embassy-stm32/src/flash/f3.rs82
-rw-r--r--embassy-stm32/src/flash/f4.rs277
-rw-r--r--embassy-stm32/src/flash/f7.rs139
-rw-r--r--embassy-stm32/src/flash/h7.rs99
-rw-r--r--embassy-stm32/src/flash/l.rs125
-rw-r--r--embassy-stm32/src/flash/mod.rs155
-rw-r--r--embassy-stm32/src/flash/other.rs29
-rw-r--r--embassy-stm32/src/i2c/timeout.rs75
-rw-r--r--embassy-stm32/src/i2c/v1.rs73
-rw-r--r--embassy-stm32/src/i2c/v2.rs160
-rw-r--r--embassy-stm32/src/lib.rs8
-rw-r--r--embassy-stm32/src/pwm/complementary_pwm.rs124
-rw-r--r--embassy-stm32/src/pwm/mod.rs40
-rw-r--r--embassy-stm32/src/rcc/h5.rs606
-rw-r--r--embassy-stm32/src/rcc/mod.rs13
-rw-r--r--embassy-stm32/src/spi/mod.rs72
-rw-r--r--embassy-stm32/src/time.rs46
-rw-r--r--embassy-stm32/src/usb/usb.rs134
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs6
-rw-r--r--embassy-time/Cargo.toml4
-rw-r--r--embassy-time/src/delay.rs20
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs7
-rw-r--r--examples/rp/.cargo/config.toml2
-rw-r--r--examples/rp/Cargo.toml5
-rw-r--r--examples/rp/src/bin/spi_display.rs158
-rw-r--r--examples/stm32f0/src/bin/adc.rs35
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f3/src/bin/flash.rs2
-rw-r--r--examples/stm32f4/src/bin/flash.rs13
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs77
-rw-r--r--examples/stm32f7/src/bin/flash.rs4
-rw-r--r--examples/stm32h5/.cargo/config.toml8
-rw-r--r--examples/stm32h5/Cargo.toml71
-rw-r--r--examples/stm32h5/build.rs5
-rw-r--r--examples/stm32h5/memory.x5
-rw-r--r--examples/stm32h5/src/bin/blinky.rs27
-rw-r--r--examples/stm32h5/src/bin/button_exti.rs27
-rw-r--r--examples/stm32h5/src/bin/eth.rs133
-rw-r--r--examples/stm32h5/src/bin/i2c.rs44
-rw-r--r--examples/stm32h5/src/bin/rng.rs20
-rw-r--r--examples/stm32h5/src/bin/usart.rs43
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs46
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs58
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs128
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h7/src/bin/flash.rs4
-rw-r--r--examples/stm32l0/src/bin/flash.rs2
-rw-r--r--examples/stm32l1/src/bin/flash.rs2
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/flash.rs2
-rw-r--r--rust-toolchain.toml1
-rw-r--r--tests/rp/Cargo.toml4
-rw-r--r--tests/stm32/Cargo.toml5
-rw-r--r--tests/stm32/src/bin/gpio.rs2
-rw-r--r--tests/stm32/src/bin/spi.rs19
-rw-r--r--tests/stm32/src/bin/spi_dma.rs18
-rw-r--r--tests/stm32/src/bin/usart.rs2
-rw-r--r--tests/stm32/src/bin/usart_dma.rs9
93 files changed, 3678 insertions, 1243 deletions
diff --git a/ci.sh b/ci.sh
index d86c93520..47bf5d660 100755
--- a/ci.sh
+++ b/ci.sh
@@ -49,6 +49,7 @@ cargo batch \
49 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ 49 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
50 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ 50 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
51 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ 51 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
52 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
52 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ 53 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
53 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ 54 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
54 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ 55 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
@@ -65,6 +66,8 @@ cargo batch \
65 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \ 66 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
66 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \ 67 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
67 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \ 68 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
69 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
70 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
68 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 71 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
69 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 72 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
70 --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \ 73 --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \
@@ -86,6 +89,7 @@ cargo batch \
86 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ 89 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
87 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ 90 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
88 --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ 91 --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
92 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \
89 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ 93 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
90 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ 94 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
91 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ 95 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
@@ -115,6 +119,7 @@ cargo batch \
115 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \ 119 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \
116 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ 120 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \
117 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ 121 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \
122 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/nucleo-stm32h563zi \
118 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ 123 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \
119 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 124 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
120 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ 125 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 3312c2f9f..c4ebdaff2 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -24,6 +24,7 @@ features = ["defmt"]
24 24
25[dependencies] 25[dependencies]
26defmt = { version = "0.3", optional = true } 26defmt = { version = "0.3", optional = true }
27digest = "0.10"
27log = { version = "0.4", optional = true } 28log = { version = "0.4", optional = true }
28ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } 29ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
29embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } 30embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
@@ -37,6 +38,7 @@ log = "0.4"
37env_logger = "0.9" 38env_logger = "0.9"
38rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version 39rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version
39futures = { version = "0.3", features = ["executor"] } 40futures = { version = "0.3", features = ["executor"] }
41sha1 = "0.10.5"
40 42
41[dev-dependencies.ed25519-dalek] 43[dev-dependencies.ed25519-dalek]
42default_features = false 44default_features = false
@@ -47,4 +49,4 @@ ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
47ed25519-salty = ["dep:salty", "_verify"] 49ed25519-salty = ["dep:salty", "_verify"]
48 50
49#Internal features 51#Internal features
50_verify = [] \ No newline at end of file 52_verify = []
diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
new file mode 100644
index 000000000..a184d1c51
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
@@ -0,0 +1,30 @@
1use digest::typenum::U64;
2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
3use ed25519_dalek::Digest as _;
4
5pub struct Sha512(ed25519_dalek::Sha512);
6
7impl Default for Sha512 {
8 fn default() -> Self {
9 Self(ed25519_dalek::Sha512::new())
10 }
11}
12
13impl Update for Sha512 {
14 fn update(&mut self, data: &[u8]) {
15 self.0.update(data)
16 }
17}
18
19impl FixedOutput for Sha512 {
20 fn finalize_into(self, out: &mut digest::Output<Self>) {
21 let result = self.0.finalize();
22 out.as_mut_slice().copy_from_slice(result.as_slice())
23 }
24}
25
26impl OutputSizeUser for Sha512 {
27 type OutputSize = U64;
28}
29
30impl HashMarker for Sha512 {}
diff --git a/embassy-boot/boot/src/digest_adapters/mod.rs b/embassy-boot/boot/src/digest_adapters/mod.rs
new file mode 100644
index 000000000..9b4b4b60c
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/mod.rs
@@ -0,0 +1,5 @@
1#[cfg(feature = "ed25519-dalek")]
2pub(crate) mod ed25519_dalek;
3
4#[cfg(feature = "ed25519-salty")]
5pub(crate) mod salty;
diff --git a/embassy-boot/boot/src/digest_adapters/salty.rs b/embassy-boot/boot/src/digest_adapters/salty.rs
new file mode 100644
index 000000000..2b5dcf3af
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/salty.rs
@@ -0,0 +1,29 @@
1use digest::typenum::U64;
2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
3
4pub struct Sha512(salty::Sha512);
5
6impl Default for Sha512 {
7 fn default() -> Self {
8 Self(salty::Sha512::new())
9 }
10}
11
12impl Update for Sha512 {
13 fn update(&mut self, data: &[u8]) {
14 self.0.update(data)
15 }
16}
17
18impl FixedOutput for Sha512 {
19 fn finalize_into(self, out: &mut digest::Output<Self>) {
20 let result = self.0.finalize();
21 out.as_mut_slice().copy_from_slice(result.as_slice())
22 }
23}
24
25impl OutputSizeUser for Sha512 {
26 type OutputSize = U64;
27}
28
29impl HashMarker for Sha512 {}
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs
index 61c902ed0..6aedec003 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -1,3 +1,4 @@
1use digest::Digest;
1use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
2use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; 3use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
3 4
@@ -121,28 +122,27 @@ impl FirmwareUpdater {
121 122
122 #[cfg(feature = "ed25519-dalek")] 123 #[cfg(feature = "ed25519-dalek")]
123 { 124 {
124 use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; 125 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
126
127 use crate::digest_adapters::ed25519_dalek::Sha512;
125 128
126 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 129 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
127 130
128 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 131 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
129 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 132 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
130 133
131 let mut digest = Sha512::new(); 134 let mut message = [0; 64];
132 for offset in (0.._update_len).step_by(_aligned.len()) { 135 self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)
133 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; 136 .await?;
134 let len = core::cmp::min(_update_len - offset, _aligned.len());
135 digest.update(&_aligned[..len]);
136 }
137 137
138 public_key 138 public_key.verify(&message, &signature).map_err(into_signature_error)?
139 .verify(&digest.finalize(), &signature)
140 .map_err(into_signature_error)?
141 } 139 }
142 #[cfg(feature = "ed25519-salty")] 140 #[cfg(feature = "ed25519-salty")]
143 { 141 {
144 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; 142 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
145 use salty::{PublicKey, Sha512, Signature}; 143 use salty::{PublicKey, Signature};
144
145 use crate::digest_adapters::salty::Sha512;
146 146
147 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError { 147 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError {
148 FirmwareUpdaterError::Signature(signature::Error::default()) 148 FirmwareUpdaterError::Signature(signature::Error::default())
@@ -153,14 +153,10 @@ impl FirmwareUpdater {
153 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; 153 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
154 let signature = Signature::try_from(&signature).map_err(into_signature_error)?; 154 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
155 155
156 let mut digest = Sha512::new(); 156 let mut message = [0; 64];
157 for offset in (0.._update_len).step_by(_aligned.len()) { 157 self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)
158 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; 158 .await?;
159 let len = core::cmp::min(_update_len - offset, _aligned.len());
160 digest.update(&_aligned[..len]);
161 }
162 159
163 let message = digest.finalize();
164 let r = public_key.verify(&message, &signature); 160 let r = public_key.verify(&message, &signature);
165 trace!( 161 trace!(
166 "Verifying with public key {}, signature {} and message {} yields ok: {}", 162 "Verifying with public key {}, signature {} and message {} yields ok: {}",
@@ -175,6 +171,25 @@ impl FirmwareUpdater {
175 self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await 171 self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await
176 } 172 }
177 173
174 /// Verify the update in DFU with any digest.
175 pub async fn hash<F: AsyncNorFlash, D: Digest>(
176 &mut self,
177 dfu_flash: &mut F,
178 update_len: usize,
179 chunk_buf: &mut [u8],
180 output: &mut [u8],
181 ) -> Result<(), FirmwareUpdaterError> {
182 let update_len = update_len as u32;
183 let mut digest = D::new();
184 for offset in (0..update_len).step_by(chunk_buf.len()) {
185 self.dfu.read(dfu_flash, offset, chunk_buf).await?;
186 let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len());
187 digest.update(&chunk_buf[..len]);
188 }
189 output.copy_from_slice(digest.finalize().as_slice());
190 Ok(())
191 }
192
178 /// Mark to trigger firmware swap on next boot. 193 /// Mark to trigger firmware swap on next boot.
179 /// 194 ///
180 /// # Safety 195 /// # Safety
@@ -328,28 +343,26 @@ impl FirmwareUpdater {
328 343
329 #[cfg(feature = "ed25519-dalek")] 344 #[cfg(feature = "ed25519-dalek")]
330 { 345 {
331 use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; 346 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
347
348 use crate::digest_adapters::ed25519_dalek::Sha512;
332 349
333 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 350 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
334 351
335 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 352 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
336 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 353 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
337 354
338 let mut digest = Sha512::new(); 355 let mut message = [0; 64];
339 for offset in (0.._update_len).step_by(_aligned.len()) { 356 self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?;
340 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
341 let len = core::cmp::min(_update_len - offset, _aligned.len());
342 digest.update(&_aligned[..len]);
343 }
344 357
345 public_key 358 public_key.verify(&message, &signature).map_err(into_signature_error)?
346 .verify(&digest.finalize(), &signature)
347 .map_err(into_signature_error)?
348 } 359 }
349 #[cfg(feature = "ed25519-salty")] 360 #[cfg(feature = "ed25519-salty")]
350 { 361 {
351 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; 362 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
352 use salty::{PublicKey, Sha512, Signature}; 363 use salty::{PublicKey, Signature};
364
365 use crate::digest_adapters::salty::Sha512;
353 366
354 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError { 367 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError {
355 FirmwareUpdaterError::Signature(signature::Error::default()) 368 FirmwareUpdaterError::Signature(signature::Error::default())
@@ -360,14 +373,9 @@ impl FirmwareUpdater {
360 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; 373 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
361 let signature = Signature::try_from(&signature).map_err(into_signature_error)?; 374 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
362 375
363 let mut digest = Sha512::new(); 376 let mut message = [0; 64];
364 for offset in (0.._update_len).step_by(_aligned.len()) { 377 self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?;
365 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
366 let len = core::cmp::min(_update_len - offset, _aligned.len());
367 digest.update(&_aligned[..len]);
368 }
369 378
370 let message = digest.finalize();
371 let r = public_key.verify(&message, &signature); 379 let r = public_key.verify(&message, &signature);
372 trace!( 380 trace!(
373 "Verifying with public key {}, signature {} and message {} yields ok: {}", 381 "Verifying with public key {}, signature {} and message {} yields ok: {}",
@@ -382,6 +390,25 @@ impl FirmwareUpdater {
382 self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) 390 self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash)
383 } 391 }
384 392
393 /// Verify the update in DFU with any digest.
394 pub fn hash_blocking<F: NorFlash, D: Digest>(
395 &mut self,
396 dfu_flash: &mut F,
397 update_len: usize,
398 chunk_buf: &mut [u8],
399 output: &mut [u8],
400 ) -> Result<(), FirmwareUpdaterError> {
401 let update_len = update_len as u32;
402 let mut digest = D::new();
403 for offset in (0..update_len).step_by(chunk_buf.len()) {
404 self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?;
405 let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len());
406 digest.update(&chunk_buf[..len]);
407 }
408 output.copy_from_slice(digest.finalize().as_slice());
409 Ok(())
410 }
411
385 /// Mark to trigger firmware swap on next boot. 412 /// Mark to trigger firmware swap on next boot.
386 /// 413 ///
387 /// # Safety 414 /// # Safety
@@ -478,3 +505,32 @@ impl FirmwareUpdater {
478 Ok(self.dfu) 505 Ok(self.dfu)
479 } 506 }
480} 507}
508
509#[cfg(test)]
510mod tests {
511 use futures::executor::block_on;
512 use sha1::{Digest, Sha1};
513
514 use super::*;
515 use crate::mem_flash::MemFlash;
516
517 #[test]
518 fn can_verify_sha1() {
519 const STATE: Partition = Partition::new(0, 4096);
520 const DFU: Partition = Partition::new(65536, 131072);
521
522 let mut flash = MemFlash::<131072, 4096, 8>::default();
523
524 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
525 let mut to_write = [0; 4096];
526 to_write[..7].copy_from_slice(update.as_slice());
527
528 let mut updater = FirmwareUpdater::new(DFU, STATE);
529 block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap();
530 let mut chunk_buf = [0; 2];
531 let mut hash = [0; 20];
532 block_on(updater.hash::<_, Sha1>(&mut flash, update.len(), &mut chunk_buf, &mut hash)).unwrap();
533
534 assert_eq!(Sha1::digest(update).as_slice(), hash);
535 }
536}
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 8b94b6bdc..ef9333d36 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -6,6 +6,7 @@
6mod fmt; 6mod fmt;
7 7
8mod boot_loader; 8mod boot_loader;
9mod digest_adapters;
9mod firmware_updater; 10mod firmware_updater;
10mod mem_flash; 11mod mem_flash;
11mod partition; 12mod partition;
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 45eb0d43d..c509d6ee5 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -19,8 +19,8 @@ nightly = ["embedded-hal-async", "embedded-storage-async"]
19[dependencies] 19[dependencies]
20embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 20embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
21embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 21embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
23embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true } 23embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true }
24embedded-storage = "0.3.0" 24embedded-storage = "0.3.0"
25embedded-storage-async = { version = "0.4.0", optional = true } 25embedded-storage-async = { version = "0.4.0", optional = true }
26nb = "1.0.0" 26nb = "1.0.0"
diff --git a/embassy-embedded-hal/src/adapter.rs b/embassy-embedded-hal/src/adapter.rs
index a49f8df4b..ee919bd84 100644
--- a/embassy-embedded-hal/src/adapter.rs
+++ b/embassy-embedded-hal/src/adapter.rs
@@ -36,27 +36,22 @@ where
36 E: embedded_hal_1::i2c::Error + 'static, 36 E: embedded_hal_1::i2c::Error + 'static,
37 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>, 37 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>,
38{ 38{
39 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Self::Error> { 39 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
40 self.wrapped.read(address, buffer) 40 self.wrapped.read(address, read)
41 } 41 }
42 42
43 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Self::Error> { 43 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
44 self.wrapped.write(address, bytes) 44 self.wrapped.write(address, write)
45 } 45 }
46 46
47 async fn write_read<'a>( 47 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
48 &'a mut self, 48 self.wrapped.write_read(address, write, read)
49 address: u8,
50 bytes: &'a [u8],
51 buffer: &'a mut [u8],
52 ) -> Result<(), Self::Error> {
53 self.wrapped.write_read(address, bytes, buffer)
54 } 49 }
55 50
56 async fn transaction<'a, 'b>( 51 async fn transaction(
57 &'a mut self, 52 &mut self,
58 address: u8, 53 address: u8,
59 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 54 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
60 ) -> Result<(), Self::Error> { 55 ) -> Result<(), Self::Error> {
61 let _ = address; 56 let _ = address;
62 let _ = operations; 57 let _ = operations;
diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs
index 8da042228..a23fbdc41 100644
--- a/embassy-embedded-hal/src/lib.rs
+++ b/embassy-embedded-hal/src/lib.rs
@@ -1,7 +1,7 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr( 2#![cfg_attr(
3 feature = "nightly", 3 feature = "nightly",
4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections) 4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections, try_blocks)
5)] 5)]
6#![cfg_attr(feature = "nightly", allow(incomplete_features))] 6#![cfg_attr(feature = "nightly", allow(incomplete_features))]
7#![warn(missing_docs)] 7#![warn(missing_docs)]
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
index c5e1fd415..829554045 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -54,35 +54,35 @@ where
54 M: RawMutex + 'static, 54 M: RawMutex + 'static,
55 BUS: i2c::I2c + 'static, 55 BUS: i2c::I2c + 'static,
56{ 56{
57 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> { 57 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
58 let mut bus = self.bus.lock().await; 58 let mut bus = self.bus.lock().await;
59 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?; 59 bus.read(address, read).await.map_err(I2cDeviceError::I2c)?;
60 Ok(()) 60 Ok(())
61 } 61 }
62 62
63 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError<BUS::Error>> { 63 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
64 let mut bus = self.bus.lock().await; 64 let mut bus = self.bus.lock().await;
65 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?; 65 bus.write(address, write).await.map_err(I2cDeviceError::I2c)?;
66 Ok(()) 66 Ok(())
67 } 67 }
68 68
69 async fn write_read<'a>( 69 async fn write_read(
70 &'a mut self, 70 &mut self,
71 address: u8, 71 address: u8,
72 wr_buffer: &'a [u8], 72 write: &[u8],
73 rd_buffer: &'a mut [u8], 73 read: &mut [u8],
74 ) -> Result<(), I2cDeviceError<BUS::Error>> { 74 ) -> Result<(), I2cDeviceError<BUS::Error>> {
75 let mut bus = self.bus.lock().await; 75 let mut bus = self.bus.lock().await;
76 bus.write_read(address, wr_buffer, rd_buffer) 76 bus.write_read(address, write, read)
77 .await 77 .await
78 .map_err(I2cDeviceError::I2c)?; 78 .map_err(I2cDeviceError::I2c)?;
79 Ok(()) 79 Ok(())
80 } 80 }
81 81
82 async fn transaction<'a, 'b>( 82 async fn transaction(
83 &'a mut self, 83 &mut self,
84 address: u8, 84 address: u8,
85 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 85 operations: &mut [embedded_hal_async::i2c::Operation<'_>],
86 ) -> Result<(), I2cDeviceError<BUS::Error>> { 86 ) -> Result<(), I2cDeviceError<BUS::Error>> {
87 let _ = address; 87 let _ = address;
88 let _ = operations; 88 let _ = operations;
@@ -121,25 +121,25 @@ where
121 M: RawMutex + 'static, 121 M: RawMutex + 'static,
122 BUS: i2c::I2c + SetConfig + 'static, 122 BUS: i2c::I2c + SetConfig + 'static,
123{ 123{
124 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> { 124 async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
125 let mut bus = self.bus.lock().await; 125 let mut bus = self.bus.lock().await;
126 bus.set_config(&self.config); 126 bus.set_config(&self.config);
127 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?; 127 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
128 Ok(()) 128 Ok(())
129 } 129 }
130 130
131 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError<BUS::Error>> { 131 async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
132 let mut bus = self.bus.lock().await; 132 let mut bus = self.bus.lock().await;
133 bus.set_config(&self.config); 133 bus.set_config(&self.config);
134 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?; 134 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
135 Ok(()) 135 Ok(())
136 } 136 }
137 137
138 async fn write_read<'a>( 138 async fn write_read(
139 &'a mut self, 139 &mut self,
140 address: u8, 140 address: u8,
141 wr_buffer: &'a [u8], 141 wr_buffer: &[u8],
142 rd_buffer: &'a mut [u8], 142 rd_buffer: &mut [u8],
143 ) -> Result<(), I2cDeviceError<BUS::Error>> { 143 ) -> Result<(), I2cDeviceError<BUS::Error>> {
144 let mut bus = self.bus.lock().await; 144 let mut bus = self.bus.lock().await;
145 bus.set_config(&self.config); 145 bus.set_config(&self.config);
@@ -149,11 +149,7 @@ where
149 Ok(()) 149 Ok(())
150 } 150 }
151 151
152 async fn transaction<'a, 'b>( 152 async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
153 &'a mut self,
154 address: u8,
155 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
156 ) -> Result<(), I2cDeviceError<BUS::Error>> {
157 let _ = address; 153 let _ = address;
158 let _ = operations; 154 let _ = operations;
159 todo!() 155 todo!()
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index d25716655..b5549a6cd 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -25,12 +25,11 @@
25//! let spi_dev2 = SpiDevice::new(spi_bus, cs_pin2); 25//! let spi_dev2 = SpiDevice::new(spi_bus, cs_pin2);
26//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); 26//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128);
27//! ``` 27//! ```
28use core::future::Future;
29 28
30use embassy_sync::blocking_mutex::raw::RawMutex; 29use embassy_sync::blocking_mutex::raw::RawMutex;
31use embassy_sync::mutex::Mutex; 30use embassy_sync::mutex::Mutex;
32use embedded_hal_1::digital::OutputPin; 31use embedded_hal_1::digital::OutputPin;
33use embedded_hal_1::spi::ErrorType; 32use embedded_hal_1::spi::Operation;
34use embedded_hal_async::spi; 33use embedded_hal_async::spi;
35 34
36use crate::shared_bus::SpiDeviceError; 35use crate::shared_bus::SpiDeviceError;
@@ -57,33 +56,92 @@ where
57 type Error = SpiDeviceError<BUS::Error, CS::Error>; 56 type Error = SpiDeviceError<BUS::Error, CS::Error>;
58} 57}
59 58
60unsafe impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 59impl<M, BUS, CS> spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
61where 60where
62 M: RawMutex + 'static, 61 M: RawMutex,
63 BUS: spi::SpiBusFlush + 'static, 62 BUS: spi::SpiBusRead,
64 CS: OutputPin, 63 CS: OutputPin,
65{ 64{
66 type Bus = BUS; 65 async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
66 let mut bus = self.bus.lock().await;
67 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
68
69 let op_res: Result<(), BUS::Error> = try {
70 for buf in operations {
71 bus.read(buf).await?;
72 }
73 };
74
75 // On failure, it's important to still flush and deassert CS.
76 let flush_res = bus.flush().await;
77 let cs_res = self.cs.set_high();
67 78
68 async fn transaction<R, F, Fut>(&mut self, f: F) -> Result<R, Self::Error> 79 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
69 where 80 flush_res.map_err(SpiDeviceError::Spi)?;
70 F: FnOnce(*mut Self::Bus) -> Fut, 81 cs_res.map_err(SpiDeviceError::Cs)?;
71 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>>, 82
72 { 83 Ok(op_res)
84 }
85}
86
87impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
88where
89 M: RawMutex,
90 BUS: spi::SpiBusWrite,
91 CS: OutputPin,
92{
93 async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
73 let mut bus = self.bus.lock().await; 94 let mut bus = self.bus.lock().await;
74 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 95 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
75 96
76 let f_res = f(&mut *bus).await; 97 let op_res: Result<(), BUS::Error> = try {
98 for buf in operations {
99 bus.write(buf).await?;
100 }
101 };
77 102
78 // On failure, it's important to still flush and deassert CS. 103 // On failure, it's important to still flush and deassert CS.
79 let flush_res = bus.flush().await; 104 let flush_res = bus.flush().await;
80 let cs_res = self.cs.set_high(); 105 let cs_res = self.cs.set_high();
81 106
82 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 107 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
83 flush_res.map_err(SpiDeviceError::Spi)?; 108 flush_res.map_err(SpiDeviceError::Spi)?;
84 cs_res.map_err(SpiDeviceError::Cs)?; 109 cs_res.map_err(SpiDeviceError::Cs)?;
85 110
86 Ok(f_res) 111 Ok(op_res)
112 }
113}
114
115impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
116where
117 M: RawMutex,
118 BUS: spi::SpiBus,
119 CS: OutputPin,
120{
121 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
122 let mut bus = self.bus.lock().await;
123 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
124
125 let op_res: Result<(), BUS::Error> = try {
126 for op in operations {
127 match op {
128 Operation::Read(buf) => bus.read(buf).await?,
129 Operation::Write(buf) => bus.write(buf).await?,
130 Operation::Transfer(read, write) => bus.transfer(read, write).await?,
131 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
132 }
133 }
134 };
135
136 // On failure, it's important to still flush and deassert CS.
137 let flush_res = bus.flush().await;
138 let cs_res = self.cs.set_high();
139
140 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
141 flush_res.map_err(SpiDeviceError::Spi)?;
142 cs_res.map_err(SpiDeviceError::Cs)?;
143
144 Ok(op_res)
87 } 145 }
88} 146}
89 147
@@ -114,33 +172,94 @@ where
114 type Error = SpiDeviceError<BUS::Error, CS::Error>; 172 type Error = SpiDeviceError<BUS::Error, CS::Error>;
115} 173}
116 174
117unsafe impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 175impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
176where
177 M: RawMutex,
178 BUS: spi::SpiBusWrite + SetConfig,
179 CS: OutputPin,
180{
181 async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
182 let mut bus = self.bus.lock().await;
183 bus.set_config(&self.config);
184 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
185
186 let op_res: Result<(), BUS::Error> = try {
187 for buf in operations {
188 bus.write(buf).await?;
189 }
190 };
191
192 // On failure, it's important to still flush and deassert CS.
193 let flush_res = bus.flush().await;
194 let cs_res = self.cs.set_high();
195
196 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
197 flush_res.map_err(SpiDeviceError::Spi)?;
198 cs_res.map_err(SpiDeviceError::Cs)?;
199
200 Ok(op_res)
201 }
202}
203
204impl<M, BUS, CS> spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
118where 205where
119 M: RawMutex + 'static, 206 M: RawMutex,
120 BUS: spi::SpiBusFlush + SetConfig + 'static, 207 BUS: spi::SpiBusRead + SetConfig,
121 CS: OutputPin, 208 CS: OutputPin,
122{ 209{
123 type Bus = BUS; 210 async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
211 let mut bus = self.bus.lock().await;
212 bus.set_config(&self.config);
213 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
214
215 let op_res: Result<(), BUS::Error> = try {
216 for buf in operations {
217 bus.read(buf).await?;
218 }
219 };
220
221 // On failure, it's important to still flush and deassert CS.
222 let flush_res = bus.flush().await;
223 let cs_res = self.cs.set_high();
224
225 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
226 flush_res.map_err(SpiDeviceError::Spi)?;
227 cs_res.map_err(SpiDeviceError::Cs)?;
228
229 Ok(op_res)
230 }
231}
124 232
125 async fn transaction<R, F, Fut>(&mut self, f: F) -> Result<R, Self::Error> 233impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
126 where 234where
127 F: FnOnce(*mut Self::Bus) -> Fut, 235 M: RawMutex,
128 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>>, 236 BUS: spi::SpiBus + SetConfig,
129 { 237 CS: OutputPin,
238{
239 async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
130 let mut bus = self.bus.lock().await; 240 let mut bus = self.bus.lock().await;
131 bus.set_config(&self.config); 241 bus.set_config(&self.config);
132 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 242 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
133 243
134 let f_res = f(&mut *bus).await; 244 let op_res: Result<(), BUS::Error> = try {
245 for op in operations {
246 match op {
247 Operation::Read(buf) => bus.read(buf).await?,
248 Operation::Write(buf) => bus.write(buf).await?,
249 Operation::Transfer(read, write) => bus.transfer(read, write).await?,
250 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
251 }
252 }
253 };
135 254
136 // On failure, it's important to still flush and deassert CS. 255 // On failure, it's important to still flush and deassert CS.
137 let flush_res = bus.flush().await; 256 let flush_res = bus.flush().await;
138 let cs_res = self.cs.set_high(); 257 let cs_res = self.cs.set_high();
139 258
140 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 259 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
141 flush_res.map_err(SpiDeviceError::Spi)?; 260 flush_res.map_err(SpiDeviceError::Spi)?;
142 cs_res.map_err(SpiDeviceError::Cs)?; 261 cs_res.map_err(SpiDeviceError::Cs)?;
143 262
144 Ok(f_res) 263 Ok(op_res)
145 } 264 }
146} 265}
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
index 892000b26..1fe520e6c 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
@@ -72,34 +72,6 @@ where
72 let _ = operations; 72 let _ = operations;
73 todo!() 73 todo!()
74 } 74 }
75
76 fn write_iter<B: IntoIterator<Item = u8>>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> {
77 let _ = addr;
78 let _ = bytes;
79 todo!()
80 }
81
82 fn write_iter_read<B: IntoIterator<Item = u8>>(
83 &mut self,
84 addr: u8,
85 bytes: B,
86 buffer: &mut [u8],
87 ) -> Result<(), Self::Error> {
88 let _ = addr;
89 let _ = bytes;
90 let _ = buffer;
91 todo!()
92 }
93
94 fn transaction_iter<'a, O: IntoIterator<Item = Operation<'a>>>(
95 &mut self,
96 address: u8,
97 operations: O,
98 ) -> Result<(), Self::Error> {
99 let _ = address;
100 let _ = operations;
101 todo!()
102 }
103} 75}
104 76
105impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS> 77impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS>
@@ -204,32 +176,4 @@ where
204 let _ = operations; 176 let _ = operations;
205 todo!() 177 todo!()
206 } 178 }
207
208 fn write_iter<B: IntoIterator<Item = u8>>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> {
209 let _ = addr;
210 let _ = bytes;
211 todo!()
212 }
213
214 fn write_iter_read<B: IntoIterator<Item = u8>>(
215 &mut self,
216 addr: u8,
217 bytes: B,
218 buffer: &mut [u8],
219 ) -> Result<(), Self::Error> {
220 let _ = addr;
221 let _ = bytes;
222 let _ = buffer;
223 todo!()
224 }
225
226 fn transaction_iter<'a, O: IntoIterator<Item = Operation<'a>>>(
227 &mut self,
228 address: u8,
229 operations: O,
230 ) -> Result<(), Self::Error> {
231 let _ = address;
232 let _ = operations;
233 todo!()
234 }
235} 179}
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index 4a08dc36e..7982ffb6e 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -23,8 +23,7 @@ use core::cell::RefCell;
23use embassy_sync::blocking_mutex::raw::RawMutex; 23use embassy_sync::blocking_mutex::raw::RawMutex;
24use embassy_sync::blocking_mutex::Mutex; 24use embassy_sync::blocking_mutex::Mutex;
25use embedded_hal_1::digital::OutputPin; 25use embedded_hal_1::digital::OutputPin;
26use embedded_hal_1::spi; 26use embedded_hal_1::spi::{self, Operation, SpiBus, SpiBusRead, SpiBusWrite};
27use embedded_hal_1::spi::SpiBusFlush;
28 27
29use crate::shared_bus::SpiDeviceError; 28use crate::shared_bus::SpiDeviceError;
30use crate::SetConfig; 29use crate::SetConfig;
@@ -50,30 +49,85 @@ where
50 type Error = SpiDeviceError<BUS::Error, CS::Error>; 49 type Error = SpiDeviceError<BUS::Error, CS::Error>;
51} 50}
52 51
53impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 52impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
54where 53where
55 M: RawMutex, 54 M: RawMutex,
56 BUS: SpiBusFlush, 55 BUS: SpiBusRead,
57 CS: OutputPin, 56 CS: OutputPin,
58{ 57{
59 type Bus = BUS; 58 fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
59 self.bus.lock(|bus| {
60 let mut bus = bus.borrow_mut();
61 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
62
63 let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
60 64
61 fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>) -> Result<R, Self::Error> { 65 // On failure, it's important to still flush and deassert CS.
66 let flush_res = bus.flush();
67 let cs_res = self.cs.set_high();
68
69 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
70 flush_res.map_err(SpiDeviceError::Spi)?;
71 cs_res.map_err(SpiDeviceError::Cs)?;
72
73 Ok(op_res)
74 })
75 }
76}
77
78impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
79where
80 M: RawMutex,
81 BUS: SpiBusWrite,
82 CS: OutputPin,
83{
84 fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
85 self.bus.lock(|bus| {
86 let mut bus = bus.borrow_mut();
87 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
88
89 let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
90
91 // On failure, it's important to still flush and deassert CS.
92 let flush_res = bus.flush();
93 let cs_res = self.cs.set_high();
94
95 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
96 flush_res.map_err(SpiDeviceError::Spi)?;
97 cs_res.map_err(SpiDeviceError::Cs)?;
98
99 Ok(op_res)
100 })
101 }
102}
103
104impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
105where
106 M: RawMutex,
107 BUS: SpiBus,
108 CS: OutputPin,
109{
110 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
62 self.bus.lock(|bus| { 111 self.bus.lock(|bus| {
63 let mut bus = bus.borrow_mut(); 112 let mut bus = bus.borrow_mut();
64 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 113 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
65 114
66 let f_res = f(&mut bus); 115 let op_res = operations.iter_mut().try_for_each(|op| match op {
116 Operation::Read(buf) => bus.read(buf),
117 Operation::Write(buf) => bus.write(buf),
118 Operation::Transfer(read, write) => bus.transfer(read, write),
119 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
120 });
67 121
68 // On failure, it's important to still flush and deassert CS. 122 // On failure, it's important to still flush and deassert CS.
69 let flush_res = bus.flush(); 123 let flush_res = bus.flush();
70 let cs_res = self.cs.set_high(); 124 let cs_res = self.cs.set_high();
71 125
72 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 126 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
73 flush_res.map_err(SpiDeviceError::Spi)?; 127 flush_res.map_err(SpiDeviceError::Spi)?;
74 cs_res.map_err(SpiDeviceError::Cs)?; 128 cs_res.map_err(SpiDeviceError::Cs)?;
75 129
76 Ok(f_res) 130 Ok(op_res)
77 }) 131 })
78 } 132 }
79} 133}
@@ -89,11 +143,11 @@ where
89 self.bus.lock(|bus| { 143 self.bus.lock(|bus| {
90 let mut bus = bus.borrow_mut(); 144 let mut bus = bus.borrow_mut();
91 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 145 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
92 let f_res = bus.transfer(words); 146 let op_res = bus.transfer(words);
93 let cs_res = self.cs.set_high(); 147 let cs_res = self.cs.set_high();
94 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 148 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
95 cs_res.map_err(SpiDeviceError::Cs)?; 149 cs_res.map_err(SpiDeviceError::Cs)?;
96 Ok(f_res) 150 Ok(op_res)
97 }) 151 })
98 } 152 }
99} 153}
@@ -110,11 +164,11 @@ where
110 self.bus.lock(|bus| { 164 self.bus.lock(|bus| {
111 let mut bus = bus.borrow_mut(); 165 let mut bus = bus.borrow_mut();
112 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 166 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
113 let f_res = bus.write(words); 167 let op_res = bus.write(words);
114 let cs_res = self.cs.set_high(); 168 let cs_res = self.cs.set_high();
115 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 169 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
116 cs_res.map_err(SpiDeviceError::Cs)?; 170 cs_res.map_err(SpiDeviceError::Cs)?;
117 Ok(f_res) 171 Ok(op_res)
118 }) 172 })
119 } 173 }
120} 174}
@@ -146,30 +200,85 @@ where
146 type Error = SpiDeviceError<BUS::Error, CS::Error>; 200 type Error = SpiDeviceError<BUS::Error, CS::Error>;
147} 201}
148 202
149impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 203impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
150where 204where
151 M: RawMutex, 205 M: RawMutex,
152 BUS: SpiBusFlush + SetConfig, 206 BUS: SpiBusRead + SetConfig,
153 CS: OutputPin, 207 CS: OutputPin,
154{ 208{
155 type Bus = BUS; 209 fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
210 self.bus.lock(|bus| {
211 let mut bus = bus.borrow_mut();
212 bus.set_config(&self.config);
213 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
214
215 let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
156 216
157 fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>) -> Result<R, Self::Error> { 217 // On failure, it's important to still flush and deassert CS.
218 let flush_res = bus.flush();
219 let cs_res = self.cs.set_high();
220
221 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
222 flush_res.map_err(SpiDeviceError::Spi)?;
223 cs_res.map_err(SpiDeviceError::Cs)?;
224 Ok(op_res)
225 })
226 }
227}
228
229impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
230where
231 M: RawMutex,
232 BUS: SpiBusWrite + SetConfig,
233 CS: OutputPin,
234{
235 fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
236 self.bus.lock(|bus| {
237 let mut bus = bus.borrow_mut();
238 bus.set_config(&self.config);
239 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
240
241 let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
242
243 // On failure, it's important to still flush and deassert CS.
244 let flush_res = bus.flush();
245 let cs_res = self.cs.set_high();
246
247 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
248 flush_res.map_err(SpiDeviceError::Spi)?;
249 cs_res.map_err(SpiDeviceError::Cs)?;
250 Ok(op_res)
251 })
252 }
253}
254
255impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
256where
257 M: RawMutex,
258 BUS: SpiBus + SetConfig,
259 CS: OutputPin,
260{
261 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
158 self.bus.lock(|bus| { 262 self.bus.lock(|bus| {
159 let mut bus = bus.borrow_mut(); 263 let mut bus = bus.borrow_mut();
160 bus.set_config(&self.config); 264 bus.set_config(&self.config);
161 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 265 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
162 266
163 let f_res = f(&mut bus); 267 let op_res = operations.iter_mut().try_for_each(|op| match op {
268 Operation::Read(buf) => bus.read(buf),
269 Operation::Write(buf) => bus.write(buf),
270 Operation::Transfer(read, write) => bus.transfer(read, write),
271 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
272 });
164 273
165 // On failure, it's important to still flush and deassert CS. 274 // On failure, it's important to still flush and deassert CS.
166 let flush_res = bus.flush(); 275 let flush_res = bus.flush();
167 let cs_res = self.cs.set_high(); 276 let cs_res = self.cs.set_high();
168 277
169 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 278 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
170 flush_res.map_err(SpiDeviceError::Spi)?; 279 flush_res.map_err(SpiDeviceError::Spi)?;
171 cs_res.map_err(SpiDeviceError::Cs)?; 280 cs_res.map_err(SpiDeviceError::Cs)?;
172 Ok(f_res) 281 Ok(op_res)
173 }) 282 })
174 } 283 }
175} 284}
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index bb8a46c82..29e1bd478 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -14,21 +14,18 @@ categories = [
14[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" 16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
17features = ["nightly", "defmt"] 17features = ["nightly", "defmt", "pender-callback"]
18flavors = [ 18flavors = [
19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["std"] }, 19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["wasm"] }, 20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
21 { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] }, 21 { name = "cortex-m", target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] },
22 { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] }, 22 { name = "riscv32", target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32", "executor-thread"] },
23 { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
24 { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
25 { name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] },
26 { name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] },
27 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
28] 23]
29 24
30[package.metadata.docs.rs] 25[package.metadata.docs.rs]
31features = ["std", "nightly", "defmt"] 26default-target = "thumbv7em-none-eabi"
27targets = ["thumbv7em-none-eabi"]
28features = ["nightly", "defmt", "pender-callback", "arch-cortex-m", "executor-thread", "executor-interrupt"]
32 29
33[features] 30[features]
34 31
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index f6c66da5a..bd0cff26b 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -22,7 +22,6 @@ use core::ptr::NonNull;
22use core::task::{Context, Poll}; 22use core::task::{Context, Poll};
23 23
24use atomic_polyfill::{AtomicU32, Ordering}; 24use atomic_polyfill::{AtomicU32, Ordering};
25use critical_section::CriticalSection;
26#[cfg(feature = "integrated-timers")] 25#[cfg(feature = "integrated-timers")]
27use embassy_time::driver::{self, AlarmHandle}; 26use embassy_time::driver::{self, AlarmHandle};
28#[cfg(feature = "integrated-timers")] 27#[cfg(feature = "integrated-timers")]
@@ -373,11 +372,11 @@ impl SyncExecutor {
373 /// - `task` must be set up to run in this executor. 372 /// - `task` must be set up to run in this executor.
374 /// - `task` must NOT be already enqueued (in this executor or another one). 373 /// - `task` must NOT be already enqueued (in this executor or another one).
375 #[inline(always)] 374 #[inline(always)]
376 unsafe fn enqueue(&self, cs: CriticalSection, task: TaskRef) { 375 unsafe fn enqueue(&self, task: TaskRef) {
377 #[cfg(feature = "rtos-trace")] 376 #[cfg(feature = "rtos-trace")]
378 trace::task_ready_begin(task.as_ptr() as u32); 377 trace::task_ready_begin(task.as_ptr() as u32);
379 378
380 if self.run_queue.enqueue(cs, task) { 379 if self.run_queue.enqueue(task) {
381 self.pender.pend(); 380 self.pender.pend();
382 } 381 }
383 } 382 }
@@ -394,9 +393,7 @@ impl SyncExecutor {
394 #[cfg(feature = "rtos-trace")] 393 #[cfg(feature = "rtos-trace")]
395 trace::task_new(task.as_ptr() as u32); 394 trace::task_new(task.as_ptr() as u32);
396 395
397 critical_section::with(|cs| { 396 self.enqueue(task);
398 self.enqueue(cs, task);
399 })
400 } 397 }
401 398
402 /// # Safety 399 /// # Safety
@@ -552,24 +549,25 @@ impl Executor {
552/// 549///
553/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. 550/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
554pub fn wake_task(task: TaskRef) { 551pub fn wake_task(task: TaskRef) {
555 critical_section::with(|cs| { 552 let header = task.header();
556 let header = task.header();
557 let state = header.state.load(Ordering::Relaxed);
558 553
554 let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
559 // If already scheduled, or if not started, 555 // If already scheduled, or if not started,
560 if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { 556 if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
561 return; 557 None
558 } else {
559 // Mark it as scheduled
560 Some(state | STATE_RUN_QUEUED)
562 } 561 }
562 });
563 563
564 // Mark it as scheduled 564 if res.is_ok() {
565 header.state.store(state | STATE_RUN_QUEUED, Ordering::Relaxed);
566
567 // We have just marked the task as scheduled, so enqueue it. 565 // We have just marked the task as scheduled, so enqueue it.
568 unsafe { 566 unsafe {
569 let executor = header.executor.get().unwrap_unchecked(); 567 let executor = header.executor.get().unwrap_unchecked();
570 executor.enqueue(cs, task); 568 executor.enqueue(task);
571 } 569 }
572 }) 570 }
573} 571}
574 572
575#[cfg(feature = "integrated-timers")] 573#[cfg(feature = "integrated-timers")]
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
index 362157535..a88174a0c 100644
--- a/embassy-executor/src/raw/run_queue.rs
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -2,7 +2,6 @@ use core::ptr;
2use core::ptr::NonNull; 2use core::ptr::NonNull;
3 3
4use atomic_polyfill::{AtomicPtr, Ordering}; 4use atomic_polyfill::{AtomicPtr, Ordering};
5use critical_section::CriticalSection;
6 5
7use super::{TaskHeader, TaskRef}; 6use super::{TaskHeader, TaskRef};
8 7
@@ -46,11 +45,18 @@ impl RunQueue {
46 /// 45 ///
47 /// `item` must NOT be already enqueued in any queue. 46 /// `item` must NOT be already enqueued in any queue.
48 #[inline(always)] 47 #[inline(always)]
49 pub(crate) unsafe fn enqueue(&self, _cs: CriticalSection, task: TaskRef) -> bool { 48 pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool {
50 let prev = self.head.load(Ordering::Relaxed); 49 let mut was_empty = false;
51 task.header().run_queue_item.next.store(prev, Ordering::Relaxed); 50
52 self.head.store(task.as_ptr() as _, Ordering::Relaxed); 51 self.head
53 prev.is_null() 52 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
53 was_empty = prev.is_null();
54 task.header().run_queue_item.next.store(prev, Ordering::Relaxed);
55 Some(task.as_ptr() as *mut _)
56 })
57 .ok();
58
59 was_empty
54 } 60 }
55 61
56 /// Empty the queue, then call `on_task` for each task that was in the queue. 62 /// Empty the queue, then call `on_task` for each task that was in the queue.
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index cbe78e592..604358c5b 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -9,9 +9,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-lora-v$VERSION/em
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/" 9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/"
10features = ["time", "defmt"] 10features = ["time", "defmt"]
11flavors = [ 11flavors = [
12 { name = "sx126x", target = "thumbv7em-none-eabihf", features = ["sx126x"] }, 12 { name = "sx126x", target = "thumbv7em-none-eabihf", features = ["sx126x"] },
13 { name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any"] }, 13 { name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x"] },
14 { name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any"] }, 14 { name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32?/stm32wl55jc-cm4", "embassy-stm32?/time-driver-any"] },
15] 15]
16 16
17[lib] 17[lib]
@@ -19,7 +19,7 @@ flavors = [
19[features] 19[features]
20sx126x = [] 20sx126x = []
21sx127x = [] 21sx127x = []
22stm32wl = ["embassy-stm32", "embassy-stm32/subghz"] 22stm32wl = ["dep:embassy-stm32"]
23time = [] 23time = []
24defmt = ["dep:defmt", "lorawan/defmt", "lorawan-device/defmt"] 24defmt = ["dep:defmt", "lorawan/defmt", "lorawan-device/defmt"]
25 25
@@ -31,8 +31,8 @@ log = { version = "0.4.14", optional = true }
31embassy-time = { version = "0.1.0", path = "../embassy-time" } 31embassy-time = { version = "0.1.0", path = "../embassy-time" }
32embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 32embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
33embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } 33embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
34embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 34embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
35embedded-hal-async = { version = "=0.2.0-alpha.0" } 35embedded-hal-async = { version = "=0.2.0-alpha.1" }
36embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } 36embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false }
37futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 37futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
38embedded-hal = { version = "0.2", features = ["unproven"] } 38embedded-hal = { version = "0.2", features = ["unproven"] }
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 4e62ca89e..4a4e7c9f9 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -87,8 +87,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
87embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } 87embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
88 88
89embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 89embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
90embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 90embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
91embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} 91embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
92embedded-io = { version = "0.4.0", features = ["async"], optional = true } 92embedded-io = { version = "0.4.0", features = ["async"], optional = true }
93 93
94defmt = { version = "0.3", optional = true } 94defmt = { version = "0.3", optional = true }
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index ef4c929a3..9ae569609 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -846,20 +846,6 @@ mod eh1 {
846 self.blocking_write(address, buffer) 846 self.blocking_write(address, buffer)
847 } 847 }
848 848
849 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
850 where
851 B: IntoIterator<Item = u8>,
852 {
853 todo!();
854 }
855
856 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error>
857 where
858 B: IntoIterator<Item = u8>,
859 {
860 todo!();
861 }
862
863 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { 849 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
864 self.blocking_write_read(address, wr_buffer, rd_buffer) 850 self.blocking_write_read(address, wr_buffer, rd_buffer)
865 } 851 }
@@ -871,13 +857,6 @@ mod eh1 {
871 ) -> Result<(), Self::Error> { 857 ) -> Result<(), Self::Error> {
872 todo!(); 858 todo!();
873 } 859 }
874
875 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
876 where
877 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
878 {
879 todo!();
880 }
881 } 860 }
882} 861}
883 862
@@ -885,28 +864,22 @@ mod eh1 {
885mod eha { 864mod eha {
886 use super::*; 865 use super::*;
887 impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { 866 impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
888 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Error> { 867 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
889 self.read(address, buffer).await 868 self.read(address, read).await
890 } 869 }
891 870
892 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Error> { 871 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
893 self.write(address, bytes).await 872 self.write(address, write).await
894 } 873 }
895 874 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
896 async fn write_read<'a>( 875 self.write_read(address, write, read).await
897 &'a mut self,
898 address: u8,
899 wr_buffer: &'a [u8],
900 rd_buffer: &'a mut [u8],
901 ) -> Result<(), Error> {
902 self.write_read(address, wr_buffer, rd_buffer).await
903 } 876 }
904 877
905 async fn transaction<'a, 'b>( 878 async fn transaction(
906 &'a mut self, 879 &mut self,
907 address: u8, 880 address: u8,
908 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 881 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
909 ) -> Result<(), Error> { 882 ) -> Result<(), Self::Error> {
910 let _ = address; 883 let _ = address;
911 let _ = operations; 884 let _ = operations;
912 todo!() 885 todo!()
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 209c665b0..cb9c7be77 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -65,9 +65,9 @@ rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c90
65#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } 65#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
66 66
67embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 67embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
68embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 68embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
69embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} 69embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
70embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} 70embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
71 71
72paste = "1.0" 72paste = "1.0"
73pio-proc = {version= "0.2", optional = true} 73pio-proc = {version= "0.2", optional = true}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index fb45ef7cf..98e182868 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -437,6 +437,37 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
437 pub fn is_low(&self) -> bool { 437 pub fn is_low(&self) -> bool {
438 self.pin.is_low() 438 self.pin.is_low()
439 } 439 }
440
441 /// Returns current pin level
442 #[inline]
443 pub fn get_level(&self) -> Level {
444 self.is_high().into()
445 }
446
447 #[inline]
448 pub async fn wait_for_high(&mut self) {
449 self.pin.wait_for_high().await;
450 }
451
452 #[inline]
453 pub async fn wait_for_low(&mut self) {
454 self.pin.wait_for_low().await;
455 }
456
457 #[inline]
458 pub async fn wait_for_rising_edge(&mut self) {
459 self.pin.wait_for_rising_edge().await;
460 }
461
462 #[inline]
463 pub async fn wait_for_falling_edge(&mut self) {
464 self.pin.wait_for_falling_edge().await;
465 }
466
467 #[inline]
468 pub async fn wait_for_any_edge(&mut self) {
469 self.pin.wait_for_any_edge().await;
470 }
440} 471}
441 472
442/// GPIO flexible pin. 473/// GPIO flexible pin.
@@ -1117,4 +1148,32 @@ mod eh1 {
1117 Ok(()) 1148 Ok(())
1118 } 1149 }
1119 } 1150 }
1151
1152 #[cfg(feature = "nightly")]
1153 impl<'d, T: Pin> embedded_hal_async::digital::Wait for OutputOpenDrain<'d, T> {
1154 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1155 self.wait_for_high().await;
1156 Ok(())
1157 }
1158
1159 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
1160 self.wait_for_low().await;
1161 Ok(())
1162 }
1163
1164 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
1165 self.wait_for_rising_edge().await;
1166 Ok(())
1167 }
1168
1169 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
1170 self.wait_for_falling_edge().await;
1171 Ok(())
1172 }
1173
1174 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
1175 self.wait_for_any_edge().await;
1176 Ok(())
1177 }
1178 }
1120} 1179}
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index e48e16d81..40e85c66f 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -490,14 +490,14 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
490 } 490 }
491 } 491 }
492 492
493 fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { 493 fn read_blocking_internal(&mut self, read: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
494 if buffer.is_empty() { 494 if read.is_empty() {
495 return Err(Error::InvalidReadBufferLength); 495 return Err(Error::InvalidReadBufferLength);
496 } 496 }
497 497
498 let p = T::regs(); 498 let p = T::regs();
499 let lastindex = buffer.len() - 1; 499 let lastindex = read.len() - 1;
500 for (i, byte) in buffer.iter_mut().enumerate() { 500 for (i, byte) in read.iter_mut().enumerate() {
501 let first = i == 0; 501 let first = i == 0;
502 let last = i == lastindex; 502 let last = i == lastindex;
503 503
@@ -524,15 +524,15 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
524 Ok(()) 524 Ok(())
525 } 525 }
526 526
527 fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { 527 fn write_blocking_internal(&mut self, write: &[u8], send_stop: bool) -> Result<(), Error> {
528 if bytes.is_empty() { 528 if write.is_empty() {
529 return Err(Error::InvalidWriteBufferLength); 529 return Err(Error::InvalidWriteBufferLength);
530 } 530 }
531 531
532 let p = T::regs(); 532 let p = T::regs();
533 533
534 for (i, byte) in bytes.iter().enumerate() { 534 for (i, byte) in write.iter().enumerate() {
535 let last = i == bytes.len() - 1; 535 let last = i == write.len() - 1;
536 536
537 // NOTE(unsafe) We have &mut self 537 // NOTE(unsafe) We have &mut self
538 unsafe { 538 unsafe {
@@ -572,21 +572,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
572 // Blocking public API 572 // Blocking public API
573 // ========================= 573 // =========================
574 574
575 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 575 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
576 Self::setup(address.into())?; 576 Self::setup(address.into())?;
577 self.read_blocking_internal(buffer, true, true) 577 self.read_blocking_internal(read, true, true)
578 // Automatic Stop 578 // Automatic Stop
579 } 579 }
580 580
581 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { 581 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
582 Self::setup(address.into())?; 582 Self::setup(address.into())?;
583 self.write_blocking_internal(bytes, true) 583 self.write_blocking_internal(write, true)
584 } 584 }
585 585
586 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 586 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
587 Self::setup(address.into())?; 587 Self::setup(address.into())?;
588 self.write_blocking_internal(bytes, false)?; 588 self.write_blocking_internal(write, false)?;
589 self.read_blocking_internal(buffer, true, true) 589 self.read_blocking_internal(read, true, true)
590 // Automatic Stop 590 // Automatic Stop
591 } 591 }
592} 592}
@@ -644,48 +644,22 @@ mod eh1 {
644 } 644 }
645 645
646 impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { 646 impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
647 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 647 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
648 self.blocking_read(address, buffer) 648 self.blocking_read(address, read)
649 } 649 }
650 650
651 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { 651 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
652 self.blocking_write(address, buffer) 652 self.blocking_write(address, write)
653 }
654
655 fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
656 where
657 B: IntoIterator<Item = u8>,
658 {
659 let mut peekable = bytes.into_iter().peekable();
660 Self::setup(address.into())?;
661
662 while let Some(tx) = peekable.next() {
663 self.write_blocking_internal(&[tx], peekable.peek().is_none())?;
664 }
665 Ok(())
666 }
667
668 fn write_iter_read<B>(&mut self, address: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error>
669 where
670 B: IntoIterator<Item = u8>,
671 {
672 let peekable = bytes.into_iter().peekable();
673 Self::setup(address.into())?;
674
675 for tx in peekable {
676 self.write_blocking_internal(&[tx], false)?
677 }
678 self.read_blocking_internal(buffer, true, true)
679 } 653 }
680 654
681 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { 655 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
682 self.blocking_write_read(address, wr_buffer, rd_buffer) 656 self.blocking_write_read(address, write, read)
683 } 657 }
684 658
685 fn transaction<'a>( 659 fn transaction(
686 &mut self, 660 &mut self,
687 address: u8, 661 address: u8,
688 operations: &mut [embedded_hal_1::i2c::Operation<'a>], 662 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
689 ) -> Result<(), Self::Error> { 663 ) -> Result<(), Self::Error> {
690 Self::setup(address.into())?; 664 Self::setup(address.into())?;
691 for i in 0..operations.len() { 665 for i in 0..operations.len() {
@@ -697,22 +671,6 @@ mod eh1 {
697 } 671 }
698 Ok(()) 672 Ok(())
699 } 673 }
700
701 fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
702 where
703 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
704 {
705 Self::setup(address.into())?;
706 let mut peekable = operations.into_iter().peekable();
707 while let Some(operation) = peekable.next() {
708 let last = peekable.peek().is_none();
709 match operation {
710 embedded_hal_1::i2c::Operation::Read(buf) => self.read_blocking_internal(buf, false, last)?,
711 embedded_hal_1::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
712 }
713 }
714 Ok(())
715 }
716 } 674 }
717} 675}
718#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 676#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
@@ -727,36 +685,29 @@ mod nightly {
727 A: AddressMode + Into<u16> + 'static, 685 A: AddressMode + Into<u16> + 'static,
728 T: Instance + 'd, 686 T: Instance + 'd,
729 { 687 {
730 async fn read<'a>(&'a mut self, address: A, read: &'a mut [u8]) -> Result<(), Self::Error> { 688 async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
731 let addr: u16 = address.into(); 689 let addr: u16 = address.into();
732 690
733 Self::setup(addr)?; 691 Self::setup(addr)?;
734 self.read_async_internal(read, false, true).await 692 self.read_async_internal(read, false, true).await
735 } 693 }
736 694
737 async fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Result<(), Self::Error> { 695 async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
738 let addr: u16 = address.into(); 696 let addr: u16 = address.into();
739 697
740 Self::setup(addr)?; 698 Self::setup(addr)?;
741 self.write_async_internal(write.iter().copied(), true).await 699 self.write_async_internal(write.iter().copied(), true).await
742 } 700 }
743 async fn write_read<'a>( 701
744 &'a mut self, 702 async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
745 address: A,
746 write: &'a [u8],
747 read: &'a mut [u8],
748 ) -> Result<(), Self::Error> {
749 let addr: u16 = address.into(); 703 let addr: u16 = address.into();
750 704
751 Self::setup(addr)?; 705 Self::setup(addr)?;
752 self.write_async_internal(write.iter().cloned(), false).await?; 706 self.write_async_internal(write.iter().cloned(), false).await?;
753 self.read_async_internal(read, false, true).await 707 self.read_async_internal(read, false, true).await
754 } 708 }
755 async fn transaction<'a, 'b>( 709
756 &'a mut self, 710 async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
757 address: A,
758 operations: &'a mut [Operation<'b>],
759 ) -> Result<(), Self::Error> {
760 let addr: u16 = address.into(); 711 let addr: u16 = address.into();
761 712
762 let mut iterator = operations.iter_mut(); 713 let mut iterator = operations.iter_mut();
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index ebd621ecf..742a35d49 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -19,6 +19,7 @@ pub enum Error {
19} 19}
20 20
21#[non_exhaustive] 21#[non_exhaustive]
22#[derive(Clone)]
22pub struct Config { 23pub struct Config {
23 pub frequency: u32, 24 pub frequency: u32,
24 pub phase: Phase, 25 pub phase: Phase,
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 14ec3d70a..a8ebacd25 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -8,10 +8,7 @@ license = "MIT OR Apache-2.0"
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" 8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" 9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/"
10 10
11# TODO: sdmmc 11features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"]
12# TODO: net
13# TODO: subghz
14features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any"]
15flavors = [ 12flavors = [
16 { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, 13 { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" },
17 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, 14 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
@@ -22,6 +19,7 @@ flavors = [
22 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, 19 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" },
23 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, 20 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" },
24 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, 21 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
22 { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" },
25 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, 23 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
26 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" }, 24 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" },
27 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, 25 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
@@ -44,9 +42,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
44embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 42embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
45 43
46embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 44embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
47embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
48embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} 46embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
49embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} 47embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
50 48
51embedded-storage = "0.3.0" 49embedded-storage = "0.3.0"
52 50
@@ -60,7 +58,7 @@ sdio-host = "0.5.0"
60embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } 58embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
61critical-section = "1.1" 59critical-section = "1.1"
62atomic-polyfill = "1.0.1" 60atomic-polyfill = "1.0.1"
63stm32-metapac = { version = "2", features = ["rt"] } 61stm32-metapac = "5"
64vcell = "0.1.3" 62vcell = "0.1.3"
65bxcan = "0.7.0" 63bxcan = "0.7.0"
66nb = "1.0.0" 64nb = "1.0.0"
@@ -69,15 +67,18 @@ seq-macro = "0.3.0"
69cfg-if = "1.0.0" 67cfg-if = "1.0.0"
70embedded-io = { version = "0.4.0", features = ["async"], optional = true } 68embedded-io = { version = "0.4.0", features = ["async"], optional = true }
71 69
70[dev-dependencies]
71critical-section = { version = "1.1", features = ["std"] }
72
72[build-dependencies] 73[build-dependencies]
73proc-macro2 = "1.0.36" 74proc-macro2 = "1.0.36"
74quote = "1.0.15" 75quote = "1.0.15"
75stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} 76stm32-metapac = { version = "5", default-features = false, features = ["metadata"]}
76 77
77[features] 78[features]
79default = ["stm32-metapac/rt"]
78defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] 80defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
79memory-x = ["stm32-metapac/memory-x"] 81memory-x = ["stm32-metapac/memory-x"]
80subghz = []
81exti = [] 82exti = []
82 83
83# Enables additional driver features that depend on embassy-time 84# Enables additional driver features that depend on embassy-time
@@ -830,6 +831,37 @@ stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ]
830stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] 831stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ]
831stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] 832stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ]
832stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] 833stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ]
834stm32h503cb = [ "stm32-metapac/stm32h503cb" ]
835stm32h503eb = [ "stm32-metapac/stm32h503eb" ]
836stm32h503kb = [ "stm32-metapac/stm32h503kb" ]
837stm32h503rb = [ "stm32-metapac/stm32h503rb" ]
838stm32h562ag = [ "stm32-metapac/stm32h562ag" ]
839stm32h562ai = [ "stm32-metapac/stm32h562ai" ]
840stm32h562ig = [ "stm32-metapac/stm32h562ig" ]
841stm32h562ii = [ "stm32-metapac/stm32h562ii" ]
842stm32h562rg = [ "stm32-metapac/stm32h562rg" ]
843stm32h562ri = [ "stm32-metapac/stm32h562ri" ]
844stm32h562vg = [ "stm32-metapac/stm32h562vg" ]
845stm32h562vi = [ "stm32-metapac/stm32h562vi" ]
846stm32h562zg = [ "stm32-metapac/stm32h562zg" ]
847stm32h562zi = [ "stm32-metapac/stm32h562zi" ]
848stm32h563ag = [ "stm32-metapac/stm32h563ag" ]
849stm32h563ai = [ "stm32-metapac/stm32h563ai" ]
850stm32h563ig = [ "stm32-metapac/stm32h563ig" ]
851stm32h563ii = [ "stm32-metapac/stm32h563ii" ]
852stm32h563mi = [ "stm32-metapac/stm32h563mi" ]
853stm32h563rg = [ "stm32-metapac/stm32h563rg" ]
854stm32h563ri = [ "stm32-metapac/stm32h563ri" ]
855stm32h563vg = [ "stm32-metapac/stm32h563vg" ]
856stm32h563vi = [ "stm32-metapac/stm32h563vi" ]
857stm32h563zg = [ "stm32-metapac/stm32h563zg" ]
858stm32h563zi = [ "stm32-metapac/stm32h563zi" ]
859stm32h573ai = [ "stm32-metapac/stm32h573ai" ]
860stm32h573ii = [ "stm32-metapac/stm32h573ii" ]
861stm32h573mi = [ "stm32-metapac/stm32h573mi" ]
862stm32h573ri = [ "stm32-metapac/stm32h573ri" ]
863stm32h573vi = [ "stm32-metapac/stm32h573vi" ]
864stm32h573zi = [ "stm32-metapac/stm32h573zi" ]
833stm32h723ve = [ "stm32-metapac/stm32h723ve" ] 865stm32h723ve = [ "stm32-metapac/stm32h723ve" ]
834stm32h723vg = [ "stm32-metapac/stm32h723vg" ] 866stm32h723vg = [ "stm32-metapac/stm32h723vg" ]
835stm32h723ze = [ "stm32-metapac/stm32h723ze" ] 867stm32h723ze = [ "stm32-metapac/stm32h723ze" ]
@@ -1312,6 +1344,22 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
1312stm32l562re = [ "stm32-metapac/stm32l562re" ] 1344stm32l562re = [ "stm32-metapac/stm32l562re" ]
1313stm32l562ve = [ "stm32-metapac/stm32l562ve" ] 1345stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
1314stm32l562ze = [ "stm32-metapac/stm32l562ze" ] 1346stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
1347stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
1348stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
1349stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
1350stm32u535je = [ "stm32-metapac/stm32u535je" ]
1351stm32u535nc = [ "stm32-metapac/stm32u535nc" ]
1352stm32u535ne = [ "stm32-metapac/stm32u535ne" ]
1353stm32u535rb = [ "stm32-metapac/stm32u535rb" ]
1354stm32u535rc = [ "stm32-metapac/stm32u535rc" ]
1355stm32u535re = [ "stm32-metapac/stm32u535re" ]
1356stm32u535vc = [ "stm32-metapac/stm32u535vc" ]
1357stm32u535ve = [ "stm32-metapac/stm32u535ve" ]
1358stm32u545ce = [ "stm32-metapac/stm32u545ce" ]
1359stm32u545je = [ "stm32-metapac/stm32u545je" ]
1360stm32u545ne = [ "stm32-metapac/stm32u545ne" ]
1361stm32u545re = [ "stm32-metapac/stm32u545re" ]
1362stm32u545ve = [ "stm32-metapac/stm32u545ve" ]
1315stm32u575ag = [ "stm32-metapac/stm32u575ag" ] 1363stm32u575ag = [ "stm32-metapac/stm32u575ag" ]
1316stm32u575ai = [ "stm32-metapac/stm32u575ai" ] 1364stm32u575ai = [ "stm32-metapac/stm32u575ai" ]
1317stm32u575cg = [ "stm32-metapac/stm32u575cg" ] 1365stm32u575cg = [ "stm32-metapac/stm32u575cg" ]
@@ -1333,6 +1381,32 @@ stm32u585qi = [ "stm32-metapac/stm32u585qi" ]
1333stm32u585ri = [ "stm32-metapac/stm32u585ri" ] 1381stm32u585ri = [ "stm32-metapac/stm32u585ri" ]
1334stm32u585vi = [ "stm32-metapac/stm32u585vi" ] 1382stm32u585vi = [ "stm32-metapac/stm32u585vi" ]
1335stm32u585zi = [ "stm32-metapac/stm32u585zi" ] 1383stm32u585zi = [ "stm32-metapac/stm32u585zi" ]
1384stm32u595ai = [ "stm32-metapac/stm32u595ai" ]
1385stm32u595aj = [ "stm32-metapac/stm32u595aj" ]
1386stm32u595qi = [ "stm32-metapac/stm32u595qi" ]
1387stm32u595qj = [ "stm32-metapac/stm32u595qj" ]
1388stm32u595ri = [ "stm32-metapac/stm32u595ri" ]
1389stm32u595rj = [ "stm32-metapac/stm32u595rj" ]
1390stm32u595vi = [ "stm32-metapac/stm32u595vi" ]
1391stm32u595vj = [ "stm32-metapac/stm32u595vj" ]
1392stm32u595zi = [ "stm32-metapac/stm32u595zi" ]
1393stm32u595zj = [ "stm32-metapac/stm32u595zj" ]
1394stm32u599bj = [ "stm32-metapac/stm32u599bj" ]
1395stm32u599ni = [ "stm32-metapac/stm32u599ni" ]
1396stm32u599nj = [ "stm32-metapac/stm32u599nj" ]
1397stm32u599vi = [ "stm32-metapac/stm32u599vi" ]
1398stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
1399stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
1400stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
1401stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
1402stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
1403stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
1404stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
1405stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ]
1406stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ]
1407stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ]
1408stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ]
1409stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ]
1336stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] 1410stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
1337stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] 1411stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
1338stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] 1412stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 481fec677..b01e8ba45 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -3,9 +3,9 @@ use std::fmt::Write as _;
3use std::path::PathBuf; 3use std::path::PathBuf;
4use std::{env, fs}; 4use std::{env, fs};
5 5
6use proc_macro2::TokenStream; 6use proc_macro2::{Ident, TokenStream};
7use quote::{format_ident, quote}; 7use quote::{format_ident, quote};
8use stm32_metapac::metadata::METADATA; 8use stm32_metapac::metadata::{MemoryRegionKind, METADATA};
9 9
10fn main() { 10fn main() {
11 let chip_name = match env::vars() 11 let chip_name = match env::vars()
@@ -50,7 +50,7 @@ fn main() {
50 // We *shouldn't* have singletons for these, but the HAL currently requires 50 // We *shouldn't* have singletons for these, but the HAL currently requires
51 // singletons, for using with RccPeripheral to enable/disable clocks to them. 51 // singletons, for using with RccPeripheral to enable/disable clocks to them.
52 "rcc" => { 52 "rcc" => {
53 if r.version.starts_with("h7") || r.version.starts_with("f4") { 53 if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") {
54 singletons.push("MCO1".to_string()); 54 singletons.push("MCO1".to_string());
55 singletons.push("MCO2".to_string()); 55 singletons.push("MCO2".to_string());
56 } 56 }
@@ -107,6 +107,94 @@ fn main() {
107 }); 107 });
108 108
109 // ======== 109 // ========
110 // Generate FLASH regions
111 let mut flash_regions = TokenStream::new();
112 let flash_memory_regions: Vec<_> = METADATA
113 .memory
114 .iter()
115 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some())
116 .collect();
117 for region in flash_memory_regions.iter() {
118 let region_name = format_ident!("{}", get_flash_region_name(region.name));
119 let bank_variant = format_ident!(
120 "{}",
121 if region.name.starts_with("BANK_1") {
122 "Bank1"
123 } else if region.name.starts_with("BANK_2") {
124 "Bank2"
125 } else if region.name == "OTP" {
126 "Otp"
127 } else {
128 continue;
129 }
130 );
131 let base = region.address;
132 let size = region.size;
133 let settings = region.settings.as_ref().unwrap();
134 let erase_size = settings.erase_size;
135 let write_size = settings.write_size;
136 let erase_value = settings.erase_value;
137
138 flash_regions.extend(quote! {
139 pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion {
140 bank: crate::flash::FlashBank::#bank_variant,
141 base: #base,
142 size: #size,
143 erase_size: #erase_size,
144 write_size: #write_size,
145 erase_value: #erase_value,
146 };
147 });
148
149 let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
150 flash_regions.extend(quote! {
151 #[cfg(flash)]
152 pub struct #region_type<'d>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>,);
153 });
154 }
155
156 let (fields, (inits, region_names)): (Vec<TokenStream>, (Vec<TokenStream>, Vec<Ident>)) = flash_memory_regions
157 .iter()
158 .map(|f| {
159 let region_name = get_flash_region_name(f.name);
160 let field_name = format_ident!("{}", region_name.to_lowercase());
161 let field_type = format_ident!("{}", get_flash_region_type_name(f.name));
162 let field = quote! {
163 pub #field_name: #field_type<'d>
164 };
165 let region_name = format_ident!("{}", region_name);
166 let init = quote! {
167 #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()})
168 };
169
170 (field, (init, region_name))
171 })
172 .unzip();
173
174 let regions_len = flash_memory_regions.len();
175 flash_regions.extend(quote! {
176 #[cfg(flash)]
177 pub struct FlashLayout<'d> {
178 #(#fields),*
179 }
180
181 #[cfg(flash)]
182 impl<'d> FlashLayout<'d> {
183 pub(crate) fn new(mut p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
184 Self {
185 #(#inits),*
186 }
187 }
188 }
189
190 pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [
191 #(&#region_names),*
192 ];
193 });
194
195 g.extend(quote! { pub mod flash_regions { #flash_regions } });
196
197 // ========
110 // Generate DMA IRQs. 198 // Generate DMA IRQs.
111 199
112 let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); 200 let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new();
@@ -451,7 +539,10 @@ fn main() {
451 // MCO is special 539 // MCO is special
452 if pin.signal.starts_with("MCO_") { 540 if pin.signal.starts_with("MCO_") {
453 // Supported in H7 only for now 541 // Supported in H7 only for now
454 if regs.version.starts_with("h7") || regs.version.starts_with("f4") { 542 if regs.version.starts_with("h5")
543 || regs.version.starts_with("h7")
544 || regs.version.starts_with("f4")
545 {
455 peri = format_ident!("{}", pin.signal.replace("_", "")); 546 peri = format_ident!("{}", pin.signal.replace("_", ""));
456 } else { 547 } else {
457 continue; 548 continue;
@@ -578,11 +669,25 @@ fn main() {
578 // ======== 669 // ========
579 // Write foreach_foo! macrotables 670 // Write foreach_foo! macrotables
580 671
672 let mut flash_regions_table: Vec<Vec<String>> = Vec::new();
581 let mut interrupts_table: Vec<Vec<String>> = Vec::new(); 673 let mut interrupts_table: Vec<Vec<String>> = Vec::new();
582 let mut peripherals_table: Vec<Vec<String>> = Vec::new(); 674 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
583 let mut pins_table: Vec<Vec<String>> = Vec::new(); 675 let mut pins_table: Vec<Vec<String>> = Vec::new();
584 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 676 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
585 677
678 for m in METADATA
679 .memory
680 .iter()
681 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some())
682 {
683 let settings = m.settings.as_ref().unwrap();
684 let mut row = Vec::new();
685 row.push(get_flash_region_type_name(m.name));
686 row.push(settings.write_size.to_string());
687 row.push(settings.erase_size.to_string());
688 flash_regions_table.push(row);
689 }
690
586 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; 691 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32;
587 let gpio_stride = 0x400; 692 let gpio_stride = 0x400;
588 693
@@ -679,6 +784,7 @@ fn main() {
679 784
680 let mut m = String::new(); 785 let mut m = String::new();
681 786
787 make_table(&mut m, "foreach_flash_region", &flash_regions_table);
682 make_table(&mut m, "foreach_interrupt", &interrupts_table); 788 make_table(&mut m, "foreach_interrupt", &interrupts_table);
683 make_table(&mut m, "foreach_peripheral", &peripherals_table); 789 make_table(&mut m, "foreach_peripheral", &peripherals_table);
684 make_table(&mut m, "foreach_pin", &pins_table); 790 make_table(&mut m, "foreach_pin", &pins_table);
@@ -831,3 +937,19 @@ macro_rules! {} {{
831 ) 937 )
832 .unwrap(); 938 .unwrap();
833} 939}
940
941fn get_flash_region_name(name: &str) -> String {
942 let name = name.replace("BANK_", "BANK").replace("REGION_", "REGION");
943 if name.contains("REGION") {
944 name
945 } else {
946 name + "_REGION"
947 }
948}
949
950fn get_flash_region_type_name(name: &str) -> String {
951 get_flash_region_name(name)
952 .replace("BANK", "Bank")
953 .replace("REGION", "Region")
954 .replace("_", "")
955}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ec49dace7..56ecd63ca 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -7,21 +7,18 @@
7#[cfg_attr(adc_v4, path = "v4.rs")] 7#[cfg_attr(adc_v4, path = "v4.rs")]
8mod _version; 8mod _version;
9 9
10#[cfg(not(any(adc_f1, adc_v1)))] 10#[cfg(not(adc_f1))]
11mod resolution; 11mod resolution;
12#[cfg(not(adc_v1))]
13mod sample_time; 12mod sample_time;
14 13
15#[allow(unused)] 14#[allow(unused)]
16pub use _version::*; 15pub use _version::*;
17#[cfg(not(any(adc_f1, adc_v1)))] 16#[cfg(not(adc_f1))]
18pub use resolution::Resolution; 17pub use resolution::Resolution;
19#[cfg(not(adc_v1))]
20pub use sample_time::SampleTime; 18pub use sample_time::SampleTime;
21 19
22use crate::peripherals; 20use crate::peripherals;
23 21
24#[cfg(not(adc_v1))]
25pub struct Adc<'d, T: Instance> { 22pub struct Adc<'d, T: Instance> {
26 #[allow(unused)] 23 #[allow(unused)]
27 adc: crate::PeripheralRef<'d, T>, 24 adc: crate::PeripheralRef<'d, T>,
@@ -44,9 +41,9 @@ pub(crate) mod sealed {
44 } 41 }
45} 42}
46 43
47#[cfg(not(any(adc_f1, adc_v2, adc_v4)))] 44#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))]
48pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 45pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
49#[cfg(any(adc_f1, adc_v2, adc_v4))] 46#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))]
50pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 47pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
51 48
52pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 49pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 62b52a46c..67fb9b8c0 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,4 +1,4 @@
1#[cfg(any(adc_v2, adc_v3, adc_g0))] 1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
2#[derive(Clone, Copy, Debug, Eq, PartialEq)] 2#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3pub enum Resolution { 3pub enum Resolution {
4 TwelveBit, 4 TwelveBit,
@@ -19,7 +19,7 @@ pub enum Resolution {
19 19
20impl Default for Resolution { 20impl Default for Resolution {
21 fn default() -> Self { 21 fn default() -> Self {
22 #[cfg(any(adc_v2, adc_v3, adc_g0))] 22 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
23 { 23 {
24 Self::TwelveBit 24 Self::TwelveBit
25 } 25 }
@@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, 40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, 41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, 42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
43 #[cfg(any(adc_v2, adc_v3, adc_g0))] 43 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, 44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
45 } 45 }
46 } 46 }
@@ -56,7 +56,7 @@ impl Resolution {
56 Resolution::TwelveBit => (1 << 12) - 1, 56 Resolution::TwelveBit => (1 << 12) - 1,
57 Resolution::TenBit => (1 << 10) - 1, 57 Resolution::TenBit => (1 << 10) - 1,
58 Resolution::EightBit => (1 << 8) - 1, 58 Resolution::EightBit => (1 << 8) - 1,
59 #[cfg(any(adc_v2, adc_v3, adc_g0))] 59 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
60 Resolution::SixBit => (1 << 6) - 1, 60 Resolution::SixBit => (1 << 6) - 1,
61 } 61 }
62 } 62 }
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index bc5fb1d6f..0faa1e3c0 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -25,7 +25,7 @@ macro_rules! impl_sample_time {
25 }; 25 };
26} 26}
27 27
28#[cfg(adc_f1)] 28#[cfg(any(adc_f1, adc_v1))]
29impl_sample_time!( 29impl_sample_time!(
30 "1.5", 30 "1.5",
31 Cycles1_5, 31 Cycles1_5,
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 8b1378917..82a8c3efb 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -1 +1,171 @@
1use embassy_hal_common::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs;
1 3
4use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
5use crate::peripherals::ADC;
6use crate::Peripheral;
7
8pub const VDDA_CALIB_MV: u32 = 3300;
9pub const VREF_INT: u32 = 1230;
10
11pub struct Vbat;
12impl InternalChannel<ADC> for Vbat {}
13impl super::sealed::InternalChannel<ADC> for Vbat {
14 fn channel(&self) -> u8 {
15 18
16 }
17}
18
19pub struct Vref;
20impl InternalChannel<ADC> for Vref {}
21impl super::sealed::InternalChannel<ADC> for Vref {
22 fn channel(&self) -> u8 {
23 17
24 }
25}
26
27pub struct Temperature;
28impl InternalChannel<ADC> for Temperature {}
29impl super::sealed::InternalChannel<ADC> for Temperature {
30 fn channel(&self) -> u8 {
31 16
32 }
33}
34
35impl<'d, T: Instance> Adc<'d, T> {
36 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
37 into_ref!(adc);
38 T::enable();
39 T::reset();
40
41 // Delay 1μs when using HSI14 as the ADC clock.
42 //
43 // Table 57. ADC characteristics
44 // tstab = 14 * 1/fadc
45 delay.delay_us(1);
46
47 let s = Self {
48 adc,
49 sample_time: Default::default(),
50 };
51 s.calibrate();
52 s
53 }
54
55 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
56 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
57 //
58 // 6.3.20 Vbat monitoring characteristics
59 // ts_vbat ≥ 4μs
60 unsafe {
61 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
62 }
63 Vbat
64 }
65
66 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
67 // Table 28. Embedded internal reference voltage
68 // tstart = 10μs
69 unsafe {
70 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
71 }
72 delay.delay_us(10);
73 Vref
74 }
75
76 pub fn enable_temperature(&self, delay: &mut impl DelayUs<u32>) -> Temperature {
77 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
78 //
79 // 6.3.19 Temperature sensor characteristics
80 // tstart ≤ 10μs
81 // ts_temp ≥ 4μs
82 unsafe {
83 T::regs().ccr().modify(|reg| reg.set_tsen(true));
84 }
85 delay.delay_us(10);
86 Temperature
87 }
88
89 fn calibrate(&self) {
90 unsafe {
91 // A.7.1 ADC calibration code example
92 if T::regs().cr().read().aden() {
93 T::regs().cr().modify(|reg| reg.set_addis(true));
94 }
95 while T::regs().cr().read().aden() {
96 // spin
97 }
98 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
99 T::regs().cr().modify(|reg| reg.set_adcal(true));
100 while T::regs().cr().read().adcal() {
101 // spin
102 }
103 }
104 }
105
106 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
107 self.sample_time = sample_time;
108 }
109
110 pub fn set_resolution(&mut self, resolution: Resolution) {
111 unsafe {
112 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
113 }
114 }
115
116 pub fn read<P>(&mut self, pin: &mut P) -> u16
117 where
118 P: AdcPin<T> + crate::gpio::sealed::Pin,
119 {
120 let channel = pin.channel();
121 unsafe {
122 pin.set_as_analog();
123 self.read_channel(channel)
124 }
125 }
126
127 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
128 let channel = channel.channel();
129 unsafe { self.read_channel(channel) }
130 }
131
132 unsafe fn read_channel(&mut self, channel: u8) -> u16 {
133 // A.7.2 ADC enable sequence code example
134 if T::regs().isr().read().adrdy() {
135 T::regs().isr().modify(|reg| reg.set_adrdy(true));
136 }
137 T::regs().cr().modify(|reg| reg.set_aden(true));
138 while !T::regs().isr().read().adrdy() {
139 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
140 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
141 // ADEN bit until the ADRDY flag goes high.
142 T::regs().cr().modify(|reg| reg.set_aden(true));
143 }
144
145 T::regs().isr().modify(|reg| {
146 reg.set_eoc(true);
147 reg.set_eosmp(true);
148 });
149
150 // A.7.5 Single conversion sequence code example - Software trigger
151 T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
152 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
153 T::regs().cr().modify(|reg| reg.set_adstart(true));
154 while !T::regs().isr().read().eoc() {
155 // spin
156 }
157 let value = T::regs().dr().read().0 as u16;
158
159 // A.7.3 ADC disable code example
160 T::regs().cr().modify(|reg| reg.set_adstp(true));
161 while T::regs().cr().read().adstp() {
162 // spin
163 }
164 T::regs().cr().modify(|reg| reg.set_addis(true));
165 while T::regs().cr().read().aden() {
166 // spin
167 }
168
169 value
170 }
171}
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 442fee48e..6f26fd194 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -190,6 +190,10 @@ mod low_level_api {
190 fence(Ordering::SeqCst); 190 fence(Ordering::SeqCst);
191 191
192 let ch = dma.ch(channel_number as _); 192 let ch = dma.ch(channel_number as _);
193
194 // Reset ch
195 ch.cr().write(|w| w.set_reset(true));
196
193 ch.llr().write(|_| {}); // no linked list 197 ch.llr().write(|_| {}); // no linked list
194 ch.tr1().write(|w| { 198 ch.tr1().write(|w| {
195 w.set_sdw(data_size.into()); 199 w.set_sdw(data_size.into());
@@ -252,7 +256,7 @@ mod low_level_api {
252 /// Gets the running status of the channel 256 /// Gets the running status of the channel
253 pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool { 257 pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool {
254 let ch = dma.ch(ch as _); 258 let ch = dma.ch(ch as _);
255 !ch.sr().read().idlef() 259 !ch.sr().read().tcf()
256 } 260 }
257 261
258 /// Gets the total remaining transfers for the channel 262 /// Gets the total remaining transfers for the channel
@@ -291,7 +295,10 @@ mod low_level_api {
291 } 295 }
292 296
293 if sr.suspf() || sr.tcf() { 297 if sr.suspf() || sr.tcf() {
294 ch.cr().write(|w| w.set_reset(true)); 298 // disable all xxIEs to prevent the irq from firing again.
299 ch.cr().write(|_| {});
300
301 // Wake the future. It'll look at tcf and see it's set.
295 STATE.channels[state_index].waker.wake(); 302 STATE.channels[state_index].waker.wake();
296 } 303 }
297 } 304 }
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index fcb4a296c..d49b1f767 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -9,7 +9,7 @@ pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::*; 9use super::*;
10use crate::gpio::sealed::{AFType, Pin as _}; 10use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 11use crate::gpio::{AnyPin, Speed};
12use crate::pac::{ETH, RCC, SYSCFG}; 12use crate::pac::ETH;
13use crate::Peripheral; 13use crate::Peripheral;
14 14
15const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet 15const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
@@ -60,16 +60,33 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
60 unsafe { 60 unsafe {
61 // Enable the necessary Clocks 61 // Enable the necessary Clocks
62 // NOTE(unsafe) We have exclusive access to the registers 62 // NOTE(unsafe) We have exclusive access to the registers
63 #[cfg(not(rcc_h5))]
63 critical_section::with(|_| { 64 critical_section::with(|_| {
64 RCC.apb4enr().modify(|w| w.set_syscfgen(true)); 65 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
65 RCC.ahb1enr().modify(|w| { 66 crate::pac::RCC.ahb1enr().modify(|w| {
66 w.set_eth1macen(true); 67 w.set_eth1macen(true);
67 w.set_eth1txen(true); 68 w.set_eth1txen(true);
68 w.set_eth1rxen(true); 69 w.set_eth1rxen(true);
69 }); 70 });
70 71
71 // RMII 72 // RMII
72 SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); 73 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
74 });
75
76 #[cfg(rcc_h5)]
77 critical_section::with(|_| {
78 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
79
80 crate::pac::RCC.ahb1enr().modify(|w| {
81 w.set_ethen(true);
82 w.set_ethtxen(true);
83 w.set_ethrxen(true);
84 });
85
86 // RMII
87 crate::pac::SBS
88 .pmcr()
89 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
73 }); 90 });
74 91
75 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 92 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index e1ce09a49..10109e56a 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -25,11 +25,11 @@ fn cpu_regs() -> pac::exti::Exti {
25 EXTI 25 EXTI
26} 26}
27 27
28#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5)))] 28#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
29fn exticr_regs() -> pac::syscfg::Syscfg { 29fn exticr_regs() -> pac::syscfg::Syscfg {
30 pac::SYSCFG 30 pac::SYSCFG
31} 31}
32#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] 32#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
33fn exticr_regs() -> pac::exti::Exti { 33fn exticr_regs() -> pac::exti::Exti {
34 EXTI 34 EXTI
35} 35}
@@ -39,9 +39,9 @@ fn exticr_regs() -> pac::afio::Afio {
39} 39}
40 40
41pub unsafe fn on_irq() { 41pub unsafe fn on_irq() {
42 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] 42 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
43 let bits = EXTI.pr(0).read().0; 43 let bits = EXTI.pr(0).read().0;
44 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] 44 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
45 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; 45 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
46 46
47 // Mask all the channels that fired. 47 // Mask all the channels that fired.
@@ -53,9 +53,9 @@ pub unsafe fn on_irq() {
53 } 53 }
54 54
55 // Clear pending 55 // Clear pending
56 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] 56 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
57 EXTI.pr(0).write_value(Lines(bits)); 57 EXTI.pr(0).write_value(Lines(bits));
58 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] 58 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
59 { 59 {
60 EXTI.rpr(0).write_value(Lines(bits)); 60 EXTI.rpr(0).write_value(Lines(bits));
61 EXTI.fpr(0).write_value(Lines(bits)); 61 EXTI.fpr(0).write_value(Lines(bits));
@@ -213,9 +213,9 @@ impl<'a> ExtiInputFuture<'a> {
213 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); 213 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
214 214
215 // clear pending bit 215 // clear pending bit
216 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))] 216 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
217 EXTI.pr(0).write(|w| w.set_line(pin, true)); 217 EXTI.pr(0).write(|w| w.set_line(pin, true));
218 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))] 218 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
219 { 219 {
220 EXTI.rpr(0).write(|w| w.set_line(pin, true)); 220 EXTI.rpr(0).write(|w| w.set_line(pin, true));
221 EXTI.fpr(0).write(|w| w.set_line(pin, true)); 221 EXTI.fpr(0).write(|w| w.set_line(pin, true));
@@ -364,7 +364,7 @@ pub(crate) unsafe fn init() {
364 364
365 foreach_exti_irq!(enable_irq); 365 foreach_exti_irq!(enable_irq);
366 366
367 #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1)))] 367 #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))]
368 <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable(); 368 <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
369 #[cfg(stm32f1)] 369 #[cfg(stm32f1)]
370 <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable(); 370 <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
new file mode 100644
index 000000000..8235d6f08
--- /dev/null
+++ b/embassy-stm32/src/flash/common.rs
@@ -0,0 +1,211 @@
1use atomic_polyfill::{fence, Ordering};
2use embassy_hal_common::drop::OnDrop;
3use embassy_hal_common::{into_ref, PeripheralRef};
4
5use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
6use crate::flash::FlashBank;
7use crate::Peripheral;
8
9pub struct Flash<'d> {
10 inner: PeripheralRef<'d, crate::peripherals::FLASH>,
11}
12
13impl<'d> Flash<'d> {
14 pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self {
15 into_ref!(p);
16 Self { inner: p }
17 }
18
19 pub fn into_regions(self) -> FlashLayout<'d> {
20 FlashLayout::new(self.release())
21 }
22
23 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
24 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
25 }
26
27 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
28 unsafe { blocking_write(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) }
29 }
30
31 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
32 unsafe { blocking_erase(FLASH_BASE as u32, from, to) }
33 }
34
35 pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> {
36 let mut flash = self;
37 unsafe { flash.inner.clone_unchecked() }
38 }
39}
40
41fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
42 if offset + bytes.len() as u32 > size {
43 return Err(Error::Size);
44 }
45
46 let start_address = base + offset;
47 let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) };
48 bytes.copy_from_slice(flash_data);
49 Ok(())
50}
51
52unsafe fn blocking_write(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
53 if offset + bytes.len() as u32 > size {
54 return Err(Error::Size);
55 }
56 if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 {
57 return Err(Error::Unaligned);
58 }
59
60 let mut address = base + offset;
61 trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
62
63 for chunk in bytes.chunks(WRITE_SIZE) {
64 critical_section::with(|_| {
65 family::clear_all_err();
66 fence(Ordering::SeqCst);
67 family::unlock();
68 fence(Ordering::SeqCst);
69 family::begin_write();
70 fence(Ordering::SeqCst);
71
72 let _on_drop = OnDrop::new(|| {
73 family::end_write();
74 fence(Ordering::SeqCst);
75 family::lock();
76 });
77
78 family::blocking_write(address, chunk.try_into().unwrap())
79 })?;
80 address += WRITE_SIZE as u32;
81 }
82 Ok(())
83}
84
85unsafe fn blocking_erase(base: u32, from: u32, to: u32) -> Result<(), Error> {
86 let start_address = base + from;
87 let end_address = base + to;
88 let regions = family::get_flash_regions();
89
90 // Test if the address range is aligned at sector base addresses
91 let mut address = start_address;
92 while address < end_address {
93 let sector = get_sector(address, regions);
94 if sector.start != address {
95 return Err(Error::Unaligned);
96 }
97 address += sector.size;
98 }
99 if address != end_address {
100 return Err(Error::Unaligned);
101 }
102
103 trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
104
105 let mut address = start_address;
106 while address < end_address {
107 let sector = get_sector(address, regions);
108 trace!("Erasing sector: {:?}", sector);
109
110 critical_section::with(|_| {
111 family::clear_all_err();
112 fence(Ordering::SeqCst);
113 family::unlock();
114 fence(Ordering::SeqCst);
115
116 let _on_drop = OnDrop::new(|| {
117 family::lock();
118 });
119
120 family::blocking_erase_sector(&sector)
121 })?;
122 address += sector.size;
123 }
124 Ok(())
125}
126
127pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
128 let mut current_bank = FlashBank::Bank1;
129 let mut bank_offset = 0;
130 for region in regions {
131 if region.bank != current_bank {
132 current_bank = region.bank;
133 bank_offset = 0;
134 }
135
136 if address < region.end() {
137 let index_in_region = (address - region.base) / region.erase_size;
138 return FlashSector {
139 bank: region.bank,
140 index_in_bank: bank_offset + index_in_region as u8,
141 start: region.base + index_in_region * region.erase_size,
142 size: region.erase_size,
143 };
144 }
145
146 bank_offset += region.sectors();
147 }
148
149 panic!("Flash sector not found");
150}
151
152impl FlashRegion {
153 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
154 blocking_read(self.base, self.size, offset, bytes)
155 }
156
157 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
158 unsafe { blocking_write(self.base, self.size, offset, bytes) }
159 }
160
161 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
162 unsafe { blocking_erase(self.base, from, to) }
163 }
164}
165
166foreach_flash_region! {
167 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
168 impl crate::_generated::flash_regions::$type_name<'_> {
169 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
170 blocking_read(self.0.base, self.0.size, offset, bytes)
171 }
172
173 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
174 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes) }
175 }
176
177 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
178 unsafe { blocking_erase(self.0.base, from, to) }
179 }
180 }
181
182 impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> {
183 type Error = Error;
184 }
185
186 impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
187 const READ_SIZE: usize = 1;
188
189 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
190 self.blocking_read(offset, bytes)
191 }
192
193 fn capacity(&self) -> usize {
194 self.0.size as usize
195 }
196 }
197
198 impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> {
199 const WRITE_SIZE: usize = $write_size;
200 const ERASE_SIZE: usize = $erase_size;
201
202 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
203 self.blocking_write(offset, bytes)
204 }
205
206 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
207 self.blocking_erase(from, to)
208 }
209 }
210 };
211}
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 1cb08ee1a..10a09c42c 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -1,9 +1,16 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3
4use atomic_polyfill::{fence, Ordering};
5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 7use crate::flash::Error;
5use crate::pac; 8use crate::pac;
6 9
10pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
11 &FLASH_REGIONS
12}
13
7pub(crate) unsafe fn lock() { 14pub(crate) unsafe fn lock() {
8 pac::FLASH.cr().modify(|w| w.set_lock(true)); 15 pac::FLASH.cr().modify(|w| w.set_lock(true));
9} 16}
@@ -13,58 +20,55 @@ pub(crate) unsafe fn unlock() {
13 pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); 20 pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
14} 21}
15 22
16pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 23pub(crate) unsafe fn begin_write() {
24 assert_eq!(0, WRITE_SIZE % 2);
25
17 pac::FLASH.cr().write(|w| w.set_pg(true)); 26 pac::FLASH.cr().write(|w| w.set_pg(true));
27}
18 28
19 let ret = { 29pub(crate) unsafe fn end_write() {
20 let mut ret: Result<(), Error> = Ok(()); 30 pac::FLASH.cr().write(|w| w.set_pg(false));
21 let mut offset = offset; 31}
22 for chunk in buf.chunks(2) {
23 write_volatile(offset as *mut u16, u16::from_le_bytes(chunk[0..2].try_into().unwrap()));
24 offset += chunk.len() as u32;
25 32
26 ret = blocking_wait_ready(); 33pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
27 if ret.is_err() { 34 let mut address = start_address;
28 break; 35 for chunk in buf.chunks(2) {
29 } 36 write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap()));
30 } 37 address += chunk.len() as u32;
31 ret
32 };
33 38
34 pac::FLASH.cr().write(|w| w.set_pg(false)); 39 // prevents parallelism errors
40 fence(Ordering::SeqCst);
41 }
35 42
36 ret 43 blocking_wait_ready()
37} 44}
38 45
39pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
40 for page in (from..to).step_by(super::ERASE_SIZE) { 47 pac::FLASH.cr().modify(|w| {
41 pac::FLASH.cr().modify(|w| { 48 w.set_per(true);
42 w.set_per(true); 49 });
43 });
44 50
45 pac::FLASH.ar().write(|w| w.set_far(page)); 51 pac::FLASH.ar().write(|w| w.set_far(sector.start));
46 52
47 pac::FLASH.cr().modify(|w| { 53 pac::FLASH.cr().modify(|w| {
48 w.set_strt(true); 54 w.set_strt(true);
49 }); 55 });
50 56
51 let mut ret: Result<(), Error> = blocking_wait_ready(); 57 let mut ret: Result<(), Error> = blocking_wait_ready();
52 58
53 if !pac::FLASH.sr().read().eop() { 59 if !pac::FLASH.sr().read().eop() {
54 trace!("FLASH: EOP not set"); 60 trace!("FLASH: EOP not set");
55 ret = Err(Error::Prog); 61 ret = Err(Error::Prog);
56 } else { 62 } else {
57 pac::FLASH.sr().write(|w| w.set_eop(true)); 63 pac::FLASH.sr().write(|w| w.set_eop(true));
58 } 64 }
59 65
60 pac::FLASH.cr().modify(|w| w.set_per(false)); 66 pac::FLASH.cr().modify(|w| w.set_per(false));
61 67
62 clear_all_err(); 68 clear_all_err();
63 if ret.is_err() { 69 if ret.is_err() {
64 return ret; 70 return ret;
65 }
66 } 71 }
67
68 Ok(()) 72 Ok(())
69} 73}
70 74
@@ -82,7 +86,7 @@ pub(crate) unsafe fn clear_all_err() {
82 }); 86 });
83} 87}
84 88
85pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 89unsafe fn blocking_wait_ready() -> Result<(), Error> {
86 loop { 90 loop {
87 let sr = pac::FLASH.sr().read(); 91 let sr = pac::FLASH.sr().read();
88 92
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 9e23a8adf..2ce9df69f 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -2,27 +2,108 @@ use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; 5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9const SECOND_BANK_SECTOR_START: u32 = 12; 9#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
10mod alt_regions {
11 use embassy_hal_common::PeripheralRef;
12 use stm32_metapac::FLASH_SIZE;
10 13
11unsafe fn is_dual_bank() -> bool { 14 use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
12 match FLASH_SIZE / 1024 { 15 use crate::flash::{Bank1Region1, Bank1Region2, Flash, FlashBank, FlashRegion};
13 // 1 MB devices depend on configuration 16 use crate::peripherals::FLASH;
14 1024 => { 17
15 if cfg!(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)) { 18 pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
16 pac::FLASH.optcr().read().db1m() 19 size: 3 * BANK1_REGION3.erase_size,
17 } else { 20 ..BANK1_REGION3
18 false 21 };
22 pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion {
23 bank: FlashBank::Bank2,
24 base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2,
25 ..BANK1_REGION1
26 };
27 pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion {
28 bank: FlashBank::Bank2,
29 base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2,
30 ..BANK1_REGION2
31 };
32 pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion {
33 bank: FlashBank::Bank2,
34 base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2,
35 size: 3 * BANK1_REGION3.erase_size,
36 ..BANK1_REGION3
37 };
38
39 pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [
40 &BANK1_REGION1,
41 &BANK1_REGION2,
42 &ALT_BANK1_REGION3,
43 &ALT_BANK2_REGION1,
44 &ALT_BANK2_REGION2,
45 &ALT_BANK2_REGION3,
46 ];
47
48 pub type AltBank1Region1<'d> = Bank1Region1<'d>;
49 pub type AltBank1Region2<'d> = Bank1Region2<'d>;
50 pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
51 pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
52 pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
53 pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
54
55 pub struct AltFlashLayout<'d> {
56 pub bank1_region1: AltBank1Region1<'d>,
57 pub bank1_region2: AltBank1Region2<'d>,
58 pub bank1_region3: AltBank1Region3<'d>,
59 pub bank2_region1: AltBank2Region1<'d>,
60 pub bank2_region2: AltBank2Region2<'d>,
61 pub bank2_region3: AltBank2Region3<'d>,
62 }
63
64 impl<'d> Flash<'d> {
65 pub fn into_alt_regions(self) -> AltFlashLayout<'d> {
66 unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
67
68 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
69 // Also, all flash region operations are protected with a cs.
70 let mut p = self.release();
71 AltFlashLayout {
72 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }),
73 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }),
74 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }),
75 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }),
76 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }),
77 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }),
19 } 78 }
20 } 79 }
21 // 2 MB devices are always dual bank
22 2048 => true,
23 // All other devices are single bank
24 _ => false,
25 } 80 }
81
82 impl Drop for AltFlashLayout<'_> {
83 fn drop(&mut self) {
84 unsafe {
85 super::lock();
86 crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false))
87 };
88 }
89 }
90}
91
92#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
93pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS};
94
95#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
96pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
97 if unsafe { pac::FLASH.optcr().read().db1m() } {
98 &ALT_FLASH_REGIONS
99 } else {
100 &FLASH_REGIONS
101 }
102}
103
104#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
105pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
106 &FLASH_REGIONS
26} 107}
27 108
28pub(crate) unsafe fn lock() { 109pub(crate) unsafe fn lock() {
@@ -34,93 +115,34 @@ pub(crate) unsafe fn unlock() {
34 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 115 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
35} 116}
36 117
37pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 118pub(crate) unsafe fn begin_write() {
119 assert_eq!(0, WRITE_SIZE % 4);
120
38 pac::FLASH.cr().write(|w| { 121 pac::FLASH.cr().write(|w| {
39 w.set_pg(true); 122 w.set_pg(true);
40 w.set_psize(pac::flash::vals::Psize::PSIZE32); 123 w.set_psize(pac::flash::vals::Psize::PSIZE32);
41 }); 124 });
42
43 let ret = {
44 let mut ret: Result<(), Error> = Ok(());
45 let mut offset = offset;
46 for chunk in buf.chunks(super::WRITE_SIZE) {
47 for val in chunk.chunks(4) {
48 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
49 offset += val.len() as u32;
50
51 // prevents parallelism errors
52 fence(Ordering::SeqCst);
53 }
54
55 ret = blocking_wait_ready();
56 if ret.is_err() {
57 break;
58 }
59 }
60 ret
61 };
62
63 pac::FLASH.cr().write(|w| w.set_pg(false));
64
65 ret
66} 125}
67 126
68struct FlashSector { 127pub(crate) unsafe fn end_write() {
69 index: u8, 128 pac::FLASH.cr().write(|w| w.set_pg(false));
70 size: u32,
71}
72
73fn get_sector(addr: u32, dual_bank: bool) -> FlashSector {
74 let offset = addr - FLASH_BASE as u32;
75
76 let bank_size = match dual_bank {
77 true => FLASH_SIZE / 2,
78 false => FLASH_SIZE,
79 } as u32;
80
81 let bank = offset / bank_size;
82 let offset_in_bank = offset % bank_size;
83
84 let index_in_bank = if offset_in_bank >= ERASE_SIZE as u32 / 2 {
85 4 + offset_in_bank / ERASE_SIZE as u32
86 } else {
87 offset_in_bank / (ERASE_SIZE as u32 / 8)
88 };
89
90 // First 4 sectors are 16KB, then one 64KB, and rest are 128KB
91 let size = match index_in_bank {
92 0..=3 => 16 * 1024,
93 4 => 64 * 1024,
94 _ => 128 * 1024,
95 };
96
97 let index = if bank == 1 {
98 SECOND_BANK_SECTOR_START + index_in_bank
99 } else {
100 index_in_bank
101 } as u8;
102
103 FlashSector { index, size }
104} 129}
105 130
106pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 131pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
107 let mut addr = from; 132 let mut address = start_address;
108 let dual_bank = is_dual_bank(); 133 for val in buf.chunks(4) {
134 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
135 address += val.len() as u32;
109 136
110 while addr < to { 137 // prevents parallelism errors
111 let sector = get_sector(addr, dual_bank); 138 fence(Ordering::SeqCst);
112 erase_sector(sector.index)?;
113 addr += sector.size;
114 } 139 }
115 140
116 Ok(()) 141 blocking_wait_ready()
117} 142}
118 143
119unsafe fn erase_sector(sector: u8) -> Result<(), Error> { 144pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
120 let bank = sector / SECOND_BANK_SECTOR_START as u8; 145 let snb = ((sector.bank as u8) << 4) + sector.index_in_bank;
121 let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_START as u8);
122
123 trace!("Erasing sector: {}", sector);
124 146
125 pac::FLASH.cr().modify(|w| { 147 pac::FLASH.cr().modify(|w| {
126 w.set_ser(true); 148 w.set_ser(true);
@@ -148,7 +170,7 @@ pub(crate) unsafe fn clear_all_err() {
148 }); 170 });
149} 171}
150 172
151pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 173unsafe fn blocking_wait_ready() -> Result<(), Error> {
152 loop { 174 loop {
153 let sr = pac::FLASH.sr().read(); 175 let sr = pac::FLASH.sr().read();
154 176
@@ -173,3 +195,80 @@ pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> {
173 } 195 }
174 } 196 }
175} 197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::flash::{get_sector, FlashBank};
203
204 #[test]
205 #[cfg(stm32f429)]
206 fn can_get_sector_single_bank() {
207 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
208 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
209 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
210
211 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
212 assert_eq!(
213 FlashSector {
214 bank: FlashBank::Bank1,
215 index_in_bank,
216 start,
217 size
218 },
219 get_sector(address, &FLASH_REGIONS)
220 )
221 };
222
223 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
224 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
225 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
226 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
227
228 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
229 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
230
231 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
232 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
233 assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
234 assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
235
236 let assert_sector = |bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| {
237 assert_eq!(
238 FlashSector {
239 bank,
240 index_in_bank,
241 start,
242 size
243 },
244 get_sector(address, &ALT_FLASH_REGIONS)
245 )
246 };
247
248 assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
249 assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
250 assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
251 assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
252
253 assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
254 assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
255
256 assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
257 assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
258 assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
259 assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
260
261 assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000);
262 assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF);
263 assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000);
264 assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF);
265
266 assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000);
267 assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF);
268
269 assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000);
270 assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF);
271 assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
272 assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
273 }
274}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index dd0d8439d..6427d5a09 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -2,9 +2,14 @@ use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 6use crate::flash::Error;
6use crate::pac; 7use crate::pac;
7 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12
8pub(crate) unsafe fn lock() { 13pub(crate) unsafe fn lock() {
9 pac::FLASH.cr().modify(|w| w.set_lock(true)); 14 pac::FLASH.cr().modify(|w| w.set_lock(true));
10} 15}
@@ -14,64 +19,36 @@ pub(crate) unsafe fn unlock() {
14 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 19 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
15} 20}
16 21
17pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 22pub(crate) unsafe fn begin_write() {
23 assert_eq!(0, WRITE_SIZE % 4);
24
18 pac::FLASH.cr().write(|w| { 25 pac::FLASH.cr().write(|w| {
19 w.set_pg(true); 26 w.set_pg(true);
20 w.set_psize(pac::flash::vals::Psize::PSIZE32); 27 w.set_psize(pac::flash::vals::Psize::PSIZE32);
21 }); 28 });
29}
22 30
23 let ret = { 31pub(crate) unsafe fn end_write() {
24 let mut ret: Result<(), Error> = Ok(());
25 let mut offset = offset;
26 for chunk in buf.chunks(super::WRITE_SIZE) {
27 for val in chunk.chunks(4) {
28 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
29 offset += val.len() as u32;
30
31 // prevents parallelism errors
32 fence(Ordering::SeqCst);
33 }
34
35 ret = blocking_wait_ready();
36 if ret.is_err() {
37 break;
38 }
39 }
40 ret
41 };
42
43 pac::FLASH.cr().write(|w| w.set_pg(false)); 32 pac::FLASH.cr().write(|w| w.set_pg(false));
44
45 ret
46} 33}
47 34
48pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 35pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
49 let start_sector = if from >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { 36 let mut address = start_address;
50 4 + (from - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32 37 for val in buf.chunks(4) {
51 } else { 38 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
52 (from - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8) 39 address += val.len() as u32;
53 }; 40
54 41 // prevents parallelism errors
55 let end_sector = if to >= (super::FLASH_BASE + super::ERASE_SIZE / 2) as u32 { 42 fence(Ordering::SeqCst);
56 4 + (to - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32
57 } else {
58 (to - super::FLASH_BASE as u32) / (super::ERASE_SIZE as u32 / 8)
59 };
60
61 for sector in start_sector..end_sector {
62 let ret = erase_sector(sector as u8);
63 if ret.is_err() {
64 return ret;
65 }
66 } 43 }
67 44
68 Ok(()) 45 blocking_wait_ready()
69} 46}
70 47
71unsafe fn erase_sector(sector: u8) -> Result<(), Error> { 48pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
72 pac::FLASH.cr().modify(|w| { 49 pac::FLASH.cr().modify(|w| {
73 w.set_ser(true); 50 w.set_ser(true);
74 w.set_snb(sector) 51 w.set_snb(sector.index_in_bank)
75 }); 52 });
76 53
77 pac::FLASH.cr().modify(|w| { 54 pac::FLASH.cr().modify(|w| {
@@ -107,7 +84,7 @@ pub(crate) unsafe fn clear_all_err() {
107 }); 84 });
108} 85}
109 86
110pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 87unsafe fn blocking_wait_ready() -> Result<(), Error> {
111 loop { 88 loop {
112 let sr = pac::FLASH.sr().read(); 89 let sr = pac::FLASH.sr().read();
113 90
@@ -132,3 +109,75 @@ pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> {
132 } 109 }
133 } 110 }
134} 111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::flash::{get_sector, FlashBank};
117
118 #[test]
119 #[cfg(stm32f732)]
120 fn can_get_sector() {
121 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
122 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
123 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
124
125 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
126 assert_eq!(
127 FlashSector {
128 bank: FlashBank::Bank1,
129 index_in_bank,
130 start,
131 size
132 },
133 get_sector(address, &FLASH_REGIONS)
134 )
135 };
136
137 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
138 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
139 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
140 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
141
142 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
143 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
144
145 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
146 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
147 assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
148 assert_sector(7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
149 }
150
151 #[test]
152 #[cfg(stm32f769)]
153 fn can_get_sector() {
154 const SMALL_SECTOR_SIZE: u32 = 32 * 1024;
155 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024;
156 const LARGE_SECTOR_SIZE: u32 = 256 * 1024;
157
158 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| {
159 assert_eq!(
160 FlashSector {
161 bank: FlashBank::Bank1,
162 index_in_bank,
163 start,
164 size
165 },
166 get_sector(address, &FLASH_REGIONS)
167 )
168 };
169
170 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
171 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_7FFF);
172 assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_8000);
173 assert_sector(3, 0x0801_8000, SMALL_SECTOR_SIZE, 0x0801_FFFF);
174
175 assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0802_0000);
176 assert_sector(4, 0x0802_0000, MEDIUM_SECTOR_SIZE, 0x0803_FFFF);
177
178 assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0804_0000);
179 assert_sector(5, 0x0804_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
180 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000);
181 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
182 }
183}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 7de95ac11..4f38d50c0 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,13 +1,18 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3
4use atomic_polyfill::{fence, Ordering};
5
6use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 7use crate::flash::Error;
5use crate::pac; 8use crate::pac;
6 9
7const SECOND_BANK_OFFSET: usize = 0x0010_0000;
8
9const fn is_dual_bank() -> bool { 10const fn is_dual_bank() -> bool {
10 super::FLASH_SIZE / 2 > super::ERASE_SIZE 11 FLASH_REGIONS.len() == 2
12}
13
14pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
11} 16}
12 17
13pub(crate) unsafe fn lock() { 18pub(crate) unsafe fn lock() {
@@ -20,90 +25,64 @@ pub(crate) unsafe fn lock() {
20pub(crate) unsafe fn unlock() { 25pub(crate) unsafe fn unlock() {
21 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); 26 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
22 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); 27 pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
23
24 if is_dual_bank() { 28 if is_dual_bank() {
25 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); 29 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
26 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); 30 pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
27 } 31 }
28} 32}
29 33
30pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 34pub(crate) unsafe fn begin_write() {
31 let bank = if !is_dual_bank() || (offset - super::FLASH_BASE as u32) < SECOND_BANK_OFFSET as u32 { 35 assert_eq!(0, WRITE_SIZE % 4);
36}
37
38pub(crate) unsafe fn end_write() {}
39
40pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
41 // We cannot have the write setup sequence in begin_write as it depends on the address
42 let bank = if start_address < BANK1_REGION.end() {
32 pac::FLASH.bank(0) 43 pac::FLASH.bank(0)
33 } else { 44 } else {
34 pac::FLASH.bank(1) 45 pac::FLASH.bank(1)
35 }; 46 };
36
37 bank.cr().write(|w| { 47 bank.cr().write(|w| {
38 w.set_pg(true); 48 w.set_pg(true);
39 w.set_psize(2); // 32 bits at once 49 w.set_psize(2); // 32 bits at once
40 }); 50 });
41
42 cortex_m::asm::isb(); 51 cortex_m::asm::isb();
43 cortex_m::asm::dsb(); 52 cortex_m::asm::dsb();
44 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); 53 fence(Ordering::SeqCst);
45 54
46 let ret = { 55 let mut res = None;
47 let mut ret: Result<(), Error> = Ok(()); 56 let mut address = start_address;
48 let mut offset = offset; 57 for val in buf.chunks(4) {
49 'outer: for chunk in buf.chunks(super::WRITE_SIZE) { 58 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
50 for val in chunk.chunks(4) { 59 address += val.len() as u32;
51 trace!("Writing at {:x}", offset); 60
52 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); 61 res = Some(blocking_wait_ready(bank));
53 offset += val.len() as u32; 62 bank.sr().modify(|w| {
54 63 if w.eop() {
55 ret = blocking_wait_ready(bank); 64 w.set_eop(true);
56 bank.sr().modify(|w| {
57 if w.eop() {
58 w.set_eop(true);
59 }
60 });
61 if ret.is_err() {
62 break 'outer;
63 }
64 } 65 }
66 });
67 if res.unwrap().is_err() {
68 break;
65 } 69 }
66 ret 70 }
67 };
68 71
69 bank.cr().write(|w| w.set_pg(false)); 72 bank.cr().write(|w| w.set_pg(false));
70 73
71 cortex_m::asm::isb(); 74 cortex_m::asm::isb();
72 cortex_m::asm::dsb(); 75 cortex_m::asm::dsb();
73 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); 76 fence(Ordering::SeqCst);
74
75 ret
76}
77
78pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> {
79 let from = from - super::FLASH_BASE as u32;
80 let to = to - super::FLASH_BASE as u32;
81
82 let (start, end) = if to <= super::FLASH_SIZE as u32 {
83 let start_sector = from / super::ERASE_SIZE as u32;
84 let end_sector = to / super::ERASE_SIZE as u32;
85 (start_sector, end_sector)
86 } else {
87 error!("Attempting to write outside of defined sectors {:x} {:x}", from, to);
88 return Err(Error::Unaligned);
89 };
90
91 trace!("Erasing sectors from {} to {}", start, end);
92 for sector in start..end {
93 let bank = if sector >= 8 { 1 } else { 0 };
94 let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8);
95 if ret.is_err() {
96 return ret;
97 }
98 }
99 77
100 Ok(()) 78 res.unwrap()
101} 79}
102 80
103unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> { 81pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
82 let bank = pac::FLASH.bank(sector.bank as usize);
104 bank.cr().modify(|w| { 83 bank.cr().modify(|w| {
105 w.set_ser(true); 84 w.set_ser(true);
106 w.set_snb(sector) 85 w.set_snb(sector.index_in_bank)
107 }); 86 });
108 87
109 bank.cr().modify(|w| { 88 bank.cr().modify(|w| {
@@ -160,7 +139,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
160 }); 139 });
161} 140}
162 141
163pub(crate) unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { 142unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
164 loop { 143 loop {
165 let sr = bank.sr().read(); 144 let sr = bank.sr().read();
166 145
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 5048a3314..7d9cc6ea3 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,9 +1,15 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3 2
3use atomic_polyfill::{fence, Ordering};
4
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4use crate::flash::Error; 6use crate::flash::Error;
5use crate::pac; 7use crate::pac;
6 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12
7pub(crate) unsafe fn lock() { 13pub(crate) unsafe fn lock() {
8 #[cfg(any(flash_wl, flash_wb, flash_l4))] 14 #[cfg(any(flash_wl, flash_wb, flash_l4))]
9 pac::FLASH.cr().modify(|w| w.set_lock(true)); 15 pac::FLASH.cr().modify(|w| w.set_lock(true));
@@ -33,82 +39,75 @@ pub(crate) unsafe fn unlock() {
33 } 39 }
34} 40}
35 41
36pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { 42pub(crate) unsafe fn begin_write() {
43 assert_eq!(0, WRITE_SIZE % 4);
44
37 #[cfg(any(flash_wl, flash_wb, flash_l4))] 45 #[cfg(any(flash_wl, flash_wb, flash_l4))]
38 pac::FLASH.cr().write(|w| w.set_pg(true)); 46 pac::FLASH.cr().write(|w| w.set_pg(true));
47}
39 48
40 let ret = { 49pub(crate) unsafe fn end_write() {
41 let mut ret: Result<(), Error> = Ok(());
42 let mut offset = offset;
43 for chunk in buf.chunks(super::WRITE_SIZE) {
44 for val in chunk.chunks(4) {
45 write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap()));
46 offset += val.len() as u32;
47 }
48
49 ret = blocking_wait_ready();
50 if ret.is_err() {
51 break;
52 }
53 }
54 ret
55 };
56
57 #[cfg(any(flash_wl, flash_wb, flash_l4))] 50 #[cfg(any(flash_wl, flash_wb, flash_l4))]
58 pac::FLASH.cr().write(|w| w.set_pg(false)); 51 pac::FLASH.cr().write(|w| w.set_pg(false));
59
60 ret
61} 52}
62 53
63pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { 54pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
64 for page in (from..to).step_by(super::ERASE_SIZE) { 55 let mut address = start_address;
65 #[cfg(any(flash_l0, flash_l1))] 56 for val in buf.chunks(4) {
66 { 57 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
67 pac::FLASH.pecr().modify(|w| { 58 address += val.len() as u32;
68 w.set_erase(true);
69 w.set_prog(true);
70 });
71 59
72 write_volatile(page as *mut u32, 0xFFFFFFFF); 60 // prevents parallelism errors
73 } 61 fence(Ordering::SeqCst);
74 62 }
75 #[cfg(any(flash_wl, flash_wb, flash_l4))]
76 {
77 let idx = (page - super::FLASH_BASE as u32) / super::ERASE_SIZE as u32;
78
79 #[cfg(flash_l4)]
80 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
81
82 pac::FLASH.cr().modify(|w| {
83 w.set_per(true);
84 w.set_pnb(idx as u8);
85 #[cfg(any(flash_wl, flash_wb))]
86 w.set_strt(true);
87 #[cfg(any(flash_l4))]
88 w.set_start(true);
89 #[cfg(any(flash_l4))]
90 w.set_bker(bank);
91 });
92 }
93
94 let ret: Result<(), Error> = blocking_wait_ready();
95 63
96 #[cfg(any(flash_wl, flash_wb, flash_l4))] 64 blocking_wait_ready()
97 pac::FLASH.cr().modify(|w| w.set_per(false)); 65}
98 66
99 #[cfg(any(flash_l0, flash_l1))] 67pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
68 #[cfg(any(flash_l0, flash_l1))]
69 {
100 pac::FLASH.pecr().modify(|w| { 70 pac::FLASH.pecr().modify(|w| {
101 w.set_erase(false); 71 w.set_erase(true);
102 w.set_prog(false); 72 w.set_prog(true);
103 }); 73 });
104 74
105 clear_all_err(); 75 write_volatile(sector.start as *mut u32, 0xFFFFFFFF);
106 if ret.is_err() { 76 }
107 return ret; 77
108 } 78 #[cfg(any(flash_wl, flash_wb, flash_l4))]
79 {
80 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
81
82 #[cfg(flash_l4)]
83 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
84
85 pac::FLASH.cr().modify(|w| {
86 w.set_per(true);
87 w.set_pnb(idx as u8);
88 #[cfg(any(flash_wl, flash_wb))]
89 w.set_strt(true);
90 #[cfg(any(flash_l4))]
91 w.set_start(true);
92 #[cfg(any(flash_l4))]
93 w.set_bker(bank);
94 });
109 } 95 }
110 96
111 Ok(()) 97 let ret: Result<(), Error> = blocking_wait_ready();
98
99 #[cfg(any(flash_wl, flash_wb, flash_l4))]
100 pac::FLASH.cr().modify(|w| w.set_per(false));
101
102 #[cfg(any(flash_l0, flash_l1))]
103 pac::FLASH.pecr().modify(|w| {
104 w.set_erase(false);
105 w.set_prog(false);
106 });
107
108 clear_all_err();
109
110 ret
112} 111}
113 112
114pub(crate) unsafe fn clear_all_err() { 113pub(crate) unsafe fn clear_all_err() {
@@ -149,7 +148,7 @@ pub(crate) unsafe fn clear_all_err() {
149 }); 148 });
150} 149}
151 150
152pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { 151unsafe fn blocking_wait_ready() -> Result<(), Error> {
153 loop { 152 loop {
154 let sr = pac::FLASH.sr().read(); 153 let sr = pac::FLASH.sr().read();
155 154
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index b7166a437..231ff1f9e 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,89 +1,67 @@
1use embassy_hal_common::{into_ref, PeripheralRef}; 1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
2use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
3 2
4pub use crate::pac::{ERASE_SIZE, ERASE_VALUE, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 3#[cfg(flash)]
5use crate::peripherals::FLASH; 4mod common;
6use crate::Peripheral;
7const FLASH_END: usize = FLASH_BASE + FLASH_SIZE;
8 5
9#[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] 6#[cfg(flash)]
10#[cfg_attr(flash_f3, path = "f3.rs")] 7pub use common::*;
11#[cfg_attr(flash_f4, path = "f4.rs")]
12#[cfg_attr(flash_f7, path = "f7.rs")]
13#[cfg_attr(flash_h7, path = "h7.rs")]
14mod family;
15 8
16pub struct Flash<'d> { 9pub use crate::_generated::flash_regions::*;
17 _inner: PeripheralRef<'d, FLASH>, 10pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
18}
19 11
20impl<'d> Flash<'d> { 12#[derive(Debug)]
21 pub fn new(p: impl Peripheral<P = FLASH> + 'd) -> Self { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22 into_ref!(p); 14pub struct FlashRegion {
23 Self { _inner: p } 15 pub bank: FlashBank,
24 } 16 pub base: u32,
25 17 pub size: u32,
26 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 18 pub erase_size: u32,
27 let offset = FLASH_BASE as u32 + offset; 19 pub write_size: u32,
28 if offset as usize >= FLASH_END || offset as usize + bytes.len() > FLASH_END { 20 pub erase_value: u8,
29 return Err(Error::Size); 21}
30 }
31
32 let flash_data = unsafe { core::slice::from_raw_parts(offset as *const u8, bytes.len()) };
33 bytes.copy_from_slice(flash_data);
34 Ok(())
35 }
36
37 pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
38 let offset = FLASH_BASE as u32 + offset;
39 if offset as usize + buf.len() > FLASH_END {
40 return Err(Error::Size);
41 }
42 if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 {
43 return Err(Error::Unaligned);
44 }
45 trace!("Writing {} bytes at 0x{:x}", buf.len(), offset);
46
47 self.clear_all_err();
48
49 unsafe {
50 family::unlock();
51 let res = family::blocking_write(offset, buf);
52 family::lock();
53 res
54 }
55 }
56 22
57 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 23#[derive(Debug, PartialEq)]
58 let from = FLASH_BASE as u32 + from; 24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59 let to = FLASH_BASE as u32 + to; 25pub struct FlashSector {
60 if to < from || to as usize > FLASH_END { 26 pub bank: FlashBank,
61 return Err(Error::Size); 27 pub index_in_bank: u8,
62 } 28 pub start: u32,
63 if (from as usize % ERASE_SIZE) != 0 || (to as usize % ERASE_SIZE) != 0 { 29 pub size: u32,
64 return Err(Error::Unaligned); 30}
65 }
66 31
67 self.clear_all_err(); 32#[derive(Clone, Copy, Debug, PartialEq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub enum FlashBank {
35 Bank1 = 0,
36 Bank2 = 1,
37 Otp,
38}
68 39
69 unsafe { 40impl FlashRegion {
70 family::unlock(); 41 pub const fn end(&self) -> u32 {
71 let res = family::blocking_erase(from, to); 42 self.base + self.size
72 family::lock();
73 res
74 }
75 } 43 }
76 44
77 fn clear_all_err(&mut self) { 45 pub const fn sectors(&self) -> u8 {
78 unsafe { family::clear_all_err() }; 46 (self.size / self.erase_size) as u8
79 } 47 }
80} 48}
81 49
82impl Drop for Flash<'_> { 50#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
83 fn drop(&mut self) { 51#[cfg_attr(flash_f3, path = "f3.rs")]
84 unsafe { family::lock() }; 52#[cfg_attr(flash_f4, path = "f4.rs")]
85 } 53#[cfg_attr(flash_f7, path = "f7.rs")]
86} 54#[cfg_attr(flash_h7, path = "h7.rs")]
55#[cfg_attr(
56 not(any(
57 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f3, flash_f4, flash_f7, flash_h7
58 )),
59 path = "other.rs"
60)]
61mod family;
62
63#[allow(unused_imports)]
64pub use family::*;
87 65
88#[derive(Debug, Copy, Clone, PartialEq, Eq)] 66#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))] 67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -97,10 +75,6 @@ pub enum Error {
97 Parallelism, 75 Parallelism,
98} 76}
99 77
100impl<'d> ErrorType for Flash<'d> {
101 type Error = Error;
102}
103
104impl NorFlashError for Error { 78impl NorFlashError for Error {
105 fn kind(&self) -> NorFlashErrorKind { 79 fn kind(&self) -> NorFlashErrorKind {
106 match self { 80 match self {
@@ -110,28 +84,3 @@ impl NorFlashError for Error {
110 } 84 }
111 } 85 }
112} 86}
113
114impl<'d> ReadNorFlash for Flash<'d> {
115 const READ_SIZE: usize = WRITE_SIZE;
116
117 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
118 self.blocking_read(offset, bytes)
119 }
120
121 fn capacity(&self) -> usize {
122 FLASH_SIZE
123 }
124}
125
126impl<'d> NorFlash for Flash<'d> {
127 const WRITE_SIZE: usize = WRITE_SIZE;
128 const ERASE_SIZE: usize = ERASE_SIZE;
129
130 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
131 self.blocking_erase(from, to)
132 }
133
134 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
135 self.blocking_write(offset, bytes)
136 }
137}
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
new file mode 100644
index 000000000..c151cb828
--- /dev/null
+++ b/embassy-stm32/src/flash/other.rs
@@ -0,0 +1,29 @@
1#![allow(unused)]
2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4
5pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
6 &FLASH_REGIONS
7}
8
9pub(crate) unsafe fn lock() {
10 unimplemented!();
11}
12pub(crate) unsafe fn unlock() {
13 unimplemented!();
14}
15pub(crate) unsafe fn begin_write() {
16 unimplemented!();
17}
18pub(crate) unsafe fn end_write() {
19 unimplemented!();
20}
21pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
22 unimplemented!();
23}
24pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> {
25 unimplemented!();
26}
27pub(crate) unsafe fn clear_all_err() {
28 unimplemented!();
29}
diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs
index 4fca1ca2b..939e2750e 100644
--- a/embassy-stm32/src/i2c/timeout.rs
+++ b/embassy-stm32/src/i2c/timeout.rs
@@ -28,64 +28,64 @@ impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
28 } 28 }
29 29
30 /// Blocking read with a custom timeout 30 /// Blocking read with a custom timeout
31 pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { 31 pub fn blocking_read_timeout(&mut self, addr: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
32 self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout)) 32 self.i2c.blocking_read_timeout(addr, read, timeout_fn(timeout))
33 } 33 }
34 34
35 /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`] 35 /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
36 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { 36 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
37 self.blocking_read_timeout(addr, buffer, self.timeout) 37 self.blocking_read_timeout(addr, read, self.timeout)
38 } 38 }
39 39
40 /// Blocking write with a custom timeout 40 /// Blocking write with a custom timeout
41 pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> { 41 pub fn blocking_write_timeout(&mut self, addr: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
42 self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout)) 42 self.i2c.blocking_write_timeout(addr, write, timeout_fn(timeout))
43 } 43 }
44 44
45 /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`] 45 /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
46 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 46 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
47 self.blocking_write_timeout(addr, bytes, self.timeout) 47 self.blocking_write_timeout(addr, write, self.timeout)
48 } 48 }
49 49
50 /// Blocking write-read with a custom timeout 50 /// Blocking write-read with a custom timeout
51 pub fn blocking_write_read_timeout( 51 pub fn blocking_write_read_timeout(
52 &mut self, 52 &mut self,
53 addr: u8, 53 addr: u8,
54 bytes: &[u8], 54 write: &[u8],
55 buffer: &mut [u8], 55 read: &mut [u8],
56 timeout: Duration, 56 timeout: Duration,
57 ) -> Result<(), Error> { 57 ) -> Result<(), Error> {
58 self.i2c 58 self.i2c
59 .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout)) 59 .blocking_write_read_timeout(addr, write, read, timeout_fn(timeout))
60 } 60 }
61 61
62 /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`] 62 /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
63 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 63 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
64 self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout) 64 self.blocking_write_read_timeout(addr, write, read, self.timeout)
65 } 65 }
66} 66}
67 67
68impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> { 68impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
69 type Error = Error; 69 type Error = Error;
70 70
71 fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 71 fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
72 self.blocking_read(addr, buffer) 72 self.blocking_read(addr, read)
73 } 73 }
74} 74}
75 75
76impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> { 76impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
77 type Error = Error; 77 type Error = Error;
78 78
79 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { 79 fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
80 self.blocking_write(addr, bytes) 80 self.blocking_write(addr, write)
81 } 81 }
82} 82}
83 83
84impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> { 84impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
85 type Error = Error; 85 type Error = Error;
86 86
87 fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { 87 fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
88 self.blocking_write_read(addr, bytes, buffer) 88 self.blocking_write_read(addr, write, read)
89 } 89 }
90} 90}
91 91
@@ -98,45 +98,24 @@ mod eh1 {
98 } 98 }
99 99
100 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> { 100 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
101 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 101 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
102 self.blocking_read(address, buffer) 102 self.blocking_read(address, read)
103 } 103 }
104 104
105 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { 105 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
106 self.blocking_write(address, buffer) 106 self.blocking_write(address, write)
107 } 107 }
108 108
109 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> 109 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
110 where 110 self.blocking_write_read(address, write, read)
111 B: IntoIterator<Item = u8>,
112 {
113 todo!();
114 } 111 }
115 112
116 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> 113 fn transaction(
117 where
118 B: IntoIterator<Item = u8>,
119 {
120 todo!();
121 }
122
123 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
124 self.blocking_write_read(address, wr_buffer, rd_buffer)
125 }
126
127 fn transaction<'a>(
128 &mut self, 114 &mut self,
129 _address: u8, 115 _address: u8,
130 _operations: &mut [embedded_hal_1::i2c::Operation<'a>], 116 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
131 ) -> Result<(), Self::Error> { 117 ) -> Result<(), Self::Error> {
132 todo!(); 118 todo!();
133 } 119 }
134
135 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
136 where
137 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
138 {
139 todo!();
140 }
141 } 120 }
142} 121}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index f140e2b0d..4b47f0eb1 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -307,18 +307,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
307 } 307 }
308 } 308 }
309 309
310 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { 310 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
311 self.blocking_read_timeout(addr, buffer, || Ok(())) 311 self.blocking_read_timeout(addr, read, || Ok(()))
312 } 312 }
313 313
314 pub fn blocking_write_timeout( 314 pub fn blocking_write_timeout(
315 &mut self, 315 &mut self,
316 addr: u8, 316 addr: u8,
317 bytes: &[u8], 317 write: &[u8],
318 check_timeout: impl Fn() -> Result<(), Error>, 318 check_timeout: impl Fn() -> Result<(), Error>,
319 ) -> Result<(), Error> { 319 ) -> Result<(), Error> {
320 unsafe { 320 unsafe {
321 self.write_bytes(addr, bytes, &check_timeout)?; 321 self.write_bytes(addr, write, &check_timeout)?;
322 // Send a STOP condition 322 // Send a STOP condition
323 T::regs().cr1().modify(|reg| reg.set_stop(true)); 323 T::regs().cr1().modify(|reg| reg.set_stop(true));
324 // Wait for STOP condition to transmit. 324 // Wait for STOP condition to transmit.
@@ -331,49 +331,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
331 Ok(()) 331 Ok(())
332 } 332 }
333 333
334 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 334 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
335 self.blocking_write_timeout(addr, bytes, || Ok(())) 335 self.blocking_write_timeout(addr, write, || Ok(()))
336 } 336 }
337 337
338 pub fn blocking_write_read_timeout( 338 pub fn blocking_write_read_timeout(
339 &mut self, 339 &mut self,
340 addr: u8, 340 addr: u8,
341 bytes: &[u8], 341 write: &[u8],
342 buffer: &mut [u8], 342 read: &mut [u8],
343 check_timeout: impl Fn() -> Result<(), Error>, 343 check_timeout: impl Fn() -> Result<(), Error>,
344 ) -> Result<(), Error> { 344 ) -> Result<(), Error> {
345 unsafe { self.write_bytes(addr, bytes, &check_timeout)? }; 345 unsafe { self.write_bytes(addr, write, &check_timeout)? };
346 self.blocking_read_timeout(addr, buffer, &check_timeout)?; 346 self.blocking_read_timeout(addr, read, &check_timeout)?;
347 347
348 Ok(()) 348 Ok(())
349 } 349 }
350 350
351 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 351 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
352 self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(())) 352 self.blocking_write_read_timeout(addr, write, read, || Ok(()))
353 } 353 }
354} 354}
355 355
356impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 356impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
357 type Error = Error; 357 type Error = Error;
358 358
359 fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 359 fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
360 self.blocking_read(addr, buffer) 360 self.blocking_read(addr, read)
361 } 361 }
362} 362}
363 363
364impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { 364impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
365 type Error = Error; 365 type Error = Error;
366 366
367 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { 367 fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
368 self.blocking_write(addr, bytes) 368 self.blocking_write(addr, write)
369 } 369 }
370} 370}
371 371
372impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { 372impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
373 type Error = Error; 373 type Error = Error;
374 374
375 fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { 375 fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
376 self.blocking_write_read(addr, bytes, buffer) 376 self.blocking_write_read(addr, write, read)
377 } 377 }
378} 378}
379 379
@@ -402,46 +402,25 @@ mod eh1 {
402 } 402 }
403 403
404 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> { 404 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> {
405 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 405 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
406 self.blocking_read(address, buffer) 406 self.blocking_read(address, read)
407 }
408
409 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
410 self.blocking_write(address, buffer)
411 }
412
413 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
414 where
415 B: IntoIterator<Item = u8>,
416 {
417 todo!();
418 } 407 }
419 408
420 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> 409 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
421 where 410 self.blocking_write(address, write)
422 B: IntoIterator<Item = u8>,
423 {
424 todo!();
425 } 411 }
426 412
427 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { 413 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
428 self.blocking_write_read(address, wr_buffer, rd_buffer) 414 self.blocking_write_read(address, write, read)
429 } 415 }
430 416
431 fn transaction<'a>( 417 fn transaction(
432 &mut self, 418 &mut self,
433 _address: u8, 419 _address: u8,
434 _operations: &mut [embedded_hal_1::i2c::Operation<'a>], 420 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
435 ) -> Result<(), Self::Error> { 421 ) -> Result<(), Self::Error> {
436 todo!(); 422 todo!();
437 } 423 }
438
439 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
440 where
441 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
442 {
443 todo!();
444 }
445 } 424 }
446} 425}
447 426
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 06ff07b21..7218f7706 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -262,7 +262,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
262 if T::regs().isr().read().txis() { 262 if T::regs().isr().read().txis() {
263 T::regs().txdr().write(|w| w.set_txdata(0)); 263 T::regs().txdr().write(|w| w.set_txdata(0));
264 } 264 }
265 if T::regs().isr().read().txe() { 265 if !T::regs().isr().read().txe() {
266 T::regs().isr().modify(|w| w.set_txe(true)) 266 T::regs().isr().modify(|w| w.set_txe(true))
267 } 267 }
268 } 268 }
@@ -345,12 +345,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
345 fn read_internal( 345 fn read_internal(
346 &mut self, 346 &mut self,
347 address: u8, 347 address: u8,
348 buffer: &mut [u8], 348 read: &mut [u8],
349 restart: bool, 349 restart: bool,
350 check_timeout: impl Fn() -> Result<(), Error>, 350 check_timeout: impl Fn() -> Result<(), Error>,
351 ) -> Result<(), Error> { 351 ) -> Result<(), Error> {
352 let completed_chunks = buffer.len() / 255; 352 let completed_chunks = read.len() / 255;
353 let total_chunks = if completed_chunks * 255 == buffer.len() { 353 let total_chunks = if completed_chunks * 255 == read.len() {
354 completed_chunks 354 completed_chunks
355 } else { 355 } else {
356 completed_chunks + 1 356 completed_chunks + 1
@@ -360,7 +360,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
360 unsafe { 360 unsafe {
361 Self::master_read( 361 Self::master_read(
362 address, 362 address,
363 buffer.len().min(255), 363 read.len().min(255),
364 Stop::Automatic, 364 Stop::Automatic,
365 last_chunk_idx != 0, 365 last_chunk_idx != 0,
366 restart, 366 restart,
@@ -368,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
368 )?; 368 )?;
369 } 369 }
370 370
371 for (number, chunk) in buffer.chunks_mut(255).enumerate() { 371 for (number, chunk) in read.chunks_mut(255).enumerate() {
372 if number != 0 { 372 if number != 0 {
373 // NOTE(unsafe) We have &mut self 373 // NOTE(unsafe) We have &mut self
374 unsafe { 374 unsafe {
@@ -391,12 +391,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
391 fn write_internal( 391 fn write_internal(
392 &mut self, 392 &mut self,
393 address: u8, 393 address: u8,
394 bytes: &[u8], 394 write: &[u8],
395 send_stop: bool, 395 send_stop: bool,
396 check_timeout: impl Fn() -> Result<(), Error>, 396 check_timeout: impl Fn() -> Result<(), Error>,
397 ) -> Result<(), Error> { 397 ) -> Result<(), Error> {
398 let completed_chunks = bytes.len() / 255; 398 let completed_chunks = write.len() / 255;
399 let total_chunks = if completed_chunks * 255 == bytes.len() { 399 let total_chunks = if completed_chunks * 255 == write.len() {
400 completed_chunks 400 completed_chunks
401 } else { 401 } else {
402 completed_chunks + 1 402 completed_chunks + 1
@@ -410,14 +410,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
410 unsafe { 410 unsafe {
411 Self::master_write( 411 Self::master_write(
412 address, 412 address,
413 bytes.len().min(255), 413 write.len().min(255),
414 Stop::Software, 414 Stop::Software,
415 last_chunk_idx != 0, 415 last_chunk_idx != 0,
416 &check_timeout, 416 &check_timeout,
417 )?; 417 )?;
418 } 418 }
419 419
420 for (number, chunk) in bytes.chunks(255).enumerate() { 420 for (number, chunk) in write.chunks(255).enumerate() {
421 if number != 0 { 421 if number != 0 {
422 // NOTE(unsafe) We have &mut self 422 // NOTE(unsafe) We have &mut self
423 unsafe { 423 unsafe {
@@ -448,7 +448,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
448 async fn write_dma_internal( 448 async fn write_dma_internal(
449 &mut self, 449 &mut self,
450 address: u8, 450 address: u8,
451 bytes: &[u8], 451 write: &[u8],
452 first_slice: bool, 452 first_slice: bool,
453 last_slice: bool, 453 last_slice: bool,
454 check_timeout: impl Fn() -> Result<(), Error>, 454 check_timeout: impl Fn() -> Result<(), Error>,
@@ -456,7 +456,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
456 where 456 where
457 TXDMA: crate::i2c::TxDma<T>, 457 TXDMA: crate::i2c::TxDma<T>,
458 { 458 {
459 let total_len = bytes.len(); 459 let total_len = write.len();
460 let completed_chunks = total_len / 255; 460 let completed_chunks = total_len / 255;
461 let total_chunks = if completed_chunks * 255 == total_len { 461 let total_chunks = if completed_chunks * 255 == total_len {
462 completed_chunks 462 completed_chunks
@@ -476,7 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
476 476
477 let ch = &mut self.tx_dma; 477 let ch = &mut self.tx_dma;
478 let request = ch.request(); 478 let request = ch.request();
479 crate::dma::write(ch, request, bytes, dst) 479 crate::dma::write(ch, request, write, dst)
480 }; 480 };
481 481
482 let state = T::state(); 482 let state = T::state();
@@ -641,25 +641,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
641 // ========================= 641 // =========================
642 // Async public API 642 // Async public API
643 643
644 pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> 644 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
645 where 645 where
646 TXDMA: crate::i2c::TxDma<T>, 646 TXDMA: crate::i2c::TxDma<T>,
647 { 647 {
648 if bytes.is_empty() { 648 if write.is_empty() {
649 self.write_internal(address, bytes, true, || Ok(())) 649 self.write_internal(address, write, true, || Ok(()))
650 } else { 650 } else {
651 self.write_dma_internal(address, bytes, true, true, || Ok(())).await 651 self.write_dma_internal(address, write, true, true, || Ok(())).await
652 } 652 }
653 } 653 }
654 654
655 pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> 655 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
656 where 656 where
657 TXDMA: crate::i2c::TxDma<T>, 657 TXDMA: crate::i2c::TxDma<T>,
658 { 658 {
659 if bytes.is_empty() { 659 if write.is_empty() {
660 return Err(Error::ZeroLengthTransfer); 660 return Err(Error::ZeroLengthTransfer);
661 } 661 }
662 let mut iter = bytes.iter(); 662 let mut iter = write.iter();
663 663
664 let mut first = true; 664 let mut first = true;
665 let mut current = iter.next(); 665 let mut current = iter.next();
@@ -685,21 +685,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
685 } 685 }
686 } 686 }
687 687
688 pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> 688 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
689 where 689 where
690 TXDMA: super::TxDma<T>, 690 TXDMA: super::TxDma<T>,
691 RXDMA: super::RxDma<T>, 691 RXDMA: super::RxDma<T>,
692 { 692 {
693 if bytes.is_empty() { 693 if write.is_empty() {
694 self.write_internal(address, bytes, false, || Ok(()))?; 694 self.write_internal(address, write, false, || Ok(()))?;
695 } else { 695 } else {
696 self.write_dma_internal(address, bytes, true, true, || Ok(())).await?; 696 self.write_dma_internal(address, write, true, true, || Ok(())).await?;
697 } 697 }
698 698
699 if buffer.is_empty() { 699 if read.is_empty() {
700 self.read_internal(address, buffer, true, || Ok(()))?; 700 self.read_internal(address, read, true, || Ok(()))?;
701 } else { 701 } else {
702 self.read_dma_internal(address, buffer, true, || Ok(())).await?; 702 self.read_dma_internal(address, read, true, || Ok(())).await?;
703 } 703 }
704 704
705 Ok(()) 705 Ok(())
@@ -711,57 +711,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
711 pub fn blocking_read_timeout( 711 pub fn blocking_read_timeout(
712 &mut self, 712 &mut self,
713 address: u8, 713 address: u8,
714 buffer: &mut [u8], 714 read: &mut [u8],
715 check_timeout: impl Fn() -> Result<(), Error>, 715 check_timeout: impl Fn() -> Result<(), Error>,
716 ) -> Result<(), Error> { 716 ) -> Result<(), Error> {
717 self.read_internal(address, buffer, false, &check_timeout) 717 self.read_internal(address, read, false, &check_timeout)
718 // Automatic Stop 718 // Automatic Stop
719 } 719 }
720 720
721 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 721 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
722 self.blocking_read_timeout(address, buffer, || Ok(())) 722 self.blocking_read_timeout(address, read, || Ok(()))
723 } 723 }
724 724
725 pub fn blocking_write_timeout( 725 pub fn blocking_write_timeout(
726 &mut self, 726 &mut self,
727 address: u8, 727 address: u8,
728 bytes: &[u8], 728 write: &[u8],
729 check_timeout: impl Fn() -> Result<(), Error>, 729 check_timeout: impl Fn() -> Result<(), Error>,
730 ) -> Result<(), Error> { 730 ) -> Result<(), Error> {
731 self.write_internal(address, bytes, true, &check_timeout) 731 self.write_internal(address, write, true, &check_timeout)
732 } 732 }
733 733
734 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { 734 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
735 self.blocking_write_timeout(address, bytes, || Ok(())) 735 self.blocking_write_timeout(address, write, || Ok(()))
736 } 736 }
737 737
738 pub fn blocking_write_read_timeout( 738 pub fn blocking_write_read_timeout(
739 &mut self, 739 &mut self,
740 address: u8, 740 address: u8,
741 bytes: &[u8], 741 write: &[u8],
742 buffer: &mut [u8], 742 read: &mut [u8],
743 check_timeout: impl Fn() -> Result<(), Error>, 743 check_timeout: impl Fn() -> Result<(), Error>,
744 ) -> Result<(), Error> { 744 ) -> Result<(), Error> {
745 self.write_internal(address, bytes, false, &check_timeout)?; 745 self.write_internal(address, write, false, &check_timeout)?;
746 self.read_internal(address, buffer, true, &check_timeout) 746 self.read_internal(address, read, true, &check_timeout)
747 // Automatic Stop 747 // Automatic Stop
748 } 748 }
749 749
750 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 750 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
751 self.blocking_write_read_timeout(address, bytes, buffer, || Ok(())) 751 self.blocking_write_read_timeout(address, write, read, || Ok(()))
752 } 752 }
753 753
754 pub fn blocking_write_vectored_timeout( 754 pub fn blocking_write_vectored_timeout(
755 &mut self, 755 &mut self,
756 address: u8, 756 address: u8,
757 bytes: &[&[u8]], 757 write: &[&[u8]],
758 check_timeout: impl Fn() -> Result<(), Error>, 758 check_timeout: impl Fn() -> Result<(), Error>,
759 ) -> Result<(), Error> { 759 ) -> Result<(), Error> {
760 if bytes.is_empty() { 760 if write.is_empty() {
761 return Err(Error::ZeroLengthTransfer); 761 return Err(Error::ZeroLengthTransfer);
762 } 762 }
763 let first_length = bytes[0].len(); 763 let first_length = write[0].len();
764 let last_slice_index = bytes.len() - 1; 764 let last_slice_index = write.len() - 1;
765 765
766 // NOTE(unsafe) We have &mut self 766 // NOTE(unsafe) We have &mut self
767 unsafe { 767 unsafe {
@@ -774,7 +774,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
774 )?; 774 )?;
775 } 775 }
776 776
777 for (idx, slice) in bytes.iter().enumerate() { 777 for (idx, slice) in write.iter().enumerate() {
778 let slice_len = slice.len(); 778 let slice_len = slice.len();
779 let completed_chunks = slice_len / 255; 779 let completed_chunks = slice_len / 255;
780 let total_chunks = if completed_chunks * 255 == slice_len { 780 let total_chunks = if completed_chunks * 255 == slice_len {
@@ -828,8 +828,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
828 Ok(()) 828 Ok(())
829 } 829 }
830 830
831 pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { 831 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
832 self.blocking_write_vectored_timeout(address, bytes, || Ok(())) 832 self.blocking_write_vectored_timeout(address, write, || Ok(()))
833 } 833 }
834} 834}
835 835
@@ -847,16 +847,16 @@ mod eh02 {
847 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { 847 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
848 type Error = Error; 848 type Error = Error;
849 849
850 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { 850 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
851 self.blocking_write(address, bytes) 851 self.blocking_write(address, write)
852 } 852 }
853 } 853 }
854 854
855 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { 855 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
856 type Error = Error; 856 type Error = Error;
857 857
858 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { 858 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
859 self.blocking_write_read(address, bytes, buffer) 859 self.blocking_write_read(address, write, read)
860 } 860 }
861 } 861 }
862} 862}
@@ -1010,46 +1010,25 @@ mod eh1 {
1010 } 1010 }
1011 1011
1012 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { 1012 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
1013 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 1013 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
1014 self.blocking_read(address, buffer) 1014 self.blocking_read(address, read)
1015 }
1016
1017 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
1018 self.blocking_write(address, buffer)
1019 }
1020
1021 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
1022 where
1023 B: IntoIterator<Item = u8>,
1024 {
1025 todo!();
1026 } 1015 }
1027 1016
1028 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> 1017 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
1029 where 1018 self.blocking_write(address, write)
1030 B: IntoIterator<Item = u8>,
1031 {
1032 todo!();
1033 } 1019 }
1034 1020
1035 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { 1021 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
1036 self.blocking_write_read(address, wr_buffer, rd_buffer) 1022 self.blocking_write_read(address, write, read)
1037 } 1023 }
1038 1024
1039 fn transaction<'a>( 1025 fn transaction(
1040 &mut self, 1026 &mut self,
1041 _address: u8, 1027 _address: u8,
1042 _operations: &mut [embedded_hal_1::i2c::Operation<'a>], 1028 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
1043 ) -> Result<(), Self::Error> { 1029 ) -> Result<(), Self::Error> {
1044 todo!(); 1030 todo!();
1045 } 1031 }
1046
1047 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
1048 where
1049 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
1050 {
1051 todo!();
1052 }
1053 } 1032 }
1054} 1033}
1055 1034
@@ -1059,27 +1038,22 @@ mod eha {
1059 use super::*; 1038 use super::*;
1060 1039
1061 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { 1040 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
1062 async fn read<'a>(&'a mut self, address: u8, read: &'a mut [u8]) -> Result<(), Self::Error> { 1041 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
1063 self.read(address, read).await 1042 self.read(address, read).await
1064 } 1043 }
1065 1044
1066 async fn write<'a>(&'a mut self, address: u8, write: &'a [u8]) -> Result<(), Self::Error> { 1045 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
1067 self.write(address, write).await 1046 self.write(address, write).await
1068 } 1047 }
1069 1048
1070 async fn write_read<'a>( 1049 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
1071 &'a mut self,
1072 address: u8,
1073 write: &'a [u8],
1074 read: &'a mut [u8],
1075 ) -> Result<(), Self::Error> {
1076 self.write_read(address, write, read).await 1050 self.write_read(address, write, read).await
1077 } 1051 }
1078 1052
1079 async fn transaction<'a, 'b>( 1053 async fn transaction(
1080 &'a mut self, 1054 &mut self,
1081 address: u8, 1055 address: u8,
1082 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 1056 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
1083 ) -> Result<(), Self::Error> { 1057 ) -> Result<(), Self::Error> {
1084 let _ = address; 1058 let _ = address;
1085 let _ = operations; 1059 let _ = operations;
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 8dc4df2dc..d4d7155bd 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -43,9 +43,6 @@ pub mod i2c;
43 43
44#[cfg(crc)] 44#[cfg(crc)]
45pub mod crc; 45pub mod crc;
46#[cfg(any(
47 flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7
48))]
49pub mod flash; 46pub mod flash;
50pub mod pwm; 47pub mod pwm;
51#[cfg(quadspi)] 48#[cfg(quadspi)]
@@ -56,6 +53,8 @@ pub mod rng;
56pub mod sdmmc; 53pub mod sdmmc;
57#[cfg(spi)] 54#[cfg(spi)]
58pub mod spi; 55pub mod spi;
56#[cfg(stm32wl)]
57pub mod subghz;
59#[cfg(usart)] 58#[cfg(usart)]
60pub mod usart; 59pub mod usart;
61#[cfg(all(usb, feature = "time"))] 60#[cfg(all(usb, feature = "time"))]
@@ -65,9 +64,6 @@ pub mod usb_otg;
65#[cfg(iwdg)] 64#[cfg(iwdg)]
66pub mod wdg; 65pub mod wdg;
67 66
68#[cfg(feature = "subghz")]
69pub mod subghz;
70
71// This must go last, so that it sees all the impl_foo! macros defined earlier. 67// This must go last, so that it sees all the impl_foo! macros defined earlier.
72pub(crate) mod _generated { 68pub(crate) mod _generated {
73 #![allow(dead_code)] 69 #![allow(dead_code)]
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
new file mode 100644
index 000000000..13edfbaa3
--- /dev/null
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -0,0 +1,124 @@
1use core::marker::PhantomData;
2
3use embassy_hal_common::{into_ref, PeripheralRef};
4pub use stm32_metapac::timer::vals::Ckd;
5
6use super::simple_pwm::*;
7use super::*;
8#[allow(unused_imports)]
9use crate::gpio::sealed::{AFType, Pin};
10use crate::gpio::AnyPin;
11use crate::time::Hertz;
12use crate::Peripheral;
13
14pub struct ComplementaryPwmPin<'d, Perip, Channel> {
15 _pin: PeripheralRef<'d, AnyPin>,
16 phantom: PhantomData<(Perip, Channel)>,
17}
18
19macro_rules! complementary_channel_impl {
20 ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
23 into_ref!(pin);
24 critical_section::with(|_| unsafe {
25 pin.set_low();
26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
27 #[cfg(gpio_v2)]
28 pin.set_speed(crate::gpio::Speed::VeryHigh);
29 });
30 ComplementaryPwmPin {
31 _pin: pin.map_into(),
32 phantom: PhantomData,
33 }
34 }
35 }
36 };
37}
38
39complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin);
40complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin);
41complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin);
42complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin);
43
44pub struct ComplementaryPwm<'d, T> {
45 inner: PeripheralRef<'d, T>,
46}
47
48impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
49 pub fn new(
50 tim: impl Peripheral<P = T> + 'd,
51 _ch1: Option<PwmPin<'d, T, Ch1>>,
52 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
53 _ch2: Option<PwmPin<'d, T, Ch2>>,
54 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
55 _ch3: Option<PwmPin<'d, T, Ch3>>,
56 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
57 _ch4: Option<PwmPin<'d, T, Ch4>>,
58 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
59 freq: Hertz,
60 ) -> Self {
61 Self::new_inner(tim, freq)
62 }
63
64 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
65 into_ref!(tim);
66
67 T::enable();
68 <T as crate::rcc::sealed::RccPeripheral>::reset();
69
70 let mut this = Self { inner: tim };
71
72 this.inner.set_frequency(freq);
73 this.inner.start();
74
75 unsafe {
76 this.inner.enable_outputs(true);
77
78 this.inner
79 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
80 this.inner
81 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
82 this.inner
83 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
84 this.inner
85 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
86 }
87 this
88 }
89
90 pub fn enable(&mut self, channel: Channel) {
91 unsafe {
92 self.inner.enable_channel(channel, true);
93 self.inner.enable_complementary_channel(channel, true);
94 }
95 }
96
97 pub fn disable(&mut self, channel: Channel) {
98 unsafe {
99 self.inner.enable_complementary_channel(channel, false);
100 self.inner.enable_channel(channel, false);
101 }
102 }
103
104 pub fn set_freq(&mut self, freq: Hertz) {
105 self.inner.set_frequency(freq);
106 }
107
108 pub fn get_max_duty(&self) -> u16 {
109 unsafe { self.inner.get_max_compare_value() }
110 }
111
112 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
113 assert!(duty < self.get_max_duty());
114 unsafe { self.inner.set_compare_value(channel, duty) }
115 }
116
117 pub fn set_dead_time_clock_division(&mut self, value: Ckd) {
118 unsafe { self.inner.set_dead_time_clock_division(value) }
119 }
120
121 pub fn set_dead_time_value(&mut self, value: u8) {
122 unsafe { self.inner.set_dead_time_value(value) }
123 }
124}
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index d3713391c..0bef07089 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -1,5 +1,8 @@
1pub mod complementary_pwm;
1pub mod simple_pwm; 2pub mod simple_pwm;
2 3
4use stm32_metapac::timer::vals::Ckd;
5
3#[cfg(feature = "unstable-pac")] 6#[cfg(feature = "unstable-pac")]
4pub mod low_level { 7pub mod low_level {
5 pub use super::sealed::*; 8 pub use super::sealed::*;
@@ -67,6 +70,14 @@ pub(crate) mod sealed {
67 unsafe fn get_max_compare_value(&self) -> u16; 70 unsafe fn get_max_compare_value(&self) -> u16;
68 } 71 }
69 72
73 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
74 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd);
75
76 unsafe fn set_dead_time_value(&mut self, value: u8);
77
78 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
79 }
80
70 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { 81 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
71 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 82 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
72 83
@@ -82,6 +93,12 @@ pub trait CaptureCompare16bitInstance:
82 sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static 93 sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static
83{ 94{
84} 95}
96
97pub trait ComplementaryCaptureCompare16bitInstance:
98 sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static
99{
100}
101
85pub trait CaptureCompare32bitInstance: 102pub trait CaptureCompare32bitInstance:
86 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static 103 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static
87{ 104{
@@ -209,6 +226,29 @@ foreach_interrupt! {
209 impl CaptureCompare16bitInstance for crate::peripherals::$inst { 226 impl CaptureCompare16bitInstance for crate::peripherals::$inst {
210 227
211 } 228 }
229
230 impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
231 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) {
232 use crate::timer::sealed::AdvancedControlInstance;
233 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
234 }
235
236 unsafe fn set_dead_time_value(&mut self, value: u8) {
237 use crate::timer::sealed::AdvancedControlInstance;
238 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
239 }
240
241 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
242 use crate::timer::sealed::AdvancedControlInstance;
243 Self::regs_advanced()
244 .ccer()
245 .modify(|w| w.set_ccne(channel.raw(), enable));
246 }
247 }
248
249 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
250
251 }
212 }; 252 };
213} 253}
214 254
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
new file mode 100644
index 000000000..17fbc6056
--- /dev/null
+++ b/embassy-stm32/src/rcc/h5.rs
@@ -0,0 +1,606 @@
1use core::marker::PhantomData;
2
3use stm32_metapac::rcc::vals::{Hpre, Ppre, Timpre};
4
5use crate::pac::pwr::vals::Vos;
6use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
7use crate::pac::{FLASH, PWR, RCC};
8use crate::rcc::{set_freqs, Clocks};
9use crate::time::Hertz;
10use crate::{peripherals, Peripheral};
11
12/// HSI speed
13pub const HSI_FREQ: Hertz = Hertz(64_000_000);
14
15/// CSI speed
16pub const CSI_FREQ: Hertz = Hertz(4_000_000);
17
18/// HSI48 speed
19pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
20
21/// LSI speed
22pub const LSI_FREQ: Hertz = Hertz(32_000);
23
24const VCO_MIN: u32 = 150_000_000;
25const VCO_MAX: u32 = 420_000_000;
26const VCO_WIDE_MIN: u32 = 128_000_000;
27const VCO_WIDE_MAX: u32 = 560_000_000;
28
29/// Voltage Scale
30///
31/// Represents the voltage range feeding the CPU core. The maximum core
32/// clock frequency depends on this value.
33#[derive(Copy, Clone, PartialEq)]
34pub enum VoltageScale {
35 /// VOS 0 range VCORE 1.30V - 1.40V
36 Scale0,
37 /// VOS 1 range VCORE 1.15V - 1.26V
38 Scale1,
39 /// VOS 2 range VCORE 1.05V - 1.15V
40 Scale2,
41 /// VOS 3 range VCORE 0.95V - 1.05V
42 Scale3,
43}
44
45pub enum HseMode {
46 /// crystal/ceramic oscillator (HSEBYP=0)
47 Oscillator,
48 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
49 BypassAnalog,
50 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
51 BypassDigital,
52}
53
54pub struct Hse {
55 /// HSE frequency.
56 pub freq: Hertz,
57 /// HSE mode.
58 pub mode: HseMode,
59}
60
61pub enum Hsi {
62 /// 64Mhz
63 Mhz64,
64 /// 32Mhz (divided by 2)
65 Mhz32,
66 /// 16Mhz (divided by 4)
67 Mhz16,
68 /// 8Mhz (divided by 8)
69 Mhz8,
70}
71
72pub enum Sysclk {
73 /// HSI selected as sysclk
74 HSI,
75 /// HSE selected as sysclk
76 HSE,
77 /// CSI selected as sysclk
78 CSI,
79 /// PLL1_P selected as sysclk
80 Pll1P,
81}
82
83pub enum PllSource {
84 Hsi,
85 Csi,
86 Hse,
87}
88
89pub struct Pll {
90 /// Source clock selection.
91 pub source: PllSource,
92
93 /// PLL pre-divider (DIVM). Must be between 1 and 63.
94 pub prediv: u8,
95
96 /// PLL multiplication factor. Must be between 4 and 512.
97 pub mul: u16,
98
99 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
100 /// On PLL1, it must be even (in particular, it cannot be 1.)
101 pub divp: Option<u16>,
102 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
103 pub divq: Option<u16>,
104 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
105 pub divr: Option<u16>,
106}
107
108/// AHB prescaler
109#[derive(Clone, Copy, PartialEq)]
110pub enum AHBPrescaler {
111 NotDivided,
112 Div2,
113 Div4,
114 Div8,
115 Div16,
116 Div64,
117 Div128,
118 Div256,
119 Div512,
120}
121
122impl AHBPrescaler {
123 fn div(&self, clk: Hertz) -> Hertz {
124 match self {
125 Self::NotDivided => clk,
126 Self::Div2 => clk / 2u32,
127 Self::Div4 => clk / 4u32,
128 Self::Div8 => clk / 8u32,
129 Self::Div16 => clk / 16u32,
130 Self::Div64 => clk / 64u32,
131 Self::Div128 => clk / 128u32,
132 Self::Div256 => clk / 256u32,
133 Self::Div512 => clk / 512u32,
134 }
135 }
136}
137
138/// APB prescaler
139#[derive(Clone, Copy)]
140pub enum APBPrescaler {
141 NotDivided,
142 Div2,
143 Div4,
144 Div8,
145 Div16,
146}
147
148impl APBPrescaler {
149 fn div(&self, clk: Hertz) -> Hertz {
150 match self {
151 Self::NotDivided => clk,
152 Self::Div2 => clk / 2u32,
153 Self::Div4 => clk / 4u32,
154 Self::Div8 => clk / 8u32,
155 Self::Div16 => clk / 16u32,
156 }
157 }
158
159 fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz {
160 match (tim, self) {
161 // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
162 // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2
163 (TimerPrescaler::DefaultX2, Self::NotDivided) => clk,
164 (TimerPrescaler::DefaultX2, Self::Div2) => clk,
165 (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32,
166 (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32,
167 (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32,
168 // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2
169 // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2
170 // this makes NO SENSE and is different than in the H7. Mistake in the RM??
171 (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32,
172 (TimerPrescaler::DefaultX4, Self::Div2) => clk,
173 (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32,
174 (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32,
175 (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32,
176 }
177 }
178}
179
180/// APB prescaler
181#[derive(Clone, Copy)]
182pub enum TimerPrescaler {
183 DefaultX2,
184 DefaultX4,
185}
186
187impl From<TimerPrescaler> for Timpre {
188 fn from(value: TimerPrescaler) -> Self {
189 match value {
190 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
191 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
192 }
193 }
194}
195
196impl From<APBPrescaler> for Ppre {
197 fn from(val: APBPrescaler) -> Ppre {
198 match val {
199 APBPrescaler::NotDivided => Ppre::DIV1,
200 APBPrescaler::Div2 => Ppre::DIV2,
201 APBPrescaler::Div4 => Ppre::DIV4,
202 APBPrescaler::Div8 => Ppre::DIV8,
203 APBPrescaler::Div16 => Ppre::DIV16,
204 }
205 }
206}
207
208impl From<AHBPrescaler> for Hpre {
209 fn from(val: AHBPrescaler) -> Hpre {
210 match val {
211 AHBPrescaler::NotDivided => Hpre::DIV1,
212 AHBPrescaler::Div2 => Hpre::DIV2,
213 AHBPrescaler::Div4 => Hpre::DIV4,
214 AHBPrescaler::Div8 => Hpre::DIV8,
215 AHBPrescaler::Div16 => Hpre::DIV16,
216 AHBPrescaler::Div64 => Hpre::DIV64,
217 AHBPrescaler::Div128 => Hpre::DIV128,
218 AHBPrescaler::Div256 => Hpre::DIV256,
219 AHBPrescaler::Div512 => Hpre::DIV512,
220 }
221 }
222}
223
224/// Configuration of the core clocks
225#[non_exhaustive]
226pub struct Config {
227 pub hsi: Option<Hsi>,
228 pub hse: Option<Hse>,
229 pub csi: bool,
230 pub hsi48: bool,
231 pub sys: Sysclk,
232
233 pub pll1: Option<Pll>,
234 pub pll2: Option<Pll>,
235 #[cfg(rcc_h5)]
236 pub pll3: Option<Pll>,
237
238 pub ahb_pre: AHBPrescaler,
239 pub apb1_pre: APBPrescaler,
240 pub apb2_pre: APBPrescaler,
241 pub apb3_pre: APBPrescaler,
242 pub timer_prescaler: TimerPrescaler,
243
244 pub voltage_scale: VoltageScale,
245}
246
247impl Default for Config {
248 fn default() -> Self {
249 Self {
250 hsi: Some(Hsi::Mhz64),
251 hse: None,
252 csi: false,
253 hsi48: false,
254 sys: Sysclk::HSI,
255 pll1: None,
256 pll2: None,
257 #[cfg(rcc_h5)]
258 pll3: None,
259
260 ahb_pre: AHBPrescaler::NotDivided,
261 apb1_pre: APBPrescaler::NotDivided,
262 apb2_pre: APBPrescaler::NotDivided,
263 apb3_pre: APBPrescaler::NotDivided,
264 timer_prescaler: TimerPrescaler::DefaultX2,
265
266 voltage_scale: VoltageScale::Scale3,
267 }
268 }
269}
270
271pub(crate) mod sealed {
272 pub trait McoInstance {
273 type Source;
274 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
275 }
276}
277
278pub trait McoInstance: sealed::McoInstance + 'static {}
279
280pin_trait!(McoPin, McoInstance);
281
282macro_rules! impl_peri {
283 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
284 impl sealed::McoInstance for peripherals::$peri {
285 type Source = $source;
286
287 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
288 RCC.cfgr().modify(|w| {
289 w.$set_source(source);
290 w.$set_prescaler(prescaler);
291 });
292 }
293 }
294
295 impl McoInstance for peripherals::$peri {}
296 };
297}
298
299impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
300impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
301
302pub struct Mco<'d, T: McoInstance> {
303 phantom: PhantomData<&'d mut T>,
304}
305
306impl<'d, T: McoInstance> Mco<'d, T> {
307 pub fn new(
308 _peri: impl Peripheral<P = T> + 'd,
309 _pin: impl Peripheral<P = impl McoPin<T>> + 'd,
310 _source: T::Source,
311 ) -> Self {
312 todo!();
313 }
314}
315
316pub(crate) unsafe fn init(config: Config) {
317 let (vos, max_clk) = match config.voltage_scale {
318 VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)),
319 VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)),
320 VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)),
321 VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)),
322 };
323
324 // Configure voltage scale.
325 PWR.voscr().modify(|w| w.set_vos(vos));
326 while !PWR.vossr().read().vosrdy() {}
327
328 // Configure HSI
329 let hsi = match config.hsi {
330 None => {
331 RCC.cr().modify(|w| w.set_hsion(false));
332 None
333 }
334 Some(hsi) => {
335 let (freq, hsidiv) = match hsi {
336 Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
337 Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
338 Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
339 Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
340 };
341 RCC.cr().modify(|w| {
342 w.set_hsidiv(hsidiv);
343 w.set_hsion(true);
344 });
345 while !RCC.cr().read().hsirdy() {}
346 Some(freq)
347 }
348 };
349
350 // Configure HSE
351 let hse = match config.hse {
352 None => {
353 RCC.cr().modify(|w| w.set_hseon(false));
354 None
355 }
356 Some(hse) => {
357 let (byp, ext) = match hse.mode {
358 HseMode::Oscillator => (false, Hseext::ANALOG),
359 HseMode::BypassAnalog => (true, Hseext::ANALOG),
360 HseMode::BypassDigital => (true, Hseext::DIGITAL),
361 };
362
363 RCC.cr().modify(|w| {
364 w.set_hsebyp(byp);
365 w.set_hseext(ext);
366 });
367 RCC.cr().modify(|w| w.set_hseon(true));
368 while !RCC.cr().read().hserdy() {}
369 Some(hse.freq)
370 }
371 };
372
373 // Configure HSI48.
374 RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
375 let _hsi48 = match config.hsi48 {
376 false => None,
377 true => {
378 while !RCC.cr().read().hsi48rdy() {}
379 Some(CSI_FREQ)
380 }
381 };
382
383 // Configure CSI.
384 RCC.cr().modify(|w| w.set_csion(config.csi));
385 let csi = match config.csi {
386 false => None,
387 true => {
388 while !RCC.cr().read().csirdy() {}
389 Some(CSI_FREQ)
390 }
391 };
392
393 // Configure PLLs.
394 let pll_input = PllInput { csi, hse, hsi };
395 let pll1 = init_pll(0, config.pll1, &pll_input);
396 let _pll2 = init_pll(1, config.pll2, &pll_input);
397 #[cfg(rcc_h5)]
398 let _pll3 = init_pll(2, config.pll3, &pll_input);
399
400 // Configure sysclk
401 let (sys, sw) = match config.sys {
402 Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
403 Sysclk::HSE => (unwrap!(hse), Sw::HSE),
404 Sysclk::CSI => (unwrap!(csi), Sw::CSI),
405 Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
406 };
407 assert!(sys <= max_clk);
408
409 let hclk = config.ahb_pre.div(sys);
410
411 let apb1 = config.apb1_pre.div(hclk);
412 let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler);
413 let apb2 = config.apb2_pre.div(hclk);
414 let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler);
415 let apb3 = config.apb3_pre.div(hclk);
416
417 flash_setup(hclk, config.voltage_scale);
418
419 // Set hpre
420 let hpre = config.ahb_pre.into();
421 RCC.cfgr2().modify(|w| w.set_hpre(hpre));
422 while RCC.cfgr2().read().hpre() != hpre {}
423
424 // set ppre
425 RCC.cfgr2().modify(|w| {
426 w.set_ppre1(config.apb1_pre.into());
427 w.set_ppre2(config.apb2_pre.into());
428 w.set_ppre3(config.apb3_pre.into());
429 });
430
431 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
432
433 RCC.cfgr().modify(|w| w.set_sw(sw));
434 while RCC.cfgr().read().sws() != sw {}
435
436 set_freqs(Clocks {
437 sys,
438 ahb1: hclk,
439 ahb2: hclk,
440 ahb3: hclk,
441 ahb4: hclk,
442 apb1,
443 apb2,
444 apb3,
445 apb1_tim,
446 apb2_tim,
447 adc: None,
448 });
449}
450
451struct PllInput {
452 hsi: Option<Hertz>,
453 hse: Option<Hertz>,
454 csi: Option<Hertz>,
455}
456
457struct PllOutput {
458 p: Option<Hertz>,
459 #[allow(dead_code)]
460 q: Option<Hertz>,
461 #[allow(dead_code)]
462 r: Option<Hertz>,
463}
464
465unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
466 let Some(config) = config else {
467 // Stop PLL
468 RCC.cr().modify(|w| w.set_pllon(num, false));
469 while RCC.cr().read().pllrdy(num) {}
470
471 // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
472 RCC.pllcfgr(num).write(|w| {
473 w.set_divm(0);
474 });
475
476 return PllOutput{
477 p: None,
478 q: None,
479 r: None,
480 }
481 };
482
483 assert!(1 <= config.prediv && config.prediv <= 63);
484 assert!(4 <= config.mul && config.mul <= 512);
485
486 let (in_clk, src) = match config.source {
487 PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
488 PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
489 PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
490 };
491
492 let ref_clk = in_clk / config.prediv as u32;
493
494 let ref_range = match ref_clk.0 {
495 ..=1_999_999 => Pllrge::RANGE1,
496 ..=3_999_999 => Pllrge::RANGE2,
497 ..=7_999_999 => Pllrge::RANGE4,
498 ..=16_000_000 => Pllrge::RANGE8,
499 x => panic!("pll ref_clk out of range: {} mhz", x),
500 };
501
502 // The smaller range (150 to 420 MHz) must
503 // be chosen when the reference clock frequency is lower than 2 MHz.
504 let wide_allowed = ref_range != Pllrge::RANGE1;
505
506 let vco_clk = ref_clk * config.mul;
507 let vco_range = match vco_clk.0 {
508 VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO,
509 VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO,
510 x => panic!("pll vco_clk out of range: {} mhz", x),
511 };
512
513 let p = config.divp.map(|div| {
514 assert!(1 <= div && div <= 128);
515 if num == 0 {
516 // on PLL1, DIVP must be even.
517 assert!(div % 2 == 0);
518 }
519
520 vco_clk / div
521 });
522 let q = config.divq.map(|div| {
523 assert!(1 <= div && div <= 128);
524 vco_clk / div
525 });
526 let r = config.divr.map(|div| {
527 assert!(1 <= div && div <= 128);
528 vco_clk / div
529 });
530
531 RCC.pllcfgr(num).write(|w| {
532 w.set_pllsrc(src);
533 w.set_divm(config.prediv);
534 w.set_pllvcosel(vco_range);
535 w.set_pllrge(ref_range);
536 w.set_pllfracen(false);
537 w.set_pllpen(p.is_some());
538 w.set_pllqen(q.is_some());
539 w.set_pllren(r.is_some());
540 });
541 RCC.plldivr(num).write(|w| {
542 w.set_plln(config.mul - 1);
543 w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
544 w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
545 w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
546 });
547
548 RCC.cr().modify(|w| w.set_pllon(num, true));
549 while !RCC.cr().read().pllrdy(num) {}
550
551 PllOutput { p, q, r }
552}
553
554fn flash_setup(clk: Hertz, vos: VoltageScale) {
555 // RM0481 Rev 1, table 37
556 // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
557 // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
558 // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
559 // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
560 // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
561 // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
562 // 5 2 170 to 200 MHz 210 to 250 MHz
563
564 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
565 // states and programming delay
566 let (latency, wrhighfreq) = match (vos, clk.0) {
567 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
568 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
569 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
570 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
571 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
572 (VoltageScale::Scale0, ..=250_000_000) => (5, 2),
573
574 (VoltageScale::Scale1, ..=34_000_000) => (0, 0),
575 (VoltageScale::Scale1, ..=68_000_000) => (1, 0),
576 (VoltageScale::Scale1, ..=102_000_000) => (2, 1),
577 (VoltageScale::Scale1, ..=136_000_000) => (3, 1),
578 (VoltageScale::Scale1, ..=170_000_000) => (4, 2),
579 (VoltageScale::Scale1, ..=200_000_000) => (5, 2),
580
581 (VoltageScale::Scale2, ..=30_000_000) => (0, 0),
582 (VoltageScale::Scale2, ..=60_000_000) => (1, 0),
583 (VoltageScale::Scale2, ..=90_000_000) => (2, 1),
584 (VoltageScale::Scale2, ..=120_000_000) => (3, 1),
585 (VoltageScale::Scale2, ..=150_000_000) => (4, 2),
586
587 (VoltageScale::Scale3, ..=20_000_000) => (0, 0),
588 (VoltageScale::Scale3, ..=40_000_000) => (1, 0),
589 (VoltageScale::Scale3, ..=60_000_000) => (2, 1),
590 (VoltageScale::Scale3, ..=80_000_000) => (3, 1),
591 (VoltageScale::Scale3, ..=100_000_000) => (4, 2),
592
593 _ => unreachable!(),
594 };
595
596 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
597
598 // NOTE(unsafe) Atomic write
599 unsafe {
600 FLASH.acr().write(|w| {
601 w.set_wrhighfreq(wrhighfreq);
602 w.set_latency(latency);
603 });
604 while FLASH.acr().read().latency() != latency {}
605 }
606}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d4bd3d6b8..d6a31f17b 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -21,6 +21,7 @@ use crate::time::Hertz;
21#[cfg_attr(rcc_u5, path = "u5.rs")] 21#[cfg_attr(rcc_u5, path = "u5.rs")]
22#[cfg_attr(rcc_wb, path = "wb.rs")] 22#[cfg_attr(rcc_wb, path = "wb.rs")]
23#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] 23#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
24#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")]
24mod _version; 25mod _version;
25pub use _version::*; 26pub use _version::*;
26 27
@@ -36,7 +37,7 @@ pub struct Clocks {
36 pub apb2: Hertz, 37 pub apb2: Hertz,
37 #[cfg(not(any(rcc_c0, rcc_g0)))] 38 #[cfg(not(any(rcc_c0, rcc_g0)))]
38 pub apb2_tim: Hertz, 39 pub apb2_tim: Hertz,
39 #[cfg(any(rcc_wl5, rcc_wle, rcc_u5))] 40 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))]
40 pub apb3: Hertz, 41 pub apb3: Hertz,
41 #[cfg(any(rcc_h7, rcc_h7ab))] 42 #[cfg(any(rcc_h7, rcc_h7ab))]
42 pub apb4: Hertz, 43 pub apb4: Hertz,
@@ -44,14 +45,16 @@ pub struct Clocks {
44 // AHB 45 // AHB
45 pub ahb1: Hertz, 46 pub ahb1: Hertz,
46 #[cfg(any( 47 #[cfg(any(
47 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5, rcc_wle 48 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
49 rcc_wl5, rcc_wle
48 ))] 50 ))]
49 pub ahb2: Hertz, 51 pub ahb2: Hertz,
50 #[cfg(any( 52 #[cfg(any(
51 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5, rcc_wle 53 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5,
54 rcc_wle
52 ))] 55 ))]
53 pub ahb3: Hertz, 56 pub ahb3: Hertz,
54 #[cfg(any(rcc_h7, rcc_h7ab))] 57 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
55 pub ahb4: Hertz, 58 pub ahb4: Hertz,
56 59
57 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] 60 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@@ -60,7 +63,7 @@ pub struct Clocks {
60 #[cfg(stm32f1)] 63 #[cfg(stm32f1)]
61 pub adc: Hertz, 64 pub adc: Hertz,
62 65
63 #[cfg(any(rcc_h7, rcc_h7ab))] 66 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
64 pub adc: Option<Hertz>, 67 pub adc: Option<Hertz>,
65} 68}
66 69
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 1f1708873..481ea4abc 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -258,7 +258,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
258 w.set_spe(true); 258 w.set_spe(true);
259 }); 259 });
260 } 260 }
261 #[cfg(any(spi_v3, spi_v4))] 261 #[cfg(any(spi_v3, spi_v4, spi_v5))]
262 unsafe { 262 unsafe {
263 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); 263 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
264 T::REGS.cfg2().modify(|w| { 264 T::REGS.cfg2().modify(|w| {
@@ -317,7 +317,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
317 }); 317 });
318 } 318 }
319 319
320 #[cfg(any(spi_v3, spi_v4))] 320 #[cfg(any(spi_v3, spi_v4, spi_v5))]
321 unsafe { 321 unsafe {
322 T::REGS.cfg2().modify(|w| { 322 T::REGS.cfg2().modify(|w| {
323 w.set_cpha(cpha); 323 w.set_cpha(cpha);
@@ -330,7 +330,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
330 pub fn get_current_config(&self) -> Config { 330 pub fn get_current_config(&self) -> Config {
331 #[cfg(any(spi_v1, spi_f1, spi_v2))] 331 #[cfg(any(spi_v1, spi_f1, spi_v2))]
332 let cfg = unsafe { T::REGS.cr1().read() }; 332 let cfg = unsafe { T::REGS.cr1().read() };
333 #[cfg(any(spi_v3, spi_v4))] 333 #[cfg(any(spi_v3, spi_v4, spi_v5))]
334 let cfg = unsafe { T::REGS.cfg2().read() }; 334 let cfg = unsafe { T::REGS.cfg2().read() };
335 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { 335 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
336 Polarity::IdleLow 336 Polarity::IdleLow
@@ -383,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
383 w.set_spe(true); 383 w.set_spe(true);
384 }); 384 });
385 } 385 }
386 #[cfg(any(spi_v3, spi_v4))] 386 #[cfg(any(spi_v3, spi_v4, spi_v5))]
387 unsafe { 387 unsafe {
388 T::REGS.cr1().modify(|w| { 388 T::REGS.cr1().modify(|w| {
389 w.set_csusp(true); 389 w.set_csusp(true);
@@ -429,7 +429,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
429 T::REGS.cr1().modify(|w| { 429 T::REGS.cr1().modify(|w| {
430 w.set_spe(true); 430 w.set_spe(true);
431 }); 431 });
432 #[cfg(any(spi_v3, spi_v4))] 432 #[cfg(any(spi_v3, spi_v4, spi_v5))]
433 T::REGS.cr1().modify(|w| { 433 T::REGS.cr1().modify(|w| {
434 w.set_cstart(true); 434 w.set_cstart(true);
435 }); 435 });
@@ -459,7 +459,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
459 } 459 }
460 460
461 // SPIv3 clears rxfifo on SPE=0 461 // SPIv3 clears rxfifo on SPE=0
462 #[cfg(not(any(spi_v3, spi_v4)))] 462 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
463 flush_rx_fifo(T::REGS); 463 flush_rx_fifo(T::REGS);
464 464
465 set_rxdmaen(T::REGS, true); 465 set_rxdmaen(T::REGS, true);
@@ -481,7 +481,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
481 T::REGS.cr1().modify(|w| { 481 T::REGS.cr1().modify(|w| {
482 w.set_spe(true); 482 w.set_spe(true);
483 }); 483 });
484 #[cfg(any(spi_v3, spi_v4))] 484 #[cfg(any(spi_v3, spi_v4, spi_v5))]
485 T::REGS.cr1().modify(|w| { 485 T::REGS.cr1().modify(|w| {
486 w.set_cstart(true); 486 w.set_cstart(true);
487 }); 487 });
@@ -514,7 +514,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
514 } 514 }
515 515
516 // SPIv3 clears rxfifo on SPE=0 516 // SPIv3 clears rxfifo on SPE=0
517 #[cfg(not(any(spi_v3, spi_v4)))] 517 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
518 flush_rx_fifo(T::REGS); 518 flush_rx_fifo(T::REGS);
519 519
520 set_rxdmaen(T::REGS, true); 520 set_rxdmaen(T::REGS, true);
@@ -534,7 +534,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
534 T::REGS.cr1().modify(|w| { 534 T::REGS.cr1().modify(|w| {
535 w.set_spe(true); 535 w.set_spe(true);
536 }); 536 });
537 #[cfg(any(spi_v3, spi_v4))] 537 #[cfg(any(spi_v3, spi_v4, spi_v5))]
538 T::REGS.cr1().modify(|w| { 538 T::REGS.cr1().modify(|w| {
539 w.set_cstart(true); 539 w.set_cstart(true);
540 }); 540 });
@@ -619,9 +619,9 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
619 } 619 }
620} 620}
621 621
622#[cfg(not(any(spi_v3, spi_v4)))] 622#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
623use vals::Br; 623use vals::Br;
624#[cfg(any(spi_v3, spi_v4))] 624#[cfg(any(spi_v3, spi_v4, spi_v5))]
625use vals::Mbr as Br; 625use vals::Mbr as Br;
626 626
627fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { 627fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
@@ -647,17 +647,17 @@ trait RegsExt {
647 647
648impl RegsExt for Regs { 648impl RegsExt for Regs {
649 fn tx_ptr<W>(&self) -> *mut W { 649 fn tx_ptr<W>(&self) -> *mut W {
650 #[cfg(not(any(spi_v3, spi_v4)))] 650 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
651 let dr = self.dr(); 651 let dr = self.dr();
652 #[cfg(any(spi_v3, spi_v4))] 652 #[cfg(any(spi_v3, spi_v4, spi_v5))]
653 let dr = self.txdr(); 653 let dr = self.txdr();
654 dr.ptr() as *mut W 654 dr.ptr() as *mut W
655 } 655 }
656 656
657 fn rx_ptr<W>(&self) -> *mut W { 657 fn rx_ptr<W>(&self) -> *mut W {
658 #[cfg(not(any(spi_v3, spi_v4)))] 658 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
659 let dr = self.dr(); 659 let dr = self.dr();
660 #[cfg(any(spi_v3, spi_v4))] 660 #[cfg(any(spi_v3, spi_v4, spi_v5))]
661 let dr = self.rxdr(); 661 let dr = self.rxdr();
662 dr.ptr() as *mut W 662 dr.ptr() as *mut W
663 } 663 }
@@ -667,22 +667,22 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
667 if sr.ovr() { 667 if sr.ovr() {
668 return Err(Error::Overrun); 668 return Err(Error::Overrun);
669 } 669 }
670 #[cfg(not(any(spi_f1, spi_v3, spi_v4)))] 670 #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))]
671 if sr.fre() { 671 if sr.fre() {
672 return Err(Error::Framing); 672 return Err(Error::Framing);
673 } 673 }
674 #[cfg(any(spi_v3, spi_v4))] 674 #[cfg(any(spi_v3, spi_v4, spi_v5))]
675 if sr.tifre() { 675 if sr.tifre() {
676 return Err(Error::Framing); 676 return Err(Error::Framing);
677 } 677 }
678 if sr.modf() { 678 if sr.modf() {
679 return Err(Error::ModeFault); 679 return Err(Error::ModeFault);
680 } 680 }
681 #[cfg(not(any(spi_v3, spi_v4)))] 681 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
682 if sr.crcerr() { 682 if sr.crcerr() {
683 return Err(Error::Crc); 683 return Err(Error::Crc);
684 } 684 }
685 #[cfg(any(spi_v3, spi_v4))] 685 #[cfg(any(spi_v3, spi_v4, spi_v5))]
686 if sr.crce() { 686 if sr.crce() {
687 return Err(Error::Crc); 687 return Err(Error::Crc);
688 } 688 }
@@ -696,11 +696,11 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
696 696
697 check_error_flags(sr)?; 697 check_error_flags(sr)?;
698 698
699 #[cfg(not(any(spi_v3, spi_v4)))] 699 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
700 if sr.txe() { 700 if sr.txe() {
701 return Ok(()); 701 return Ok(());
702 } 702 }
703 #[cfg(any(spi_v3, spi_v4))] 703 #[cfg(any(spi_v3, spi_v4, spi_v5))]
704 if sr.txp() { 704 if sr.txp() {
705 return Ok(()); 705 return Ok(());
706 } 706 }
@@ -713,11 +713,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
713 713
714 check_error_flags(sr)?; 714 check_error_flags(sr)?;
715 715
716 #[cfg(not(any(spi_v3, spi_v4)))] 716 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
717 if sr.rxne() { 717 if sr.rxne() {
718 return Ok(()); 718 return Ok(());
719 } 719 }
720 #[cfg(any(spi_v3, spi_v4))] 720 #[cfg(any(spi_v3, spi_v4, spi_v5))]
721 if sr.rxp() { 721 if sr.rxp() {
722 return Ok(()); 722 return Ok(());
723 } 723 }
@@ -726,11 +726,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
726 726
727fn flush_rx_fifo(regs: Regs) { 727fn flush_rx_fifo(regs: Regs) {
728 unsafe { 728 unsafe {
729 #[cfg(not(any(spi_v3, spi_v4)))] 729 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
730 while regs.sr().read().rxne() { 730 while regs.sr().read().rxne() {
731 let _ = regs.dr().read(); 731 let _ = regs.dr().read();
732 } 732 }
733 #[cfg(any(spi_v3, spi_v4))] 733 #[cfg(any(spi_v3, spi_v4, spi_v5))]
734 while regs.sr().read().rxp() { 734 while regs.sr().read().rxp() {
735 let _ = regs.rxdr().read(); 735 let _ = regs.rxdr().read();
736 } 736 }
@@ -739,11 +739,11 @@ fn flush_rx_fifo(regs: Regs) {
739 739
740fn set_txdmaen(regs: Regs, val: bool) { 740fn set_txdmaen(regs: Regs, val: bool) {
741 unsafe { 741 unsafe {
742 #[cfg(not(any(spi_v3, spi_v4)))] 742 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
743 regs.cr2().modify(|reg| { 743 regs.cr2().modify(|reg| {
744 reg.set_txdmaen(val); 744 reg.set_txdmaen(val);
745 }); 745 });
746 #[cfg(any(spi_v3, spi_v4))] 746 #[cfg(any(spi_v3, spi_v4, spi_v5))]
747 regs.cfg1().modify(|reg| { 747 regs.cfg1().modify(|reg| {
748 reg.set_txdmaen(val); 748 reg.set_txdmaen(val);
749 }); 749 });
@@ -752,11 +752,11 @@ fn set_txdmaen(regs: Regs, val: bool) {
752 752
753fn set_rxdmaen(regs: Regs, val: bool) { 753fn set_rxdmaen(regs: Regs, val: bool) {
754 unsafe { 754 unsafe {
755 #[cfg(not(any(spi_v3, spi_v4)))] 755 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
756 regs.cr2().modify(|reg| { 756 regs.cr2().modify(|reg| {
757 reg.set_rxdmaen(val); 757 reg.set_rxdmaen(val);
758 }); 758 });
759 #[cfg(any(spi_v3, spi_v4))] 759 #[cfg(any(spi_v3, spi_v4, spi_v5))]
760 regs.cfg1().modify(|reg| { 760 regs.cfg1().modify(|reg| {
761 reg.set_rxdmaen(val); 761 reg.set_rxdmaen(val);
762 }); 762 });
@@ -768,9 +768,9 @@ fn finish_dma(regs: Regs) {
768 #[cfg(spi_v2)] 768 #[cfg(spi_v2)]
769 while regs.sr().read().ftlvl() > 0 {} 769 while regs.sr().read().ftlvl() > 0 {}
770 770
771 #[cfg(any(spi_v3, spi_v4))] 771 #[cfg(any(spi_v3, spi_v4, spi_v5))]
772 while !regs.sr().read().txc() {} 772 while !regs.sr().read().txc() {}
773 #[cfg(not(any(spi_v3, spi_v4)))] 773 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
774 while regs.sr().read().bsy() {} 774 while regs.sr().read().bsy() {}
775 775
776 // Disable the spi peripheral 776 // Disable the spi peripheral
@@ -780,12 +780,12 @@ fn finish_dma(regs: Regs) {
780 780
781 // The peripheral automatically disables the DMA stream on completion without error, 781 // The peripheral automatically disables the DMA stream on completion without error,
782 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. 782 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2.
783 #[cfg(not(any(spi_v3, spi_v4)))] 783 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
784 regs.cr2().modify(|reg| { 784 regs.cr2().modify(|reg| {
785 reg.set_txdmaen(false); 785 reg.set_txdmaen(false);
786 reg.set_rxdmaen(false); 786 reg.set_rxdmaen(false);
787 }); 787 });
788 #[cfg(any(spi_v3, spi_v4))] 788 #[cfg(any(spi_v3, spi_v4, spi_v5))]
789 regs.cfg1().modify(|reg| { 789 regs.cfg1().modify(|reg| {
790 reg.set_txdmaen(false); 790 reg.set_txdmaen(false);
791 reg.set_rxdmaen(false); 791 reg.set_rxdmaen(false);
@@ -799,7 +799,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
799 unsafe { 799 unsafe {
800 ptr::write_volatile(regs.tx_ptr(), tx_word); 800 ptr::write_volatile(regs.tx_ptr(), tx_word);
801 801
802 #[cfg(any(spi_v3, spi_v4))] 802 #[cfg(any(spi_v3, spi_v4, spi_v5))]
803 regs.cr1().modify(|reg| reg.set_cstart(true)); 803 regs.cr1().modify(|reg| reg.set_cstart(true));
804 } 804 }
805 805
@@ -970,7 +970,7 @@ pub(crate) mod sealed {
970 } 970 }
971 } 971 }
972 972
973 #[cfg(any(spi_v3, spi_v4))] 973 #[cfg(any(spi_v3, spi_v4, spi_v5))]
974 pub fn dsize(&self) -> u8 { 974 pub fn dsize(&self) -> u8 {
975 match self { 975 match self {
976 WordSize::EightBit => 0b0111, 976 WordSize::EightBit => 0b0111,
@@ -978,7 +978,7 @@ pub(crate) mod sealed {
978 } 978 }
979 } 979 }
980 980
981 #[cfg(any(spi_v3, spi_v4))] 981 #[cfg(any(spi_v3, spi_v4, spi_v5))]
982 pub fn _frxth(&self) -> vals::Fthlv { 982 pub fn _frxth(&self) -> vals::Fthlv {
983 match self { 983 match self {
984 WordSize::EightBit => vals::Fthlv::ONEFRAME, 984 WordSize::EightBit => vals::Fthlv::ONEFRAME,
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 975517a48..f08abe331 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -1,7 +1,9 @@
1//! Time units 1//! Time units
2 2
3use core::ops::{Div, Mul};
4
3/// Hertz 5/// Hertz
4#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq)] 6#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
7 9
@@ -33,3 +35,45 @@ pub fn khz(kilohertz: u32) -> Hertz {
33pub fn mhz(megahertz: u32) -> Hertz { 35pub fn mhz(megahertz: u32) -> Hertz {
34 Hertz::mhz(megahertz) 36 Hertz::mhz(megahertz)
35} 37}
38
39impl Mul<u32> for Hertz {
40 type Output = Hertz;
41 fn mul(self, rhs: u32) -> Self::Output {
42 Hertz(self.0 * rhs)
43 }
44}
45
46impl Div<u32> for Hertz {
47 type Output = Hertz;
48 fn div(self, rhs: u32) -> Self::Output {
49 Hertz(self.0 / rhs)
50 }
51}
52
53impl Mul<u16> for Hertz {
54 type Output = Hertz;
55 fn mul(self, rhs: u16) -> Self::Output {
56 self * (rhs as u32)
57 }
58}
59
60impl Div<u16> for Hertz {
61 type Output = Hertz;
62 fn div(self, rhs: u16) -> Self::Output {
63 self / (rhs as u32)
64 }
65}
66
67impl Mul<u8> for Hertz {
68 type Output = Hertz;
69 fn mul(self, rhs: u8) -> Self::Output {
70 self * (rhs as u32)
71 }
72}
73
74impl Div<u8> for Hertz {
75 type Output = Hertz;
76 fn div(self, rhs: u8) -> Self::Output {
77 self / (rhs as u32)
78 }
79}
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 0355c5f14..ad68eaba2 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,22 +12,29 @@ use embassy_usb_driver as driver;
12use embassy_usb_driver::{ 12use embassy_usb_driver::{
13 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 13 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
14}; 14};
15use pac::common::{Reg, RW};
16use pac::usb::vals::{EpType, Stat};
17 15
18use super::{DmPin, DpPin, Instance}; 16use super::{DmPin, DpPin, Instance};
19use crate::gpio::sealed::AFType; 17use crate::gpio::sealed::AFType;
20use crate::interrupt::InterruptExt; 18use crate::interrupt::InterruptExt;
21use crate::pac::usb::regs; 19use crate::pac::usb::regs;
20use crate::pac::usb::vals::{EpType, Stat};
21use crate::pac::USBRAM;
22use crate::rcc::sealed::RccPeripheral; 22use crate::rcc::sealed::RccPeripheral;
23use crate::{pac, Peripheral}; 23use crate::Peripheral;
24 24
25const EP_COUNT: usize = 8; 25const EP_COUNT: usize = 8;
26 26
27#[cfg(any(usb_v1_x1, usb_v1_x2))] 27#[cfg(any(usbram_16x1_512, usbram_16x2_512))]
28const EP_MEMORY_SIZE: usize = 512; 28const USBRAM_SIZE: usize = 512;
29#[cfg(not(any(usb_v1_x1, usb_v1_x2)))] 29#[cfg(usbram_16x2_1024)]
30const EP_MEMORY_SIZE: usize = 1024; 30const USBRAM_SIZE: usize = 1024;
31#[cfg(usbram_32_2048)]
32const USBRAM_SIZE: usize = 2048;
33
34#[cfg(not(usbram_32_2048))]
35const USBRAM_ALIGN: usize = 2;
36#[cfg(usbram_32_2048)]
37const USBRAM_ALIGN: usize = 4;
31 38
32const NEW_AW: AtomicWaker = AtomicWaker::new(); 39const NEW_AW: AtomicWaker = AtomicWaker::new();
33static BUS_WAKER: AtomicWaker = NEW_AW; 40static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -57,25 +64,60 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
57 r 64 r
58} 65}
59 66
67fn align_len_up(len: u16) -> u16 {
68 ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16
69}
70
60// Returns (actual_len, len_bits) 71// Returns (actual_len, len_bits)
61fn calc_out_len(len: u16) -> (u16, u16) { 72fn calc_out_len(len: u16) -> (u16, u16) {
62 match len { 73 match len {
63 2..=62 => ((len + 1) / 2 * 2, ((len + 1) / 2) << 10), 74 // NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity.
64 63..=480 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), 75 2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10),
76 61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000),
65 _ => panic!("invalid OUT length {}", len), 77 _ => panic!("invalid OUT length {}", len),
66 } 78 }
67} 79}
68fn ep_in_addr<T: Instance>(index: usize) -> Reg<u16, RW> { 80
69 T::regs().ep_mem(index * 4 + 0) 81#[cfg(not(usbram_32_2048))]
70} 82mod btable {
71fn ep_in_len<T: Instance>(index: usize) -> Reg<u16, RW> { 83 use super::*;
72 T::regs().ep_mem(index * 4 + 1) 84
73} 85 pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) {
74fn ep_out_addr<T: Instance>(index: usize) -> Reg<u16, RW> { 86 USBRAM.mem(index * 4 + 0).write_value(addr);
75 T::regs().ep_mem(index * 4 + 2) 87 }
88
89 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
90 USBRAM.mem(index * 4 + 1).write_value(len);
91 }
92
93 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
94 USBRAM.mem(index * 4 + 2).write_value(addr);
95 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
96 }
97
98 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
99 USBRAM.mem(index * 4 + 3).read()
100 }
76} 101}
77fn ep_out_len<T: Instance>(index: usize) -> Reg<u16, RW> { 102#[cfg(usbram_32_2048)]
78 T::regs().ep_mem(index * 4 + 3) 103mod btable {
104 use super::*;
105
106 pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {}
107
108 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
109 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
110 }
111
112 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
113 USBRAM
114 .mem(index * 2 + 1)
115 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
116 }
117
118 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
119 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
120 }
79} 121}
80 122
81struct EndpointBuffer<T: Instance> { 123struct EndpointBuffer<T: Instance> {
@@ -87,23 +129,25 @@ struct EndpointBuffer<T: Instance> {
87impl<T: Instance> EndpointBuffer<T> { 129impl<T: Instance> EndpointBuffer<T> {
88 fn read(&mut self, buf: &mut [u8]) { 130 fn read(&mut self, buf: &mut [u8]) {
89 assert!(buf.len() <= self.len as usize); 131 assert!(buf.len() <= self.len as usize);
90 for i in 0..((buf.len() + 1) / 2) { 132 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
91 let val = unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).read() }; 133 let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() };
92 buf[i * 2] = val as u8; 134 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
93 if i * 2 + 1 < buf.len() { 135 buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
94 buf[i * 2 + 1] = (val >> 8) as u8;
95 }
96 } 136 }
97 } 137 }
98 138
99 fn write(&mut self, buf: &[u8]) { 139 fn write(&mut self, buf: &[u8]) {
100 assert!(buf.len() <= self.len as usize); 140 assert!(buf.len() <= self.len as usize);
101 for i in 0..((buf.len() + 1) / 2) { 141 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
102 let mut val = buf[i * 2] as u16; 142 let mut val = [0u8; USBRAM_ALIGN];
103 if i * 2 + 1 < buf.len() { 143 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
104 val |= (buf[i * 2 + 1] as u16) << 8; 144 val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]);
105 } 145
106 unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).write_value(val) }; 146 #[cfg(not(usbram_32_2048))]
147 let val = u16::from_le_bytes(val);
148 #[cfg(usbram_32_2048)]
149 let val = u32::from_le_bytes(val);
150 unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) };
107 } 151 }
108 } 152 }
109} 153}
@@ -139,8 +183,12 @@ impl<'d, T: Instance> Driver<'d, T> {
139 #[cfg(stm32l5)] 183 #[cfg(stm32l5)]
140 unsafe { 184 unsafe {
141 crate::peripherals::PWR::enable(); 185 crate::peripherals::PWR::enable();
186 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
187 }
142 188
143 pac::PWR.cr2().modify(|w| w.set_usv(true)); 189 #[cfg(pwr_h5)]
190 unsafe {
191 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))
144 } 192 }
145 193
146 unsafe { 194 unsafe {
@@ -256,8 +304,9 @@ impl<'d, T: Instance> Driver<'d, T> {
256 } 304 }
257 305
258 fn alloc_ep_mem(&mut self, len: u16) -> u16 { 306 fn alloc_ep_mem(&mut self, len: u16) -> u16 {
307 assert!(len as usize % USBRAM_ALIGN == 0);
259 let addr = self.ep_mem_free; 308 let addr = self.ep_mem_free;
260 if addr + len > EP_MEMORY_SIZE as _ { 309 if addr + len > USBRAM_SIZE as _ {
261 panic!("Endpoint memory full"); 310 panic!("Endpoint memory full");
262 } 311 }
263 self.ep_mem_free += len; 312 self.ep_mem_free += len;
@@ -306,10 +355,7 @@ impl<'d, T: Instance> Driver<'d, T> {
306 let addr = self.alloc_ep_mem(len); 355 let addr = self.alloc_ep_mem(len);
307 356
308 trace!(" len_bits = {:04x}", len_bits); 357 trace!(" len_bits = {:04x}", len_bits);
309 unsafe { 358 unsafe { btable::write_out::<T>(index, addr, len_bits) }
310 ep_out_addr::<T>(index).write_value(addr);
311 ep_out_len::<T>(index).write_value(len_bits);
312 }
313 359
314 EndpointBuffer { 360 EndpointBuffer {
315 addr, 361 addr,
@@ -321,13 +367,11 @@ impl<'d, T: Instance> Driver<'d, T> {
321 assert!(!ep.used_in); 367 assert!(!ep.used_in);
322 ep.used_in = true; 368 ep.used_in = true;
323 369
324 let len = (max_packet_size + 1) / 2 * 2; 370 let len = align_len_up(max_packet_size);
325 let addr = self.alloc_ep_mem(len); 371 let addr = self.alloc_ep_mem(len);
326 372
327 unsafe { 373 // ep_in_len is written when actually TXing packets.
328 ep_in_addr::<T>(index).write_value(addr); 374 unsafe { btable::write_in::<T>(index, addr) }
329 // ep_in_len is written when actually TXing packets.
330 }
331 375
332 EndpointBuffer { 376 EndpointBuffer {
333 addr, 377 addr,
@@ -398,7 +442,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
398 w.set_ctrm(true); 442 w.set_ctrm(true);
399 }); 443 });
400 444
401 #[cfg(usb_v3)] 445 #[cfg(any(usb_v3, usb_v4))]
402 regs.bcdr().write(|w| w.set_dppu(true)) 446 regs.bcdr().write(|w| w.set_dppu(true))
403 } 447 }
404 448
@@ -633,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
633 fn write_data(&mut self, buf: &[u8]) { 677 fn write_data(&mut self, buf: &[u8]) {
634 let index = self.info.addr.index(); 678 let index = self.info.addr.index();
635 self.buf.write(buf); 679 self.buf.write(buf);
636 unsafe { ep_in_len::<T>(index).write_value(buf.len() as _) }; 680 unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) }
637 } 681 }
638 682
639 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 683 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
640 let index = self.info.addr.index(); 684 let index = self.info.addr.index();
641 let rx_len = unsafe { ep_out_len::<T>(index).read() as usize } & 0x3FF; 685 let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF;
642 trace!("READ DONE, rx_len = {}", rx_len); 686 trace!("READ DONE, rx_len = {}", rx_len);
643 if rx_len > buf.len() { 687 if rx_len > buf.len() {
644 return Err(EndpointError::BufferOverflow); 688 return Err(EndpointError::BufferOverflow);
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
index 84fef78cb..193e0df0d 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -89,6 +89,9 @@ foreach_interrupt!(
89 } else if #[cfg(stm32h7)] { 89 } else if #[cfg(stm32h7)] {
90 const FIFO_DEPTH_WORDS: u16 = 1024; 90 const FIFO_DEPTH_WORDS: u16 = 1024;
91 const ENDPOINT_COUNT: usize = 9; 91 const ENDPOINT_COUNT: usize = 9;
92 } else if #[cfg(stm32u5)] {
93 const FIFO_DEPTH_WORDS: u16 = 320;
94 const ENDPOINT_COUNT: usize = 6;
92 } else { 95 } else {
93 compile_error!("USB_OTG_FS peripheral is not supported by this chip."); 96 compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
94 } 97 }
@@ -137,6 +140,9 @@ foreach_interrupt!(
137 ))] { 140 ))] {
138 const FIFO_DEPTH_WORDS: u16 = 1024; 141 const FIFO_DEPTH_WORDS: u16 = 1024;
139 const ENDPOINT_COUNT: usize = 9; 142 const ENDPOINT_COUNT: usize = 9;
143 } else if #[cfg(stm32u5)] {
144 const FIFO_DEPTH_WORDS: u16 = 1024;
145 const ENDPOINT_COUNT: usize = 9;
140 } else { 146 } else {
141 compile_error!("USB_OTG_HS peripheral is not supported by this chip."); 147 compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
142 } 148 }
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 5b14814a1..38d31f1c4 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true }
152log = { version = "0.4.14", optional = true } 152log = { version = "0.4.14", optional = true }
153 153
154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } 154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
156embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} 156embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
157 157
158futures-util = { version = "0.3.17", default-features = false } 158futures-util = { version = "0.3.17", default-features = false }
159embassy-sync = { version = "0.1", path = "../embassy-sync" } 159embassy-sync = { version = "0.1", path = "../embassy-sync" }
diff --git a/embassy-time/src/delay.rs b/embassy-time/src/delay.rs
index 0ca176abd..cf1918724 100644
--- a/embassy-time/src/delay.rs
+++ b/embassy-time/src/delay.rs
@@ -19,14 +19,12 @@ mod eh1 {
19 use super::*; 19 use super::*;
20 20
21 impl embedded_hal_1::delay::DelayUs for Delay { 21 impl embedded_hal_1::delay::DelayUs for Delay {
22 type Error = core::convert::Infallible; 22 fn delay_us(&mut self, us: u32) {
23 23 block_for(Duration::from_micros(us as u64))
24 fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
25 Ok(block_for(Duration::from_micros(us as u64)))
26 } 24 }
27 25
28 fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { 26 fn delay_ms(&mut self, ms: u32) {
29 Ok(block_for(Duration::from_millis(ms as u64))) 27 block_for(Duration::from_millis(ms as u64))
30 } 28 }
31 } 29 }
32} 30}
@@ -37,14 +35,12 @@ mod eha {
37 use crate::Timer; 35 use crate::Timer;
38 36
39 impl embedded_hal_async::delay::DelayUs for Delay { 37 impl embedded_hal_async::delay::DelayUs for Delay {
40 type Error = core::convert::Infallible; 38 async fn delay_us(&mut self, micros: u32) {
41 39 Timer::after(Duration::from_micros(micros as _)).await
42 async fn delay_us(&mut self, micros: u32) -> Result<(), Self::Error> {
43 Ok(Timer::after(Duration::from_micros(micros as _)).await)
44 } 40 }
45 41
46 async fn delay_ms(&mut self, millis: u32) -> Result<(), Self::Error> { 42 async fn delay_ms(&mut self, millis: u32) {
47 Ok(Timer::after(Duration::from_millis(millis as _)).await) 43 Timer::after(Duration::from_millis(millis as _)).await
48 } 44 }
49 } 45 }
50} 46}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index b8027d19a..49c21920b 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -5,7 +5,7 @@ use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 5#[cfg(feature = "defmt")]
6use defmt_rtt as _; 6use defmt_rtt as _;
7use embassy_boot_stm32::*; 7use embassy_boot_stm32::*;
8use embassy_stm32::flash::{Flash, ERASE_SIZE}; 8use embassy_stm32::flash::Flash;
9 9
10#[entry] 10#[entry]
11fn main() -> ! { 11fn main() -> ! {
@@ -19,9 +19,10 @@ fn main() -> ! {
19 } 19 }
20 */ 20 */
21 21
22 let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default(); 22 let mut bl: BootLoader<2048> = BootLoader::default();
23 let flash = Flash::new(p.FLASH); 23 let flash = Flash::new(p.FLASH);
24 let mut flash = BootFlash::new(flash); 24 let layout = flash.into_regions();
25 let mut flash = BootFlash::new(layout.bank1_region);
25 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); 26 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
26 core::mem::drop(flash); 27 core::mem::drop(flash);
27 unsafe { bl.load(start) } 28 unsafe { bl.load(start) }
diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml
index d1c8c1c5a..2ee6fcb00 100644
--- a/examples/rp/.cargo/config.toml
+++ b/examples/rp/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip RP2040" 2runner = "probe-rs-cli run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index aea61eec5..63d0ac82a 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -6,6 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7 7
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
@@ -30,8 +31,8 @@ display-interface = "0.4.1"
30byte-slice-cast = { version = "1.2.0", default-features = false } 31byte-slice-cast = { version = "1.2.0", default-features = false }
31smart-leds = "0.3.0" 32smart-leds = "0.3.0"
32 33
33embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 34embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
34embedded-hal-async = "0.2.0-alpha.0" 35embedded-hal-async = "0.2.0-alpha.1"
35embedded-io = { version = "0.4.0", features = ["async", "defmt"] } 36embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
36embedded-storage = { version = "0.3" } 37embedded-storage = { version = "0.3" }
37static_cell = "1.0.0" 38static_cell = "1.0.0"
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index 778cad3fa..85a19ce07 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -5,10 +5,13 @@
5use core::cell::RefCell; 5use core::cell::RefCell;
6 6
7use defmt::*; 7use defmt::*;
8use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
10use embassy_rp::spi; 11use embassy_rp::spi;
11use embassy_rp::spi::{Blocking, Spi}; 12use embassy_rp::spi::{Blocking, Spi};
13use embassy_sync::blocking_mutex::raw::NoopRawMutex;
14use embassy_sync::blocking_mutex::Mutex;
12use embassy_time::Delay; 15use embassy_time::Delay;
13use embedded_graphics::image::{Image, ImageRawLE}; 16use embedded_graphics::image::{Image, ImageRawLE};
14use embedded_graphics::mono_font::ascii::FONT_10X20; 17use embedded_graphics::mono_font::ascii::FONT_10X20;
@@ -21,10 +24,9 @@ use st7789::{Orientation, ST7789};
21use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
22 25
23use crate::my_display_interface::SPIDeviceInterface; 26use crate::my_display_interface::SPIDeviceInterface;
24use crate::shared_spi::SpiDeviceWithCs;
25use crate::touch::Touch; 27use crate::touch::Touch;
26 28
27//const DISPLAY_FREQ: u32 = 64_000_000; 29const DISPLAY_FREQ: u32 = 64_000_000;
28const TOUCH_FREQ: u32 = 200_000; 30const TOUCH_FREQ: u32 = 200_000;
29 31
30#[embassy_executor::main] 32#[embassy_executor::main]
@@ -43,16 +45,20 @@ async fn main(_spawner: Spawner) {
43 //let touch_irq = p.PIN_17; 45 //let touch_irq = p.PIN_17;
44 46
45 // create SPI 47 // create SPI
46 let mut config = spi::Config::default(); 48 let mut display_config = spi::Config::default();
47 config.frequency = TOUCH_FREQ; // use the lowest freq 49 display_config.frequency = DISPLAY_FREQ;
48 config.phase = spi::Phase::CaptureOnSecondTransition; 50 display_config.phase = spi::Phase::CaptureOnSecondTransition;
49 config.polarity = spi::Polarity::IdleHigh; 51 display_config.polarity = spi::Polarity::IdleHigh;
52 let mut touch_config = spi::Config::default();
53 touch_config.frequency = TOUCH_FREQ;
54 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
55 touch_config.polarity = spi::Polarity::IdleHigh;
50 56
51 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); 57 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
52 let spi_bus = RefCell::new(spi); 58 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
53 59
54 let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); 60 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
55 let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); 61 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
56 62
57 let mut touch = Touch::new(touch_spi); 63 let mut touch = Touch::new(touch_spi);
58 64
@@ -104,85 +110,9 @@ async fn main(_spawner: Spawner) {
104 } 110 }
105} 111}
106 112
107mod shared_spi {
108 use core::cell::RefCell;
109 use core::fmt::Debug;
110
111 use embedded_hal_1::digital::OutputPin;
112 use embedded_hal_1::spi;
113 use embedded_hal_1::spi::SpiDevice;
114
115 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
116 pub enum SpiDeviceWithCsError<BUS, CS> {
117 #[allow(unused)] // will probably use in the future when adding a flush() to SpiBus
118 Spi(BUS),
119 Cs(CS),
120 }
121
122 impl<BUS, CS> spi::Error for SpiDeviceWithCsError<BUS, CS>
123 where
124 BUS: spi::Error + Debug,
125 CS: Debug,
126 {
127 fn kind(&self) -> spi::ErrorKind {
128 match self {
129 Self::Spi(e) => e.kind(),
130 Self::Cs(_) => spi::ErrorKind::Other,
131 }
132 }
133 }
134
135 pub struct SpiDeviceWithCs<'a, BUS, CS> {
136 bus: &'a RefCell<BUS>,
137 cs: CS,
138 }
139
140 impl<'a, BUS, CS> SpiDeviceWithCs<'a, BUS, CS> {
141 pub fn new(bus: &'a RefCell<BUS>, cs: CS) -> Self {
142 Self { bus, cs }
143 }
144 }
145
146 impl<'a, BUS, CS> spi::ErrorType for SpiDeviceWithCs<'a, BUS, CS>
147 where
148 BUS: spi::ErrorType,
149 CS: OutputPin,
150 {
151 type Error = SpiDeviceWithCsError<BUS::Error, CS::Error>;
152 }
153
154 impl<'a, BUS, CS> SpiDevice for SpiDeviceWithCs<'a, BUS, CS>
155 where
156 BUS: spi::SpiBusFlush,
157 CS: OutputPin,
158 {
159 type Bus = BUS;
160
161 fn transaction<R>(
162 &mut self,
163 f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>,
164 ) -> Result<R, Self::Error> {
165 let mut bus = self.bus.borrow_mut();
166 self.cs.set_low().map_err(SpiDeviceWithCsError::Cs)?;
167
168 let f_res = f(&mut bus);
169
170 // On failure, it's important to still flush and deassert CS.
171 let flush_res = bus.flush();
172 let cs_res = self.cs.set_high();
173
174 let f_res = f_res.map_err(SpiDeviceWithCsError::Spi)?;
175 flush_res.map_err(SpiDeviceWithCsError::Spi)?;
176 cs_res.map_err(SpiDeviceWithCsError::Cs)?;
177
178 Ok(f_res)
179 }
180 }
181}
182
183/// Driver for the XPT2046 resistive touchscreen sensor 113/// Driver for the XPT2046 resistive touchscreen sensor
184mod touch { 114mod touch {
185 use embedded_hal_1::spi::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; 115 use embedded_hal_1::spi::{Operation, SpiDevice};
186 116
187 struct Calibration { 117 struct Calibration {
188 x1: i32, 118 x1: i32,
@@ -209,7 +139,6 @@ mod touch {
209 impl<SPI> Touch<SPI> 139 impl<SPI> Touch<SPI>
210 where 140 where
211 SPI: SpiDevice, 141 SPI: SpiDevice,
212 SPI::Bus: SpiBus,
213 { 142 {
214 pub fn new(spi: SPI) -> Self { 143 pub fn new(spi: SPI) -> Self {
215 Self { spi } 144 Self { spi }
@@ -219,13 +148,12 @@ mod touch {
219 let mut x = [0; 2]; 148 let mut x = [0; 2];
220 let mut y = [0; 2]; 149 let mut y = [0; 2];
221 self.spi 150 self.spi
222 .transaction(|bus| { 151 .transaction(&mut [
223 bus.write(&[0x90])?; 152 Operation::Write(&[0x90]),
224 bus.read(&mut x)?; 153 Operation::Read(&mut x),
225 bus.write(&[0xd0])?; 154 Operation::Write(&[0xd0]),
226 bus.read(&mut y)?; 155 Operation::Read(&mut y),
227 Ok(()) 156 ])
228 })
229 .unwrap(); 157 .unwrap();
230 158
231 let x = (u16::from_be_bytes(x) >> 3) as i32; 159 let x = (u16::from_be_bytes(x) >> 3) as i32;
@@ -247,7 +175,7 @@ mod touch {
247mod my_display_interface { 175mod my_display_interface {
248 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; 176 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
249 use embedded_hal_1::digital::OutputPin; 177 use embedded_hal_1::digital::OutputPin;
250 use embedded_hal_1::spi::{SpiBusWrite, SpiDevice}; 178 use embedded_hal_1::spi::SpiDeviceWrite;
251 179
252 /// SPI display interface. 180 /// SPI display interface.
253 /// 181 ///
@@ -259,8 +187,7 @@ mod my_display_interface {
259 187
260 impl<SPI, DC> SPIDeviceInterface<SPI, DC> 188 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
261 where 189 where
262 SPI: SpiDevice, 190 SPI: SpiDeviceWrite,
263 SPI::Bus: SpiBusWrite,
264 DC: OutputPin, 191 DC: OutputPin,
265 { 192 {
266 /// Create new SPI interface for communciation with a display driver 193 /// Create new SPI interface for communciation with a display driver
@@ -271,42 +198,27 @@ mod my_display_interface {
271 198
272 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> 199 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
273 where 200 where
274 SPI: SpiDevice, 201 SPI: SpiDeviceWrite,
275 SPI::Bus: SpiBusWrite,
276 DC: OutputPin, 202 DC: OutputPin,
277 { 203 {
278 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { 204 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
279 let r = self.spi.transaction(|bus| { 205 // 1 = data, 0 = command
280 // 1 = data, 0 = command 206 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
281 if let Err(_) = self.dc.set_low() {
282 return Ok(Err(DisplayError::DCError));
283 }
284
285 // Send words over SPI
286 send_u8(bus, cmds)?;
287 207
288 Ok(Ok(())) 208 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
289 }); 209 Ok(())
290 r.map_err(|_| DisplayError::BusWriteError)?
291 } 210 }
292 211
293 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { 212 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
294 let r = self.spi.transaction(|bus| { 213 // 1 = data, 0 = command
295 // 1 = data, 0 = command 214 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
296 if let Err(_) = self.dc.set_high() {
297 return Ok(Err(DisplayError::DCError));
298 }
299
300 // Send words over SPI
301 send_u8(bus, buf)?;
302 215
303 Ok(Ok(())) 216 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
304 }); 217 Ok(())
305 r.map_err(|_| DisplayError::BusWriteError)?
306 } 218 }
307 } 219 }
308 220
309 fn send_u8<T: SpiBusWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { 221 fn send_u8<T: SpiDeviceWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
310 match words { 222 match words {
311 DataFormat::U8(slice) => spi.write(slice), 223 DataFormat::U8(slice) => spi.write(slice),
312 DataFormat::U16(slice) => { 224 DataFormat::U16(slice) => {
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
new file mode 100644
index 000000000..8ed9f98f8
--- /dev/null
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_time::{Delay, Duration, 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 adc = Adc::new(p.ADC, &mut Delay);
17 adc.set_sample_time(SampleTime::Cycles71_5);
18 let mut pin = p.PA1;
19
20 let mut vrefint = adc.enable_vref(&mut Delay);
21 let vrefint_sample = adc.read_internal(&mut vrefint);
22 let convert_to_millivolts = |sample| {
23 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
24 // 6.3.4 Embedded reference voltage
25 const VREFINT_MV: u32 = 1230; // mV
26
27 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
28 };
29
30 loop {
31 let v = adc.read(&mut pin);
32 info!("--> {} - {} mV", v, convert_to_millivolts(v));
33 Timer::after(Duration::from_millis(100)).await;
34 }
35}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 387af783a..99f37cdda 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index baa7484d0..e40ad4fc0 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index 7ea068a42..bd3a7c95e 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -13,6 +12,8 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
14 info!("Hello Flash!"); 13 info!("Hello Flash!");
15 14
15 // Once can also call `into_regions()` to get access to NorFlash implementations
16 // for each of the unique characteristics.
16 let mut f = Flash::new(p.FLASH); 17 let mut f = Flash::new(p.FLASH);
17 18
18 // Sector 5 19 // Sector 5
@@ -30,19 +31,19 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
30 31
31 info!("Reading..."); 32 info!("Reading...");
32 let mut buf = [0u8; 32]; 33 let mut buf = [0u8; 32];
33 unwrap!(f.read(offset, &mut buf)); 34 unwrap!(f.blocking_read(offset, &mut buf));
34 info!("Read: {=[u8]:x}", buf); 35 info!("Read: {=[u8]:x}", buf);
35 36
36 info!("Erasing..."); 37 info!("Erasing...");
37 unwrap!(f.erase(offset, offset + size)); 38 unwrap!(f.blocking_erase(offset, offset + size));
38 39
39 info!("Reading..."); 40 info!("Reading...");
40 let mut buf = [0u8; 32]; 41 let mut buf = [0u8; 32];
41 unwrap!(f.read(offset, &mut buf)); 42 unwrap!(f.blocking_read(offset, &mut buf));
42 info!("Read after erase: {=[u8]:x}", buf); 43 info!("Read after erase: {=[u8]:x}", buf);
43 44
44 info!("Writing..."); 45 info!("Writing...");
45 unwrap!(f.write( 46 unwrap!(f.blocking_write(
46 offset, 47 offset,
47 &[ 48 &[
48 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, 49 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,
@@ -52,7 +53,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
52 53
53 info!("Reading..."); 54 info!("Reading...");
54 let mut buf = [0u8; 32]; 55 let mut buf = [0u8; 32];
55 unwrap!(f.read(offset, &mut buf)); 56 unwrap!(f.blocking_read(offset, &mut buf));
56 info!("Read: {=[u8]:x}", buf); 57 info!("Read: {=[u8]:x}", buf);
57 assert_eq!( 58 assert_eq!(
58 &buf[..], 59 &buf[..],
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
new file mode 100644
index 000000000..6e17f3fd3
--- /dev/null
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -0,0 +1,77 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin};
8use embassy_stm32::pwm::simple_pwm::PwmPin;
9use embassy_stm32::pwm::Channel;
10use embassy_stm32::time::khz;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!");
18
19 let ch1 = PwmPin::new_ch1(p.PE9);
20 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7);
21 let mut pwm = ComplementaryPwm::new(
22 p.TIM1,
23 Some(ch1),
24 Some(ch1n),
25 None,
26 None,
27 None,
28 None,
29 None,
30 None,
31 khz(10),
32 );
33
34 /*
35 Dead-time = T_clk * T_dts * T_dtg
36
37 T_dts:
38 This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the
39 dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters
40 (ETR, TIx),
41 00: tDTS=tCK_INT
42 01: tDTS=2*tCK_INT
43 10: tDTS=4*tCK_INT
44
45 T_dtg:
46 This bit-field defines the duration of the dead-time inserted between the complementary
47 outputs. DT correspond to this duration.
48 DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS.
49 DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS.
50 DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS.
51 DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS.
52 Example if TDTS=125ns (8MHz), dead-time possible values are:
53 0 to 15875 ns by 125 ns steps,
54 16 us to 31750 ns by 250 ns steps,
55 32 us to 63us by 1 us steps,
56 64 us to 126 us by 2 us steps
57 */
58 pwm.set_dead_time_clock_division(Ckd::DIV1);
59 pwm.set_dead_time_value(0);
60
61 let max = pwm.get_max_duty();
62 pwm.enable(Channel::Ch1);
63
64 info!("PWM initialized");
65 info!("PWM max duty {}", max);
66
67 loop {
68 pwm.set_duty(Channel::Ch1, 0);
69 Timer::after(Duration::from_millis(300)).await;
70 pwm.set_duty(Channel::Ch1, max / 4);
71 Timer::after(Duration::from_millis(300)).await;
72 pwm.set_duty(Channel::Ch1, max / 2);
73 Timer::after(Duration::from_millis(300)).await;
74 pwm.set_duty(Channel::Ch1, max - 1);
75 Timer::after(Duration::from_millis(300)).await;
76 }
77}
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index 4a7bca1fa..aabfe8557 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 15 info!("Hello Flash!");
16 16
17 const ADDR: u32 = 0x8_0000; 17 const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000.
18 18
19 // wait a bit before accessing the flash 19 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 20 Timer::after(Duration::from_millis(300)).await;
21 21
22 let mut f = Flash::new(p.FLASH); 22 let mut f = Flash::new(p.FLASH).into_regions().bank1_region3;
23 23
24 info!("Reading..."); 24 info!("Reading...");
25 let mut buf = [0u8; 32]; 25 let mut buf = [0u8; 32];
diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml
new file mode 100644
index 000000000..c8b864b6c
--- /dev/null
+++ b/examples/stm32h5/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H563ZITx'
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
new file mode 100644
index 000000000..f240c3896
--- /dev/null
+++ b/examples/stm32h5/Cargo.toml
@@ -0,0 +1,71 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h7-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
13embedded-io = { version = "0.4.0", features = ["async"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15
16defmt = "0.3"
17defmt-rtt = "0.4"
18
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
23embedded-hal-async = { version = "=0.2.0-alpha.1" }
24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false }
28rand_core = "0.6.3"
29critical-section = "1.1"
30micromath = "2.0.0"
31stm32-fmc = "0.2.4"
32embedded-storage = "0.3.0"
33static_cell = "1.0"
34
35# cargo build/run
36[profile.dev]
37codegen-units = 1
38debug = 2
39debug-assertions = true # <-
40incremental = false
41opt-level = 3 # <-
42overflow-checks = true # <-
43
44# cargo test
45[profile.test]
46codegen-units = 1
47debug = 2
48debug-assertions = true # <-
49incremental = false
50opt-level = 3 # <-
51overflow-checks = true # <-
52
53# cargo build/run --release
54[profile.release]
55codegen-units = 1
56debug = 2
57debug-assertions = false # <-
58incremental = false
59lto = 'fat'
60opt-level = 3 # <-
61overflow-checks = false # <-
62
63# cargo test --release
64[profile.bench]
65codegen-units = 1
66debug = 2
67debug-assertions = false # <-
68incremental = false
69lto = 'fat'
70opt-level = 3 # <-
71overflow-checks = false # <-
diff --git a/examples/stm32h5/build.rs b/examples/stm32h5/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32h5/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/stm32h5/memory.x b/examples/stm32h5/memory.x
new file mode 100644
index 000000000..456061509
--- /dev/null
+++ b/examples/stm32h5/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 0x200000
4 RAM : ORIGIN = 0x20000000, LENGTH = 0x50000
5}
diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs
new file mode 100644
index 000000000..f9bf90d2e
--- /dev/null
+++ b/examples/stm32h5/src/bin/blinky.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, 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.PB0, Level::High, Speed::Low);
17
18 loop {
19 info!("high");
20 led.set_high();
21 Timer::after(Duration::from_millis(500)).await;
22
23 info!("low");
24 led.set_low();
25 Timer::after(Duration::from_millis(500)).await;
26 }
27}
diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs
new file mode 100644
index 000000000..dfe587d41
--- /dev/null
+++ b/examples/stm32h5/src/bin/button_exti.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::exti::ExtiInput;
8use embassy_stm32::gpio::{Input, Pull};
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 button = Input::new(p.PC13, Pull::Down);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18
19 info!("Press the USER button...");
20
21 loop {
22 button.wait_for_rising_edge().await;
23 info!("Pressed!");
24 button.wait_for_falling_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
new file mode 100644
index 000000000..6d650da9e
--- /dev/null
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -0,0 +1,133 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
13use embassy_stm32::rng::Rng;
14use embassy_stm32::time::Hertz;
15use embassy_stm32::{interrupt, Config};
16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::Write;
18use rand_core::RngCore;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31type Device = Ethernet<'static, ETH, GenericSMI>;
32
33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device>) -> ! {
35 stack.run().await
36}
37
38#[embassy_executor::main]
39async fn main(spawner: Spawner) -> ! {
40 let mut config = Config::default();
41 config.rcc.hsi = None;
42 config.rcc.hsi48 = true; // needed for rng
43 config.rcc.hse = Some(Hse {
44 freq: Hertz(8_000_000),
45 mode: HseMode::BypassDigital,
46 });
47 config.rcc.pll1 = Some(Pll {
48 source: PllSource::Hse,
49 prediv: 2,
50 mul: 125,
51 divp: Some(2),
52 divq: Some(2),
53 divr: None,
54 });
55 config.rcc.ahb_pre = AHBPrescaler::NotDivided;
56 config.rcc.apb1_pre = APBPrescaler::NotDivided;
57 config.rcc.apb2_pre = APBPrescaler::NotDivided;
58 config.rcc.apb3_pre = APBPrescaler::NotDivided;
59 config.rcc.sys = Sysclk::Pll1P;
60 config.rcc.voltage_scale = VoltageScale::Scale0;
61 let p = embassy_stm32::init(config);
62 info!("Hello World!");
63
64 // Generate random seed.
65 let mut rng = Rng::new(p.RNG);
66 let mut seed = [0; 8];
67 rng.fill_bytes(&mut seed);
68 let seed = u64::from_le_bytes(seed);
69
70 let eth_int = interrupt::take!(ETH);
71 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
72
73 let device = Ethernet::new(
74 singleton!(PacketQueue::<4, 4>::new()),
75 p.ETH,
76 eth_int,
77 p.PA1,
78 p.PA2,
79 p.PC1,
80 p.PA7,
81 p.PC4,
82 p.PC5,
83 p.PG13,
84 p.PB15,
85 p.PG11,
86 GenericSMI,
87 mac_addr,
88 0,
89 );
90
91 let config = embassy_net::Config::Dhcp(Default::default());
92 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
93 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
94 // dns_servers: Vec::new(),
95 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
96 //});
97
98 // Init network stack
99 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
100
101 // Launch network task
102 unwrap!(spawner.spawn(net_task(&stack)));
103
104 info!("Network task initialized");
105
106 // Then we can use it!
107 let mut rx_buffer = [0; 1024];
108 let mut tx_buffer = [0; 1024];
109
110 loop {
111 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
112
113 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
114
115 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
116 info!("connecting...");
117 let r = socket.connect(remote_endpoint).await;
118 if let Err(e) = r {
119 info!("connect error: {:?}", e);
120 Timer::after(Duration::from_secs(3)).await;
121 continue;
122 }
123 info!("connected!");
124 loop {
125 let r = socket.write_all(b"Hello\n").await;
126 if let Err(e) = r {
127 info!("write error: {:?}", e);
128 continue;
129 }
130 Timer::after(Duration::from_secs(1)).await;
131 }
132 }
133}
diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs
new file mode 100644
index 000000000..6cbf58bbc
--- /dev/null
+++ b/examples/stm32h5/src/bin/i2c.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
8use embassy_stm32::interrupt;
9use embassy_stm32::time::Hertz;
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello world!");
19 let p = embassy_stm32::init(Default::default());
20
21 let irq = interrupt::take!(I2C2_EV);
22 let mut i2c = I2c::new(
23 p.I2C2,
24 p.PB10,
25 p.PB11,
26 irq,
27 p.GPDMA1_CH4,
28 p.GPDMA1_CH5,
29 Hertz(100_000),
30 Default::default(),
31 );
32
33 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
34 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
35 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
36
37 let mut data = [0u8; 1];
38
39 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
40 Ok(()) => info!("Whoami: {}", data[0]),
41 Err(Error::Timeout) => error!("Operation timed out"),
42 Err(e) => error!("I2c Error: {:?}", e),
43 }
44}
diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs
new file mode 100644
index 000000000..af9be0b62
--- /dev/null
+++ b/examples/stm32h5/src/bin/rng.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rng::Rng;
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 rng = Rng::new(p.RNG);
16
17 let mut buf = [0u8; 16];
18 unwrap!(rng.async_fill_bytes(&mut buf).await);
19 info!("random bytes: {:02x}", buf);
20}
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
new file mode 100644
index 000000000..405f18ec7
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cortex_m_rt::entry;
6use defmt::*;
7use embassy_executor::Executor;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart};
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::task]
15async fn main_task() {
16 let p = embassy_stm32::init(Default::default());
17
18 let config = Config::default();
19 let irq = interrupt::take!(UART7);
20 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config);
21
22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
23 info!("wrote Hello, starting echo");
24
25 let mut buf = [0u8; 1];
26 loop {
27 unwrap!(usart.blocking_read(&mut buf));
28 unwrap!(usart.blocking_write(&buf));
29 }
30}
31
32static EXECUTOR: StaticCell<Executor> = StaticCell::new();
33
34#[entry]
35fn main() -> ! {
36 info!("Hello World!");
37
38 let executor = EXECUTOR.init(Executor::new());
39
40 executor.run(|spawner| {
41 unwrap!(spawner.spawn(main_task()));
42 })
43}
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
new file mode 100644
index 000000000..43d791aae
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -0,0 +1,46 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::fmt::Write;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma;
11use embassy_stm32::interrupt;
12use embassy_stm32::usart::{Config, Uart};
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::task]
18async fn main_task() {
19 let p = embassy_stm32::init(Default::default());
20
21 let config = Config::default();
22 let irq = interrupt::take!(UART7);
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, NoDma, config);
24
25 for n in 0u32.. {
26 let mut s: String<128> = String::new();
27 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
28
29 usart.write(s.as_bytes()).await.ok();
30
31 info!("wrote DMA");
32 }
33}
34
35static EXECUTOR: StaticCell<Executor> = StaticCell::new();
36
37#[entry]
38fn main() -> ! {
39 info!("Hello World!");
40
41 let executor = EXECUTOR.init(Executor::new());
42
43 executor.run(|spawner| {
44 unwrap!(spawner.spawn(main_task()));
45 })
46}
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
new file mode 100644
index 000000000..16a499582
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -0,0 +1,58 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt;
9use embassy_stm32::peripherals::{GPDMA1_CH1, UART7};
10use embassy_stm32::usart::{Config, Uart, UartRx};
11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
12use embassy_sync::channel::Channel;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
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}
26
27static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
28
29#[embassy_executor::main]
30async fn main(spawner: Spawner) -> ! {
31 let p = embassy_stm32::init(Default::default());
32 info!("Hello World!");
33
34 let config = Config::default();
35 let irq = interrupt::take!(UART7);
36 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, p.GPDMA1_CH1, config);
37 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
38
39 let (mut tx, rx) = usart.split();
40
41 unwrap!(spawner.spawn(reader(rx)));
42
43 loop {
44 let buf = CHANNEL.recv().await;
45 info!("writing...");
46 unwrap!(tx.write(&buf).await);
47 }
48}
49
50#[embassy_executor::task]
51async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) {
52 let mut buf = [0; 8];
53 loop {
54 info!("reading...");
55 unwrap!(rx.read(&mut buf).await);
56 CHANNEL.send(buf).await;
57 }
58}
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
new file mode 100644
index 000000000..6af269c1d
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -0,0 +1,128 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, pac, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut config = Config::default();
20 config.rcc.hsi = None;
21 config.rcc.hsi48 = true; // needed for usb
22 config.rcc.hse = Some(Hse {
23 freq: Hertz(8_000_000),
24 mode: HseMode::BypassDigital,
25 });
26 config.rcc.pll1 = Some(Pll {
27 source: PllSource::Hse,
28 prediv: 2,
29 mul: 125,
30 divp: Some(2), // 250mhz
31 divq: None,
32 divr: None,
33 });
34 config.rcc.ahb_pre = AHBPrescaler::Div2;
35 config.rcc.apb1_pre = APBPrescaler::Div4;
36 config.rcc.apb2_pre = APBPrescaler::Div2;
37 config.rcc.apb3_pre = APBPrescaler::Div4;
38 config.rcc.sys = Sysclk::Pll1P;
39 config.rcc.voltage_scale = VoltageScale::Scale0;
40 let p = embassy_stm32::init(config);
41
42 info!("Hello World!");
43
44 unsafe {
45 pac::RCC.ccipr4().write(|w| {
46 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
47 });
48 }
49
50 // Create the driver, from the HAL.
51 let irq = interrupt::take!(USB_DRD_FS);
52 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
53
54 // Create embassy-usb Config
55 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
56 config.manufacturer = Some("Embassy");
57 config.product = Some("USB-serial example");
58 config.serial_number = Some("12345678");
59
60 // Required for windows compatiblity.
61 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
62 config.device_class = 0xEF;
63 config.device_sub_class = 0x02;
64 config.device_protocol = 0x01;
65 config.composite_with_iads = true;
66
67 // Create embassy-usb DeviceBuilder using the driver and config.
68 // It needs some buffers for building the descriptors.
69 let mut device_descriptor = [0; 256];
70 let mut config_descriptor = [0; 256];
71 let mut bos_descriptor = [0; 256];
72 let mut control_buf = [0; 64];
73
74 let mut state = State::new();
75
76 let mut builder = Builder::new(
77 driver,
78 config,
79 &mut device_descriptor,
80 &mut config_descriptor,
81 &mut bos_descriptor,
82 &mut control_buf,
83 );
84
85 // Create classes on the builder.
86 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
87
88 // Build the builder.
89 let mut usb = builder.build();
90
91 // Run the USB device.
92 let usb_fut = usb.run();
93
94 // Do stuff with the class!
95 let echo_fut = async {
96 loop {
97 class.wait_connection().await;
98 info!("Connected");
99 let _ = echo(&mut class).await;
100 info!("Disconnected");
101 }
102 };
103
104 // Run everything concurrently.
105 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
106 join(usb_fut, echo_fut).await;
107}
108
109struct Disconnected {}
110
111impl From<EndpointError> for Disconnected {
112 fn from(val: EndpointError) -> Self {
113 match val {
114 EndpointError::BufferOverflow => panic!("Buffer overflow"),
115 EndpointError::Disabled => Disconnected {},
116 }
117 }
118}
119
120async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
121 let mut buf = [0; 64];
122 loop {
123 let n = class.read_packet(&mut buf).await?;
124 let data = &buf[..n];
125 info!("data: {:x}", data);
126 class.write_packet(data).await?;
127 }
128}
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index d0d6a9497..154f5a987 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
23embedded-hal-async = { version = "=0.2.0-alpha.0" } 23embedded-hal-async = { version = "=0.2.0-alpha.1" }
24embedded-nal-async = "0.4.0" 24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index ee86bdbf6..7ee9838c9 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -14,12 +14,12 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 15 info!("Hello Flash!");
16 16
17 const ADDR: u32 = 0x08_0000; 17 const ADDR: u32 = 0; // This is the offset into bank 2, the absolute address is 0x8_0000
18 18
19 // wait a bit before accessing the flash 19 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 20 Timer::after(Duration::from_millis(300)).await;
21 21
22 let mut f = Flash::new(p.FLASH); 22 let mut f = Flash::new(p.FLASH).into_regions().bank2_region;
23 23
24 info!("Reading..."); 24 info!("Reading...");
25 let mut buf = [0u8; 32]; 25 let mut buf = [0u8; 32];
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index ffe4fb10b..337425028 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index 476ed51a4..38feb0d76 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x26000; 16 const ADDR: u32 = 0x26000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 7c254eba3..fa39df6db 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -18,8 +18,8 @@ defmt-rtt = "0.4"
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
22embedded-hal-async = { version = "=0.2.0-alpha.0" } 22embedded-hal-async = { version = "=0.2.0-alpha.1" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.7.5", default-features = false } 25heapless = { version = "0.7.5", default-features = false }
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 9fc7e0f4a..0d2194ea2 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] }
12embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } 12embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
13 13
14lorawan-device = { version = "0.8.0", default-features = false, features = ["async"] } 14lorawan-device = { version = "0.8.0", default-features = false, features = ["async"] }
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 2a8880624..e6bc2865c 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 15
16 const ADDR: u32 = 0x36000; 16 const ADDR: u32 = 0x36000;
17 17
18 let mut f = Flash::new(p.FLASH); 18 let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
19 19
20 info!("Reading..."); 20 info!("Reading...");
21 let mut buf = [0u8; 8]; 21 let mut buf = [0u8; 8];
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 22abacdea..9785cd9eb 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -9,5 +9,6 @@ targets = [
9 "thumbv6m-none-eabi", 9 "thumbv6m-none-eabi",
10 "thumbv7em-none-eabihf", 10 "thumbv7em-none-eabihf",
11 "thumbv8m.main-none-eabihf", 11 "thumbv8m.main-none-eabihf",
12 "riscv32imac-unknown-none-elf",
12 "wasm32-unknown-unknown", 13 "wasm32-unknown-unknown",
13] 14]
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index eb447be35..463a370fe 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -17,8 +17,8 @@ defmt-rtt = "0.4"
17cortex-m = { version = "0.7.6" } 17cortex-m = { version = "0.7.6" }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 20embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
21embedded-hal-async = { version = "=0.2.0-alpha.0" } 21embedded-hal-async = { version = "=0.2.0-alpha.1" }
22panic-probe = { version = "0.3.0", features = ["print-defmt"] } 22panic-probe = { version = "0.3.0", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24embedded-io = { version = "0.4.0", features = ["async"] } 24embedded-io = { version = "0.4.0", features = ["async"] }
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 17b640797..bd181f235 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -11,6 +11,7 @@ stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo
11stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo 11stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo
12stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo 12stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo
13stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo 13stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo
14stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
14stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 15stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
15 16
16[dependencies] 17[dependencies]
@@ -25,8 +26,8 @@ defmt-rtt = "0.4"
25cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 26cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
26cortex-m-rt = "0.7.0" 27cortex-m-rt = "0.7.0"
27embedded-hal = "0.2.6" 28embedded-hal = "0.2.6"
28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 29embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
29embedded-hal-async = { version = "=0.2.0-alpha.0" } 30embedded-hal-async = { version = "=0.2.0-alpha.1" }
30panic-probe = { version = "0.3.0", features = ["print-defmt"] } 31panic-probe = { version = "0.3.0", features = ["print-defmt"] }
31 32
32[profile.dev] 33[profile.dev]
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index 18fd85d44..6a36df8cc 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -30,6 +30,8 @@ async fn main(_spawner: Spawner) {
30 let (mut a, mut b) = (p.PB6, p.PB7); 30 let (mut a, mut b) = (p.PB6, p.PB7);
31 #[cfg(feature = "stm32u585ai")] 31 #[cfg(feature = "stm32u585ai")]
32 let (mut a, mut b) = (p.PD9, p.PD8); 32 let (mut a, mut b) = (p.PD9, p.PD8);
33 #[cfg(feature = "stm32h563zi")]
34 let (mut a, mut b) = (p.PB6, p.PB7);
33 35
34 // Test initial output 36 // Test initial output
35 { 37 {
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 1c5dc87c0..bf8098b1b 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -17,22 +17,25 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 17 info!("Hello World!");
18 18
19 #[cfg(feature = "stm32f103c8")] 19 #[cfg(feature = "stm32f103c8")]
20 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 20 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
21 #[cfg(feature = "stm32f429zi")] 21 #[cfg(feature = "stm32f429zi")]
22 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 22 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
23 #[cfg(feature = "stm32h755zi")] 23 #[cfg(feature = "stm32h755zi")]
24 let (sck, mosi, miso) = (p.PA5, p.PB5, p.PA6); 24 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PB5, p.PA6);
25 #[cfg(feature = "stm32g491re")] 25 #[cfg(feature = "stm32g491re")]
26 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 26 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
27 #[cfg(feature = "stm32g071rb")] 27 #[cfg(feature = "stm32g071rb")]
28 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 28 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
29 #[cfg(feature = "stm32wb55rg")] 29 #[cfg(feature = "stm32wb55rg")]
30 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 30 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
31 #[cfg(feature = "stm32u585ai")] 31 #[cfg(feature = "stm32u585ai")]
32 let (sck, mosi, miso) = (p.PE13, p.PE15, p.PE14); 32 let (spi, sck, mosi, miso) = (p.SPI1, p.PE13, p.PE15, p.PE14);
33 #[cfg(feature = "stm32h563zi")]
34 let (spi, sck, mosi, miso) = (p.SPI4, p.PE12, p.PE14, p.PE13);
33 35
36 info!("asdfa;");
34 let mut spi = Spi::new( 37 let mut spi = Spi::new(
35 p.SPI1, 38 spi,
36 sck, // Arduino D13 39 sck, // Arduino D13
37 mosi, // Arduino D11 40 mosi, // Arduino D11
38 miso, // Arduino D12 41 miso, // Arduino D12
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index cb2152e0b..b3dad8132 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -16,22 +16,24 @@ async fn main(_spawner: Spawner) {
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 #[cfg(feature = "stm32f103c8")] 18 #[cfg(feature = "stm32f103c8")]
19 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); 19 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2);
20 #[cfg(feature = "stm32f429zi")] 20 #[cfg(feature = "stm32f429zi")]
21 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); 21 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2);
22 #[cfg(feature = "stm32h755zi")] 22 #[cfg(feature = "stm32h755zi")]
23 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); 23 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1);
24 #[cfg(feature = "stm32g491re")] 24 #[cfg(feature = "stm32g491re")]
25 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 25 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
26 #[cfg(feature = "stm32g071rb")] 26 #[cfg(feature = "stm32g071rb")]
27 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 27 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
28 #[cfg(feature = "stm32wb55rg")] 28 #[cfg(feature = "stm32wb55rg")]
29 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 29 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
30 #[cfg(feature = "stm32u585ai")] 30 #[cfg(feature = "stm32u585ai")]
31 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); 31 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1);
32 #[cfg(feature = "stm32h563zi")]
33 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI4, p.PE12, p.PE14, p.PE13, p.GPDMA1_CH0, p.GPDMA1_CH1);
32 34
33 let mut spi = Spi::new( 35 let mut spi = Spi::new(
34 p.SPI1, 36 spi,
35 sck, // Arduino D13 37 sck, // Arduino D13
36 mosi, // Arduino D11 38 mosi, // Arduino D11
37 miso, // Arduino D12 39 miso, // Arduino D12
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index af55867f2..52409567c 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -32,6 +32,8 @@ async fn main(_spawner: Spawner) {
32 let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); 32 let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
33 #[cfg(feature = "stm32u585ai")] 33 #[cfg(feature = "stm32u585ai")]
34 let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); 34 let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
35 #[cfg(feature = "stm32h563zi")]
36 let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
35 37
36 let config = Config::default(); 38 let config = Config::default();
37 let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); 39 let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index d12605a9a..3f70791c1 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -62,6 +62,15 @@ async fn main(_spawner: Spawner) {
62 p.GPDMA1_CH0, 62 p.GPDMA1_CH0,
63 p.GPDMA1_CH1, 63 p.GPDMA1_CH1,
64 ); 64 );
65 #[cfg(feature = "stm32h563zi")]
66 let (tx, rx, usart, irq, tx_dma, rx_dma) = (
67 p.PB6,
68 p.PB7,
69 p.LPUART1,
70 interrupt::take!(LPUART1),
71 p.GPDMA1_CH0,
72 p.GPDMA1_CH1,
73 );
65 74
66 let config = Config::default(); 75 let config = Config::default();
67 let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); 76 let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config);