diff options
93 files changed, 3678 insertions, 1243 deletions
| @@ -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] |
| 26 | defmt = { version = "0.3", optional = true } | 26 | defmt = { version = "0.3", optional = true } |
| 27 | digest = "0.10" | ||
| 27 | log = { version = "0.4", optional = true } | 28 | log = { version = "0.4", optional = true } |
| 28 | ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } | 29 | ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } |
| 29 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } | 30 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } |
| @@ -37,6 +38,7 @@ log = "0.4" | |||
| 37 | env_logger = "0.9" | 38 | env_logger = "0.9" |
| 38 | rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version | 39 | rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version |
| 39 | futures = { version = "0.3", features = ["executor"] } | 40 | futures = { version = "0.3", features = ["executor"] } |
| 41 | sha1 = "0.10.5" | ||
| 40 | 42 | ||
| 41 | [dev-dependencies.ed25519-dalek] | 43 | [dev-dependencies.ed25519-dalek] |
| 42 | default_features = false | 44 | default_features = false |
| @@ -47,4 +49,4 @@ ed25519-dalek = ["dep:ed25519-dalek", "_verify"] | |||
| 47 | ed25519-salty = ["dep:salty", "_verify"] | 49 | ed25519-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 @@ | |||
| 1 | use digest::typenum::U64; | ||
| 2 | use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; | ||
| 3 | use ed25519_dalek::Digest as _; | ||
| 4 | |||
| 5 | pub struct Sha512(ed25519_dalek::Sha512); | ||
| 6 | |||
| 7 | impl Default for Sha512 { | ||
| 8 | fn default() -> Self { | ||
| 9 | Self(ed25519_dalek::Sha512::new()) | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | impl Update for Sha512 { | ||
| 14 | fn update(&mut self, data: &[u8]) { | ||
| 15 | self.0.update(data) | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | impl 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 | |||
| 26 | impl OutputSizeUser for Sha512 { | ||
| 27 | type OutputSize = U64; | ||
| 28 | } | ||
| 29 | |||
| 30 | impl 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")] | ||
| 2 | pub(crate) mod ed25519_dalek; | ||
| 3 | |||
| 4 | #[cfg(feature = "ed25519-salty")] | ||
| 5 | pub(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 @@ | |||
| 1 | use digest::typenum::U64; | ||
| 2 | use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; | ||
| 3 | |||
| 4 | pub struct Sha512(salty::Sha512); | ||
| 5 | |||
| 6 | impl Default for Sha512 { | ||
| 7 | fn default() -> Self { | ||
| 8 | Self(salty::Sha512::new()) | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | impl Update for Sha512 { | ||
| 13 | fn update(&mut self, data: &[u8]) { | ||
| 14 | self.0.update(data) | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | impl 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 | |||
| 25 | impl OutputSizeUser for Sha512 { | ||
| 26 | type OutputSize = U64; | ||
| 27 | } | ||
| 28 | |||
| 29 | impl 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 @@ | |||
| 1 | use digest::Digest; | ||
| 1 | use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; | 2 | use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; |
| 2 | use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; | 3 | use 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)] | ||
| 510 | mod 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 @@ | |||
| 6 | mod fmt; | 6 | mod fmt; |
| 7 | 7 | ||
| 8 | mod boot_loader; | 8 | mod boot_loader; |
| 9 | mod digest_adapters; | ||
| 9 | mod firmware_updater; | 10 | mod firmware_updater; |
| 10 | mod mem_flash; | 11 | mod mem_flash; |
| 11 | mod partition; | 12 | mod 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] |
| 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 23 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true } | 23 | embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true } |
| 24 | embedded-storage = "0.3.0" | 24 | embedded-storage = "0.3.0" |
| 25 | embedded-storage-async = { version = "0.4.0", optional = true } | 25 | embedded-storage-async = { version = "0.4.0", optional = true } |
| 26 | nb = "1.0.0" | 26 | nb = "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 | //! ``` |
| 28 | use core::future::Future; | ||
| 29 | 28 | ||
| 30 | use embassy_sync::blocking_mutex::raw::RawMutex; | 29 | use embassy_sync::blocking_mutex::raw::RawMutex; |
| 31 | use embassy_sync::mutex::Mutex; | 30 | use embassy_sync::mutex::Mutex; |
| 32 | use embedded_hal_1::digital::OutputPin; | 31 | use embedded_hal_1::digital::OutputPin; |
| 33 | use embedded_hal_1::spi::ErrorType; | 32 | use embedded_hal_1::spi::Operation; |
| 34 | use embedded_hal_async::spi; | 33 | use embedded_hal_async::spi; |
| 35 | 34 | ||
| 36 | use crate::shared_bus::SpiDeviceError; | 35 | use 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 | ||
| 60 | unsafe impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS> | 59 | impl<M, BUS, CS> spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS> |
| 61 | where | 60 | where |
| 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 | |||
| 87 | impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS> | ||
| 88 | where | ||
| 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 | |||
| 115 | impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS> | ||
| 116 | where | ||
| 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 | ||
| 117 | unsafe impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> | 175 | impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS> |
| 176 | where | ||
| 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 | |||
| 204 | impl<M, BUS, CS> spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS> | ||
| 118 | where | 205 | where |
| 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> | 233 | impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> |
| 126 | where | 234 | where |
| 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 | ||
| 105 | impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS> | 77 | impl<'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; | |||
| 23 | use embassy_sync::blocking_mutex::raw::RawMutex; | 23 | use embassy_sync::blocking_mutex::raw::RawMutex; |
| 24 | use embassy_sync::blocking_mutex::Mutex; | 24 | use embassy_sync::blocking_mutex::Mutex; |
| 25 | use embedded_hal_1::digital::OutputPin; | 25 | use embedded_hal_1::digital::OutputPin; |
| 26 | use embedded_hal_1::spi; | 26 | use embedded_hal_1::spi::{self, Operation, SpiBus, SpiBusRead, SpiBusWrite}; |
| 27 | use embedded_hal_1::spi::SpiBusFlush; | ||
| 28 | 27 | ||
| 29 | use crate::shared_bus::SpiDeviceError; | 28 | use crate::shared_bus::SpiDeviceError; |
| 30 | use crate::SetConfig; | 29 | use 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 | ||
| 53 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> | 52 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS> |
| 54 | where | 53 | where |
| 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 | |||
| 78 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS> | ||
| 79 | where | ||
| 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 | |||
| 104 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> | ||
| 105 | where | ||
| 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 | ||
| 149 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> | 203 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS> |
| 150 | where | 204 | where |
| 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 | |||
| 229 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS> | ||
| 230 | where | ||
| 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 | |||
| 255 | impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> | ||
| 256 | where | ||
| 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] |
| 15 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" | 15 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" |
| 16 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" | 16 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" |
| 17 | features = ["nightly", "defmt"] | 17 | features = ["nightly", "defmt", "pender-callback"] |
| 18 | flavors = [ | 18 | flavors = [ |
| 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] |
| 31 | features = ["std", "nightly", "defmt"] | 26 | default-target = "thumbv7em-none-eabi" |
| 27 | targets = ["thumbv7em-none-eabi"] | ||
| 28 | features = ["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; | |||
| 22 | use core::task::{Context, Poll}; | 22 | use core::task::{Context, Poll}; |
| 23 | 23 | ||
| 24 | use atomic_polyfill::{AtomicU32, Ordering}; | 24 | use atomic_polyfill::{AtomicU32, Ordering}; |
| 25 | use critical_section::CriticalSection; | ||
| 26 | #[cfg(feature = "integrated-timers")] | 25 | #[cfg(feature = "integrated-timers")] |
| 27 | use embassy_time::driver::{self, AlarmHandle}; | 26 | use 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`]. |
| 554 | pub fn wake_task(task: TaskRef) { | 551 | pub 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; | |||
| 2 | use core::ptr::NonNull; | 2 | use core::ptr::NonNull; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{AtomicPtr, Ordering}; | 4 | use atomic_polyfill::{AtomicPtr, Ordering}; |
| 5 | use critical_section::CriticalSection; | ||
| 6 | 5 | ||
| 7 | use super::{TaskHeader, TaskRef}; | 6 | use 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 | |||
| 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/" | 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/" |
| 10 | features = ["time", "defmt"] | 10 | features = ["time", "defmt"] |
| 11 | flavors = [ | 11 | flavors = [ |
| 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] |
| 20 | sx126x = [] | 20 | sx126x = [] |
| 21 | sx127x = [] | 21 | sx127x = [] |
| 22 | stm32wl = ["embassy-stm32", "embassy-stm32/subghz"] | 22 | stm32wl = ["dep:embassy-stm32"] |
| 23 | time = [] | 23 | time = [] |
| 24 | defmt = ["dep:defmt", "lorawan/defmt", "lorawan-device/defmt"] | 24 | defmt = ["dep:defmt", "lorawan/defmt", "lorawan-device/defmt"] |
| 25 | 25 | ||
| @@ -31,8 +31,8 @@ log = { version = "0.4.14", optional = true } | |||
| 31 | embassy-time = { version = "0.1.0", path = "../embassy-time" } | 31 | embassy-time = { version = "0.1.0", path = "../embassy-time" } |
| 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } | 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } |
| 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 35 | embedded-hal-async = { version = "=0.2.0-alpha.0" } | 35 | embedded-hal-async = { version = "=0.2.0-alpha.1" } |
| 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } | 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } |
| 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } | 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } |
| 38 | embedded-hal = { version = "0.2", features = ["unproven"] } | 38 | embedded-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" } | |||
| 87 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } | 87 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } |
| 88 | 88 | ||
| 89 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 89 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 90 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 90 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
| 91 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} | 91 | embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} |
| 92 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } | 92 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 93 | 93 | ||
| 94 | defmt = { version = "0.3", optional = true } | 94 | defmt = { 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 { | |||
| 885 | mod eha { | 864 | mod 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 | ||
| 67 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 67 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 68 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 68 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
| 69 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} | 69 | embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} |
| 70 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 70 | embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} |
| 71 | 71 | ||
| 72 | paste = "1.0" | 72 | paste = "1.0" |
| 73 | pio-proc = {version= "0.2", optional = true} | 73 | pio-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)] | ||
| 22 | pub struct Config { | 23 | pub 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" | |||
| 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" | 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" |
| 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" | 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" |
| 10 | 10 | ||
| 11 | # TODO: sdmmc | 11 | features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"] |
| 12 | # TODO: net | ||
| 13 | # TODO: subghz | ||
| 14 | features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any"] | ||
| 15 | flavors = [ | 12 | flavors = [ |
| 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" } | |||
| 44 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } | 42 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 45 | 43 | ||
| 46 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 44 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 47 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 45 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
| 48 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} | 46 | embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} |
| 49 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 47 | embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} |
| 50 | 48 | ||
| 51 | embedded-storage = "0.3.0" | 49 | embedded-storage = "0.3.0" |
| 52 | 50 | ||
| @@ -60,7 +58,7 @@ sdio-host = "0.5.0" | |||
| 60 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } | 58 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } |
| 61 | critical-section = "1.1" | 59 | critical-section = "1.1" |
| 62 | atomic-polyfill = "1.0.1" | 60 | atomic-polyfill = "1.0.1" |
| 63 | stm32-metapac = { version = "2", features = ["rt"] } | 61 | stm32-metapac = "5" |
| 64 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 65 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 66 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -69,15 +67,18 @@ seq-macro = "0.3.0" | |||
| 69 | cfg-if = "1.0.0" | 67 | cfg-if = "1.0.0" |
| 70 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } | 68 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 71 | 69 | ||
| 70 | [dev-dependencies] | ||
| 71 | critical-section = { version = "1.1", features = ["std"] } | ||
| 72 | |||
| 72 | [build-dependencies] | 73 | [build-dependencies] |
| 73 | proc-macro2 = "1.0.36" | 74 | proc-macro2 = "1.0.36" |
| 74 | quote = "1.0.15" | 75 | quote = "1.0.15" |
| 75 | stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} | 76 | stm32-metapac = { version = "5", default-features = false, features = ["metadata"]} |
| 76 | 77 | ||
| 77 | [features] | 78 | [features] |
| 79 | default = ["stm32-metapac/rt"] | ||
| 78 | defmt = ["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"] | 80 | defmt = ["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"] |
| 79 | memory-x = ["stm32-metapac/memory-x"] | 81 | memory-x = ["stm32-metapac/memory-x"] |
| 80 | subghz = [] | ||
| 81 | exti = [] | 82 | exti = [] |
| 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" ] | |||
| 830 | stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] | 831 | stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] |
| 831 | stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] | 832 | stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] |
| 832 | stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] | 833 | stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] |
| 834 | stm32h503cb = [ "stm32-metapac/stm32h503cb" ] | ||
| 835 | stm32h503eb = [ "stm32-metapac/stm32h503eb" ] | ||
| 836 | stm32h503kb = [ "stm32-metapac/stm32h503kb" ] | ||
| 837 | stm32h503rb = [ "stm32-metapac/stm32h503rb" ] | ||
| 838 | stm32h562ag = [ "stm32-metapac/stm32h562ag" ] | ||
| 839 | stm32h562ai = [ "stm32-metapac/stm32h562ai" ] | ||
| 840 | stm32h562ig = [ "stm32-metapac/stm32h562ig" ] | ||
| 841 | stm32h562ii = [ "stm32-metapac/stm32h562ii" ] | ||
| 842 | stm32h562rg = [ "stm32-metapac/stm32h562rg" ] | ||
| 843 | stm32h562ri = [ "stm32-metapac/stm32h562ri" ] | ||
| 844 | stm32h562vg = [ "stm32-metapac/stm32h562vg" ] | ||
| 845 | stm32h562vi = [ "stm32-metapac/stm32h562vi" ] | ||
| 846 | stm32h562zg = [ "stm32-metapac/stm32h562zg" ] | ||
| 847 | stm32h562zi = [ "stm32-metapac/stm32h562zi" ] | ||
| 848 | stm32h563ag = [ "stm32-metapac/stm32h563ag" ] | ||
| 849 | stm32h563ai = [ "stm32-metapac/stm32h563ai" ] | ||
| 850 | stm32h563ig = [ "stm32-metapac/stm32h563ig" ] | ||
| 851 | stm32h563ii = [ "stm32-metapac/stm32h563ii" ] | ||
| 852 | stm32h563mi = [ "stm32-metapac/stm32h563mi" ] | ||
| 853 | stm32h563rg = [ "stm32-metapac/stm32h563rg" ] | ||
| 854 | stm32h563ri = [ "stm32-metapac/stm32h563ri" ] | ||
| 855 | stm32h563vg = [ "stm32-metapac/stm32h563vg" ] | ||
| 856 | stm32h563vi = [ "stm32-metapac/stm32h563vi" ] | ||
| 857 | stm32h563zg = [ "stm32-metapac/stm32h563zg" ] | ||
| 858 | stm32h563zi = [ "stm32-metapac/stm32h563zi" ] | ||
| 859 | stm32h573ai = [ "stm32-metapac/stm32h573ai" ] | ||
| 860 | stm32h573ii = [ "stm32-metapac/stm32h573ii" ] | ||
| 861 | stm32h573mi = [ "stm32-metapac/stm32h573mi" ] | ||
| 862 | stm32h573ri = [ "stm32-metapac/stm32h573ri" ] | ||
| 863 | stm32h573vi = [ "stm32-metapac/stm32h573vi" ] | ||
| 864 | stm32h573zi = [ "stm32-metapac/stm32h573zi" ] | ||
| 833 | stm32h723ve = [ "stm32-metapac/stm32h723ve" ] | 865 | stm32h723ve = [ "stm32-metapac/stm32h723ve" ] |
| 834 | stm32h723vg = [ "stm32-metapac/stm32h723vg" ] | 866 | stm32h723vg = [ "stm32-metapac/stm32h723vg" ] |
| 835 | stm32h723ze = [ "stm32-metapac/stm32h723ze" ] | 867 | stm32h723ze = [ "stm32-metapac/stm32h723ze" ] |
| @@ -1312,6 +1344,22 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] | |||
| 1312 | stm32l562re = [ "stm32-metapac/stm32l562re" ] | 1344 | stm32l562re = [ "stm32-metapac/stm32l562re" ] |
| 1313 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] | 1345 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] |
| 1314 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] | 1346 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] |
| 1347 | stm32u535cb = [ "stm32-metapac/stm32u535cb" ] | ||
| 1348 | stm32u535cc = [ "stm32-metapac/stm32u535cc" ] | ||
| 1349 | stm32u535ce = [ "stm32-metapac/stm32u535ce" ] | ||
| 1350 | stm32u535je = [ "stm32-metapac/stm32u535je" ] | ||
| 1351 | stm32u535nc = [ "stm32-metapac/stm32u535nc" ] | ||
| 1352 | stm32u535ne = [ "stm32-metapac/stm32u535ne" ] | ||
| 1353 | stm32u535rb = [ "stm32-metapac/stm32u535rb" ] | ||
| 1354 | stm32u535rc = [ "stm32-metapac/stm32u535rc" ] | ||
| 1355 | stm32u535re = [ "stm32-metapac/stm32u535re" ] | ||
| 1356 | stm32u535vc = [ "stm32-metapac/stm32u535vc" ] | ||
| 1357 | stm32u535ve = [ "stm32-metapac/stm32u535ve" ] | ||
| 1358 | stm32u545ce = [ "stm32-metapac/stm32u545ce" ] | ||
| 1359 | stm32u545je = [ "stm32-metapac/stm32u545je" ] | ||
| 1360 | stm32u545ne = [ "stm32-metapac/stm32u545ne" ] | ||
| 1361 | stm32u545re = [ "stm32-metapac/stm32u545re" ] | ||
| 1362 | stm32u545ve = [ "stm32-metapac/stm32u545ve" ] | ||
| 1315 | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] | 1363 | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] |
| 1316 | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] | 1364 | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] |
| 1317 | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] | 1365 | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] |
| @@ -1333,6 +1381,32 @@ stm32u585qi = [ "stm32-metapac/stm32u585qi" ] | |||
| 1333 | stm32u585ri = [ "stm32-metapac/stm32u585ri" ] | 1381 | stm32u585ri = [ "stm32-metapac/stm32u585ri" ] |
| 1334 | stm32u585vi = [ "stm32-metapac/stm32u585vi" ] | 1382 | stm32u585vi = [ "stm32-metapac/stm32u585vi" ] |
| 1335 | stm32u585zi = [ "stm32-metapac/stm32u585zi" ] | 1383 | stm32u585zi = [ "stm32-metapac/stm32u585zi" ] |
| 1384 | stm32u595ai = [ "stm32-metapac/stm32u595ai" ] | ||
| 1385 | stm32u595aj = [ "stm32-metapac/stm32u595aj" ] | ||
| 1386 | stm32u595qi = [ "stm32-metapac/stm32u595qi" ] | ||
| 1387 | stm32u595qj = [ "stm32-metapac/stm32u595qj" ] | ||
| 1388 | stm32u595ri = [ "stm32-metapac/stm32u595ri" ] | ||
| 1389 | stm32u595rj = [ "stm32-metapac/stm32u595rj" ] | ||
| 1390 | stm32u595vi = [ "stm32-metapac/stm32u595vi" ] | ||
| 1391 | stm32u595vj = [ "stm32-metapac/stm32u595vj" ] | ||
| 1392 | stm32u595zi = [ "stm32-metapac/stm32u595zi" ] | ||
| 1393 | stm32u595zj = [ "stm32-metapac/stm32u595zj" ] | ||
| 1394 | stm32u599bj = [ "stm32-metapac/stm32u599bj" ] | ||
| 1395 | stm32u599ni = [ "stm32-metapac/stm32u599ni" ] | ||
| 1396 | stm32u599nj = [ "stm32-metapac/stm32u599nj" ] | ||
| 1397 | stm32u599vi = [ "stm32-metapac/stm32u599vi" ] | ||
| 1398 | stm32u599vj = [ "stm32-metapac/stm32u599vj" ] | ||
| 1399 | stm32u599zi = [ "stm32-metapac/stm32u599zi" ] | ||
| 1400 | stm32u599zj = [ "stm32-metapac/stm32u599zj" ] | ||
| 1401 | stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] | ||
| 1402 | stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] | ||
| 1403 | stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] | ||
| 1404 | stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] | ||
| 1405 | stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] | ||
| 1406 | stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] | ||
| 1407 | stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] | ||
| 1408 | stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] | ||
| 1409 | stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] | ||
| 1336 | stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] | 1410 | stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] |
| 1337 | stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] | 1411 | stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] |
| 1338 | stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] | 1412 | stm32wb30ce = [ "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 _; | |||
| 3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
| 4 | use std::{env, fs}; | 4 | use std::{env, fs}; |
| 5 | 5 | ||
| 6 | use proc_macro2::TokenStream; | 6 | use proc_macro2::{Ident, TokenStream}; |
| 7 | use quote::{format_ident, quote}; | 7 | use quote::{format_ident, quote}; |
| 8 | use stm32_metapac::metadata::METADATA; | 8 | use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; |
| 9 | 9 | ||
| 10 | fn main() { | 10 | fn 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 | |||
| 941 | fn 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 | |||
| 950 | fn 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")] |
| 8 | mod _version; | 8 | mod _version; |
| 9 | 9 | ||
| 10 | #[cfg(not(any(adc_f1, adc_v1)))] | 10 | #[cfg(not(adc_f1))] |
| 11 | mod resolution; | 11 | mod resolution; |
| 12 | #[cfg(not(adc_v1))] | ||
| 13 | mod sample_time; | 12 | mod sample_time; |
| 14 | 13 | ||
| 15 | #[allow(unused)] | 14 | #[allow(unused)] |
| 16 | pub use _version::*; | 15 | pub use _version::*; |
| 17 | #[cfg(not(any(adc_f1, adc_v1)))] | 16 | #[cfg(not(adc_f1))] |
| 18 | pub use resolution::Resolution; | 17 | pub use resolution::Resolution; |
| 19 | #[cfg(not(adc_v1))] | ||
| 20 | pub use sample_time::SampleTime; | 18 | pub use sample_time::SampleTime; |
| 21 | 19 | ||
| 22 | use crate::peripherals; | 20 | use crate::peripherals; |
| 23 | 21 | ||
| 24 | #[cfg(not(adc_v1))] | ||
| 25 | pub struct Adc<'d, T: Instance> { | 22 | pub 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)))] |
| 48 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 45 | pub 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))] |
| 50 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 47 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 51 | 48 | ||
| 52 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 49 | pub 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)] |
| 3 | pub enum Resolution { | 3 | pub enum Resolution { |
| 4 | TwelveBit, | 4 | TwelveBit, |
| @@ -19,7 +19,7 @@ pub enum Resolution { | |||
| 19 | 19 | ||
| 20 | impl Default for Resolution { | 20 | impl 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))] |
| 29 | impl_sample_time!( | 29 | impl_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 @@ | |||
| 1 | use embassy_hal_common::into_ref; | ||
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | ||
| 1 | 3 | ||
| 4 | use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; | ||
| 5 | use crate::peripherals::ADC; | ||
| 6 | use crate::Peripheral; | ||
| 7 | |||
| 8 | pub const VDDA_CALIB_MV: u32 = 3300; | ||
| 9 | pub const VREF_INT: u32 = 1230; | ||
| 10 | |||
| 11 | pub struct Vbat; | ||
| 12 | impl InternalChannel<ADC> for Vbat {} | ||
| 13 | impl super::sealed::InternalChannel<ADC> for Vbat { | ||
| 14 | fn channel(&self) -> u8 { | ||
| 15 | 18 | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | pub struct Vref; | ||
| 20 | impl InternalChannel<ADC> for Vref {} | ||
| 21 | impl super::sealed::InternalChannel<ADC> for Vref { | ||
| 22 | fn channel(&self) -> u8 { | ||
| 23 | 17 | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | pub struct Temperature; | ||
| 28 | impl InternalChannel<ADC> for Temperature {} | ||
| 29 | impl super::sealed::InternalChannel<ADC> for Temperature { | ||
| 30 | fn channel(&self) -> u8 { | ||
| 31 | 16 | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | impl<'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}; | |||
| 9 | use super::*; | 9 | use super::*; |
| 10 | use crate::gpio::sealed::{AFType, Pin as _}; | 10 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 11 | use crate::gpio::{AnyPin, Speed}; | 11 | use crate::gpio::{AnyPin, Speed}; |
| 12 | use crate::pac::{ETH, RCC, SYSCFG}; | 12 | use crate::pac::ETH; |
| 13 | use crate::Peripheral; | 13 | use crate::Peripheral; |
| 14 | 14 | ||
| 15 | const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet | 15 | const 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)))] |
| 29 | fn exticr_regs() -> pac::syscfg::Syscfg { | 29 | fn 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))] |
| 33 | fn exticr_regs() -> pac::exti::Exti { | 33 | fn 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 | ||
| 41 | pub unsafe fn on_irq() { | 41 | pub 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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | ||
| 2 | use embassy_hal_common::drop::OnDrop; | ||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 4 | |||
| 5 | use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | ||
| 6 | use crate::flash::FlashBank; | ||
| 7 | use crate::Peripheral; | ||
| 8 | |||
| 9 | pub struct Flash<'d> { | ||
| 10 | inner: PeripheralRef<'d, crate::peripherals::FLASH>, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl<'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 | |||
| 41 | fn 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 | |||
| 52 | unsafe 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 | |||
| 85 | unsafe 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(§or) | ||
| 121 | })?; | ||
| 122 | address += sector.size; | ||
| 123 | } | ||
| 124 | Ok(()) | ||
| 125 | } | ||
| 126 | |||
| 127 | pub(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 | |||
| 152 | impl 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 | |||
| 166 | foreach_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 @@ | |||
| 1 | use core::convert::TryInto; | 1 | use core::convert::TryInto; |
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{fence, Ordering}; | ||
| 5 | |||
| 6 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 7 | use crate::flash::Error; |
| 5 | use crate::pac; | 8 | use crate::pac; |
| 6 | 9 | ||
| 10 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 11 | &FLASH_REGIONS | ||
| 12 | } | ||
| 13 | |||
| 7 | pub(crate) unsafe fn lock() { | 14 | pub(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 | ||
| 16 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 23 | pub(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 = { | 29 | pub(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(); | 33 | pub(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 | ||
| 39 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 46 | pub(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 | ||
| 85 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 89 | unsafe 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; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; | 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | const SECOND_BANK_SECTOR_START: u32 = 12; | 9 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 10 | mod alt_regions { | ||
| 11 | use embassy_hal_common::PeripheralRef; | ||
| 12 | use stm32_metapac::FLASH_SIZE; | ||
| 10 | 13 | ||
| 11 | unsafe 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))] | ||
| 93 | pub use alt_regions::{AltFlashLayout, ALT_FLASH_REGIONS}; | ||
| 94 | |||
| 95 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | ||
| 96 | pub 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)))] | ||
| 105 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 106 | &FLASH_REGIONS | ||
| 26 | } | 107 | } |
| 27 | 108 | ||
| 28 | pub(crate) unsafe fn lock() { | 109 | pub(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 | ||
| 37 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 118 | pub(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 | ||
| 68 | struct FlashSector { | 127 | pub(crate) unsafe fn end_write() { |
| 69 | index: u8, | 128 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 70 | size: u32, | ||
| 71 | } | ||
| 72 | |||
| 73 | fn 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 | ||
| 106 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 131 | pub(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 | ||
| 119 | unsafe fn erase_sector(sector: u8) -> Result<(), Error> { | 144 | pub(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 | ||
| 151 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 173 | unsafe 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)] | ||
| 200 | mod 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; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 5 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 6 | use crate::pac; | 7 | use crate::pac; |
| 7 | 8 | ||
| 9 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 10 | &FLASH_REGIONS | ||
| 11 | } | ||
| 12 | |||
| 8 | pub(crate) unsafe fn lock() { | 13 | pub(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 | ||
| 17 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 22 | pub(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 = { | 31 | pub(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 | ||
| 48 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 35 | pub(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 | ||
| 71 | unsafe fn erase_sector(sector: u8) -> Result<(), Error> { | 48 | pub(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 | ||
| 110 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 87 | unsafe 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)] | ||
| 114 | mod 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 @@ | |||
| 1 | use core::convert::TryInto; | 1 | use core::convert::TryInto; |
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{fence, Ordering}; | ||
| 5 | |||
| 6 | use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 7 | use crate::flash::Error; |
| 5 | use crate::pac; | 8 | use crate::pac; |
| 6 | 9 | ||
| 7 | const SECOND_BANK_OFFSET: usize = 0x0010_0000; | ||
| 8 | |||
| 9 | const fn is_dual_bank() -> bool { | 10 | const fn is_dual_bank() -> bool { |
| 10 | super::FLASH_SIZE / 2 > super::ERASE_SIZE | 11 | FLASH_REGIONS.len() == 2 |
| 12 | } | ||
| 13 | |||
| 14 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 15 | &FLASH_REGIONS | ||
| 11 | } | 16 | } |
| 12 | 17 | ||
| 13 | pub(crate) unsafe fn lock() { | 18 | pub(crate) unsafe fn lock() { |
| @@ -20,90 +25,64 @@ pub(crate) unsafe fn lock() { | |||
| 20 | pub(crate) unsafe fn unlock() { | 25 | pub(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 | ||
| 30 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 34 | pub(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 | |||
| 38 | pub(crate) unsafe fn end_write() {} | ||
| 39 | |||
| 40 | pub(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 | |||
| 78 | pub(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 | ||
| 103 | unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> { | 81 | pub(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 | ||
| 163 | pub(crate) unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { | 142 | unsafe 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 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | 2 | ||
| 3 | use atomic_polyfill::{fence, Ordering}; | ||
| 4 | |||
| 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 5 | use crate::pac; | 7 | use crate::pac; |
| 6 | 8 | ||
| 9 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 10 | &FLASH_REGIONS | ||
| 11 | } | ||
| 12 | |||
| 7 | pub(crate) unsafe fn lock() { | 13 | pub(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 | ||
| 36 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | 42 | pub(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 = { | 49 | pub(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 | ||
| 63 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | 54 | pub(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))] | 67 | pub(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 | ||
| 114 | pub(crate) unsafe fn clear_all_err() { | 113 | pub(crate) unsafe fn clear_all_err() { |
| @@ -149,7 +148,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 149 | }); | 148 | }); |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | 151 | unsafe 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 @@ | |||
| 1 | use embassy_hal_common::{into_ref, PeripheralRef}; | 1 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; |
| 2 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | ||
| 3 | 2 | ||
| 4 | pub use crate::pac::{ERASE_SIZE, ERASE_VALUE, FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | 3 | #[cfg(flash)] |
| 5 | use crate::peripherals::FLASH; | 4 | mod common; |
| 6 | use crate::Peripheral; | ||
| 7 | const 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")] | 7 | pub 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")] | ||
| 14 | mod family; | ||
| 15 | 8 | ||
| 16 | pub struct Flash<'d> { | 9 | pub use crate::_generated::flash_regions::*; |
| 17 | _inner: PeripheralRef<'d, FLASH>, | 10 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; |
| 18 | } | ||
| 19 | 11 | ||
| 20 | impl<'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); | 14 | pub 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; | 25 | pub 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))] | ||
| 34 | pub enum FlashBank { | ||
| 35 | Bank1 = 0, | ||
| 36 | Bank2 = 1, | ||
| 37 | Otp, | ||
| 38 | } | ||
| 68 | 39 | ||
| 69 | unsafe { | 40 | impl 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 | ||
| 82 | impl 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 | )] | ||
| 61 | mod family; | ||
| 62 | |||
| 63 | #[allow(unused_imports)] | ||
| 64 | pub 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 | ||
| 100 | impl<'d> ErrorType for Flash<'d> { | ||
| 101 | type Error = Error; | ||
| 102 | } | ||
| 103 | |||
| 104 | impl NorFlashError for Error { | 78 | impl 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 | |||
| 114 | impl<'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 | |||
| 126 | impl<'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 | |||
| 3 | use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 4 | |||
| 5 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 6 | &FLASH_REGIONS | ||
| 7 | } | ||
| 8 | |||
| 9 | pub(crate) unsafe fn lock() { | ||
| 10 | unimplemented!(); | ||
| 11 | } | ||
| 12 | pub(crate) unsafe fn unlock() { | ||
| 13 | unimplemented!(); | ||
| 14 | } | ||
| 15 | pub(crate) unsafe fn begin_write() { | ||
| 16 | unimplemented!(); | ||
| 17 | } | ||
| 18 | pub(crate) unsafe fn end_write() { | ||
| 19 | unimplemented!(); | ||
| 20 | } | ||
| 21 | pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 22 | unimplemented!(); | ||
| 23 | } | ||
| 24 | pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { | ||
| 25 | unimplemented!(); | ||
| 26 | } | ||
| 27 | pub(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 | ||
| 68 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> { | 68 | impl<'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 | ||
| 76 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> { | 76 | impl<'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 | ||
| 84 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> { | 84 | impl<'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 | ||
| 356 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | 356 | impl<'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 | ||
| 364 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { | 364 | impl<'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 | ||
| 372 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { | 372 | impl<'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)] |
| 45 | pub mod crc; | 45 | pub 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 | ))] | ||
| 49 | pub mod flash; | 46 | pub mod flash; |
| 50 | pub mod pwm; | 47 | pub mod pwm; |
| 51 | #[cfg(quadspi)] | 48 | #[cfg(quadspi)] |
| @@ -56,6 +53,8 @@ pub mod rng; | |||
| 56 | pub mod sdmmc; | 53 | pub mod sdmmc; |
| 57 | #[cfg(spi)] | 54 | #[cfg(spi)] |
| 58 | pub mod spi; | 55 | pub mod spi; |
| 56 | #[cfg(stm32wl)] | ||
| 57 | pub mod subghz; | ||
| 59 | #[cfg(usart)] | 58 | #[cfg(usart)] |
| 60 | pub mod usart; | 59 | pub 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)] |
| 66 | pub mod wdg; | 65 | pub mod wdg; |
| 67 | 66 | ||
| 68 | #[cfg(feature = "subghz")] | ||
| 69 | pub 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. |
| 72 | pub(crate) mod _generated { | 68 | pub(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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 4 | pub use stm32_metapac::timer::vals::Ckd; | ||
| 5 | |||
| 6 | use super::simple_pwm::*; | ||
| 7 | use super::*; | ||
| 8 | #[allow(unused_imports)] | ||
| 9 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 10 | use crate::gpio::AnyPin; | ||
| 11 | use crate::time::Hertz; | ||
| 12 | use crate::Peripheral; | ||
| 13 | |||
| 14 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | ||
| 15 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 16 | phantom: PhantomData<(Perip, Channel)>, | ||
| 17 | } | ||
| 18 | |||
| 19 | macro_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 | |||
| 39 | complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); | ||
| 40 | complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); | ||
| 41 | complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); | ||
| 42 | complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); | ||
| 43 | |||
| 44 | pub struct ComplementaryPwm<'d, T> { | ||
| 45 | inner: PeripheralRef<'d, T>, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'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 @@ | |||
| 1 | pub mod complementary_pwm; | ||
| 1 | pub mod simple_pwm; | 2 | pub mod simple_pwm; |
| 2 | 3 | ||
| 4 | use stm32_metapac::timer::vals::Ckd; | ||
| 5 | |||
| 3 | #[cfg(feature = "unstable-pac")] | 6 | #[cfg(feature = "unstable-pac")] |
| 4 | pub mod low_level { | 7 | pub 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 | |||
| 97 | pub trait ComplementaryCaptureCompare16bitInstance: | ||
| 98 | sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static | ||
| 99 | { | ||
| 100 | } | ||
| 101 | |||
| 85 | pub trait CaptureCompare32bitInstance: | 102 | pub 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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use stm32_metapac::rcc::vals::{Hpre, Ppre, Timpre}; | ||
| 4 | |||
| 5 | use crate::pac::pwr::vals::Vos; | ||
| 6 | use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; | ||
| 7 | use crate::pac::{FLASH, PWR, RCC}; | ||
| 8 | use crate::rcc::{set_freqs, Clocks}; | ||
| 9 | use crate::time::Hertz; | ||
| 10 | use crate::{peripherals, Peripheral}; | ||
| 11 | |||
| 12 | /// HSI speed | ||
| 13 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 14 | |||
| 15 | /// CSI speed | ||
| 16 | pub const CSI_FREQ: Hertz = Hertz(4_000_000); | ||
| 17 | |||
| 18 | /// HSI48 speed | ||
| 19 | pub const HSI48_FREQ: Hertz = Hertz(48_000_000); | ||
| 20 | |||
| 21 | /// LSI speed | ||
| 22 | pub const LSI_FREQ: Hertz = Hertz(32_000); | ||
| 23 | |||
| 24 | const VCO_MIN: u32 = 150_000_000; | ||
| 25 | const VCO_MAX: u32 = 420_000_000; | ||
| 26 | const VCO_WIDE_MIN: u32 = 128_000_000; | ||
| 27 | const 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)] | ||
| 34 | pub 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 | |||
| 45 | pub 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 | |||
| 54 | pub struct Hse { | ||
| 55 | /// HSE frequency. | ||
| 56 | pub freq: Hertz, | ||
| 57 | /// HSE mode. | ||
| 58 | pub mode: HseMode, | ||
| 59 | } | ||
| 60 | |||
| 61 | pub 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 | |||
| 72 | pub 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 | |||
| 83 | pub enum PllSource { | ||
| 84 | Hsi, | ||
| 85 | Csi, | ||
| 86 | Hse, | ||
| 87 | } | ||
| 88 | |||
| 89 | pub 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)] | ||
| 110 | pub enum AHBPrescaler { | ||
| 111 | NotDivided, | ||
| 112 | Div2, | ||
| 113 | Div4, | ||
| 114 | Div8, | ||
| 115 | Div16, | ||
| 116 | Div64, | ||
| 117 | Div128, | ||
| 118 | Div256, | ||
| 119 | Div512, | ||
| 120 | } | ||
| 121 | |||
| 122 | impl 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)] | ||
| 140 | pub enum APBPrescaler { | ||
| 141 | NotDivided, | ||
| 142 | Div2, | ||
| 143 | Div4, | ||
| 144 | Div8, | ||
| 145 | Div16, | ||
| 146 | } | ||
| 147 | |||
| 148 | impl 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)] | ||
| 182 | pub enum TimerPrescaler { | ||
| 183 | DefaultX2, | ||
| 184 | DefaultX4, | ||
| 185 | } | ||
| 186 | |||
| 187 | impl 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 | |||
| 196 | impl 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 | |||
| 208 | impl 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] | ||
| 226 | pub 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 | |||
| 247 | impl 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 | |||
| 271 | pub(crate) mod sealed { | ||
| 272 | pub trait McoInstance { | ||
| 273 | type Source; | ||
| 274 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 279 | |||
| 280 | pin_trait!(McoPin, McoInstance); | ||
| 281 | |||
| 282 | macro_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 | |||
| 299 | impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); | ||
| 300 | impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); | ||
| 301 | |||
| 302 | pub struct Mco<'d, T: McoInstance> { | ||
| 303 | phantom: PhantomData<&'d mut T>, | ||
| 304 | } | ||
| 305 | |||
| 306 | impl<'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 | |||
| 316 | pub(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 | |||
| 451 | struct PllInput { | ||
| 452 | hsi: Option<Hertz>, | ||
| 453 | hse: Option<Hertz>, | ||
| 454 | csi: Option<Hertz>, | ||
| 455 | } | ||
| 456 | |||
| 457 | struct PllOutput { | ||
| 458 | p: Option<Hertz>, | ||
| 459 | #[allow(dead_code)] | ||
| 460 | q: Option<Hertz>, | ||
| 461 | #[allow(dead_code)] | ||
| 462 | r: Option<Hertz>, | ||
| 463 | } | ||
| 464 | |||
| 465 | unsafe 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 | |||
| 554 | fn 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")] | ||
| 24 | mod _version; | 25 | mod _version; |
| 25 | pub use _version::*; | 26 | pub 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)))] |
| 623 | use vals::Br; | 623 | use vals::Br; |
| 624 | #[cfg(any(spi_v3, spi_v4))] | 624 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 625 | use vals::Mbr as Br; | 625 | use vals::Mbr as Br; |
| 626 | 626 | ||
| 627 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { | 627 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { |
| @@ -647,17 +647,17 @@ trait RegsExt { | |||
| 647 | 647 | ||
| 648 | impl RegsExt for Regs { | 648 | impl 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 | ||
| 727 | fn flush_rx_fifo(regs: Regs) { | 727 | fn 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 | ||
| 740 | fn set_txdmaen(regs: Regs, val: bool) { | 740 | fn 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 | ||
| 753 | fn set_rxdmaen(regs: Regs, val: bool) { | 753 | fn 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 | ||
| 3 | use 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))] |
| 6 | pub struct Hertz(pub u32); | 8 | pub struct Hertz(pub u32); |
| 7 | 9 | ||
| @@ -33,3 +35,45 @@ pub fn khz(kilohertz: u32) -> Hertz { | |||
| 33 | pub fn mhz(megahertz: u32) -> Hertz { | 35 | pub fn mhz(megahertz: u32) -> Hertz { |
| 34 | Hertz::mhz(megahertz) | 36 | Hertz::mhz(megahertz) |
| 35 | } | 37 | } |
| 38 | |||
| 39 | impl Mul<u32> for Hertz { | ||
| 40 | type Output = Hertz; | ||
| 41 | fn mul(self, rhs: u32) -> Self::Output { | ||
| 42 | Hertz(self.0 * rhs) | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Div<u32> for Hertz { | ||
| 47 | type Output = Hertz; | ||
| 48 | fn div(self, rhs: u32) -> Self::Output { | ||
| 49 | Hertz(self.0 / rhs) | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | impl Mul<u16> for Hertz { | ||
| 54 | type Output = Hertz; | ||
| 55 | fn mul(self, rhs: u16) -> Self::Output { | ||
| 56 | self * (rhs as u32) | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | impl Div<u16> for Hertz { | ||
| 61 | type Output = Hertz; | ||
| 62 | fn div(self, rhs: u16) -> Self::Output { | ||
| 63 | self / (rhs as u32) | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | impl Mul<u8> for Hertz { | ||
| 68 | type Output = Hertz; | ||
| 69 | fn mul(self, rhs: u8) -> Self::Output { | ||
| 70 | self * (rhs as u32) | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl 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; | |||
| 12 | use embassy_usb_driver::{ | 12 | use embassy_usb_driver::{ |
| 13 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | 13 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, |
| 14 | }; | 14 | }; |
| 15 | use pac::common::{Reg, RW}; | ||
| 16 | use pac::usb::vals::{EpType, Stat}; | ||
| 17 | 15 | ||
| 18 | use super::{DmPin, DpPin, Instance}; | 16 | use super::{DmPin, DpPin, Instance}; |
| 19 | use crate::gpio::sealed::AFType; | 17 | use crate::gpio::sealed::AFType; |
| 20 | use crate::interrupt::InterruptExt; | 18 | use crate::interrupt::InterruptExt; |
| 21 | use crate::pac::usb::regs; | 19 | use crate::pac::usb::regs; |
| 20 | use crate::pac::usb::vals::{EpType, Stat}; | ||
| 21 | use crate::pac::USBRAM; | ||
| 22 | use crate::rcc::sealed::RccPeripheral; | 22 | use crate::rcc::sealed::RccPeripheral; |
| 23 | use crate::{pac, Peripheral}; | 23 | use crate::Peripheral; |
| 24 | 24 | ||
| 25 | const EP_COUNT: usize = 8; | 25 | const EP_COUNT: usize = 8; |
| 26 | 26 | ||
| 27 | #[cfg(any(usb_v1_x1, usb_v1_x2))] | 27 | #[cfg(any(usbram_16x1_512, usbram_16x2_512))] |
| 28 | const EP_MEMORY_SIZE: usize = 512; | 28 | const USBRAM_SIZE: usize = 512; |
| 29 | #[cfg(not(any(usb_v1_x1, usb_v1_x2)))] | 29 | #[cfg(usbram_16x2_1024)] |
| 30 | const EP_MEMORY_SIZE: usize = 1024; | 30 | const USBRAM_SIZE: usize = 1024; |
| 31 | #[cfg(usbram_32_2048)] | ||
| 32 | const USBRAM_SIZE: usize = 2048; | ||
| 33 | |||
| 34 | #[cfg(not(usbram_32_2048))] | ||
| 35 | const USBRAM_ALIGN: usize = 2; | ||
| 36 | #[cfg(usbram_32_2048)] | ||
| 37 | const USBRAM_ALIGN: usize = 4; | ||
| 31 | 38 | ||
| 32 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 39 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 33 | static BUS_WAKER: AtomicWaker = NEW_AW; | 40 | static 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 | ||
| 67 | fn 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) |
| 61 | fn calc_out_len(len: u16) -> (u16, u16) { | 72 | fn 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 | } |
| 68 | fn 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 | } | 82 | mod btable { |
| 71 | fn 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) { |
| 74 | fn 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 | } |
| 77 | fn ep_out_len<T: Instance>(index: usize) -> Reg<u16, RW> { | 102 | #[cfg(usbram_32_2048)] |
| 78 | T::regs().ep_mem(index * 4 + 3) | 103 | mod 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 | ||
| 81 | struct EndpointBuffer<T: Instance> { | 123 | struct EndpointBuffer<T: Instance> { |
| @@ -87,23 +129,25 @@ struct EndpointBuffer<T: Instance> { | |||
| 87 | impl<T: Instance> EndpointBuffer<T> { | 129 | impl<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 } | |||
| 152 | log = { version = "0.4.14", optional = true } | 152 | log = { version = "0.4.14", optional = true } |
| 153 | 153 | ||
| 154 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } | 154 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } |
| 155 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 155 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
| 156 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} | 156 | embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} |
| 157 | 157 | ||
| 158 | futures-util = { version = "0.3.17", default-features = false } | 158 | futures-util = { version = "0.3.17", default-features = false } |
| 159 | embassy-sync = { version = "0.1", path = "../embassy-sync" } | 159 | embassy-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")] |
| 6 | use defmt_rtt as _; | 6 | use defmt_rtt as _; |
| 7 | use embassy_boot_stm32::*; | 7 | use embassy_boot_stm32::*; |
| 8 | use embassy_stm32::flash::{Flash, ERASE_SIZE}; | 8 | use embassy_stm32::flash::Flash; |
| 9 | 9 | ||
| 10 | #[entry] | 10 | #[entry] |
| 11 | fn main() -> ! { | 11 | fn 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"))'] |
| 2 | runner = "probe-run --chip RP2040" | 2 | runner = "probe-rs-cli run --chip RP2040" |
| 3 | 3 | ||
| 4 | [build] | 4 | [build] |
| 5 | target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ | 5 | target = "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] |
| 9 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | ||
| 9 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 11 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| @@ -30,8 +31,8 @@ display-interface = "0.4.1" | |||
| 30 | byte-slice-cast = { version = "1.2.0", default-features = false } | 31 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 31 | smart-leds = "0.3.0" | 32 | smart-leds = "0.3.0" |
| 32 | 33 | ||
| 33 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 34 | embedded-hal-async = "0.2.0-alpha.0" | 35 | embedded-hal-async = "0.2.0-alpha.1" |
| 35 | embedded-io = { version = "0.4.0", features = ["async", "defmt"] } | 36 | embedded-io = { version = "0.4.0", features = ["async", "defmt"] } |
| 36 | embedded-storage = { version = "0.3" } | 37 | embedded-storage = { version = "0.3" } |
| 37 | static_cell = "1.0.0" | 38 | static_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 @@ | |||
| 5 | use core::cell::RefCell; | 5 | use core::cell::RefCell; |
| 6 | 6 | ||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; | ||
| 8 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 9 | use embassy_rp::gpio::{Level, Output}; | 10 | use embassy_rp::gpio::{Level, Output}; |
| 10 | use embassy_rp::spi; | 11 | use embassy_rp::spi; |
| 11 | use embassy_rp::spi::{Blocking, Spi}; | 12 | use embassy_rp::spi::{Blocking, Spi}; |
| 13 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 14 | use embassy_sync::blocking_mutex::Mutex; | ||
| 12 | use embassy_time::Delay; | 15 | use embassy_time::Delay; |
| 13 | use embedded_graphics::image::{Image, ImageRawLE}; | 16 | use embedded_graphics::image::{Image, ImageRawLE}; |
| 14 | use embedded_graphics::mono_font::ascii::FONT_10X20; | 17 | use embedded_graphics::mono_font::ascii::FONT_10X20; |
| @@ -21,10 +24,9 @@ use st7789::{Orientation, ST7789}; | |||
| 21 | use {defmt_rtt as _, panic_probe as _}; | 24 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 25 | ||
| 23 | use crate::my_display_interface::SPIDeviceInterface; | 26 | use crate::my_display_interface::SPIDeviceInterface; |
| 24 | use crate::shared_spi::SpiDeviceWithCs; | ||
| 25 | use crate::touch::Touch; | 27 | use crate::touch::Touch; |
| 26 | 28 | ||
| 27 | //const DISPLAY_FREQ: u32 = 64_000_000; | 29 | const DISPLAY_FREQ: u32 = 64_000_000; |
| 28 | const TOUCH_FREQ: u32 = 200_000; | 30 | const 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 | ||
| 107 | mod 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 |
| 184 | mod touch { | 114 | mod 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 { | |||
| 247 | mod my_display_interface { | 175 | mod 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 8 | use embassy_time::{Delay, Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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" | |||
| 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-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 @@ | |||
| 5 | use defmt::{info, unwrap}; | 5 | use defmt::{info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::flash::Flash; | 7 | use embassy_stm32::flash::Flash; |
| 8 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; | ||
| 8 | use embassy_stm32::pwm::simple_pwm::PwmPin; | ||
| 9 | use embassy_stm32::pwm::Channel; | ||
| 10 | use embassy_stm32::time::khz; | ||
| 11 | use embassy_time::{Duration, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async 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] | ||
| 2 | runner = 'probe-rs-cli run --chip STM32H563ZITx' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv8m.main-none-eabihf" | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h7-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | ||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | ||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } | ||
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } | ||
| 13 | embedded-io = { version = "0.4.0", features = ["async"] } | ||
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 15 | |||
| 16 | defmt = "0.3" | ||
| 17 | defmt-rtt = "0.4" | ||
| 18 | |||
| 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 20 | cortex-m-rt = "0.7.0" | ||
| 21 | embedded-hal = "0.2.6" | ||
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } | ||
| 23 | embedded-hal-async = { version = "=0.2.0-alpha.1" } | ||
| 24 | embedded-nal-async = "0.4.0" | ||
| 25 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 27 | heapless = { version = "0.7.5", default-features = false } | ||
| 28 | rand_core = "0.6.3" | ||
| 29 | critical-section = "1.1" | ||
| 30 | micromath = "2.0.0" | ||
| 31 | stm32-fmc = "0.2.4" | ||
| 32 | embedded-storage = "0.3.0" | ||
| 33 | static_cell = "1.0" | ||
| 34 | |||
| 35 | # cargo build/run | ||
| 36 | [profile.dev] | ||
| 37 | codegen-units = 1 | ||
| 38 | debug = 2 | ||
| 39 | debug-assertions = true # <- | ||
| 40 | incremental = false | ||
| 41 | opt-level = 3 # <- | ||
| 42 | overflow-checks = true # <- | ||
| 43 | |||
| 44 | # cargo test | ||
| 45 | [profile.test] | ||
| 46 | codegen-units = 1 | ||
| 47 | debug = 2 | ||
| 48 | debug-assertions = true # <- | ||
| 49 | incremental = false | ||
| 50 | opt-level = 3 # <- | ||
| 51 | overflow-checks = true # <- | ||
| 52 | |||
| 53 | # cargo build/run --release | ||
| 54 | [profile.release] | ||
| 55 | codegen-units = 1 | ||
| 56 | debug = 2 | ||
| 57 | debug-assertions = false # <- | ||
| 58 | incremental = false | ||
| 59 | lto = 'fat' | ||
| 60 | opt-level = 3 # <- | ||
| 61 | overflow-checks = false # <- | ||
| 62 | |||
| 63 | # cargo test --release | ||
| 64 | [profile.bench] | ||
| 65 | codegen-units = 1 | ||
| 66 | debug = 2 | ||
| 67 | debug-assertions = false # <- | ||
| 68 | incremental = false | ||
| 69 | lto = 'fat' | ||
| 70 | opt-level = 3 # <- | ||
| 71 | overflow-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 @@ | |||
| 1 | fn 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 8 | use embassy_time::{Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::exti::ExtiInput; | ||
| 8 | use embassy_stm32::gpio::{Input, Pull}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_net::tcp::TcpSocket; | ||
| 8 | use embassy_net::{Ipv4Address, Stack, StackResources}; | ||
| 9 | use embassy_stm32::eth::generic_smi::GenericSMI; | ||
| 10 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | ||
| 11 | use embassy_stm32::peripherals::ETH; | ||
| 12 | use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; | ||
| 13 | use embassy_stm32::rng::Rng; | ||
| 14 | use embassy_stm32::time::Hertz; | ||
| 15 | use embassy_stm32::{interrupt, Config}; | ||
| 16 | use embassy_time::{Duration, Timer}; | ||
| 17 | use embedded_io::asynch::Write; | ||
| 18 | use rand_core::RngCore; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | macro_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 | |||
| 31 | type Device = Ethernet<'static, ETH, GenericSMI>; | ||
| 32 | |||
| 33 | #[embassy_executor::task] | ||
| 34 | async fn net_task(stack: &'static Stack<Device>) -> ! { | ||
| 35 | stack.run().await | ||
| 36 | } | ||
| 37 | |||
| 38 | #[embassy_executor::main] | ||
| 39 | async 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_time::Duration; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | const ADDRESS: u8 = 0x5F; | ||
| 14 | const WHOAMI: u8 = 0x0F; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rng::Rng; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async 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 | |||
| 5 | use cortex_m_rt::entry; | ||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Executor; | ||
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | ||
| 11 | use static_cell::StaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::task] | ||
| 15 | async 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 | |||
| 32 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 33 | |||
| 34 | #[entry] | ||
| 35 | fn 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 | |||
| 5 | use core::fmt::Write; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::dma::NoDma; | ||
| 11 | use embassy_stm32::interrupt; | ||
| 12 | use embassy_stm32::usart::{Config, Uart}; | ||
| 13 | use heapless::String; | ||
| 14 | use static_cell::StaticCell; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async 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 | |||
| 35 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 36 | |||
| 37 | #[entry] | ||
| 38 | fn 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; | ||
| 10 | use embassy_stm32::usart::{Config, Uart, UartRx}; | ||
| 11 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 12 | use embassy_sync::channel::Channel; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async 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 | |||
| 27 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | ||
| 28 | |||
| 29 | #[embassy_executor::main] | ||
| 30 | async 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] | ||
| 51 | async 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 | |||
| 5 | use defmt::{panic, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; | ||
| 8 | use embassy_stm32::time::Hertz; | ||
| 9 | use embassy_stm32::usb::{Driver, Instance}; | ||
| 10 | use embassy_stm32::{interrupt, pac, Config}; | ||
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 12 | use embassy_usb::driver::EndpointError; | ||
| 13 | use embassy_usb::Builder; | ||
| 14 | use futures::future::join; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async 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 | |||
| 109 | struct Disconnected {} | ||
| 110 | |||
| 111 | impl 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 | |||
| 120 | async 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" | |||
| 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 23 | embedded-hal-async = { version = "=0.2.0-alpha.0" } | 23 | embedded-hal-async = { version = "=0.2.0-alpha.1" } |
| 24 | embedded-nal-async = "0.4.0" | 24 | embedded-nal-async = "0.4.0" |
| 25 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 25 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 26 | futures = { 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" | |||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 20 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 22 | embedded-hal-async = { version = "=0.2.0-alpha.0" } | 22 | embedded-hal-async = { version = "=0.2.0-alpha.1" } |
| 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 25 | heapless = { version = "0.7.5", default-features = false } | 25 | heapless = { 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" | |||
| 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } |
| 12 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } | 12 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } |
| 13 | 13 | ||
| 14 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"] } | 14 | lorawan-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" | |||
| 17 | cortex-m = { version = "0.7.6" } | 17 | cortex-m = { version = "0.7.6" } |
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 21 | embedded-hal-async = { version = "=0.2.0-alpha.0" } | 21 | embedded-hal-async = { version = "=0.2.0-alpha.1" } |
| 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 24 | embedded-io = { version = "0.4.0", features = ["async"] } | 24 | embedded-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 | |||
| 11 | stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo | 11 | stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo |
| 12 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo | 12 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo |
| 13 | stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo | 13 | stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo |
| 14 | stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo | ||
| 14 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board | 15 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board |
| 15 | 16 | ||
| 16 | [dependencies] | 17 | [dependencies] |
| @@ -25,8 +26,8 @@ defmt-rtt = "0.4" | |||
| 25 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 26 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 26 | cortex-m-rt = "0.7.0" | 27 | cortex-m-rt = "0.7.0" |
| 27 | embedded-hal = "0.2.6" | 28 | embedded-hal = "0.2.6" |
| 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 29 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } |
| 29 | embedded-hal-async = { version = "=0.2.0-alpha.0" } | 30 | embedded-hal-async = { version = "=0.2.0-alpha.1" } |
| 30 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 31 | panic-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); |
