diff options
229 files changed, 8571 insertions, 4158 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 46d26562c..0c195a13b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "editor.formatOnSave": true, | ||
| 3 | "[toml]": { | 2 | "[toml]": { |
| 4 | "editor.formatOnSave": false | 3 | "editor.formatOnSave": false |
| 5 | }, | 4 | }, |
| @@ -124,6 +124,7 @@ cargo batch \ | |||
| 124 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ | 124 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ |
| 125 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ | 125 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ |
| 126 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ | 126 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ |
| 127 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \ | ||
| 127 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ | 128 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ |
| 128 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ | 129 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ |
| 129 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ | 130 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ |
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/cyw43/src/fmt.rs +++ b/cyw43/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-boot-nrf/src/fmt.rs b/embassy-boot-nrf/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-nrf/src/fmt.rs +++ b/embassy-boot-nrf/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-boot-rp/src/fmt.rs b/embassy-boot-rp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-rp/src/fmt.rs +++ b/embassy-boot-rp/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-boot-stm32/src/fmt.rs b/embassy-boot-stm32/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot-stm32/src/fmt.rs +++ b/embassy-boot-stm32/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index ca1a1b10c..a38558056 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs | |||
| @@ -183,29 +183,29 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S | |||
| 183 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | | 183 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 184 | /// |-----------|------------|--------|--------|--------|--------| | 184 | /// |-----------|------------|--------|--------|--------|--------| |
| 185 | /// | Active | 0 | 1 | 2 | 3 | - | | 185 | /// | Active | 0 | 1 | 2 | 3 | - | |
| 186 | /// | DFU | 0 | 3 | 2 | 1 | X | | 186 | /// | DFU | 0 | 4 | 5 | 6 | X | |
| 187 | /// | 187 | /// |
| 188 | /// The algorithm starts by copying 'backwards', and after the first step, the layout is | 188 | /// The algorithm starts by copying 'backwards', and after the first step, the layout is |
| 189 | /// as follows: | 189 | /// as follows: |
| 190 | /// | 190 | /// |
| 191 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | | 191 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 192 | /// |-----------|------------|--------|--------|--------|--------| | 192 | /// |-----------|------------|--------|--------|--------|--------| |
| 193 | /// | Active | 1 | 1 | 2 | 1 | - | | 193 | /// | Active | 1 | 1 | 2 | 6 | - | |
| 194 | /// | DFU | 1 | 3 | 2 | 1 | 3 | | 194 | /// | DFU | 1 | 4 | 5 | 6 | 3 | |
| 195 | /// | 195 | /// |
| 196 | /// The next iteration performs the same steps | 196 | /// The next iteration performs the same steps |
| 197 | /// | 197 | /// |
| 198 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | | 198 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 199 | /// |-----------|------------|--------|--------|--------|--------| | 199 | /// |-----------|------------|--------|--------|--------|--------| |
| 200 | /// | Active | 2 | 1 | 2 | 1 | - | | 200 | /// | Active | 2 | 1 | 5 | 6 | - | |
| 201 | /// | DFU | 2 | 3 | 2 | 2 | 3 | | 201 | /// | DFU | 2 | 4 | 5 | 2 | 3 | |
| 202 | /// | 202 | /// |
| 203 | /// And again until we're done | 203 | /// And again until we're done |
| 204 | /// | 204 | /// |
| 205 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | | 205 | /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 206 | /// |-----------|------------|--------|--------|--------|--------| | 206 | /// |-----------|------------|--------|--------|--------|--------| |
| 207 | /// | Active | 3 | 3 | 2 | 1 | - | | 207 | /// | Active | 3 | 4 | 5 | 6 | - | |
| 208 | /// | DFU | 3 | 3 | 1 | 2 | 3 | | 208 | /// | DFU | 3 | 4 | 1 | 2 | 3 | |
| 209 | /// | 209 | /// |
| 210 | /// ## REVERTING | 210 | /// ## REVERTING |
| 211 | /// | 211 | /// |
| @@ -220,19 +220,19 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S | |||
| 220 | /// | 220 | /// |
| 221 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | | 221 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 222 | /// |-----------|--------------|--------|--------|--------|--------| | 222 | /// |-----------|--------------|--------|--------|--------|--------| |
| 223 | /// | Active | 3 | 1 | 2 | 1 | - | | 223 | /// | Active | 3 | 1 | 5 | 6 | - | |
| 224 | /// | DFU | 3 | 3 | 1 | 2 | 3 | | 224 | /// | DFU | 3 | 4 | 1 | 2 | 3 | |
| 225 | /// | 225 | /// |
| 226 | /// | 226 | /// |
| 227 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | | 227 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 228 | /// |-----------|--------------|--------|--------|--------|--------| | 228 | /// |-----------|--------------|--------|--------|--------|--------| |
| 229 | /// | Active | 3 | 1 | 2 | 1 | - | | 229 | /// | Active | 3 | 1 | 2 | 6 | - | |
| 230 | /// | DFU | 3 | 3 | 2 | 2 | 3 | | 230 | /// | DFU | 3 | 4 | 5 | 2 | 3 | |
| 231 | /// | 231 | /// |
| 232 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | | 232 | /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | |
| 233 | /// |-----------|--------------|--------|--------|--------|--------| | 233 | /// |-----------|--------------|--------|--------|--------|--------| |
| 234 | /// | Active | 3 | 1 | 2 | 3 | - | | 234 | /// | Active | 3 | 1 | 2 | 3 | - | |
| 235 | /// | DFU | 3 | 3 | 2 | 1 | 3 | | 235 | /// | DFU | 3 | 4 | 5 | 6 | 3 | |
| 236 | /// | 236 | /// |
| 237 | pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> { | 237 | pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> { |
| 238 | // Ensure we have enough progress pages to store copy progress | 238 | // Ensure we have enough progress pages to store copy progress |
diff --git a/embassy-boot/src/fmt.rs b/embassy-boot/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-boot/src/fmt.rs +++ b/embassy-boot/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs index ae0d0a7f9..bafc31583 100644 --- a/embassy-embedded-hal/src/adapter/blocking_async.rs +++ b/embassy-embedded-hal/src/adapter/blocking_async.rs | |||
| @@ -104,8 +104,10 @@ where | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | /// NOR flash wrapper | 106 | /// NOR flash wrapper |
| 107 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; | 107 | use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, ReadNorFlash}; |
| 108 | use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; | 108 | use embedded_storage_async::nor_flash::{ |
| 109 | MultiwriteNorFlash as AsyncMultiwriteNorFlash, NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash, | ||
| 110 | }; | ||
| 109 | 111 | ||
| 110 | impl<T> ErrorType for BlockingAsync<T> | 112 | impl<T> ErrorType for BlockingAsync<T> |
| 111 | where | 113 | where |
| @@ -143,3 +145,5 @@ where | |||
| 143 | self.wrapped.capacity() | 145 | self.wrapped.capacity() |
| 144 | } | 146 | } |
| 145 | } | 147 | } |
| 148 | |||
| 149 | impl<T> AsyncMultiwriteNorFlash for BlockingAsync<T> where T: MultiwriteNorFlash {} | ||
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index 779c04263..71ce09def 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | |||
| @@ -106,6 +106,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { | |||
| 106 | pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self { | 106 | pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self { |
| 107 | Self { bus, config } | 107 | Self { bus, config } |
| 108 | } | 108 | } |
| 109 | |||
| 110 | /// Change the device's config at runtime | ||
| 111 | pub fn set_config(&mut self, config: BUS::Config) { | ||
| 112 | self.config = config; | ||
| 113 | } | ||
| 109 | } | 114 | } |
| 110 | 115 | ||
| 111 | impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS> | 116 | impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS> |
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 62b2c92a0..9890f218d 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs | |||
| @@ -122,6 +122,11 @@ impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> { | |||
| 122 | pub fn new(bus: &'a Mutex<M, BUS>, cs: CS, config: BUS::Config) -> Self { | 122 | pub fn new(bus: &'a Mutex<M, BUS>, cs: CS, config: BUS::Config) -> Self { |
| 123 | Self { bus, cs, config } | 123 | Self { bus, cs, config } |
| 124 | } | 124 | } |
| 125 | |||
| 126 | /// Change the device's config at runtime | ||
| 127 | pub fn set_config(&mut self, config: BUS::Config) { | ||
| 128 | self.config = config; | ||
| 129 | } | ||
| 125 | } | 130 | } |
| 126 | 131 | ||
| 127 | impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> | 132 | impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> |
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 233c9e1fd..627767c8a 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs | |||
| @@ -67,9 +67,11 @@ where | |||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { | 69 | fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { |
| 70 | let _ = address; | 70 | self.bus.lock(|bus| { |
| 71 | let _ = operations; | 71 | bus.borrow_mut() |
| 72 | todo!() | 72 | .transaction(address, operations) |
| 73 | .map_err(I2cDeviceError::I2c) | ||
| 74 | }) | ||
| 73 | } | 75 | } |
| 74 | } | 76 | } |
| 75 | 77 | ||
| @@ -130,6 +132,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { | |||
| 130 | pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, config: BUS::Config) -> Self { | 132 | pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, config: BUS::Config) -> Self { |
| 131 | Self { bus, config } | 133 | Self { bus, config } |
| 132 | } | 134 | } |
| 135 | |||
| 136 | /// Change the device's config at runtime | ||
| 137 | pub fn set_config(&mut self, config: BUS::Config) { | ||
| 138 | self.config = config; | ||
| 139 | } | ||
| 133 | } | 140 | } |
| 134 | 141 | ||
| 135 | impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> | 142 | impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> |
| @@ -171,8 +178,10 @@ where | |||
| 171 | } | 178 | } |
| 172 | 179 | ||
| 173 | fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { | 180 | fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { |
| 174 | let _ = address; | 181 | self.bus.lock(|bus| { |
| 175 | let _ = operations; | 182 | let mut bus = bus.borrow_mut(); |
| 176 | todo!() | 183 | bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?; |
| 184 | bus.transaction(address, operations).map_err(I2cDeviceError::I2c) | ||
| 185 | }) | ||
| 177 | } | 186 | } |
| 178 | } | 187 | } |
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index 59b65bfbd..801899f9f 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs | |||
| @@ -147,6 +147,11 @@ impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> { | |||
| 147 | pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS, config: BUS::Config) -> Self { | 147 | pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS, config: BUS::Config) -> Self { |
| 148 | Self { bus, cs, config } | 148 | Self { bus, cs, config } |
| 149 | } | 149 | } |
| 150 | |||
| 151 | /// Change the device's config at runtime | ||
| 152 | pub fn set_config(&mut self, config: BUS::Config) { | ||
| 153 | self.config = config; | ||
| 154 | } | ||
| 150 | } | 155 | } |
| 151 | 156 | ||
| 152 | impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> | 157 | impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> |
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 1efb2788b..96c6267b2 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs | |||
| @@ -93,10 +93,21 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre | |||
| 93 | #[cfg(feature = "nightly")] | 93 | #[cfg(feature = "nightly")] |
| 94 | let mut task_outer: ItemFn = parse_quote! { | 94 | let mut task_outer: ItemFn = parse_quote! { |
| 95 | #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> { | 95 | #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> { |
| 96 | type Fut = impl ::core::future::Future + 'static; | 96 | trait _EmbassyInternalTaskTrait { |
| 97 | type Fut: ::core::future::Future + 'static; | ||
| 98 | fn construct(#fargs) -> Self::Fut; | ||
| 99 | } | ||
| 100 | |||
| 101 | impl _EmbassyInternalTaskTrait for () { | ||
| 102 | type Fut = impl core::future::Future + 'static; | ||
| 103 | fn construct(#fargs) -> Self::Fut { | ||
| 104 | #task_inner_ident(#(#full_args,)*) | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 97 | const POOL_SIZE: usize = #pool_size; | 108 | const POOL_SIZE: usize = #pool_size; |
| 98 | static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); | 109 | static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); |
| 99 | unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } | 110 | unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } |
| 100 | } | 111 | } |
| 101 | }; | 112 | }; |
| 102 | #[cfg(not(feature = "nightly"))] | 113 | #[cfg(not(feature = "nightly"))] |
diff --git a/embassy-executor-macros/src/util/ctxt.rs b/embassy-executor-macros/src/util/ctxt.rs index 74c872c3c..9c78cda01 100644 --- a/embassy-executor-macros/src/util/ctxt.rs +++ b/embassy-executor-macros/src/util/ctxt.rs | |||
| @@ -7,7 +7,6 @@ use std::thread; | |||
| 7 | 7 | ||
| 8 | use proc_macro2::TokenStream; | 8 | use proc_macro2::TokenStream; |
| 9 | use quote::{quote, ToTokens}; | 9 | use quote::{quote, ToTokens}; |
| 10 | use syn; | ||
| 11 | 10 | ||
| 12 | /// A type to collect errors together and format them. | 11 | /// A type to collect errors together and format them. |
| 13 | /// | 12 | /// |
diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-executor/src/fmt.rs +++ b/embassy-executor/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3d5e3ab9f..d9ea5c005 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -30,7 +30,7 @@ use core::ptr::NonNull; | |||
| 30 | use core::task::{Context, Poll}; | 30 | use core::task::{Context, Poll}; |
| 31 | 31 | ||
| 32 | #[cfg(feature = "integrated-timers")] | 32 | #[cfg(feature = "integrated-timers")] |
| 33 | use embassy_time_driver::{self, AlarmHandle}; | 33 | use embassy_time_driver::AlarmHandle; |
| 34 | #[cfg(feature = "rtos-trace")] | 34 | #[cfg(feature = "rtos-trace")] |
| 35 | use rtos_trace::trace; | 35 | use rtos_trace::trace; |
| 36 | 36 | ||
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 2c2441dd5..348cc7dc4 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] | 1 | #![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] |
| 2 | 2 | ||
| 3 | use std::boxed::Box; | 3 | use std::boxed::Box; |
| 4 | use std::future::poll_fn; | 4 | use std::future::poll_fn; |
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-futures/src/fmt.rs +++ b/embassy-futures/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-hal-internal/src/fmt.rs +++ b/embassy-hal-internal/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs index 19dabcf6f..5e64dce9d 100644 --- a/embassy-hal-internal/src/interrupt.rs +++ b/embassy-hal-internal/src/interrupt.rs | |||
| @@ -30,14 +30,12 @@ macro_rules! interrupt_mod { | |||
| 30 | pub mod typelevel { | 30 | pub mod typelevel { |
| 31 | use super::InterruptExt; | 31 | use super::InterruptExt; |
| 32 | 32 | ||
| 33 | mod sealed { | 33 | trait SealedInterrupt {} |
| 34 | pub trait Interrupt {} | ||
| 35 | } | ||
| 36 | 34 | ||
| 37 | /// Type-level interrupt. | 35 | /// Type-level interrupt. |
| 38 | /// | 36 | /// |
| 39 | /// This trait is implemented for all typelevel interrupt types in this module. | 37 | /// This trait is implemented for all typelevel interrupt types in this module. |
| 40 | pub trait Interrupt: sealed::Interrupt { | 38 | pub trait Interrupt: SealedInterrupt { |
| 41 | 39 | ||
| 42 | /// Interrupt enum variant. | 40 | /// Interrupt enum variant. |
| 43 | /// | 41 | /// |
| @@ -105,7 +103,7 @@ macro_rules! interrupt_mod { | |||
| 105 | #[doc=stringify!($irqs)] | 103 | #[doc=stringify!($irqs)] |
| 106 | #[doc=" typelevel interrupt."] | 104 | #[doc=" typelevel interrupt."] |
| 107 | pub enum $irqs {} | 105 | pub enum $irqs {} |
| 108 | impl sealed::Interrupt for $irqs{} | 106 | impl SealedInterrupt for $irqs{} |
| 109 | impl Interrupt for $irqs { | 107 | impl Interrupt for $irqs { |
| 110 | const IRQ: super::Interrupt = super::Interrupt::$irqs; | 108 | const IRQ: super::Interrupt = super::Interrupt::$irqs; |
| 111 | } | 109 | } |
diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs index 12737c690..2ac42c557 100644 --- a/embassy-net-adin1110/src/fmt.rs +++ b/embassy-net-adin1110/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -83,14 +83,17 @@ macro_rules! todo { | |||
| 83 | }; | 83 | }; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | #[cfg(not(feature = "defmt"))] | ||
| 86 | macro_rules! unreachable { | 87 | macro_rules! unreachable { |
| 87 | ($($x:tt)*) => { | 88 | ($($x:tt)*) => { |
| 88 | { | 89 | ::core::unreachable!($($x)*) |
| 89 | #[cfg(not(feature = "defmt"))] | 90 | }; |
| 90 | ::core::unreachable!($($x)*); | 91 | } |
| 91 | #[cfg(feature = "defmt")] | 92 | |
| 92 | ::defmt::unreachable!($($x)*); | 93 | #[cfg(feature = "defmt")] |
| 93 | } | 94 | macro_rules! unreachable { |
| 95 | ($($x:tt)*) => { | ||
| 96 | ::defmt::unreachable!($($x)*) | ||
| 94 | }; | 97 | }; |
| 95 | } | 98 | } |
| 96 | 99 | ||
| @@ -113,7 +116,7 @@ macro_rules! trace { | |||
| 113 | #[cfg(feature = "defmt")] | 116 | #[cfg(feature = "defmt")] |
| 114 | ::defmt::trace!($s $(, $x)*); | 117 | ::defmt::trace!($s $(, $x)*); |
| 115 | #[cfg(not(any(feature = "log", feature="defmt")))] | 118 | #[cfg(not(any(feature = "log", feature="defmt")))] |
| 116 | let _ignored = ($( & $x ),*); | 119 | let _ = ($( & $x ),*); |
| 117 | } | 120 | } |
| 118 | }; | 121 | }; |
| 119 | } | 122 | } |
| @@ -126,7 +129,7 @@ macro_rules! debug { | |||
| 126 | #[cfg(feature = "defmt")] | 129 | #[cfg(feature = "defmt")] |
| 127 | ::defmt::debug!($s $(, $x)*); | 130 | ::defmt::debug!($s $(, $x)*); |
| 128 | #[cfg(not(any(feature = "log", feature="defmt")))] | 131 | #[cfg(not(any(feature = "log", feature="defmt")))] |
| 129 | let _ignored = ($( & $x ),*); | 132 | let _ = ($( & $x ),*); |
| 130 | } | 133 | } |
| 131 | }; | 134 | }; |
| 132 | } | 135 | } |
| @@ -139,7 +142,7 @@ macro_rules! info { | |||
| 139 | #[cfg(feature = "defmt")] | 142 | #[cfg(feature = "defmt")] |
| 140 | ::defmt::info!($s $(, $x)*); | 143 | ::defmt::info!($s $(, $x)*); |
| 141 | #[cfg(not(any(feature = "log", feature="defmt")))] | 144 | #[cfg(not(any(feature = "log", feature="defmt")))] |
| 142 | let _ignored = ($( & $x ),*); | 145 | let _ = ($( & $x ),*); |
| 143 | } | 146 | } |
| 144 | }; | 147 | }; |
| 145 | } | 148 | } |
| @@ -152,7 +155,7 @@ macro_rules! warn { | |||
| 152 | #[cfg(feature = "defmt")] | 155 | #[cfg(feature = "defmt")] |
| 153 | ::defmt::warn!($s $(, $x)*); | 156 | ::defmt::warn!($s $(, $x)*); |
| 154 | #[cfg(not(any(feature = "log", feature="defmt")))] | 157 | #[cfg(not(any(feature = "log", feature="defmt")))] |
| 155 | let _ignored = ($( & $x ),*); | 158 | let _ = ($( & $x ),*); |
| 156 | } | 159 | } |
| 157 | }; | 160 | }; |
| 158 | } | 161 | } |
| @@ -165,7 +168,7 @@ macro_rules! error { | |||
| 165 | #[cfg(feature = "defmt")] | 168 | #[cfg(feature = "defmt")] |
| 166 | ::defmt::error!($s $(, $x)*); | 169 | ::defmt::error!($s $(, $x)*); |
| 167 | #[cfg(not(any(feature = "log", feature="defmt")))] | 170 | #[cfg(not(any(feature = "log", feature="defmt")))] |
| 168 | let _ignored = ($( & $x ),*); | 171 | let _ = ($( & $x ),*); |
| 169 | } | 172 | } |
| 170 | }; | 173 | }; |
| 171 | } | 174 | } |
| @@ -226,7 +229,7 @@ impl<T, E> Try for Result<T, E> { | |||
| 226 | } | 229 | } |
| 227 | } | 230 | } |
| 228 | 231 | ||
| 229 | pub struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 230 | 233 | ||
| 231 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
| 232 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | 235 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
diff --git a/embassy-net-driver-channel/src/fmt.rs b/embassy-net-driver-channel/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-driver-channel/src/fmt.rs +++ b/embassy-net-driver-channel/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-enc28j60/src/fmt.rs +++ b/embassy-net-enc28j60/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs index f18134927..dda35f498 100644 --- a/embassy-net-enc28j60/src/lib.rs +++ b/embassy-net-enc28j60/src/lib.rs | |||
| @@ -17,7 +17,6 @@ mod phy; | |||
| 17 | mod traits; | 17 | mod traits; |
| 18 | 18 | ||
| 19 | use core::cmp; | 19 | use core::cmp; |
| 20 | use core::convert::TryInto; | ||
| 21 | 20 | ||
| 22 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; | 21 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; |
| 23 | use embassy_time::Duration; | 22 | use embassy_time::Duration; |
| @@ -645,8 +644,8 @@ where | |||
| 645 | Self: 'a; | 644 | Self: 'a; |
| 646 | 645 | ||
| 647 | fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | 646 | fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
| 648 | let rx_buf = unsafe { &mut RX_BUF }; | 647 | let rx_buf = unsafe { &mut *core::ptr::addr_of_mut!(RX_BUF) }; |
| 649 | let tx_buf = unsafe { &mut TX_BUF }; | 648 | let tx_buf = unsafe { &mut *core::ptr::addr_of_mut!(TX_BUF) }; |
| 650 | if let Some(n) = self.receive(rx_buf) { | 649 | if let Some(n) = self.receive(rx_buf) { |
| 651 | Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self })) | 650 | Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self })) |
| 652 | } else { | 651 | } else { |
| @@ -656,7 +655,7 @@ where | |||
| 656 | } | 655 | } |
| 657 | 656 | ||
| 658 | fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> { | 657 | fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> { |
| 659 | let tx_buf = unsafe { &mut TX_BUF }; | 658 | let tx_buf = unsafe { &mut *core::ptr::addr_of_mut!(TX_BUF) }; |
| 660 | Some(TxToken { buf: tx_buf, eth: self }) | 659 | Some(TxToken { buf: tx_buf, eth: self }) |
| 661 | } | 660 | } |
| 662 | 661 | ||
diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-esp-hosted/src/fmt.rs +++ b/embassy-net-esp-hosted/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net-ppp/src/fmt.rs +++ b/embassy-net-ppp/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs index de30934eb..56f55fba1 100644 --- a/embassy-net-tuntap/src/lib.rs +++ b/embassy-net-tuntap/src/lib.rs | |||
| @@ -6,7 +6,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; | |||
| 6 | use std::task::Context; | 6 | use std::task::Context; |
| 7 | 7 | ||
| 8 | use async_io::Async; | 8 | use async_io::Async; |
| 9 | use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; | 9 | use embassy_net_driver::{Capabilities, Driver, HardwareAddress, LinkState}; |
| 10 | use log::*; | 10 | use log::*; |
| 11 | 11 | ||
| 12 | /// Get the MTU of the given interface. | 12 | /// Get the MTU of the given interface. |
diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs index b987c2b36..e1f963d95 100644 --- a/embassy-net-wiznet/src/chip/mod.rs +++ b/embassy-net-wiznet/src/chip/mod.rs | |||
| @@ -2,49 +2,40 @@ | |||
| 2 | mod w5500; | 2 | mod w5500; |
| 3 | pub use w5500::W5500; | 3 | pub use w5500::W5500; |
| 4 | mod w5100s; | 4 | mod w5100s; |
| 5 | use embedded_hal_async::spi::SpiDevice; | ||
| 5 | pub use w5100s::W5100S; | 6 | pub use w5100s::W5100S; |
| 6 | 7 | ||
| 7 | pub(crate) mod sealed { | 8 | pub(crate) trait SealedChip { |
| 8 | use embedded_hal_async::spi::SpiDevice; | 9 | type Address; |
| 9 | 10 | ||
| 10 | pub trait Chip { | 11 | const COMMON_MODE: Self::Address; |
| 11 | type Address; | 12 | const COMMON_MAC: Self::Address; |
| 12 | 13 | const COMMON_SOCKET_INTR: Self::Address; | |
| 13 | const COMMON_MODE: Self::Address; | 14 | const COMMON_PHY_CFG: Self::Address; |
| 14 | const COMMON_MAC: Self::Address; | 15 | const SOCKET_MODE: Self::Address; |
| 15 | const COMMON_SOCKET_INTR: Self::Address; | 16 | const SOCKET_COMMAND: Self::Address; |
| 16 | const COMMON_PHY_CFG: Self::Address; | 17 | const SOCKET_RXBUF_SIZE: Self::Address; |
| 17 | const SOCKET_MODE: Self::Address; | 18 | const SOCKET_TXBUF_SIZE: Self::Address; |
| 18 | const SOCKET_COMMAND: Self::Address; | 19 | const SOCKET_TX_FREE_SIZE: Self::Address; |
| 19 | const SOCKET_RXBUF_SIZE: Self::Address; | 20 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address; |
| 20 | const SOCKET_TXBUF_SIZE: Self::Address; | 21 | const SOCKET_RECVD_SIZE: Self::Address; |
| 21 | const SOCKET_TX_FREE_SIZE: Self::Address; | 22 | const SOCKET_RX_DATA_READ_PTR: Self::Address; |
| 22 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address; | 23 | const SOCKET_INTR_MASK: Self::Address; |
| 23 | const SOCKET_RECVD_SIZE: Self::Address; | 24 | const SOCKET_INTR: Self::Address; |
| 24 | const SOCKET_RX_DATA_READ_PTR: Self::Address; | 25 | |
| 25 | const SOCKET_INTR_MASK: Self::Address; | 26 | const SOCKET_MODE_VALUE: u8; |
| 26 | const SOCKET_INTR: Self::Address; | 27 | |
| 27 | 28 | const BUF_SIZE: u16; | |
| 28 | const SOCKET_MODE_VALUE: u8; | 29 | const AUTO_WRAP: bool; |
| 29 | 30 | ||
| 30 | const BUF_SIZE: u16; | 31 | fn rx_addr(addr: u16) -> Self::Address; |
| 31 | const AUTO_WRAP: bool; | 32 | fn tx_addr(addr: u16) -> Self::Address; |
| 32 | 33 | ||
| 33 | fn rx_addr(addr: u16) -> Self::Address; | 34 | async fn bus_read<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &mut [u8]) |
| 34 | fn tx_addr(addr: u16) -> Self::Address; | 35 | -> Result<(), SPI::Error>; |
| 35 | 36 | async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error>; | |
| 36 | async fn bus_read<SPI: SpiDevice>( | ||
| 37 | spi: &mut SPI, | ||
| 38 | address: Self::Address, | ||
| 39 | data: &mut [u8], | ||
| 40 | ) -> Result<(), SPI::Error>; | ||
| 41 | async fn bus_write<SPI: SpiDevice>( | ||
| 42 | spi: &mut SPI, | ||
| 43 | address: Self::Address, | ||
| 44 | data: &[u8], | ||
| 45 | ) -> Result<(), SPI::Error>; | ||
| 46 | } | ||
| 47 | } | 37 | } |
| 48 | 38 | ||
| 49 | /// Trait for Wiznet chips. | 39 | /// Trait for Wiznet chips. |
| 50 | pub trait Chip: sealed::Chip {} | 40 | #[allow(private_bounds)] |
| 41 | pub trait Chip: SealedChip {} | ||
diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs index 7d328bce5..23ce3ed83 100644 --- a/embassy-net-wiznet/src/chip/w5100s.rs +++ b/embassy-net-wiznet/src/chip/w5100s.rs | |||
| @@ -8,7 +8,7 @@ const RX_BASE: u16 = 0x6000; | |||
| 8 | pub enum W5100S {} | 8 | pub enum W5100S {} |
| 9 | 9 | ||
| 10 | impl super::Chip for W5100S {} | 10 | impl super::Chip for W5100S {} |
| 11 | impl super::sealed::Chip for W5100S { | 11 | impl super::SealedChip for W5100S { |
| 12 | type Address = u16; | 12 | type Address = u16; |
| 13 | 13 | ||
| 14 | const COMMON_MODE: Self::Address = 0x00; | 14 | const COMMON_MODE: Self::Address = 0x00; |
diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs index 16236126d..12e610ea2 100644 --- a/embassy-net-wiznet/src/chip/w5500.rs +++ b/embassy-net-wiznet/src/chip/w5500.rs | |||
| @@ -12,7 +12,7 @@ pub enum RegisterBlock { | |||
| 12 | pub enum W5500 {} | 12 | pub enum W5500 {} |
| 13 | 13 | ||
| 14 | impl super::Chip for W5500 {} | 14 | impl super::Chip for W5500 {} |
| 15 | impl super::sealed::Chip for W5500 { | 15 | impl super::SealedChip for W5500 { |
| 16 | type Address = (RegisterBlock, u16); | 16 | type Address = (RegisterBlock, u16); |
| 17 | 17 | ||
| 18 | const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00); | 18 | const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00); |
diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-net/src/fmt.rs +++ b/embassy-net/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-nrf/src/fmt.rs +++ b/embassy-nrf/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 3649ea61a..f2353f21d 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs | |||
| @@ -473,10 +473,12 @@ impl sealed::Pin for AnyPin { | |||
| 473 | 473 | ||
| 474 | // ==================== | 474 | // ==================== |
| 475 | 475 | ||
| 476 | #[cfg(not(feature = "_nrf51"))] | ||
| 476 | pub(crate) trait PselBits { | 477 | pub(crate) trait PselBits { |
| 477 | fn psel_bits(&self) -> u32; | 478 | fn psel_bits(&self) -> u32; |
| 478 | } | 479 | } |
| 479 | 480 | ||
| 481 | #[cfg(not(feature = "_nrf51"))] | ||
| 480 | impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> { | 482 | impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> { |
| 481 | #[inline] | 483 | #[inline] |
| 482 | fn psel_bits(&self) -> u32 { | 484 | fn psel_bits(&self) -> u32 { |
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 12f4ed0a0..4a28279a9 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -167,8 +167,10 @@ unsafe fn handle_gpiote_interrupt() { | |||
| 167 | } | 167 | } |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | #[cfg(not(feature = "_nrf51"))] | ||
| 170 | struct BitIter(u32); | 171 | struct BitIter(u32); |
| 171 | 172 | ||
| 173 | #[cfg(not(feature = "_nrf51"))] | ||
| 172 | impl Iterator for BitIter { | 174 | impl Iterator for BitIter { |
| 173 | type Item = u32; | 175 | type Item = u32; |
| 174 | 176 | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 718f229a3..3457dd933 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -225,10 +225,31 @@ pub mod config { | |||
| 225 | /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used. | 225 | /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used. |
| 226 | #[cfg(feature = "nrf52840")] | 226 | #[cfg(feature = "nrf52840")] |
| 227 | pub reg0: bool, | 227 | pub reg0: bool, |
| 228 | /// Configure the voltage of the first stage DCDC. It is stored in non-volatile memory (UICR.REGOUT0 register); pass None to not touch it. | ||
| 229 | #[cfg(feature = "nrf52840")] | ||
| 230 | pub reg0_voltage: Option<Reg0Voltage>, | ||
| 228 | /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used. | 231 | /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used. |
| 229 | pub reg1: bool, | 232 | pub reg1: bool, |
| 230 | } | 233 | } |
| 231 | 234 | ||
| 235 | /// Output voltage setting for REG0 regulator stage. | ||
| 236 | #[cfg(feature = "nrf52840")] | ||
| 237 | pub enum Reg0Voltage { | ||
| 238 | /// 1.8 V | ||
| 239 | _1V8 = 0, | ||
| 240 | /// 2.1 V | ||
| 241 | _2V1 = 1, | ||
| 242 | /// 2.4 V | ||
| 243 | _2V4 = 2, | ||
| 244 | /// 2.7 V | ||
| 245 | _2V7 = 3, | ||
| 246 | /// 3.0 V | ||
| 247 | _3V0 = 4, | ||
| 248 | /// 3.3 V | ||
| 249 | _3v3 = 5, | ||
| 250 | //ERASED = 7, means 1.8V | ||
| 251 | } | ||
| 252 | |||
| 232 | /// Settings for enabling the built in DCDC converters. | 253 | /// Settings for enabling the built in DCDC converters. |
| 233 | #[cfg(feature = "_nrf5340-app")] | 254 | #[cfg(feature = "_nrf5340-app")] |
| 234 | pub struct DcdcConfig { | 255 | pub struct DcdcConfig { |
| @@ -279,6 +300,8 @@ pub mod config { | |||
| 279 | dcdc: DcdcConfig { | 300 | dcdc: DcdcConfig { |
| 280 | #[cfg(feature = "nrf52840")] | 301 | #[cfg(feature = "nrf52840")] |
| 281 | reg0: false, | 302 | reg0: false, |
| 303 | #[cfg(feature = "nrf52840")] | ||
| 304 | reg0_voltage: None, | ||
| 282 | reg1: false, | 305 | reg1: false, |
| 283 | }, | 306 | }, |
| 284 | #[cfg(feature = "_nrf5340-app")] | 307 | #[cfg(feature = "_nrf5340-app")] |
| @@ -337,6 +360,7 @@ mod consts { | |||
| 337 | pub const UICR_PSELRESET2: *mut u32 = 0x10001204 as *mut u32; | 360 | pub const UICR_PSELRESET2: *mut u32 = 0x10001204 as *mut u32; |
| 338 | pub const UICR_NFCPINS: *mut u32 = 0x1000120C as *mut u32; | 361 | pub const UICR_NFCPINS: *mut u32 = 0x1000120C as *mut u32; |
| 339 | pub const UICR_APPROTECT: *mut u32 = 0x10001208 as *mut u32; | 362 | pub const UICR_APPROTECT: *mut u32 = 0x10001208 as *mut u32; |
| 363 | pub const UICR_REGOUT0: *mut u32 = 0x10001304 as *mut u32; | ||
| 340 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | 364 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; |
| 341 | pub const APPROTECT_DISABLED: u32 = 0x0000_005a; | 365 | pub const APPROTECT_DISABLED: u32 = 0x0000_005a; |
| 342 | } | 366 | } |
| @@ -493,6 +517,21 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 493 | } | 517 | } |
| 494 | } | 518 | } |
| 495 | 519 | ||
| 520 | #[cfg(feature = "nrf52840")] | ||
| 521 | unsafe { | ||
| 522 | if let Some(value) = config.dcdc.reg0_voltage { | ||
| 523 | let value = value as u32; | ||
| 524 | let res = uicr_write_masked(consts::UICR_REGOUT0, value, 0b00000000_00000000_00000000_00000111); | ||
| 525 | needs_reset |= res == WriteResult::Written; | ||
| 526 | if res == WriteResult::Failed { | ||
| 527 | warn!( | ||
| 528 | "Failed to set regulator voltage, as UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 529 | To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." | ||
| 530 | ); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 496 | if needs_reset { | 535 | if needs_reset { |
| 497 | cortex_m::peripheral::SCB::sys_reset(); | 536 | cortex_m::peripheral::SCB::sys_reset(); |
| 498 | } | 537 | } |
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3c35baee5..2970ad3f2 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs | |||
| @@ -21,8 +21,6 @@ pub(crate) mod sealed { | |||
| 21 | fn regs() -> &'static pac::timer0::RegisterBlock; | 21 | fn regs() -> &'static pac::timer0::RegisterBlock; |
| 22 | } | 22 | } |
| 23 | pub trait ExtendedInstance {} | 23 | pub trait ExtendedInstance {} |
| 24 | |||
| 25 | pub trait TimerType {} | ||
| 26 | } | 24 | } |
| 27 | 25 | ||
| 28 | /// Basic Timer instance. | 26 | /// Basic Timer instance. |
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 21360bf66..4c01fe195 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs | |||
| @@ -19,14 +19,9 @@ static WAKER: AtomicWaker = AtomicWaker::new(); | |||
| 19 | 19 | ||
| 20 | /// ADC config. | 20 | /// ADC config. |
| 21 | #[non_exhaustive] | 21 | #[non_exhaustive] |
| 22 | #[derive(Default)] | ||
| 22 | pub struct Config {} | 23 | pub struct Config {} |
| 23 | 24 | ||
| 24 | impl Default for Config { | ||
| 25 | fn default() -> Self { | ||
| 26 | Self {} | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | enum Source<'p> { | 25 | enum Source<'p> { |
| 31 | Pin(PeripheralRef<'p, AnyPin>), | 26 | Pin(PeripheralRef<'p, AnyPin>), |
| 32 | TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), | 27 | TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), |
| @@ -175,7 +170,7 @@ impl<'d, M: Mode> Adc<'d, M> { | |||
| 175 | while !r.cs().read().ready() {} | 170 | while !r.cs().read().ready() {} |
| 176 | match r.cs().read().err() { | 171 | match r.cs().read().err() { |
| 177 | true => Err(Error::ConversionFailed), | 172 | true => Err(Error::ConversionFailed), |
| 178 | false => Ok(r.result().read().result().into()), | 173 | false => Ok(r.result().read().result()), |
| 179 | } | 174 | } |
| 180 | } | 175 | } |
| 181 | } | 176 | } |
| @@ -221,7 +216,7 @@ impl<'d> Adc<'d, Async> { | |||
| 221 | Self::wait_for_ready().await; | 216 | Self::wait_for_ready().await; |
| 222 | match r.cs().read().err() { | 217 | match r.cs().read().err() { |
| 223 | true => Err(Error::ConversionFailed), | 218 | true => Err(Error::ConversionFailed), |
| 224 | false => Ok(r.result().read().result().into()), | 219 | false => Ok(r.result().read().result()), |
| 225 | } | 220 | } |
| 226 | } | 221 | } |
| 227 | 222 | ||
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 19232b801..b7f6aeac9 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -737,7 +737,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { | |||
| 737 | assert!(config.refdiv >= 1 && config.refdiv <= 63); | 737 | assert!(config.refdiv >= 1 && config.refdiv <= 63); |
| 738 | assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); | 738 | assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); |
| 739 | let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); | 739 | let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); |
| 740 | assert!(vco_freq >= 750_000_000 && vco_freq <= 1800_000_000); | 740 | assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); |
| 741 | 741 | ||
| 742 | // Load VCO-related dividers before starting VCO | 742 | // Load VCO-related dividers before starting VCO |
| 743 | p.cs().write(|w| w.set_refdiv(config.refdiv as _)); | 743 | p.cs().write(|w| w.set_refdiv(config.refdiv as _)); |
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 088a842a1..44aabce6b 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -96,7 +96,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | |||
| 96 | ) -> Transfer<'a, C> { | 96 | ) -> Transfer<'a, C> { |
| 97 | copy_inner( | 97 | copy_inner( |
| 98 | ch, | 98 | ch, |
| 99 | &mut DUMMY as *const u32, | 99 | core::ptr::addr_of_mut!(DUMMY) as *const u32, |
| 100 | to as *mut u32, | 100 | to as *mut u32, |
| 101 | len, | 101 | len, |
| 102 | W::size(), | 102 | W::size(), |
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 2d673cf6c..422b77400 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -326,9 +326,9 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | |||
| 326 | // If the destination address is already aligned, then we can just DMA directly | 326 | // If the destination address is already aligned, then we can just DMA directly |
| 327 | if (bytes.as_ptr() as u32) % 4 == 0 { | 327 | if (bytes.as_ptr() as u32) % 4 == 0 { |
| 328 | // Safety: alignment and size have been checked for compatibility | 328 | // Safety: alignment and size have been checked for compatibility |
| 329 | let mut buf: &mut [u32] = | 329 | let buf: &mut [u32] = |
| 330 | unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u32, bytes.len() / 4) }; | 330 | unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u32, bytes.len() / 4) }; |
| 331 | self.background_read(offset, &mut buf)?.await; | 331 | self.background_read(offset, buf)?.await; |
| 332 | return Ok(()); | 332 | return Ok(()); |
| 333 | } | 333 | } |
| 334 | 334 | ||
| @@ -420,8 +420,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash | |||
| 420 | 420 | ||
| 421 | #[allow(dead_code)] | 421 | #[allow(dead_code)] |
| 422 | mod ram_helpers { | 422 | mod ram_helpers { |
| 423 | use core::marker::PhantomData; | ||
| 424 | |||
| 425 | use super::*; | 423 | use super::*; |
| 426 | use crate::rom_data; | 424 | use crate::rom_data; |
| 427 | 425 | ||
diff --git a/embassy-rp/src/float/mod.rs b/embassy-rp/src/float/mod.rs index 945afff90..3ad6f1c50 100644 --- a/embassy-rp/src/float/mod.rs +++ b/embassy-rp/src/float/mod.rs | |||
| @@ -89,6 +89,7 @@ pub(crate) trait Float: | |||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /// Returns true if `self` is infinity | 91 | /// Returns true if `self` is infinity |
| 92 | #[allow(unused)] | ||
| 92 | fn is_infinity(self) -> bool { | 93 | fn is_infinity(self) -> bool { |
| 93 | (self.repr() & (Self::EXPONENT_MASK | Self::SIGNIFICAND_MASK)) == Self::EXPONENT_MASK | 94 | (self.repr() & (Self::EXPONENT_MASK | Self::SIGNIFICAND_MASK)) == Self::EXPONENT_MASK |
| 94 | } | 95 | } |
diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-rp/src/fmt.rs +++ b/embassy-rp/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 62eeb4cf6..a84c00a2c 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -225,8 +225,8 @@ fn irq_handler<const N: usize>(bank: pac::io::Io, wakers: &[AtomicWaker; N]) { | |||
| 225 | // The status register is divided into groups of four, one group for | 225 | // The status register is divided into groups of four, one group for |
| 226 | // each pin. Each group consists of four trigger levels LEVEL_LOW, | 226 | // each pin. Each group consists of four trigger levels LEVEL_LOW, |
| 227 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. | 227 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. |
| 228 | let pin_group = (pin % 8) as usize; | 228 | let pin_group = pin % 8; |
| 229 | let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32; | 229 | let event = (intsx.read().0 >> (pin_group * 4)) & 0xf; |
| 230 | 230 | ||
| 231 | // no more than one event can be awaited per pin at any given time, so | 231 | // no more than one event can be awaited per pin at any given time, so |
| 232 | // we can just clear all interrupt enables for that pin without having | 232 | // we can just clear all interrupt enables for that pin without having |
| @@ -238,7 +238,7 @@ fn irq_handler<const N: usize>(bank: pac::io::Io, wakers: &[AtomicWaker; N]) { | |||
| 238 | w.set_level_high(pin_group, true); | 238 | w.set_level_high(pin_group, true); |
| 239 | w.set_level_low(pin_group, true); | 239 | w.set_level_low(pin_group, true); |
| 240 | }); | 240 | }); |
| 241 | wakers[pin as usize].wake(); | 241 | wakers[pin].wake(); |
| 242 | } | 242 | } |
| 243 | } | 243 | } |
| 244 | } | 244 | } |
| @@ -976,8 +976,6 @@ impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5); | |||
| 976 | // ==================== | 976 | // ==================== |
| 977 | 977 | ||
| 978 | mod eh02 { | 978 | mod eh02 { |
| 979 | use core::convert::Infallible; | ||
| 980 | |||
| 981 | use super::*; | 979 | use super::*; |
| 982 | 980 | ||
| 983 | impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { | 981 | impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { |
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index ac0eac96d..26a819b25 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -352,7 +352,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 352 | } | 352 | } |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P) | 355 | pub(crate) fn set_up_i2c_pin<P, T>(pin: &P) |
| 356 | where | 356 | where |
| 357 | P: core::ops::Deref<Target = T>, | 357 | P: core::ops::Deref<Target = T>, |
| 358 | T: crate::gpio::Pin, | 358 | T: crate::gpio::Pin, |
| @@ -749,7 +749,7 @@ where | |||
| 749 | 749 | ||
| 750 | let addr: u16 = address.into(); | 750 | let addr: u16 = address.into(); |
| 751 | 751 | ||
| 752 | if operations.len() > 0 { | 752 | if !operations.is_empty() { |
| 753 | Self::setup(addr)?; | 753 | Self::setup(addr)?; |
| 754 | } | 754 | } |
| 755 | let mut iterator = operations.iter_mut(); | 755 | let mut iterator = operations.iter_mut(); |
| @@ -762,7 +762,7 @@ where | |||
| 762 | self.read_async_internal(buffer, false, last).await?; | 762 | self.read_async_internal(buffer, false, last).await?; |
| 763 | } | 763 | } |
| 764 | Operation::Write(buffer) => { | 764 | Operation::Write(buffer) => { |
| 765 | self.write_async_internal(buffer.into_iter().cloned(), last).await?; | 765 | self.write_async_internal(buffer.iter().cloned(), last).await?; |
| 766 | } | 766 | } |
| 767 | } | 767 | } |
| 768 | } | 768 | } |
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 97ca17295..e2d4fbac0 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs | |||
| @@ -289,7 +289,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 289 | pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> { | 289 | pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> { |
| 290 | let p = T::regs(); | 290 | let p = T::regs(); |
| 291 | 291 | ||
| 292 | if buffer.len() == 0 { | 292 | if buffer.is_empty() { |
| 293 | return Err(Error::InvalidResponseBufferLength); | 293 | return Err(Error::InvalidResponseBufferLength); |
| 294 | } | 294 | } |
| 295 | 295 | ||
| @@ -318,15 +318,13 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | Poll::Pending | 320 | Poll::Pending |
| 321 | } else if stat.rx_done() { | ||
| 322 | p.ic_clr_rx_done().read(); | ||
| 323 | Poll::Ready(Ok(ReadStatus::Done)) | ||
| 324 | } else if stat.rd_req() && stat.tx_empty() { | ||
| 325 | Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) | ||
| 321 | } else { | 326 | } else { |
| 322 | if stat.rx_done() { | 327 | Poll::Pending |
| 323 | p.ic_clr_rx_done().read(); | ||
| 324 | Poll::Ready(Ok(ReadStatus::Done)) | ||
| 325 | } else if stat.rd_req() && stat.tx_empty() { | ||
| 326 | Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) | ||
| 327 | } else { | ||
| 328 | Poll::Pending | ||
| 329 | } | ||
| 330 | } | 328 | } |
| 331 | }, | 329 | }, |
| 332 | |_me| { | 330 | |_me| { |
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 46973fdc8..1c83e306d 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -183,14 +183,14 @@ embassy_hal_internal::peripherals! { | |||
| 183 | DMA_CH10, | 183 | DMA_CH10, |
| 184 | DMA_CH11, | 184 | DMA_CH11, |
| 185 | 185 | ||
| 186 | PWM_CH0, | 186 | PWM_SLICE0, |
| 187 | PWM_CH1, | 187 | PWM_SLICE1, |
| 188 | PWM_CH2, | 188 | PWM_SLICE2, |
| 189 | PWM_CH3, | 189 | PWM_SLICE3, |
| 190 | PWM_CH4, | 190 | PWM_SLICE4, |
| 191 | PWM_CH5, | 191 | PWM_SLICE5, |
| 192 | PWM_CH6, | 192 | PWM_SLICE6, |
| 193 | PWM_CH7, | 193 | PWM_SLICE7, |
| 194 | 194 | ||
| 195 | USB, | 195 | USB, |
| 196 | 196 | ||
| @@ -238,8 +238,8 @@ select_bootloader! { | |||
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | /// Installs a stack guard for the CORE0 stack in MPU region 0. | 240 | /// Installs a stack guard for the CORE0 stack in MPU region 0. |
| 241 | /// Will fail if the MPU is already confgigured. This function requires | 241 | /// Will fail if the MPU is already configured. This function requires |
| 242 | /// a `_stack_end` symbol to be defined by the linker script, and expexcts | 242 | /// a `_stack_end` symbol to be defined by the linker script, and expects |
| 243 | /// `_stack_end` to be located at the lowest address (largest depth) of | 243 | /// `_stack_end` to be located at the lowest address (largest depth) of |
| 244 | /// the stack. | 244 | /// the stack. |
| 245 | /// | 245 | /// |
| @@ -274,7 +274,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> { | |||
| 274 | extern "C" { | 274 | extern "C" { |
| 275 | static mut _stack_end: usize; | 275 | static mut _stack_end: usize; |
| 276 | } | 276 | } |
| 277 | unsafe { install_stack_guard(&mut _stack_end as *mut usize) } | 277 | unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | #[inline(always)] | 280 | #[inline(always)] |
| @@ -354,6 +354,7 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 354 | 354 | ||
| 355 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. | 355 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. |
| 356 | trait RegExt<T: Copy> { | 356 | trait RegExt<T: Copy> { |
| 357 | #[allow(unused)] | ||
| 357 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 358 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 358 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 359 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 359 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 360 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 252f30dc1..d9d65694a 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -59,7 +59,7 @@ static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); | |||
| 59 | 59 | ||
| 60 | #[inline(always)] | 60 | #[inline(always)] |
| 61 | fn core1_setup(stack_bottom: *mut usize) { | 61 | fn core1_setup(stack_bottom: *mut usize) { |
| 62 | if let Err(_) = install_stack_guard(stack_bottom) { | 62 | if install_stack_guard(stack_bottom).is_err() { |
| 63 | // currently only happens if the MPU was already set up, which | 63 | // currently only happens if the MPU was already set up, which |
| 64 | // would indicate that the core is already in use from outside | 64 | // would indicate that the core is already in use from outside |
| 65 | // embassy, somehow. trap if so since we can't deal with that. | 65 | // embassy, somehow. trap if so since we can't deal with that. |
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ca9795024..7eca700ba 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs | |||
| @@ -268,7 +268,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | /// Set the pin's input sync bypass. | 270 | /// Set the pin's input sync bypass. |
| 271 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { | 271 | pub fn set_input_sync_bypass(&mut self, bypass: bool) { |
| 272 | let mask = 1 << self.pin(); | 272 | let mask = 1 << self.pin(); |
| 273 | if bypass { | 273 | if bypass { |
| 274 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); | 274 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); |
| @@ -463,7 +463,7 @@ impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { | |||
| 463 | } | 463 | } |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) { | 466 | fn assert_consecutive<PIO: Instance>(pins: &[&Pin<PIO>]) { |
| 467 | for (p1, p2) in pins.iter().zip(pins.iter().skip(1)) { | 467 | for (p1, p2) in pins.iter().zip(pins.iter().skip(1)) { |
| 468 | // purposely does not allow wrap-around because we can't claim pins 30 and 31. | 468 | // purposely does not allow wrap-around because we can't claim pins 30 and 31. |
| 469 | assert!(p1.pin() + 1 == p2.pin(), "pins must be consecutive"); | 469 | assert!(p1.pin() + 1 == p2.pin(), "pins must be consecutive"); |
| @@ -764,7 +764,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 764 | w.set_set_count(1); | 764 | w.set_set_count(1); |
| 765 | }); | 765 | }); |
| 766 | // SET PINS, (dir) | 766 | // SET PINS, (dir) |
| 767 | unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) }; | 767 | unsafe { sm.exec_instr(0b11100_000_000_00000 | level as u16) }; |
| 768 | } | 768 | } |
| 769 | }); | 769 | }); |
| 770 | } | 770 | } |
| @@ -867,9 +867,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 867 | prog: &Program<SIZE>, | 867 | prog: &Program<SIZE>, |
| 868 | ) -> Result<LoadedProgram<'d, PIO>, LoadError> { | 868 | ) -> Result<LoadedProgram<'d, PIO>, LoadError> { |
| 869 | match prog.origin { | 869 | match prog.origin { |
| 870 | Some(origin) => self | 870 | Some(origin) => self.try_load_program_at(prog, origin).map_err(LoadError::AddressInUse), |
| 871 | .try_load_program_at(prog, origin) | ||
| 872 | .map_err(|a| LoadError::AddressInUse(a)), | ||
| 873 | None => { | 871 | None => { |
| 874 | // naively search for free space, allowing wraparound since | 872 | // naively search for free space, allowing wraparound since |
| 875 | // PIO does support that. with only 32 instruction slots it | 873 | // PIO does support that. with only 32 instruction slots it |
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 784a05f92..5aab3ff4f 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs | |||
| @@ -82,13 +82,13 @@ impl From<InputMode> for Divmode { | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | /// PWM driver. | 84 | /// PWM driver. |
| 85 | pub struct Pwm<'d, T: Channel> { | 85 | pub struct Pwm<'d, T: Slice> { |
| 86 | inner: PeripheralRef<'d, T>, | 86 | inner: PeripheralRef<'d, T>, |
| 87 | pin_a: Option<PeripheralRef<'d, AnyPin>>, | 87 | pin_a: Option<PeripheralRef<'d, AnyPin>>, |
| 88 | pin_b: Option<PeripheralRef<'d, AnyPin>>, | 88 | pin_b: Option<PeripheralRef<'d, AnyPin>>, |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | impl<'d, T: Channel> Pwm<'d, T> { | 91 | impl<'d, T: Slice> Pwm<'d, T> { |
| 92 | fn new_inner( | 92 | fn new_inner( |
| 93 | inner: impl Peripheral<P = T> + 'd, | 93 | inner: impl Peripheral<P = T> + 'd, |
| 94 | a: Option<PeripheralRef<'d, AnyPin>>, | 94 | a: Option<PeripheralRef<'d, AnyPin>>, |
| @@ -114,8 +114,8 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 114 | } | 114 | } |
| 115 | Self { | 115 | Self { |
| 116 | inner, | 116 | inner, |
| 117 | pin_a: a.into(), | 117 | pin_a: a, |
| 118 | pin_b: b.into(), | 118 | pin_b: b, |
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | 121 | ||
| @@ -129,7 +129,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 129 | #[inline] | 129 | #[inline] |
| 130 | pub fn new_output_a( | 130 | pub fn new_output_a( |
| 131 | inner: impl Peripheral<P = T> + 'd, | 131 | inner: impl Peripheral<P = T> + 'd, |
| 132 | a: impl Peripheral<P = impl PwmPinA<T>> + 'd, | 132 | a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, |
| 133 | config: Config, | 133 | config: Config, |
| 134 | ) -> Self { | 134 | ) -> Self { |
| 135 | into_ref!(a); | 135 | into_ref!(a); |
| @@ -140,7 +140,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 140 | #[inline] | 140 | #[inline] |
| 141 | pub fn new_output_b( | 141 | pub fn new_output_b( |
| 142 | inner: impl Peripheral<P = T> + 'd, | 142 | inner: impl Peripheral<P = T> + 'd, |
| 143 | b: impl Peripheral<P = impl PwmPinB<T>> + 'd, | 143 | b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, |
| 144 | config: Config, | 144 | config: Config, |
| 145 | ) -> Self { | 145 | ) -> Self { |
| 146 | into_ref!(b); | 146 | into_ref!(b); |
| @@ -151,8 +151,8 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 151 | #[inline] | 151 | #[inline] |
| 152 | pub fn new_output_ab( | 152 | pub fn new_output_ab( |
| 153 | inner: impl Peripheral<P = T> + 'd, | 153 | inner: impl Peripheral<P = T> + 'd, |
| 154 | a: impl Peripheral<P = impl PwmPinA<T>> + 'd, | 154 | a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, |
| 155 | b: impl Peripheral<P = impl PwmPinB<T>> + 'd, | 155 | b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, |
| 156 | config: Config, | 156 | config: Config, |
| 157 | ) -> Self { | 157 | ) -> Self { |
| 158 | into_ref!(a, b); | 158 | into_ref!(a, b); |
| @@ -163,7 +163,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 163 | #[inline] | 163 | #[inline] |
| 164 | pub fn new_input( | 164 | pub fn new_input( |
| 165 | inner: impl Peripheral<P = T> + 'd, | 165 | inner: impl Peripheral<P = T> + 'd, |
| 166 | b: impl Peripheral<P = impl PwmPinB<T>> + 'd, | 166 | b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, |
| 167 | mode: InputMode, | 167 | mode: InputMode, |
| 168 | config: Config, | 168 | config: Config, |
| 169 | ) -> Self { | 169 | ) -> Self { |
| @@ -175,8 +175,8 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 175 | #[inline] | 175 | #[inline] |
| 176 | pub fn new_output_input( | 176 | pub fn new_output_input( |
| 177 | inner: impl Peripheral<P = T> + 'd, | 177 | inner: impl Peripheral<P = T> + 'd, |
| 178 | a: impl Peripheral<P = impl PwmPinA<T>> + 'd, | 178 | a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, |
| 179 | b: impl Peripheral<P = impl PwmPinB<T>> + 'd, | 179 | b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, |
| 180 | mode: InputMode, | 180 | mode: InputMode, |
| 181 | config: Config, | 181 | config: Config, |
| 182 | ) -> Self { | 182 | ) -> Self { |
| @@ -190,7 +190,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | fn configure(p: pac::pwm::Channel, config: &Config) { | 192 | fn configure(p: pac::pwm::Channel, config: &Config) { |
| 193 | if config.divider > FixedU16::<fixed::types::extra::U4>::from_bits(0xFF_F) { | 193 | if config.divider > FixedU16::<fixed::types::extra::U4>::from_bits(0xFFF) { |
| 194 | panic!("Requested divider is too large"); | 194 | panic!("Requested divider is too large"); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| @@ -265,18 +265,18 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 265 | } | 265 | } |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | /// Batch representation of PWM channels. | 268 | /// Batch representation of PWM slices. |
| 269 | pub struct PwmBatch(u32); | 269 | pub struct PwmBatch(u32); |
| 270 | 270 | ||
| 271 | impl PwmBatch { | 271 | impl PwmBatch { |
| 272 | #[inline] | 272 | #[inline] |
| 273 | /// Enable a PWM channel in this batch. | 273 | /// Enable a PWM slice in this batch. |
| 274 | pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) { | 274 | pub fn enable(&mut self, pwm: &Pwm<'_, impl Slice>) { |
| 275 | self.0 |= pwm.bit(); | 275 | self.0 |= pwm.bit(); |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | #[inline] | 278 | #[inline] |
| 279 | /// Enable channels in this batch in a PWM. | 279 | /// Enable slices in this batch in a PWM. |
| 280 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { | 280 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { |
| 281 | let mut en = PwmBatch(0); | 281 | let mut en = PwmBatch(0); |
| 282 | batch(&mut en); | 282 | batch(&mut en); |
| @@ -288,7 +288,7 @@ impl PwmBatch { | |||
| 288 | } | 288 | } |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | impl<'d, T: Channel> Drop for Pwm<'d, T> { | 291 | impl<'d, T: Slice> Drop for Pwm<'d, T> { |
| 292 | fn drop(&mut self) { | 292 | fn drop(&mut self) { |
| 293 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); | 293 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); |
| 294 | if let Some(pin) = &self.pin_a { | 294 | if let Some(pin) = &self.pin_a { |
| @@ -301,24 +301,24 @@ impl<'d, T: Channel> Drop for Pwm<'d, T> { | |||
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | mod sealed { | 303 | mod sealed { |
| 304 | pub trait Channel {} | 304 | pub trait Slice {} |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | /// PWM Channel. | 307 | /// PWM Slice. |
| 308 | pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static { | 308 | pub trait Slice: Peripheral<P = Self> + sealed::Slice + Sized + 'static { |
| 309 | /// Channel number. | 309 | /// Slice number. |
| 310 | fn number(&self) -> u8; | 310 | fn number(&self) -> u8; |
| 311 | 311 | ||
| 312 | /// Channel register block. | 312 | /// Slice register block. |
| 313 | fn regs(&self) -> pac::pwm::Channel { | 313 | fn regs(&self) -> pac::pwm::Channel { |
| 314 | pac::PWM.ch(self.number() as _) | 314 | pac::PWM.ch(self.number() as _) |
| 315 | } | 315 | } |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | macro_rules! channel { | 318 | macro_rules! slice { |
| 319 | ($name:ident, $num:expr) => { | 319 | ($name:ident, $num:expr) => { |
| 320 | impl sealed::Channel for peripherals::$name {} | 320 | impl sealed::Slice for peripherals::$name {} |
| 321 | impl Channel for peripherals::$name { | 321 | impl Slice for peripherals::$name { |
| 322 | fn number(&self) -> u8 { | 322 | fn number(&self) -> u8 { |
| 323 | $num | 323 | $num |
| 324 | } | 324 | } |
| @@ -326,19 +326,19 @@ macro_rules! channel { | |||
| 326 | }; | 326 | }; |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | channel!(PWM_CH0, 0); | 329 | slice!(PWM_SLICE0, 0); |
| 330 | channel!(PWM_CH1, 1); | 330 | slice!(PWM_SLICE1, 1); |
| 331 | channel!(PWM_CH2, 2); | 331 | slice!(PWM_SLICE2, 2); |
| 332 | channel!(PWM_CH3, 3); | 332 | slice!(PWM_SLICE3, 3); |
| 333 | channel!(PWM_CH4, 4); | 333 | slice!(PWM_SLICE4, 4); |
| 334 | channel!(PWM_CH5, 5); | 334 | slice!(PWM_SLICE5, 5); |
| 335 | channel!(PWM_CH6, 6); | 335 | slice!(PWM_SLICE6, 6); |
| 336 | channel!(PWM_CH7, 7); | 336 | slice!(PWM_SLICE7, 7); |
| 337 | 337 | ||
| 338 | /// PWM Pin A. | 338 | /// PWM Channel A. |
| 339 | pub trait PwmPinA<T: Channel>: GpioPin {} | 339 | pub trait ChannelAPin<T: Slice>: GpioPin {} |
| 340 | /// PWM Pin B. | 340 | /// PWM Channel B. |
| 341 | pub trait PwmPinB<T: Channel>: GpioPin {} | 341 | pub trait ChannelBPin<T: Slice>: GpioPin {} |
| 342 | 342 | ||
| 343 | macro_rules! impl_pin { | 343 | macro_rules! impl_pin { |
| 344 | ($pin:ident, $channel:ident, $kind:ident) => { | 344 | ($pin:ident, $channel:ident, $kind:ident) => { |
| @@ -346,33 +346,33 @@ macro_rules! impl_pin { | |||
| 346 | }; | 346 | }; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | impl_pin!(PIN_0, PWM_CH0, PwmPinA); | 349 | impl_pin!(PIN_0, PWM_SLICE0, ChannelAPin); |
| 350 | impl_pin!(PIN_1, PWM_CH0, PwmPinB); | 350 | impl_pin!(PIN_1, PWM_SLICE0, ChannelBPin); |
| 351 | impl_pin!(PIN_2, PWM_CH1, PwmPinA); | 351 | impl_pin!(PIN_2, PWM_SLICE1, ChannelAPin); |
| 352 | impl_pin!(PIN_3, PWM_CH1, PwmPinB); | 352 | impl_pin!(PIN_3, PWM_SLICE1, ChannelBPin); |
| 353 | impl_pin!(PIN_4, PWM_CH2, PwmPinA); | 353 | impl_pin!(PIN_4, PWM_SLICE2, ChannelAPin); |
| 354 | impl_pin!(PIN_5, PWM_CH2, PwmPinB); | 354 | impl_pin!(PIN_5, PWM_SLICE2, ChannelBPin); |
| 355 | impl_pin!(PIN_6, PWM_CH3, PwmPinA); | 355 | impl_pin!(PIN_6, PWM_SLICE3, ChannelAPin); |
| 356 | impl_pin!(PIN_7, PWM_CH3, PwmPinB); | 356 | impl_pin!(PIN_7, PWM_SLICE3, ChannelBPin); |
| 357 | impl_pin!(PIN_8, PWM_CH4, PwmPinA); | 357 | impl_pin!(PIN_8, PWM_SLICE4, ChannelAPin); |
| 358 | impl_pin!(PIN_9, PWM_CH4, PwmPinB); | 358 | impl_pin!(PIN_9, PWM_SLICE4, ChannelBPin); |
| 359 | impl_pin!(PIN_10, PWM_CH5, PwmPinA); | 359 | impl_pin!(PIN_10, PWM_SLICE5, ChannelAPin); |
| 360 | impl_pin!(PIN_11, PWM_CH5, PwmPinB); | 360 | impl_pin!(PIN_11, PWM_SLICE5, ChannelBPin); |
| 361 | impl_pin!(PIN_12, PWM_CH6, PwmPinA); | 361 | impl_pin!(PIN_12, PWM_SLICE6, ChannelAPin); |
| 362 | impl_pin!(PIN_13, PWM_CH6, PwmPinB); | 362 | impl_pin!(PIN_13, PWM_SLICE6, ChannelBPin); |
| 363 | impl_pin!(PIN_14, PWM_CH7, PwmPinA); | 363 | impl_pin!(PIN_14, PWM_SLICE7, ChannelAPin); |
| 364 | impl_pin!(PIN_15, PWM_CH7, PwmPinB); | 364 | impl_pin!(PIN_15, PWM_SLICE7, ChannelBPin); |
| 365 | impl_pin!(PIN_16, PWM_CH0, PwmPinA); | 365 | impl_pin!(PIN_16, PWM_SLICE0, ChannelAPin); |
| 366 | impl_pin!(PIN_17, PWM_CH0, PwmPinB); | 366 | impl_pin!(PIN_17, PWM_SLICE0, ChannelBPin); |
| 367 | impl_pin!(PIN_18, PWM_CH1, PwmPinA); | 367 | impl_pin!(PIN_18, PWM_SLICE1, ChannelAPin); |
| 368 | impl_pin!(PIN_19, PWM_CH1, PwmPinB); | 368 | impl_pin!(PIN_19, PWM_SLICE1, ChannelBPin); |
| 369 | impl_pin!(PIN_20, PWM_CH2, PwmPinA); | 369 | impl_pin!(PIN_20, PWM_SLICE2, ChannelAPin); |
| 370 | impl_pin!(PIN_21, PWM_CH2, PwmPinB); | 370 | impl_pin!(PIN_21, PWM_SLICE2, ChannelBPin); |
| 371 | impl_pin!(PIN_22, PWM_CH3, PwmPinA); | 371 | impl_pin!(PIN_22, PWM_SLICE3, ChannelAPin); |
| 372 | impl_pin!(PIN_23, PWM_CH3, PwmPinB); | 372 | impl_pin!(PIN_23, PWM_SLICE3, ChannelBPin); |
| 373 | impl_pin!(PIN_24, PWM_CH4, PwmPinA); | 373 | impl_pin!(PIN_24, PWM_SLICE4, ChannelAPin); |
| 374 | impl_pin!(PIN_25, PWM_CH4, PwmPinB); | 374 | impl_pin!(PIN_25, PWM_SLICE4, ChannelBPin); |
| 375 | impl_pin!(PIN_26, PWM_CH5, PwmPinA); | 375 | impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin); |
| 376 | impl_pin!(PIN_27, PWM_CH5, PwmPinB); | 376 | impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin); |
| 377 | impl_pin!(PIN_28, PWM_CH6, PwmPinA); | 377 | impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin); |
| 378 | impl_pin!(PIN_29, PWM_CH6, PwmPinB); | 378 | impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin); |
diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs index b35b4ed72..34487819f 100644 --- a/embassy-rp/src/relocate.rs +++ b/embassy-rp/src/relocate.rs | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | use core::iter::Iterator; | ||
| 2 | |||
| 3 | use pio::{Program, SideSet, Wrap}; | 1 | use pio::{Program, SideSet, Wrap}; |
| 4 | 2 | ||
| 5 | pub struct CodeIterator<'a, I> | 3 | pub struct CodeIterator<'a, I> |
| @@ -22,15 +20,15 @@ where | |||
| 22 | { | 20 | { |
| 23 | type Item = u16; | 21 | type Item = u16; |
| 24 | fn next(&mut self) -> Option<Self::Item> { | 22 | fn next(&mut self) -> Option<Self::Item> { |
| 25 | self.iter.next().and_then(|&instr| { | 23 | self.iter.next().map(|&instr| { |
| 26 | Some(if instr & 0b1110_0000_0000_0000 == 0 { | 24 | if instr & 0b1110_0000_0000_0000 == 0 { |
| 27 | // this is a JMP instruction -> add offset to address | 25 | // this is a JMP instruction -> add offset to address |
| 28 | let address = (instr & 0b1_1111) as u8; | 26 | let address = (instr & 0b1_1111) as u8; |
| 29 | let address = address.wrapping_add(self.offset) % 32; | 27 | let address = address.wrapping_add(self.offset) % 32; |
| 30 | instr & (!0b11111) | address as u16 | 28 | instr & (!0b11111) | address as u16 |
| 31 | } else { | 29 | } else { |
| 32 | instr | 30 | instr |
| 33 | }) | 31 | } |
| 34 | }) | 32 | }) |
| 35 | } | 33 | } |
| 36 | } | 34 | } |
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index b696989f5..c8691bdc2 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs | |||
| @@ -29,8 +29,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 29 | // Set the RTC divider | 29 | // Set the RTC divider |
| 30 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); | 30 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); |
| 31 | 31 | ||
| 32 | let result = Self { inner }; | 32 | Self { inner } |
| 33 | result | ||
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. | 35 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 99c958129..da1157984 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -1,17 +1,11 @@ | |||
| 1 | //! Buffered UART driver. | 1 | //! Buffered UART driver. |
| 2 | use core::future::{poll_fn, Future}; | 2 | use core::future::Future; |
| 3 | use core::slice; | 3 | use core::slice; |
| 4 | use core::task::Poll; | ||
| 5 | 4 | ||
| 6 | use atomic_polyfill::{AtomicU8, Ordering}; | 5 | use atomic_polyfill::AtomicU8; |
| 7 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | 7 | ||
| 11 | use super::*; | 8 | use super::*; |
| 12 | use crate::clocks::clk_peri_freq; | ||
| 13 | use crate::interrupt::typelevel::{Binding, Interrupt}; | ||
| 14 | use crate::{interrupt, RegExt}; | ||
| 15 | 9 | ||
| 16 | pub struct State { | 10 | pub struct State { |
| 17 | tx_waker: AtomicWaker, | 11 | tx_waker: AtomicWaker, |
| @@ -467,7 +461,7 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | |||
| 467 | 461 | ||
| 468 | // TX is inactive if the the buffer is not available. | 462 | // TX is inactive if the the buffer is not available. |
| 469 | // We can now unregister the interrupt handler | 463 | // We can now unregister the interrupt handler |
| 470 | if state.tx_buf.len() == 0 { | 464 | if state.tx_buf.is_empty() { |
| 471 | T::Interrupt::disable(); | 465 | T::Interrupt::disable(); |
| 472 | } | 466 | } |
| 473 | } | 467 | } |
| @@ -480,7 +474,7 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { | |||
| 480 | 474 | ||
| 481 | // RX is inactive if the the buffer is not available. | 475 | // RX is inactive if the the buffer is not available. |
| 482 | // We can now unregister the interrupt handler | 476 | // We can now unregister the interrupt handler |
| 483 | if state.rx_buf.len() == 0 { | 477 | if state.rx_buf.is_empty() { |
| 484 | T::Interrupt::disable(); | 478 | T::Interrupt::disable(); |
| 485 | } | 479 | } |
| 486 | } | 480 | } |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index f372cb640..65dcf4eb4 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -322,7 +322,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 322 | 322 | ||
| 323 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { | 323 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { |
| 324 | fn drop(&mut self) { | 324 | fn drop(&mut self) { |
| 325 | if let Some(_) = self.rx_dma { | 325 | if self.rx_dma.is_some() { |
| 326 | T::Interrupt::disable(); | 326 | T::Interrupt::disable(); |
| 327 | // clear dma flags. irq handlers use these to disambiguate among themselves. | 327 | // clear dma flags. irq handlers use these to disambiguate among themselves. |
| 328 | T::regs().uartdmacr().write_clear(|reg| { | 328 | T::regs().uartdmacr().write_clear(|reg| { |
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 905661d64..d68dee4a3 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs | |||
| @@ -465,7 +465,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 465 | 465 | ||
| 466 | trait Dir { | 466 | trait Dir { |
| 467 | fn dir() -> Direction; | 467 | fn dir() -> Direction; |
| 468 | fn waker(i: usize) -> &'static AtomicWaker; | ||
| 469 | } | 468 | } |
| 470 | 469 | ||
| 471 | /// Type for In direction. | 470 | /// Type for In direction. |
| @@ -474,11 +473,6 @@ impl Dir for In { | |||
| 474 | fn dir() -> Direction { | 473 | fn dir() -> Direction { |
| 475 | Direction::In | 474 | Direction::In |
| 476 | } | 475 | } |
| 477 | |||
| 478 | #[inline] | ||
| 479 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 480 | &EP_IN_WAKERS[i] | ||
| 481 | } | ||
| 482 | } | 476 | } |
| 483 | 477 | ||
| 484 | /// Type for Out direction. | 478 | /// Type for Out direction. |
| @@ -487,11 +481,6 @@ impl Dir for Out { | |||
| 487 | fn dir() -> Direction { | 481 | fn dir() -> Direction { |
| 488 | Direction::Out | 482 | Direction::Out |
| 489 | } | 483 | } |
| 490 | |||
| 491 | #[inline] | ||
| 492 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 493 | &EP_OUT_WAKERS[i] | ||
| 494 | } | ||
| 495 | } | 484 | } |
| 496 | 485 | ||
| 497 | /// Endpoint for RP USB driver. | 486 | /// Endpoint for RP USB driver. |
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index bd70851ea..6aaef1d35 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | use core::convert::TryFrom; | ||
| 2 | |||
| 3 | use crate::evt::CsEvt; | 1 | use crate::evt::CsEvt; |
| 4 | use crate::PacketHeader; | 2 | use crate::PacketHeader; |
| 5 | 3 | ||
diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-stm32-wpan/src/fmt.rs +++ b/embassy-stm32-wpan/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 158c630b9..d00e7aa55 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -71,8 +71,8 @@ sdio-host = "0.5.0" | |||
| 71 | critical-section = "1.1" | 71 | critical-section = "1.1" |
| 72 | #stm32-metapac = { version = "15" } | 72 | #stm32-metapac = { version = "15" } |
| 73 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739" } | 73 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739" } |
| 74 | |||
| 74 | vcell = "0.1.3" | 75 | vcell = "0.1.3" |
| 75 | bxcan = "0.7.0" | ||
| 76 | nb = "1.0.0" | 76 | nb = "1.0.0" |
| 77 | stm32-fmc = "0.3.0" | 77 | stm32-fmc = "0.3.0" |
| 78 | cfg-if = "1.0.0" | 78 | cfg-if = "1.0.0" |
| @@ -84,6 +84,7 @@ document-features = "0.2.7" | |||
| 84 | 84 | ||
| 85 | static_assertions = { version = "1.1" } | 85 | static_assertions = { version = "1.1" } |
| 86 | volatile-register = { version = "0.2.1" } | 86 | volatile-register = { version = "0.2.1" } |
| 87 | bitflags = "2.4.2" | ||
| 87 | 88 | ||
| 88 | 89 | ||
| 89 | 90 | ||
| @@ -97,7 +98,6 @@ quote = "1.0.15" | |||
| 97 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 98 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 98 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739", default-features = false, features = ["metadata"]} | 99 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739", default-features = false, features = ["metadata"]} |
| 99 | 100 | ||
| 100 | |||
| 101 | [features] | 101 | [features] |
| 102 | default = ["rt"] | 102 | default = ["rt"] |
| 103 | 103 | ||
| @@ -105,7 +105,7 @@ default = ["rt"] | |||
| 105 | rt = ["stm32-metapac/rt"] | 105 | rt = ["stm32-metapac/rt"] |
| 106 | 106 | ||
| 107 | ## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging | 107 | ## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging |
| 108 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] | 108 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] |
| 109 | 109 | ||
| 110 | exti = [] | 110 | exti = [] |
| 111 | low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] | 111 | low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6217a3309..129c5df76 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -509,25 +509,20 @@ fn main() { | |||
| 509 | if let Some(rcc) = &p.rcc { | 509 | if let Some(rcc) = &p.rcc { |
| 510 | let en = rcc.enable.as_ref().unwrap(); | 510 | let en = rcc.enable.as_ref().unwrap(); |
| 511 | 511 | ||
| 512 | let rst = match &rcc.reset { | 512 | let (start_rst, end_rst) = match &rcc.reset { |
| 513 | Some(rst) => { | 513 | Some(rst) => { |
| 514 | let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); | 514 | let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); |
| 515 | let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); | 515 | let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); |
| 516 | quote! { | 516 | ( |
| 517 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); | 517 | quote! { |
| 518 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); | 518 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); |
| 519 | } | 519 | }, |
| 520 | quote! { | ||
| 521 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); | ||
| 522 | }, | ||
| 523 | ) | ||
| 520 | } | 524 | } |
| 521 | None => TokenStream::new(), | 525 | None => (TokenStream::new(), TokenStream::new()), |
| 522 | }; | ||
| 523 | |||
| 524 | let after_enable = if chip_name.starts_with("stm32f2") { | ||
| 525 | // Errata: ES0005 - 2.1.11 Delay after an RCC peripheral clock enabling | ||
| 526 | quote! { | ||
| 527 | cortex_m::asm::dsb(); | ||
| 528 | } | ||
| 529 | } else { | ||
| 530 | TokenStream::new() | ||
| 531 | }; | 526 | }; |
| 532 | 527 | ||
| 533 | let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; | 528 | let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; |
| @@ -589,16 +584,29 @@ fn main() { | |||
| 589 | }; | 584 | }; |
| 590 | 585 | ||
| 591 | g.extend(quote! { | 586 | g.extend(quote! { |
| 592 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { | 587 | impl crate::rcc::SealedRccPeripheral for peripherals::#pname { |
| 593 | fn frequency() -> crate::time::Hertz { | 588 | fn frequency() -> crate::time::Hertz { |
| 594 | #clock_frequency | 589 | #clock_frequency |
| 595 | } | 590 | } |
| 596 | fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { | 591 | fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { |
| 597 | #before_enable | 592 | #before_enable |
| 598 | #incr_stop_refcount | 593 | #incr_stop_refcount |
| 594 | |||
| 595 | #start_rst | ||
| 596 | |||
| 599 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | 597 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); |
| 600 | #after_enable | 598 | |
| 601 | #rst | 599 | // we must wait two peripheral clock cycles before the clock is active |
| 600 | // this seems to work, but might be incorrect | ||
| 601 | // see http://efton.sk/STM32/gotcha/g183.html | ||
| 602 | |||
| 603 | // dummy read (like in the ST HALs) | ||
| 604 | let _ = crate::pac::RCC.#en_reg().read(); | ||
| 605 | |||
| 606 | // DSB for good measure | ||
| 607 | cortex_m::asm::dsb(); | ||
| 608 | |||
| 609 | #end_rst | ||
| 602 | } | 610 | } |
| 603 | fn disable_with_cs(_cs: critical_section::CriticalSection) { | 611 | fn disable_with_cs(_cs: critical_section::CriticalSection) { |
| 604 | #before_disable | 612 | #before_disable |
| @@ -764,6 +772,8 @@ fn main() { | |||
| 764 | #[rustfmt::skip] | 772 | #[rustfmt::skip] |
| 765 | let signals: HashMap<_, _> = [ | 773 | let signals: HashMap<_, _> = [ |
| 766 | // (kind, signal) => trait | 774 | // (kind, signal) => trait |
| 775 | (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)), | ||
| 776 | (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)), | ||
| 767 | (("usart", "TX"), quote!(crate::usart::TxPin)), | 777 | (("usart", "TX"), quote!(crate::usart::TxPin)), |
| 768 | (("usart", "RX"), quote!(crate::usart::RxPin)), | 778 | (("usart", "RX"), quote!(crate::usart::RxPin)), |
| 769 | (("usart", "CTS"), quote!(crate::usart::CtsPin)), | 779 | (("usart", "CTS"), quote!(crate::usart::CtsPin)), |
| @@ -816,20 +826,20 @@ fn main() { | |||
| 816 | (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), | 826 | (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), |
| 817 | (("usb", "DP"), quote!(crate::usb::DpPin)), | 827 | (("usb", "DP"), quote!(crate::usb::DpPin)), |
| 818 | (("usb", "DM"), quote!(crate::usb::DmPin)), | 828 | (("usb", "DM"), quote!(crate::usb::DmPin)), |
| 819 | (("otg", "DP"), quote!(crate::usb_otg::DpPin)), | 829 | (("otg", "DP"), quote!(crate::usb::DpPin)), |
| 820 | (("otg", "DM"), quote!(crate::usb_otg::DmPin)), | 830 | (("otg", "DM"), quote!(crate::usb::DmPin)), |
| 821 | (("otg", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)), | 831 | (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)), |
| 822 | (("otg", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)), | 832 | (("otg", "ULPI_DIR"), quote!(crate::usb::UlpiDirPin)), |
| 823 | (("otg", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)), | 833 | (("otg", "ULPI_NXT"), quote!(crate::usb::UlpiNxtPin)), |
| 824 | (("otg", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)), | 834 | (("otg", "ULPI_STP"), quote!(crate::usb::UlpiStpPin)), |
| 825 | (("otg", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)), | 835 | (("otg", "ULPI_D0"), quote!(crate::usb::UlpiD0Pin)), |
| 826 | (("otg", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)), | 836 | (("otg", "ULPI_D1"), quote!(crate::usb::UlpiD1Pin)), |
| 827 | (("otg", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)), | 837 | (("otg", "ULPI_D2"), quote!(crate::usb::UlpiD2Pin)), |
| 828 | (("otg", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)), | 838 | (("otg", "ULPI_D3"), quote!(crate::usb::UlpiD3Pin)), |
| 829 | (("otg", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)), | 839 | (("otg", "ULPI_D4"), quote!(crate::usb::UlpiD4Pin)), |
| 830 | (("otg", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)), | 840 | (("otg", "ULPI_D5"), quote!(crate::usb::UlpiD5Pin)), |
| 831 | (("otg", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)), | 841 | (("otg", "ULPI_D6"), quote!(crate::usb::UlpiD6Pin)), |
| 832 | (("otg", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)), | 842 | (("otg", "ULPI_D7"), quote!(crate::usb::UlpiD7Pin)), |
| 833 | (("can", "TX"), quote!(crate::can::TxPin)), | 843 | (("can", "TX"), quote!(crate::can::TxPin)), |
| 834 | (("can", "RX"), quote!(crate::can::RxPin)), | 844 | (("can", "RX"), quote!(crate::can::RxPin)), |
| 835 | (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), | 845 | (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), |
| @@ -1114,6 +1124,8 @@ fn main() { | |||
| 1114 | 1124 | ||
| 1115 | let signals: HashMap<_, _> = [ | 1125 | let signals: HashMap<_, _> = [ |
| 1116 | // (kind, signal) => trait | 1126 | // (kind, signal) => trait |
| 1127 | (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), | ||
| 1128 | (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), | ||
| 1117 | (("usart", "RX"), quote!(crate::usart::RxDma)), | 1129 | (("usart", "RX"), quote!(crate::usart::RxDma)), |
| 1118 | (("usart", "TX"), quote!(crate::usart::TxDma)), | 1130 | (("usart", "TX"), quote!(crate::usart::TxDma)), |
| 1119 | (("lpuart", "RX"), quote!(crate::usart::RxDma)), | 1131 | (("lpuart", "RX"), quote!(crate::usart::RxDma)), |
| @@ -1134,6 +1146,8 @@ fn main() { | |||
| 1134 | (("dac", "CH2"), quote!(crate::dac::DacDma2)), | 1146 | (("dac", "CH2"), quote!(crate::dac::DacDma2)), |
| 1135 | (("timer", "UP"), quote!(crate::timer::UpDma)), | 1147 | (("timer", "UP"), quote!(crate::timer::UpDma)), |
| 1136 | (("hash", "IN"), quote!(crate::hash::Dma)), | 1148 | (("hash", "IN"), quote!(crate::hash::Dma)), |
| 1149 | (("cryp", "IN"), quote!(crate::cryp::DmaIn)), | ||
| 1150 | (("cryp", "OUT"), quote!(crate::cryp::DmaOut)), | ||
| 1137 | (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), | 1151 | (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), |
| 1138 | (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), | 1152 | (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), |
| 1139 | (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), | 1153 | (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), |
| @@ -1485,7 +1499,7 @@ fn main() { | |||
| 1485 | #[crate::interrupt] | 1499 | #[crate::interrupt] |
| 1486 | unsafe fn #irq () { | 1500 | unsafe fn #irq () { |
| 1487 | #( | 1501 | #( |
| 1488 | <crate::peripherals::#channels as crate::dma::sealed::ChannelInterrupt>::on_irq(); | 1502 | <crate::peripherals::#channels as crate::dma::ChannelInterrupt>::on_irq(); |
| 1489 | )* | 1503 | )* |
| 1490 | } | 1504 | } |
| 1491 | } | 1505 | } |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index b27b99827..cecf67947 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -33,7 +33,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 33 | 33 | ||
| 34 | pub struct Vref; | 34 | pub struct Vref; |
| 35 | impl<T: Instance> AdcPin<T> for Vref {} | 35 | impl<T: Instance> AdcPin<T> for Vref {} |
| 36 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 36 | impl<T: Instance> super::SealedAdcPin<T> for Vref { |
| 37 | fn channel(&self) -> u8 { | 37 | fn channel(&self) -> u8 { |
| 38 | 17 | 38 | 17 |
| 39 | } | 39 | } |
| @@ -41,7 +41,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vref { | |||
| 41 | 41 | ||
| 42 | pub struct Temperature; | 42 | pub struct Temperature; |
| 43 | impl<T: Instance> AdcPin<T> for Temperature {} | 43 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 44 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 44 | impl<T: Instance> super::SealedAdcPin<T> for Temperature { |
| 45 | fn channel(&self) -> u8 { | 45 | fn channel(&self) -> u8 { |
| 46 | 16 | 46 | 16 |
| 47 | } | 47 | } |
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index efade1f64..c5581dba1 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs | |||
| @@ -33,7 +33,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 33 | 33 | ||
| 34 | pub struct Vref; | 34 | pub struct Vref; |
| 35 | impl<T: Instance> AdcPin<T> for Vref {} | 35 | impl<T: Instance> AdcPin<T> for Vref {} |
| 36 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 36 | impl<T: Instance> super::SealedAdcPin<T> for Vref { |
| 37 | fn channel(&self) -> u8 { | 37 | fn channel(&self) -> u8 { |
| 38 | 18 | 38 | 18 |
| 39 | } | 39 | } |
| @@ -48,7 +48,7 @@ impl Vref { | |||
| 48 | 48 | ||
| 49 | pub struct Temperature; | 49 | pub struct Temperature; |
| 50 | impl<T: Instance> AdcPin<T> for Temperature {} | 50 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 51 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 51 | impl<T: Instance> super::SealedAdcPin<T> for Temperature { |
| 52 | fn channel(&self) -> u8 { | 52 | fn channel(&self) -> u8 { |
| 53 | 16 | 53 | 16 |
| 54 | } | 54 | } |
| @@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | fn freq() -> Hertz { | 104 | fn freq() -> Hertz { |
| 105 | <T as crate::rcc::sealed::RccPeripheral>::frequency() | 105 | <T as crate::rcc::SealedRccPeripheral>::frequency() |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | 108 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { |
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index f842893fa..672ace04f 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs | |||
| @@ -65,7 +65,7 @@ fn update_vref<T: Instance>(op: i8) { | |||
| 65 | 65 | ||
| 66 | pub struct Vref<T: Instance>(core::marker::PhantomData<T>); | 66 | pub struct Vref<T: Instance>(core::marker::PhantomData<T>); |
| 67 | impl<T: Instance> AdcPin<T> for Vref<T> {} | 67 | impl<T: Instance> AdcPin<T> for Vref<T> {} |
| 68 | impl<T: Instance> super::sealed::AdcPin<T> for Vref<T> { | 68 | impl<T: Instance> super::SealedAdcPin<T> for Vref<T> { |
| 69 | fn channel(&self) -> u8 { | 69 | fn channel(&self) -> u8 { |
| 70 | 17 | 70 | 17 |
| 71 | } | 71 | } |
| @@ -124,7 +124,7 @@ impl<T: Instance> Drop for Vref<T> { | |||
| 124 | 124 | ||
| 125 | pub struct Temperature<T: Instance>(core::marker::PhantomData<T>); | 125 | pub struct Temperature<T: Instance>(core::marker::PhantomData<T>); |
| 126 | impl<T: Instance> AdcPin<T> for Temperature<T> {} | 126 | impl<T: Instance> AdcPin<T> for Temperature<T> {} |
| 127 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature<T> { | 127 | impl<T: Instance> super::SealedAdcPin<T> for Temperature<T> { |
| 128 | fn channel(&self) -> u8 { | 128 | fn channel(&self) -> u8 { |
| 129 | 16 | 129 | 16 |
| 130 | } | 130 | } |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0d0d40549..ead2357ce 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -17,6 +17,8 @@ mod _version; | |||
| 17 | #[allow(unused)] | 17 | #[allow(unused)] |
| 18 | #[cfg(not(adc_f3_v2))] | 18 | #[cfg(not(adc_f3_v2))] |
| 19 | pub use _version::*; | 19 | pub use _version::*; |
| 20 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | ||
| 21 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 20 | 22 | ||
| 21 | #[cfg(not(any(adc_f1, adc_f3_v2)))] | 23 | #[cfg(not(any(adc_f1, adc_f3_v2)))] |
| 22 | pub use crate::pac::adc::vals::Res as Resolution; | 24 | pub use crate::pac::adc::vals::Res as Resolution; |
| @@ -31,63 +33,65 @@ pub struct Adc<'d, T: Instance> { | |||
| 31 | sample_time: SampleTime, | 33 | sample_time: SampleTime, |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | pub(crate) mod sealed { | 36 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 35 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 37 | pub struct State { |
| 36 | use embassy_sync::waitqueue::AtomicWaker; | 38 | pub waker: AtomicWaker, |
| 37 | 39 | } | |
| 38 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | ||
| 39 | pub struct State { | ||
| 40 | pub waker: AtomicWaker, | ||
| 41 | } | ||
| 42 | 40 | ||
| 43 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 41 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 44 | impl State { | 42 | impl State { |
| 45 | pub const fn new() -> Self { | 43 | pub const fn new() -> Self { |
| 46 | Self { | 44 | Self { |
| 47 | waker: AtomicWaker::new(), | 45 | waker: AtomicWaker::new(), |
| 48 | } | ||
| 49 | } | 46 | } |
| 50 | } | 47 | } |
| 48 | } | ||
| 51 | 49 | ||
| 52 | pub trait InterruptableInstance { | 50 | trait SealedInstance { |
| 53 | type Interrupt: crate::interrupt::typelevel::Interrupt; | 51 | #[allow(unused)] |
| 54 | } | 52 | fn regs() -> crate::pac::adc::Adc; |
| 55 | 53 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | |
| 56 | pub trait Instance: InterruptableInstance { | 54 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 57 | fn regs() -> crate::pac::adc::Adc; | 55 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 58 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 56 | fn state() -> &'static State; |
| 59 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 57 | } |
| 60 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | ||
| 61 | fn state() -> &'static State; | ||
| 62 | } | ||
| 63 | 58 | ||
| 64 | pub trait AdcPin<T: Instance> { | 59 | pub(crate) trait SealedAdcPin<T: Instance> { |
| 65 | #[cfg(any(adc_v1, adc_l0, adc_v2))] | 60 | #[cfg(any(adc_v1, adc_l0, adc_v2))] |
| 66 | fn set_as_analog(&mut self) {} | 61 | fn set_as_analog(&mut self) {} |
| 67 | 62 | ||
| 68 | fn channel(&self) -> u8; | 63 | #[allow(unused)] |
| 69 | } | 64 | fn channel(&self) -> u8; |
| 65 | } | ||
| 70 | 66 | ||
| 71 | pub trait InternalChannel<T> { | 67 | trait SealedInternalChannel<T> { |
| 72 | fn channel(&self) -> u8; | 68 | #[allow(unused)] |
| 73 | } | 69 | fn channel(&self) -> u8; |
| 74 | } | 70 | } |
| 75 | 71 | ||
| 76 | /// ADC instance. | 72 | /// ADC instance. |
| 77 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))] | 73 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))] |
| 78 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 74 | #[allow(private_bounds)] |
| 75 | pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { | ||
| 76 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 77 | } | ||
| 79 | /// ADC instance. | 78 | /// ADC instance. |
| 80 | #[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))] | 79 | #[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))] |
| 81 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 80 | #[allow(private_bounds)] |
| 81 | pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { | ||
| 82 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 83 | } | ||
| 82 | 84 | ||
| 83 | /// ADC pin. | 85 | /// ADC pin. |
| 84 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 86 | #[allow(private_bounds)] |
| 87 | pub trait AdcPin<T: Instance>: SealedAdcPin<T> {} | ||
| 85 | /// ADC internal channel. | 88 | /// ADC internal channel. |
| 86 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} | 89 | #[allow(private_bounds)] |
| 90 | pub trait InternalChannel<T>: SealedInternalChannel<T> {} | ||
| 87 | 91 | ||
| 88 | foreach_adc!( | 92 | foreach_adc!( |
| 89 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 93 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 90 | impl crate::adc::sealed::Instance for peripherals::$inst { | 94 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 91 | fn regs() -> crate::pac::adc::Adc { | 95 | fn regs() -> crate::pac::adc::Adc { |
| 92 | crate::pac::$inst | 96 | crate::pac::$inst |
| 93 | } | 97 | } |
| @@ -98,21 +102,15 @@ foreach_adc!( | |||
| 98 | } | 102 | } |
| 99 | 103 | ||
| 100 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 104 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 101 | fn state() -> &'static sealed::State { | 105 | fn state() -> &'static State { |
| 102 | static STATE: sealed::State = sealed::State::new(); | 106 | static STATE: State = State::new(); |
| 103 | &STATE | 107 | &STATE |
| 104 | } | 108 | } |
| 105 | } | 109 | } |
| 106 | 110 | ||
| 107 | foreach_interrupt!( | 111 | impl crate::adc::Instance for peripherals::$inst { |
| 108 | ($inst,adc,ADC,GLOBAL,$irq:ident) => { | 112 | type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL; |
| 109 | impl sealed::InterruptableInstance for peripherals::$inst { | 113 | } |
| 110 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 111 | } | ||
| 112 | }; | ||
| 113 | ); | ||
| 114 | |||
| 115 | impl crate::adc::Instance for peripherals::$inst {} | ||
| 116 | }; | 114 | }; |
| 117 | ); | 115 | ); |
| 118 | 116 | ||
| @@ -120,10 +118,10 @@ macro_rules! impl_adc_pin { | |||
| 120 | ($inst:ident, $pin:ident, $ch:expr) => { | 118 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 121 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} | 119 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 122 | 120 | ||
| 123 | impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { | 121 | impl crate::adc::SealedAdcPin<peripherals::$inst> for crate::peripherals::$pin { |
| 124 | #[cfg(any(adc_v1, adc_l0, adc_v2))] | 122 | #[cfg(any(adc_v1, adc_l0, adc_v2))] |
| 125 | fn set_as_analog(&mut self) { | 123 | fn set_as_analog(&mut self) { |
| 126 | <Self as crate::gpio::sealed::Pin>::set_as_analog(self); | 124 | <Self as crate::gpio::SealedPin>::set_as_analog(self); |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | fn channel(&self) -> u8 { | 127 | fn channel(&self) -> u8 { |
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index a8dc6ce98..e9b46be80 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -39,7 +39,7 @@ pub struct Vbat; | |||
| 39 | impl AdcPin<ADC> for Vbat {} | 39 | impl AdcPin<ADC> for Vbat {} |
| 40 | 40 | ||
| 41 | #[cfg(not(adc_l0))] | 41 | #[cfg(not(adc_l0))] |
| 42 | impl super::sealed::AdcPin<ADC> for Vbat { | 42 | impl super::SealedAdcPin<ADC> for Vbat { |
| 43 | fn channel(&self) -> u8 { | 43 | fn channel(&self) -> u8 { |
| 44 | 18 | 44 | 18 |
| 45 | } | 45 | } |
| @@ -47,7 +47,7 @@ impl super::sealed::AdcPin<ADC> for Vbat { | |||
| 47 | 47 | ||
| 48 | pub struct Vref; | 48 | pub struct Vref; |
| 49 | impl AdcPin<ADC> for Vref {} | 49 | impl AdcPin<ADC> for Vref {} |
| 50 | impl super::sealed::AdcPin<ADC> for Vref { | 50 | impl super::SealedAdcPin<ADC> for Vref { |
| 51 | fn channel(&self) -> u8 { | 51 | fn channel(&self) -> u8 { |
| 52 | 17 | 52 | 17 |
| 53 | } | 53 | } |
| @@ -55,7 +55,7 @@ impl super::sealed::AdcPin<ADC> for Vref { | |||
| 55 | 55 | ||
| 56 | pub struct Temperature; | 56 | pub struct Temperature; |
| 57 | impl AdcPin<ADC> for Temperature {} | 57 | impl AdcPin<ADC> for Temperature {} |
| 58 | impl super::sealed::AdcPin<ADC> for Temperature { | 58 | impl super::SealedAdcPin<ADC> for Temperature { |
| 59 | fn channel(&self) -> u8 { | 59 | fn channel(&self) -> u8 { |
| 60 | 16 | 60 | 16 |
| 61 | } | 61 | } |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index f6f7dbfcc..a43eb72db 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -16,7 +16,7 @@ pub const ADC_POWERUP_TIME_US: u32 = 3; | |||
| 16 | 16 | ||
| 17 | pub struct VrefInt; | 17 | pub struct VrefInt; |
| 18 | impl AdcPin<ADC1> for VrefInt {} | 18 | impl AdcPin<ADC1> for VrefInt {} |
| 19 | impl super::sealed::AdcPin<ADC1> for VrefInt { | 19 | impl super::SealedAdcPin<ADC1> for VrefInt { |
| 20 | fn channel(&self) -> u8 { | 20 | fn channel(&self) -> u8 { |
| 21 | 17 | 21 | 17 |
| 22 | } | 22 | } |
| @@ -31,7 +31,7 @@ impl VrefInt { | |||
| 31 | 31 | ||
| 32 | pub struct Temperature; | 32 | pub struct Temperature; |
| 33 | impl AdcPin<ADC1> for Temperature {} | 33 | impl AdcPin<ADC1> for Temperature {} |
| 34 | impl super::sealed::AdcPin<ADC1> for Temperature { | 34 | impl super::SealedAdcPin<ADC1> for Temperature { |
| 35 | fn channel(&self) -> u8 { | 35 | fn channel(&self) -> u8 { |
| 36 | cfg_if::cfg_if! { | 36 | cfg_if::cfg_if! { |
| 37 | if #[cfg(any(stm32f2, stm32f40, stm32f41))] { | 37 | if #[cfg(any(stm32f2, stm32f40, stm32f41))] { |
| @@ -52,7 +52,7 @@ impl Temperature { | |||
| 52 | 52 | ||
| 53 | pub struct Vbat; | 53 | pub struct Vbat; |
| 54 | impl AdcPin<ADC1> for Vbat {} | 54 | impl AdcPin<ADC1> for Vbat {} |
| 55 | impl super::sealed::AdcPin<ADC1> for Vbat { | 55 | impl super::SealedAdcPin<ADC1> for Vbat { |
| 56 | fn channel(&self) -> u8 { | 56 | fn channel(&self) -> u8 { |
| 57 | 18 | 57 | 18 |
| 58 | } | 58 | } |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 5f3512cad..8c9b47197 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | |||
| 12 | 12 | ||
| 13 | pub struct VrefInt; | 13 | pub struct VrefInt; |
| 14 | impl<T: Instance> AdcPin<T> for VrefInt {} | 14 | impl<T: Instance> AdcPin<T> for VrefInt {} |
| 15 | impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { | 15 | impl<T: Instance> super::SealedAdcPin<T> for VrefInt { |
| 16 | fn channel(&self) -> u8 { | 16 | fn channel(&self) -> u8 { |
| 17 | cfg_if! { | 17 | cfg_if! { |
| 18 | if #[cfg(adc_g0)] { | 18 | if #[cfg(adc_g0)] { |
| @@ -29,7 +29,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { | |||
| 29 | 29 | ||
| 30 | pub struct Temperature; | 30 | pub struct Temperature; |
| 31 | impl<T: Instance> AdcPin<T> for Temperature {} | 31 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 32 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 32 | impl<T: Instance> super::SealedAdcPin<T> for Temperature { |
| 33 | fn channel(&self) -> u8 { | 33 | fn channel(&self) -> u8 { |
| 34 | cfg_if! { | 34 | cfg_if! { |
| 35 | if #[cfg(adc_g0)] { | 35 | if #[cfg(adc_g0)] { |
| @@ -46,7 +46,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | |||
| 46 | 46 | ||
| 47 | pub struct Vbat; | 47 | pub struct Vbat; |
| 48 | impl<T: Instance> AdcPin<T> for Vbat {} | 48 | impl<T: Instance> AdcPin<T> for Vbat {} |
| 49 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | 49 | impl<T: Instance> super::SealedAdcPin<T> for Vbat { |
| 50 | fn channel(&self) -> u8 { | 50 | fn channel(&self) -> u8 { |
| 51 | cfg_if! { | 51 | cfg_if! { |
| 52 | if #[cfg(adc_g0)] { | 52 | if #[cfg(adc_g0)] { |
| @@ -65,7 +65,7 @@ cfg_if! { | |||
| 65 | if #[cfg(adc_h5)] { | 65 | if #[cfg(adc_h5)] { |
| 66 | pub struct VddCore; | 66 | pub struct VddCore; |
| 67 | impl<T: Instance> AdcPin<T> for VddCore {} | 67 | impl<T: Instance> AdcPin<T> for VddCore {} |
| 68 | impl<T: Instance> super::sealed::AdcPin<T> for VddCore { | 68 | impl<T: Instance> super::SealedAdcPin<T> for VddCore { |
| 69 | fn channel(&self) -> u8 { | 69 | fn channel(&self) -> u8 { |
| 70 | 6 | 70 | 6 |
| 71 | } | 71 | } |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 3fd047375..1ae25bea2 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -35,7 +35,7 @@ const VBAT_CHANNEL: u8 = 17; | |||
| 35 | /// Internal voltage reference channel. | 35 | /// Internal voltage reference channel. |
| 36 | pub struct VrefInt; | 36 | pub struct VrefInt; |
| 37 | impl<T: Instance> InternalChannel<T> for VrefInt {} | 37 | impl<T: Instance> InternalChannel<T> for VrefInt {} |
| 38 | impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { | 38 | impl<T: Instance> super::SealedInternalChannel<T> for VrefInt { |
| 39 | fn channel(&self) -> u8 { | 39 | fn channel(&self) -> u8 { |
| 40 | VREF_CHANNEL | 40 | VREF_CHANNEL |
| 41 | } | 41 | } |
| @@ -44,7 +44,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { | |||
| 44 | /// Internal temperature channel. | 44 | /// Internal temperature channel. |
| 45 | pub struct Temperature; | 45 | pub struct Temperature; |
| 46 | impl<T: Instance> InternalChannel<T> for Temperature {} | 46 | impl<T: Instance> InternalChannel<T> for Temperature {} |
| 47 | impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { | 47 | impl<T: Instance> super::SealedInternalChannel<T> for Temperature { |
| 48 | fn channel(&self) -> u8 { | 48 | fn channel(&self) -> u8 { |
| 49 | TEMP_CHANNEL | 49 | TEMP_CHANNEL |
| 50 | } | 50 | } |
| @@ -53,7 +53,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { | |||
| 53 | /// Internal battery voltage channel. | 53 | /// Internal battery voltage channel. |
| 54 | pub struct Vbat; | 54 | pub struct Vbat; |
| 55 | impl<T: Instance> InternalChannel<T> for Vbat {} | 55 | impl<T: Instance> InternalChannel<T> for Vbat {} |
| 56 | impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { | 56 | impl<T: Instance> super::SealedInternalChannel<T> for Vbat { |
| 57 | fn channel(&self) -> u8 { | 57 | fn channel(&self) -> u8 { |
| 58 | VBAT_CHANNEL | 58 | VBAT_CHANNEL |
| 59 | } | 59 | } |
| @@ -276,7 +276,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 276 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 276 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| 277 | where | 277 | where |
| 278 | P: AdcPin<T>, | 278 | P: AdcPin<T>, |
| 279 | P: crate::gpio::sealed::Pin, | 279 | P: crate::gpio::Pin, |
| 280 | { | 280 | { |
| 281 | pin.set_as_analog(); | 281 | pin.set_as_analog(); |
| 282 | 282 | ||
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs deleted file mode 100644 index 7e00eca6f..000000000 --- a/embassy-stm32/src/can/bxcan.rs +++ /dev/null | |||
| @@ -1,637 +0,0 @@ | |||
| 1 | use core::convert::AsMut; | ||
| 2 | use core::future::poll_fn; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::ops::{Deref, DerefMut}; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | pub use bxcan; | ||
| 8 | use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; | ||
| 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 10 | use futures::FutureExt; | ||
| 11 | |||
| 12 | use crate::gpio::sealed::AFType; | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | ||
| 14 | use crate::pac::can::vals::{Ide, Lec}; | ||
| 15 | use crate::rcc::RccPeripheral; | ||
| 16 | use crate::{interrupt, peripherals, Peripheral}; | ||
| 17 | |||
| 18 | pub mod enums; | ||
| 19 | use enums::*; | ||
| 20 | pub mod util; | ||
| 21 | |||
| 22 | /// Contains CAN frame and additional metadata. | ||
| 23 | /// | ||
| 24 | /// Timestamp is available if `time` feature is enabled. | ||
| 25 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 26 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 27 | pub struct Envelope { | ||
| 28 | /// Reception time. | ||
| 29 | #[cfg(feature = "time")] | ||
| 30 | pub ts: embassy_time::Instant, | ||
| 31 | /// The actual CAN frame. | ||
| 32 | pub frame: bxcan::Frame, | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Interrupt handler. | ||
| 36 | pub struct TxInterruptHandler<T: Instance> { | ||
| 37 | _phantom: PhantomData<T>, | ||
| 38 | } | ||
| 39 | |||
| 40 | impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> { | ||
| 41 | unsafe fn on_interrupt() { | ||
| 42 | T::regs().tsr().write(|v| { | ||
| 43 | v.set_rqcp(0, true); | ||
| 44 | v.set_rqcp(1, true); | ||
| 45 | v.set_rqcp(2, true); | ||
| 46 | }); | ||
| 47 | |||
| 48 | T::state().tx_waker.wake(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | /// RX0 interrupt handler. | ||
| 53 | pub struct Rx0InterruptHandler<T: Instance> { | ||
| 54 | _phantom: PhantomData<T>, | ||
| 55 | } | ||
| 56 | |||
| 57 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | ||
| 58 | unsafe fn on_interrupt() { | ||
| 59 | // info!("rx0 irq"); | ||
| 60 | Can::<T>::receive_fifo(RxFifo::Fifo0); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | /// RX1 interrupt handler. | ||
| 65 | pub struct Rx1InterruptHandler<T: Instance> { | ||
| 66 | _phantom: PhantomData<T>, | ||
| 67 | } | ||
| 68 | |||
| 69 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | ||
| 70 | unsafe fn on_interrupt() { | ||
| 71 | // info!("rx1 irq"); | ||
| 72 | Can::<T>::receive_fifo(RxFifo::Fifo1); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// SCE interrupt handler. | ||
| 77 | pub struct SceInterruptHandler<T: Instance> { | ||
| 78 | _phantom: PhantomData<T>, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | ||
| 82 | unsafe fn on_interrupt() { | ||
| 83 | // info!("sce irq"); | ||
| 84 | let msr = T::regs().msr(); | ||
| 85 | let msr_val = msr.read(); | ||
| 86 | |||
| 87 | if msr_val.erri() { | ||
| 88 | msr.modify(|v| v.set_erri(true)); | ||
| 89 | T::state().err_waker.wake(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | /// CAN driver | ||
| 95 | pub struct Can<'d, T: Instance> { | ||
| 96 | can: bxcan::Can<BxcanInstance<'d, T>>, | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Error returned by `try_read` | ||
| 100 | #[derive(Debug)] | ||
| 101 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 102 | pub enum TryReadError { | ||
| 103 | /// Bus error | ||
| 104 | BusError(BusError), | ||
| 105 | /// Receive buffer is empty | ||
| 106 | Empty, | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Error returned by `try_write` | ||
| 110 | #[derive(Debug)] | ||
| 111 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 112 | pub enum TryWriteError { | ||
| 113 | /// All transmit mailboxes are full | ||
| 114 | Full, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl<'d, T: Instance> Can<'d, T> { | ||
| 118 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | ||
| 119 | /// You must call [Can::enable_non_blocking] to use the peripheral. | ||
| 120 | pub fn new( | ||
| 121 | peri: impl Peripheral<P = T> + 'd, | ||
| 122 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 123 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 124 | _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> | ||
| 125 | + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> | ||
| 126 | + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> | ||
| 127 | + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> | ||
| 128 | + 'd, | ||
| 129 | ) -> Self { | ||
| 130 | into_ref!(peri, rx, tx); | ||
| 131 | |||
| 132 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 133 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 134 | |||
| 135 | T::enable_and_reset(); | ||
| 136 | |||
| 137 | { | ||
| 138 | T::regs().ier().write(|w| { | ||
| 139 | w.set_errie(true); | ||
| 140 | w.set_fmpie(0, true); | ||
| 141 | w.set_fmpie(1, true); | ||
| 142 | w.set_tmeie(true); | ||
| 143 | }); | ||
| 144 | |||
| 145 | T::regs().mcr().write(|w| { | ||
| 146 | // Enable timestamps on rx messages | ||
| 147 | |||
| 148 | w.set_ttcm(true); | ||
| 149 | }); | ||
| 150 | } | ||
| 151 | |||
| 152 | unsafe { | ||
| 153 | T::TXInterrupt::unpend(); | ||
| 154 | T::TXInterrupt::enable(); | ||
| 155 | |||
| 156 | T::RX0Interrupt::unpend(); | ||
| 157 | T::RX0Interrupt::enable(); | ||
| 158 | |||
| 159 | T::RX1Interrupt::unpend(); | ||
| 160 | T::RX1Interrupt::enable(); | ||
| 161 | |||
| 162 | T::SCEInterrupt::unpend(); | ||
| 163 | T::SCEInterrupt::enable(); | ||
| 164 | } | ||
| 165 | |||
| 166 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 167 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 168 | |||
| 169 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); | ||
| 170 | Self { can } | ||
| 171 | } | ||
| 172 | |||
| 173 | /// Set CAN bit rate. | ||
| 174 | pub fn set_bitrate(&mut self, bitrate: u32) { | ||
| 175 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 176 | let sjw = u8::from(bit_timing.sync_jump_width) as u32; | ||
| 177 | let seg1 = u8::from(bit_timing.seg1) as u32; | ||
| 178 | let seg2 = u8::from(bit_timing.seg2) as u32; | ||
| 179 | let prescaler = u16::from(bit_timing.prescaler) as u32; | ||
| 180 | self.can | ||
| 181 | .modify_config() | ||
| 182 | .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1)) | ||
| 183 | .leave_disabled(); | ||
| 184 | } | ||
| 185 | |||
| 186 | /// Enables the peripheral and synchronizes with the bus. | ||
| 187 | /// | ||
| 188 | /// This will wait for 11 consecutive recessive bits (bus idle state). | ||
| 189 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | ||
| 190 | pub async fn enable(&mut self) { | ||
| 191 | while self.enable_non_blocking().is_err() { | ||
| 192 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | ||
| 193 | // Yield to allow other tasks to execute while can bus is initializing. | ||
| 194 | embassy_futures::yield_now().await; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Queues the message to be sent. | ||
| 199 | /// | ||
| 200 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 201 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | ||
| 202 | self.split().0.write(frame).await | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Attempts to transmit a frame without blocking. | ||
| 206 | /// | ||
| 207 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 208 | pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> { | ||
| 209 | self.split().0.try_write(frame) | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Waits for a specific transmit mailbox to become empty | ||
| 213 | pub async fn flush(&self, mb: bxcan::Mailbox) { | ||
| 214 | CanTx::<T>::flush_inner(mb).await | ||
| 215 | } | ||
| 216 | |||
| 217 | /// Waits until any of the transmit mailboxes become empty | ||
| 218 | pub async fn flush_any(&self) { | ||
| 219 | CanTx::<T>::flush_any_inner().await | ||
| 220 | } | ||
| 221 | |||
| 222 | /// Waits until all of the transmit mailboxes become empty | ||
| 223 | pub async fn flush_all(&self) { | ||
| 224 | CanTx::<T>::flush_all_inner().await | ||
| 225 | } | ||
| 226 | |||
| 227 | /// Read a CAN frame. | ||
| 228 | /// | ||
| 229 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 230 | /// | ||
| 231 | /// Returns a tuple of the time the message was received and the message frame | ||
| 232 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 233 | self.split().1.read().await | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Attempts to read a CAN frame without blocking. | ||
| 237 | /// | ||
| 238 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 239 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 240 | self.split().1.try_read() | ||
| 241 | } | ||
| 242 | |||
| 243 | /// Waits while receive queue is empty. | ||
| 244 | pub async fn wait_not_empty(&mut self) { | ||
| 245 | self.split().1.wait_not_empty().await | ||
| 246 | } | ||
| 247 | |||
| 248 | unsafe fn receive_fifo(fifo: RxFifo) { | ||
| 249 | // Generate timestamp as early as possible | ||
| 250 | #[cfg(feature = "time")] | ||
| 251 | let ts = embassy_time::Instant::now(); | ||
| 252 | |||
| 253 | let state = T::state(); | ||
| 254 | let regs = T::regs(); | ||
| 255 | let fifo_idx = match fifo { | ||
| 256 | RxFifo::Fifo0 => 0usize, | ||
| 257 | RxFifo::Fifo1 => 1usize, | ||
| 258 | }; | ||
| 259 | let rfr = regs.rfr(fifo_idx); | ||
| 260 | let fifo = regs.rx(fifo_idx); | ||
| 261 | |||
| 262 | loop { | ||
| 263 | // If there are no pending messages, there is nothing to do | ||
| 264 | if rfr.read().fmp() == 0 { | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | let rir = fifo.rir().read(); | ||
| 269 | let id = if rir.ide() == Ide::STANDARD { | ||
| 270 | Id::from(StandardId::new_unchecked(rir.stid())) | ||
| 271 | } else { | ||
| 272 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 273 | let exid = rir.exid() & 0x3FFFF; | ||
| 274 | let id = (stid << 18) | (exid); | ||
| 275 | Id::from(ExtendedId::new_unchecked(id)) | ||
| 276 | }; | ||
| 277 | let data_len = fifo.rdtr().read().dlc() as usize; | ||
| 278 | let mut data: [u8; 8] = [0; 8]; | ||
| 279 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 280 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 281 | |||
| 282 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); | ||
| 283 | let envelope = Envelope { | ||
| 284 | #[cfg(feature = "time")] | ||
| 285 | ts, | ||
| 286 | frame, | ||
| 287 | }; | ||
| 288 | |||
| 289 | rfr.modify(|v| v.set_rfom(true)); | ||
| 290 | |||
| 291 | /* | ||
| 292 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 293 | */ | ||
| 294 | let _ = state.rx_queue.try_send(envelope); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | /// Split the CAN driver into transmit and receive halves. | ||
| 299 | /// | ||
| 300 | /// Useful for doing separate transmit/receive tasks. | ||
| 301 | pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { | ||
| 302 | let (tx, rx0, rx1) = self.can.split_by_ref(); | ||
| 303 | (CanTx { tx }, CanRx { rx0, rx1 }) | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | impl<'d, T: Instance> AsMut<bxcan::Can<BxcanInstance<'d, T>>> for Can<'d, T> { | ||
| 308 | /// Get mutable access to the lower-level driver from the `bxcan` crate. | ||
| 309 | fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { | ||
| 310 | &mut self.can | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | /// CAN driver, transmit half. | ||
| 315 | pub struct CanTx<'c, 'd, T: Instance> { | ||
| 316 | tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, | ||
| 317 | } | ||
| 318 | |||
| 319 | impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | ||
| 320 | /// Queues the message to be sent. | ||
| 321 | /// | ||
| 322 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 323 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | ||
| 324 | poll_fn(|cx| { | ||
| 325 | T::state().tx_waker.register(cx.waker()); | ||
| 326 | if let Ok(status) = self.tx.transmit(frame) { | ||
| 327 | return Poll::Ready(status); | ||
| 328 | } | ||
| 329 | |||
| 330 | Poll::Pending | ||
| 331 | }) | ||
| 332 | .await | ||
| 333 | } | ||
| 334 | |||
| 335 | /// Attempts to transmit a frame without blocking. | ||
| 336 | /// | ||
| 337 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 338 | pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> { | ||
| 339 | self.tx.transmit(frame).map_err(|_| TryWriteError::Full) | ||
| 340 | } | ||
| 341 | |||
| 342 | async fn flush_inner(mb: bxcan::Mailbox) { | ||
| 343 | poll_fn(|cx| { | ||
| 344 | T::state().tx_waker.register(cx.waker()); | ||
| 345 | if T::regs().tsr().read().tme(mb.index()) { | ||
| 346 | return Poll::Ready(()); | ||
| 347 | } | ||
| 348 | |||
| 349 | Poll::Pending | ||
| 350 | }) | ||
| 351 | .await; | ||
| 352 | } | ||
| 353 | |||
| 354 | /// Waits for a specific transmit mailbox to become empty | ||
| 355 | pub async fn flush(&self, mb: bxcan::Mailbox) { | ||
| 356 | Self::flush_inner(mb).await | ||
| 357 | } | ||
| 358 | |||
| 359 | async fn flush_any_inner() { | ||
| 360 | poll_fn(|cx| { | ||
| 361 | T::state().tx_waker.register(cx.waker()); | ||
| 362 | |||
| 363 | let tsr = T::regs().tsr().read(); | ||
| 364 | if tsr.tme(bxcan::Mailbox::Mailbox0.index()) | ||
| 365 | || tsr.tme(bxcan::Mailbox::Mailbox1.index()) | ||
| 366 | || tsr.tme(bxcan::Mailbox::Mailbox2.index()) | ||
| 367 | { | ||
| 368 | return Poll::Ready(()); | ||
| 369 | } | ||
| 370 | |||
| 371 | Poll::Pending | ||
| 372 | }) | ||
| 373 | .await; | ||
| 374 | } | ||
| 375 | |||
| 376 | /// Waits until any of the transmit mailboxes become empty | ||
| 377 | pub async fn flush_any(&self) { | ||
| 378 | Self::flush_any_inner().await | ||
| 379 | } | ||
| 380 | |||
| 381 | async fn flush_all_inner() { | ||
| 382 | poll_fn(|cx| { | ||
| 383 | T::state().tx_waker.register(cx.waker()); | ||
| 384 | |||
| 385 | let tsr = T::regs().tsr().read(); | ||
| 386 | if tsr.tme(bxcan::Mailbox::Mailbox0.index()) | ||
| 387 | && tsr.tme(bxcan::Mailbox::Mailbox1.index()) | ||
| 388 | && tsr.tme(bxcan::Mailbox::Mailbox2.index()) | ||
| 389 | { | ||
| 390 | return Poll::Ready(()); | ||
| 391 | } | ||
| 392 | |||
| 393 | Poll::Pending | ||
| 394 | }) | ||
| 395 | .await; | ||
| 396 | } | ||
| 397 | |||
| 398 | /// Waits until all of the transmit mailboxes become empty | ||
| 399 | pub async fn flush_all(&self) { | ||
| 400 | Self::flush_all_inner().await | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /// CAN driver, receive half. | ||
| 405 | #[allow(dead_code)] | ||
| 406 | pub struct CanRx<'c, 'd, T: Instance> { | ||
| 407 | rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, | ||
| 408 | rx1: &'c mut bxcan::Rx1<BxcanInstance<'d, T>>, | ||
| 409 | } | ||
| 410 | |||
| 411 | impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | ||
| 412 | /// Read a CAN frame. | ||
| 413 | /// | ||
| 414 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 415 | /// | ||
| 416 | /// Returns a tuple of the time the message was received and the message frame | ||
| 417 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 418 | poll_fn(|cx| { | ||
| 419 | T::state().err_waker.register(cx.waker()); | ||
| 420 | if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { | ||
| 421 | return Poll::Ready(Ok(envelope)); | ||
| 422 | } else if let Some(err) = self.curr_error() { | ||
| 423 | return Poll::Ready(Err(err)); | ||
| 424 | } | ||
| 425 | |||
| 426 | Poll::Pending | ||
| 427 | }) | ||
| 428 | .await | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Attempts to read a CAN frame without blocking. | ||
| 432 | /// | ||
| 433 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 434 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 435 | if let Ok(envelope) = T::state().rx_queue.try_receive() { | ||
| 436 | return Ok(envelope); | ||
| 437 | } | ||
| 438 | |||
| 439 | if let Some(err) = self.curr_error() { | ||
| 440 | return Err(TryReadError::BusError(err)); | ||
| 441 | } | ||
| 442 | |||
| 443 | Err(TryReadError::Empty) | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Waits while receive queue is empty. | ||
| 447 | pub async fn wait_not_empty(&mut self) { | ||
| 448 | poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await | ||
| 449 | } | ||
| 450 | |||
| 451 | fn curr_error(&self) -> Option<BusError> { | ||
| 452 | let err = { T::regs().esr().read() }; | ||
| 453 | if err.boff() { | ||
| 454 | return Some(BusError::BusOff); | ||
| 455 | } else if err.epvf() { | ||
| 456 | return Some(BusError::BusPassive); | ||
| 457 | } else if err.ewgf() { | ||
| 458 | return Some(BusError::BusWarning); | ||
| 459 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 460 | return Some(err); | ||
| 461 | } | ||
| 462 | None | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | enum RxFifo { | ||
| 467 | Fifo0, | ||
| 468 | Fifo1, | ||
| 469 | } | ||
| 470 | |||
| 471 | impl<'d, T: Instance> Drop for Can<'d, T> { | ||
| 472 | fn drop(&mut self) { | ||
| 473 | // Cannot call `free()` because it moves the instance. | ||
| 474 | // Manually reset the peripheral. | ||
| 475 | T::regs().mcr().write(|w| w.set_reset(true)); | ||
| 476 | T::disable(); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | impl<'d, T: Instance> Deref for Can<'d, T> { | ||
| 481 | type Target = bxcan::Can<BxcanInstance<'d, T>>; | ||
| 482 | |||
| 483 | fn deref(&self) -> &Self::Target { | ||
| 484 | &self.can | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | impl<'d, T: Instance> DerefMut for Can<'d, T> { | ||
| 489 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 490 | &mut self.can | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | pub(crate) mod sealed { | ||
| 495 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 496 | use embassy_sync::channel::Channel; | ||
| 497 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 498 | |||
| 499 | use super::Envelope; | ||
| 500 | |||
| 501 | pub struct State { | ||
| 502 | pub tx_waker: AtomicWaker, | ||
| 503 | pub err_waker: AtomicWaker, | ||
| 504 | pub rx_queue: Channel<CriticalSectionRawMutex, Envelope, 32>, | ||
| 505 | } | ||
| 506 | |||
| 507 | impl State { | ||
| 508 | pub const fn new() -> Self { | ||
| 509 | Self { | ||
| 510 | tx_waker: AtomicWaker::new(), | ||
| 511 | err_waker: AtomicWaker::new(), | ||
| 512 | rx_queue: Channel::new(), | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | pub trait Instance { | ||
| 518 | const REGISTERS: *mut bxcan::RegisterBlock; | ||
| 519 | |||
| 520 | fn regs() -> crate::pac::can::Can; | ||
| 521 | fn state() -> &'static State; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | /// CAN instance trait. | ||
| 526 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | ||
| 527 | /// TX interrupt for this instance. | ||
| 528 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 529 | /// RX0 interrupt for this instance. | ||
| 530 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 531 | /// RX1 interrupt for this instance. | ||
| 532 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 533 | /// SCE interrupt for this instance. | ||
| 534 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 535 | } | ||
| 536 | |||
| 537 | /// BXCAN instance newtype. | ||
| 538 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | ||
| 539 | |||
| 540 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | ||
| 541 | const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS; | ||
| 542 | } | ||
| 543 | |||
| 544 | foreach_peripheral!( | ||
| 545 | (can, $inst:ident) => { | ||
| 546 | impl sealed::Instance for peripherals::$inst { | ||
| 547 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; | ||
| 548 | |||
| 549 | fn regs() -> crate::pac::can::Can { | ||
| 550 | crate::pac::$inst | ||
| 551 | } | ||
| 552 | |||
| 553 | fn state() -> &'static sealed::State { | ||
| 554 | static STATE: sealed::State = sealed::State::new(); | ||
| 555 | &STATE | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | impl Instance for peripherals::$inst { | ||
| 560 | type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; | ||
| 561 | type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; | ||
| 562 | type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; | ||
| 563 | type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; | ||
| 564 | } | ||
| 565 | }; | ||
| 566 | ); | ||
| 567 | |||
| 568 | foreach_peripheral!( | ||
| 569 | (can, CAN) => { | ||
| 570 | unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN> { | ||
| 571 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 572 | } | ||
| 573 | }; | ||
| 574 | // CAN1 and CAN2 is a combination of master and slave instance. | ||
| 575 | // CAN1 owns the filter bank and needs to be enabled in order | ||
| 576 | // for CAN2 to receive messages. | ||
| 577 | (can, CAN1) => { | ||
| 578 | cfg_if::cfg_if! { | ||
| 579 | if #[cfg(all( | ||
| 580 | any(stm32l4, stm32f72, stm32f73), | ||
| 581 | not(any(stm32l49, stm32l4a)) | ||
| 582 | ))] { | ||
| 583 | // Most L4 devices and some F7 devices use the name "CAN1" | ||
| 584 | // even if there is no "CAN2" peripheral. | ||
| 585 | unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | ||
| 586 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 587 | } | ||
| 588 | } else { | ||
| 589 | unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | ||
| 590 | const NUM_FILTER_BANKS: u8 = 28; | ||
| 591 | } | ||
| 592 | unsafe impl<'d> bxcan::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} | ||
| 593 | } | ||
| 594 | } | ||
| 595 | }; | ||
| 596 | (can, CAN3) => { | ||
| 597 | unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { | ||
| 598 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 599 | } | ||
| 600 | }; | ||
| 601 | ); | ||
| 602 | |||
| 603 | pin_trait!(RxPin, Instance); | ||
| 604 | pin_trait!(TxPin, Instance); | ||
| 605 | |||
| 606 | trait Index { | ||
| 607 | fn index(&self) -> usize; | ||
| 608 | } | ||
| 609 | |||
| 610 | impl Index for bxcan::Mailbox { | ||
| 611 | fn index(&self) -> usize { | ||
| 612 | match self { | ||
| 613 | bxcan::Mailbox::Mailbox0 => 0, | ||
| 614 | bxcan::Mailbox::Mailbox1 => 1, | ||
| 615 | bxcan::Mailbox::Mailbox2 => 2, | ||
| 616 | } | ||
| 617 | } | ||
| 618 | } | ||
| 619 | |||
| 620 | trait IntoBusError { | ||
| 621 | fn into_bus_err(self) -> Option<BusError>; | ||
| 622 | } | ||
| 623 | |||
| 624 | impl IntoBusError for Lec { | ||
| 625 | fn into_bus_err(self) -> Option<BusError> { | ||
| 626 | match self { | ||
| 627 | Lec::STUFF => Some(BusError::Stuff), | ||
| 628 | Lec::FORM => Some(BusError::Form), | ||
| 629 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 630 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 631 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 632 | Lec::CRC => Some(BusError::Crc), | ||
| 633 | Lec::CUSTOM => Some(BusError::Software), | ||
| 634 | _ => None, | ||
| 635 | } | ||
| 636 | } | ||
| 637 | } | ||
diff --git a/embassy-stm32/src/can/bxcan/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs new file mode 100644 index 000000000..9940c7f50 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/filter.rs | |||
| @@ -0,0 +1,475 @@ | |||
| 1 | //! Filter bank API. | ||
| 2 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; | ||
| 6 | |||
| 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames | ||
| 8 | const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers | ||
| 9 | const F16_RTR: u16 = 0b10000; | ||
| 10 | const F16_IDE: u16 = 0b01000; | ||
| 11 | |||
| 12 | /// A 16-bit filter list entry. | ||
| 13 | /// | ||
| 14 | /// This can match data and remote frames using standard IDs. | ||
| 15 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | pub struct ListEntry16(u16); | ||
| 18 | |||
| 19 | /// A 32-bit filter list entry. | ||
| 20 | /// | ||
| 21 | /// This can match data and remote frames using extended or standard IDs. | ||
| 22 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 24 | pub struct ListEntry32(u32); | ||
| 25 | |||
| 26 | /// A 16-bit identifier mask. | ||
| 27 | #[derive(Debug, Copy, Clone)] | ||
| 28 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 29 | pub struct Mask16 { | ||
| 30 | id: u16, | ||
| 31 | mask: u16, | ||
| 32 | } | ||
| 33 | |||
| 34 | /// A 32-bit identifier mask. | ||
| 35 | #[derive(Debug, Copy, Clone)] | ||
| 36 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 37 | pub struct Mask32 { | ||
| 38 | id: u32, | ||
| 39 | mask: u32, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl ListEntry16 { | ||
| 43 | /// Creates a filter list entry that accepts data frames with the given standard ID. | ||
| 44 | /// | ||
| 45 | /// This entry will *not* accept remote frames with the same ID. | ||
| 46 | pub fn data_frames_with_id(id: StandardId) -> Self { | ||
| 47 | Self(id.as_raw() << 5) | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Creates a filter list entry that accepts remote frames with the given standard ID. | ||
| 51 | pub fn remote_frames_with_id(id: StandardId) -> Self { | ||
| 52 | Self(id.as_raw() << 5 | F16_RTR) | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl ListEntry32 { | ||
| 57 | /// Creates a filter list entry that accepts data frames with the given ID. | ||
| 58 | /// | ||
| 59 | /// This entry will *not* accept remote frames with the same ID. | ||
| 60 | /// | ||
| 61 | /// The filter will only accept *either* standard *or* extended frames, depending on `id`. | ||
| 62 | pub fn data_frames_with_id(id: impl Into<Id>) -> Self { | ||
| 63 | match id.into() { | ||
| 64 | Id::Standard(id) => Self(u32::from(id.as_raw()) << 21), | ||
| 65 | Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE), | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Creates a filter list entry that accepts remote frames with the given ID. | ||
| 70 | pub fn remote_frames_with_id(id: impl Into<Id>) -> Self { | ||
| 71 | match id.into() { | ||
| 72 | Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR), | ||
| 73 | Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR), | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | impl Mask16 { | ||
| 79 | /// Creates a 16-bit identifier mask that accepts all frames. | ||
| 80 | /// | ||
| 81 | /// This will accept both standard and extended data and remote frames with any ID. | ||
| 82 | pub fn accept_all() -> Self { | ||
| 83 | Self { id: 0, mask: 0 } | ||
| 84 | } | ||
| 85 | |||
| 86 | /// Creates a 16-bit identifier mask that accepts all frames with the given standard | ||
| 87 | /// ID and mask combination. | ||
| 88 | /// | ||
| 89 | /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` | ||
| 90 | /// | ||
| 91 | /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs. | ||
| 92 | /// | ||
| 93 | /// Both data and remote frames with `id` will be accepted. Any extended frames will be | ||
| 94 | /// rejected. | ||
| 95 | pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { | ||
| 96 | Self { | ||
| 97 | id: id.as_raw() << 5, | ||
| 98 | mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0 | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | /// Make the filter accept data frames only. | ||
| 103 | pub fn data_frames_only(&mut self) -> &mut Self { | ||
| 104 | self.id &= !F16_RTR; // RTR = 0 | ||
| 105 | self.mask |= F16_RTR; | ||
| 106 | self | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Make the filter accept remote frames only. | ||
| 110 | pub fn remote_frames_only(&mut self) -> &mut Self { | ||
| 111 | self.id |= F16_RTR; // RTR = 1 | ||
| 112 | self.mask |= F16_RTR; | ||
| 113 | self | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | impl Mask32 { | ||
| 118 | /// Creates a 32-bit identifier mask that accepts all frames. | ||
| 119 | /// | ||
| 120 | /// This will accept both standard and extended data and remote frames with any ID. | ||
| 121 | pub fn accept_all() -> Self { | ||
| 122 | Self { id: 0, mask: 0 } | ||
| 123 | } | ||
| 124 | |||
| 125 | /// Creates a 32-bit identifier mask that accepts all frames with the given extended | ||
| 126 | /// ID and mask combination. | ||
| 127 | /// | ||
| 128 | /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` | ||
| 129 | /// | ||
| 130 | /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs. | ||
| 131 | /// | ||
| 132 | /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected. | ||
| 133 | pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self { | ||
| 134 | Self { | ||
| 135 | id: id.as_raw() << 3 | F32_IDE, | ||
| 136 | mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1 | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Creates a 32-bit identifier mask that accepts all frames with the given standard | ||
| 141 | /// ID and mask combination. | ||
| 142 | /// | ||
| 143 | /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` | ||
| 144 | /// | ||
| 145 | /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs. | ||
| 146 | /// | ||
| 147 | /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected. | ||
| 148 | pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { | ||
| 149 | Self { | ||
| 150 | id: u32::from(id.as_raw()) << 21, | ||
| 151 | mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0 | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | /// Make the filter accept data frames only. | ||
| 156 | pub fn data_frames_only(&mut self) -> &mut Self { | ||
| 157 | self.id &= !F32_RTR; // RTR = 0 | ||
| 158 | self.mask |= F32_RTR; | ||
| 159 | self | ||
| 160 | } | ||
| 161 | |||
| 162 | /// Make the filter accept remote frames only. | ||
| 163 | pub fn remote_frames_only(&mut self) -> &mut Self { | ||
| 164 | self.id |= F32_RTR; // RTR = 1 | ||
| 165 | self.mask |= F32_RTR; | ||
| 166 | self | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | /// The configuration of a filter bank. | ||
| 171 | #[derive(Debug, Copy, Clone)] | ||
| 172 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 173 | pub enum BankConfig { | ||
| 174 | /// Specify up to 4 exact standard CAN ID's. | ||
| 175 | List16([ListEntry16; 4]), | ||
| 176 | /// Specify up to 2 exact standard or extended CAN ID's. | ||
| 177 | List32([ListEntry32; 2]), | ||
| 178 | /// Specify up to 2 standard ID's with masks. | ||
| 179 | Mask16([Mask16; 2]), | ||
| 180 | /// Specify a single extended ID with mask. | ||
| 181 | Mask32(Mask32), | ||
| 182 | } | ||
| 183 | |||
| 184 | impl From<[ListEntry16; 4]> for BankConfig { | ||
| 185 | #[inline] | ||
| 186 | fn from(entries: [ListEntry16; 4]) -> Self { | ||
| 187 | Self::List16(entries) | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | impl From<[ListEntry32; 2]> for BankConfig { | ||
| 192 | #[inline] | ||
| 193 | fn from(entries: [ListEntry32; 2]) -> Self { | ||
| 194 | Self::List32(entries) | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | impl From<[Mask16; 2]> for BankConfig { | ||
| 199 | #[inline] | ||
| 200 | fn from(entries: [Mask16; 2]) -> Self { | ||
| 201 | Self::Mask16(entries) | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | impl From<Mask32> for BankConfig { | ||
| 206 | #[inline] | ||
| 207 | fn from(filter: Mask32) -> Self { | ||
| 208 | Self::Mask32(filter) | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Interface to the filter banks of a CAN peripheral. | ||
| 213 | pub struct MasterFilters<'a, I: FilterOwner> { | ||
| 214 | /// Number of assigned filter banks. | ||
| 215 | /// | ||
| 216 | /// On chips with splittable filter banks, this value can be dynamic. | ||
| 217 | bank_count: u8, | ||
| 218 | _can: PhantomData<&'a mut I>, | ||
| 219 | canregs: crate::pac::can::Can, | ||
| 220 | } | ||
| 221 | |||
| 222 | // NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it | ||
| 223 | // exists. | ||
| 224 | impl<I: FilterOwner> MasterFilters<'_, I> { | ||
| 225 | pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self { | ||
| 226 | // Enable initialization mode. | ||
| 227 | canregs.fmr().modify(|reg| reg.set_finit(true)); | ||
| 228 | |||
| 229 | // Read the filter split value. | ||
| 230 | let bank_count = canregs.fmr().read().can2sb(); | ||
| 231 | |||
| 232 | // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all | ||
| 233 | // of them to the master peripheral, and in devices with 28, assigns them 50/50 to | ||
| 234 | // master/slave instances) | ||
| 235 | |||
| 236 | Self { | ||
| 237 | bank_count, | ||
| 238 | _can: PhantomData, | ||
| 239 | canregs, | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | fn banks_imm(&self) -> FilterBanks { | ||
| 244 | FilterBanks { | ||
| 245 | start_idx: 0, | ||
| 246 | bank_count: self.bank_count, | ||
| 247 | canregs: self.canregs, | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | /// Returns the number of filter banks currently assigned to this instance. | ||
| 252 | /// | ||
| 253 | /// Chips with splittable filter banks may start out with some banks assigned to the master | ||
| 254 | /// instance and some assigned to the slave instance. | ||
| 255 | pub fn num_banks(&self) -> u8 { | ||
| 256 | self.bank_count | ||
| 257 | } | ||
| 258 | |||
| 259 | /// Disables all enabled filter banks. | ||
| 260 | /// | ||
| 261 | /// This causes all incoming frames to be disposed. | ||
| 262 | pub fn clear(&mut self) -> &mut Self { | ||
| 263 | self.banks_imm().clear(); | ||
| 264 | self | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Disables a filter bank. | ||
| 268 | /// | ||
| 269 | /// If `index` is out of bounds, this will panic. | ||
| 270 | pub fn disable_bank(&mut self, index: u8) -> &mut Self { | ||
| 271 | self.banks_imm().disable(index); | ||
| 272 | self | ||
| 273 | } | ||
| 274 | |||
| 275 | /// Configures a filter bank according to `config` and enables it. | ||
| 276 | /// | ||
| 277 | /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`] | ||
| 278 | /// passed to this function. In the event that both FIFOs are configured to accept an incoming | ||
| 279 | /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so | ||
| 280 | /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept | ||
| 281 | /// the frame. | ||
| 282 | /// | ||
| 283 | /// # Parameters | ||
| 284 | /// | ||
| 285 | /// - `index`: the filter index. | ||
| 286 | /// - `fifo`: the receive FIFO the filter should pass accepted messages to. | ||
| 287 | /// - `config`: the filter configuration. | ||
| 288 | pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self { | ||
| 289 | self.banks_imm().enable(index, fifo, config.into()); | ||
| 290 | self | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | impl<I: MasterInstance> MasterFilters<'_, I> { | ||
| 295 | /// Sets the index at which the filter banks owned by the slave peripheral start. | ||
| 296 | pub fn set_split(&mut self, split_index: u8) -> &mut Self { | ||
| 297 | assert!(split_index <= I::NUM_FILTER_BANKS); | ||
| 298 | self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index)); | ||
| 299 | self.bank_count = split_index; | ||
| 300 | self | ||
| 301 | } | ||
| 302 | |||
| 303 | /// Accesses the filters assigned to the slave peripheral. | ||
| 304 | pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> { | ||
| 305 | // NB: This mutably borrows `self`, so it has full access to the filter bank registers. | ||
| 306 | SlaveFilters { | ||
| 307 | start_idx: self.bank_count, | ||
| 308 | bank_count: I::NUM_FILTER_BANKS - self.bank_count, | ||
| 309 | _can: PhantomData, | ||
| 310 | canregs: self.canregs, | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | impl<I: FilterOwner> Drop for MasterFilters<'_, I> { | ||
| 316 | #[inline] | ||
| 317 | fn drop(&mut self) { | ||
| 318 | // Leave initialization mode. | ||
| 319 | self.canregs.fmr().modify(|regs| regs.set_finit(false)); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | /// Interface to the filter banks assigned to a slave peripheral. | ||
| 324 | pub struct SlaveFilters<'a, I: Instance> { | ||
| 325 | start_idx: u8, | ||
| 326 | bank_count: u8, | ||
| 327 | _can: PhantomData<&'a mut I>, | ||
| 328 | canregs: crate::pac::can::Can, | ||
| 329 | } | ||
| 330 | |||
| 331 | impl<I: Instance> SlaveFilters<'_, I> { | ||
| 332 | fn banks_imm(&self) -> FilterBanks { | ||
| 333 | FilterBanks { | ||
| 334 | start_idx: self.start_idx, | ||
| 335 | bank_count: self.bank_count, | ||
| 336 | canregs: self.canregs, | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | /// Returns the number of filter banks currently assigned to this instance. | ||
| 341 | /// | ||
| 342 | /// Chips with splittable filter banks may start out with some banks assigned to the master | ||
| 343 | /// instance and some assigned to the slave instance. | ||
| 344 | pub fn num_banks(&self) -> u8 { | ||
| 345 | self.bank_count | ||
| 346 | } | ||
| 347 | |||
| 348 | /// Disables all enabled filter banks. | ||
| 349 | /// | ||
| 350 | /// This causes all incoming frames to be disposed. | ||
| 351 | pub fn clear(&mut self) -> &mut Self { | ||
| 352 | self.banks_imm().clear(); | ||
| 353 | self | ||
| 354 | } | ||
| 355 | |||
| 356 | /// Disables a filter bank. | ||
| 357 | /// | ||
| 358 | /// If `index` is out of bounds, this will panic. | ||
| 359 | pub fn disable_bank(&mut self, index: u8) -> &mut Self { | ||
| 360 | self.banks_imm().disable(index); | ||
| 361 | self | ||
| 362 | } | ||
| 363 | |||
| 364 | /// Configures a filter bank according to `config` and enables it. | ||
| 365 | /// | ||
| 366 | /// # Parameters | ||
| 367 | /// | ||
| 368 | /// - `index`: the filter index. | ||
| 369 | /// - `fifo`: the receive FIFO the filter should pass accepted messages to. | ||
| 370 | /// - `config`: the filter configuration. | ||
| 371 | pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self { | ||
| 372 | self.banks_imm().enable(index, fifo, config.into()); | ||
| 373 | self | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | struct FilterBanks { | ||
| 378 | start_idx: u8, | ||
| 379 | bank_count: u8, | ||
| 380 | canregs: crate::pac::can::Can, | ||
| 381 | } | ||
| 382 | |||
| 383 | impl FilterBanks { | ||
| 384 | fn clear(&mut self) { | ||
| 385 | let mask = filter_bitmask(self.start_idx, self.bank_count); | ||
| 386 | |||
| 387 | self.canregs.fa1r().modify(|reg| { | ||
| 388 | for i in 0..28usize { | ||
| 389 | if (0x01u32 << i) & mask != 0 { | ||
| 390 | reg.set_fact(i, false); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | }); | ||
| 394 | } | ||
| 395 | |||
| 396 | fn assert_bank_index(&self, index: u8) { | ||
| 397 | assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index)); | ||
| 398 | } | ||
| 399 | |||
| 400 | fn disable(&mut self, index: u8) { | ||
| 401 | self.assert_bank_index(index); | ||
| 402 | self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false)) | ||
| 403 | } | ||
| 404 | |||
| 405 | fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { | ||
| 406 | self.assert_bank_index(index); | ||
| 407 | |||
| 408 | // Configure mode. | ||
| 409 | let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); | ||
| 410 | self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode)); | ||
| 411 | |||
| 412 | // Configure scale. | ||
| 413 | let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); | ||
| 414 | self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale)); | ||
| 415 | |||
| 416 | // Configure filter register. | ||
| 417 | let (fxr1, fxr2); | ||
| 418 | match config { | ||
| 419 | BankConfig::List16([a, b, c, d]) => { | ||
| 420 | fxr1 = (u32::from(b.0) << 16) | u32::from(a.0); | ||
| 421 | fxr2 = (u32::from(d.0) << 16) | u32::from(c.0); | ||
| 422 | } | ||
| 423 | BankConfig::List32([a, b]) => { | ||
| 424 | fxr1 = a.0; | ||
| 425 | fxr2 = b.0; | ||
| 426 | } | ||
| 427 | BankConfig::Mask16([a, b]) => { | ||
| 428 | fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id); | ||
| 429 | fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id); | ||
| 430 | } | ||
| 431 | BankConfig::Mask32(a) => { | ||
| 432 | fxr1 = a.id; | ||
| 433 | fxr2 = a.mask; | ||
| 434 | } | ||
| 435 | }; | ||
| 436 | let bank = self.canregs.fb(index as usize); | ||
| 437 | bank.fr1().write(|w| w.0 = fxr1); | ||
| 438 | bank.fr2().write(|w| w.0 = fxr2); | ||
| 439 | |||
| 440 | // Assign to the right FIFO | ||
| 441 | self.canregs.ffa1r().modify(|reg| { | ||
| 442 | reg.set_ffa( | ||
| 443 | index as usize, | ||
| 444 | match fifo { | ||
| 445 | Fifo::Fifo0 => false, | ||
| 446 | Fifo::Fifo1 => true, | ||
| 447 | }, | ||
| 448 | ) | ||
| 449 | }); | ||
| 450 | |||
| 451 | // Set active. | ||
| 452 | self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true)) | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Computes a bitmask for per-filter-bank registers that only includes filters in the given range. | ||
| 457 | fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 { | ||
| 458 | let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits | ||
| 459 | count_mask << start_idx | ||
| 460 | } | ||
| 461 | |||
| 462 | #[cfg(test)] | ||
| 463 | mod tests { | ||
| 464 | use super::*; | ||
| 465 | |||
| 466 | #[test] | ||
| 467 | fn test_filter_bitmask() { | ||
| 468 | assert_eq!(filter_bitmask(0, 1), 0x1); | ||
| 469 | assert_eq!(filter_bitmask(1, 1), 0b10); | ||
| 470 | assert_eq!(filter_bitmask(0, 4), 0xf); | ||
| 471 | assert_eq!(filter_bitmask(1, 3), 0xe); | ||
| 472 | assert_eq!(filter_bitmask(8, 1), 0x100); | ||
| 473 | assert_eq!(filter_bitmask(8, 4), 0xf00); | ||
| 474 | } | ||
| 475 | } | ||
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs new file mode 100644 index 000000000..65fd0e9c2 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/mod.rs | |||
| @@ -0,0 +1,989 @@ | |||
| 1 | pub mod filter; | ||
| 2 | mod registers; | ||
| 3 | |||
| 4 | use core::future::poll_fn; | ||
| 5 | use core::marker::PhantomData; | ||
| 6 | use core::task::Poll; | ||
| 7 | |||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 10 | use embassy_sync::channel::Channel; | ||
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 13 | |||
| 14 | use self::filter::MasterFilters; | ||
| 15 | use self::registers::{Registers, RxFifo}; | ||
| 16 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; | ||
| 17 | use super::frame::{Envelope, Frame}; | ||
| 18 | use super::util; | ||
| 19 | use crate::can::enums::{BusError, TryReadError}; | ||
| 20 | use crate::gpio::AFType; | ||
| 21 | use crate::interrupt::typelevel::Interrupt; | ||
| 22 | use crate::rcc::RccPeripheral; | ||
| 23 | use crate::{interrupt, peripherals, Peripheral}; | ||
| 24 | |||
| 25 | /// Interrupt handler. | ||
| 26 | pub struct TxInterruptHandler<T: Instance> { | ||
| 27 | _phantom: PhantomData<T>, | ||
| 28 | } | ||
| 29 | |||
| 30 | impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> { | ||
| 31 | unsafe fn on_interrupt() { | ||
| 32 | T::regs().tsr().write(|v| { | ||
| 33 | v.set_rqcp(0, true); | ||
| 34 | v.set_rqcp(1, true); | ||
| 35 | v.set_rqcp(2, true); | ||
| 36 | }); | ||
| 37 | T::state().tx_mode.on_interrupt::<T>(); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | /// RX0 interrupt handler. | ||
| 42 | pub struct Rx0InterruptHandler<T: Instance> { | ||
| 43 | _phantom: PhantomData<T>, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | ||
| 47 | unsafe fn on_interrupt() { | ||
| 48 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo0); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | /// RX1 interrupt handler. | ||
| 53 | pub struct Rx1InterruptHandler<T: Instance> { | ||
| 54 | _phantom: PhantomData<T>, | ||
| 55 | } | ||
| 56 | |||
| 57 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | ||
| 58 | unsafe fn on_interrupt() { | ||
| 59 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo1); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | /// SCE interrupt handler. | ||
| 64 | pub struct SceInterruptHandler<T: Instance> { | ||
| 65 | _phantom: PhantomData<T>, | ||
| 66 | } | ||
| 67 | |||
| 68 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | ||
| 69 | unsafe fn on_interrupt() { | ||
| 70 | // info!("sce irq"); | ||
| 71 | let msr = T::regs().msr(); | ||
| 72 | let msr_val = msr.read(); | ||
| 73 | |||
| 74 | if msr_val.erri() { | ||
| 75 | msr.modify(|v| v.set_erri(true)); | ||
| 76 | T::state().err_waker.wake(); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Configuration proxy returned by [`Can::modify_config`]. | ||
| 82 | pub struct CanConfig<'a, T: Instance> { | ||
| 83 | can: PhantomData<&'a mut T>, | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<T: Instance> CanConfig<'_, T> { | ||
| 87 | /// Configures the bit timings. | ||
| 88 | /// | ||
| 89 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 90 | /// parameters as follows: | ||
| 91 | /// | ||
| 92 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 93 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 94 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 95 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 96 | /// | ||
| 97 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 98 | /// parameter to this method. | ||
| 99 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 100 | Registers(T::regs()).set_bit_timing(bt); | ||
| 101 | self | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Configure the CAN bit rate. | ||
| 105 | /// | ||
| 106 | /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing]. | ||
| 107 | pub fn set_bitrate(self, bitrate: u32) -> Self { | ||
| 108 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 109 | self.set_bit_timing(bit_timing) | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 113 | /// signals together. | ||
| 114 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 115 | Registers(T::regs()).set_loopback(enabled); | ||
| 116 | self | ||
| 117 | } | ||
| 118 | |||
| 119 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 120 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 121 | Registers(T::regs()).set_silent(enabled); | ||
| 122 | self | ||
| 123 | } | ||
| 124 | |||
| 125 | /// Enables or disables automatic retransmission of messages. | ||
| 126 | /// | ||
| 127 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 128 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 129 | /// | ||
| 130 | /// Automatic retransmission is enabled by default. | ||
| 131 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 132 | Registers(T::regs()).set_automatic_retransmit(enabled); | ||
| 133 | self | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | impl<T: Instance> Drop for CanConfig<'_, T> { | ||
| 138 | #[inline] | ||
| 139 | fn drop(&mut self) { | ||
| 140 | Registers(T::regs()).leave_init_mode(); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | /// CAN driver | ||
| 145 | pub struct Can<'d, T: Instance> { | ||
| 146 | peri: PeripheralRef<'d, T>, | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Error returned by `try_write` | ||
| 150 | #[derive(Debug)] | ||
| 151 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 152 | pub enum TryWriteError { | ||
| 153 | /// All transmit mailboxes are full | ||
| 154 | Full, | ||
| 155 | } | ||
| 156 | |||
| 157 | impl<'d, T: Instance> Can<'d, T> { | ||
| 158 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | ||
| 159 | /// You must call [Can::enable_non_blocking] to use the peripheral. | ||
| 160 | pub fn new( | ||
| 161 | peri: impl Peripheral<P = T> + 'd, | ||
| 162 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 163 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 164 | _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> | ||
| 165 | + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> | ||
| 166 | + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> | ||
| 167 | + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> | ||
| 168 | + 'd, | ||
| 169 | ) -> Self { | ||
| 170 | into_ref!(peri, rx, tx); | ||
| 171 | |||
| 172 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 173 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 174 | |||
| 175 | T::enable_and_reset(); | ||
| 176 | |||
| 177 | { | ||
| 178 | T::regs().ier().write(|w| { | ||
| 179 | w.set_errie(true); | ||
| 180 | w.set_fmpie(0, true); | ||
| 181 | w.set_fmpie(1, true); | ||
| 182 | w.set_tmeie(true); | ||
| 183 | }); | ||
| 184 | |||
| 185 | T::regs().mcr().write(|w| { | ||
| 186 | // Enable timestamps on rx messages | ||
| 187 | |||
| 188 | w.set_ttcm(true); | ||
| 189 | }); | ||
| 190 | } | ||
| 191 | |||
| 192 | unsafe { | ||
| 193 | T::TXInterrupt::unpend(); | ||
| 194 | T::TXInterrupt::enable(); | ||
| 195 | |||
| 196 | T::RX0Interrupt::unpend(); | ||
| 197 | T::RX0Interrupt::enable(); | ||
| 198 | |||
| 199 | T::RX1Interrupt::unpend(); | ||
| 200 | T::RX1Interrupt::enable(); | ||
| 201 | |||
| 202 | T::SCEInterrupt::unpend(); | ||
| 203 | T::SCEInterrupt::enable(); | ||
| 204 | } | ||
| 205 | |||
| 206 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 207 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 208 | |||
| 209 | Registers(T::regs()).leave_init_mode(); | ||
| 210 | |||
| 211 | Self { peri } | ||
| 212 | } | ||
| 213 | |||
| 214 | /// Set CAN bit rate. | ||
| 215 | pub fn set_bitrate(&mut self, bitrate: u32) { | ||
| 216 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 217 | self.modify_config().set_bit_timing(bit_timing); | ||
| 218 | } | ||
| 219 | |||
| 220 | /// Configure bit timings and silent/loop-back mode. | ||
| 221 | /// | ||
| 222 | /// Calling this method will enter initialization mode. You must enable the peripheral | ||
| 223 | /// again afterwards with [`enable`](Self::enable). | ||
| 224 | pub fn modify_config(&mut self) -> CanConfig<'_, T> { | ||
| 225 | Registers(T::regs()).enter_init_mode(); | ||
| 226 | |||
| 227 | CanConfig { can: PhantomData } | ||
| 228 | } | ||
| 229 | |||
| 230 | /// Enables the peripheral and synchronizes with the bus. | ||
| 231 | /// | ||
| 232 | /// This will wait for 11 consecutive recessive bits (bus idle state). | ||
| 233 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | ||
| 234 | pub async fn enable(&mut self) { | ||
| 235 | while Registers(T::regs()).enable_non_blocking().is_err() { | ||
| 236 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | ||
| 237 | // Yield to allow other tasks to execute while can bus is initializing. | ||
| 238 | embassy_futures::yield_now().await; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | /// Queues the message to be sent. | ||
| 243 | /// | ||
| 244 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 245 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { | ||
| 246 | self.split().0.write(frame).await | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Attempts to transmit a frame without blocking. | ||
| 250 | /// | ||
| 251 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 252 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { | ||
| 253 | self.split().0.try_write(frame) | ||
| 254 | } | ||
| 255 | |||
| 256 | /// Waits for a specific transmit mailbox to become empty | ||
| 257 | pub async fn flush(&self, mb: Mailbox) { | ||
| 258 | CanTx::<T>::flush_inner(mb).await | ||
| 259 | } | ||
| 260 | |||
| 261 | /// Waits until any of the transmit mailboxes become empty | ||
| 262 | pub async fn flush_any(&self) { | ||
| 263 | CanTx::<T>::flush_any_inner().await | ||
| 264 | } | ||
| 265 | |||
| 266 | /// Waits until all of the transmit mailboxes become empty | ||
| 267 | pub async fn flush_all(&self) { | ||
| 268 | CanTx::<T>::flush_all_inner().await | ||
| 269 | } | ||
| 270 | |||
| 271 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 272 | /// | ||
| 273 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 274 | /// aborted, this function has no effect and returns `false`. | ||
| 275 | /// | ||
| 276 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 277 | /// returns `true`. | ||
| 278 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 279 | Registers(T::regs()).abort(mailbox) | ||
| 280 | } | ||
| 281 | |||
| 282 | /// Returns `true` if no frame is pending for transmission. | ||
| 283 | pub fn is_transmitter_idle(&self) -> bool { | ||
| 284 | Registers(T::regs()).is_idle() | ||
| 285 | } | ||
| 286 | |||
| 287 | /// Read a CAN frame. | ||
| 288 | /// | ||
| 289 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 290 | /// | ||
| 291 | /// Returns a tuple of the time the message was received and the message frame | ||
| 292 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 293 | T::state().rx_mode.read::<T>().await | ||
| 294 | } | ||
| 295 | |||
| 296 | /// Attempts to read a CAN frame without blocking. | ||
| 297 | /// | ||
| 298 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 299 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 300 | T::state().rx_mode.try_read::<T>() | ||
| 301 | } | ||
| 302 | |||
| 303 | /// Waits while receive queue is empty. | ||
| 304 | pub async fn wait_not_empty(&mut self) { | ||
| 305 | T::state().rx_mode.wait_not_empty::<T>().await | ||
| 306 | } | ||
| 307 | |||
| 308 | /// Split the CAN driver into transmit and receive halves. | ||
| 309 | /// | ||
| 310 | /// Useful for doing separate transmit/receive tasks. | ||
| 311 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { | ||
| 312 | ( | ||
| 313 | CanTx { | ||
| 314 | _peri: unsafe { self.peri.clone_unchecked() }, | ||
| 315 | }, | ||
| 316 | CanRx { | ||
| 317 | peri: unsafe { self.peri.clone_unchecked() }, | ||
| 318 | }, | ||
| 319 | ) | ||
| 320 | } | ||
| 321 | |||
| 322 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 323 | pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( | ||
| 324 | &'c mut self, | ||
| 325 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 326 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | ||
| 327 | ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 328 | let (tx, rx) = self.split(); | ||
| 329 | BufferedCan { | ||
| 330 | tx: tx.buffered(txb), | ||
| 331 | rx: rx.buffered(rxb), | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<'d, T: FilterOwner> Can<'d, T> { | ||
| 337 | /// Accesses the filter banks owned by this CAN peripheral. | ||
| 338 | /// | ||
| 339 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | ||
| 340 | /// peripheral instead. | ||
| 341 | pub fn modify_filters(&mut self) -> MasterFilters<'_, T> { | ||
| 342 | unsafe { MasterFilters::new(T::regs()) } | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | /// Buffered CAN driver. | ||
| 347 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | ||
| 348 | tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, | ||
| 349 | rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, | ||
| 350 | } | ||
| 351 | |||
| 352 | impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 353 | /// Async write frame to TX buffer. | ||
| 354 | pub async fn write(&mut self, frame: &Frame) { | ||
| 355 | self.tx.write(frame).await | ||
| 356 | } | ||
| 357 | |||
| 358 | /// Returns a sender that can be used for sending CAN frames. | ||
| 359 | pub fn writer(&self) -> BufferedCanSender { | ||
| 360 | self.tx.writer() | ||
| 361 | } | ||
| 362 | |||
| 363 | /// Async read frame from RX buffer. | ||
| 364 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 365 | self.rx.read().await | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Attempts to read a CAN frame without blocking. | ||
| 369 | /// | ||
| 370 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 371 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 372 | self.rx.try_read() | ||
| 373 | } | ||
| 374 | |||
| 375 | /// Waits while receive queue is empty. | ||
| 376 | pub async fn wait_not_empty(&mut self) { | ||
| 377 | self.rx.wait_not_empty().await | ||
| 378 | } | ||
| 379 | |||
| 380 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 381 | pub fn reader(&self) -> BufferedCanReceiver { | ||
| 382 | self.rx.reader() | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | /// CAN driver, transmit half. | ||
| 387 | pub struct CanTx<'d, T: Instance> { | ||
| 388 | _peri: PeripheralRef<'d, T>, | ||
| 389 | } | ||
| 390 | |||
| 391 | impl<'d, T: Instance> CanTx<'d, T> { | ||
| 392 | /// Queues the message to be sent. | ||
| 393 | /// | ||
| 394 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 395 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { | ||
| 396 | poll_fn(|cx| { | ||
| 397 | T::state().tx_mode.register(cx.waker()); | ||
| 398 | if let Ok(status) = Registers(T::regs()).transmit(frame) { | ||
| 399 | return Poll::Ready(status); | ||
| 400 | } | ||
| 401 | |||
| 402 | Poll::Pending | ||
| 403 | }) | ||
| 404 | .await | ||
| 405 | } | ||
| 406 | |||
| 407 | /// Attempts to transmit a frame without blocking. | ||
| 408 | /// | ||
| 409 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 410 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { | ||
| 411 | Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) | ||
| 412 | } | ||
| 413 | |||
| 414 | async fn flush_inner(mb: Mailbox) { | ||
| 415 | poll_fn(|cx| { | ||
| 416 | T::state().tx_mode.register(cx.waker()); | ||
| 417 | if T::regs().tsr().read().tme(mb.index()) { | ||
| 418 | return Poll::Ready(()); | ||
| 419 | } | ||
| 420 | |||
| 421 | Poll::Pending | ||
| 422 | }) | ||
| 423 | .await; | ||
| 424 | } | ||
| 425 | |||
| 426 | /// Waits for a specific transmit mailbox to become empty | ||
| 427 | pub async fn flush(&self, mb: Mailbox) { | ||
| 428 | Self::flush_inner(mb).await | ||
| 429 | } | ||
| 430 | |||
| 431 | async fn flush_any_inner() { | ||
| 432 | poll_fn(|cx| { | ||
| 433 | T::state().tx_mode.register(cx.waker()); | ||
| 434 | |||
| 435 | let tsr = T::regs().tsr().read(); | ||
| 436 | if tsr.tme(Mailbox::Mailbox0.index()) | ||
| 437 | || tsr.tme(Mailbox::Mailbox1.index()) | ||
| 438 | || tsr.tme(Mailbox::Mailbox2.index()) | ||
| 439 | { | ||
| 440 | return Poll::Ready(()); | ||
| 441 | } | ||
| 442 | |||
| 443 | Poll::Pending | ||
| 444 | }) | ||
| 445 | .await; | ||
| 446 | } | ||
| 447 | |||
| 448 | /// Waits until any of the transmit mailboxes become empty | ||
| 449 | pub async fn flush_any(&self) { | ||
| 450 | Self::flush_any_inner().await | ||
| 451 | } | ||
| 452 | |||
| 453 | async fn flush_all_inner() { | ||
| 454 | poll_fn(|cx| { | ||
| 455 | T::state().tx_mode.register(cx.waker()); | ||
| 456 | |||
| 457 | let tsr = T::regs().tsr().read(); | ||
| 458 | if tsr.tme(Mailbox::Mailbox0.index()) | ||
| 459 | && tsr.tme(Mailbox::Mailbox1.index()) | ||
| 460 | && tsr.tme(Mailbox::Mailbox2.index()) | ||
| 461 | { | ||
| 462 | return Poll::Ready(()); | ||
| 463 | } | ||
| 464 | |||
| 465 | Poll::Pending | ||
| 466 | }) | ||
| 467 | .await; | ||
| 468 | } | ||
| 469 | |||
| 470 | /// Waits until all of the transmit mailboxes become empty | ||
| 471 | pub async fn flush_all(&self) { | ||
| 472 | Self::flush_all_inner().await | ||
| 473 | } | ||
| 474 | |||
| 475 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 476 | /// | ||
| 477 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 478 | /// aborted, this function has no effect and returns `false`. | ||
| 479 | /// | ||
| 480 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 481 | /// returns `true`. | ||
| 482 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 483 | Registers(T::regs()).abort(mailbox) | ||
| 484 | } | ||
| 485 | |||
| 486 | /// Returns `true` if no frame is pending for transmission. | ||
| 487 | pub fn is_idle(&self) -> bool { | ||
| 488 | Registers(T::regs()).is_idle() | ||
| 489 | } | ||
| 490 | |||
| 491 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 492 | pub fn buffered<const TX_BUF_SIZE: usize>( | ||
| 493 | self, | ||
| 494 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 495 | ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 496 | BufferedCanTx::new(self, txb) | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | /// User supplied buffer for TX buffering | ||
| 501 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; | ||
| 502 | |||
| 503 | /// Buffered CAN driver, transmit half. | ||
| 504 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { | ||
| 505 | _tx: CanTx<'d, T>, | ||
| 506 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | ||
| 507 | } | ||
| 508 | |||
| 509 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 510 | fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { | ||
| 511 | Self { _tx, tx_buf }.setup() | ||
| 512 | } | ||
| 513 | |||
| 514 | fn setup(self) -> Self { | ||
| 515 | // We don't want interrupts being processed while we change modes. | ||
| 516 | critical_section::with(|_| unsafe { | ||
| 517 | let tx_inner = super::common::ClassicBufferedTxInner { | ||
| 518 | tx_receiver: self.tx_buf.receiver().into(), | ||
| 519 | }; | ||
| 520 | T::mut_state().tx_mode = TxMode::Buffered(tx_inner); | ||
| 521 | }); | ||
| 522 | self | ||
| 523 | } | ||
| 524 | |||
| 525 | /// Async write frame to TX buffer. | ||
| 526 | pub async fn write(&mut self, frame: &Frame) { | ||
| 527 | self.tx_buf.send(*frame).await; | ||
| 528 | T::TXInterrupt::pend(); // Wake for Tx | ||
| 529 | } | ||
| 530 | |||
| 531 | /// Returns a sender that can be used for sending CAN frames. | ||
| 532 | pub fn writer(&self) -> BufferedCanSender { | ||
| 533 | BufferedCanSender { | ||
| 534 | tx_buf: self.tx_buf.sender().into(), | ||
| 535 | waker: T::TXInterrupt::pend, | ||
| 536 | } | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 541 | fn drop(&mut self) { | ||
| 542 | critical_section::with(|_| unsafe { | ||
| 543 | T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 544 | }); | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | /// CAN driver, receive half. | ||
| 549 | #[allow(dead_code)] | ||
| 550 | pub struct CanRx<'d, T: Instance> { | ||
| 551 | peri: PeripheralRef<'d, T>, | ||
| 552 | } | ||
| 553 | |||
| 554 | impl<'d, T: Instance> CanRx<'d, T> { | ||
| 555 | /// Read a CAN frame. | ||
| 556 | /// | ||
| 557 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 558 | /// | ||
| 559 | /// Returns a tuple of the time the message was received and the message frame | ||
| 560 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 561 | T::state().rx_mode.read::<T>().await | ||
| 562 | } | ||
| 563 | |||
| 564 | /// Attempts to read a CAN frame without blocking. | ||
| 565 | /// | ||
| 566 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 567 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 568 | T::state().rx_mode.try_read::<T>() | ||
| 569 | } | ||
| 570 | |||
| 571 | /// Waits while receive queue is empty. | ||
| 572 | pub async fn wait_not_empty(&mut self) { | ||
| 573 | T::state().rx_mode.wait_not_empty::<T>().await | ||
| 574 | } | ||
| 575 | |||
| 576 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 577 | pub fn buffered<const RX_BUF_SIZE: usize>( | ||
| 578 | self, | ||
| 579 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | ||
| 580 | ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { | ||
| 581 | BufferedCanRx::new(self, rxb) | ||
| 582 | } | ||
| 583 | } | ||
| 584 | |||
| 585 | /// User supplied buffer for RX Buffering | ||
| 586 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; | ||
| 587 | |||
| 588 | /// CAN driver, receive half in Buffered mode. | ||
| 589 | pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { | ||
| 590 | _rx: CanRx<'d, T>, | ||
| 591 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | ||
| 592 | } | ||
| 593 | |||
| 594 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { | ||
| 595 | fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { | ||
| 596 | BufferedCanRx { _rx, rx_buf }.setup() | ||
| 597 | } | ||
| 598 | |||
| 599 | fn setup(self) -> Self { | ||
| 600 | // We don't want interrupts being processed while we change modes. | ||
| 601 | critical_section::with(|_| unsafe { | ||
| 602 | let rx_inner = super::common::ClassicBufferedRxInner { | ||
| 603 | rx_sender: self.rx_buf.sender().into(), | ||
| 604 | }; | ||
| 605 | T::mut_state().rx_mode = RxMode::Buffered(rx_inner); | ||
| 606 | }); | ||
| 607 | self | ||
| 608 | } | ||
| 609 | |||
| 610 | /// Async read frame from RX buffer. | ||
| 611 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 612 | self.rx_buf.receive().await | ||
| 613 | } | ||
| 614 | |||
| 615 | /// Attempts to read a CAN frame without blocking. | ||
| 616 | /// | ||
| 617 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 618 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 619 | match &T::state().rx_mode { | ||
| 620 | RxMode::Buffered(_) => { | ||
| 621 | if let Ok(result) = self.rx_buf.try_receive() { | ||
| 622 | match result { | ||
| 623 | Ok(envelope) => Ok(envelope), | ||
| 624 | Err(e) => Err(TryReadError::BusError(e)), | ||
| 625 | } | ||
| 626 | } else { | ||
| 627 | if let Some(err) = Registers(T::regs()).curr_error() { | ||
| 628 | return Err(TryReadError::BusError(err)); | ||
| 629 | } else { | ||
| 630 | Err(TryReadError::Empty) | ||
| 631 | } | ||
| 632 | } | ||
| 633 | } | ||
| 634 | _ => { | ||
| 635 | panic!("Bad Mode") | ||
| 636 | } | ||
| 637 | } | ||
| 638 | } | ||
| 639 | |||
| 640 | /// Waits while receive queue is empty. | ||
| 641 | pub async fn wait_not_empty(&mut self) { | ||
| 642 | poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await | ||
| 643 | } | ||
| 644 | |||
| 645 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 646 | pub fn reader(&self) -> BufferedCanReceiver { | ||
| 647 | self.rx_buf.receiver().into() | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { | ||
| 652 | fn drop(&mut self) { | ||
| 653 | critical_section::with(|_| unsafe { | ||
| 654 | T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 655 | }); | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | impl<'d, T: Instance> Drop for Can<'d, T> { | ||
| 660 | fn drop(&mut self) { | ||
| 661 | // Cannot call `free()` because it moves the instance. | ||
| 662 | // Manually reset the peripheral. | ||
| 663 | T::regs().mcr().write(|w| w.set_reset(true)); | ||
| 664 | T::disable(); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | /// Identifies one of the two receive FIFOs. | ||
| 669 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
| 670 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 671 | pub enum Fifo { | ||
| 672 | /// First receive FIFO | ||
| 673 | Fifo0 = 0, | ||
| 674 | /// Second receive FIFO | ||
| 675 | Fifo1 = 1, | ||
| 676 | } | ||
| 677 | |||
| 678 | /// Identifies one of the three transmit mailboxes. | ||
| 679 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] | ||
| 680 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 681 | pub enum Mailbox { | ||
| 682 | /// Transmit mailbox 0 | ||
| 683 | Mailbox0 = 0, | ||
| 684 | /// Transmit mailbox 1 | ||
| 685 | Mailbox1 = 1, | ||
| 686 | /// Transmit mailbox 2 | ||
| 687 | Mailbox2 = 2, | ||
| 688 | } | ||
| 689 | |||
| 690 | /// Contains information about a frame enqueued for transmission via [`Can::transmit`] or | ||
| 691 | /// [`Tx::transmit`]. | ||
| 692 | pub struct TransmitStatus { | ||
| 693 | dequeued_frame: Option<Frame>, | ||
| 694 | mailbox: Mailbox, | ||
| 695 | } | ||
| 696 | |||
| 697 | impl TransmitStatus { | ||
| 698 | /// Returns the lower-priority frame that was dequeued to make space for the new frame. | ||
| 699 | #[inline] | ||
| 700 | pub fn dequeued_frame(&self) -> Option<&Frame> { | ||
| 701 | self.dequeued_frame.as_ref() | ||
| 702 | } | ||
| 703 | |||
| 704 | /// Returns the [`Mailbox`] the frame was enqueued in. | ||
| 705 | #[inline] | ||
| 706 | pub fn mailbox(&self) -> Mailbox { | ||
| 707 | self.mailbox | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | pub(crate) enum RxMode { | ||
| 712 | NonBuffered(AtomicWaker), | ||
| 713 | Buffered(super::common::ClassicBufferedRxInner), | ||
| 714 | } | ||
| 715 | |||
| 716 | impl RxMode { | ||
| 717 | pub fn on_interrupt<T: Instance>(&self, fifo: RxFifo) { | ||
| 718 | match self { | ||
| 719 | Self::NonBuffered(waker) => { | ||
| 720 | // Disable interrupts until read | ||
| 721 | let fifo_idx = match fifo { | ||
| 722 | RxFifo::Fifo0 => 0usize, | ||
| 723 | RxFifo::Fifo1 => 1usize, | ||
| 724 | }; | ||
| 725 | T::regs().ier().write(|w| { | ||
| 726 | w.set_fmpie(fifo_idx, false); | ||
| 727 | }); | ||
| 728 | waker.wake(); | ||
| 729 | } | ||
| 730 | Self::Buffered(buf) => { | ||
| 731 | loop { | ||
| 732 | match Registers(T::regs()).receive_fifo(fifo) { | ||
| 733 | Some(envelope) => { | ||
| 734 | // NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 735 | let _ = buf.rx_sender.try_send(Ok(envelope)); | ||
| 736 | } | ||
| 737 | None => return, | ||
| 738 | }; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> { | ||
| 745 | match self { | ||
| 746 | Self::NonBuffered(waker) => { | ||
| 747 | poll_fn(|cx| { | ||
| 748 | T::state().err_waker.register(cx.waker()); | ||
| 749 | waker.register(cx.waker()); | ||
| 750 | match self.try_read::<T>() { | ||
| 751 | Ok(result) => Poll::Ready(Ok(result)), | ||
| 752 | Err(TryReadError::Empty) => Poll::Pending, | ||
| 753 | Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), | ||
| 754 | } | ||
| 755 | }) | ||
| 756 | .await | ||
| 757 | } | ||
| 758 | _ => { | ||
| 759 | panic!("Bad Mode") | ||
| 760 | } | ||
| 761 | } | ||
| 762 | } | ||
| 763 | pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { | ||
| 764 | match self { | ||
| 765 | Self::NonBuffered(_) => { | ||
| 766 | let registers = Registers(T::regs()); | ||
| 767 | if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { | ||
| 768 | T::regs().ier().write(|w| { | ||
| 769 | w.set_fmpie(0, true); | ||
| 770 | }); | ||
| 771 | Ok(msg) | ||
| 772 | } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { | ||
| 773 | T::regs().ier().write(|w| { | ||
| 774 | w.set_fmpie(1, true); | ||
| 775 | }); | ||
| 776 | Ok(msg) | ||
| 777 | } else if let Some(err) = registers.curr_error() { | ||
| 778 | Err(TryReadError::BusError(err)) | ||
| 779 | } else { | ||
| 780 | Err(TryReadError::Empty) | ||
| 781 | } | ||
| 782 | } | ||
| 783 | _ => { | ||
| 784 | panic!("Bad Mode") | ||
| 785 | } | ||
| 786 | } | ||
| 787 | } | ||
| 788 | pub async fn wait_not_empty<T: Instance>(&self) { | ||
| 789 | match &T::state().rx_mode { | ||
| 790 | Self::NonBuffered(waker) => { | ||
| 791 | poll_fn(|cx| { | ||
| 792 | waker.register(cx.waker()); | ||
| 793 | if Registers(T::regs()).receive_frame_available() { | ||
| 794 | Poll::Ready(()) | ||
| 795 | } else { | ||
| 796 | Poll::Pending | ||
| 797 | } | ||
| 798 | }) | ||
| 799 | .await | ||
| 800 | } | ||
| 801 | _ => { | ||
| 802 | panic!("Bad Mode") | ||
| 803 | } | ||
| 804 | } | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 | enum TxMode { | ||
| 809 | NonBuffered(AtomicWaker), | ||
| 810 | Buffered(super::common::ClassicBufferedTxInner), | ||
| 811 | } | ||
| 812 | |||
| 813 | impl TxMode { | ||
| 814 | pub fn buffer_free<T: Instance>(&self) -> bool { | ||
| 815 | let tsr = T::regs().tsr().read(); | ||
| 816 | tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index()) | ||
| 817 | } | ||
| 818 | pub fn on_interrupt<T: Instance>(&self) { | ||
| 819 | match &T::state().tx_mode { | ||
| 820 | TxMode::NonBuffered(waker) => waker.wake(), | ||
| 821 | TxMode::Buffered(buf) => { | ||
| 822 | while self.buffer_free::<T>() { | ||
| 823 | match buf.tx_receiver.try_receive() { | ||
| 824 | Ok(frame) => { | ||
| 825 | _ = Registers(T::regs()).transmit(&frame); | ||
| 826 | } | ||
| 827 | Err(_) => { | ||
| 828 | break; | ||
| 829 | } | ||
| 830 | } | ||
| 831 | } | ||
| 832 | } | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | fn register(&self, arg: &core::task::Waker) { | ||
| 837 | match self { | ||
| 838 | TxMode::NonBuffered(waker) => { | ||
| 839 | waker.register(arg); | ||
| 840 | } | ||
| 841 | _ => { | ||
| 842 | panic!("Bad mode"); | ||
| 843 | } | ||
| 844 | } | ||
| 845 | } | ||
| 846 | } | ||
| 847 | |||
| 848 | struct State { | ||
| 849 | pub(crate) rx_mode: RxMode, | ||
| 850 | pub(crate) tx_mode: TxMode, | ||
| 851 | pub err_waker: AtomicWaker, | ||
| 852 | } | ||
| 853 | |||
| 854 | impl State { | ||
| 855 | pub const fn new() -> Self { | ||
| 856 | Self { | ||
| 857 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), | ||
| 858 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | ||
| 859 | err_waker: AtomicWaker::new(), | ||
| 860 | } | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 864 | trait SealedInstance { | ||
| 865 | fn regs() -> crate::pac::can::Can; | ||
| 866 | fn state() -> &'static State; | ||
| 867 | unsafe fn mut_state() -> &'static mut State; | ||
| 868 | } | ||
| 869 | |||
| 870 | /// CAN instance trait. | ||
| 871 | #[allow(private_bounds)] | ||
| 872 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + 'static { | ||
| 873 | /// TX interrupt for this instance. | ||
| 874 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 875 | /// RX0 interrupt for this instance. | ||
| 876 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 877 | /// RX1 interrupt for this instance. | ||
| 878 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 879 | /// SCE interrupt for this instance. | ||
| 880 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 881 | } | ||
| 882 | |||
| 883 | /// A bxCAN instance that owns filter banks. | ||
| 884 | /// | ||
| 885 | /// In master-slave-instance setups, only the master instance owns the filter banks, and needs to | ||
| 886 | /// split some of them off for use by the slave instance. In that case, the master instance should | ||
| 887 | /// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement | ||
| 888 | /// [`Instance`]. | ||
| 889 | /// | ||
| 890 | /// In single-instance configurations, the instance owns all filter banks and they can not be split | ||
| 891 | /// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. | ||
| 892 | /// | ||
| 893 | /// # Safety | ||
| 894 | /// | ||
| 895 | /// This trait must only be implemented if the instance does, in fact, own its associated filter | ||
| 896 | /// banks, and `NUM_FILTER_BANKS` must be correct. | ||
| 897 | pub unsafe trait FilterOwner: Instance { | ||
| 898 | /// The total number of filter banks available to the instance. | ||
| 899 | /// | ||
| 900 | /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. | ||
| 901 | const NUM_FILTER_BANKS: u8; | ||
| 902 | } | ||
| 903 | |||
| 904 | /// A bxCAN master instance that shares filter banks with a slave instance. | ||
| 905 | /// | ||
| 906 | /// In master-slave-instance setups, this trait should be implemented for the master instance. | ||
| 907 | /// | ||
| 908 | /// # Safety | ||
| 909 | /// | ||
| 910 | /// This trait must only be implemented when there is actually an associated slave instance. | ||
| 911 | pub unsafe trait MasterInstance: FilterOwner {} | ||
| 912 | |||
| 913 | foreach_peripheral!( | ||
| 914 | (can, $inst:ident) => { | ||
| 915 | impl SealedInstance for peripherals::$inst { | ||
| 916 | |||
| 917 | fn regs() -> crate::pac::can::Can { | ||
| 918 | crate::pac::$inst | ||
| 919 | } | ||
| 920 | |||
| 921 | unsafe fn mut_state() -> & 'static mut State { | ||
| 922 | static mut STATE: State = State::new(); | ||
| 923 | &mut *core::ptr::addr_of_mut!(STATE) | ||
| 924 | } | ||
| 925 | fn state() -> &'static State { | ||
| 926 | unsafe { peripherals::$inst::mut_state() } | ||
| 927 | } | ||
| 928 | } | ||
| 929 | |||
| 930 | impl Instance for peripherals::$inst { | ||
| 931 | type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; | ||
| 932 | type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; | ||
| 933 | type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; | ||
| 934 | type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; | ||
| 935 | } | ||
| 936 | }; | ||
| 937 | ); | ||
| 938 | |||
| 939 | foreach_peripheral!( | ||
| 940 | (can, CAN) => { | ||
| 941 | unsafe impl FilterOwner for peripherals::CAN { | ||
| 942 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 943 | } | ||
| 944 | }; | ||
| 945 | // CAN1 and CAN2 is a combination of master and slave instance. | ||
| 946 | // CAN1 owns the filter bank and needs to be enabled in order | ||
| 947 | // for CAN2 to receive messages. | ||
| 948 | (can, CAN1) => { | ||
| 949 | cfg_if::cfg_if! { | ||
| 950 | if #[cfg(all( | ||
| 951 | any(stm32l4, stm32f72, stm32f73), | ||
| 952 | not(any(stm32l49, stm32l4a)) | ||
| 953 | ))] { | ||
| 954 | // Most L4 devices and some F7 devices use the name "CAN1" | ||
| 955 | // even if there is no "CAN2" peripheral. | ||
| 956 | unsafe impl FilterOwner for peripherals::CAN1 { | ||
| 957 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 958 | } | ||
| 959 | } else { | ||
| 960 | unsafe impl FilterOwner for peripherals::CAN1 { | ||
| 961 | const NUM_FILTER_BANKS: u8 = 28; | ||
| 962 | } | ||
| 963 | unsafe impl MasterInstance for peripherals::CAN1 {} | ||
| 964 | } | ||
| 965 | } | ||
| 966 | }; | ||
| 967 | (can, CAN3) => { | ||
| 968 | unsafe impl FilterOwner for peripherals::CAN3 { | ||
| 969 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 970 | } | ||
| 971 | }; | ||
| 972 | ); | ||
| 973 | |||
| 974 | pin_trait!(RxPin, Instance); | ||
| 975 | pin_trait!(TxPin, Instance); | ||
| 976 | |||
| 977 | trait Index { | ||
| 978 | fn index(&self) -> usize; | ||
| 979 | } | ||
| 980 | |||
| 981 | impl Index for Mailbox { | ||
| 982 | fn index(&self) -> usize { | ||
| 983 | match self { | ||
| 984 | Mailbox::Mailbox0 => 0, | ||
| 985 | Mailbox::Mailbox1 => 1, | ||
| 986 | Mailbox::Mailbox2 => 2, | ||
| 987 | } | ||
| 988 | } | ||
| 989 | } | ||
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs new file mode 100644 index 000000000..732567797 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/registers.rs | |||
| @@ -0,0 +1,510 @@ | |||
| 1 | use core::cmp::Ordering; | ||
| 2 | use core::convert::Infallible; | ||
| 3 | |||
| 4 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 5 | use stm32_metapac::can::vals::Lec; | ||
| 6 | |||
| 7 | use super::{Mailbox, TransmitStatus}; | ||
| 8 | use crate::can::enums::BusError; | ||
| 9 | use crate::can::frame::{Envelope, Frame, Header}; | ||
| 10 | |||
| 11 | pub(crate) struct Registers(pub crate::pac::can::Can); | ||
| 12 | |||
| 13 | impl Registers { | ||
| 14 | pub fn enter_init_mode(&mut self) { | ||
| 15 | self.0.mcr().modify(|reg| { | ||
| 16 | reg.set_sleep(false); | ||
| 17 | reg.set_inrq(true); | ||
| 18 | }); | ||
| 19 | loop { | ||
| 20 | let msr = self.0.msr().read(); | ||
| 21 | if !msr.slak() && msr.inak() { | ||
| 22 | break; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | // Leaves initialization mode, enters sleep mode. | ||
| 28 | pub fn leave_init_mode(&mut self) { | ||
| 29 | self.0.mcr().modify(|reg| { | ||
| 30 | reg.set_sleep(true); | ||
| 31 | reg.set_inrq(false); | ||
| 32 | }); | ||
| 33 | loop { | ||
| 34 | let msr = self.0.msr().read(); | ||
| 35 | if msr.slak() && !msr.inak() { | ||
| 36 | break; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 42 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 43 | let seg1 = u8::from(bt.seg1); | ||
| 44 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 45 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 46 | self.0.btr().modify(|reg| { | ||
| 47 | reg.set_brp(prescaler - 1); | ||
| 48 | reg.set_ts(0, seg1 - 1); | ||
| 49 | reg.set_ts(1, seg2 - 1); | ||
| 50 | reg.set_sjw(sync_jump_width - 1); | ||
| 51 | }); | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 55 | pub fn set_silent(&self, enabled: bool) { | ||
| 56 | let mode = match enabled { | ||
| 57 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 58 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 59 | }; | ||
| 60 | self.0.btr().modify(|reg| reg.set_silm(mode)); | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Enables or disables automatic retransmission of messages. | ||
| 64 | /// | ||
| 65 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 66 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 67 | /// | ||
| 68 | /// Automatic retransmission is enabled by default. | ||
| 69 | pub fn set_automatic_retransmit(&self, enabled: bool) { | ||
| 70 | self.0.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 74 | /// signals together. | ||
| 75 | pub fn set_loopback(&self, enabled: bool) { | ||
| 76 | self.0.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Configures the automatic wake-up feature. | ||
| 80 | /// | ||
| 81 | /// This is turned off by default. | ||
| 82 | /// | ||
| 83 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 84 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 85 | /// frame. | ||
| 86 | #[allow(dead_code)] | ||
| 87 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 88 | self.0.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 92 | /// | ||
| 93 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 94 | /// if you want non-blocking initialization. | ||
| 95 | /// | ||
| 96 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 97 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 98 | /// successfully. | ||
| 99 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 100 | let msr = self.0.msr().read(); | ||
| 101 | if msr.slak() { | ||
| 102 | self.0.mcr().modify(|reg| { | ||
| 103 | reg.set_abom(true); | ||
| 104 | reg.set_sleep(false); | ||
| 105 | }); | ||
| 106 | Err(nb::Error::WouldBlock) | ||
| 107 | } else { | ||
| 108 | Ok(()) | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Puts the peripheral in a sleep mode to save power. | ||
| 113 | /// | ||
| 114 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 115 | #[allow(dead_code)] | ||
| 116 | pub fn sleep(&mut self) { | ||
| 117 | self.0.mcr().modify(|reg| { | ||
| 118 | reg.set_sleep(true); | ||
| 119 | reg.set_inrq(false); | ||
| 120 | }); | ||
| 121 | loop { | ||
| 122 | let msr = self.0.msr().read(); | ||
| 123 | if msr.slak() && !msr.inak() { | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Wakes up from sleep mode. | ||
| 130 | /// | ||
| 131 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 132 | /// frame will cause that interrupt. | ||
| 133 | #[allow(dead_code)] | ||
| 134 | pub fn wakeup(&mut self) { | ||
| 135 | self.0.mcr().modify(|reg| { | ||
| 136 | reg.set_sleep(false); | ||
| 137 | reg.set_inrq(false); | ||
| 138 | }); | ||
| 139 | loop { | ||
| 140 | let msr = self.0.msr().read(); | ||
| 141 | if !msr.slak() && !msr.inak() { | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn curr_error(&self) -> Option<BusError> { | ||
| 148 | let err = { self.0.esr().read() }; | ||
| 149 | if err.boff() { | ||
| 150 | return Some(BusError::BusOff); | ||
| 151 | } else if err.epvf() { | ||
| 152 | return Some(BusError::BusPassive); | ||
| 153 | } else if err.ewgf() { | ||
| 154 | return Some(BusError::BusWarning); | ||
| 155 | } else if err.lec() != Lec::NOERROR { | ||
| 156 | return Some(match err.lec() { | ||
| 157 | Lec::STUFF => BusError::Stuff, | ||
| 158 | Lec::FORM => BusError::Form, | ||
| 159 | Lec::ACK => BusError::Acknowledge, | ||
| 160 | Lec::BITRECESSIVE => BusError::BitRecessive, | ||
| 161 | Lec::BITDOMINANT => BusError::BitDominant, | ||
| 162 | Lec::CRC => BusError::Crc, | ||
| 163 | Lec::CUSTOM => BusError::Software, | ||
| 164 | Lec::NOERROR => unreachable!(), | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | None | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 171 | /// | ||
| 172 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 173 | /// Transmit order is preserved for frames with identical priority. | ||
| 174 | /// | ||
| 175 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 176 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 177 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 178 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 179 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 180 | // Get the index of the next free mailbox or the one with the lowest priority. | ||
| 181 | let tsr = self.0.tsr().read(); | ||
| 182 | let idx = tsr.code() as usize; | ||
| 183 | |||
| 184 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 185 | let pending_frame = if frame_is_pending { | ||
| 186 | // High priority frames are transmitted first by the mailbox system. | ||
| 187 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 188 | // The controller schedules pending frames of same priority based on the | ||
| 189 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 190 | // and only accept higher priority frames. | ||
| 191 | self.check_priority(0, frame.id().into())?; | ||
| 192 | self.check_priority(1, frame.id().into())?; | ||
| 193 | self.check_priority(2, frame.id().into())?; | ||
| 194 | |||
| 195 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 196 | if all_frames_are_pending { | ||
| 197 | // No free mailbox is available. This can only happen when three frames with | ||
| 198 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 199 | // of them are blocked by bus traffic with even higher priority. | ||
| 200 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 201 | self.read_pending_mailbox(idx) | ||
| 202 | } else { | ||
| 203 | // There was a free mailbox. | ||
| 204 | None | ||
| 205 | } | ||
| 206 | } else { | ||
| 207 | // All mailboxes are available: Send frame without performing any checks. | ||
| 208 | None | ||
| 209 | }; | ||
| 210 | |||
| 211 | self.write_mailbox(idx, frame); | ||
| 212 | |||
| 213 | let mailbox = match idx { | ||
| 214 | 0 => Mailbox::Mailbox0, | ||
| 215 | 1 => Mailbox::Mailbox1, | ||
| 216 | 2 => Mailbox::Mailbox2, | ||
| 217 | _ => unreachable!(), | ||
| 218 | }; | ||
| 219 | Ok(TransmitStatus { | ||
| 220 | dequeued_frame: pending_frame, | ||
| 221 | mailbox, | ||
| 222 | }) | ||
| 223 | } | ||
| 224 | |||
| 225 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 226 | /// lower priority (higher ID) than the identifier `id`. | ||
| 227 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 228 | // Read the pending frame's id to check its priority. | ||
| 229 | assert!(idx < 3); | ||
| 230 | let tir = &self.0.tx(idx).tir().read(); | ||
| 231 | //let tir = &can.tx[idx].tir.read(); | ||
| 232 | |||
| 233 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 234 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 235 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 236 | // There's a mailbox whose priority is higher or equal | ||
| 237 | // the priority of the new frame. | ||
| 238 | return Err(nb::Error::WouldBlock); | ||
| 239 | } | ||
| 240 | |||
| 241 | Ok(()) | ||
| 242 | } | ||
| 243 | |||
| 244 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 245 | debug_assert!(idx < 3); | ||
| 246 | |||
| 247 | let mb = self.0.tx(idx); | ||
| 248 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 249 | |||
| 250 | mb.tdlr() | ||
| 251 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 252 | mb.tdhr() | ||
| 253 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 254 | let id: IdReg = frame.id().into(); | ||
| 255 | mb.tir().write(|w| { | ||
| 256 | w.0 = id.0; | ||
| 257 | w.set_txrq(true); | ||
| 258 | }); | ||
| 259 | } | ||
| 260 | |||
| 261 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 262 | if self.abort_by_index(idx) { | ||
| 263 | debug_assert!(idx < 3); | ||
| 264 | |||
| 265 | let mb = self.0.tx(idx); | ||
| 266 | |||
| 267 | let id = IdReg(mb.tir().read().0); | ||
| 268 | let mut data = [0xff; 8]; | ||
| 269 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 270 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 271 | let len = mb.tdtr().read().dlc(); | ||
| 272 | |||
| 273 | Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | ||
| 274 | } else { | ||
| 275 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 276 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 277 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 278 | // has preempted the execution. | ||
| 279 | None | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 284 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 285 | self.0.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 286 | |||
| 287 | // Wait for the abort request to be finished. | ||
| 288 | loop { | ||
| 289 | let tsr = self.0.tsr().read(); | ||
| 290 | if false == tsr.abrq(idx) { | ||
| 291 | break tsr.txok(idx) == false; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 297 | /// | ||
| 298 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 299 | /// aborted, this function has no effect and returns `false`. | ||
| 300 | /// | ||
| 301 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 302 | /// returns `true`. | ||
| 303 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 304 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | ||
| 305 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 306 | let tsr = self.0.tsr().read(); | ||
| 307 | let mailbox_empty = match mailbox { | ||
| 308 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 309 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 310 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 311 | }; | ||
| 312 | if mailbox_empty { | ||
| 313 | false | ||
| 314 | } else { | ||
| 315 | self.abort_by_index(mailbox as usize) | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | /// Returns `true` if no frame is pending for transmission. | ||
| 320 | pub fn is_idle(&self) -> bool { | ||
| 321 | let tsr = self.0.tsr().read(); | ||
| 322 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 323 | } | ||
| 324 | |||
| 325 | pub fn receive_frame_available(&self) -> bool { | ||
| 326 | if self.0.rfr(0).read().fmp() != 0 { | ||
| 327 | true | ||
| 328 | } else if self.0.rfr(1).read().fmp() != 0 { | ||
| 329 | true | ||
| 330 | } else { | ||
| 331 | false | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | pub fn receive_fifo(&self, fifo: RxFifo) -> Option<Envelope> { | ||
| 336 | // Generate timestamp as early as possible | ||
| 337 | #[cfg(feature = "time")] | ||
| 338 | let ts = embassy_time::Instant::now(); | ||
| 339 | |||
| 340 | use crate::pac::can::vals::Ide; | ||
| 341 | |||
| 342 | let fifo_idx = match fifo { | ||
| 343 | RxFifo::Fifo0 => 0usize, | ||
| 344 | RxFifo::Fifo1 => 1usize, | ||
| 345 | }; | ||
| 346 | let rfr = self.0.rfr(fifo_idx); | ||
| 347 | let fifo = self.0.rx(fifo_idx); | ||
| 348 | |||
| 349 | // If there are no pending messages, there is nothing to do | ||
| 350 | if rfr.read().fmp() == 0 { | ||
| 351 | return None; | ||
| 352 | } | ||
| 353 | |||
| 354 | let rir = fifo.rir().read(); | ||
| 355 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 356 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 357 | } else { | ||
| 358 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 359 | let exid = rir.exid() & 0x3FFFF; | ||
| 360 | let id = (stid << 18) | (exid); | ||
| 361 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 362 | }; | ||
| 363 | let rdtr = fifo.rdtr().read(); | ||
| 364 | let data_len = rdtr.dlc(); | ||
| 365 | let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; | ||
| 366 | |||
| 367 | #[cfg(not(feature = "time"))] | ||
| 368 | let ts = rdtr.time(); | ||
| 369 | |||
| 370 | let mut data: [u8; 8] = [0; 8]; | ||
| 371 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 372 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 373 | |||
| 374 | let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); | ||
| 375 | let envelope = Envelope { ts, frame }; | ||
| 376 | |||
| 377 | rfr.modify(|v| v.set_rfom(true)); | ||
| 378 | |||
| 379 | Some(envelope) | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Identifier of a CAN message. | ||
| 384 | /// | ||
| 385 | /// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a | ||
| 386 | /// extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 387 | /// | ||
| 388 | /// The `Ord` trait can be used to determine the frame’s priority this ID | ||
| 389 | /// belongs to. | ||
| 390 | /// Lower identifier values have a higher priority. Additionally standard frames | ||
| 391 | /// have a higher priority than extended frames and data frames have a higher | ||
| 392 | /// priority than remote frames. | ||
| 393 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 394 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 395 | pub(crate) struct IdReg(u32); | ||
| 396 | |||
| 397 | impl IdReg { | ||
| 398 | const STANDARD_SHIFT: u32 = 21; | ||
| 399 | |||
| 400 | const EXTENDED_SHIFT: u32 = 3; | ||
| 401 | |||
| 402 | const IDE_MASK: u32 = 0x0000_0004; | ||
| 403 | |||
| 404 | const RTR_MASK: u32 = 0x0000_0002; | ||
| 405 | |||
| 406 | /// Creates a new standard identifier (11bit, Range: 0..0x7FF) | ||
| 407 | /// | ||
| 408 | /// Panics for IDs outside the allowed range. | ||
| 409 | fn new_standard(id: StandardId) -> Self { | ||
| 410 | Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) | ||
| 411 | } | ||
| 412 | |||
| 413 | /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 414 | /// | ||
| 415 | /// Panics for IDs outside the allowed range. | ||
| 416 | fn new_extended(id: ExtendedId) -> IdReg { | ||
| 417 | Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) | ||
| 418 | } | ||
| 419 | |||
| 420 | fn from_register(reg: u32) -> IdReg { | ||
| 421 | Self(reg & 0xFFFF_FFFE) | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Returns the identifier. | ||
| 425 | fn to_id(self) -> Id { | ||
| 426 | if self.is_extended() { | ||
| 427 | Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) | ||
| 428 | } else { | ||
| 429 | Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | /// Returns the identifier. | ||
| 434 | fn id(self) -> embedded_can::Id { | ||
| 435 | if self.is_extended() { | ||
| 436 | embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) | ||
| 437 | .unwrap() | ||
| 438 | .into() | ||
| 439 | } else { | ||
| 440 | embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) | ||
| 441 | .unwrap() | ||
| 442 | .into() | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Returns `true` if the identifier is an extended identifier. | ||
| 447 | fn is_extended(self) -> bool { | ||
| 448 | self.0 & Self::IDE_MASK != 0 | ||
| 449 | } | ||
| 450 | |||
| 451 | /// Returns `true` if the identifer is part of a remote frame (RTR bit set). | ||
| 452 | fn rtr(self) -> bool { | ||
| 453 | self.0 & Self::RTR_MASK != 0 | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | impl From<&embedded_can::Id> for IdReg { | ||
| 458 | fn from(eid: &embedded_can::Id) -> Self { | ||
| 459 | match eid { | ||
| 460 | embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), | ||
| 461 | embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), | ||
| 462 | } | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | impl From<IdReg> for embedded_can::Id { | ||
| 467 | fn from(idr: IdReg) -> Self { | ||
| 468 | idr.id() | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | /// `IdReg` is ordered by priority. | ||
| 473 | impl Ord for IdReg { | ||
| 474 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 475 | // When the IDs match, data frames have priority over remote frames. | ||
| 476 | let rtr = self.rtr().cmp(&other.rtr()).reverse(); | ||
| 477 | |||
| 478 | let id_a = self.to_id(); | ||
| 479 | let id_b = other.to_id(); | ||
| 480 | match (id_a, id_b) { | ||
| 481 | (Id::Standard(a), Id::Standard(b)) => { | ||
| 482 | // Lower IDs have priority over higher IDs. | ||
| 483 | a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) | ||
| 484 | } | ||
| 485 | (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), | ||
| 486 | (Id::Standard(a), Id::Extended(b)) => { | ||
| 487 | // Standard frames have priority over extended frames if their Base IDs match. | ||
| 488 | a.as_raw() | ||
| 489 | .cmp(&b.standard_id().as_raw()) | ||
| 490 | .reverse() | ||
| 491 | .then(Ordering::Greater) | ||
| 492 | } | ||
| 493 | (Id::Extended(a), Id::Standard(b)) => { | ||
| 494 | a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) | ||
| 495 | } | ||
| 496 | } | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | impl PartialOrd for IdReg { | ||
| 501 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 502 | Some(self.cmp(other)) | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 507 | pub(crate) enum RxFifo { | ||
| 508 | Fifo0, | ||
| 509 | Fifo1, | ||
| 510 | } | ||
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs new file mode 100644 index 000000000..a54b54f6e --- /dev/null +++ b/embassy-stm32/src/can/common.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | ||
| 2 | |||
| 3 | use super::enums::*; | ||
| 4 | use super::frame::*; | ||
| 5 | |||
| 6 | pub(crate) struct ClassicBufferedRxInner { | ||
| 7 | pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>, | ||
| 8 | } | ||
| 9 | pub(crate) struct ClassicBufferedTxInner { | ||
| 10 | pub tx_receiver: DynamicReceiver<'static, Frame>, | ||
| 11 | } | ||
| 12 | |||
| 13 | #[cfg(any(can_fdcan_v1, can_fdcan_h7))] | ||
| 14 | |||
| 15 | pub(crate) struct FdBufferedRxInner { | ||
| 16 | pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>, | ||
| 17 | } | ||
| 18 | |||
| 19 | #[cfg(any(can_fdcan_v1, can_fdcan_h7))] | ||
| 20 | pub(crate) struct FdBufferedTxInner { | ||
| 21 | pub tx_receiver: DynamicReceiver<'static, FdFrame>, | ||
| 22 | } | ||
| 23 | |||
| 24 | /// Sender that can be used for sending CAN frames. | ||
| 25 | #[derive(Copy, Clone)] | ||
| 26 | pub struct BufferedCanSender { | ||
| 27 | pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>, | ||
| 28 | pub(crate) waker: fn(), | ||
| 29 | } | ||
| 30 | |||
| 31 | impl BufferedCanSender { | ||
| 32 | /// Async write frame to TX buffer. | ||
| 33 | pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> { | ||
| 34 | self.tx_buf.try_send(frame)?; | ||
| 35 | (self.waker)(); | ||
| 36 | Ok(()) | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Async write frame to TX buffer. | ||
| 40 | pub async fn write(&mut self, frame: Frame) { | ||
| 41 | self.tx_buf.send(frame).await; | ||
| 42 | (self.waker)(); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Allows a poll_fn to poll until the channel is ready to write | ||
| 46 | pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { | ||
| 47 | self.tx_buf.poll_ready_to_send(cx) | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 52 | pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>; | ||
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 36139a45c..4d89c84d1 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -28,3 +28,25 @@ pub enum BusError { | |||
| 28 | /// At least one of error counter has reached the Error_Warning limit of 96. | 28 | /// At least one of error counter has reached the Error_Warning limit of 96. |
| 29 | BusWarning, | 29 | BusWarning, |
| 30 | } | 30 | } |
| 31 | |||
| 32 | /// Frame Create Errors | ||
| 33 | #[derive(Debug)] | ||
| 34 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 35 | pub enum FrameCreateError { | ||
| 36 | /// Data in header does not match supplied. | ||
| 37 | NotEnoughData, | ||
| 38 | /// Invalid data length not 0-8 for Classic packet or valid for FD. | ||
| 39 | InvalidDataLength, | ||
| 40 | /// Invalid ID. | ||
| 41 | InvalidCanId, | ||
| 42 | } | ||
| 43 | |||
| 44 | /// Error returned by `try_read` | ||
| 45 | #[derive(Debug)] | ||
| 46 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 47 | pub enum TryReadError { | ||
| 48 | /// Bus error | ||
| 49 | BusError(BusError), | ||
| 50 | /// Receive buffer is empty | ||
| 51 | Empty, | ||
| 52 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs index 830edf3bb..040a999b4 100644 --- a/embassy-stm32/src/can/fd/message_ram/mod.rs +++ b/embassy-stm32/src/can/fd/message_ram/mod.rs | |||
| @@ -140,26 +140,6 @@ pub(crate) struct _TxBufferElement; | |||
| 140 | impl generic::Readable for TxBufferElementHeader {} | 140 | impl generic::Readable for TxBufferElementHeader {} |
| 141 | impl generic::Writable for TxBufferElementHeader {} | 141 | impl generic::Writable for TxBufferElementHeader {} |
| 142 | 142 | ||
| 143 | /// FdCan Message RAM instance. | ||
| 144 | /// | ||
| 145 | /// # Safety | ||
| 146 | /// | ||
| 147 | /// It is only safe to implement this trait, when: | ||
| 148 | /// | ||
| 149 | /// * The implementing type has ownership of the Message RAM, preventing any | ||
| 150 | /// other accesses to the register block. | ||
| 151 | /// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed | ||
| 152 | /// for as long as ownership or a borrow of the implementing type is present. | ||
| 153 | pub unsafe trait Instance { | ||
| 154 | const MSG_RAM: *mut RegisterBlock; | ||
| 155 | fn msg_ram(&self) -> &RegisterBlock { | ||
| 156 | unsafe { &*Self::MSG_RAM } | ||
| 157 | } | ||
| 158 | fn msg_ram_mut(&mut self) -> &mut RegisterBlock { | ||
| 159 | unsafe { &mut *Self::MSG_RAM } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | // Ensure the RegisterBlock is the same size as on pg 1957 of RM0440. | 143 | // Ensure the RegisterBlock is the same size as on pg 1957 of RM0440. |
| 164 | static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); | 144 | static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); |
| 165 | static_assertions::assert_eq_size!(Receive, [u32; 54]); | 145 | static_assertions::assert_eq_size!(Receive, [u32; 54]); |
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 8ec09ac12..e32f19d91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs | |||
| @@ -30,7 +30,12 @@ impl Registers { | |||
| 30 | &mut self.msg_ram_mut().transmit.tbsa[bufidx] | 30 | &mut self.msg_ram_mut().transmit.tbsa[bufidx] |
| 31 | } | 31 | } |
| 32 | pub fn msg_ram_mut(&self) -> &mut RegisterBlock { | 32 | pub fn msg_ram_mut(&self) -> &mut RegisterBlock { |
| 33 | #[cfg(stm32h7)] | ||
| 34 | let ptr = self.msgram.ram(self.msg_ram_offset / 4).as_ptr() as *mut RegisterBlock; | ||
| 35 | |||
| 36 | #[cfg(not(stm32h7))] | ||
| 33 | let ptr = self.msgram.as_ptr() as *mut RegisterBlock; | 37 | let ptr = self.msgram.as_ptr() as *mut RegisterBlock; |
| 38 | |||
| 34 | unsafe { &mut (*ptr) } | 39 | unsafe { &mut (*ptr) } |
| 35 | } | 40 | } |
| 36 | 41 | ||
| @@ -56,7 +61,10 @@ impl Registers { | |||
| 56 | match maybe_header { | 61 | match maybe_header { |
| 57 | Some((header, ts)) => { | 62 | Some((header, ts)) => { |
| 58 | let data = &buffer[0..header.len() as usize]; | 63 | let data = &buffer[0..header.len() as usize]; |
| 59 | Some((F::from_header(header, data)?, ts)) | 64 | match F::from_header(header, data) { |
| 65 | Ok(frame) => Some((frame, ts)), | ||
| 66 | Err(_) => None, | ||
| 67 | } | ||
| 60 | } | 68 | } |
| 61 | None => None, | 69 | None => None, |
| 62 | } | 70 | } |
| @@ -182,7 +190,7 @@ impl Registers { | |||
| 182 | DataLength::Fdcan(len) => len, | 190 | DataLength::Fdcan(len) => len, |
| 183 | DataLength::Classic(len) => len, | 191 | DataLength::Classic(len) => len, |
| 184 | }; | 192 | }; |
| 185 | if len as usize > ClassicFrame::MAX_DATA_LEN { | 193 | if len as usize > ClassicData::MAX_DATA_LEN { |
| 186 | return None; | 194 | return None; |
| 187 | } | 195 | } |
| 188 | 196 | ||
| @@ -317,17 +325,6 @@ impl Registers { | |||
| 317 | */ | 325 | */ |
| 318 | } | 326 | } |
| 319 | 327 | ||
| 320 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | ||
| 321 | #[inline] | ||
| 322 | pub fn free(mut self) { | ||
| 323 | //self.disable_interrupts(Interrupts::all()); | ||
| 324 | |||
| 325 | //TODO check this! | ||
| 326 | self.enter_init_mode(); | ||
| 327 | self.set_power_down_mode(true); | ||
| 328 | //self.control.instance | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] | 328 | /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] |
| 332 | #[inline] | 329 | #[inline] |
| 333 | pub fn apply_config(&mut self, config: FdCanConfig) { | 330 | pub fn apply_config(&mut self, config: FdCanConfig) { |
| @@ -400,66 +397,17 @@ impl Registers { | |||
| 400 | 397 | ||
| 401 | /// Moves out of ConfigMode and into specified mode | 398 | /// Moves out of ConfigMode and into specified mode |
| 402 | #[inline] | 399 | #[inline] |
| 403 | pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { | 400 | pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) { |
| 404 | match mode { | 401 | match mode { |
| 405 | crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), | 402 | crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), |
| 406 | crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), | 403 | crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), |
| 407 | crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), | 404 | crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true), |
| 408 | crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), | 405 | crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), |
| 409 | crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), | 406 | crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), |
| 410 | } | 407 | } |
| 411 | self.leave_init_mode(config); | 408 | self.leave_init_mode(config); |
| 412 | } | 409 | } |
| 413 | 410 | ||
| 414 | /// Moves out of ConfigMode and into InternalLoopbackMode | ||
| 415 | #[inline] | ||
| 416 | pub fn into_internal_loopback(mut self, config: FdCanConfig) { | ||
| 417 | self.set_loopback_mode(LoopbackMode::Internal); | ||
| 418 | self.leave_init_mode(config); | ||
| 419 | } | ||
| 420 | |||
| 421 | /// Moves out of ConfigMode and into ExternalLoopbackMode | ||
| 422 | #[inline] | ||
| 423 | pub fn into_external_loopback(mut self, config: FdCanConfig) { | ||
| 424 | self.set_loopback_mode(LoopbackMode::External); | ||
| 425 | self.leave_init_mode(config); | ||
| 426 | } | ||
| 427 | |||
| 428 | /// Moves out of ConfigMode and into RestrictedOperationMode | ||
| 429 | #[inline] | ||
| 430 | pub fn into_restricted(mut self, config: FdCanConfig) { | ||
| 431 | self.set_restricted_operations(true); | ||
| 432 | self.leave_init_mode(config); | ||
| 433 | } | ||
| 434 | |||
| 435 | /// Moves out of ConfigMode and into NormalOperationMode | ||
| 436 | #[inline] | ||
| 437 | pub fn into_normal(mut self, config: FdCanConfig) { | ||
| 438 | self.set_normal_operations(true); | ||
| 439 | self.leave_init_mode(config); | ||
| 440 | } | ||
| 441 | |||
| 442 | /// Moves out of ConfigMode and into BusMonitoringMode | ||
| 443 | #[inline] | ||
| 444 | pub fn into_bus_monitoring(mut self, config: FdCanConfig) { | ||
| 445 | self.set_bus_monitoring_mode(true); | ||
| 446 | self.leave_init_mode(config); | ||
| 447 | } | ||
| 448 | |||
| 449 | /// Moves out of ConfigMode and into Testmode | ||
| 450 | #[inline] | ||
| 451 | pub fn into_test_mode(mut self, config: FdCanConfig) { | ||
| 452 | self.set_test_mode(true); | ||
| 453 | self.leave_init_mode(config); | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Moves out of ConfigMode and into PoweredDownmode | ||
| 457 | #[inline] | ||
| 458 | pub fn into_powered_down(mut self, config: FdCanConfig) { | ||
| 459 | self.set_power_down_mode(true); | ||
| 460 | self.leave_init_mode(config); | ||
| 461 | } | ||
| 462 | |||
| 463 | /// Configures the bit timings. | 411 | /// Configures the bit timings. |
| 464 | /// | 412 | /// |
| 465 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | 413 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter |
| @@ -557,6 +505,7 @@ impl Registers { | |||
| 557 | 505 | ||
| 558 | /// Configures and resets the timestamp counter | 506 | /// Configures and resets the timestamp counter |
| 559 | #[inline] | 507 | #[inline] |
| 508 | #[allow(unused)] | ||
| 560 | pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { | 509 | pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { |
| 561 | #[cfg(stm32h7)] | 510 | #[cfg(stm32h7)] |
| 562 | let (tcp, tss) = match select { | 511 | let (tcp, tss) = match select { |
| @@ -634,7 +583,7 @@ impl Registers { | |||
| 634 | 583 | ||
| 635 | use crate::can::fd::message_ram::*; | 584 | use crate::can::fd::message_ram::*; |
| 636 | //use fdcan::message_ram::*; | 585 | //use fdcan::message_ram::*; |
| 637 | let mut offset_words = self.msg_ram_offset as u16; | 586 | let mut offset_words = (self.msg_ram_offset / 4) as u16; |
| 638 | 587 | ||
| 639 | // 11-bit filter | 588 | // 11-bit filter |
| 640 | r.sidfc().modify(|w| w.set_flssa(offset_words)); | 589 | r.sidfc().modify(|w| w.set_flssa(offset_words)); |
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index fe8969a5a..e31821ca2 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -5,24 +5,24 @@ use core::task::Poll; | |||
| 5 | 5 | ||
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 8 | use embassy_sync::channel::Channel; | 8 | use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | 10 | ||
| 10 | use crate::can::fd::peripheral::Registers; | 11 | use crate::can::fd::peripheral::Registers; |
| 11 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::AFType; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 14 | use crate::{interrupt, peripherals, Peripheral}; | 15 | use crate::{interrupt, peripherals, Peripheral}; |
| 15 | 16 | ||
| 16 | pub mod enums; | ||
| 17 | pub(crate) mod fd; | 17 | pub(crate) mod fd; |
| 18 | pub mod frame; | ||
| 19 | mod util; | ||
| 20 | 18 | ||
| 21 | use enums::*; | 19 | use self::fd::config::*; |
| 22 | use fd::config::*; | 20 | use self::fd::filter::*; |
| 23 | use fd::filter::*; | 21 | pub use self::fd::{config, filter}; |
| 24 | pub use fd::{config, filter}; | 22 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; |
| 25 | use frame::*; | 23 | use super::enums::*; |
| 24 | use super::frame::*; | ||
| 25 | use super::util; | ||
| 26 | 26 | ||
| 27 | /// Timestamp for incoming packets. Use Embassy time when enabled. | 27 | /// Timestamp for incoming packets. Use Embassy time when enabled. |
| 28 | #[cfg(feature = "time")] | 28 | #[cfg(feature = "time")] |
| @@ -53,8 +53,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | match &T::state().tx_mode { | 55 | match &T::state().tx_mode { |
| 56 | sealed::TxMode::NonBuffered(waker) => waker.wake(), | 56 | TxMode::NonBuffered(waker) => waker.wake(), |
| 57 | sealed::TxMode::ClassicBuffered(buf) => { | 57 | TxMode::ClassicBuffered(buf) => { |
| 58 | if !T::registers().tx_queue_is_full() { | 58 | if !T::registers().tx_queue_is_full() { |
| 59 | match buf.tx_receiver.try_receive() { | 59 | match buf.tx_receiver.try_receive() { |
| 60 | Ok(frame) => { | 60 | Ok(frame) => { |
| @@ -64,7 +64,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | sealed::TxMode::FdBuffered(buf) => { | 67 | TxMode::FdBuffered(buf) => { |
| 68 | if !T::registers().tx_queue_is_full() { | 68 | if !T::registers().tx_queue_is_full() { |
| 69 | match buf.tx_receiver.try_receive() { | 69 | match buf.tx_receiver.try_receive() { |
| 70 | Ok(frame) => { | 70 | Ok(frame) => { |
| @@ -106,7 +106,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup | |||
| 106 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 106 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 107 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 107 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 108 | /// Different operating modes | 108 | /// Different operating modes |
| 109 | pub enum FdcanOperatingMode { | 109 | pub enum OperatingMode { |
| 110 | //PoweredDownMode, | 110 | //PoweredDownMode, |
| 111 | //ConfigMode, | 111 | //ConfigMode, |
| 112 | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without | 112 | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without |
| @@ -144,7 +144,7 @@ pub enum FdcanOperatingMode { | |||
| 144 | 144 | ||
| 145 | /// FDCAN Configuration instance instance | 145 | /// FDCAN Configuration instance instance |
| 146 | /// Create instance of this first | 146 | /// Create instance of this first |
| 147 | pub struct FdcanConfigurator<'d, T: Instance> { | 147 | pub struct CanConfigurator<'d, T: Instance> { |
| 148 | config: crate::can::fd::config::FdCanConfig, | 148 | config: crate::can::fd::config::FdCanConfig, |
| 149 | /// Reference to internals. | 149 | /// Reference to internals. |
| 150 | instance: FdcanInstance<'d, T>, | 150 | instance: FdcanInstance<'d, T>, |
| @@ -165,7 +165,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm | |||
| 165 | } | 165 | } |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | impl<'d, T: Instance> FdcanConfigurator<'d, T> { | 168 | impl<'d, T: Instance> CanConfigurator<'d, T> { |
| 169 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. | 169 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. |
| 170 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. | 170 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. |
| 171 | pub fn new( | 171 | pub fn new( |
| @@ -175,7 +175,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 175 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> | 175 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> |
| 176 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> | 176 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> |
| 177 | + 'd, | 177 | + 'd, |
| 178 | ) -> FdcanConfigurator<'d, T> { | 178 | ) -> CanConfigurator<'d, T> { |
| 179 | into_ref!(peri, rx, tx); | 179 | into_ref!(peri, rx, tx); |
| 180 | 180 | ||
| 181 | rx.set_as_af(rx.af_num(), AFType::Input); | 181 | rx.set_as_af(rx.af_num(), AFType::Input); |
| @@ -269,13 +269,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | /// Start in mode. | 271 | /// Start in mode. |
| 272 | pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> { | 272 | pub fn start(self, mode: OperatingMode) -> Can<'d, T> { |
| 273 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); | 273 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); |
| 274 | critical_section::with(|_| unsafe { | 274 | critical_section::with(|_| unsafe { |
| 275 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; | 275 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; |
| 276 | }); | 276 | }); |
| 277 | T::registers().into_mode(self.config, mode); | 277 | T::registers().into_mode(self.config, mode); |
| 278 | let ret = Fdcan { | 278 | let ret = Can { |
| 279 | config: self.config, | 279 | config: self.config, |
| 280 | instance: self.instance, | 280 | instance: self.instance, |
| 281 | _mode: mode, | 281 | _mode: mode, |
| @@ -284,30 +284,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | /// Start, entering mode. Does same as start(mode) | 286 | /// Start, entering mode. Does same as start(mode) |
| 287 | pub fn into_normal_mode(self) -> Fdcan<'d, T> { | 287 | pub fn into_normal_mode(self) -> Can<'d, T> { |
| 288 | self.start(FdcanOperatingMode::NormalOperationMode) | 288 | self.start(OperatingMode::NormalOperationMode) |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | /// Start, entering mode. Does same as start(mode) | 291 | /// Start, entering mode. Does same as start(mode) |
| 292 | pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> { | 292 | pub fn into_internal_loopback_mode(self) -> Can<'d, T> { |
| 293 | self.start(FdcanOperatingMode::InternalLoopbackMode) | 293 | self.start(OperatingMode::InternalLoopbackMode) |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | /// Start, entering mode. Does same as start(mode) | 296 | /// Start, entering mode. Does same as start(mode) |
| 297 | pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> { | 297 | pub fn into_external_loopback_mode(self) -> Can<'d, T> { |
| 298 | self.start(FdcanOperatingMode::ExternalLoopbackMode) | 298 | self.start(OperatingMode::ExternalLoopbackMode) |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | /// FDCAN Instance | 302 | /// FDCAN Instance |
| 303 | pub struct Fdcan<'d, T: Instance> { | 303 | pub struct Can<'d, T: Instance> { |
| 304 | config: crate::can::fd::config::FdCanConfig, | 304 | config: crate::can::fd::config::FdCanConfig, |
| 305 | /// Reference to internals. | 305 | /// Reference to internals. |
| 306 | instance: FdcanInstance<'d, T>, | 306 | instance: FdcanInstance<'d, T>, |
| 307 | _mode: FdcanOperatingMode, | 307 | _mode: OperatingMode, |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | impl<'d, T: Instance> Fdcan<'d, T> { | 310 | impl<'d, T: Instance> Can<'d, T> { |
| 311 | /// Flush one of the TX mailboxes. | 311 | /// Flush one of the TX mailboxes. |
| 312 | pub async fn flush(&self, idx: usize) { | 312 | pub async fn flush(&self, idx: usize) { |
| 313 | poll_fn(|cx| { | 313 | poll_fn(|cx| { |
| @@ -330,12 +330,12 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 330 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 330 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 331 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 331 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 332 | /// transmitted, then tries again. | 332 | /// transmitted, then tries again. |
| 333 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 333 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 334 | T::state().tx_mode.write::<T>(frame).await | 334 | T::state().tx_mode.write::<T>(frame).await |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | /// Returns the next received message frame | 337 | /// Returns the next received message frame |
| 338 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 338 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 339 | T::state().rx_mode.read_classic::<T>().await | 339 | T::state().rx_mode.read_classic::<T>().await |
| 340 | } | 340 | } |
| 341 | 341 | ||
| @@ -348,19 +348,19 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | /// Returns the next received message frame | 350 | /// Returns the next received message frame |
| 351 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 351 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { |
| 352 | T::state().rx_mode.read_fd::<T>().await | 352 | T::state().rx_mode.read_fd::<T>().await |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | /// Split instance into separate Tx(write) and Rx(read) portions | 355 | /// Split instance into separate Tx(write) and Rx(read) portions |
| 356 | pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) { | 356 | pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) { |
| 357 | ( | 357 | ( |
| 358 | FdcanTx { | 358 | CanTx { |
| 359 | config: self.config, | 359 | config: self.config, |
| 360 | _instance: self.instance, | 360 | _instance: self.instance, |
| 361 | _mode: self._mode, | 361 | _mode: self._mode, |
| 362 | }, | 362 | }, |
| 363 | FdcanRx { | 363 | CanRx { |
| 364 | _instance1: PhantomData::<T>, | 364 | _instance1: PhantomData::<T>, |
| 365 | _instance2: T::regs(), | 365 | _instance2: T::regs(), |
| 366 | _mode: self._mode, | 366 | _mode: self._mode, |
| @@ -369,8 +369,8 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | /// Join split rx and tx portions back together | 371 | /// Join split rx and tx portions back together |
| 372 | pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self { | 372 | pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self { |
| 373 | Fdcan { | 373 | Can { |
| 374 | config: tx.config, | 374 | config: tx.config, |
| 375 | //_instance2: T::regs(), | 375 | //_instance2: T::regs(), |
| 376 | instance: tx._instance, | 376 | instance: tx._instance, |
| @@ -398,59 +398,27 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | /// User supplied buffer for RX Buffering | 400 | /// User supplied buffer for RX Buffering |
| 401 | pub type RxBuf<const BUF_SIZE: usize> = | 401 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; |
| 402 | Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>; | ||
| 403 | 402 | ||
| 404 | /// User supplied buffer for TX buffering | 403 | /// User supplied buffer for TX buffering |
| 405 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>; | 404 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; |
| 406 | 405 | ||
| 407 | /// Buffered FDCAN Instance | 406 | /// Buffered FDCAN Instance |
| 408 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 407 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 409 | _instance1: PhantomData<T>, | 408 | _instance1: PhantomData<T>, |
| 410 | _instance2: &'d crate::pac::can::Fdcan, | 409 | _instance2: &'d crate::pac::can::Fdcan, |
| 411 | _mode: FdcanOperatingMode, | 410 | _mode: OperatingMode, |
| 412 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 411 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 413 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 412 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 414 | } | 413 | } |
| 415 | 414 | ||
| 416 | /// Sender that can be used for sending CAN frames. | ||
| 417 | #[derive(Copy, Clone)] | ||
| 418 | pub struct BufferedCanSender { | ||
| 419 | tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, | ||
| 420 | waker: fn(), | ||
| 421 | } | ||
| 422 | |||
| 423 | impl BufferedCanSender { | ||
| 424 | /// Async write frame to TX buffer. | ||
| 425 | pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> { | ||
| 426 | self.tx_buf.try_send(frame)?; | ||
| 427 | (self.waker)(); | ||
| 428 | Ok(()) | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Async write frame to TX buffer. | ||
| 432 | pub async fn write(&mut self, frame: ClassicFrame) { | ||
| 433 | self.tx_buf.send(frame).await; | ||
| 434 | (self.waker)(); | ||
| 435 | } | ||
| 436 | |||
| 437 | /// Allows a poll_fn to poll until the channel is ready to write | ||
| 438 | pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { | ||
| 439 | self.tx_buf.poll_ready_to_send(cx) | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 444 | pub type BufferedCanReceiver = | ||
| 445 | embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; | ||
| 446 | |||
| 447 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 415 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 448 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 416 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 449 | { | 417 | { |
| 450 | fn new( | 418 | fn new( |
| 451 | _instance1: PhantomData<T>, | 419 | _instance1: PhantomData<T>, |
| 452 | _instance2: &'d crate::pac::can::Fdcan, | 420 | _instance2: &'d crate::pac::can::Fdcan, |
| 453 | _mode: FdcanOperatingMode, | 421 | _mode: OperatingMode, |
| 454 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 422 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 455 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 423 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 456 | ) -> Self { | 424 | ) -> Self { |
| @@ -467,26 +435,26 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 467 | fn setup(self) -> Self { | 435 | fn setup(self) -> Self { |
| 468 | // We don't want interrupts being processed while we change modes. | 436 | // We don't want interrupts being processed while we change modes. |
| 469 | critical_section::with(|_| unsafe { | 437 | critical_section::with(|_| unsafe { |
| 470 | let rx_inner = sealed::ClassicBufferedRxInner { | 438 | let rx_inner = super::common::ClassicBufferedRxInner { |
| 471 | rx_sender: self.rx_buf.sender().into(), | 439 | rx_sender: self.rx_buf.sender().into(), |
| 472 | }; | 440 | }; |
| 473 | let tx_inner = sealed::ClassicBufferedTxInner { | 441 | let tx_inner = super::common::ClassicBufferedTxInner { |
| 474 | tx_receiver: self.tx_buf.receiver().into(), | 442 | tx_receiver: self.tx_buf.receiver().into(), |
| 475 | }; | 443 | }; |
| 476 | T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner); | 444 | T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); |
| 477 | T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner); | 445 | T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner); |
| 478 | }); | 446 | }); |
| 479 | self | 447 | self |
| 480 | } | 448 | } |
| 481 | 449 | ||
| 482 | /// Async write frame to TX buffer. | 450 | /// Async write frame to TX buffer. |
| 483 | pub async fn write(&mut self, frame: ClassicFrame) { | 451 | pub async fn write(&mut self, frame: Frame) { |
| 484 | self.tx_buf.send(frame).await; | 452 | self.tx_buf.send(frame).await; |
| 485 | T::IT0Interrupt::pend(); // Wake for Tx | 453 | T::IT0Interrupt::pend(); // Wake for Tx |
| 486 | } | 454 | } |
| 487 | 455 | ||
| 488 | /// Async read frame from RX buffer. | 456 | /// Async read frame from RX buffer. |
| 489 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 457 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 490 | self.rx_buf.receive().await | 458 | self.rx_buf.receive().await |
| 491 | } | 459 | } |
| 492 | 460 | ||
| @@ -509,15 +477,14 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr | |||
| 509 | { | 477 | { |
| 510 | fn drop(&mut self) { | 478 | fn drop(&mut self) { |
| 511 | critical_section::with(|_| unsafe { | 479 | critical_section::with(|_| unsafe { |
| 512 | T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | 480 | T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); |
| 513 | T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | 481 | T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); |
| 514 | }); | 482 | }); |
| 515 | } | 483 | } |
| 516 | } | 484 | } |
| 517 | 485 | ||
| 518 | /// User supplied buffer for RX Buffering | 486 | /// User supplied buffer for RX Buffering |
| 519 | pub type RxFdBuf<const BUF_SIZE: usize> = | 487 | pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>; |
| 520 | Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>; | ||
| 521 | 488 | ||
| 522 | /// User supplied buffer for TX buffering | 489 | /// User supplied buffer for TX buffering |
| 523 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; | 490 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; |
| @@ -526,7 +493,7 @@ pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFra | |||
| 526 | pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 493 | pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 527 | _instance1: PhantomData<T>, | 494 | _instance1: PhantomData<T>, |
| 528 | _instance2: &'d crate::pac::can::Fdcan, | 495 | _instance2: &'d crate::pac::can::Fdcan, |
| 529 | _mode: FdcanOperatingMode, | 496 | _mode: OperatingMode, |
| 530 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 497 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 531 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 498 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 532 | } | 499 | } |
| @@ -534,7 +501,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF | |||
| 534 | /// Sender that can be used for sending CAN frames. | 501 | /// Sender that can be used for sending CAN frames. |
| 535 | #[derive(Copy, Clone)] | 502 | #[derive(Copy, Clone)] |
| 536 | pub struct BufferedFdCanSender { | 503 | pub struct BufferedFdCanSender { |
| 537 | tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, | 504 | tx_buf: DynamicSender<'static, FdFrame>, |
| 538 | waker: fn(), | 505 | waker: fn(), |
| 539 | } | 506 | } |
| 540 | 507 | ||
| @@ -559,8 +526,7 @@ impl BufferedFdCanSender { | |||
| 559 | } | 526 | } |
| 560 | 527 | ||
| 561 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 528 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 562 | pub type BufferedFdCanReceiver = | 529 | pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; |
| 563 | embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; | ||
| 564 | 530 | ||
| 565 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 531 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 566 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 532 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| @@ -568,7 +534,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 568 | fn new( | 534 | fn new( |
| 569 | _instance1: PhantomData<T>, | 535 | _instance1: PhantomData<T>, |
| 570 | _instance2: &'d crate::pac::can::Fdcan, | 536 | _instance2: &'d crate::pac::can::Fdcan, |
| 571 | _mode: FdcanOperatingMode, | 537 | _mode: OperatingMode, |
| 572 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 538 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 573 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 539 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 574 | ) -> Self { | 540 | ) -> Self { |
| @@ -585,14 +551,14 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 585 | fn setup(self) -> Self { | 551 | fn setup(self) -> Self { |
| 586 | // We don't want interrupts being processed while we change modes. | 552 | // We don't want interrupts being processed while we change modes. |
| 587 | critical_section::with(|_| unsafe { | 553 | critical_section::with(|_| unsafe { |
| 588 | let rx_inner = sealed::FdBufferedRxInner { | 554 | let rx_inner = super::common::FdBufferedRxInner { |
| 589 | rx_sender: self.rx_buf.sender().into(), | 555 | rx_sender: self.rx_buf.sender().into(), |
| 590 | }; | 556 | }; |
| 591 | let tx_inner = sealed::FdBufferedTxInner { | 557 | let tx_inner = super::common::FdBufferedTxInner { |
| 592 | tx_receiver: self.tx_buf.receiver().into(), | 558 | tx_receiver: self.tx_buf.receiver().into(), |
| 593 | }; | 559 | }; |
| 594 | T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner); | 560 | T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); |
| 595 | T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner); | 561 | T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner); |
| 596 | }); | 562 | }); |
| 597 | self | 563 | self |
| 598 | } | 564 | } |
| @@ -604,7 +570,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 604 | } | 570 | } |
| 605 | 571 | ||
| 606 | /// Async read frame from RX buffer. | 572 | /// Async read frame from RX buffer. |
| 607 | pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 573 | pub async fn read(&mut self) -> Result<FdEnvelope, BusError> { |
| 608 | self.rx_buf.receive().await | 574 | self.rx_buf.receive().await |
| 609 | } | 575 | } |
| 610 | 576 | ||
| @@ -627,32 +593,32 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr | |||
| 627 | { | 593 | { |
| 628 | fn drop(&mut self) { | 594 | fn drop(&mut self) { |
| 629 | critical_section::with(|_| unsafe { | 595 | critical_section::with(|_| unsafe { |
| 630 | T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | 596 | T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); |
| 631 | T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | 597 | T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); |
| 632 | }); | 598 | }); |
| 633 | } | 599 | } |
| 634 | } | 600 | } |
| 635 | 601 | ||
| 636 | /// FDCAN Rx only Instance | 602 | /// FDCAN Rx only Instance |
| 637 | pub struct FdcanRx<'d, T: Instance> { | 603 | pub struct CanRx<'d, T: Instance> { |
| 638 | _instance1: PhantomData<T>, | 604 | _instance1: PhantomData<T>, |
| 639 | _instance2: &'d crate::pac::can::Fdcan, | 605 | _instance2: &'d crate::pac::can::Fdcan, |
| 640 | _mode: FdcanOperatingMode, | 606 | _mode: OperatingMode, |
| 641 | } | 607 | } |
| 642 | 608 | ||
| 643 | /// FDCAN Tx only Instance | 609 | /// FDCAN Tx only Instance |
| 644 | pub struct FdcanTx<'d, T: Instance> { | 610 | pub struct CanTx<'d, T: Instance> { |
| 645 | config: crate::can::fd::config::FdCanConfig, | 611 | config: crate::can::fd::config::FdCanConfig, |
| 646 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); | 612 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); |
| 647 | _mode: FdcanOperatingMode, | 613 | _mode: OperatingMode, |
| 648 | } | 614 | } |
| 649 | 615 | ||
| 650 | impl<'c, 'd, T: Instance> FdcanTx<'d, T> { | 616 | impl<'c, 'd, T: Instance> CanTx<'d, T> { |
| 651 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 617 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| 652 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 618 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 653 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 619 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 654 | /// transmitted, then tries again. | 620 | /// transmitted, then tries again. |
| 655 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 621 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 656 | T::state().tx_mode.write::<T>(frame).await | 622 | T::state().tx_mode.write::<T>(frame).await |
| 657 | } | 623 | } |
| 658 | 624 | ||
| @@ -665,204 +631,216 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> { | |||
| 665 | } | 631 | } |
| 666 | } | 632 | } |
| 667 | 633 | ||
| 668 | impl<'c, 'd, T: Instance> FdcanRx<'d, T> { | 634 | impl<'c, 'd, T: Instance> CanRx<'d, T> { |
| 669 | /// Returns the next received message frame | 635 | /// Returns the next received message frame |
| 670 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 636 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 671 | T::state().rx_mode.read_classic::<T>().await | 637 | T::state().rx_mode.read_classic::<T>().await |
| 672 | } | 638 | } |
| 673 | 639 | ||
| 674 | /// Returns the next received message frame | 640 | /// Returns the next received message frame |
| 675 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 641 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { |
| 676 | T::state().rx_mode.read_fd::<T>().await | 642 | T::state().rx_mode.read_fd::<T>().await |
| 677 | } | 643 | } |
| 678 | } | 644 | } |
| 679 | 645 | ||
| 680 | pub(crate) mod sealed { | 646 | enum RxMode { |
| 681 | use core::future::poll_fn; | 647 | NonBuffered(AtomicWaker), |
| 682 | use core::task::Poll; | 648 | ClassicBuffered(super::common::ClassicBufferedRxInner), |
| 683 | 649 | FdBuffered(super::common::FdBufferedRxInner), | |
| 684 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | 650 | } |
| 685 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 686 | |||
| 687 | use super::CanHeader; | ||
| 688 | use crate::can::_version::{BusError, Timestamp}; | ||
| 689 | use crate::can::frame::{ClassicFrame, FdFrame}; | ||
| 690 | |||
| 691 | pub struct ClassicBufferedRxInner { | ||
| 692 | pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, | ||
| 693 | } | ||
| 694 | pub struct ClassicBufferedTxInner { | ||
| 695 | pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, | ||
| 696 | } | ||
| 697 | |||
| 698 | pub struct FdBufferedRxInner { | ||
| 699 | pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, | ||
| 700 | } | ||
| 701 | pub struct FdBufferedTxInner { | ||
| 702 | pub tx_receiver: DynamicReceiver<'static, FdFrame>, | ||
| 703 | } | ||
| 704 | |||
| 705 | pub enum RxMode { | ||
| 706 | NonBuffered(AtomicWaker), | ||
| 707 | ClassicBuffered(ClassicBufferedRxInner), | ||
| 708 | FdBuffered(FdBufferedRxInner), | ||
| 709 | } | ||
| 710 | 651 | ||
| 711 | impl RxMode { | 652 | impl RxMode { |
| 712 | pub fn register(&self, arg: &core::task::Waker) { | 653 | fn register(&self, arg: &core::task::Waker) { |
| 713 | match self { | 654 | match self { |
| 714 | RxMode::NonBuffered(waker) => waker.register(arg), | 655 | RxMode::NonBuffered(waker) => waker.register(arg), |
| 715 | _ => { | 656 | _ => { |
| 716 | panic!("Bad Mode") | 657 | panic!("Bad Mode") |
| 717 | } | ||
| 718 | } | 658 | } |
| 719 | } | 659 | } |
| 660 | } | ||
| 720 | 661 | ||
| 721 | pub fn on_interrupt<T: Instance>(&self, fifonr: usize) { | 662 | fn on_interrupt<T: Instance>(&self, fifonr: usize) { |
| 722 | T::regs().ir().write(|w| w.set_rfn(fifonr, true)); | 663 | T::regs().ir().write(|w| w.set_rfn(fifonr, true)); |
| 723 | match self { | 664 | match self { |
| 724 | RxMode::NonBuffered(waker) => { | 665 | RxMode::NonBuffered(waker) => { |
| 725 | waker.wake(); | 666 | waker.wake(); |
| 726 | } | 667 | } |
| 727 | RxMode::ClassicBuffered(buf) => { | 668 | RxMode::ClassicBuffered(buf) => { |
| 728 | if let Some(result) = self.read::<T, _>() { | 669 | if let Some(result) = self.try_read::<T>() { |
| 729 | let _ = buf.rx_sender.try_send(result); | 670 | let _ = buf.rx_sender.try_send(result); |
| 730 | } | ||
| 731 | } | 671 | } |
| 732 | RxMode::FdBuffered(buf) => { | 672 | } |
| 733 | if let Some(result) = self.read::<T, _>() { | 673 | RxMode::FdBuffered(buf) => { |
| 734 | let _ = buf.rx_sender.try_send(result); | 674 | if let Some(result) = self.try_read_fd::<T>() { |
| 735 | } | 675 | let _ = buf.rx_sender.try_send(result); |
| 736 | } | 676 | } |
| 737 | } | 677 | } |
| 738 | } | 678 | } |
| 679 | } | ||
| 739 | 680 | ||
| 740 | fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> { | 681 | //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { |
| 741 | if let Some((msg, ts)) = T::registers().read(0) { | 682 | fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> { |
| 742 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | 683 | if let Some((frame, ts)) = T::registers().read(0) { |
| 743 | Some(Ok((msg, ts))) | 684 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); |
| 744 | } else if let Some((msg, ts)) = T::registers().read(1) { | 685 | Some(Ok(Envelope { ts, frame })) |
| 745 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | 686 | } else if let Some((frame, ts)) = T::registers().read(1) { |
| 746 | Some(Ok((msg, ts))) | 687 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); |
| 747 | } else if let Some(err) = T::registers().curr_error() { | 688 | Some(Ok(Envelope { ts, frame })) |
| 748 | // TODO: this is probably wrong | 689 | } else if let Some(err) = T::registers().curr_error() { |
| 749 | Some(Err(err)) | 690 | // TODO: this is probably wrong |
| 750 | } else { | 691 | Some(Err(err)) |
| 751 | None | 692 | } else { |
| 752 | } | 693 | None |
| 753 | } | 694 | } |
| 695 | } | ||
| 754 | 696 | ||
| 755 | async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> { | 697 | //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { |
| 756 | poll_fn(|cx| { | 698 | fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> { |
| 757 | T::state().err_waker.register(cx.waker()); | 699 | if let Some((frame, ts)) = T::registers().read(0) { |
| 758 | self.register(cx.waker()); | 700 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); |
| 759 | match self.read::<T, _>() { | 701 | Some(Ok(FdEnvelope { ts, frame })) |
| 760 | Some(result) => Poll::Ready(result), | 702 | } else if let Some((frame, ts)) = T::registers().read(1) { |
| 761 | None => Poll::Pending, | 703 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); |
| 762 | } | 704 | Some(Ok(FdEnvelope { ts, frame })) |
| 763 | }) | 705 | } else if let Some(err) = T::registers().curr_error() { |
| 764 | .await | 706 | // TODO: this is probably wrong |
| 707 | Some(Err(err)) | ||
| 708 | } else { | ||
| 709 | None | ||
| 765 | } | 710 | } |
| 711 | } | ||
| 766 | 712 | ||
| 767 | pub async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> { | 713 | fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> { |
| 768 | self.read_async::<T, _>().await | 714 | if let Some((msg, ts)) = T::registers().read(0) { |
| 715 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 716 | Some(Ok((msg, ts))) | ||
| 717 | } else if let Some((msg, ts)) = T::registers().read(1) { | ||
| 718 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 719 | Some(Ok((msg, ts))) | ||
| 720 | } else if let Some(err) = T::registers().curr_error() { | ||
| 721 | // TODO: this is probably wrong | ||
| 722 | Some(Err(err)) | ||
| 723 | } else { | ||
| 724 | None | ||
| 769 | } | 725 | } |
| 726 | } | ||
| 727 | |||
| 728 | async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> { | ||
| 729 | poll_fn(|cx| { | ||
| 730 | T::state().err_waker.register(cx.waker()); | ||
| 731 | self.register(cx.waker()); | ||
| 732 | match self.read::<T, _>() { | ||
| 733 | Some(result) => Poll::Ready(result), | ||
| 734 | None => Poll::Pending, | ||
| 735 | } | ||
| 736 | }) | ||
| 737 | .await | ||
| 738 | } | ||
| 770 | 739 | ||
| 771 | pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> { | 740 | async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { |
| 772 | self.read_async::<T, _>().await | 741 | match self.read_async::<T, _>().await { |
| 742 | Ok((frame, ts)) => Ok(Envelope { ts, frame }), | ||
| 743 | Err(e) => Err(e), | ||
| 773 | } | 744 | } |
| 774 | } | 745 | } |
| 775 | 746 | ||
| 776 | pub enum TxMode { | 747 | async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> { |
| 777 | NonBuffered(AtomicWaker), | 748 | match self.read_async::<T, _>().await { |
| 778 | ClassicBuffered(ClassicBufferedTxInner), | 749 | Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), |
| 779 | FdBuffered(FdBufferedTxInner), | 750 | Err(e) => Err(e), |
| 751 | } | ||
| 780 | } | 752 | } |
| 753 | } | ||
| 781 | 754 | ||
| 782 | impl TxMode { | 755 | enum TxMode { |
| 783 | pub fn register(&self, arg: &core::task::Waker) { | 756 | NonBuffered(AtomicWaker), |
| 784 | match self { | 757 | ClassicBuffered(super::common::ClassicBufferedTxInner), |
| 785 | TxMode::NonBuffered(waker) => { | 758 | FdBuffered(super::common::FdBufferedTxInner), |
| 786 | waker.register(arg); | 759 | } |
| 787 | } | 760 | |
| 788 | _ => { | 761 | impl TxMode { |
| 789 | panic!("Bad mode"); | 762 | fn register(&self, arg: &core::task::Waker) { |
| 790 | } | 763 | match self { |
| 764 | TxMode::NonBuffered(waker) => { | ||
| 765 | waker.register(arg); | ||
| 766 | } | ||
| 767 | _ => { | ||
| 768 | panic!("Bad mode"); | ||
| 791 | } | 769 | } |
| 792 | } | 770 | } |
| 771 | } | ||
| 793 | 772 | ||
| 794 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 773 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| 795 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 774 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 796 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 775 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 797 | /// transmitted, then tries again. | 776 | /// transmitted, then tries again. |
| 798 | async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> { | 777 | async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> { |
| 799 | poll_fn(|cx| { | 778 | poll_fn(|cx| { |
| 800 | self.register(cx.waker()); | 779 | self.register(cx.waker()); |
| 801 | 780 | ||
| 802 | if let Ok(dropped) = T::registers().write(frame) { | 781 | if let Ok(dropped) = T::registers().write(frame) { |
| 803 | return Poll::Ready(dropped); | 782 | return Poll::Ready(dropped); |
| 804 | } | 783 | } |
| 805 | 784 | ||
| 806 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | 785 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes |
| 807 | // to clear. | 786 | // to clear. |
| 808 | Poll::Pending | 787 | Poll::Pending |
| 809 | }) | 788 | }) |
| 810 | .await | 789 | .await |
| 811 | } | 790 | } |
| 812 | 791 | ||
| 813 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 792 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| 814 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 793 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 815 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 794 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 816 | /// transmitted, then tries again. | 795 | /// transmitted, then tries again. |
| 817 | pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 796 | async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> { |
| 818 | self.write_generic::<T, _>(frame).await | 797 | self.write_generic::<T, _>(frame).await |
| 819 | } | 798 | } |
| 820 | 799 | ||
| 821 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 800 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| 822 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 801 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 823 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 802 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 824 | /// transmitted, then tries again. | 803 | /// transmitted, then tries again. |
| 825 | pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { | 804 | async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { |
| 826 | self.write_generic::<T, _>(frame).await | 805 | self.write_generic::<T, _>(frame).await |
| 827 | } | ||
| 828 | } | 806 | } |
| 807 | } | ||
| 829 | 808 | ||
| 830 | pub struct State { | 809 | struct State { |
| 831 | pub rx_mode: RxMode, | 810 | pub rx_mode: RxMode, |
| 832 | pub tx_mode: TxMode, | 811 | pub tx_mode: TxMode, |
| 833 | pub ns_per_timer_tick: u64, | 812 | pub ns_per_timer_tick: u64, |
| 834 | 813 | ||
| 835 | pub err_waker: AtomicWaker, | 814 | pub err_waker: AtomicWaker, |
| 836 | } | 815 | } |
| 837 | 816 | ||
| 838 | impl State { | 817 | impl State { |
| 839 | pub const fn new() -> Self { | 818 | const fn new() -> Self { |
| 840 | Self { | 819 | Self { |
| 841 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), | 820 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), |
| 842 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | 821 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), |
| 843 | ns_per_timer_tick: 0, | 822 | ns_per_timer_tick: 0, |
| 844 | err_waker: AtomicWaker::new(), | 823 | err_waker: AtomicWaker::new(), |
| 845 | } | ||
| 846 | } | 824 | } |
| 847 | } | 825 | } |
| 826 | } | ||
| 848 | 827 | ||
| 849 | pub trait Instance { | 828 | trait SealedInstance { |
| 850 | const MSG_RAM_OFFSET: usize; | 829 | const MSG_RAM_OFFSET: usize; |
| 851 | 830 | ||
| 852 | fn regs() -> &'static crate::pac::can::Fdcan; | 831 | fn regs() -> &'static crate::pac::can::Fdcan; |
| 853 | fn registers() -> crate::can::fd::peripheral::Registers; | 832 | fn registers() -> crate::can::fd::peripheral::Registers; |
| 854 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram; | 833 | fn state() -> &'static State; |
| 855 | fn state() -> &'static State; | 834 | unsafe fn mut_state() -> &'static mut State; |
| 856 | unsafe fn mut_state() -> &'static mut State; | 835 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; |
| 857 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; | ||
| 858 | } | ||
| 859 | } | 836 | } |
| 860 | 837 | ||
| 861 | /// Instance trait | 838 | /// Instance trait |
| 862 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 839 | #[allow(private_bounds)] |
| 840 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 863 | /// Interrupt 0 | 841 | /// Interrupt 0 |
| 864 | type IT0Interrupt: crate::interrupt::typelevel::Interrupt; | 842 | type IT0Interrupt: crate::interrupt::typelevel::Interrupt; |
| 865 | /// Interrupt 0 | 843 | /// Interrupt 1 |
| 866 | type IT1Interrupt: crate::interrupt::typelevel::Interrupt; | 844 | type IT1Interrupt: crate::interrupt::typelevel::Interrupt; |
| 867 | } | 845 | } |
| 868 | 846 | ||
| @@ -871,7 +849,7 @@ pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | |||
| 871 | 849 | ||
| 872 | macro_rules! impl_fdcan { | 850 | macro_rules! impl_fdcan { |
| 873 | ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { | 851 | ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { |
| 874 | impl sealed::Instance for peripherals::$inst { | 852 | impl SealedInstance for peripherals::$inst { |
| 875 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; | 853 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; |
| 876 | 854 | ||
| 877 | fn regs() -> &'static crate::pac::can::Fdcan { | 855 | fn regs() -> &'static crate::pac::can::Fdcan { |
| @@ -880,14 +858,11 @@ macro_rules! impl_fdcan { | |||
| 880 | fn registers() -> Registers { | 858 | fn registers() -> Registers { |
| 881 | Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} | 859 | Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} |
| 882 | } | 860 | } |
| 883 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram { | 861 | unsafe fn mut_state() -> &'static mut State { |
| 884 | &crate::pac::$msg_ram_inst | 862 | static mut STATE: State = State::new(); |
| 885 | } | 863 | &mut *core::ptr::addr_of_mut!(STATE) |
| 886 | unsafe fn mut_state() -> & 'static mut sealed::State { | ||
| 887 | static mut STATE: sealed::State = sealed::State::new(); | ||
| 888 | & mut STATE | ||
| 889 | } | 864 | } |
| 890 | fn state() -> &'static sealed::State { | 865 | fn state() -> &'static State { |
| 891 | unsafe { peripherals::$inst::mut_state() } | 866 | unsafe { peripherals::$inst::mut_state() } |
| 892 | } | 867 | } |
| 893 | 868 | ||
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 9c293035d..d2d1f7aa6 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs | |||
| @@ -1,6 +1,16 @@ | |||
| 1 | //! Definition for CAN Frames | 1 | //! Definition for CAN Frames |
| 2 | use bit_field::BitField; | 2 | use bit_field::BitField; |
| 3 | 3 | ||
| 4 | use crate::can::enums::FrameCreateError; | ||
| 5 | |||
| 6 | /// Calculate proper timestamp when available. | ||
| 7 | #[cfg(feature = "time")] | ||
| 8 | pub type Timestamp = embassy_time::Instant; | ||
| 9 | |||
| 10 | /// Raw register timestamp | ||
| 11 | #[cfg(not(feature = "time"))] | ||
| 12 | pub type Timestamp = u16; | ||
| 13 | |||
| 4 | /// CAN Header, without meta data | 14 | /// CAN Header, without meta data |
| 5 | #[derive(Debug, Copy, Clone)] | 15 | #[derive(Debug, Copy, Clone)] |
| 6 | pub struct Header { | 16 | pub struct Header { |
| @@ -9,6 +19,20 @@ pub struct Header { | |||
| 9 | flags: u8, | 19 | flags: u8, |
| 10 | } | 20 | } |
| 11 | 21 | ||
| 22 | #[cfg(feature = "defmt")] | ||
| 23 | impl defmt::Format for Header { | ||
| 24 | fn format(&self, fmt: defmt::Formatter<'_>) { | ||
| 25 | match self.id() { | ||
| 26 | embedded_can::Id::Standard(id) => { | ||
| 27 | defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,) | ||
| 28 | } | ||
| 29 | embedded_can::Id::Extended(id) => { | ||
| 30 | defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,) | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 12 | impl Header { | 36 | impl Header { |
| 13 | const FLAG_RTR: usize = 0; // Remote | 37 | const FLAG_RTR: usize = 0; // Remote |
| 14 | const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN | 38 | const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN |
| @@ -54,13 +78,21 @@ impl Header { | |||
| 54 | pub fn bit_rate_switching(&self) -> bool { | 78 | pub fn bit_rate_switching(&self) -> bool { |
| 55 | self.flags.get_bit(Self::FLAG_BRS) | 79 | self.flags.get_bit(Self::FLAG_BRS) |
| 56 | } | 80 | } |
| 81 | |||
| 82 | /// Get priority of frame | ||
| 83 | pub(crate) fn priority(&self) -> u32 { | ||
| 84 | match self.id() { | ||
| 85 | embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18, | ||
| 86 | embedded_can::Id::Extended(id) => id.as_raw(), | ||
| 87 | } | ||
| 88 | } | ||
| 57 | } | 89 | } |
| 58 | 90 | ||
| 59 | /// Trait for FDCAN frame types, providing ability to construct from a Header | 91 | /// Trait for FDCAN frame types, providing ability to construct from a Header |
| 60 | /// and to retrieve the Header from a frame | 92 | /// and to retrieve the Header from a frame |
| 61 | pub trait CanHeader: Sized { | 93 | pub trait CanHeader: Sized { |
| 62 | /// Construct frame from header and payload | 94 | /// Construct frame from header and payload |
| 63 | fn from_header(header: Header, data: &[u8]) -> Option<Self>; | 95 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>; |
| 64 | 96 | ||
| 65 | /// Get this frame's header struct | 97 | /// Get this frame's header struct |
| 66 | fn header(&self) -> &Header; | 98 | fn header(&self) -> &Header; |
| @@ -70,24 +102,26 @@ pub trait CanHeader: Sized { | |||
| 70 | /// | 102 | /// |
| 71 | /// Contains 0 to 8 Bytes of data. | 103 | /// Contains 0 to 8 Bytes of data. |
| 72 | #[derive(Debug, Copy, Clone)] | 104 | #[derive(Debug, Copy, Clone)] |
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 73 | pub struct ClassicData { | 106 | pub struct ClassicData { |
| 74 | pub(crate) bytes: [u8; 8], | 107 | pub(crate) bytes: [u8; Self::MAX_DATA_LEN], |
| 75 | } | 108 | } |
| 76 | 109 | ||
| 77 | impl ClassicData { | 110 | impl ClassicData { |
| 111 | pub(crate) const MAX_DATA_LEN: usize = 8; | ||
| 78 | /// Creates a data payload from a raw byte slice. | 112 | /// Creates a data payload from a raw byte slice. |
| 79 | /// | 113 | /// |
| 80 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | 114 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or |
| 81 | /// cannot be represented with an FDCAN DLC. | 115 | /// cannot be represented with an FDCAN DLC. |
| 82 | pub fn new(data: &[u8]) -> Option<Self> { | 116 | pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> { |
| 83 | if !FdData::is_valid_len(data.len()) { | 117 | if data.len() > 8 { |
| 84 | return None; | 118 | return Err(FrameCreateError::InvalidDataLength); |
| 85 | } | 119 | } |
| 86 | 120 | ||
| 87 | let mut bytes = [0; 8]; | 121 | let mut bytes = [0; 8]; |
| 88 | bytes[..data.len()].copy_from_slice(data); | 122 | bytes[..data.len()].copy_from_slice(data); |
| 89 | 123 | ||
| 90 | Some(Self { bytes }) | 124 | Ok(Self { bytes }) |
| 91 | } | 125 | } |
| 92 | 126 | ||
| 93 | /// Raw read access to data. | 127 | /// Raw read access to data. |
| @@ -110,60 +144,53 @@ impl ClassicData { | |||
| 110 | } | 144 | } |
| 111 | } | 145 | } |
| 112 | 146 | ||
| 113 | /// Frame with up to 8 bytes of data payload as per Classic CAN | 147 | /// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN |
| 148 | /// For CAN-FD support use FdFrame | ||
| 114 | #[derive(Debug, Copy, Clone)] | 149 | #[derive(Debug, Copy, Clone)] |
| 115 | pub struct ClassicFrame { | 150 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 151 | pub struct Frame { | ||
| 116 | can_header: Header, | 152 | can_header: Header, |
| 117 | data: ClassicData, | 153 | data: ClassicData, |
| 118 | } | 154 | } |
| 119 | 155 | ||
| 120 | impl ClassicFrame { | 156 | impl Frame { |
| 121 | pub(crate) const MAX_DATA_LEN: usize = 8; | ||
| 122 | |||
| 123 | /// Create a new CAN classic Frame | 157 | /// Create a new CAN classic Frame |
| 124 | pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { | 158 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 125 | ClassicFrame { can_header, data } | 159 | let data = ClassicData::new(raw_data)?; |
| 160 | Ok(Frame { can_header, data: data }) | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Creates a new data frame. | ||
| 164 | pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> { | ||
| 165 | let eid: embedded_can::Id = id.into(); | ||
| 166 | let header = Header::new(eid, data.len() as u8, false); | ||
| 167 | Self::new(header, data) | ||
| 126 | } | 168 | } |
| 127 | 169 | ||
| 128 | /// Create new extended frame | 170 | /// Create new extended frame |
| 129 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | 171 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 130 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | 172 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { |
| 131 | match ClassicData::new(raw_data) { | 173 | Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) |
| 132 | Some(data) => Some(ClassicFrame::new( | ||
| 133 | Header::new(id.into(), raw_data.len() as u8, false), | ||
| 134 | data, | ||
| 135 | )), | ||
| 136 | None => None, | ||
| 137 | } | ||
| 138 | } else { | 174 | } else { |
| 139 | None | 175 | Err(FrameCreateError::InvalidCanId) |
| 140 | } | 176 | } |
| 141 | } | 177 | } |
| 142 | 178 | ||
| 143 | /// Create new standard frame | 179 | /// Create new standard frame |
| 144 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | 180 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 145 | if let Some(id) = embedded_can::StandardId::new(raw_id) { | 181 | if let Some(id) = embedded_can::StandardId::new(raw_id) { |
| 146 | match ClassicData::new(raw_data) { | 182 | Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) |
| 147 | Some(data) => Some(ClassicFrame::new( | ||
| 148 | Header::new(id.into(), raw_data.len() as u8, false), | ||
| 149 | data, | ||
| 150 | )), | ||
| 151 | None => None, | ||
| 152 | } | ||
| 153 | } else { | 183 | } else { |
| 154 | None | 184 | Err(FrameCreateError::InvalidCanId) |
| 155 | } | 185 | } |
| 156 | } | 186 | } |
| 157 | 187 | ||
| 158 | /// Create new remote frame | 188 | /// Create new remote frame |
| 159 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | 189 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> { |
| 160 | if len <= 8usize { | 190 | if len <= 8usize { |
| 161 | Some(ClassicFrame::new( | 191 | Self::new(Header::new(id.into(), len as u8, true), &[0; 8]) |
| 162 | Header::new(id.into(), len as u8, true), | ||
| 163 | ClassicData::empty(), | ||
| 164 | )) | ||
| 165 | } else { | 192 | } else { |
| 166 | None | 193 | Err(FrameCreateError::InvalidDataLength) |
| 167 | } | 194 | } |
| 168 | } | 195 | } |
| 169 | 196 | ||
| @@ -181,24 +208,28 @@ impl ClassicFrame { | |||
| 181 | pub fn data(&self) -> &[u8] { | 208 | pub fn data(&self) -> &[u8] { |
| 182 | &self.data.raw() | 209 | &self.data.raw() |
| 183 | } | 210 | } |
| 211 | |||
| 212 | /// Get priority of frame | ||
| 213 | pub fn priority(&self) -> u32 { | ||
| 214 | self.header().priority() | ||
| 215 | } | ||
| 184 | } | 216 | } |
| 185 | 217 | ||
| 186 | impl embedded_can::Frame for ClassicFrame { | 218 | impl embedded_can::Frame for Frame { |
| 187 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | 219 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { |
| 188 | match ClassicData::new(raw_data) { | 220 | let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); |
| 189 | Some(data) => Some(ClassicFrame::new( | 221 | match frameopt { |
| 190 | Header::new(id.into(), raw_data.len() as u8, false), | 222 | Ok(frame) => Some(frame), |
| 191 | data, | 223 | Err(_) => None, |
| 192 | )), | ||
| 193 | None => None, | ||
| 194 | } | 224 | } |
| 195 | } | 225 | } |
| 196 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | 226 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { |
| 197 | if len <= 8 { | 227 | if len <= 8 { |
| 198 | Some(ClassicFrame::new( | 228 | let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]); |
| 199 | Header::new(id.into(), len as u8, true), | 229 | match frameopt { |
| 200 | ClassicData::empty(), | 230 | Ok(frame) => Some(frame), |
| 201 | )) | 231 | Err(_) => None, |
| 232 | } | ||
| 202 | } else { | 233 | } else { |
| 203 | None | 234 | None |
| 204 | } | 235 | } |
| @@ -223,9 +254,9 @@ impl embedded_can::Frame for ClassicFrame { | |||
| 223 | } | 254 | } |
| 224 | } | 255 | } |
| 225 | 256 | ||
| 226 | impl CanHeader for ClassicFrame { | 257 | impl CanHeader for Frame { |
| 227 | fn from_header(header: Header, data: &[u8]) -> Option<Self> { | 258 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { |
| 228 | Some(Self::new(header, ClassicData::new(data)?)) | 259 | Self::new(header, data) |
| 229 | } | 260 | } |
| 230 | 261 | ||
| 231 | fn header(&self) -> &Header { | 262 | fn header(&self) -> &Header { |
| @@ -233,10 +264,31 @@ impl CanHeader for ClassicFrame { | |||
| 233 | } | 264 | } |
| 234 | } | 265 | } |
| 235 | 266 | ||
| 267 | /// Contains CAN frame and additional metadata. | ||
| 268 | /// | ||
| 269 | /// Timestamp is available if `time` feature is enabled. | ||
| 270 | /// For CAN-FD support use FdEnvelope | ||
| 271 | #[derive(Debug, Clone)] | ||
| 272 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 273 | pub struct Envelope { | ||
| 274 | /// Reception time. | ||
| 275 | pub ts: Timestamp, | ||
| 276 | /// The actual CAN frame. | ||
| 277 | pub frame: Frame, | ||
| 278 | } | ||
| 279 | |||
| 280 | impl Envelope { | ||
| 281 | /// Convert into a tuple | ||
| 282 | pub fn parts(self) -> (Frame, Timestamp) { | ||
| 283 | (self.frame, self.ts) | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 236 | /// Payload of a (FD)CAN data frame. | 287 | /// Payload of a (FD)CAN data frame. |
| 237 | /// | 288 | /// |
| 238 | /// Contains 0 to 64 Bytes of data. | 289 | /// Contains 0 to 64 Bytes of data. |
| 239 | #[derive(Debug, Copy, Clone)] | 290 | #[derive(Debug, Copy, Clone)] |
| 291 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 240 | pub struct FdData { | 292 | pub struct FdData { |
| 241 | pub(crate) bytes: [u8; 64], | 293 | pub(crate) bytes: [u8; 64], |
| 242 | } | 294 | } |
| @@ -246,15 +298,15 @@ impl FdData { | |||
| 246 | /// | 298 | /// |
| 247 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | 299 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or |
| 248 | /// cannot be represented with an FDCAN DLC. | 300 | /// cannot be represented with an FDCAN DLC. |
| 249 | pub fn new(data: &[u8]) -> Option<Self> { | 301 | pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> { |
| 250 | if !FdData::is_valid_len(data.len()) { | 302 | if !FdData::is_valid_len(data.len()) { |
| 251 | return None; | 303 | return Err(FrameCreateError::InvalidDataLength); |
| 252 | } | 304 | } |
| 253 | 305 | ||
| 254 | let mut bytes = [0; 64]; | 306 | let mut bytes = [0; 64]; |
| 255 | bytes[..data.len()].copy_from_slice(data); | 307 | bytes[..data.len()].copy_from_slice(data); |
| 256 | 308 | ||
| 257 | Some(Self { bytes }) | 309 | Ok(Self { bytes }) |
| 258 | } | 310 | } |
| 259 | 311 | ||
| 260 | /// Raw read access to data. | 312 | /// Raw read access to data. |
| @@ -286,6 +338,7 @@ impl FdData { | |||
| 286 | 338 | ||
| 287 | /// Frame with up to 8 bytes of data payload as per Fd CAN | 339 | /// Frame with up to 8 bytes of data payload as per Fd CAN |
| 288 | #[derive(Debug, Copy, Clone)] | 340 | #[derive(Debug, Copy, Clone)] |
| 341 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 289 | pub struct FdFrame { | 342 | pub struct FdFrame { |
| 290 | can_header: Header, | 343 | can_header: Header, |
| 291 | data: FdData, | 344 | data: FdData, |
| @@ -293,40 +346,35 @@ pub struct FdFrame { | |||
| 293 | 346 | ||
| 294 | impl FdFrame { | 347 | impl FdFrame { |
| 295 | /// Create a new CAN classic Frame | 348 | /// Create a new CAN classic Frame |
| 296 | pub fn new(can_header: Header, data: FdData) -> FdFrame { | 349 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 297 | FdFrame { can_header, data } | 350 | let data = FdData::new(raw_data)?; |
| 351 | Ok(FdFrame { can_header, data }) | ||
| 298 | } | 352 | } |
| 299 | 353 | ||
| 300 | /// Create new extended frame | 354 | /// Create new extended frame |
| 301 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | 355 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 302 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | 356 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { |
| 303 | match FdData::new(raw_data) { | 357 | Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) |
| 304 | Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||
| 305 | None => None, | ||
| 306 | } | ||
| 307 | } else { | 358 | } else { |
| 308 | None | 359 | Err(FrameCreateError::InvalidCanId) |
| 309 | } | 360 | } |
| 310 | } | 361 | } |
| 311 | 362 | ||
| 312 | /// Create new standard frame | 363 | /// Create new standard frame |
| 313 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | 364 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 314 | if let Some(id) = embedded_can::StandardId::new(raw_id) { | 365 | if let Some(id) = embedded_can::StandardId::new(raw_id) { |
| 315 | match FdData::new(raw_data) { | 366 | Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data) |
| 316 | Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||
| 317 | None => None, | ||
| 318 | } | ||
| 319 | } else { | 367 | } else { |
| 320 | None | 368 | Err(FrameCreateError::InvalidCanId) |
| 321 | } | 369 | } |
| 322 | } | 370 | } |
| 323 | 371 | ||
| 324 | /// Create new remote frame | 372 | /// Create new remote frame |
| 325 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | 373 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> { |
| 326 | if len <= 8 { | 374 | if len <= 8 { |
| 327 | Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) | 375 | Self::new(Header::new(id.into(), len as u8, true), &[0; 8]) |
| 328 | } else { | 376 | } else { |
| 329 | None | 377 | Err(FrameCreateError::InvalidDataLength) |
| 330 | } | 378 | } |
| 331 | } | 379 | } |
| 332 | 380 | ||
| @@ -348,20 +396,17 @@ impl FdFrame { | |||
| 348 | 396 | ||
| 349 | impl embedded_can::Frame for FdFrame { | 397 | impl embedded_can::Frame for FdFrame { |
| 350 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | 398 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { |
| 351 | match FdData::new(raw_data) { | 399 | match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) { |
| 352 | Some(data) => Some(FdFrame::new( | 400 | Ok(frame) => Some(frame), |
| 353 | Header::new_fd(id.into(), raw_data.len() as u8, false, true), | 401 | Err(_) => None, |
| 354 | data, | ||
| 355 | )), | ||
| 356 | None => None, | ||
| 357 | } | 402 | } |
| 358 | } | 403 | } |
| 359 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | 404 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { |
| 360 | if len <= 8 { | 405 | if len <= 8 { |
| 361 | Some(FdFrame::new( | 406 | match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) { |
| 362 | Header::new_fd(id.into(), len as u8, true, true), | 407 | Ok(frame) => Some(frame), |
| 363 | FdData::empty(), | 408 | Err(_) => None, |
| 364 | )) | 409 | } |
| 365 | } else { | 410 | } else { |
| 366 | None | 411 | None |
| 367 | } | 412 | } |
| @@ -388,11 +433,31 @@ impl embedded_can::Frame for FdFrame { | |||
| 388 | } | 433 | } |
| 389 | 434 | ||
| 390 | impl CanHeader for FdFrame { | 435 | impl CanHeader for FdFrame { |
| 391 | fn from_header(header: Header, data: &[u8]) -> Option<Self> { | 436 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { |
| 392 | Some(Self::new(header, FdData::new(data)?)) | 437 | Self::new(header, data) |
| 393 | } | 438 | } |
| 394 | 439 | ||
| 395 | fn header(&self) -> &Header { | 440 | fn header(&self) -> &Header { |
| 396 | self.header() | 441 | self.header() |
| 397 | } | 442 | } |
| 398 | } | 443 | } |
| 444 | |||
| 445 | /// Contains CAN FD frame and additional metadata. | ||
| 446 | /// | ||
| 447 | /// Timestamp is available if `time` feature is enabled. | ||
| 448 | #[derive(Debug, Clone)] | ||
| 449 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 450 | pub struct FdEnvelope { | ||
| 451 | /// Reception time. | ||
| 452 | pub ts: Timestamp, | ||
| 453 | |||
| 454 | /// The actual CAN frame. | ||
| 455 | pub frame: FdFrame, | ||
| 456 | } | ||
| 457 | |||
| 458 | impl FdEnvelope { | ||
| 459 | /// Convert into a tuple | ||
| 460 | pub fn parts(self) -> (FdFrame, Timestamp) { | ||
| 461 | (self.frame, self.ts) | ||
| 462 | } | ||
| 463 | } | ||
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 915edb3a6..410a6bfcb 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs | |||
| @@ -1,7 +1,14 @@ | |||
| 1 | //! Controller Area Network (CAN) | 1 | //! Controller Area Network (CAN) |
| 2 | #![macro_use] | 2 | #![macro_use] |
| 3 | 3 | ||
| 4 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] | 4 | #[cfg_attr(can_bxcan, path = "bxcan/mod.rs")] |
| 5 | #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] | 5 | #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | pub use _version::*; | 7 | pub use _version::*; |
| 8 | |||
| 9 | mod common; | ||
| 10 | pub mod enums; | ||
| 11 | pub mod frame; | ||
| 12 | pub mod util; | ||
| 13 | |||
| 14 | pub use frame::Frame; | ||
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 0166ab819..f8909d438 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs | |||
| @@ -2,7 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 2 | 2 | ||
| 3 | use crate::pac::CRC as PAC_CRC; | 3 | use crate::pac::CRC as PAC_CRC; |
| 4 | use crate::peripherals::CRC; | 4 | use crate::peripherals::CRC; |
| 5 | use crate::rcc::sealed::RccPeripheral; | 5 | use crate::rcc::SealedRccPeripheral; |
| 6 | use crate::Peripheral; | 6 | use crate::Peripheral; |
| 7 | 7 | ||
| 8 | /// CRC driver. | 8 | /// CRC driver. |
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index 0c4ae55ce..46f5ea1be 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs | |||
| @@ -3,7 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 3 | use crate::pac::crc::vals; | 3 | use crate::pac::crc::vals; |
| 4 | use crate::pac::CRC as PAC_CRC; | 4 | use crate::pac::CRC as PAC_CRC; |
| 5 | use crate::peripherals::CRC; | 5 | use crate::peripherals::CRC; |
| 6 | use crate::rcc::sealed::RccPeripheral; | 6 | use crate::rcc::SealedRccPeripheral; |
| 7 | use crate::Peripheral; | 7 | use crate::Peripheral; |
| 8 | 8 | ||
| 9 | /// CRC driver. | 9 | /// CRC driver. |
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 8f259520a..18b5ec918 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs | |||
| @@ -2,14 +2,39 @@ | |||
| 2 | #[cfg(any(cryp_v2, cryp_v3))] | 2 | #[cfg(any(cryp_v2, cryp_v3))] |
| 3 | use core::cmp::min; | 3 | use core::cmp::min; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::ptr; | ||
| 5 | 6 | ||
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 7 | 9 | ||
| 10 | use crate::dma::{NoDma, Priority, Transfer, TransferOptions}; | ||
| 11 | use crate::interrupt::typelevel::Interrupt; | ||
| 8 | use crate::{interrupt, pac, peripherals, Peripheral}; | 12 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| 9 | 13 | ||
| 10 | const DES_BLOCK_SIZE: usize = 8; // 64 bits | 14 | const DES_BLOCK_SIZE: usize = 8; // 64 bits |
| 11 | const AES_BLOCK_SIZE: usize = 16; // 128 bits | 15 | const AES_BLOCK_SIZE: usize = 16; // 128 bits |
| 12 | 16 | ||
| 17 | static CRYP_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 18 | |||
| 19 | /// CRYP interrupt handler. | ||
| 20 | pub struct InterruptHandler<T: Instance> { | ||
| 21 | _phantom: PhantomData<T>, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 25 | unsafe fn on_interrupt() { | ||
| 26 | let bits = T::regs().misr().read(); | ||
| 27 | if bits.inmis() { | ||
| 28 | T::regs().imscr().modify(|w| w.set_inim(false)); | ||
| 29 | CRYP_WAKER.wake(); | ||
| 30 | } | ||
| 31 | if bits.outmis() { | ||
| 32 | T::regs().imscr().modify(|w| w.set_outim(false)); | ||
| 33 | CRYP_WAKER.wake(); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 13 | /// This trait encapsulates all cipher-specific behavior/ | 38 | /// This trait encapsulates all cipher-specific behavior/ |
| 14 | pub trait Cipher<'c> { | 39 | pub trait Cipher<'c> { |
| 15 | /// Processing block size. Determined by the processor and the algorithm. | 40 | /// Processing block size. Determined by the processor and the algorithm. |
| @@ -32,17 +57,26 @@ pub trait Cipher<'c> { | |||
| 32 | fn prepare_key(&self, _p: &pac::cryp::Cryp) {} | 57 | fn prepare_key(&self, _p: &pac::cryp::Cryp) {} |
| 33 | 58 | ||
| 34 | /// Performs any cipher-specific initialization. | 59 | /// Performs any cipher-specific initialization. |
| 35 | fn init_phase(&self, _p: &pac::cryp::Cryp) {} | 60 | fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {} |
| 61 | |||
| 62 | /// Performs any cipher-specific initialization. | ||
| 63 | async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) | ||
| 64 | where | ||
| 65 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 66 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 67 | { | ||
| 68 | } | ||
| 36 | 69 | ||
| 37 | /// Called prior to processing the last data block for cipher-specific operations. | 70 | /// Called prior to processing the last data block for cipher-specific operations. |
| 38 | fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { | 71 | fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { |
| 39 | return [0; 4]; | 72 | return [0; 4]; |
| 40 | } | 73 | } |
| 41 | 74 | ||
| 42 | /// Called after processing the last data block for cipher-specific operations. | 75 | /// Called after processing the last data block for cipher-specific operations. |
| 43 | fn post_final_block( | 76 | fn post_final_blocking<T: Instance, DmaIn, DmaOut>( |
| 44 | &self, | 77 | &self, |
| 45 | _p: &pac::cryp::Cryp, | 78 | _p: &pac::cryp::Cryp, |
| 79 | _cryp: &Cryp<T, DmaIn, DmaOut>, | ||
| 46 | _dir: Direction, | 80 | _dir: Direction, |
| 47 | _int_data: &mut [u8; AES_BLOCK_SIZE], | 81 | _int_data: &mut [u8; AES_BLOCK_SIZE], |
| 48 | _temp1: [u32; 4], | 82 | _temp1: [u32; 4], |
| @@ -50,7 +84,22 @@ pub trait Cipher<'c> { | |||
| 50 | ) { | 84 | ) { |
| 51 | } | 85 | } |
| 52 | 86 | ||
| 53 | /// Called prior to processing the first associated data block for cipher-specific operations. | 87 | /// Called after processing the last data block for cipher-specific operations. |
| 88 | async fn post_final<T: Instance, DmaIn, DmaOut>( | ||
| 89 | &self, | ||
| 90 | _p: &pac::cryp::Cryp, | ||
| 91 | _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 92 | _dir: Direction, | ||
| 93 | _int_data: &mut [u8; AES_BLOCK_SIZE], | ||
| 94 | _temp1: [u32; 4], | ||
| 95 | _padding_mask: [u8; 16], | ||
| 96 | ) where | ||
| 97 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 98 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 99 | { | ||
| 100 | } | ||
| 101 | |||
| 102 | /// Returns the AAD header block as required by the cipher. | ||
| 54 | fn get_header_block(&self) -> &[u8] { | 103 | fn get_header_block(&self) -> &[u8] { |
| 55 | return [0; 0].as_slice(); | 104 | return [0; 0].as_slice(); |
| 56 | } | 105 | } |
| @@ -425,14 +474,24 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { | |||
| 425 | p.cr().modify(|w| w.set_algomode3(true)); | 474 | p.cr().modify(|w| w.set_algomode3(true)); |
| 426 | } | 475 | } |
| 427 | 476 | ||
| 428 | fn init_phase(&self, p: &pac::cryp::Cryp) { | 477 | fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { |
| 478 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | ||
| 479 | p.cr().modify(|w| w.set_crypen(true)); | ||
| 480 | while p.cr().read().crypen() {} | ||
| 481 | } | ||
| 482 | |||
| 483 | async fn init_phase<T: Instance, DmaIn, DmaOut>( | ||
| 484 | &self, | ||
| 485 | p: &pac::cryp::Cryp, | ||
| 486 | _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 487 | ) { | ||
| 429 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | 488 | p.cr().modify(|w| w.set_gcm_ccmph(0)); |
| 430 | p.cr().modify(|w| w.set_crypen(true)); | 489 | p.cr().modify(|w| w.set_crypen(true)); |
| 431 | while p.cr().read().crypen() {} | 490 | while p.cr().read().crypen() {} |
| 432 | } | 491 | } |
| 433 | 492 | ||
| 434 | #[cfg(cryp_v2)] | 493 | #[cfg(cryp_v2)] |
| 435 | fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { | 494 | fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { |
| 436 | //Handle special GCM partial block process. | 495 | //Handle special GCM partial block process. |
| 437 | if dir == Direction::Encrypt { | 496 | if dir == Direction::Encrypt { |
| 438 | p.cr().modify(|w| w.set_crypen(false)); | 497 | p.cr().modify(|w| w.set_crypen(false)); |
| @@ -446,16 +505,17 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { | |||
| 446 | } | 505 | } |
| 447 | 506 | ||
| 448 | #[cfg(cryp_v3)] | 507 | #[cfg(cryp_v3)] |
| 449 | fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { | 508 | fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { |
| 450 | //Handle special GCM partial block process. | 509 | //Handle special GCM partial block process. |
| 451 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); | 510 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); |
| 452 | [0; 4] | 511 | [0; 4] |
| 453 | } | 512 | } |
| 454 | 513 | ||
| 455 | #[cfg(cryp_v2)] | 514 | #[cfg(cryp_v2)] |
| 456 | fn post_final_block( | 515 | fn post_final_blocking<T: Instance, DmaIn, DmaOut>( |
| 457 | &self, | 516 | &self, |
| 458 | p: &pac::cryp::Cryp, | 517 | p: &pac::cryp::Cryp, |
| 518 | cryp: &Cryp<T, DmaIn, DmaOut>, | ||
| 459 | dir: Direction, | 519 | dir: Direction, |
| 460 | int_data: &mut [u8; AES_BLOCK_SIZE], | 520 | int_data: &mut [u8; AES_BLOCK_SIZE], |
| 461 | _temp1: [u32; 4], | 521 | _temp1: [u32; 4], |
| @@ -471,17 +531,44 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { | |||
| 471 | } | 531 | } |
| 472 | p.cr().modify(|w| w.set_crypen(true)); | 532 | p.cr().modify(|w| w.set_crypen(true)); |
| 473 | p.cr().modify(|w| w.set_gcm_ccmph(3)); | 533 | p.cr().modify(|w| w.set_gcm_ccmph(3)); |
| 474 | let mut index = 0; | 534 | |
| 475 | let end_index = Self::BLOCK_SIZE; | 535 | cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data); |
| 476 | while index < end_index { | 536 | cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); |
| 477 | let mut in_word: [u8; 4] = [0; 4]; | 537 | } |
| 478 | in_word.copy_from_slice(&int_data[index..index + 4]); | 538 | } |
| 479 | p.din().write_value(u32::from_ne_bytes(in_word)); | 539 | |
| 480 | index += 4; | 540 | #[cfg(cryp_v2)] |
| 481 | } | 541 | async fn post_final<T: Instance, DmaIn, DmaOut>( |
| 482 | for _ in 0..4 { | 542 | &self, |
| 483 | p.dout().read(); | 543 | p: &pac::cryp::Cryp, |
| 544 | cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 545 | dir: Direction, | ||
| 546 | int_data: &mut [u8; AES_BLOCK_SIZE], | ||
| 547 | _temp1: [u32; 4], | ||
| 548 | padding_mask: [u8; AES_BLOCK_SIZE], | ||
| 549 | ) where | ||
| 550 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 551 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 552 | { | ||
| 553 | if dir == Direction::Encrypt { | ||
| 554 | // Handle special GCM partial block process. | ||
| 555 | p.cr().modify(|w| w.set_crypen(false)); | ||
| 556 | p.cr().modify(|w| w.set_algomode3(true)); | ||
| 557 | p.cr().modify(|w| w.set_algomode0(0)); | ||
| 558 | for i in 0..AES_BLOCK_SIZE { | ||
| 559 | int_data[i] = int_data[i] & padding_mask[i]; | ||
| 484 | } | 560 | } |
| 561 | p.cr().modify(|w| w.set_crypen(true)); | ||
| 562 | p.cr().modify(|w| w.set_gcm_ccmph(3)); | ||
| 563 | |||
| 564 | let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | ||
| 565 | |||
| 566 | let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); | ||
| 567 | let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); | ||
| 568 | |||
| 569 | embassy_futures::join::join(read, write).await; | ||
| 570 | |||
| 571 | int_data.copy_from_slice(&out_data); | ||
| 485 | } | 572 | } |
| 486 | } | 573 | } |
| 487 | } | 574 | } |
| @@ -532,14 +619,24 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { | |||
| 532 | p.cr().modify(|w| w.set_algomode3(true)); | 619 | p.cr().modify(|w| w.set_algomode3(true)); |
| 533 | } | 620 | } |
| 534 | 621 | ||
| 535 | fn init_phase(&self, p: &pac::cryp::Cryp) { | 622 | fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { |
| 623 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | ||
| 624 | p.cr().modify(|w| w.set_crypen(true)); | ||
| 625 | while p.cr().read().crypen() {} | ||
| 626 | } | ||
| 627 | |||
| 628 | async fn init_phase<T: Instance, DmaIn, DmaOut>( | ||
| 629 | &self, | ||
| 630 | p: &pac::cryp::Cryp, | ||
| 631 | _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 632 | ) { | ||
| 536 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | 633 | p.cr().modify(|w| w.set_gcm_ccmph(0)); |
| 537 | p.cr().modify(|w| w.set_crypen(true)); | 634 | p.cr().modify(|w| w.set_crypen(true)); |
| 538 | while p.cr().read().crypen() {} | 635 | while p.cr().read().crypen() {} |
| 539 | } | 636 | } |
| 540 | 637 | ||
| 541 | #[cfg(cryp_v2)] | 638 | #[cfg(cryp_v2)] |
| 542 | fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { | 639 | fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { |
| 543 | //Handle special GCM partial block process. | 640 | //Handle special GCM partial block process. |
| 544 | if dir == Direction::Encrypt { | 641 | if dir == Direction::Encrypt { |
| 545 | p.cr().modify(|w| w.set_crypen(false)); | 642 | p.cr().modify(|w| w.set_crypen(false)); |
| @@ -553,16 +650,17 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { | |||
| 553 | } | 650 | } |
| 554 | 651 | ||
| 555 | #[cfg(cryp_v3)] | 652 | #[cfg(cryp_v3)] |
| 556 | fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { | 653 | fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { |
| 557 | //Handle special GCM partial block process. | 654 | //Handle special GCM partial block process. |
| 558 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); | 655 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); |
| 559 | [0; 4] | 656 | [0; 4] |
| 560 | } | 657 | } |
| 561 | 658 | ||
| 562 | #[cfg(cryp_v2)] | 659 | #[cfg(cryp_v2)] |
| 563 | fn post_final_block( | 660 | fn post_final_blocking<T: Instance, DmaIn, DmaOut>( |
| 564 | &self, | 661 | &self, |
| 565 | p: &pac::cryp::Cryp, | 662 | p: &pac::cryp::Cryp, |
| 663 | cryp: &Cryp<T, DmaIn, DmaOut>, | ||
| 566 | dir: Direction, | 664 | dir: Direction, |
| 567 | int_data: &mut [u8; AES_BLOCK_SIZE], | 665 | int_data: &mut [u8; AES_BLOCK_SIZE], |
| 568 | _temp1: [u32; 4], | 666 | _temp1: [u32; 4], |
| @@ -578,17 +676,42 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { | |||
| 578 | } | 676 | } |
| 579 | p.cr().modify(|w| w.set_crypen(true)); | 677 | p.cr().modify(|w| w.set_crypen(true)); |
| 580 | p.cr().modify(|w| w.set_gcm_ccmph(3)); | 678 | p.cr().modify(|w| w.set_gcm_ccmph(3)); |
| 581 | let mut index = 0; | 679 | |
| 582 | let end_index = Self::BLOCK_SIZE; | 680 | cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data); |
| 583 | while index < end_index { | 681 | cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data); |
| 584 | let mut in_word: [u8; 4] = [0; 4]; | 682 | } |
| 585 | in_word.copy_from_slice(&int_data[index..index + 4]); | 683 | } |
| 586 | p.din().write_value(u32::from_ne_bytes(in_word)); | 684 | |
| 587 | index += 4; | 685 | #[cfg(cryp_v2)] |
| 588 | } | 686 | async fn post_final<T: Instance, DmaIn, DmaOut>( |
| 589 | for _ in 0..4 { | 687 | &self, |
| 590 | p.dout().read(); | 688 | p: &pac::cryp::Cryp, |
| 689 | cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 690 | dir: Direction, | ||
| 691 | int_data: &mut [u8; AES_BLOCK_SIZE], | ||
| 692 | _temp1: [u32; 4], | ||
| 693 | padding_mask: [u8; AES_BLOCK_SIZE], | ||
| 694 | ) where | ||
| 695 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 696 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 697 | { | ||
| 698 | if dir == Direction::Encrypt { | ||
| 699 | // Handle special GCM partial block process. | ||
| 700 | p.cr().modify(|w| w.set_crypen(false)); | ||
| 701 | p.cr().modify(|w| w.set_algomode3(true)); | ||
| 702 | p.cr().modify(|w| w.set_algomode0(0)); | ||
| 703 | for i in 0..AES_BLOCK_SIZE { | ||
| 704 | int_data[i] = int_data[i] & padding_mask[i]; | ||
| 591 | } | 705 | } |
| 706 | p.cr().modify(|w| w.set_crypen(true)); | ||
| 707 | p.cr().modify(|w| w.set_gcm_ccmph(3)); | ||
| 708 | |||
| 709 | let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | ||
| 710 | |||
| 711 | let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); | ||
| 712 | let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); | ||
| 713 | |||
| 714 | embassy_futures::join::join(read, write).await; | ||
| 592 | } | 715 | } |
| 593 | } | 716 | } |
| 594 | } | 717 | } |
| @@ -697,18 +820,24 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip | |||
| 697 | p.cr().modify(|w| w.set_algomode3(true)); | 820 | p.cr().modify(|w| w.set_algomode3(true)); |
| 698 | } | 821 | } |
| 699 | 822 | ||
| 700 | fn init_phase(&self, p: &pac::cryp::Cryp) { | 823 | fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) { |
| 701 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | 824 | p.cr().modify(|w| w.set_gcm_ccmph(0)); |
| 702 | 825 | ||
| 703 | let mut index = 0; | 826 | cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); |
| 704 | let end_index = index + Self::BLOCK_SIZE; | 827 | |
| 705 | // Write block in | 828 | p.cr().modify(|w| w.set_crypen(true)); |
| 706 | while index < end_index { | 829 | while p.cr().read().crypen() {} |
| 707 | let mut in_word: [u8; 4] = [0; 4]; | 830 | } |
| 708 | in_word.copy_from_slice(&self.block0[index..index + 4]); | 831 | |
| 709 | p.din().write_value(u32::from_ne_bytes(in_word)); | 832 | async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) |
| 710 | index += 4; | 833 | where |
| 711 | } | 834 | DmaIn: crate::cryp::DmaIn<T>, |
| 835 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 836 | { | ||
| 837 | p.cr().modify(|w| w.set_gcm_ccmph(0)); | ||
| 838 | |||
| 839 | Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await; | ||
| 840 | |||
| 712 | p.cr().modify(|w| w.set_crypen(true)); | 841 | p.cr().modify(|w| w.set_crypen(true)); |
| 713 | while p.cr().read().crypen() {} | 842 | while p.cr().read().crypen() {} |
| 714 | } | 843 | } |
| @@ -718,7 +847,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip | |||
| 718 | } | 847 | } |
| 719 | 848 | ||
| 720 | #[cfg(cryp_v2)] | 849 | #[cfg(cryp_v2)] |
| 721 | fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { | 850 | fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { |
| 722 | //Handle special CCM partial block process. | 851 | //Handle special CCM partial block process. |
| 723 | let mut temp1 = [0; 4]; | 852 | let mut temp1 = [0; 4]; |
| 724 | if dir == Direction::Decrypt { | 853 | if dir == Direction::Decrypt { |
| @@ -737,16 +866,17 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip | |||
| 737 | } | 866 | } |
| 738 | 867 | ||
| 739 | #[cfg(cryp_v3)] | 868 | #[cfg(cryp_v3)] |
| 740 | fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { | 869 | fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { |
| 741 | //Handle special GCM partial block process. | 870 | //Handle special GCM partial block process. |
| 742 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); | 871 | p.cr().modify(|w| w.set_npblb(padding_len as u8)); |
| 743 | [0; 4] | 872 | [0; 4] |
| 744 | } | 873 | } |
| 745 | 874 | ||
| 746 | #[cfg(cryp_v2)] | 875 | #[cfg(cryp_v2)] |
| 747 | fn post_final_block( | 876 | fn post_final_blocking<T: Instance, DmaIn, DmaOut>( |
| 748 | &self, | 877 | &self, |
| 749 | p: &pac::cryp::Cryp, | 878 | p: &pac::cryp::Cryp, |
| 879 | cryp: &Cryp<T, DmaIn, DmaOut>, | ||
| 750 | dir: Direction, | 880 | dir: Direction, |
| 751 | int_data: &mut [u8; AES_BLOCK_SIZE], | 881 | int_data: &mut [u8; AES_BLOCK_SIZE], |
| 752 | temp1: [u32; 4], | 882 | temp1: [u32; 4], |
| @@ -774,8 +904,48 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip | |||
| 774 | let int_word = u32::from_le_bytes(int_bytes); | 904 | let int_word = u32::from_le_bytes(int_bytes); |
| 775 | in_data[i] = int_word; | 905 | in_data[i] = int_word; |
| 776 | in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; | 906 | in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; |
| 777 | p.din().write_value(in_data[i]); | ||
| 778 | } | 907 | } |
| 908 | cryp.write_words_blocking(Self::BLOCK_SIZE, &in_data); | ||
| 909 | } | ||
| 910 | } | ||
| 911 | |||
| 912 | #[cfg(cryp_v2)] | ||
| 913 | async fn post_final<T: Instance, DmaIn, DmaOut>( | ||
| 914 | &self, | ||
| 915 | p: &pac::cryp::Cryp, | ||
| 916 | cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, | ||
| 917 | dir: Direction, | ||
| 918 | int_data: &mut [u8; AES_BLOCK_SIZE], | ||
| 919 | temp1: [u32; 4], | ||
| 920 | padding_mask: [u8; 16], | ||
| 921 | ) where | ||
| 922 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 923 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 924 | { | ||
| 925 | if dir == Direction::Decrypt { | ||
| 926 | //Handle special CCM partial block process. | ||
| 927 | let mut temp2 = [0; 4]; | ||
| 928 | temp2[0] = p.csgcmccmr(0).read().swap_bytes(); | ||
| 929 | temp2[1] = p.csgcmccmr(1).read().swap_bytes(); | ||
| 930 | temp2[2] = p.csgcmccmr(2).read().swap_bytes(); | ||
| 931 | temp2[3] = p.csgcmccmr(3).read().swap_bytes(); | ||
| 932 | p.cr().modify(|w| w.set_algomode3(true)); | ||
| 933 | p.cr().modify(|w| w.set_algomode0(1)); | ||
| 934 | p.cr().modify(|w| w.set_gcm_ccmph(3)); | ||
| 935 | // Header phase | ||
| 936 | p.cr().modify(|w| w.set_gcm_ccmph(1)); | ||
| 937 | for i in 0..AES_BLOCK_SIZE { | ||
| 938 | int_data[i] = int_data[i] & padding_mask[i]; | ||
| 939 | } | ||
| 940 | let mut in_data: [u32; 4] = [0; 4]; | ||
| 941 | for i in 0..in_data.len() { | ||
| 942 | let mut int_bytes: [u8; 4] = [0; 4]; | ||
| 943 | int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]); | ||
| 944 | let int_word = u32::from_le_bytes(int_bytes); | ||
| 945 | in_data[i] = int_word; | ||
| 946 | in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; | ||
| 947 | } | ||
| 948 | Cryp::<T, DmaIn, DmaOut>::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await; | ||
| 779 | } | 949 | } |
| 780 | } | 950 | } |
| 781 | } | 951 | } |
| @@ -845,24 +1015,40 @@ pub enum Direction { | |||
| 845 | } | 1015 | } |
| 846 | 1016 | ||
| 847 | /// Crypto Accelerator Driver | 1017 | /// Crypto Accelerator Driver |
| 848 | pub struct Cryp<'d, T: Instance> { | 1018 | pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> { |
| 849 | _peripheral: PeripheralRef<'d, T>, | 1019 | _peripheral: PeripheralRef<'d, T>, |
| 1020 | indma: PeripheralRef<'d, DmaIn>, | ||
| 1021 | outdma: PeripheralRef<'d, DmaOut>, | ||
| 850 | } | 1022 | } |
| 851 | 1023 | ||
| 852 | impl<'d, T: Instance> Cryp<'d, T> { | 1024 | impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { |
| 853 | /// Create a new CRYP driver. | 1025 | /// Create a new CRYP driver. |
| 854 | pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { | 1026 | pub fn new( |
| 1027 | peri: impl Peripheral<P = T> + 'd, | ||
| 1028 | indma: impl Peripheral<P = DmaIn> + 'd, | ||
| 1029 | outdma: impl Peripheral<P = DmaOut> + 'd, | ||
| 1030 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 1031 | ) -> Self { | ||
| 855 | T::enable_and_reset(); | 1032 | T::enable_and_reset(); |
| 856 | into_ref!(peri); | 1033 | into_ref!(peri, indma, outdma); |
| 857 | let instance = Self { _peripheral: peri }; | 1034 | let instance = Self { |
| 1035 | _peripheral: peri, | ||
| 1036 | indma: indma, | ||
| 1037 | outdma: outdma, | ||
| 1038 | }; | ||
| 1039 | |||
| 1040 | T::Interrupt::unpend(); | ||
| 1041 | unsafe { T::Interrupt::enable() }; | ||
| 1042 | |||
| 858 | instance | 1043 | instance |
| 859 | } | 1044 | } |
| 860 | 1045 | ||
| 861 | /// Start a new cipher operation. | 1046 | /// Start a new encrypt or decrypt operation for the given cipher. |
| 862 | /// Key size must be 128, 192, or 256 bits. | 1047 | pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( |
| 863 | /// Initialization vector must only be supplied if necessary. | 1048 | &self, |
| 864 | /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. | 1049 | cipher: &'c C, |
| 865 | pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { | 1050 | dir: Direction, |
| 1051 | ) -> Context<'c, C> { | ||
| 866 | let mut ctx: Context<'c, C> = Context { | 1052 | let mut ctx: Context<'c, C> = Context { |
| 867 | dir, | 1053 | dir, |
| 868 | last_block_processed: false, | 1054 | last_block_processed: false, |
| @@ -929,7 +1115,90 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 929 | // Flush in/out FIFOs | 1115 | // Flush in/out FIFOs |
| 930 | T::regs().cr().modify(|w| w.fflush()); | 1116 | T::regs().cr().modify(|w| w.fflush()); |
| 931 | 1117 | ||
| 932 | ctx.cipher.init_phase(&T::regs()); | 1118 | ctx.cipher.init_phase_blocking(&T::regs(), self); |
| 1119 | |||
| 1120 | self.store_context(&mut ctx); | ||
| 1121 | |||
| 1122 | ctx | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | /// Start a new encrypt or decrypt operation for the given cipher. | ||
| 1126 | pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( | ||
| 1127 | &mut self, | ||
| 1128 | cipher: &'c C, | ||
| 1129 | dir: Direction, | ||
| 1130 | ) -> Context<'c, C> | ||
| 1131 | where | ||
| 1132 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1133 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 1134 | { | ||
| 1135 | let mut ctx: Context<'c, C> = Context { | ||
| 1136 | dir, | ||
| 1137 | last_block_processed: false, | ||
| 1138 | cr: 0, | ||
| 1139 | iv: [0; 4], | ||
| 1140 | csgcmccm: [0; 8], | ||
| 1141 | csgcm: [0; 8], | ||
| 1142 | aad_complete: false, | ||
| 1143 | header_len: 0, | ||
| 1144 | payload_len: 0, | ||
| 1145 | cipher: cipher, | ||
| 1146 | phantom_data: PhantomData, | ||
| 1147 | header_processed: false, | ||
| 1148 | aad_buffer: [0; 16], | ||
| 1149 | aad_buffer_len: 0, | ||
| 1150 | }; | ||
| 1151 | |||
| 1152 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1153 | |||
| 1154 | let key = ctx.cipher.key(); | ||
| 1155 | |||
| 1156 | if key.len() == (128 / 8) { | ||
| 1157 | T::regs().cr().modify(|w| w.set_keysize(0)); | ||
| 1158 | } else if key.len() == (192 / 8) { | ||
| 1159 | T::regs().cr().modify(|w| w.set_keysize(1)); | ||
| 1160 | } else if key.len() == (256 / 8) { | ||
| 1161 | T::regs().cr().modify(|w| w.set_keysize(2)); | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | self.load_key(key); | ||
| 1165 | |||
| 1166 | // Set data type to 8-bit. This will match software implementations. | ||
| 1167 | T::regs().cr().modify(|w| w.set_datatype(2)); | ||
| 1168 | |||
| 1169 | ctx.cipher.prepare_key(&T::regs()); | ||
| 1170 | |||
| 1171 | ctx.cipher.set_algomode(&T::regs()); | ||
| 1172 | |||
| 1173 | // Set encrypt/decrypt | ||
| 1174 | if dir == Direction::Encrypt { | ||
| 1175 | T::regs().cr().modify(|w| w.set_algodir(false)); | ||
| 1176 | } else { | ||
| 1177 | T::regs().cr().modify(|w| w.set_algodir(true)); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | // Load the IV into the registers. | ||
| 1181 | let iv = ctx.cipher.iv(); | ||
| 1182 | let mut full_iv: [u8; 16] = [0; 16]; | ||
| 1183 | full_iv[0..iv.len()].copy_from_slice(iv); | ||
| 1184 | let mut iv_idx = 0; | ||
| 1185 | let mut iv_word: [u8; 4] = [0; 4]; | ||
| 1186 | iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); | ||
| 1187 | iv_idx += 4; | ||
| 1188 | T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); | ||
| 1189 | iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); | ||
| 1190 | iv_idx += 4; | ||
| 1191 | T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); | ||
| 1192 | iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); | ||
| 1193 | iv_idx += 4; | ||
| 1194 | T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); | ||
| 1195 | iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); | ||
| 1196 | T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); | ||
| 1197 | |||
| 1198 | // Flush in/out FIFOs | ||
| 1199 | T::regs().cr().modify(|w| w.fflush()); | ||
| 1200 | |||
| 1201 | ctx.cipher.init_phase(&T::regs(), self).await; | ||
| 933 | 1202 | ||
| 934 | self.store_context(&mut ctx); | 1203 | self.store_context(&mut ctx); |
| 935 | 1204 | ||
| @@ -938,10 +1207,9 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 938 | 1207 | ||
| 939 | #[cfg(any(cryp_v2, cryp_v3))] | 1208 | #[cfg(any(cryp_v2, cryp_v3))] |
| 940 | /// Controls the header phase of cipher processing. | 1209 | /// Controls the header phase of cipher processing. |
| 941 | /// This function is only valid for GCM, CCM, and GMAC modes. | 1210 | /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. |
| 942 | /// It only needs to be called if using one of these modes and there is associated data. | 1211 | /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload_blocking`. |
| 943 | /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. | 1212 | /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. |
| 944 | /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. | ||
| 945 | /// When supplying the last block of AAD, `last_aad_block` must be `true`. | 1213 | /// When supplying the last block of AAD, `last_aad_block` must be `true`. |
| 946 | pub fn aad_blocking< | 1214 | pub fn aad_blocking< |
| 947 | 'c, | 1215 | 'c, |
| @@ -985,15 +1253,7 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 985 | if ctx.aad_buffer_len < C::BLOCK_SIZE { | 1253 | if ctx.aad_buffer_len < C::BLOCK_SIZE { |
| 986 | // The buffer isn't full and this is the last buffer, so process it as is (already padded). | 1254 | // The buffer isn't full and this is the last buffer, so process it as is (already padded). |
| 987 | if last_aad_block { | 1255 | if last_aad_block { |
| 988 | let mut index = 0; | 1256 | self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); |
| 989 | let end_index = C::BLOCK_SIZE; | ||
| 990 | // Write block in | ||
| 991 | while index < end_index { | ||
| 992 | let mut in_word: [u8; 4] = [0; 4]; | ||
| 993 | in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); | ||
| 994 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 995 | index += 4; | ||
| 996 | } | ||
| 997 | // Block until input FIFO is empty. | 1257 | // Block until input FIFO is empty. |
| 998 | while !T::regs().sr().read().ifem() {} | 1258 | while !T::regs().sr().read().ifem() {} |
| 999 | 1259 | ||
| @@ -1008,15 +1268,7 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1008 | } | 1268 | } |
| 1009 | } else { | 1269 | } else { |
| 1010 | // Load the full block from the buffer. | 1270 | // Load the full block from the buffer. |
| 1011 | let mut index = 0; | 1271 | self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); |
| 1012 | let end_index = C::BLOCK_SIZE; | ||
| 1013 | // Write block in | ||
| 1014 | while index < end_index { | ||
| 1015 | let mut in_word: [u8; 4] = [0; 4]; | ||
| 1016 | in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); | ||
| 1017 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 1018 | index += 4; | ||
| 1019 | } | ||
| 1020 | // Block until input FIFO is empty. | 1272 | // Block until input FIFO is empty. |
| 1021 | while !T::regs().sr().read().ifem() {} | 1273 | while !T::regs().sr().read().ifem() {} |
| 1022 | } | 1274 | } |
| @@ -1032,33 +1284,108 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1032 | 1284 | ||
| 1033 | // Load full data blocks into core. | 1285 | // Load full data blocks into core. |
| 1034 | let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; | 1286 | let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; |
| 1035 | for block in 0..num_full_blocks { | 1287 | let start_index = len_to_copy; |
| 1036 | let mut index = len_to_copy + (block * C::BLOCK_SIZE); | 1288 | let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); |
| 1037 | let end_index = index + C::BLOCK_SIZE; | 1289 | self.write_bytes_blocking(C::BLOCK_SIZE, &aad[start_index..end_index]); |
| 1038 | // Write block in | 1290 | |
| 1039 | while index < end_index { | 1291 | if last_aad_block { |
| 1040 | let mut in_word: [u8; 4] = [0; 4]; | 1292 | if leftovers > 0 { |
| 1041 | in_word.copy_from_slice(&aad[index..index + 4]); | 1293 | self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer); |
| 1042 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 1043 | index += 4; | ||
| 1044 | } | 1294 | } |
| 1045 | // Block until input FIFO is empty. | 1295 | // Switch to payload phase. |
| 1046 | while !T::regs().sr().read().ifem() {} | 1296 | ctx.aad_complete = true; |
| 1297 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1298 | T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); | ||
| 1299 | T::regs().cr().modify(|w| w.fflush()); | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | self.store_context(ctx); | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | #[cfg(any(cryp_v2, cryp_v3))] | ||
| 1306 | /// Controls the header phase of cipher processing. | ||
| 1307 | /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. | ||
| 1308 | /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. | ||
| 1309 | /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. | ||
| 1310 | /// When supplying the last block of AAD, `last_aad_block` must be `true`. | ||
| 1311 | pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>>( | ||
| 1312 | &mut self, | ||
| 1313 | ctx: &mut Context<'c, C>, | ||
| 1314 | aad: &[u8], | ||
| 1315 | last_aad_block: bool, | ||
| 1316 | ) where | ||
| 1317 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1318 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 1319 | { | ||
| 1320 | self.load_context(ctx); | ||
| 1321 | |||
| 1322 | // Perform checks for correctness. | ||
| 1323 | if ctx.aad_complete { | ||
| 1324 | panic!("Cannot update AAD after starting payload!") | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | ctx.header_len += aad.len() as u64; | ||
| 1328 | |||
| 1329 | // Header phase | ||
| 1330 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1331 | T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); | ||
| 1332 | T::regs().cr().modify(|w| w.set_crypen(true)); | ||
| 1333 | |||
| 1334 | // First write the header B1 block if not yet written. | ||
| 1335 | if !ctx.header_processed { | ||
| 1336 | ctx.header_processed = true; | ||
| 1337 | let header = ctx.cipher.get_header_block(); | ||
| 1338 | ctx.aad_buffer[0..header.len()].copy_from_slice(header); | ||
| 1339 | ctx.aad_buffer_len += header.len(); | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | // Fill the header block to make a full block. | ||
| 1343 | let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); | ||
| 1344 | ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); | ||
| 1345 | ctx.aad_buffer_len += len_to_copy; | ||
| 1346 | ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); | ||
| 1347 | let mut aad_len_remaining = aad.len() - len_to_copy; | ||
| 1348 | |||
| 1349 | if ctx.aad_buffer_len < C::BLOCK_SIZE { | ||
| 1350 | // The buffer isn't full and this is the last buffer, so process it as is (already padded). | ||
| 1351 | if last_aad_block { | ||
| 1352 | Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; | ||
| 1353 | assert_eq!(T::regs().sr().read().ifem(), true); | ||
| 1354 | |||
| 1355 | // Switch to payload phase. | ||
| 1356 | ctx.aad_complete = true; | ||
| 1357 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1358 | T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); | ||
| 1359 | T::regs().cr().modify(|w| w.fflush()); | ||
| 1360 | } else { | ||
| 1361 | // Just return because we don't yet have a full block to process. | ||
| 1362 | return; | ||
| 1363 | } | ||
| 1364 | } else { | ||
| 1365 | // Load the full block from the buffer. | ||
| 1366 | Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; | ||
| 1367 | assert_eq!(T::regs().sr().read().ifem(), true); | ||
| 1047 | } | 1368 | } |
| 1048 | 1369 | ||
| 1370 | // Handle a partial block that is passed in. | ||
| 1371 | ctx.aad_buffer_len = 0; | ||
| 1372 | let leftovers = aad_len_remaining % C::BLOCK_SIZE; | ||
| 1373 | ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); | ||
| 1374 | ctx.aad_buffer_len += leftovers; | ||
| 1375 | ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); | ||
| 1376 | aad_len_remaining -= leftovers; | ||
| 1377 | assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); | ||
| 1378 | |||
| 1379 | // Load full data blocks into core. | ||
| 1380 | let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; | ||
| 1381 | let start_index = len_to_copy; | ||
| 1382 | let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); | ||
| 1383 | Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await; | ||
| 1384 | |||
| 1049 | if last_aad_block { | 1385 | if last_aad_block { |
| 1050 | if leftovers > 0 { | 1386 | if leftovers > 0 { |
| 1051 | let mut index = 0; | 1387 | Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; |
| 1052 | let end_index = C::BLOCK_SIZE; | 1388 | assert_eq!(T::regs().sr().read().ifem(), true); |
| 1053 | // Write block in | ||
| 1054 | while index < end_index { | ||
| 1055 | let mut in_word: [u8; 4] = [0; 4]; | ||
| 1056 | in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); | ||
| 1057 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 1058 | index += 4; | ||
| 1059 | } | ||
| 1060 | // Block until input FIFO is empty. | ||
| 1061 | while !T::regs().sr().read().ifem() {} | ||
| 1062 | } | 1389 | } |
| 1063 | // Switch to payload phase. | 1390 | // Switch to payload phase. |
| 1064 | ctx.aad_complete = true; | 1391 | ctx.aad_complete = true; |
| @@ -1074,7 +1401,7 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1074 | /// The context determines algorithm, mode, and state of the crypto accelerator. | 1401 | /// The context determines algorithm, mode, and state of the crypto accelerator. |
| 1075 | /// When the last piece of data is supplied, `last_block` should be `true`. | 1402 | /// When the last piece of data is supplied, `last_block` should be `true`. |
| 1076 | /// This function panics under various mismatches of parameters. | 1403 | /// This function panics under various mismatches of parameters. |
| 1077 | /// Input and output buffer lengths must match. | 1404 | /// Output buffer must be at least as long as the input buffer. |
| 1078 | /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. | 1405 | /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. |
| 1079 | /// Padding or ciphertext stealing must be managed by the application for these modes. | 1406 | /// Padding or ciphertext stealing must be managed by the application for these modes. |
| 1080 | /// Data must also be a multiple of block size unless `last_block` is `true`. | 1407 | /// Data must also be a multiple of block size unless `last_block` is `true`. |
| @@ -1125,54 +1452,121 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1125 | // Load data into core, block by block. | 1452 | // Load data into core, block by block. |
| 1126 | let num_full_blocks = input.len() / C::BLOCK_SIZE; | 1453 | let num_full_blocks = input.len() / C::BLOCK_SIZE; |
| 1127 | for block in 0..num_full_blocks { | 1454 | for block in 0..num_full_blocks { |
| 1128 | let mut index = block * C::BLOCK_SIZE; | 1455 | let index = block * C::BLOCK_SIZE; |
| 1129 | let end_index = index + C::BLOCK_SIZE; | ||
| 1130 | // Write block in | 1456 | // Write block in |
| 1131 | while index < end_index { | 1457 | self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); |
| 1132 | let mut in_word: [u8; 4] = [0; 4]; | ||
| 1133 | in_word.copy_from_slice(&input[index..index + 4]); | ||
| 1134 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 1135 | index += 4; | ||
| 1136 | } | ||
| 1137 | let mut index = block * C::BLOCK_SIZE; | ||
| 1138 | let end_index = index + C::BLOCK_SIZE; | ||
| 1139 | // Block until there is output to read. | ||
| 1140 | while !T::regs().sr().read().ofne() {} | ||
| 1141 | // Read block out | 1458 | // Read block out |
| 1142 | while index < end_index { | 1459 | self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]); |
| 1143 | let out_word: u32 = T::regs().dout().read(); | ||
| 1144 | output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); | ||
| 1145 | index += 4; | ||
| 1146 | } | ||
| 1147 | } | 1460 | } |
| 1148 | 1461 | ||
| 1149 | // Handle the final block, which is incomplete. | 1462 | // Handle the final block, which is incomplete. |
| 1150 | if last_block_remainder > 0 { | 1463 | if last_block_remainder > 0 { |
| 1151 | let padding_len = C::BLOCK_SIZE - last_block_remainder; | 1464 | let padding_len = C::BLOCK_SIZE - last_block_remainder; |
| 1152 | let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len); | 1465 | let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); |
| 1153 | 1466 | ||
| 1154 | let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | 1467 | let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; |
| 1155 | let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | 1468 | let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; |
| 1156 | last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); | 1469 | last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); |
| 1157 | let mut index = 0; | 1470 | self.write_bytes_blocking(C::BLOCK_SIZE, &last_block); |
| 1158 | let end_index = C::BLOCK_SIZE; | 1471 | self.read_bytes_blocking(C::BLOCK_SIZE, &mut intermediate_data); |
| 1159 | // Write block in | 1472 | |
| 1160 | while index < end_index { | 1473 | // Handle the last block depending on mode. |
| 1161 | let mut in_word: [u8; 4] = [0; 4]; | 1474 | let output_len = output.len(); |
| 1162 | in_word.copy_from_slice(&last_block[index..index + 4]); | 1475 | output[output_len - last_block_remainder..output_len] |
| 1163 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | 1476 | .copy_from_slice(&intermediate_data[0..last_block_remainder]); |
| 1164 | index += 4; | 1477 | |
| 1478 | let mut mask: [u8; 16] = [0; 16]; | ||
| 1479 | mask[..last_block_remainder].fill(0xFF); | ||
| 1480 | ctx.cipher | ||
| 1481 | .post_final_blocking(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask); | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | ctx.payload_len += input.len() as u64; | ||
| 1485 | |||
| 1486 | self.store_context(ctx); | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /// Performs encryption/decryption on the provided context. | ||
| 1490 | /// The context determines algorithm, mode, and state of the crypto accelerator. | ||
| 1491 | /// When the last piece of data is supplied, `last_block` should be `true`. | ||
| 1492 | /// This function panics under various mismatches of parameters. | ||
| 1493 | /// Output buffer must be at least as long as the input buffer. | ||
| 1494 | /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. | ||
| 1495 | /// Padding or ciphertext stealing must be managed by the application for these modes. | ||
| 1496 | /// Data must also be a multiple of block size unless `last_block` is `true`. | ||
| 1497 | pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( | ||
| 1498 | &mut self, | ||
| 1499 | ctx: &mut Context<'c, C>, | ||
| 1500 | input: &[u8], | ||
| 1501 | output: &mut [u8], | ||
| 1502 | last_block: bool, | ||
| 1503 | ) where | ||
| 1504 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1505 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 1506 | { | ||
| 1507 | self.load_context(ctx); | ||
| 1508 | |||
| 1509 | let last_block_remainder = input.len() % C::BLOCK_SIZE; | ||
| 1510 | |||
| 1511 | // Perform checks for correctness. | ||
| 1512 | if !ctx.aad_complete && ctx.header_len > 0 { | ||
| 1513 | panic!("Additional associated data must be processed first!"); | ||
| 1514 | } else if !ctx.aad_complete { | ||
| 1515 | #[cfg(any(cryp_v2, cryp_v3))] | ||
| 1516 | { | ||
| 1517 | ctx.aad_complete = true; | ||
| 1518 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1519 | T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); | ||
| 1520 | T::regs().cr().modify(|w| w.fflush()); | ||
| 1521 | T::regs().cr().modify(|w| w.set_crypen(true)); | ||
| 1165 | } | 1522 | } |
| 1166 | let mut index = 0; | 1523 | } |
| 1167 | let end_index = C::BLOCK_SIZE; | 1524 | if ctx.last_block_processed { |
| 1168 | // Block until there is output to read. | 1525 | panic!("The last block has already been processed!"); |
| 1169 | while !T::regs().sr().read().ofne() {} | 1526 | } |
| 1170 | // Read block out | 1527 | if input.len() > output.len() { |
| 1171 | while index < end_index { | 1528 | panic!("Output buffer length must match input length."); |
| 1172 | let out_word: u32 = T::regs().dout().read(); | 1529 | } |
| 1173 | intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); | 1530 | if !last_block { |
| 1174 | index += 4; | 1531 | if last_block_remainder != 0 { |
| 1532 | panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); | ||
| 1533 | } | ||
| 1534 | } | ||
| 1535 | if C::REQUIRES_PADDING { | ||
| 1536 | if last_block_remainder != 0 { | ||
| 1537 | panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); | ||
| 1175 | } | 1538 | } |
| 1539 | } | ||
| 1540 | if last_block { | ||
| 1541 | ctx.last_block_processed = true; | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | // Load data into core, block by block. | ||
| 1545 | let num_full_blocks = input.len() / C::BLOCK_SIZE; | ||
| 1546 | for block in 0..num_full_blocks { | ||
| 1547 | let index = block * C::BLOCK_SIZE; | ||
| 1548 | // Read block out | ||
| 1549 | let read = Self::read_bytes( | ||
| 1550 | &mut self.outdma, | ||
| 1551 | C::BLOCK_SIZE, | ||
| 1552 | &mut output[index..index + C::BLOCK_SIZE], | ||
| 1553 | ); | ||
| 1554 | // Write block in | ||
| 1555 | let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); | ||
| 1556 | embassy_futures::join::join(read, write).await; | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | // Handle the final block, which is incomplete. | ||
| 1560 | if last_block_remainder > 0 { | ||
| 1561 | let padding_len = C::BLOCK_SIZE - last_block_remainder; | ||
| 1562 | let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); | ||
| 1563 | |||
| 1564 | let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | ||
| 1565 | let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; | ||
| 1566 | last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); | ||
| 1567 | let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data); | ||
| 1568 | let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block); | ||
| 1569 | embassy_futures::join::join(read, write).await; | ||
| 1176 | 1570 | ||
| 1177 | // Handle the last block depending on mode. | 1571 | // Handle the last block depending on mode. |
| 1178 | let output_len = output.len(); | 1572 | let output_len = output.len(); |
| @@ -1182,7 +1576,8 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1182 | let mut mask: [u8; 16] = [0; 16]; | 1576 | let mut mask: [u8; 16] = [0; 16]; |
| 1183 | mask[..last_block_remainder].fill(0xFF); | 1577 | mask[..last_block_remainder].fill(0xFF); |
| 1184 | ctx.cipher | 1578 | ctx.cipher |
| 1185 | .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); | 1579 | .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) |
| 1580 | .await; | ||
| 1186 | } | 1581 | } |
| 1187 | 1582 | ||
| 1188 | ctx.payload_len += input.len() as u64; | 1583 | ctx.payload_len += input.len() as u64; |
| @@ -1191,8 +1586,8 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1191 | } | 1586 | } |
| 1192 | 1587 | ||
| 1193 | #[cfg(any(cryp_v2, cryp_v3))] | 1588 | #[cfg(any(cryp_v2, cryp_v3))] |
| 1194 | /// This function only needs to be called for GCM, CCM, and GMAC modes to | 1589 | /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. |
| 1195 | /// generate an authentication tag. | 1590 | /// Called after the all data has been encrypted/decrypted by `payload`. |
| 1196 | pub fn finish_blocking< | 1591 | pub fn finish_blocking< |
| 1197 | 'c, | 1592 | 'c, |
| 1198 | const TAG_SIZE: usize, | 1593 | const TAG_SIZE: usize, |
| @@ -1213,28 +1608,72 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1213 | let payloadlen2: u32 = (ctx.payload_len * 8) as u32; | 1608 | let payloadlen2: u32 = (ctx.payload_len * 8) as u32; |
| 1214 | 1609 | ||
| 1215 | #[cfg(cryp_v2)] | 1610 | #[cfg(cryp_v2)] |
| 1216 | { | 1611 | let footer: [u32; 4] = [ |
| 1217 | T::regs().din().write_value(headerlen1.swap_bytes()); | 1612 | headerlen1.swap_bytes(), |
| 1218 | T::regs().din().write_value(headerlen2.swap_bytes()); | 1613 | headerlen2.swap_bytes(), |
| 1219 | T::regs().din().write_value(payloadlen1.swap_bytes()); | 1614 | payloadlen1.swap_bytes(), |
| 1220 | T::regs().din().write_value(payloadlen2.swap_bytes()); | 1615 | payloadlen2.swap_bytes(), |
| 1221 | } | 1616 | ]; |
| 1222 | |||
| 1223 | #[cfg(cryp_v3)] | 1617 | #[cfg(cryp_v3)] |
| 1224 | { | 1618 | let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; |
| 1225 | T::regs().din().write_value(headerlen1); | 1619 | |
| 1226 | T::regs().din().write_value(headerlen2); | 1620 | self.write_words_blocking(C::BLOCK_SIZE, &footer); |
| 1227 | T::regs().din().write_value(payloadlen1); | ||
| 1228 | T::regs().din().write_value(payloadlen2); | ||
| 1229 | } | ||
| 1230 | 1621 | ||
| 1231 | while !T::regs().sr().read().ofne() {} | 1622 | while !T::regs().sr().read().ofne() {} |
| 1232 | 1623 | ||
| 1233 | let mut full_tag: [u8; 16] = [0; 16]; | 1624 | let mut full_tag: [u8; 16] = [0; 16]; |
| 1234 | full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); | 1625 | self.read_bytes_blocking(C::BLOCK_SIZE, &mut full_tag); |
| 1235 | full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); | 1626 | let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; |
| 1236 | full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); | 1627 | tag.copy_from_slice(&full_tag[0..TAG_SIZE]); |
| 1237 | full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); | 1628 | |
| 1629 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1630 | |||
| 1631 | tag | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | #[cfg(any(cryp_v2, cryp_v3))] | ||
| 1635 | // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. | ||
| 1636 | /// Called after the all data has been encrypted/decrypted by `payload`. | ||
| 1637 | pub async fn finish< | ||
| 1638 | 'c, | ||
| 1639 | const TAG_SIZE: usize, | ||
| 1640 | C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>, | ||
| 1641 | >( | ||
| 1642 | &mut self, | ||
| 1643 | mut ctx: Context<'c, C>, | ||
| 1644 | ) -> [u8; TAG_SIZE] | ||
| 1645 | where | ||
| 1646 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1647 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 1648 | { | ||
| 1649 | self.load_context(&mut ctx); | ||
| 1650 | |||
| 1651 | T::regs().cr().modify(|w| w.set_crypen(false)); | ||
| 1652 | T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); | ||
| 1653 | T::regs().cr().modify(|w| w.set_crypen(true)); | ||
| 1654 | |||
| 1655 | let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; | ||
| 1656 | let headerlen2: u32 = (ctx.header_len * 8) as u32; | ||
| 1657 | let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; | ||
| 1658 | let payloadlen2: u32 = (ctx.payload_len * 8) as u32; | ||
| 1659 | |||
| 1660 | #[cfg(cryp_v2)] | ||
| 1661 | let footer: [u32; 4] = [ | ||
| 1662 | headerlen1.swap_bytes(), | ||
| 1663 | headerlen2.swap_bytes(), | ||
| 1664 | payloadlen1.swap_bytes(), | ||
| 1665 | payloadlen2.swap_bytes(), | ||
| 1666 | ]; | ||
| 1667 | #[cfg(cryp_v3)] | ||
| 1668 | let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; | ||
| 1669 | |||
| 1670 | let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer); | ||
| 1671 | |||
| 1672 | let mut full_tag: [u8; 16] = [0; 16]; | ||
| 1673 | let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag); | ||
| 1674 | |||
| 1675 | embassy_futures::join::join(read, write).await; | ||
| 1676 | |||
| 1238 | let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; | 1677 | let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; |
| 1239 | tag.copy_from_slice(&full_tag[0..TAG_SIZE]); | 1678 | tag.copy_from_slice(&full_tag[0..TAG_SIZE]); |
| 1240 | 1679 | ||
| @@ -1325,18 +1764,134 @@ impl<'d, T: Instance> Cryp<'d, T> { | |||
| 1325 | // Enable crypto processor. | 1764 | // Enable crypto processor. |
| 1326 | T::regs().cr().modify(|w| w.set_crypen(true)); | 1765 | T::regs().cr().modify(|w| w.set_crypen(true)); |
| 1327 | } | 1766 | } |
| 1328 | } | ||
| 1329 | 1767 | ||
| 1330 | pub(crate) mod sealed { | 1768 | fn write_bytes_blocking(&self, block_size: usize, blocks: &[u8]) { |
| 1331 | use super::*; | 1769 | // Ensure input is a multiple of block size. |
| 1770 | assert_eq!(blocks.len() % block_size, 0); | ||
| 1771 | let mut index = 0; | ||
| 1772 | let end_index = blocks.len(); | ||
| 1773 | while index < end_index { | ||
| 1774 | let mut in_word: [u8; 4] = [0; 4]; | ||
| 1775 | in_word.copy_from_slice(&blocks[index..index + 4]); | ||
| 1776 | T::regs().din().write_value(u32::from_ne_bytes(in_word)); | ||
| 1777 | index += 4; | ||
| 1778 | if index % block_size == 0 { | ||
| 1779 | // Block until input FIFO is empty. | ||
| 1780 | while !T::regs().sr().read().ifem() {} | ||
| 1781 | } | ||
| 1782 | } | ||
| 1783 | } | ||
| 1332 | 1784 | ||
| 1333 | pub trait Instance { | 1785 | async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) |
| 1334 | fn regs() -> pac::cryp::Cryp; | 1786 | where |
| 1787 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1788 | { | ||
| 1789 | if blocks.len() == 0 { | ||
| 1790 | return; | ||
| 1791 | } | ||
| 1792 | // Ensure input is a multiple of block size. | ||
| 1793 | assert_eq!(blocks.len() % block_size, 0); | ||
| 1794 | // Configure DMA to transfer input to crypto core. | ||
| 1795 | let dma_request = dma.request(); | ||
| 1796 | let dst_ptr = T::regs().din().as_ptr(); | ||
| 1797 | let num_words = blocks.len() / 4; | ||
| 1798 | let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); | ||
| 1799 | let options = TransferOptions { | ||
| 1800 | priority: Priority::High, | ||
| 1801 | ..Default::default() | ||
| 1802 | }; | ||
| 1803 | let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; | ||
| 1804 | T::regs().dmacr().modify(|w| w.set_dien(true)); | ||
| 1805 | // Wait for the transfer to complete. | ||
| 1806 | dma_transfer.await; | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | #[cfg(any(cryp_v2, cryp_v3))] | ||
| 1810 | fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { | ||
| 1811 | assert_eq!((blocks.len() * 4) % block_size, 0); | ||
| 1812 | let mut byte_counter: usize = 0; | ||
| 1813 | for word in blocks { | ||
| 1814 | T::regs().din().write_value(*word); | ||
| 1815 | byte_counter += 4; | ||
| 1816 | if byte_counter % block_size == 0 { | ||
| 1817 | // Block until input FIFO is empty. | ||
| 1818 | while !T::regs().sr().read().ifem() {} | ||
| 1819 | } | ||
| 1820 | } | ||
| 1821 | } | ||
| 1822 | |||
| 1823 | #[cfg(any(cryp_v2, cryp_v3))] | ||
| 1824 | async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) | ||
| 1825 | where | ||
| 1826 | DmaIn: crate::cryp::DmaIn<T>, | ||
| 1827 | { | ||
| 1828 | if blocks.len() == 0 { | ||
| 1829 | return; | ||
| 1830 | } | ||
| 1831 | // Ensure input is a multiple of block size. | ||
| 1832 | assert_eq!((blocks.len() * 4) % block_size, 0); | ||
| 1833 | // Configure DMA to transfer input to crypto core. | ||
| 1834 | let dma_request = dma.request(); | ||
| 1835 | let dst_ptr = T::regs().din().as_ptr(); | ||
| 1836 | let num_words = blocks.len(); | ||
| 1837 | let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); | ||
| 1838 | let options = TransferOptions { | ||
| 1839 | priority: Priority::High, | ||
| 1840 | ..Default::default() | ||
| 1841 | }; | ||
| 1842 | let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; | ||
| 1843 | T::regs().dmacr().modify(|w| w.set_dien(true)); | ||
| 1844 | // Wait for the transfer to complete. | ||
| 1845 | dma_transfer.await; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { | ||
| 1849 | // Block until there is output to read. | ||
| 1850 | while !T::regs().sr().read().ofne() {} | ||
| 1851 | // Ensure input is a multiple of block size. | ||
| 1852 | assert_eq!(blocks.len() % block_size, 0); | ||
| 1853 | // Read block out | ||
| 1854 | let mut index = 0; | ||
| 1855 | let end_index = blocks.len(); | ||
| 1856 | while index < end_index { | ||
| 1857 | let out_word: u32 = T::regs().dout().read(); | ||
| 1858 | blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); | ||
| 1859 | index += 4; | ||
| 1860 | } | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) | ||
| 1864 | where | ||
| 1865 | DmaOut: crate::cryp::DmaOut<T>, | ||
| 1866 | { | ||
| 1867 | if blocks.len() == 0 { | ||
| 1868 | return; | ||
| 1869 | } | ||
| 1870 | // Ensure input is a multiple of block size. | ||
| 1871 | assert_eq!(blocks.len() % block_size, 0); | ||
| 1872 | // Configure DMA to get output from crypto core. | ||
| 1873 | let dma_request = dma.request(); | ||
| 1874 | let src_ptr = T::regs().dout().as_ptr(); | ||
| 1875 | let num_words = blocks.len() / 4; | ||
| 1876 | let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); | ||
| 1877 | let options = TransferOptions { | ||
| 1878 | priority: Priority::VeryHigh, | ||
| 1879 | ..Default::default() | ||
| 1880 | }; | ||
| 1881 | let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; | ||
| 1882 | T::regs().dmacr().modify(|w| w.set_doen(true)); | ||
| 1883 | // Wait for the transfer to complete. | ||
| 1884 | dma_transfer.await; | ||
| 1335 | } | 1885 | } |
| 1336 | } | 1886 | } |
| 1337 | 1887 | ||
| 1888 | trait SealedInstance { | ||
| 1889 | fn regs() -> pac::cryp::Cryp; | ||
| 1890 | } | ||
| 1891 | |||
| 1338 | /// CRYP instance trait. | 1892 | /// CRYP instance trait. |
| 1339 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | 1893 | #[allow(private_bounds)] |
| 1894 | pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | ||
| 1340 | /// Interrupt for this CRYP instance. | 1895 | /// Interrupt for this CRYP instance. |
| 1341 | type Interrupt: interrupt::typelevel::Interrupt; | 1896 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1342 | } | 1897 | } |
| @@ -1347,10 +1902,13 @@ foreach_interrupt!( | |||
| 1347 | type Interrupt = crate::interrupt::typelevel::$irq; | 1902 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 1348 | } | 1903 | } |
| 1349 | 1904 | ||
| 1350 | impl sealed::Instance for peripherals::$inst { | 1905 | impl SealedInstance for peripherals::$inst { |
| 1351 | fn regs() -> crate::pac::cryp::Cryp { | 1906 | fn regs() -> crate::pac::cryp::Cryp { |
| 1352 | crate::pac::$inst | 1907 | crate::pac::$inst |
| 1353 | } | 1908 | } |
| 1354 | } | 1909 | } |
| 1355 | }; | 1910 | }; |
| 1356 | ); | 1911 | ); |
| 1912 | |||
| 1913 | dma_trait!(DmaIn, Instance); | ||
| 1914 | dma_trait!(DmaOut, Instance); | ||
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 60f9404c2..acfed8356 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs | |||
| @@ -127,7 +127,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { | |||
| 127 | pub fn new( | 127 | pub fn new( |
| 128 | _peri: impl Peripheral<P = T> + 'd, | 128 | _peri: impl Peripheral<P = T> + 'd, |
| 129 | dma: impl Peripheral<P = DMA> + 'd, | 129 | dma: impl Peripheral<P = DMA> + 'd, |
| 130 | pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::sealed::Pin> + 'd, | 130 | pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd, |
| 131 | ) -> Self { | 131 | ) -> Self { |
| 132 | into_ref!(dma, pin); | 132 | into_ref!(dma, pin); |
| 133 | pin.set_as_analog(); | 133 | pin.set_as_analog(); |
| @@ -392,8 +392,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { | |||
| 392 | _peri: impl Peripheral<P = T> + 'd, | 392 | _peri: impl Peripheral<P = T> + 'd, |
| 393 | dma_ch1: impl Peripheral<P = DMACh1> + 'd, | 393 | dma_ch1: impl Peripheral<P = DMACh1> + 'd, |
| 394 | dma_ch2: impl Peripheral<P = DMACh2> + 'd, | 394 | dma_ch2: impl Peripheral<P = DMACh2> + 'd, |
| 395 | pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::sealed::Pin> + 'd, | 395 | pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd, |
| 396 | pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::sealed::Pin> + 'd, | 396 | pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd, |
| 397 | ) -> Self { | 397 | ) -> Self { |
| 398 | into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); | 398 | into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); |
| 399 | pin_ch1.set_as_analog(); | 399 | pin_ch1.set_as_analog(); |
| @@ -488,14 +488,13 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { | |||
| 488 | } | 488 | } |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | pub(crate) mod sealed { | 491 | trait SealedInstance { |
| 492 | pub trait Instance { | 492 | fn regs() -> &'static crate::pac::dac::Dac; |
| 493 | fn regs() -> &'static crate::pac::dac::Dac; | ||
| 494 | } | ||
| 495 | } | 493 | } |
| 496 | 494 | ||
| 497 | /// DAC instance. | 495 | /// DAC instance. |
| 498 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 496 | #[allow(private_bounds)] |
| 497 | pub trait Instance: SealedInstance + RccPeripheral + 'static {} | ||
| 499 | dma_trait!(DacDma1, Instance); | 498 | dma_trait!(DacDma1, Instance); |
| 500 | dma_trait!(DacDma2, Instance); | 499 | dma_trait!(DacDma2, Instance); |
| 501 | 500 | ||
| @@ -504,7 +503,7 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | |||
| 504 | 503 | ||
| 505 | foreach_peripheral!( | 504 | foreach_peripheral!( |
| 506 | (dac, $inst:ident) => { | 505 | (dac, $inst:ident) => { |
| 507 | impl crate::dac::sealed::Instance for peripherals::$inst { | 506 | impl crate::dac::SealedInstance for peripherals::$inst { |
| 508 | fn regs() -> &'static crate::pac::dac::Dac { | 507 | fn regs() -> &'static crate::pac::dac::Dac { |
| 509 | &crate::pac::$inst | 508 | &crate::pac::$inst |
| 510 | } | 509 | } |
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 826b04a4b..646ee2ce2 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs | |||
| @@ -7,8 +7,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use crate::dma::Transfer; | 9 | use crate::dma::Transfer; |
| 10 | use crate::gpio::sealed::AFType; | 10 | use crate::gpio::{AFType, Speed}; |
| 11 | use crate::gpio::Speed; | ||
| 12 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::{interrupt, Peripheral}; | 12 | use crate::{interrupt, Peripheral}; |
| 14 | 13 | ||
| @@ -431,14 +430,13 @@ where | |||
| 431 | } | 430 | } |
| 432 | } | 431 | } |
| 433 | 432 | ||
| 434 | mod sealed { | 433 | trait SealedInstance: crate::rcc::RccPeripheral { |
| 435 | pub trait Instance: crate::rcc::RccPeripheral { | 434 | fn regs(&self) -> crate::pac::dcmi::Dcmi; |
| 436 | fn regs(&self) -> crate::pac::dcmi::Dcmi; | ||
| 437 | } | ||
| 438 | } | 435 | } |
| 439 | 436 | ||
| 440 | /// DCMI instance. | 437 | /// DCMI instance. |
| 441 | pub trait Instance: sealed::Instance + 'static { | 438 | #[allow(private_bounds)] |
| 439 | pub trait Instance: SealedInstance + 'static { | ||
| 442 | /// Interrupt for this instance. | 440 | /// Interrupt for this instance. |
| 443 | type Interrupt: interrupt::typelevel::Interrupt; | 441 | type Interrupt: interrupt::typelevel::Interrupt; |
| 444 | } | 442 | } |
| @@ -465,7 +463,7 @@ pin_trait!(PixClkPin, Instance); | |||
| 465 | #[allow(unused)] | 463 | #[allow(unused)] |
| 466 | macro_rules! impl_peripheral { | 464 | macro_rules! impl_peripheral { |
| 467 | ($inst:ident, $irq:ident) => { | 465 | ($inst:ident, $irq:ident) => { |
| 468 | impl sealed::Instance for crate::peripherals::$inst { | 466 | impl SealedInstance for crate::peripherals::$inst { |
| 469 | fn regs(&self) -> crate::pac::dcmi::Dcmi { | 467 | fn regs(&self) -> crate::pac::dcmi::Dcmi { |
| 470 | crate::pac::$inst | 468 | crate::pac::$inst |
| 471 | } | 469 | } |
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 08aba2795..a6344cf06 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use core::future::Future; | 1 | use core::future::{poll_fn, Future}; |
| 2 | use core::pin::Pin; | 2 | use core::pin::Pin; |
| 3 | use core::sync::atomic::{fence, AtomicUsize, Ordering}; | 3 | use core::sync::atomic::{fence, AtomicUsize, Ordering}; |
| 4 | use core::task::{Context, Poll, Waker}; | 4 | use core::task::{Context, Poll, Waker}; |
| @@ -10,8 +10,7 @@ use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDm | |||
| 10 | use super::word::{Word, WordSize}; | 10 | use super::word::{Word, WordSize}; |
| 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; | 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::interrupt::Priority; | 13 | use crate::{interrupt, pac}; |
| 14 | use crate::pac; | ||
| 15 | 14 | ||
| 16 | pub(crate) struct ChannelInfo { | 15 | pub(crate) struct ChannelInfo { |
| 17 | pub(crate) dma: DmaInfo, | 16 | pub(crate) dma: DmaInfo, |
| @@ -45,6 +44,8 @@ pub struct TransferOptions { | |||
| 45 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. | 44 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. |
| 46 | #[cfg(dma)] | 45 | #[cfg(dma)] |
| 47 | pub fifo_threshold: Option<FifoThreshold>, | 46 | pub fifo_threshold: Option<FifoThreshold>, |
| 47 | /// Request priority level | ||
| 48 | pub priority: Priority, | ||
| 48 | /// Enable circular DMA | 49 | /// Enable circular DMA |
| 49 | /// | 50 | /// |
| 50 | /// Note: | 51 | /// Note: |
| @@ -68,6 +69,7 @@ impl Default for TransferOptions { | |||
| 68 | flow_ctrl: FlowControl::Dma, | 69 | flow_ctrl: FlowControl::Dma, |
| 69 | #[cfg(dma)] | 70 | #[cfg(dma)] |
| 70 | fifo_threshold: None, | 71 | fifo_threshold: None, |
| 72 | priority: Priority::VeryHigh, | ||
| 71 | circular: false, | 73 | circular: false, |
| 72 | half_transfer_ir: false, | 74 | half_transfer_ir: false, |
| 73 | complete_transfer_ir: true, | 75 | complete_transfer_ir: true, |
| @@ -75,6 +77,44 @@ impl Default for TransferOptions { | |||
| 75 | } | 77 | } |
| 76 | } | 78 | } |
| 77 | 79 | ||
| 80 | /// DMA request priority | ||
| 81 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 82 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 83 | pub enum Priority { | ||
| 84 | /// Low Priority | ||
| 85 | Low, | ||
| 86 | /// Medium Priority | ||
| 87 | Medium, | ||
| 88 | /// High Priority | ||
| 89 | High, | ||
| 90 | /// Very High Priority | ||
| 91 | VeryHigh, | ||
| 92 | } | ||
| 93 | |||
| 94 | #[cfg(dma)] | ||
| 95 | impl From<Priority> for pac::dma::vals::Pl { | ||
| 96 | fn from(value: Priority) -> Self { | ||
| 97 | match value { | ||
| 98 | Priority::Low => pac::dma::vals::Pl::LOW, | ||
| 99 | Priority::Medium => pac::dma::vals::Pl::MEDIUM, | ||
| 100 | Priority::High => pac::dma::vals::Pl::HIGH, | ||
| 101 | Priority::VeryHigh => pac::dma::vals::Pl::VERYHIGH, | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | #[cfg(bdma)] | ||
| 107 | impl From<Priority> for pac::bdma::vals::Pl { | ||
| 108 | fn from(value: Priority) -> Self { | ||
| 109 | match value { | ||
| 110 | Priority::Low => pac::bdma::vals::Pl::LOW, | ||
| 111 | Priority::Medium => pac::bdma::vals::Pl::MEDIUM, | ||
| 112 | Priority::High => pac::bdma::vals::Pl::HIGH, | ||
| 113 | Priority::VeryHigh => pac::bdma::vals::Pl::VERYHIGH, | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 78 | #[cfg(dma)] | 118 | #[cfg(dma)] |
| 79 | pub use dma_only::*; | 119 | pub use dma_only::*; |
| 80 | #[cfg(dma)] | 120 | #[cfg(dma)] |
| @@ -213,8 +253,8 @@ impl ChannelState { | |||
| 213 | /// safety: must be called only once | 253 | /// safety: must be called only once |
| 214 | pub(crate) unsafe fn init( | 254 | pub(crate) unsafe fn init( |
| 215 | cs: critical_section::CriticalSection, | 255 | cs: critical_section::CriticalSection, |
| 216 | #[cfg(dma)] dma_priority: Priority, | 256 | #[cfg(dma)] dma_priority: interrupt::Priority, |
| 217 | #[cfg(bdma)] bdma_priority: Priority, | 257 | #[cfg(bdma)] bdma_priority: interrupt::Priority, |
| 218 | ) { | 258 | ) { |
| 219 | foreach_interrupt! { | 259 | foreach_interrupt! { |
| 220 | ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { | 260 | ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { |
| @@ -334,7 +374,7 @@ impl AnyChannel { | |||
| 334 | w.set_dir(dir.into()); | 374 | w.set_dir(dir.into()); |
| 335 | w.set_msize(data_size.into()); | 375 | w.set_msize(data_size.into()); |
| 336 | w.set_psize(data_size.into()); | 376 | w.set_psize(data_size.into()); |
| 337 | w.set_pl(pac::dma::vals::Pl::VERYHIGH); | 377 | w.set_pl(options.priority.into()); |
| 338 | w.set_minc(incr_mem); | 378 | w.set_minc(incr_mem); |
| 339 | w.set_pinc(false); | 379 | w.set_pinc(false); |
| 340 | w.set_teie(true); | 380 | w.set_teie(true); |
| @@ -374,7 +414,7 @@ impl AnyChannel { | |||
| 374 | w.set_tcie(options.complete_transfer_ir); | 414 | w.set_tcie(options.complete_transfer_ir); |
| 375 | w.set_htie(options.half_transfer_ir); | 415 | w.set_htie(options.half_transfer_ir); |
| 376 | w.set_circ(options.circular); | 416 | w.set_circ(options.circular); |
| 377 | w.set_pl(pac::bdma::vals::Pl::VERYHIGH); | 417 | w.set_pl(options.priority.into()); |
| 378 | w.set_en(false); // don't start yet | 418 | w.set_en(false); // don't start yet |
| 379 | }); | 419 | }); |
| 380 | } | 420 | } |
| @@ -470,6 +510,31 @@ impl AnyChannel { | |||
| 470 | DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), | 510 | DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), |
| 471 | } | 511 | } |
| 472 | } | 512 | } |
| 513 | |||
| 514 | fn disable_circular_mode(&self) { | ||
| 515 | let info = self.info(); | ||
| 516 | match self.info().dma { | ||
| 517 | #[cfg(dma)] | ||
| 518 | DmaInfo::Dma(regs) => regs.st(info.num).cr().modify(|w| { | ||
| 519 | w.set_circ(false); | ||
| 520 | }), | ||
| 521 | #[cfg(bdma)] | ||
| 522 | DmaInfo::Bdma(regs) => regs.ch(info.num).cr().modify(|w| { | ||
| 523 | w.set_circ(false); | ||
| 524 | }), | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | fn poll_stop(&self) -> Poll<()> { | ||
| 529 | use core::sync::atomic::compiler_fence; | ||
| 530 | compiler_fence(Ordering::SeqCst); | ||
| 531 | |||
| 532 | if !self.is_running() { | ||
| 533 | Poll::Ready(()) | ||
| 534 | } else { | ||
| 535 | Poll::Pending | ||
| 536 | } | ||
| 537 | } | ||
| 473 | } | 538 | } |
| 474 | 539 | ||
| 475 | /// DMA transfer. | 540 | /// DMA transfer. |
| @@ -789,6 +854,25 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 789 | pub fn is_running(&mut self) -> bool { | 854 | pub fn is_running(&mut self) -> bool { |
| 790 | self.channel.is_running() | 855 | self.channel.is_running() |
| 791 | } | 856 | } |
| 857 | |||
| 858 | /// Stop the DMA transfer and await until the buffer is full. | ||
| 859 | /// | ||
| 860 | /// This disables the DMA transfer's circular mode so that the transfer | ||
| 861 | /// stops when the buffer is full. | ||
| 862 | /// | ||
| 863 | /// This is designed to be used with streaming input data such as the | ||
| 864 | /// I2S/SAI or ADC. | ||
| 865 | /// | ||
| 866 | /// When using the UART, you probably want `request_stop()`. | ||
| 867 | pub async fn stop(&mut self) { | ||
| 868 | self.channel.disable_circular_mode(); | ||
| 869 | //wait until cr.susp reads as true | ||
| 870 | poll_fn(|cx| { | ||
| 871 | self.set_waker(cx.waker()); | ||
| 872 | self.channel.poll_stop() | ||
| 873 | }) | ||
| 874 | .await | ||
| 875 | } | ||
| 792 | } | 876 | } |
| 793 | 877 | ||
| 794 | impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { | 878 | impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { |
| @@ -900,6 +984,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 900 | pub fn is_running(&mut self) -> bool { | 984 | pub fn is_running(&mut self) -> bool { |
| 901 | self.channel.is_running() | 985 | self.channel.is_running() |
| 902 | } | 986 | } |
| 987 | |||
| 988 | /// Stop the DMA transfer and await until the buffer is empty. | ||
| 989 | /// | ||
| 990 | /// This disables the DMA transfer's circular mode so that the transfer | ||
| 991 | /// stops when all available data has been written. | ||
| 992 | /// | ||
| 993 | /// This is designed to be used with streaming output data such as the | ||
| 994 | /// I2S/SAI or DAC. | ||
| 995 | pub async fn stop(&mut self) { | ||
| 996 | self.channel.disable_circular_mode(); | ||
| 997 | //wait until cr.susp reads as true | ||
| 998 | poll_fn(|cx| { | ||
| 999 | self.set_waker(cx.waker()); | ||
| 1000 | self.channel.poll_stop() | ||
| 1001 | }) | ||
| 1002 | .await | ||
| 1003 | } | ||
| 903 | } | 1004 | } |
| 904 | 1005 | ||
| 905 | impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { | 1006 | impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { |
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 1e9ab5944..dc7cd3a66 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -19,9 +19,7 @@ pub(crate) fn configure_dmamux(info: &DmamuxInfo, request: u8) { | |||
| 19 | }); | 19 | }); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | pub(crate) mod dmamux_sealed { | 22 | pub(crate) trait SealedMuxChannel {} |
| 23 | pub trait MuxChannel {} | ||
| 24 | } | ||
| 25 | 23 | ||
| 26 | /// DMAMUX1 instance. | 24 | /// DMAMUX1 instance. |
| 27 | pub struct DMAMUX1; | 25 | pub struct DMAMUX1; |
| @@ -30,14 +28,15 @@ pub struct DMAMUX1; | |||
| 30 | pub struct DMAMUX2; | 28 | pub struct DMAMUX2; |
| 31 | 29 | ||
| 32 | /// DMAMUX channel trait. | 30 | /// DMAMUX channel trait. |
| 33 | pub trait MuxChannel: dmamux_sealed::MuxChannel { | 31 | #[allow(private_bounds)] |
| 32 | pub trait MuxChannel: SealedMuxChannel { | ||
| 34 | /// DMAMUX instance this channel is on. | 33 | /// DMAMUX instance this channel is on. |
| 35 | type Mux; | 34 | type Mux; |
| 36 | } | 35 | } |
| 37 | 36 | ||
| 38 | macro_rules! dmamux_channel_impl { | 37 | macro_rules! dmamux_channel_impl { |
| 39 | ($channel_peri:ident, $dmamux:ident) => { | 38 | ($channel_peri:ident, $dmamux:ident) => { |
| 40 | impl crate::dma::dmamux_sealed::MuxChannel for crate::peripherals::$channel_peri {} | 39 | impl crate::dma::SealedMuxChannel for crate::peripherals::$channel_peri {} |
| 41 | impl crate::dma::MuxChannel for crate::peripherals::$channel_peri { | 40 | impl crate::dma::MuxChannel for crate::peripherals::$channel_peri { |
| 42 | type Mux = crate::dma::$dmamux; | 41 | type Mux = crate::dma::$dmamux; |
| 43 | } | 42 | } |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 960483f34..7e3681469 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -23,7 +23,7 @@ use core::mem; | |||
| 23 | 23 | ||
| 24 | use embassy_hal_internal::{impl_peripheral, Peripheral}; | 24 | use embassy_hal_internal::{impl_peripheral, Peripheral}; |
| 25 | 25 | ||
| 26 | use crate::interrupt::Priority; | 26 | use crate::interrupt; |
| 27 | 27 | ||
| 28 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 28 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 29 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 29 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -39,17 +39,18 @@ pub type Request = u8; | |||
| 39 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] | 39 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] |
| 40 | pub type Request = (); | 40 | pub type Request = (); |
| 41 | 41 | ||
| 42 | pub(crate) mod sealed { | 42 | pub(crate) trait SealedChannel { |
| 43 | pub trait Channel { | 43 | fn id(&self) -> u8; |
| 44 | fn id(&self) -> u8; | 44 | } |
| 45 | } | 45 | |
| 46 | pub trait ChannelInterrupt { | 46 | pub(crate) trait ChannelInterrupt { |
| 47 | unsafe fn on_irq(); | 47 | #[cfg_attr(not(feature = "rt"), allow(unused))] |
| 48 | } | 48 | unsafe fn on_irq(); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | /// DMA channel. | 51 | /// DMA channel. |
| 52 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + Into<AnyChannel> + 'static { | 52 | #[allow(private_bounds)] |
| 53 | pub trait Channel: SealedChannel + Peripheral<P = Self> + Into<AnyChannel> + 'static { | ||
| 53 | /// Type-erase (degrade) this pin into an `AnyChannel`. | 54 | /// Type-erase (degrade) this pin into an `AnyChannel`. |
| 54 | /// | 55 | /// |
| 55 | /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which | 56 | /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which |
| @@ -63,12 +64,12 @@ pub trait Channel: sealed::Channel + Peripheral<P = Self> + Into<AnyChannel> + ' | |||
| 63 | 64 | ||
| 64 | macro_rules! dma_channel_impl { | 65 | macro_rules! dma_channel_impl { |
| 65 | ($channel_peri:ident, $index:expr) => { | 66 | ($channel_peri:ident, $index:expr) => { |
| 66 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { | 67 | impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { |
| 67 | fn id(&self) -> u8 { | 68 | fn id(&self) -> u8 { |
| 68 | $index | 69 | $index |
| 69 | } | 70 | } |
| 70 | } | 71 | } |
| 71 | impl crate::dma::sealed::ChannelInterrupt for crate::peripherals::$channel_peri { | 72 | impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { |
| 72 | unsafe fn on_irq() { | 73 | unsafe fn on_irq() { |
| 73 | crate::dma::AnyChannel { id: $index }.on_irq(); | 74 | crate::dma::AnyChannel { id: $index }.on_irq(); |
| 74 | } | 75 | } |
| @@ -96,7 +97,7 @@ impl AnyChannel { | |||
| 96 | } | 97 | } |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | impl sealed::Channel for AnyChannel { | 100 | impl SealedChannel for AnyChannel { |
| 100 | fn id(&self) -> u8 { | 101 | fn id(&self) -> u8 { |
| 101 | self.id | 102 | self.id |
| 102 | } | 103 | } |
| @@ -131,9 +132,9 @@ pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) { | |||
| 131 | // safety: must be called only once at startup | 132 | // safety: must be called only once at startup |
| 132 | pub(crate) unsafe fn init( | 133 | pub(crate) unsafe fn init( |
| 133 | cs: critical_section::CriticalSection, | 134 | cs: critical_section::CriticalSection, |
| 134 | #[cfg(bdma)] bdma_priority: Priority, | 135 | #[cfg(bdma)] bdma_priority: interrupt::Priority, |
| 135 | #[cfg(dma)] dma_priority: Priority, | 136 | #[cfg(dma)] dma_priority: interrupt::Priority, |
| 136 | #[cfg(gpdma)] gpdma_priority: Priority, | 137 | #[cfg(gpdma)] gpdma_priority: interrupt::Priority, |
| 137 | ) { | 138 | ) { |
| 138 | #[cfg(any(dma, bdma))] | 139 | #[cfg(any(dma, bdma))] |
| 139 | dma_bdma::init( | 140 | dma_bdma::init( |
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs index a72c4b7d9..fb1bde860 100644 --- a/embassy-stm32/src/dma/word.rs +++ b/embassy-stm32/src/dma/word.rs | |||
| @@ -20,14 +20,13 @@ impl WordSize { | |||
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | mod sealed { | 23 | trait SealedWord {} |
| 24 | pub trait Word {} | ||
| 25 | } | ||
| 26 | 24 | ||
| 27 | /// DMA word trait. | 25 | /// DMA word trait. |
| 28 | /// | 26 | /// |
| 29 | /// This is implemented for u8, u16, u32, etc. | 27 | /// This is implemented for u8, u16, u32, etc. |
| 30 | pub trait Word: sealed::Word + Default + Copy + 'static { | 28 | #[allow(private_bounds)] |
| 29 | pub trait Word: SealedWord + Default + Copy + 'static { | ||
| 31 | /// Word size | 30 | /// Word size |
| 32 | fn size() -> WordSize; | 31 | fn size() -> WordSize; |
| 33 | /// Amount of bits of this word size. | 32 | /// Amount of bits of this word size. |
| @@ -36,7 +35,7 @@ pub trait Word: sealed::Word + Default + Copy + 'static { | |||
| 36 | 35 | ||
| 37 | macro_rules! impl_word { | 36 | macro_rules! impl_word { |
| 38 | (_, $T:ident, $bits:literal, $size:ident) => { | 37 | (_, $T:ident, $bits:literal, $size:ident) => { |
| 39 | impl sealed::Word for $T {} | 38 | impl SealedWord for $T {} |
| 40 | impl Word for $T { | 39 | impl Word for $T { |
| 41 | fn bits() -> usize { | 40 | fn bits() -> usize { |
| 42 | $bits | 41 | $bits |
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 71fe09c3f..bfe8a60d6 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs | |||
| @@ -177,16 +177,15 @@ pub unsafe trait PHY { | |||
| 177 | fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; | 177 | fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | pub(crate) mod sealed { | 180 | trait SealedInstance { |
| 181 | pub trait Instance { | 181 | fn regs() -> crate::pac::eth::Eth; |
| 182 | fn regs() -> crate::pac::eth::Eth; | ||
| 183 | } | ||
| 184 | } | 182 | } |
| 185 | 183 | ||
| 186 | /// Ethernet instance. | 184 | /// Ethernet instance. |
| 187 | pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {} | 185 | #[allow(private_bounds)] |
| 186 | pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} | ||
| 188 | 187 | ||
| 189 | impl sealed::Instance for crate::peripherals::ETH { | 188 | impl SealedInstance for crate::peripherals::ETH { |
| 190 | fn regs() -> crate::pac::eth::Eth { | 189 | fn regs() -> crate::pac::eth::Eth { |
| 191 | crate::pac::ETH | 190 | crate::pac::ETH |
| 192 | } | 191 | } |
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index e5b7b0452..6f0174def 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -12,15 +12,14 @@ use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress | |||
| 12 | pub(crate) use self::rx_desc::{RDes, RDesRing}; | 12 | pub(crate) use self::rx_desc::{RDes, RDesRing}; |
| 13 | pub(crate) use self::tx_desc::{TDes, TDesRing}; | 13 | pub(crate) use self::tx_desc::{TDes, TDesRing}; |
| 14 | use super::*; | 14 | use super::*; |
| 15 | use crate::gpio::sealed::{AFType, Pin as __GpioPin}; | 15 | use crate::gpio::{AFType, AnyPin, SealedPin}; |
| 16 | use crate::gpio::AnyPin; | ||
| 17 | use crate::interrupt::InterruptExt; | 16 | use crate::interrupt::InterruptExt; |
| 18 | #[cfg(eth_v1a)] | 17 | #[cfg(eth_v1a)] |
| 19 | use crate::pac::AFIO; | 18 | use crate::pac::AFIO; |
| 20 | #[cfg(any(eth_v1b, eth_v1c))] | 19 | #[cfg(any(eth_v1b, eth_v1c))] |
| 21 | use crate::pac::SYSCFG; | 20 | use crate::pac::SYSCFG; |
| 22 | use crate::pac::{ETH, RCC}; | 21 | use crate::pac::{ETH, RCC}; |
| 23 | use crate::rcc::sealed::RccPeripheral; | 22 | use crate::rcc::SealedRccPeripheral; |
| 24 | use crate::{interrupt, Peripheral}; | 23 | use crate::{interrupt, Peripheral}; |
| 25 | 24 | ||
| 26 | /// Interrupt handler. | 25 | /// Interrupt handler. |
| @@ -149,8 +148,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 149 | #[cfg(any(eth_v1b, eth_v1c))] | 148 | #[cfg(any(eth_v1b, eth_v1c))] |
| 150 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 149 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 151 | 150 | ||
| 152 | let dma = ETH.ethernet_dma(); | 151 | let dma = T::regs().ethernet_dma(); |
| 153 | let mac = ETH.ethernet_mac(); | 152 | let mac = T::regs().ethernet_mac(); |
| 154 | 153 | ||
| 155 | // Reset and wait | 154 | // Reset and wait |
| 156 | dma.dmabmr().modify(|w| w.set_sr(true)); | 155 | dma.dmabmr().modify(|w| w.set_sr(true)); |
| @@ -192,7 +191,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 192 | 191 | ||
| 193 | // TODO MTU size setting not found for v1 ethernet, check if correct | 192 | // TODO MTU size setting not found for v1 ethernet, check if correct |
| 194 | 193 | ||
| 195 | let hclk = <T as RccPeripheral>::frequency(); | 194 | let hclk = <T as SealedRccPeripheral>::frequency(); |
| 196 | let hclk_mhz = hclk.0 / 1_000_000; | 195 | let hclk_mhz = hclk.0 / 1_000_000; |
| 197 | 196 | ||
| 198 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | 197 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz |
| @@ -235,8 +234,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 235 | 234 | ||
| 236 | fence(Ordering::SeqCst); | 235 | fence(Ordering::SeqCst); |
| 237 | 236 | ||
| 238 | let mac = ETH.ethernet_mac(); | 237 | let mac = T::regs().ethernet_mac(); |
| 239 | let dma = ETH.ethernet_dma(); | 238 | let dma = T::regs().ethernet_dma(); |
| 240 | 239 | ||
| 241 | mac.maccr().modify(|w| { | 240 | mac.maccr().modify(|w| { |
| 242 | w.set_re(true); | 241 | w.set_re(true); |
| @@ -275,7 +274,7 @@ pub struct EthernetStationManagement<T: Instance> { | |||
| 275 | 274 | ||
| 276 | unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | 275 | unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { |
| 277 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | 276 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { |
| 278 | let mac = ETH.ethernet_mac(); | 277 | let mac = T::regs().ethernet_mac(); |
| 279 | 278 | ||
| 280 | mac.macmiiar().modify(|w| { | 279 | mac.macmiiar().modify(|w| { |
| 281 | w.set_pa(phy_addr); | 280 | w.set_pa(phy_addr); |
| @@ -289,7 +288,7 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | |||
| 289 | } | 288 | } |
| 290 | 289 | ||
| 291 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | 290 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { |
| 292 | let mac = ETH.ethernet_mac(); | 291 | let mac = T::regs().ethernet_mac(); |
| 293 | 292 | ||
| 294 | mac.macmiidr().write(|w| w.set_md(val)); | 293 | mac.macmiidr().write(|w| w.set_md(val)); |
| 295 | mac.macmiiar().modify(|w| { | 294 | mac.macmiiar().modify(|w| { |
| @@ -305,8 +304,8 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | |||
| 305 | 304 | ||
| 306 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | 305 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { |
| 307 | fn drop(&mut self) { | 306 | fn drop(&mut self) { |
| 308 | let dma = ETH.ethernet_dma(); | 307 | let dma = T::regs().ethernet_dma(); |
| 309 | let mac = ETH.ethernet_mac(); | 308 | let mac = T::regs().ethernet_mac(); |
| 310 | 309 | ||
| 311 | // Disable the TX DMA and wait for any previous transmissions to be completed | 310 | // Disable the TX DMA and wait for any previous transmissions to be completed |
| 312 | dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); | 311 | dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); |
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 8d69561d4..c6e015022 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs | |||
| @@ -7,11 +7,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 7 | 7 | ||
| 8 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; | 8 | 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::{AFType, AnyPin, SealedPin as _, Speed}; |
| 11 | use crate::gpio::{AnyPin, Speed}; | ||
| 12 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 13 | use crate::pac::ETH; | 12 | use crate::pac::ETH; |
| 14 | use crate::rcc::sealed::RccPeripheral; | 13 | use crate::rcc::SealedRccPeripheral; |
| 15 | use crate::{interrupt, Peripheral}; | 14 | use crate::{interrupt, Peripheral}; |
| 16 | 15 | ||
| 17 | /// Interrupt handler. | 16 | /// Interrupt handler. |
| @@ -207,9 +206,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 207 | phy: P, | 206 | phy: P, |
| 208 | mac_addr: [u8; 6], | 207 | mac_addr: [u8; 6], |
| 209 | ) -> Self { | 208 | ) -> Self { |
| 210 | let dma = ETH.ethernet_dma(); | 209 | let dma = T::regs().ethernet_dma(); |
| 211 | let mac = ETH.ethernet_mac(); | 210 | let mac = T::regs().ethernet_mac(); |
| 212 | let mtl = ETH.ethernet_mtl(); | 211 | let mtl = T::regs().ethernet_mtl(); |
| 213 | 212 | ||
| 214 | // Reset and wait | 213 | // Reset and wait |
| 215 | dma.dmamr().modify(|w| w.set_swr(true)); | 214 | dma.dmamr().modify(|w| w.set_swr(true)); |
| @@ -265,7 +264,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 265 | w.set_rbsz(RX_BUFFER_SIZE as u16); | 264 | w.set_rbsz(RX_BUFFER_SIZE as u16); |
| 266 | }); | 265 | }); |
| 267 | 266 | ||
| 268 | let hclk = <T as RccPeripheral>::frequency(); | 267 | let hclk = <T as SealedRccPeripheral>::frequency(); |
| 269 | let hclk_mhz = hclk.0 / 1_000_000; | 268 | let hclk_mhz = hclk.0 / 1_000_000; |
| 270 | 269 | ||
| 271 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | 270 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz |
| @@ -296,9 +295,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 296 | 295 | ||
| 297 | fence(Ordering::SeqCst); | 296 | fence(Ordering::SeqCst); |
| 298 | 297 | ||
| 299 | let mac = ETH.ethernet_mac(); | 298 | let mac = T::regs().ethernet_mac(); |
| 300 | let mtl = ETH.ethernet_mtl(); | 299 | let mtl = T::regs().ethernet_mtl(); |
| 301 | let dma = ETH.ethernet_dma(); | 300 | let dma = T::regs().ethernet_dma(); |
| 302 | 301 | ||
| 303 | mac.maccr().modify(|w| { | 302 | mac.maccr().modify(|w| { |
| 304 | w.set_re(true); | 303 | w.set_re(true); |
| @@ -334,7 +333,7 @@ pub struct EthernetStationManagement<T: Instance> { | |||
| 334 | 333 | ||
| 335 | unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | 334 | unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { |
| 336 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | 335 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { |
| 337 | let mac = ETH.ethernet_mac(); | 336 | let mac = T::regs().ethernet_mac(); |
| 338 | 337 | ||
| 339 | mac.macmdioar().modify(|w| { | 338 | mac.macmdioar().modify(|w| { |
| 340 | w.set_pa(phy_addr); | 339 | w.set_pa(phy_addr); |
| @@ -348,7 +347,7 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | |||
| 348 | } | 347 | } |
| 349 | 348 | ||
| 350 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | 349 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { |
| 351 | let mac = ETH.ethernet_mac(); | 350 | let mac = T::regs().ethernet_mac(); |
| 352 | 351 | ||
| 353 | mac.macmdiodr().write(|w| w.set_md(val)); | 352 | mac.macmdiodr().write(|w| w.set_md(val)); |
| 354 | mac.macmdioar().modify(|w| { | 353 | mac.macmdioar().modify(|w| { |
| @@ -364,9 +363,9 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { | |||
| 364 | 363 | ||
| 365 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | 364 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { |
| 366 | fn drop(&mut self) { | 365 | fn drop(&mut self) { |
| 367 | let dma = ETH.ethernet_dma(); | 366 | let dma = T::regs().ethernet_dma(); |
| 368 | let mac = ETH.ethernet_mac(); | 367 | let mac = T::regs().ethernet_mac(); |
| 369 | let mtl = ETH.ethernet_mtl(); | 368 | let mtl = T::regs().ethernet_mtl(); |
| 370 | 369 | ||
| 371 | // Disable the TX DMA and wait for any previous transmissions to be completed | 370 | // Disable the TX DMA and wait for any previous transmissions to be completed |
| 372 | dma.dmactx_cr().modify(|w| w.set_st(false)); | 371 | dma.dmactx_cr().modify(|w| w.set_st(false)); |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index bd10ba158..8d5dae436 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -330,12 +330,11 @@ macro_rules! impl_irq { | |||
| 330 | 330 | ||
| 331 | foreach_exti_irq!(impl_irq); | 331 | foreach_exti_irq!(impl_irq); |
| 332 | 332 | ||
| 333 | pub(crate) mod sealed { | 333 | trait SealedChannel {} |
| 334 | pub trait Channel {} | ||
| 335 | } | ||
| 336 | 334 | ||
| 337 | /// EXTI channel trait. | 335 | /// EXTI channel trait. |
| 338 | pub trait Channel: sealed::Channel + Sized { | 336 | #[allow(private_bounds)] |
| 337 | pub trait Channel: SealedChannel + Sized { | ||
| 339 | /// Get the EXTI channel number. | 338 | /// Get the EXTI channel number. |
| 340 | fn number(&self) -> u8; | 339 | fn number(&self) -> u8; |
| 341 | 340 | ||
| @@ -359,7 +358,7 @@ pub struct AnyChannel { | |||
| 359 | } | 358 | } |
| 360 | 359 | ||
| 361 | impl_peripheral!(AnyChannel); | 360 | impl_peripheral!(AnyChannel); |
| 362 | impl sealed::Channel for AnyChannel {} | 361 | impl SealedChannel for AnyChannel {} |
| 363 | impl Channel for AnyChannel { | 362 | impl Channel for AnyChannel { |
| 364 | fn number(&self) -> u8 { | 363 | fn number(&self) -> u8 { |
| 365 | self.number | 364 | self.number |
| @@ -368,7 +367,7 @@ impl Channel for AnyChannel { | |||
| 368 | 367 | ||
| 369 | macro_rules! impl_exti { | 368 | macro_rules! impl_exti { |
| 370 | ($type:ident, $number:expr) => { | 369 | ($type:ident, $number:expr) => { |
| 371 | impl sealed::Channel for peripherals::$type {} | 370 | impl SealedChannel for peripherals::$type {} |
| 372 | impl Channel for peripherals::$type { | 371 | impl Channel for peripherals::$type { |
| 373 | fn number(&self) -> u8 { | 372 | fn number(&self) -> u8 { |
| 374 | $number | 373 | $number |
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index e0c76e6b2..e2f135208 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index e7790369a..b16354a74 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 57447bea5..00e61f2d2 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, AtomicBool, Ordering}; | 2 | use core::sync::atomic::{fence, AtomicBool, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 0f512bbc4..72de0b445 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index b69c4343b..6a5adc941 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 743925e17..e32a82eef 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 3787082f9..580c490da 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | 1 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 3 | ||
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 9d731a512..aced69878 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs | |||
| @@ -3,8 +3,7 @@ use core::marker::PhantomData; | |||
| 3 | 3 | ||
| 4 | use embassy_hal_internal::into_ref; | 4 | use embassy_hal_internal::into_ref; |
| 5 | 5 | ||
| 6 | use crate::gpio::sealed::AFType; | 6 | use crate::gpio::{AFType, Pull, Speed}; |
| 7 | use crate::gpio::{Pull, Speed}; | ||
| 8 | use crate::Peripheral; | 7 | use crate::Peripheral; |
| 9 | 8 | ||
| 10 | /// FMC driver | 9 | /// FMC driver |
| @@ -44,7 +43,7 @@ where | |||
| 44 | 43 | ||
| 45 | /// Get the kernel clock currently in use for this FMC instance. | 44 | /// Get the kernel clock currently in use for this FMC instance. |
| 46 | pub fn source_clock_hz(&self) -> u32 { | 45 | pub fn source_clock_hz(&self) -> u32 { |
| 47 | <T as crate::rcc::sealed::RccPeripheral>::frequency().0 | 46 | <T as crate::rcc::SealedRccPeripheral>::frequency().0 |
| 48 | } | 47 | } |
| 49 | } | 48 | } |
| 50 | 49 | ||
| @@ -69,7 +68,7 @@ where | |||
| 69 | } | 68 | } |
| 70 | 69 | ||
| 71 | fn source_clock_hz(&self) -> u32 { | 70 | fn source_clock_hz(&self) -> u32 { |
| 72 | <T as crate::rcc::sealed::RccPeripheral>::frequency().0 | 71 | <T as crate::rcc::SealedRccPeripheral>::frequency().0 |
| 73 | } | 72 | } |
| 74 | } | 73 | } |
| 75 | 74 | ||
| @@ -201,18 +200,17 @@ impl<'d, T: Instance> Fmc<'d, T> { | |||
| 201 | )); | 200 | )); |
| 202 | } | 201 | } |
| 203 | 202 | ||
| 204 | pub(crate) mod sealed { | 203 | trait SealedInstance: crate::rcc::SealedRccPeripheral { |
| 205 | pub trait Instance: crate::rcc::sealed::RccPeripheral { | 204 | const REGS: crate::pac::fmc::Fmc; |
| 206 | const REGS: crate::pac::fmc::Fmc; | ||
| 207 | } | ||
| 208 | } | 205 | } |
| 209 | 206 | ||
| 210 | /// FMC instance trait. | 207 | /// FMC instance trait. |
| 211 | pub trait Instance: sealed::Instance + 'static {} | 208 | #[allow(private_bounds)] |
| 209 | pub trait Instance: SealedInstance + 'static {} | ||
| 212 | 210 | ||
| 213 | foreach_peripheral!( | 211 | foreach_peripheral!( |
| 214 | (fmc, $inst:ident) => { | 212 | (fmc, $inst:ident) => { |
| 215 | impl crate::fmc::sealed::Instance for crate::peripherals::$inst { | 213 | impl crate::fmc::SealedInstance for crate::peripherals::$inst { |
| 216 | const REGS: crate::pac::fmc::Fmc = crate::pac::$inst; | 214 | const REGS: crate::pac::fmc::Fmc = crate::pac::$inst; |
| 217 | } | 215 | } |
| 218 | impl crate::fmc::Instance for crate::peripherals::$inst {} | 216 | impl crate::fmc::Instance for crate::peripherals::$inst {} |
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 00e3e1727..214813a42 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -6,7 +6,6 @@ use core::convert::Infallible; | |||
| 6 | use critical_section::CriticalSection; | 6 | use critical_section::CriticalSection; |
| 7 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; |
| 8 | 8 | ||
| 9 | use self::sealed::Pin as _; | ||
| 10 | use crate::pac::gpio::{self, vals}; | 9 | use crate::pac::gpio::{self, vals}; |
| 11 | use crate::{pac, peripherals, Peripheral}; | 10 | use crate::{pac, peripherals, Peripheral}; |
| 12 | 11 | ||
| @@ -129,6 +128,18 @@ impl<'d> Flex<'d> { | |||
| 129 | }); | 128 | }); |
| 130 | } | 129 | } |
| 131 | 130 | ||
| 131 | /// Put the pin into AF mode, unchecked. | ||
| 132 | /// | ||
| 133 | /// This puts the pin into the AF mode, with the requested number, pull and speed. This is | ||
| 134 | /// completely unchecked, it can attach the pin to literally any peripheral, so use with care. | ||
| 135 | #[inline] | ||
| 136 | pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AFType, pull: Pull, speed: Speed) { | ||
| 137 | critical_section::with(|_| { | ||
| 138 | self.pin.set_as_af_pull(af_num, af_type, pull); | ||
| 139 | self.pin.set_speed(speed); | ||
| 140 | }); | ||
| 141 | } | ||
| 142 | |||
| 132 | /// Get whether the pin input level is high. | 143 | /// Get whether the pin input level is high. |
| 133 | #[inline] | 144 | #[inline] |
| 134 | pub fn is_high(&self) -> bool { | 145 | pub fn is_high(&self) -> bool { |
| @@ -508,172 +519,168 @@ pub enum OutputType { | |||
| 508 | OpenDrain, | 519 | OpenDrain, |
| 509 | } | 520 | } |
| 510 | 521 | ||
| 511 | impl From<OutputType> for sealed::AFType { | 522 | impl From<OutputType> for AFType { |
| 512 | fn from(value: OutputType) -> Self { | 523 | fn from(value: OutputType) -> Self { |
| 513 | match value { | 524 | match value { |
| 514 | OutputType::OpenDrain => sealed::AFType::OutputOpenDrain, | 525 | OutputType::OpenDrain => AFType::OutputOpenDrain, |
| 515 | OutputType::PushPull => sealed::AFType::OutputPushPull, | 526 | OutputType::PushPull => AFType::OutputPushPull, |
| 516 | } | 527 | } |
| 517 | } | 528 | } |
| 518 | } | 529 | } |
| 519 | 530 | ||
| 520 | #[allow(missing_docs)] | 531 | /// Alternate function type settings |
| 521 | pub(crate) mod sealed { | 532 | #[derive(Debug, Copy, Clone)] |
| 522 | use super::*; | 533 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 523 | 534 | pub enum AFType { | |
| 524 | /// Alternate function type settings | 535 | /// Input |
| 525 | #[derive(Debug, Copy, Clone)] | 536 | Input, |
| 526 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 537 | /// Output, drive the pin both high or low. |
| 527 | pub enum AFType { | 538 | OutputPushPull, |
| 528 | /// Input | 539 | /// Output, drive the pin low, or don't drive it at all if the output level is high. |
| 529 | Input, | 540 | OutputOpenDrain, |
| 530 | /// Output, drive the pin both high or low. | 541 | } |
| 531 | OutputPushPull, | ||
| 532 | /// Output, drive the pin low, or don't drive it at all if the output level is high. | ||
| 533 | OutputOpenDrain, | ||
| 534 | } | ||
| 535 | |||
| 536 | pub trait Pin { | ||
| 537 | fn pin_port(&self) -> u8; | ||
| 538 | |||
| 539 | #[inline] | ||
| 540 | fn _pin(&self) -> u8 { | ||
| 541 | self.pin_port() % 16 | ||
| 542 | } | ||
| 543 | #[inline] | ||
| 544 | fn _port(&self) -> u8 { | ||
| 545 | self.pin_port() / 16 | ||
| 546 | } | ||
| 547 | 542 | ||
| 548 | #[inline] | 543 | pub(crate) trait SealedPin { |
| 549 | fn block(&self) -> gpio::Gpio { | 544 | fn pin_port(&self) -> u8; |
| 550 | pac::GPIO(self._port() as _) | ||
| 551 | } | ||
| 552 | 545 | ||
| 553 | /// Set the output as high. | 546 | #[inline] |
| 554 | #[inline] | 547 | fn _pin(&self) -> u8 { |
| 555 | fn set_high(&self) { | 548 | self.pin_port() % 16 |
| 556 | let n = self._pin() as _; | 549 | } |
| 557 | self.block().bsrr().write(|w| w.set_bs(n, true)); | 550 | #[inline] |
| 558 | } | 551 | fn _port(&self) -> u8 { |
| 552 | self.pin_port() / 16 | ||
| 553 | } | ||
| 559 | 554 | ||
| 560 | /// Set the output as low. | 555 | #[inline] |
| 561 | #[inline] | 556 | fn block(&self) -> gpio::Gpio { |
| 562 | fn set_low(&self) { | 557 | pac::GPIO(self._port() as _) |
| 563 | let n = self._pin() as _; | 558 | } |
| 564 | self.block().bsrr().write(|w| w.set_br(n, true)); | ||
| 565 | } | ||
| 566 | 559 | ||
| 567 | #[inline] | 560 | /// Set the output as high. |
| 568 | fn set_as_af(&self, af_num: u8, af_type: AFType) { | 561 | #[inline] |
| 569 | self.set_as_af_pull(af_num, af_type, Pull::None); | 562 | fn set_high(&self) { |
| 570 | } | 563 | let n = self._pin() as _; |
| 564 | self.block().bsrr().write(|w| w.set_bs(n, true)); | ||
| 565 | } | ||
| 571 | 566 | ||
| 572 | #[cfg(gpio_v1)] | 567 | /// Set the output as low. |
| 573 | #[inline] | 568 | #[inline] |
| 574 | fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { | 569 | fn set_low(&self) { |
| 575 | // F1 uses the AFIO register for remapping. | 570 | let n = self._pin() as _; |
| 576 | // For now, this is not implemented, so af_num is ignored | 571 | self.block().bsrr().write(|w| w.set_br(n, true)); |
| 577 | // _af_num should be zero here, since it is not set by stm32-data | 572 | } |
| 578 | let r = self.block(); | ||
| 579 | let n = self._pin() as usize; | ||
| 580 | let crlh = if n < 8 { 0 } else { 1 }; | ||
| 581 | match af_type { | ||
| 582 | AFType::Input => { | ||
| 583 | let cnf = match pull { | ||
| 584 | Pull::Up => { | ||
| 585 | r.bsrr().write(|w| w.set_bs(n, true)); | ||
| 586 | vals::CnfIn::PULL | ||
| 587 | } | ||
| 588 | Pull::Down => { | ||
| 589 | r.bsrr().write(|w| w.set_br(n, true)); | ||
| 590 | vals::CnfIn::PULL | ||
| 591 | } | ||
| 592 | Pull::None => vals::CnfIn::FLOATING, | ||
| 593 | }; | ||
| 594 | |||
| 595 | r.cr(crlh).modify(|w| { | ||
| 596 | w.set_mode(n % 8, vals::Mode::INPUT); | ||
| 597 | w.set_cnf_in(n % 8, cnf); | ||
| 598 | }); | ||
| 599 | } | ||
| 600 | AFType::OutputPushPull => { | ||
| 601 | r.cr(crlh).modify(|w| { | ||
| 602 | w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); | ||
| 603 | w.set_cnf_out(n % 8, vals::CnfOut::ALTPUSHPULL); | ||
| 604 | }); | ||
| 605 | } | ||
| 606 | AFType::OutputOpenDrain => { | ||
| 607 | r.cr(crlh).modify(|w| { | ||
| 608 | w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); | ||
| 609 | w.set_cnf_out(n % 8, vals::CnfOut::ALTOPENDRAIN); | ||
| 610 | }); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | } | ||
| 614 | 573 | ||
| 615 | #[cfg(gpio_v2)] | 574 | #[inline] |
| 616 | #[inline] | 575 | fn set_as_af(&self, af_num: u8, af_type: AFType) { |
| 617 | fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { | 576 | self.set_as_af_pull(af_num, af_type, Pull::None); |
| 618 | let pin = self._pin() as usize; | 577 | } |
| 619 | let block = self.block(); | ||
| 620 | block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); | ||
| 621 | match af_type { | ||
| 622 | AFType::Input => {} | ||
| 623 | AFType::OutputPushPull => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)), | ||
| 624 | AFType::OutputOpenDrain => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), | ||
| 625 | } | ||
| 626 | block.pupdr().modify(|w| w.set_pupdr(pin, pull.into())); | ||
| 627 | 578 | ||
| 628 | block.moder().modify(|w| w.set_moder(pin, vals::Moder::ALTERNATE)); | 579 | #[cfg(gpio_v1)] |
| 629 | } | 580 | #[inline] |
| 581 | fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { | ||
| 582 | // F1 uses the AFIO register for remapping. | ||
| 583 | // For now, this is not implemented, so af_num is ignored | ||
| 584 | // _af_num should be zero here, since it is not set by stm32-data | ||
| 585 | let r = self.block(); | ||
| 586 | let n = self._pin() as usize; | ||
| 587 | let crlh = if n < 8 { 0 } else { 1 }; | ||
| 588 | match af_type { | ||
| 589 | AFType::Input => { | ||
| 590 | let cnf = match pull { | ||
| 591 | Pull::Up => { | ||
| 592 | r.bsrr().write(|w| w.set_bs(n, true)); | ||
| 593 | vals::CnfIn::PULL | ||
| 594 | } | ||
| 595 | Pull::Down => { | ||
| 596 | r.bsrr().write(|w| w.set_br(n, true)); | ||
| 597 | vals::CnfIn::PULL | ||
| 598 | } | ||
| 599 | Pull::None => vals::CnfIn::FLOATING, | ||
| 600 | }; | ||
| 630 | 601 | ||
| 631 | #[inline] | 602 | r.cr(crlh).modify(|w| { |
| 632 | fn set_as_analog(&self) { | 603 | w.set_mode(n % 8, vals::Mode::INPUT); |
| 633 | let pin = self._pin() as usize; | 604 | w.set_cnf_in(n % 8, cnf); |
| 634 | let block = self.block(); | 605 | }); |
| 635 | #[cfg(gpio_v1)] | 606 | } |
| 636 | { | 607 | AFType::OutputPushPull => { |
| 637 | let crlh = if pin < 8 { 0 } else { 1 }; | 608 | r.cr(crlh).modify(|w| { |
| 638 | block.cr(crlh).modify(|w| { | 609 | w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); |
| 639 | w.set_mode(pin % 8, vals::Mode::INPUT); | 610 | w.set_cnf_out(n % 8, vals::CnfOut::ALTPUSHPULL); |
| 640 | w.set_cnf_in(pin % 8, vals::CnfIn::ANALOG); | 611 | }); |
| 612 | } | ||
| 613 | AFType::OutputOpenDrain => { | ||
| 614 | r.cr(crlh).modify(|w| { | ||
| 615 | w.set_mode(n % 8, vals::Mode::OUTPUT50MHZ); | ||
| 616 | w.set_cnf_out(n % 8, vals::CnfOut::ALTOPENDRAIN); | ||
| 641 | }); | 617 | }); |
| 642 | } | 618 | } |
| 643 | #[cfg(gpio_v2)] | ||
| 644 | block.moder().modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); | ||
| 645 | } | 619 | } |
| 620 | } | ||
| 646 | 621 | ||
| 647 | /// Set the pin as "disconnected", ie doing nothing and consuming the lowest | 622 | #[cfg(gpio_v2)] |
| 648 | /// amount of power possible. | 623 | #[inline] |
| 649 | /// | 624 | fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { |
| 650 | /// This is currently the same as set_as_analog but is semantically different really. | 625 | let pin = self._pin() as usize; |
| 651 | /// Drivers should set_as_disconnected pins when dropped. | 626 | let block = self.block(); |
| 652 | #[inline] | 627 | block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); |
| 653 | fn set_as_disconnected(&self) { | 628 | match af_type { |
| 654 | self.set_as_analog(); | 629 | AFType::Input => {} |
| 630 | AFType::OutputPushPull => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)), | ||
| 631 | AFType::OutputOpenDrain => block.otyper().modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), | ||
| 655 | } | 632 | } |
| 633 | block.pupdr().modify(|w| w.set_pupdr(pin, pull.into())); | ||
| 656 | 634 | ||
| 657 | #[inline] | 635 | block.moder().modify(|w| w.set_moder(pin, vals::Moder::ALTERNATE)); |
| 658 | fn set_speed(&self, speed: Speed) { | 636 | } |
| 659 | let pin = self._pin() as usize; | ||
| 660 | 637 | ||
| 661 | #[cfg(gpio_v1)] | 638 | #[inline] |
| 662 | { | 639 | fn set_as_analog(&self) { |
| 663 | let crlh = if pin < 8 { 0 } else { 1 }; | 640 | let pin = self._pin() as usize; |
| 664 | self.block().cr(crlh).modify(|w| { | 641 | let block = self.block(); |
| 665 | w.set_mode(pin % 8, speed.into()); | 642 | #[cfg(gpio_v1)] |
| 666 | }); | 643 | { |
| 667 | } | 644 | let crlh = if pin < 8 { 0 } else { 1 }; |
| 645 | block.cr(crlh).modify(|w| { | ||
| 646 | w.set_mode(pin % 8, vals::Mode::INPUT); | ||
| 647 | w.set_cnf_in(pin % 8, vals::CnfIn::ANALOG); | ||
| 648 | }); | ||
| 649 | } | ||
| 650 | #[cfg(gpio_v2)] | ||
| 651 | block.moder().modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); | ||
| 652 | } | ||
| 668 | 653 | ||
| 669 | #[cfg(gpio_v2)] | 654 | /// Set the pin as "disconnected", ie doing nothing and consuming the lowest |
| 670 | self.block().ospeedr().modify(|w| w.set_ospeedr(pin, speed.into())); | 655 | /// amount of power possible. |
| 656 | /// | ||
| 657 | /// This is currently the same as set_as_analog but is semantically different really. | ||
| 658 | /// Drivers should set_as_disconnected pins when dropped. | ||
| 659 | #[inline] | ||
| 660 | fn set_as_disconnected(&self) { | ||
| 661 | self.set_as_analog(); | ||
| 662 | } | ||
| 663 | |||
| 664 | #[inline] | ||
| 665 | fn set_speed(&self, speed: Speed) { | ||
| 666 | let pin = self._pin() as usize; | ||
| 667 | |||
| 668 | #[cfg(gpio_v1)] | ||
| 669 | { | ||
| 670 | let crlh = if pin < 8 { 0 } else { 1 }; | ||
| 671 | self.block().cr(crlh).modify(|w| { | ||
| 672 | w.set_mode(pin % 8, speed.into()); | ||
| 673 | }); | ||
| 671 | } | 674 | } |
| 675 | |||
| 676 | #[cfg(gpio_v2)] | ||
| 677 | self.block().ospeedr().modify(|w| w.set_ospeedr(pin, speed.into())); | ||
| 672 | } | 678 | } |
| 673 | } | 679 | } |
| 674 | 680 | ||
| 675 | /// GPIO pin trait. | 681 | /// GPIO pin trait. |
| 676 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | 682 | #[allow(private_bounds)] |
| 683 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static { | ||
| 677 | /// EXTI channel assigned to this pin. | 684 | /// EXTI channel assigned to this pin. |
| 678 | /// | 685 | /// |
| 679 | /// For example, PC4 uses EXTI4. | 686 | /// For example, PC4 uses EXTI4. |
| @@ -737,7 +744,7 @@ impl Pin for AnyPin { | |||
| 737 | #[cfg(feature = "exti")] | 744 | #[cfg(feature = "exti")] |
| 738 | type ExtiChannel = crate::exti::AnyChannel; | 745 | type ExtiChannel = crate::exti::AnyChannel; |
| 739 | } | 746 | } |
| 740 | impl sealed::Pin for AnyPin { | 747 | impl SealedPin for AnyPin { |
| 741 | #[inline] | 748 | #[inline] |
| 742 | fn pin_port(&self) -> u8 { | 749 | fn pin_port(&self) -> u8 { |
| 743 | self.pin_port | 750 | self.pin_port |
| @@ -752,7 +759,7 @@ foreach_pin!( | |||
| 752 | #[cfg(feature = "exti")] | 759 | #[cfg(feature = "exti")] |
| 753 | type ExtiChannel = peripherals::$exti_ch; | 760 | type ExtiChannel = peripherals::$exti_ch; |
| 754 | } | 761 | } |
| 755 | impl sealed::Pin for peripherals::$pin_name { | 762 | impl SealedPin for peripherals::$pin_name { |
| 756 | #[inline] | 763 | #[inline] |
| 757 | fn pin_port(&self) -> u8 { | 764 | fn pin_port(&self) -> u8 { |
| 758 | $port_num * 16 + $pin_num | 765 | $port_num * 16 + $pin_num |
| @@ -769,16 +776,9 @@ foreach_pin!( | |||
| 769 | 776 | ||
| 770 | pub(crate) unsafe fn init(_cs: CriticalSection) { | 777 | pub(crate) unsafe fn init(_cs: CriticalSection) { |
| 771 | #[cfg(afio)] | 778 | #[cfg(afio)] |
| 772 | <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(_cs); | 779 | <crate::peripherals::AFIO as crate::rcc::SealedRccPeripheral>::enable_and_reset_with_cs(_cs); |
| 773 | 780 | ||
| 774 | crate::_generated::init_gpio(); | 781 | crate::_generated::init_gpio(); |
| 775 | |||
| 776 | // Setting this bit is mandatory to use PG[15:2]. | ||
| 777 | #[cfg(stm32u5)] | ||
| 778 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 779 | w.set_io2sv(true); | ||
| 780 | w.set_io2vmen(true); | ||
| 781 | }); | ||
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { | 784 | impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { |
| @@ -833,6 +833,18 @@ impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { | |||
| 833 | } | 833 | } |
| 834 | } | 834 | } |
| 835 | 835 | ||
| 836 | impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> { | ||
| 837 | type Error = Infallible; | ||
| 838 | |||
| 839 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 840 | Ok(self.is_high()) | ||
| 841 | } | ||
| 842 | |||
| 843 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 844 | Ok(self.is_low()) | ||
| 845 | } | ||
| 846 | } | ||
| 847 | |||
| 836 | impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { | 848 | impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { |
| 837 | type Error = Infallible; | 849 | type Error = Infallible; |
| 838 | 850 | ||
| @@ -1049,9 +1061,3 @@ impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { | |||
| 1049 | Ok((*self).is_set_low()) | 1061 | Ok((*self).is_set_low()) |
| 1050 | } | 1062 | } |
| 1051 | } | 1063 | } |
| 1052 | |||
| 1053 | /// Low-level GPIO manipulation. | ||
| 1054 | #[cfg(feature = "unstable-pac")] | ||
| 1055 | pub mod low_level { | ||
| 1056 | pub use super::sealed::*; | ||
| 1057 | } | ||
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index b47814f8b..787d5b1c9 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs | |||
| @@ -17,7 +17,7 @@ use crate::dma::NoDma; | |||
| 17 | use crate::dma::Transfer; | 17 | use crate::dma::Transfer; |
| 18 | use crate::interrupt::typelevel::Interrupt; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use crate::peripherals::HASH; | 19 | use crate::peripherals::HASH; |
| 20 | use crate::rcc::sealed::RccPeripheral; | 20 | use crate::rcc::SealedRccPeripheral; |
| 21 | use crate::{interrupt, pac, peripherals, Peripheral}; | 21 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| 22 | 22 | ||
| 23 | #[cfg(hash_v1)] | 23 | #[cfg(hash_v1)] |
| @@ -561,16 +561,13 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { | |||
| 561 | } | 561 | } |
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | pub(crate) mod sealed { | 564 | trait SealedInstance { |
| 565 | use super::*; | 565 | fn regs() -> pac::hash::Hash; |
| 566 | |||
| 567 | pub trait Instance { | ||
| 568 | fn regs() -> pac::hash::Hash; | ||
| 569 | } | ||
| 570 | } | 566 | } |
| 571 | 567 | ||
| 572 | /// HASH instance trait. | 568 | /// HASH instance trait. |
| 573 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | 569 | #[allow(private_bounds)] |
| 570 | pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | ||
| 574 | /// Interrupt for this HASH instance. | 571 | /// Interrupt for this HASH instance. |
| 575 | type Interrupt: interrupt::typelevel::Interrupt; | 572 | type Interrupt: interrupt::typelevel::Interrupt; |
| 576 | } | 573 | } |
| @@ -581,7 +578,7 @@ foreach_interrupt!( | |||
| 581 | type Interrupt = crate::interrupt::typelevel::$irq; | 578 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 582 | } | 579 | } |
| 583 | 580 | ||
| 584 | impl sealed::Instance for peripherals::$inst { | 581 | impl SealedInstance for peripherals::$inst { |
| 585 | fn regs() -> crate::pac::hash::Hash { | 582 | fn regs() -> crate::pac::hash::Hash { |
| 586 | crate::pac::$inst | 583 | crate::pac::$inst |
| 587 | } | 584 | } |
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 3ec646fc3..02e45819c 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs | |||
| @@ -7,9 +7,7 @@ use core::marker::PhantomData; | |||
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | pub use traits::Instance; | 8 | pub use traits::Instance; |
| 9 | 9 | ||
| 10 | #[allow(unused_imports)] | 10 | use crate::gpio::{AFType, AnyPin}; |
| 11 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 12 | use crate::gpio::AnyPin; | ||
| 13 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 14 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| 15 | 13 | ||
| @@ -54,16 +52,13 @@ pub struct ChF<T: Instance> { | |||
| 54 | phantom: PhantomData<T>, | 52 | phantom: PhantomData<T>, |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | mod sealed { | 55 | trait SealedAdvancedChannel<T: Instance> { |
| 58 | use super::Instance; | 56 | fn raw() -> usize; |
| 59 | |||
| 60 | pub trait AdvancedChannel<T: Instance> { | ||
| 61 | fn raw() -> usize; | ||
| 62 | } | ||
| 63 | } | 57 | } |
| 64 | 58 | ||
| 65 | /// Advanced channel instance trait. | 59 | /// Advanced channel instance trait. |
| 66 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} | 60 | #[allow(private_bounds)] |
| 61 | pub trait AdvancedChannel<T: Instance>: SealedAdvancedChannel<T> {} | ||
| 67 | 62 | ||
| 68 | /// HRTIM PWM pin. | 63 | /// HRTIM PWM pin. |
| 69 | pub struct PwmPin<'d, T, C> { | 64 | pub struct PwmPin<'d, T, C> { |
| @@ -113,7 +108,7 @@ macro_rules! advanced_channel_impl { | |||
| 113 | } | 108 | } |
| 114 | } | 109 | } |
| 115 | 110 | ||
| 116 | impl<T: Instance> sealed::AdvancedChannel<T> for $channel<T> { | 111 | impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { |
| 117 | fn raw() -> usize { | 112 | fn raw() -> usize { |
| 118 | $ch_num | 113 | $ch_num |
| 119 | } | 114 | } |
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index dcc2b9ef4..75f9971e2 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use crate::rcc::sealed::RccPeripheral; | 1 | use crate::rcc::RccPeripheral; |
| 2 | use crate::time::Hertz; | 2 | use crate::time::Hertz; |
| 3 | 3 | ||
| 4 | #[repr(u8)] | 4 | #[repr(u8)] |
| @@ -72,94 +72,92 @@ impl Prescaler { | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | pub(crate) mod sealed { | 75 | pub(crate) trait SealedInstance: RccPeripheral { |
| 76 | use super::*; | 76 | fn regs() -> crate::pac::hrtim::Hrtim; |
| 77 | 77 | ||
| 78 | pub trait Instance: RccPeripheral { | 78 | #[allow(unused)] |
| 79 | fn regs() -> crate::pac::hrtim::Hrtim; | 79 | fn set_master_frequency(frequency: Hertz) { |
| 80 | let f = frequency.0; | ||
| 80 | 81 | ||
| 81 | fn set_master_frequency(frequency: Hertz) { | 82 | // TODO: wire up HRTIM to the RCC mux infra. |
| 82 | let f = frequency.0; | 83 | //#[cfg(stm32f334)] |
| 84 | //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; | ||
| 85 | //#[cfg(not(stm32f334))] | ||
| 86 | let timer_f = Self::frequency().0; | ||
| 83 | 87 | ||
| 84 | // TODO: wire up HRTIM to the RCC mux infra. | 88 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); |
| 85 | //#[cfg(stm32f334)] | 89 | let psc = if Self::regs().isr().read().dllrdy() { |
| 86 | //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; | 90 | Prescaler::compute_min_high_res(psc_min) |
| 87 | //#[cfg(not(stm32f334))] | 91 | } else { |
| 88 | let timer_f = Self::frequency().0; | 92 | Prescaler::compute_min_low_res(psc_min) |
| 93 | }; | ||
| 89 | 94 | ||
| 90 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); | 95 | let timer_f = 32 * (timer_f / psc as u32); |
| 91 | let psc = if Self::regs().isr().read().dllrdy() { | 96 | let per: u16 = (timer_f / f) as u16; |
| 92 | Prescaler::compute_min_high_res(psc_min) | ||
| 93 | } else { | ||
| 94 | Prescaler::compute_min_low_res(psc_min) | ||
| 95 | }; | ||
| 96 | 97 | ||
| 97 | let timer_f = 32 * (timer_f / psc as u32); | 98 | let regs = Self::regs(); |
| 98 | let per: u16 = (timer_f / f) as u16; | ||
| 99 | 99 | ||
| 100 | let regs = Self::regs(); | 100 | regs.mcr().modify(|w| w.set_ckpsc(psc.into())); |
| 101 | 101 | regs.mper().modify(|w| w.set_mper(per)); | |
| 102 | regs.mcr().modify(|w| w.set_ckpsc(psc.into())); | 102 | } |
| 103 | regs.mper().modify(|w| w.set_mper(per)); | ||
| 104 | } | ||
| 105 | 103 | ||
| 106 | fn set_channel_frequency(channel: usize, frequency: Hertz) { | 104 | fn set_channel_frequency(channel: usize, frequency: Hertz) { |
| 107 | let f = frequency.0; | 105 | let f = frequency.0; |
| 108 | 106 | ||
| 109 | // TODO: wire up HRTIM to the RCC mux infra. | 107 | // TODO: wire up HRTIM to the RCC mux infra. |
| 110 | //#[cfg(stm32f334)] | 108 | //#[cfg(stm32f334)] |
| 111 | //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; | 109 | //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; |
| 112 | //#[cfg(not(stm32f334))] | 110 | //#[cfg(not(stm32f334))] |
| 113 | let timer_f = Self::frequency().0; | 111 | let timer_f = Self::frequency().0; |
| 114 | 112 | ||
| 115 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); | 113 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); |
| 116 | let psc = if Self::regs().isr().read().dllrdy() { | 114 | let psc = if Self::regs().isr().read().dllrdy() { |
| 117 | Prescaler::compute_min_high_res(psc_min) | 115 | Prescaler::compute_min_high_res(psc_min) |
| 118 | } else { | 116 | } else { |
| 119 | Prescaler::compute_min_low_res(psc_min) | 117 | Prescaler::compute_min_low_res(psc_min) |
| 120 | }; | 118 | }; |
| 121 | 119 | ||
| 122 | let timer_f = 32 * (timer_f / psc as u32); | 120 | let timer_f = 32 * (timer_f / psc as u32); |
| 123 | let per: u16 = (timer_f / f) as u16; | 121 | let per: u16 = (timer_f / f) as u16; |
| 124 | 122 | ||
| 125 | let regs = Self::regs(); | 123 | let regs = Self::regs(); |
| 126 | 124 | ||
| 127 | regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); | 125 | regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); |
| 128 | regs.tim(channel).per().modify(|w| w.set_per(per)); | 126 | regs.tim(channel).per().modify(|w| w.set_per(per)); |
| 129 | } | 127 | } |
| 130 | 128 | ||
| 131 | /// Set the dead time as a proportion of max_duty | 129 | /// Set the dead time as a proportion of max_duty |
| 132 | fn set_channel_dead_time(channel: usize, dead_time: u16) { | 130 | fn set_channel_dead_time(channel: usize, dead_time: u16) { |
| 133 | let regs = Self::regs(); | 131 | let regs = Self::regs(); |
| 134 | 132 | ||
| 135 | let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); | 133 | let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); |
| 136 | 134 | ||
| 137 | // The dead-time base clock runs 4 times slower than the hrtim base clock | 135 | // The dead-time base clock runs 4 times slower than the hrtim base clock |
| 138 | // u9::MAX = 511 | 136 | // u9::MAX = 511 |
| 139 | let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); | 137 | let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); |
| 140 | let psc = if Self::regs().isr().read().dllrdy() { | 138 | let psc = if Self::regs().isr().read().dllrdy() { |
| 141 | Prescaler::compute_min_high_res(psc_min) | 139 | Prescaler::compute_min_high_res(psc_min) |
| 142 | } else { | 140 | } else { |
| 143 | Prescaler::compute_min_low_res(psc_min) | 141 | Prescaler::compute_min_low_res(psc_min) |
| 144 | }; | 142 | }; |
| 145 | 143 | ||
| 146 | let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); | 144 | let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); |
| 147 | 145 | ||
| 148 | regs.tim(channel).dt().modify(|w| { | 146 | regs.tim(channel).dt().modify(|w| { |
| 149 | w.set_dtprsc(psc.into()); | 147 | w.set_dtprsc(psc.into()); |
| 150 | w.set_dtf(dt_val as u16); | 148 | w.set_dtf(dt_val as u16); |
| 151 | w.set_dtr(dt_val as u16); | 149 | w.set_dtr(dt_val as u16); |
| 152 | }); | 150 | }); |
| 153 | } | ||
| 154 | } | 151 | } |
| 155 | } | 152 | } |
| 156 | 153 | ||
| 157 | /// HRTIM instance trait. | 154 | /// HRTIM instance trait. |
| 158 | pub trait Instance: sealed::Instance + 'static {} | 155 | #[allow(private_bounds)] |
| 156 | pub trait Instance: SealedInstance + 'static {} | ||
| 159 | 157 | ||
| 160 | foreach_interrupt! { | 158 | foreach_interrupt! { |
| 161 | ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { | 159 | ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { |
| 162 | impl sealed::Instance for crate::peripherals::$inst { | 160 | impl SealedInstance for crate::peripherals::$inst { |
| 163 | fn regs() -> crate::pac::hrtim::Hrtim { | 161 | fn regs() -> crate::pac::hrtim::Hrtim { |
| 164 | crate::pac::$inst | 162 | crate::pac::$inst |
| 165 | } | 163 | } |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 2416005b5..f1b11cc44 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -14,8 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 14 | use embassy_time::{Duration, Instant}; | 14 | use embassy_time::{Duration, Instant}; |
| 15 | 15 | ||
| 16 | use crate::dma::NoDma; | 16 | use crate::dma::NoDma; |
| 17 | use crate::gpio::sealed::AFType; | 17 | use crate::gpio::{AFType, Pull}; |
| 18 | use crate::gpio::Pull; | ||
| 19 | use crate::interrupt::typelevel::Interrupt; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| 21 | use crate::{interrupt, peripherals}; | 20 | use crate::{interrupt, peripherals}; |
| @@ -175,30 +174,27 @@ impl Timeout { | |||
| 175 | } | 174 | } |
| 176 | } | 175 | } |
| 177 | 176 | ||
| 178 | pub(crate) mod sealed { | 177 | struct State { |
| 179 | use super::*; | 178 | #[allow(unused)] |
| 180 | 179 | waker: AtomicWaker, | |
| 181 | pub struct State { | 180 | } |
| 182 | #[allow(unused)] | ||
| 183 | pub waker: AtomicWaker, | ||
| 184 | } | ||
| 185 | 181 | ||
| 186 | impl State { | 182 | impl State { |
| 187 | pub const fn new() -> Self { | 183 | const fn new() -> Self { |
| 188 | Self { | 184 | Self { |
| 189 | waker: AtomicWaker::new(), | 185 | waker: AtomicWaker::new(), |
| 190 | } | ||
| 191 | } | 186 | } |
| 192 | } | 187 | } |
| 188 | } | ||
| 193 | 189 | ||
| 194 | pub trait Instance: crate::rcc::RccPeripheral { | 190 | trait SealedInstance: crate::rcc::RccPeripheral { |
| 195 | fn regs() -> crate::pac::i2c::I2c; | 191 | fn regs() -> crate::pac::i2c::I2c; |
| 196 | fn state() -> &'static State; | 192 | fn state() -> &'static State; |
| 197 | } | ||
| 198 | } | 193 | } |
| 199 | 194 | ||
| 200 | /// I2C peripheral instance | 195 | /// I2C peripheral instance |
| 201 | pub trait Instance: sealed::Instance + 'static { | 196 | #[allow(private_bounds)] |
| 197 | pub trait Instance: SealedInstance + 'static { | ||
| 202 | /// Event interrupt for this instance | 198 | /// Event interrupt for this instance |
| 203 | type EventInterrupt: interrupt::typelevel::Interrupt; | 199 | type EventInterrupt: interrupt::typelevel::Interrupt; |
| 204 | /// Error interrupt for this instance | 200 | /// Error interrupt for this instance |
| @@ -234,13 +230,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInte | |||
| 234 | 230 | ||
| 235 | foreach_peripheral!( | 231 | foreach_peripheral!( |
| 236 | (i2c, $inst:ident) => { | 232 | (i2c, $inst:ident) => { |
| 237 | impl sealed::Instance for peripherals::$inst { | 233 | impl SealedInstance for peripherals::$inst { |
| 238 | fn regs() -> crate::pac::i2c::I2c { | 234 | fn regs() -> crate::pac::i2c::I2c { |
| 239 | crate::pac::$inst | 235 | crate::pac::$inst |
| 240 | } | 236 | } |
| 241 | 237 | ||
| 242 | fn state() -> &'static sealed::State { | 238 | fn state() -> &'static State { |
| 243 | static STATE: sealed::State = sealed::State::new(); | 239 | static STATE: State = State::new(); |
| 244 | &STATE | 240 | &STATE |
| 245 | } | 241 | } |
| 246 | } | 242 | } |
| @@ -311,10 +307,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { | |||
| 311 | 307 | ||
| 312 | fn transaction( | 308 | fn transaction( |
| 313 | &mut self, | 309 | &mut self, |
| 314 | _address: u8, | 310 | address: u8, |
| 315 | _operations: &mut [embedded_hal_1::i2c::Operation<'_>], | 311 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], |
| 316 | ) -> Result<(), Self::Error> { | 312 | ) -> Result<(), Self::Error> { |
| 317 | todo!(); | 313 | self.blocking_transaction(address, operations) |
| 318 | } | 314 | } |
| 319 | } | 315 | } |
| 320 | 316 | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index cbbc201de..9f29ed5e0 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -10,11 +10,11 @@ use core::task::Poll; | |||
| 10 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 13 | use embedded_hal_1::i2c::Operation; | ||
| 13 | 14 | ||
| 14 | use super::*; | 15 | use super::*; |
| 15 | use crate::dma::Transfer; | 16 | use crate::dma::Transfer; |
| 16 | use crate::pac::i2c; | 17 | use crate::pac::i2c; |
| 17 | use crate::time::Hertz; | ||
| 18 | 18 | ||
| 19 | // /!\ /!\ | 19 | // /!\ /!\ |
| 20 | // /!\ Implementation note! /!\ | 20 | // /!\ Implementation note! /!\ |
| @@ -41,6 +41,68 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 41 | }); | 41 | }); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | /// Frame type in I2C transaction. | ||
| 45 | /// | ||
| 46 | /// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST | ||
| 47 | /// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an | ||
| 48 | /// ACK or NACK after the last byte received. | ||
| 49 | /// | ||
| 50 | /// For write operations, the following options are identical because they differ only in the (N)ACK | ||
| 51 | /// treatment relevant for read operations: | ||
| 52 | /// | ||
| 53 | /// - `FirstFrame` and `FirstAndNextFrame` | ||
| 54 | /// - `NextFrame` and `LastFrameNoStop` | ||
| 55 | /// | ||
| 56 | /// Abbreviations used below: | ||
| 57 | /// | ||
| 58 | /// - `ST` = start condition | ||
| 59 | /// - `SR` = repeated start condition | ||
| 60 | /// - `SP` = stop condition | ||
| 61 | #[derive(Copy, Clone)] | ||
| 62 | enum FrameOptions { | ||
| 63 | /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this | ||
| 64 | /// transaction. | ||
| 65 | FirstAndLastFrame, | ||
| 66 | /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but | ||
| 67 | /// not the last frame overall. | ||
| 68 | FirstFrame, | ||
| 69 | /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last | ||
| 70 | /// frame in a read operation. | ||
| 71 | FirstAndNextFrame, | ||
| 72 | /// `[ACK]` Middle frame in a read operation (neither first nor last). | ||
| 73 | NextFrame, | ||
| 74 | /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. | ||
| 75 | LastFrame, | ||
| 76 | /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. | ||
| 77 | LastFrameNoStop, | ||
| 78 | } | ||
| 79 | |||
| 80 | impl FrameOptions { | ||
| 81 | /// Sends start or repeated start condition before transfer. | ||
| 82 | fn send_start(self) -> bool { | ||
| 83 | match self { | ||
| 84 | Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, | ||
| 85 | Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Sends stop condition after transfer. | ||
| 90 | fn send_stop(self) -> bool { | ||
| 91 | match self { | ||
| 92 | Self::FirstAndLastFrame | Self::LastFrame => true, | ||
| 93 | Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Sends NACK after last byte received, indicating end of read operation. | ||
| 98 | fn send_nack(self) -> bool { | ||
| 99 | match self { | ||
| 100 | Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, | ||
| 101 | Self::FirstAndNextFrame | Self::NextFrame => false, | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 44 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 106 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 107 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 46 | T::regs().cr1().modify(|reg| { | 108 | T::regs().cr1().modify(|reg| { |
| @@ -124,46 +186,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 124 | Ok(sr1) | 186 | Ok(sr1) |
| 125 | } | 187 | } |
| 126 | 188 | ||
| 127 | fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { | 189 | fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { |
| 128 | // Send a START condition | 190 | if frame.send_start() { |
| 191 | // Send a START condition | ||
| 129 | 192 | ||
| 130 | T::regs().cr1().modify(|reg| { | 193 | T::regs().cr1().modify(|reg| { |
| 131 | reg.set_start(true); | 194 | reg.set_start(true); |
| 132 | }); | 195 | }); |
| 133 | 196 | ||
| 134 | // Wait until START condition was generated | 197 | // Wait until START condition was generated |
| 135 | while !Self::check_and_clear_error_flags()?.start() { | 198 | while !Self::check_and_clear_error_flags()?.start() { |
| 136 | timeout.check()?; | 199 | timeout.check()?; |
| 137 | } | 200 | } |
| 138 | 201 | ||
| 139 | // Also wait until signalled we're master and everything is waiting for us | 202 | // Also wait until signalled we're master and everything is waiting for us |
| 140 | while { | 203 | while { |
| 141 | Self::check_and_clear_error_flags()?; | 204 | Self::check_and_clear_error_flags()?; |
| 142 | 205 | ||
| 143 | let sr2 = T::regs().sr2().read(); | 206 | let sr2 = T::regs().sr2().read(); |
| 144 | !sr2.msl() && !sr2.busy() | 207 | !sr2.msl() && !sr2.busy() |
| 145 | } { | 208 | } { |
| 146 | timeout.check()?; | 209 | timeout.check()?; |
| 147 | } | 210 | } |
| 148 | 211 | ||
| 149 | // Set up current address, we're trying to talk to | 212 | // Set up current address, we're trying to talk to |
| 150 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); | 213 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); |
| 151 | 214 | ||
| 152 | // Wait until address was sent | 215 | // Wait until address was sent |
| 153 | // Wait for the address to be acknowledged | 216 | // Wait for the address to be acknowledged |
| 154 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 217 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 155 | while !Self::check_and_clear_error_flags()?.addr() { | 218 | while !Self::check_and_clear_error_flags()?.addr() { |
| 156 | timeout.check()?; | 219 | timeout.check()?; |
| 157 | } | 220 | } |
| 158 | 221 | ||
| 159 | // Clear condition by reading SR2 | 222 | // Clear condition by reading SR2 |
| 160 | let _ = T::regs().sr2().read(); | 223 | let _ = T::regs().sr2().read(); |
| 224 | } | ||
| 161 | 225 | ||
| 162 | // Send bytes | 226 | // Send bytes |
| 163 | for c in bytes { | 227 | for c in bytes { |
| 164 | self.send_byte(*c, timeout)?; | 228 | self.send_byte(*c, timeout)?; |
| 165 | } | 229 | } |
| 166 | 230 | ||
| 231 | if frame.send_stop() { | ||
| 232 | // Send a STOP condition | ||
| 233 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||
| 234 | // Wait for STOP condition to transmit. | ||
| 235 | while T::regs().cr1().read().stop() { | ||
| 236 | timeout.check()?; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 167 | // Fallthrough is success | 240 | // Fallthrough is success |
| 168 | Ok(()) | 241 | Ok(()) |
| 169 | } | 242 | } |
| @@ -205,8 +278,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 205 | Ok(value) | 278 | Ok(value) |
| 206 | } | 279 | } |
| 207 | 280 | ||
| 208 | fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { | 281 | fn blocking_read_timeout( |
| 209 | if let Some((last, buffer)) = buffer.split_last_mut() { | 282 | &mut self, |
| 283 | addr: u8, | ||
| 284 | buffer: &mut [u8], | ||
| 285 | timeout: Timeout, | ||
| 286 | frame: FrameOptions, | ||
| 287 | ) -> Result<(), Error> { | ||
| 288 | let Some((last, buffer)) = buffer.split_last_mut() else { | ||
| 289 | return Err(Error::Overrun); | ||
| 290 | }; | ||
| 291 | |||
| 292 | if frame.send_start() { | ||
| 210 | // Send a START condition and set ACK bit | 293 | // Send a START condition and set ACK bit |
| 211 | T::regs().cr1().modify(|reg| { | 294 | T::regs().cr1().modify(|reg| { |
| 212 | reg.set_start(true); | 295 | reg.set_start(true); |
| @@ -237,49 +320,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 237 | 320 | ||
| 238 | // Clear condition by reading SR2 | 321 | // Clear condition by reading SR2 |
| 239 | let _ = T::regs().sr2().read(); | 322 | let _ = T::regs().sr2().read(); |
| 323 | } | ||
| 240 | 324 | ||
| 241 | // Receive bytes into buffer | 325 | // Receive bytes into buffer |
| 242 | for c in buffer { | 326 | for c in buffer { |
| 243 | *c = self.recv_byte(timeout)?; | 327 | *c = self.recv_byte(timeout)?; |
| 244 | } | 328 | } |
| 245 | 329 | ||
| 246 | // Prepare to send NACK then STOP after next byte | 330 | // Prepare to send NACK then STOP after next byte |
| 247 | T::regs().cr1().modify(|reg| { | 331 | T::regs().cr1().modify(|reg| { |
| 332 | if frame.send_nack() { | ||
| 248 | reg.set_ack(false); | 333 | reg.set_ack(false); |
| 334 | } | ||
| 335 | if frame.send_stop() { | ||
| 249 | reg.set_stop(true); | 336 | reg.set_stop(true); |
| 250 | }); | 337 | } |
| 338 | }); | ||
| 251 | 339 | ||
| 252 | // Receive last byte | 340 | // Receive last byte |
| 253 | *last = self.recv_byte(timeout)?; | 341 | *last = self.recv_byte(timeout)?; |
| 254 | 342 | ||
| 343 | if frame.send_stop() { | ||
| 255 | // Wait for the STOP to be sent. | 344 | // Wait for the STOP to be sent. |
| 256 | while T::regs().cr1().read().stop() { | 345 | while T::regs().cr1().read().stop() { |
| 257 | timeout.check()?; | 346 | timeout.check()?; |
| 258 | } | 347 | } |
| 259 | |||
| 260 | // Fallthrough is success | ||
| 261 | Ok(()) | ||
| 262 | } else { | ||
| 263 | Err(Error::Overrun) | ||
| 264 | } | 348 | } |
| 349 | |||
| 350 | // Fallthrough is success | ||
| 351 | Ok(()) | ||
| 265 | } | 352 | } |
| 266 | 353 | ||
| 267 | /// Blocking read. | 354 | /// Blocking read. |
| 268 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { | 355 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { |
| 269 | self.blocking_read_timeout(addr, read, self.timeout()) | 356 | self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) |
| 270 | } | 357 | } |
| 271 | 358 | ||
| 272 | /// Blocking write. | 359 | /// Blocking write. |
| 273 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { | 360 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { |
| 274 | let timeout = self.timeout(); | 361 | self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; |
| 275 | |||
| 276 | self.write_bytes(addr, write, timeout)?; | ||
| 277 | // Send a STOP condition | ||
| 278 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||
| 279 | // Wait for STOP condition to transmit. | ||
| 280 | while T::regs().cr1().read().stop() { | ||
| 281 | timeout.check()?; | ||
| 282 | } | ||
| 283 | 362 | ||
| 284 | // Fallthrough is success | 363 | // Fallthrough is success |
| 285 | Ok(()) | 364 | Ok(()) |
| @@ -287,10 +366,85 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 287 | 366 | ||
| 288 | /// Blocking write, restart, read. | 367 | /// Blocking write, restart, read. |
| 289 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 368 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 369 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 370 | // stop condition below. | ||
| 371 | if read.is_empty() { | ||
| 372 | return Err(Error::Overrun); | ||
| 373 | } | ||
| 374 | |||
| 290 | let timeout = self.timeout(); | 375 | let timeout = self.timeout(); |
| 291 | 376 | ||
| 292 | self.write_bytes(addr, write, timeout)?; | 377 | self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; |
| 293 | self.blocking_read_timeout(addr, read, timeout)?; | 378 | self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; |
| 379 | |||
| 380 | Ok(()) | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Blocking transaction with operations. | ||
| 384 | /// | ||
| 385 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 386 | /// | ||
| 387 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 388 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 389 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 390 | // stop condition below. | ||
| 391 | if operations.iter().any(|op| match op { | ||
| 392 | Operation::Read(read) => read.is_empty(), | ||
| 393 | Operation::Write(_) => false, | ||
| 394 | }) { | ||
| 395 | return Err(Error::Overrun); | ||
| 396 | } | ||
| 397 | |||
| 398 | let timeout = self.timeout(); | ||
| 399 | |||
| 400 | let mut operations = operations.iter_mut(); | ||
| 401 | |||
| 402 | let mut prev_op: Option<&mut Operation<'_>> = None; | ||
| 403 | let mut next_op = operations.next(); | ||
| 404 | |||
| 405 | while let Some(op) = next_op { | ||
| 406 | next_op = operations.next(); | ||
| 407 | |||
| 408 | // Check if this is the first frame of this type. This is the case for the first overall | ||
| 409 | // frame in the transaction and whenever the type of operation changes. | ||
| 410 | let first_frame = | ||
| 411 | match (prev_op.as_ref(), &op) { | ||
| 412 | (None, _) => true, | ||
| 413 | (Some(Operation::Read(_)), Operation::Write(_)) | ||
| 414 | | (Some(Operation::Write(_)), Operation::Read(_)) => true, | ||
| 415 | (Some(Operation::Read(_)), Operation::Read(_)) | ||
| 416 | | (Some(Operation::Write(_)), Operation::Write(_)) => false, | ||
| 417 | }; | ||
| 418 | |||
| 419 | let frame = match (first_frame, next_op.as_ref()) { | ||
| 420 | // If this is the first frame of this type, we generate a (repeated) start condition | ||
| 421 | // but have to consider the next operation: if it is the last, we generate the final | ||
| 422 | // stop condition. Otherwise, we branch on the operation: with read operations, only | ||
| 423 | // the last byte overall (before a write operation or the end of the transaction) is | ||
| 424 | // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte. | ||
| 425 | (true, None) => FrameOptions::FirstAndLastFrame, | ||
| 426 | // Make sure to keep sending ACK for last byte in read operation when it is followed | ||
| 427 | // by another consecutive read operation. If the current operation is write, this is | ||
| 428 | // identical to `FirstFrame`. | ||
| 429 | (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame, | ||
| 430 | // Otherwise, send NACK for last byte (in read operation). (For write, this does not | ||
| 431 | // matter and could also be `FirstAndNextFrame`.) | ||
| 432 | (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame, | ||
| 433 | |||
| 434 | // If this is not the first frame of its type, we do not generate a (repeated) start | ||
| 435 | // condition. Otherwise, we branch the same way as above. | ||
| 436 | (false, None) => FrameOptions::LastFrame, | ||
| 437 | (false, Some(Operation::Read(_))) => FrameOptions::NextFrame, | ||
| 438 | (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop, | ||
| 439 | }; | ||
| 440 | |||
| 441 | match op { | ||
| 442 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, | ||
| 443 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, | ||
| 444 | } | ||
| 445 | |||
| 446 | prev_op = Some(op); | ||
| 447 | } | ||
| 294 | 448 | ||
| 295 | Ok(()) | 449 | Ok(()) |
| 296 | } | 450 | } |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index bd3abaac1..8baf2849d 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -4,11 +4,11 @@ use core::task::Poll; | |||
| 4 | 4 | ||
| 5 | use embassy_embedded_hal::SetConfig; | 5 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embedded_hal_1::i2c::Operation; | ||
| 7 | 8 | ||
| 8 | use super::*; | 9 | use super::*; |
| 9 | use crate::dma::Transfer; | 10 | use crate::dma::Transfer; |
| 10 | use crate::pac::i2c; | 11 | use crate::pac::i2c; |
| 11 | use crate::time::Hertz; | ||
| 12 | 12 | ||
| 13 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 13 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
| 14 | let regs = T::regs(); | 14 | let regs = T::regs(); |
| @@ -579,6 +579,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 579 | // Automatic Stop | 579 | // Automatic Stop |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | /// Blocking transaction with operations. | ||
| 583 | /// | ||
| 584 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 585 | /// | ||
| 586 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 587 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 588 | let _ = addr; | ||
| 589 | let _ = operations; | ||
| 590 | todo!() | ||
| 591 | } | ||
| 592 | |||
| 582 | /// Blocking write multiple buffers. | 593 | /// Blocking write multiple buffers. |
| 583 | /// | 594 | /// |
| 584 | /// The buffers are concatenated in a single write transaction. | 595 | /// The buffers are concatenated in a single write transaction. |
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index fa9ec0532..c5a606b21 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | //! Inter-IC Sound (I2S) | 1 | //! Inter-IC Sound (I2S) |
| 2 | use embassy_hal_internal::into_ref; | 2 | use embassy_hal_internal::into_ref; |
| 3 | 3 | ||
| 4 | use crate::gpio::sealed::{AFType, Pin as _}; | 4 | use crate::gpio::{AFType, AnyPin, SealedPin}; |
| 5 | use crate::gpio::AnyPin; | ||
| 6 | use crate::pac::spi::vals; | 5 | use crate::pac::spi::vals; |
| 7 | use crate::spi::{Config as SpiConfig, *}; | 6 | use crate::spi::{Config as SpiConfig, *}; |
| 8 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 523719bb9..4d535cce2 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -4,11 +4,12 @@ use core::future::poll_fn; | |||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | use core::task::Poll; | 5 | use core::task::Poll; |
| 6 | 6 | ||
| 7 | use self::sealed::Instance; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | |||
| 8 | use crate::interrupt; | 9 | use crate::interrupt; |
| 9 | use crate::interrupt::typelevel::Interrupt; | 10 | use crate::interrupt::typelevel::Interrupt; |
| 10 | use crate::peripherals::IPCC; | 11 | use crate::peripherals::IPCC; |
| 11 | use crate::rcc::sealed::RccPeripheral; | 12 | use crate::rcc::SealedRccPeripheral; |
| 12 | 13 | ||
| 13 | /// Interrupt handler. | 14 | /// Interrupt handler. |
| 14 | pub struct ReceiveInterruptHandler {} | 15 | pub struct ReceiveInterruptHandler {} |
| @@ -207,7 +208,7 @@ impl Ipcc { | |||
| 207 | } | 208 | } |
| 208 | } | 209 | } |
| 209 | 210 | ||
| 210 | impl sealed::Instance for crate::peripherals::IPCC { | 211 | impl SealedInstance for crate::peripherals::IPCC { |
| 211 | fn regs() -> crate::pac::ipcc::Ipcc { | 212 | fn regs() -> crate::pac::ipcc::Ipcc { |
| 212 | crate::pac::IPCC | 213 | crate::pac::IPCC |
| 213 | } | 214 | } |
| @@ -216,58 +217,52 @@ impl sealed::Instance for crate::peripherals::IPCC { | |||
| 216 | crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)); | 217 | crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)); |
| 217 | } | 218 | } |
| 218 | 219 | ||
| 219 | fn state() -> &'static self::sealed::State { | 220 | fn state() -> &'static State { |
| 220 | static STATE: self::sealed::State = self::sealed::State::new(); | 221 | static STATE: State = State::new(); |
| 221 | &STATE | 222 | &STATE |
| 222 | } | 223 | } |
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | pub(crate) mod sealed { | 226 | struct State { |
| 226 | use embassy_sync::waitqueue::AtomicWaker; | 227 | rx_wakers: [AtomicWaker; 6], |
| 227 | 228 | tx_wakers: [AtomicWaker; 6], | |
| 228 | use super::*; | 229 | } |
| 229 | |||
| 230 | pub struct State { | ||
| 231 | rx_wakers: [AtomicWaker; 6], | ||
| 232 | tx_wakers: [AtomicWaker; 6], | ||
| 233 | } | ||
| 234 | 230 | ||
| 235 | impl State { | 231 | impl State { |
| 236 | pub const fn new() -> Self { | 232 | const fn new() -> Self { |
| 237 | const WAKER: AtomicWaker = AtomicWaker::new(); | 233 | const WAKER: AtomicWaker = AtomicWaker::new(); |
| 238 | 234 | ||
| 239 | Self { | 235 | Self { |
| 240 | rx_wakers: [WAKER; 6], | 236 | rx_wakers: [WAKER; 6], |
| 241 | tx_wakers: [WAKER; 6], | 237 | tx_wakers: [WAKER; 6], |
| 242 | } | ||
| 243 | } | 238 | } |
| 239 | } | ||
| 244 | 240 | ||
| 245 | pub const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { | 241 | const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { |
| 246 | match channel { | 242 | match channel { |
| 247 | IpccChannel::Channel1 => &self.rx_wakers[0], | 243 | IpccChannel::Channel1 => &self.rx_wakers[0], |
| 248 | IpccChannel::Channel2 => &self.rx_wakers[1], | 244 | IpccChannel::Channel2 => &self.rx_wakers[1], |
| 249 | IpccChannel::Channel3 => &self.rx_wakers[2], | 245 | IpccChannel::Channel3 => &self.rx_wakers[2], |
| 250 | IpccChannel::Channel4 => &self.rx_wakers[3], | 246 | IpccChannel::Channel4 => &self.rx_wakers[3], |
| 251 | IpccChannel::Channel5 => &self.rx_wakers[4], | 247 | IpccChannel::Channel5 => &self.rx_wakers[4], |
| 252 | IpccChannel::Channel6 => &self.rx_wakers[5], | 248 | IpccChannel::Channel6 => &self.rx_wakers[5], |
| 253 | } | ||
| 254 | } | 249 | } |
| 250 | } | ||
| 255 | 251 | ||
| 256 | pub const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { | 252 | const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { |
| 257 | match channel { | 253 | match channel { |
| 258 | IpccChannel::Channel1 => &self.tx_wakers[0], | 254 | IpccChannel::Channel1 => &self.tx_wakers[0], |
| 259 | IpccChannel::Channel2 => &self.tx_wakers[1], | 255 | IpccChannel::Channel2 => &self.tx_wakers[1], |
| 260 | IpccChannel::Channel3 => &self.tx_wakers[2], | 256 | IpccChannel::Channel3 => &self.tx_wakers[2], |
| 261 | IpccChannel::Channel4 => &self.tx_wakers[3], | 257 | IpccChannel::Channel4 => &self.tx_wakers[3], |
| 262 | IpccChannel::Channel5 => &self.tx_wakers[4], | 258 | IpccChannel::Channel5 => &self.tx_wakers[4], |
| 263 | IpccChannel::Channel6 => &self.tx_wakers[5], | 259 | IpccChannel::Channel6 => &self.tx_wakers[5], |
| 264 | } | ||
| 265 | } | 260 | } |
| 266 | } | 261 | } |
| 262 | } | ||
| 267 | 263 | ||
| 268 | pub trait Instance: crate::rcc::RccPeripheral { | 264 | trait SealedInstance: crate::rcc::RccPeripheral { |
| 269 | fn regs() -> crate::pac::ipcc::Ipcc; | 265 | fn regs() -> crate::pac::ipcc::Ipcc; |
| 270 | fn set_cpu2(enabled: bool); | 266 | fn set_cpu2(enabled: bool); |
| 271 | fn state() -> &'static State; | 267 | fn state() -> &'static State; |
| 272 | } | ||
| 273 | } | 268 | } |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index aba53ad80..8f510047f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -75,14 +75,14 @@ pub mod sai; | |||
| 75 | pub mod sdmmc; | 75 | pub mod sdmmc; |
| 76 | #[cfg(spi)] | 76 | #[cfg(spi)] |
| 77 | pub mod spi; | 77 | pub mod spi; |
| 78 | #[cfg(ucpd)] | ||
| 79 | pub mod ucpd; | ||
| 78 | #[cfg(uid)] | 80 | #[cfg(uid)] |
| 79 | pub mod uid; | 81 | pub mod uid; |
| 80 | #[cfg(usart)] | 82 | #[cfg(usart)] |
| 81 | pub mod usart; | 83 | pub mod usart; |
| 82 | #[cfg(usb)] | 84 | #[cfg(any(usb, otg))] |
| 83 | pub mod usb; | 85 | pub mod usb; |
| 84 | #[cfg(otg)] | ||
| 85 | pub mod usb_otg; | ||
| 86 | #[cfg(iwdg)] | 86 | #[cfg(iwdg)] |
| 87 | pub mod wdg; | 87 | pub mod wdg; |
| 88 | 88 | ||
| @@ -107,10 +107,10 @@ pub use crate::_generated::interrupt; | |||
| 107 | /// Example of how to bind one interrupt: | 107 | /// Example of how to bind one interrupt: |
| 108 | /// | 108 | /// |
| 109 | /// ```rust,ignore | 109 | /// ```rust,ignore |
| 110 | /// use embassy_stm32::{bind_interrupts, usb_otg, peripherals}; | 110 | /// use embassy_stm32::{bind_interrupts, usb, peripherals}; |
| 111 | /// | 111 | /// |
| 112 | /// bind_interrupts!(struct Irqs { | 112 | /// bind_interrupts!(struct Irqs { |
| 113 | /// OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 113 | /// OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 114 | /// }); | 114 | /// }); |
| 115 | /// ``` | 115 | /// ``` |
| 116 | /// | 116 | /// |
| @@ -160,7 +160,7 @@ pub(crate) use stm32_metapac as pac; | |||
| 160 | use crate::interrupt::Priority; | 160 | use crate::interrupt::Priority; |
| 161 | #[cfg(feature = "rt")] | 161 | #[cfg(feature = "rt")] |
| 162 | pub use crate::pac::NVIC_PRIO_BITS; | 162 | pub use crate::pac::NVIC_PRIO_BITS; |
| 163 | use crate::rcc::sealed::RccPeripheral; | 163 | use crate::rcc::SealedRccPeripheral; |
| 164 | 164 | ||
| 165 | /// `embassy-stm32` global configuration. | 165 | /// `embassy-stm32` global configuration. |
| 166 | #[non_exhaustive] | 166 | #[non_exhaustive] |
| @@ -174,6 +174,14 @@ pub struct Config { | |||
| 174 | #[cfg(dbgmcu)] | 174 | #[cfg(dbgmcu)] |
| 175 | pub enable_debug_during_sleep: bool, | 175 | pub enable_debug_during_sleep: bool, |
| 176 | 176 | ||
| 177 | /// On low-power boards (eg. `stm32l4`, `stm32l5` and `stm32u5`), | ||
| 178 | /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`), | ||
| 179 | /// which needs to be enabled before these pins can be used. | ||
| 180 | /// | ||
| 181 | /// May increase power consumption. Defaults to true. | ||
| 182 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | ||
| 183 | pub enable_independent_io_supply: bool, | ||
| 184 | |||
| 177 | /// BDMA interrupt priority. | 185 | /// BDMA interrupt priority. |
| 178 | /// | 186 | /// |
| 179 | /// Defaults to P0 (highest). | 187 | /// Defaults to P0 (highest). |
| @@ -191,6 +199,18 @@ pub struct Config { | |||
| 191 | /// Defaults to P0 (highest). | 199 | /// Defaults to P0 (highest). |
| 192 | #[cfg(gpdma)] | 200 | #[cfg(gpdma)] |
| 193 | pub gpdma_interrupt_priority: Priority, | 201 | pub gpdma_interrupt_priority: Priority, |
| 202 | |||
| 203 | /// Enables UCPD1 dead battery functionality. | ||
| 204 | /// | ||
| 205 | /// Defaults to false (disabled). | ||
| 206 | #[cfg(peri_ucpd1)] | ||
| 207 | pub enable_ucpd1_dead_battery: bool, | ||
| 208 | |||
| 209 | /// Enables UCPD2 dead battery functionality. | ||
| 210 | /// | ||
| 211 | /// Defaults to false (disabled). | ||
| 212 | #[cfg(peri_ucpd2)] | ||
| 213 | pub enable_ucpd2_dead_battery: bool, | ||
| 194 | } | 214 | } |
| 195 | 215 | ||
| 196 | impl Default for Config { | 216 | impl Default for Config { |
| @@ -199,12 +219,18 @@ impl Default for Config { | |||
| 199 | rcc: Default::default(), | 219 | rcc: Default::default(), |
| 200 | #[cfg(dbgmcu)] | 220 | #[cfg(dbgmcu)] |
| 201 | enable_debug_during_sleep: true, | 221 | enable_debug_during_sleep: true, |
| 222 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | ||
| 223 | enable_independent_io_supply: true, | ||
| 202 | #[cfg(bdma)] | 224 | #[cfg(bdma)] |
| 203 | bdma_interrupt_priority: Priority::P0, | 225 | bdma_interrupt_priority: Priority::P0, |
| 204 | #[cfg(dma)] | 226 | #[cfg(dma)] |
| 205 | dma_interrupt_priority: Priority::P0, | 227 | dma_interrupt_priority: Priority::P0, |
| 206 | #[cfg(gpdma)] | 228 | #[cfg(gpdma)] |
| 207 | gpdma_interrupt_priority: Priority::P0, | 229 | gpdma_interrupt_priority: Priority::P0, |
| 230 | #[cfg(peri_ucpd1)] | ||
| 231 | enable_ucpd1_dead_battery: false, | ||
| 232 | #[cfg(peri_ucpd2)] | ||
| 233 | enable_ucpd2_dead_battery: false, | ||
| 208 | } | 234 | } |
| 209 | } | 235 | } |
| 210 | } | 236 | } |
| @@ -256,7 +282,44 @@ pub fn init(config: Config) -> Peripherals { | |||
| 256 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] | 282 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] |
| 257 | peripherals::FLASH::enable_and_reset_with_cs(cs); | 283 | peripherals::FLASH::enable_and_reset_with_cs(cs); |
| 258 | 284 | ||
| 285 | // Enable the VDDIO2 power supply on chips that have it. | ||
| 286 | // Note that this requires the PWR peripheral to be enabled first. | ||
| 287 | #[cfg(any(stm32l4, stm32l5))] | ||
| 288 | { | ||
| 289 | crate::pac::PWR.cr2().modify(|w| { | ||
| 290 | // The official documentation states that we should ideally enable VDDIO2 | ||
| 291 | // through the PVME2 bit, but it looks like this isn't required, | ||
| 292 | // and CubeMX itself skips this step. | ||
| 293 | w.set_iosv(config.enable_independent_io_supply); | ||
| 294 | }); | ||
| 295 | } | ||
| 296 | #[cfg(stm32u5)] | ||
| 297 | { | ||
| 298 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 299 | w.set_io2sv(config.enable_independent_io_supply); | ||
| 300 | }); | ||
| 301 | } | ||
| 302 | |||
| 303 | // dead battery functionality is still present on these | ||
| 304 | // chips despite them not having UCPD- disable it | ||
| 305 | #[cfg(any(stm32g070, stm32g0b0))] | ||
| 306 | { | ||
| 307 | crate::pac::SYSCFG.cfgr1().modify(|w| { | ||
| 308 | w.set_ucpd1_strobe(true); | ||
| 309 | w.set_ucpd2_strobe(true); | ||
| 310 | }); | ||
| 311 | } | ||
| 312 | |||
| 259 | unsafe { | 313 | unsafe { |
| 314 | #[cfg(ucpd)] | ||
| 315 | ucpd::init( | ||
| 316 | cs, | ||
| 317 | #[cfg(peri_ucpd1)] | ||
| 318 | config.enable_ucpd1_dead_battery, | ||
| 319 | #[cfg(peri_ucpd2)] | ||
| 320 | config.enable_ucpd2_dead_battery, | ||
| 321 | ); | ||
| 322 | |||
| 260 | #[cfg(feature = "_split-pins-enabled")] | 323 | #[cfg(feature = "_split-pins-enabled")] |
| 261 | crate::pac::SYSCFG.pmcr().modify(|pmcr| { | 324 | crate::pac::SYSCFG.pmcr().modify(|pmcr| { |
| 262 | #[cfg(feature = "split-pa0")] | 325 | #[cfg(feature = "split-pa0")] |
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index cf531e266..a3b4352c0 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -81,8 +81,8 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 81 | /// [`OpAmpOutput`] is dropped. | 81 | /// [`OpAmpOutput`] is dropped. |
| 82 | pub fn buffer_ext( | 82 | pub fn buffer_ext( |
| 83 | &'d mut self, | 83 | &'d mut self, |
| 84 | in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, | 84 | in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, |
| 85 | out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::sealed::Pin> + 'd, | 85 | out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd, |
| 86 | gain: OpAmpGain, | 86 | gain: OpAmpGain, |
| 87 | ) -> OpAmpOutput<'d, T> { | 87 | ) -> OpAmpOutput<'d, T> { |
| 88 | into_ref!(in_pin); | 88 | into_ref!(in_pin); |
| @@ -122,7 +122,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 122 | #[cfg(opamp_g4)] | 122 | #[cfg(opamp_g4)] |
| 123 | pub fn buffer_int( | 123 | pub fn buffer_int( |
| 124 | &'d mut self, | 124 | &'d mut self, |
| 125 | pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, | 125 | pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, |
| 126 | gain: OpAmpGain, | 126 | gain: OpAmpGain, |
| 127 | ) -> OpAmpInternalOutput<'d, T> { | 127 | ) -> OpAmpInternalOutput<'d, T> { |
| 128 | into_ref!(pin); | 128 | into_ref!(pin); |
| @@ -166,37 +166,39 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | |||
| 166 | } | 166 | } |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | /// Opamp instance trait. | 169 | pub(crate) trait SealedInstance { |
| 170 | pub trait Instance: sealed::Instance + 'static {} | 170 | fn regs() -> crate::pac::opamp::Opamp; |
| 171 | 171 | } | |
| 172 | pub(crate) mod sealed { | ||
| 173 | pub trait Instance { | ||
| 174 | fn regs() -> crate::pac::opamp::Opamp; | ||
| 175 | } | ||
| 176 | |||
| 177 | pub trait NonInvertingPin<T: Instance> { | ||
| 178 | fn channel(&self) -> u8; | ||
| 179 | } | ||
| 180 | 172 | ||
| 181 | pub trait InvertingPin<T: Instance> { | 173 | pub(crate) trait SealedNonInvertingPin<T: Instance> { |
| 182 | fn channel(&self) -> u8; | 174 | fn channel(&self) -> u8; |
| 183 | } | 175 | } |
| 184 | 176 | ||
| 185 | pub trait OutputPin<T: Instance> {} | 177 | pub(crate) trait SealedInvertingPin<T: Instance> { |
| 178 | #[allow(unused)] | ||
| 179 | fn channel(&self) -> u8; | ||
| 186 | } | 180 | } |
| 187 | 181 | ||
| 182 | pub(crate) trait SealedOutputPin<T: Instance> {} | ||
| 183 | |||
| 184 | /// Opamp instance trait. | ||
| 185 | #[allow(private_bounds)] | ||
| 186 | pub trait Instance: SealedInstance + 'static {} | ||
| 188 | /// Non-inverting pin trait. | 187 | /// Non-inverting pin trait. |
| 189 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} | 188 | #[allow(private_bounds)] |
| 189 | pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {} | ||
| 190 | /// Inverting pin trait. | 190 | /// Inverting pin trait. |
| 191 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} | 191 | #[allow(private_bounds)] |
| 192 | pub trait InvertingPin<T: Instance>: SealedInvertingPin<T> {} | ||
| 192 | /// Output pin trait. | 193 | /// Output pin trait. |
| 193 | pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} | 194 | #[allow(private_bounds)] |
| 195 | pub trait OutputPin<T: Instance>: SealedOutputPin<T> {} | ||
| 194 | 196 | ||
| 195 | macro_rules! impl_opamp_external_output { | 197 | macro_rules! impl_opamp_external_output { |
| 196 | ($inst:ident, $adc:ident, $ch:expr) => { | 198 | ($inst:ident, $adc:ident, $ch:expr) => { |
| 197 | foreach_adc!( | 199 | foreach_adc!( |
| 198 | ($adc, $common_inst:ident, $adc_clock:ident) => { | 200 | ($adc, $common_inst:ident, $adc_clock:ident) => { |
| 199 | impl<'d> crate::adc::sealed::AdcPin<crate::peripherals::$adc> | 201 | impl<'d> crate::adc::SealedAdcPin<crate::peripherals::$adc> |
| 200 | for OpAmpOutput<'d, crate::peripherals::$inst> | 202 | for OpAmpOutput<'d, crate::peripherals::$inst> |
| 201 | { | 203 | { |
| 202 | fn channel(&self) -> u8 { | 204 | fn channel(&self) -> u8 { |
| @@ -242,7 +244,7 @@ macro_rules! impl_opamp_internal_output { | |||
| 242 | ($inst:ident, $adc:ident, $ch:expr) => { | 244 | ($inst:ident, $adc:ident, $ch:expr) => { |
| 243 | foreach_adc!( | 245 | foreach_adc!( |
| 244 | ($adc, $common_inst:ident, $adc_clock:ident) => { | 246 | ($adc, $common_inst:ident, $adc_clock:ident) => { |
| 245 | impl<'d> crate::adc::sealed::AdcPin<crate::peripherals::$adc> | 247 | impl<'d> crate::adc::SealedAdcPin<crate::peripherals::$adc> |
| 246 | for OpAmpInternalOutput<'d, crate::peripherals::$inst> | 248 | for OpAmpInternalOutput<'d, crate::peripherals::$inst> |
| 247 | { | 249 | { |
| 248 | fn channel(&self) -> u8 { | 250 | fn channel(&self) -> u8 { |
| @@ -291,7 +293,7 @@ foreach_peripheral!( | |||
| 291 | 293 | ||
| 292 | foreach_peripheral! { | 294 | foreach_peripheral! { |
| 293 | (opamp, $inst:ident) => { | 295 | (opamp, $inst:ident) => { |
| 294 | impl sealed::Instance for crate::peripherals::$inst { | 296 | impl SealedInstance for crate::peripherals::$inst { |
| 295 | fn regs() -> crate::pac::opamp::Opamp { | 297 | fn regs() -> crate::pac::opamp::Opamp { |
| 296 | crate::pac::$inst | 298 | crate::pac::$inst |
| 297 | } | 299 | } |
| @@ -306,7 +308,7 @@ foreach_peripheral! { | |||
| 306 | macro_rules! impl_opamp_vp_pin { | 308 | macro_rules! impl_opamp_vp_pin { |
| 307 | ($inst:ident, $pin:ident, $ch:expr) => { | 309 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 308 | impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {} | 310 | impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 309 | impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin { | 311 | impl crate::opamp::SealedNonInvertingPin<peripherals::$inst> for crate::peripherals::$pin { |
| 310 | fn channel(&self) -> u8 { | 312 | fn channel(&self) -> u8 { |
| 311 | $ch | 313 | $ch |
| 312 | } | 314 | } |
| @@ -318,6 +320,6 @@ macro_rules! impl_opamp_vp_pin { | |||
| 318 | macro_rules! impl_opamp_vout_pin { | 320 | macro_rules! impl_opamp_vout_pin { |
| 319 | ($inst:ident, $pin:ident) => { | 321 | ($inst:ident, $pin:ident) => { |
| 320 | impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {} | 322 | impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 321 | impl crate::opamp::sealed::OutputPin<peripherals::$inst> for crate::peripherals::$pin {} | 323 | impl crate::opamp::SealedOutputPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 322 | }; | 324 | }; |
| 323 | } | 325 | } |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 8a709a89e..3c054e666 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -8,8 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 8 | use enums::*; | 8 | use enums::*; |
| 9 | 9 | ||
| 10 | use crate::dma::Transfer; | 10 | use crate::dma::Transfer; |
| 11 | use crate::gpio::sealed::AFType; | 11 | use crate::gpio::{AFType, AnyPin, Pull}; |
| 12 | use crate::gpio::{AnyPin, Pull}; | ||
| 13 | use crate::pac::quadspi::Quadspi as Regs; | 12 | use crate::pac::quadspi::Quadspi as Regs; |
| 14 | use crate::rcc::RccPeripheral; | 13 | use crate::rcc::RccPeripheral; |
| 15 | use crate::{peripherals, Peripheral}; | 14 | use crate::{peripherals, Peripheral}; |
| @@ -381,16 +380,13 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 381 | } | 380 | } |
| 382 | } | 381 | } |
| 383 | 382 | ||
| 384 | pub(crate) mod sealed { | 383 | trait SealedInstance { |
| 385 | use super::*; | 384 | const REGS: Regs; |
| 386 | |||
| 387 | pub trait Instance { | ||
| 388 | const REGS: Regs; | ||
| 389 | } | ||
| 390 | } | 385 | } |
| 391 | 386 | ||
| 392 | /// QSPI instance trait. | 387 | /// QSPI instance trait. |
| 393 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 388 | #[allow(private_bounds)] |
| 389 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 394 | 390 | ||
| 395 | pin_trait!(SckPin, Instance); | 391 | pin_trait!(SckPin, Instance); |
| 396 | pin_trait!(BK1D0Pin, Instance); | 392 | pin_trait!(BK1D0Pin, Instance); |
| @@ -409,7 +405,7 @@ dma_trait!(QuadDma, Instance); | |||
| 409 | 405 | ||
| 410 | foreach_peripheral!( | 406 | foreach_peripheral!( |
| 411 | (quadspi, $inst:ident) => { | 407 | (quadspi, $inst:ident) => { |
| 412 | impl sealed::Instance for peripherals::$inst { | 408 | impl SealedInstance for peripherals::$inst { |
| 413 | const REGS: Regs = crate::pac::$inst; | 409 | const REGS: Regs = crate::pac::$inst; |
| 414 | } | 410 | } |
| 415 | 411 | ||
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 39407b28c..54d3c662b 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs | |||
| @@ -24,6 +24,7 @@ pub struct LseConfig { | |||
| 24 | #[allow(dead_code)] | 24 | #[allow(dead_code)] |
| 25 | #[derive(Default, Clone, Copy)] | 25 | #[derive(Default, Clone, Copy)] |
| 26 | pub enum LseDrive { | 26 | pub enum LseDrive { |
| 27 | #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional | ||
| 27 | Low = 0, | 28 | Low = 0, |
| 28 | MediumLow = 0x01, | 29 | MediumLow = 0x01, |
| 29 | #[default] | 30 | #[default] |
| @@ -38,6 +39,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { | |||
| 38 | use crate::pac::rcc::vals::Lsedrv; | 39 | use crate::pac::rcc::vals::Lsedrv; |
| 39 | 40 | ||
| 40 | match value { | 41 | match value { |
| 42 | #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional | ||
| 41 | LseDrive::Low => Lsedrv::LOW, | 43 | LseDrive::Low => Lsedrv::LOW, |
| 42 | LseDrive::MediumLow => Lsedrv::MEDIUMLOW, | 44 | LseDrive::MediumLow => Lsedrv::MEDIUMLOW, |
| 43 | LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, | 45 | LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, |
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index bab8bb19e..1949fc891 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs | |||
| @@ -455,7 +455,14 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 455 | }; | 455 | }; |
| 456 | #[cfg(pwr_h7rm0468)] | 456 | #[cfg(pwr_h7rm0468)] |
| 457 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { | 457 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { |
| 458 | VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)), | 458 | VoltageScale::Scale0 => { |
| 459 | let d1cpre_clk_max = if pac::SYSCFG.ur18().read().cpu_freq_boost() { | ||
| 460 | 550_000_000 | ||
| 461 | } else { | ||
| 462 | 520_000_000 | ||
| 463 | }; | ||
| 464 | (Hertz(d1cpre_clk_max), Hertz(275_000_000), Hertz(137_500_000)) | ||
| 465 | } | ||
| 459 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), | 466 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), |
| 460 | VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), | 467 | VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), |
| 461 | VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), | 468 | VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), |
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index 19a8c8cb9..6f0d7b379 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | use crate::pac::crs::vals::Syncsrc; | 3 | use crate::pac::crs::vals::Syncsrc; |
| 4 | use crate::pac::{CRS, RCC}; | 4 | use crate::pac::{CRS, RCC}; |
| 5 | use crate::rcc::sealed::RccPeripheral; | 5 | use crate::rcc::SealedRccPeripheral; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | 7 | ||
| 8 | /// HSI48 speed | 8 | /// HSI48 speed |
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 654943bc1..d8604e07e 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs | |||
| @@ -2,8 +2,7 @@ use core::marker::PhantomData; | |||
| 2 | 2 | ||
| 3 | use embassy_hal_internal::into_ref; | 3 | use embassy_hal_internal::into_ref; |
| 4 | 4 | ||
| 5 | use crate::gpio::sealed::AFType; | 5 | use crate::gpio::{AFType, Speed}; |
| 6 | use crate::gpio::Speed; | ||
| 7 | #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] | 6 | #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] |
| 8 | pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; | 7 | pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; |
| 9 | #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] | 8 | #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] |
| @@ -19,23 +18,25 @@ pub enum McoPrescaler { | |||
| 19 | DIV1, | 18 | DIV1, |
| 20 | } | 19 | } |
| 21 | 20 | ||
| 22 | pub(crate) mod sealed { | 21 | pub(crate) trait SealedMcoInstance {} |
| 23 | pub trait McoInstance { | ||
| 24 | type Source; | ||
| 25 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | 22 | ||
| 29 | pub trait McoInstance: sealed::McoInstance + 'static {} | 23 | #[allow(private_bounds)] |
| 24 | pub trait McoInstance: SealedMcoInstance + 'static { | ||
| 25 | type Source; | ||
| 26 | |||
| 27 | #[doc(hidden)] | ||
| 28 | unsafe fn _apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); | ||
| 29 | } | ||
| 30 | 30 | ||
| 31 | pin_trait!(McoPin, McoInstance); | 31 | pin_trait!(McoPin, McoInstance); |
| 32 | 32 | ||
| 33 | macro_rules! impl_peri { | 33 | macro_rules! impl_peri { |
| 34 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { | 34 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { |
| 35 | impl sealed::McoInstance for peripherals::$peri { | 35 | impl SealedMcoInstance for peripherals::$peri {} |
| 36 | impl McoInstance for peripherals::$peri { | ||
| 36 | type Source = $source; | 37 | type Source = $source; |
| 37 | 38 | ||
| 38 | unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { | 39 | unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { |
| 39 | #[cfg(not(any(stm32u5, stm32wba)))] | 40 | #[cfg(not(any(stm32u5, stm32wba)))] |
| 40 | let r = RCC.cfgr(); | 41 | let r = RCC.cfgr(); |
| 41 | #[cfg(any(stm32u5, stm32wba))] | 42 | #[cfg(any(stm32u5, stm32wba))] |
| @@ -48,8 +49,6 @@ macro_rules! impl_peri { | |||
| 48 | }); | 49 | }); |
| 49 | } | 50 | } |
| 50 | } | 51 | } |
| 51 | |||
| 52 | impl McoInstance for peripherals::$peri {} | ||
| 53 | }; | 52 | }; |
| 54 | } | 53 | } |
| 55 | 54 | ||
| @@ -79,7 +78,7 @@ impl<'d, T: McoInstance> Mco<'d, T> { | |||
| 79 | into_ref!(pin); | 78 | into_ref!(pin); |
| 80 | 79 | ||
| 81 | critical_section::with(|_| unsafe { | 80 | critical_section::with(|_| unsafe { |
| 82 | T::apply_clock_settings(source, prescaler); | 81 | T::_apply_clock_settings(source, prescaler); |
| 83 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | 82 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); |
| 84 | pin.set_speed(Speed::VeryHigh); | 83 | pin.set_speed(Speed::VeryHigh); |
| 85 | }); | 84 | }); |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 910ebe205..d53d02203 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -10,6 +10,7 @@ pub use bd::*; | |||
| 10 | 10 | ||
| 11 | #[cfg(any(mco, mco1, mco2))] | 11 | #[cfg(any(mco, mco1, mco2))] |
| 12 | mod mco; | 12 | mod mco; |
| 13 | use critical_section::CriticalSection; | ||
| 13 | #[cfg(any(mco, mco1, mco2))] | 14 | #[cfg(any(mco, mco1, mco2))] |
| 14 | pub use mco::*; | 15 | pub use mco::*; |
| 15 | 16 | ||
| @@ -32,6 +33,7 @@ mod _version; | |||
| 32 | pub use _version::*; | 33 | pub use _version::*; |
| 33 | 34 | ||
| 34 | pub use crate::_generated::{mux, Clocks}; | 35 | pub use crate::_generated::{mux, Clocks}; |
| 36 | use crate::time::Hertz; | ||
| 35 | 37 | ||
| 36 | #[cfg(feature = "low-power")] | 38 | #[cfg(feature = "low-power")] |
| 37 | /// Must be written within a critical section | 39 | /// Must be written within a critical section |
| @@ -63,29 +65,21 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { | |||
| 63 | CLOCK_FREQS.assume_init_ref() | 65 | CLOCK_FREQS.assume_init_ref() |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | #[cfg(feature = "unstable-pac")] | 68 | pub(crate) trait SealedRccPeripheral { |
| 67 | pub mod low_level { | 69 | fn frequency() -> crate::time::Hertz; |
| 68 | pub use super::sealed::*; | 70 | fn enable_and_reset_with_cs(cs: CriticalSection); |
| 69 | } | 71 | fn disable_with_cs(cs: CriticalSection); |
| 70 | |||
| 71 | pub(crate) mod sealed { | ||
| 72 | use critical_section::CriticalSection; | ||
| 73 | |||
| 74 | pub trait RccPeripheral { | ||
| 75 | fn frequency() -> crate::time::Hertz; | ||
| 76 | fn enable_and_reset_with_cs(cs: CriticalSection); | ||
| 77 | fn disable_with_cs(cs: CriticalSection); | ||
| 78 | 72 | ||
| 79 | fn enable_and_reset() { | 73 | fn enable_and_reset() { |
| 80 | critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) | 74 | critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) |
| 81 | } | 75 | } |
| 82 | fn disable() { | 76 | fn disable() { |
| 83 | critical_section::with(|cs| Self::disable_with_cs(cs)) | 77 | critical_section::with(|cs| Self::disable_with_cs(cs)) |
| 84 | } | ||
| 85 | } | 78 | } |
| 86 | } | 79 | } |
| 87 | 80 | ||
| 88 | pub trait RccPeripheral: sealed::RccPeripheral + 'static {} | 81 | #[allow(private_bounds)] |
| 82 | pub trait RccPeripheral: SealedRccPeripheral + 'static {} | ||
| 89 | 83 | ||
| 90 | #[allow(unused)] | 84 | #[allow(unused)] |
| 91 | mod util { | 85 | mod util { |
| @@ -116,3 +110,12 @@ mod util { | |||
| 116 | Ok(Some(x)) | 110 | Ok(Some(x)) |
| 117 | } | 111 | } |
| 118 | } | 112 | } |
| 113 | |||
| 114 | /// Get the kernel clocok frequency of the peripheral `T`. | ||
| 115 | /// | ||
| 116 | /// # Panics | ||
| 117 | /// | ||
| 118 | /// Panics if the clock is not active. | ||
| 119 | pub fn frequency<T: RccPeripheral>() -> Hertz { | ||
| 120 | T::frequency() | ||
| 121 | } | ||
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index ca641f352..7a228e4a4 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -222,16 +222,13 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> { | |||
| 222 | 222 | ||
| 223 | impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} | 223 | impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} |
| 224 | 224 | ||
| 225 | pub(crate) mod sealed { | 225 | trait SealedInstance { |
| 226 | use super::*; | 226 | fn regs() -> pac::rng::Rng; |
| 227 | |||
| 228 | pub trait Instance { | ||
| 229 | fn regs() -> pac::rng::Rng; | ||
| 230 | } | ||
| 231 | } | 227 | } |
| 232 | 228 | ||
| 233 | /// RNG instance trait. | 229 | /// RNG instance trait. |
| 234 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | 230 | #[allow(private_bounds)] |
| 231 | pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | ||
| 235 | /// Interrupt for this RNG instance. | 232 | /// Interrupt for this RNG instance. |
| 236 | type Interrupt: interrupt::typelevel::Interrupt; | 233 | type Interrupt: interrupt::typelevel::Interrupt; |
| 237 | } | 234 | } |
| @@ -242,7 +239,7 @@ foreach_interrupt!( | |||
| 242 | type Interrupt = crate::interrupt::typelevel::$irq; | 239 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 243 | } | 240 | } |
| 244 | 241 | ||
| 245 | impl sealed::Instance for peripherals::$inst { | 242 | impl SealedInstance for peripherals::$inst { |
| 246 | fn regs() -> crate::pac::rng::Rng { | 243 | fn regs() -> crate::pac::rng::Rng { |
| 247 | crate::pac::$inst | 244 | crate::pac::$inst |
| 248 | } | 245 | } |
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index ef92fa4bb..bab8cf4a3 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs | |||
| @@ -1,13 +1,10 @@ | |||
| 1 | #[cfg(feature = "chrono")] | 1 | #[cfg(feature = "chrono")] |
| 2 | use core::convert::From; | 2 | use chrono::{Datelike, NaiveDate, Timelike, Weekday}; |
| 3 | |||
| 4 | #[cfg(feature = "chrono")] | ||
| 5 | use chrono::{self, Datelike, NaiveDate, Timelike, Weekday}; | ||
| 6 | 3 | ||
| 7 | #[cfg(any(feature = "defmt", feature = "time"))] | 4 | #[cfg(any(feature = "defmt", feature = "time"))] |
| 8 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 9 | #[cfg(any(feature = "defmt", feature = "time"))] | 6 | #[cfg(any(feature = "defmt", feature = "time"))] |
| 10 | use crate::rtc::sealed::Instance; | 7 | use crate::rtc::SealedInstance; |
| 11 | 8 | ||
| 12 | /// Represents an instant in time that can be substracted to compute a duration | 9 | /// Represents an instant in time that can be substracted to compute a duration |
| 13 | pub struct RtcInstant { | 10 | pub struct RtcInstant { |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 169505501..00abe9356 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -31,7 +31,6 @@ pub use _version::*; | |||
| 31 | use embassy_hal_internal::Peripheral; | 31 | use embassy_hal_internal::Peripheral; |
| 32 | 32 | ||
| 33 | use crate::peripherals::RTC; | 33 | use crate::peripherals::RTC; |
| 34 | use crate::rtc::sealed::Instance; | ||
| 35 | 34 | ||
| 36 | #[allow(dead_code)] | 35 | #[allow(dead_code)] |
| 37 | #[repr(u8)] | 36 | #[repr(u8)] |
| @@ -212,7 +211,7 @@ impl Rtc { | |||
| 212 | /// Create a new RTC instance. | 211 | /// Create a new RTC instance. |
| 213 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { | 212 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { |
| 214 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] | 213 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] |
| 215 | <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); | 214 | <RTC as crate::rcc::SealedRccPeripheral>::enable_and_reset(); |
| 216 | 215 | ||
| 217 | let mut this = Self { | 216 | let mut this = Self { |
| 218 | #[cfg(feature = "low-power")] | 217 | #[cfg(feature = "low-power")] |
| @@ -437,7 +436,7 @@ impl Rtc { | |||
| 437 | .fpr(0) | 436 | .fpr(0) |
| 438 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | 437 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 439 | 438 | ||
| 440 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); | 439 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); |
| 441 | }); | 440 | }); |
| 442 | } | 441 | } |
| 443 | 442 | ||
| @@ -449,8 +448,8 @@ impl Rtc { | |||
| 449 | use crate::interrupt::typelevel::Interrupt; | 448 | use crate::interrupt::typelevel::Interrupt; |
| 450 | use crate::pac::EXTI; | 449 | use crate::pac::EXTI; |
| 451 | 450 | ||
| 452 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); | 451 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); |
| 453 | unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() }; | 452 | unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; |
| 454 | 453 | ||
| 455 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | 454 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 456 | EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | 455 | EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| @@ -477,34 +476,30 @@ pub(crate) fn bcd2_to_byte(bcd: (u8, u8)) -> u8 { | |||
| 477 | tmp + (value & 0x0F) | 476 | tmp + (value & 0x0F) |
| 478 | } | 477 | } |
| 479 | 478 | ||
| 480 | pub(crate) mod sealed { | 479 | trait SealedInstance { |
| 481 | use crate::pac::rtc::Rtc; | 480 | const BACKUP_REGISTER_COUNT: usize; |
| 482 | 481 | ||
| 483 | pub trait Instance { | 482 | #[cfg(feature = "low-power")] |
| 484 | const BACKUP_REGISTER_COUNT: usize; | 483 | const EXTI_WAKEUP_LINE: usize; |
| 485 | |||
| 486 | #[cfg(feature = "low-power")] | ||
| 487 | const EXTI_WAKEUP_LINE: usize; | ||
| 488 | 484 | ||
| 489 | #[cfg(feature = "low-power")] | 485 | #[cfg(feature = "low-power")] |
| 490 | type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; | 486 | type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; |
| 491 | 487 | ||
| 492 | fn regs() -> Rtc { | 488 | fn regs() -> crate::pac::rtc::Rtc { |
| 493 | crate::pac::RTC | 489 | crate::pac::RTC |
| 494 | } | 490 | } |
| 495 | 491 | ||
| 496 | /// Read content of the backup register. | 492 | /// Read content of the backup register. |
| 497 | /// | 493 | /// |
| 498 | /// The registers retain their values during wakes from standby mode or system resets. They also | 494 | /// The registers retain their values during wakes from standby mode or system resets. They also |
| 499 | /// retain their value when Vdd is switched off as long as V_BAT is powered. | 495 | /// retain their value when Vdd is switched off as long as V_BAT is powered. |
| 500 | fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32>; | 496 | fn read_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize) -> Option<u32>; |
| 501 | 497 | ||
| 502 | /// Set content of the backup register. | 498 | /// Set content of the backup register. |
| 503 | /// | 499 | /// |
| 504 | /// The registers retain their values during wakes from standby mode or system resets. They also | 500 | /// The registers retain their values during wakes from standby mode or system resets. They also |
| 505 | /// retain their value when Vdd is switched off as long as V_BAT is powered. | 501 | /// retain their value when Vdd is switched off as long as V_BAT is powered. |
| 506 | fn write_backup_register(rtc: &Rtc, register: usize, value: u32); | 502 | fn write_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize, value: u32); |
| 507 | 503 | ||
| 508 | // fn apply_config(&mut self, rtc_config: RtcConfig); | 504 | // fn apply_config(&mut self, rtc_config: RtcConfig); |
| 509 | } | ||
| 510 | } | 505 | } |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1eda097a7..92f9de846 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Osel, Pol}; | 1 | use stm32_metapac::rtc::vals::{Osel, Pol}; |
| 2 | 2 | ||
| 3 | use super::sealed; | 3 | use super::SealedInstance; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| 5 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 6 | use crate::rtc::sealed::Instance; | ||
| 7 | 6 | ||
| 8 | #[allow(dead_code)] | 7 | #[allow(dead_code)] |
| 9 | impl super::Rtc { | 8 | impl super::Rtc { |
| @@ -126,7 +125,7 @@ impl super::Rtc { | |||
| 126 | } | 125 | } |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | impl sealed::Instance for crate::peripherals::RTC { | 128 | impl SealedInstance for crate::peripherals::RTC { |
| 130 | const BACKUP_REGISTER_COUNT: usize = 20; | 129 | const BACKUP_REGISTER_COUNT: usize = 20; |
| 131 | 130 | ||
| 132 | #[cfg(all(feature = "low-power", stm32f4))] | 131 | #[cfg(all(feature = "low-power", stm32f4))] |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 3d44a52ff..8a78d16e1 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; | 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; |
| 2 | 2 | ||
| 3 | use super::{sealed, RtcCalibrationCyclePeriod}; | 3 | use super::RtcCalibrationCyclePeriod; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| 5 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 6 | use crate::rtc::sealed::Instance; | 6 | use crate::rtc::SealedInstance; |
| 7 | 7 | ||
| 8 | impl super::Rtc { | 8 | impl super::Rtc { |
| 9 | /// Applies the RTC config | 9 | /// Applies the RTC config |
| @@ -126,7 +126,7 @@ impl super::Rtc { | |||
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | impl sealed::Instance for crate::peripherals::RTC { | 129 | impl SealedInstance for crate::peripherals::RTC { |
| 130 | const BACKUP_REGISTER_COUNT: usize = 32; | 130 | const BACKUP_REGISTER_COUNT: usize = 32; |
| 131 | 131 | ||
| 132 | #[cfg(all(feature = "low-power", stm32g4))] | 132 | #[cfg(all(feature = "low-power", stm32g4))] |
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 02f96f8a9..54dd81524 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs | |||
| @@ -6,12 +6,10 @@ use core::marker::PhantomData; | |||
| 6 | 6 | ||
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | 8 | ||
| 9 | use self::sealed::WhichSubBlock; | ||
| 10 | pub use crate::dma::word; | 9 | pub use crate::dma::word; |
| 11 | #[cfg(not(gpdma))] | 10 | #[cfg(not(gpdma))] |
| 12 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | 11 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; |
| 13 | use crate::gpio::sealed::{AFType, Pin as _}; | 12 | use crate::gpio::{AFType, AnyPin, SealedPin as _}; |
| 14 | use crate::gpio::AnyPin; | ||
| 15 | use crate::pac::sai::{vals, Sai as Regs}; | 13 | use crate::pac::sai::{vals, Sai as Regs}; |
| 16 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 17 | use crate::{peripherals, Peripheral}; | 15 | use crate::{peripherals, Peripheral}; |
| @@ -386,6 +384,7 @@ impl OutputDrive { | |||
| 386 | /// Master clock divider. | 384 | /// Master clock divider. |
| 387 | #[derive(Copy, Clone, PartialEq)] | 385 | #[derive(Copy, Clone, PartialEq)] |
| 388 | #[allow(missing_docs)] | 386 | #[allow(missing_docs)] |
| 387 | #[cfg(any(sai_v1, sai_v2))] | ||
| 389 | pub enum MasterClockDivider { | 388 | pub enum MasterClockDivider { |
| 390 | MasterClockDisabled, | 389 | MasterClockDisabled, |
| 391 | Div1, | 390 | Div1, |
| @@ -406,8 +405,79 @@ pub enum MasterClockDivider { | |||
| 406 | Div30, | 405 | Div30, |
| 407 | } | 406 | } |
| 408 | 407 | ||
| 408 | /// Master clock divider. | ||
| 409 | #[derive(Copy, Clone, PartialEq)] | ||
| 410 | #[allow(missing_docs)] | ||
| 411 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 412 | pub enum MasterClockDivider { | ||
| 413 | MasterClockDisabled, | ||
| 414 | Div1, | ||
| 415 | Div2, | ||
| 416 | Div3, | ||
| 417 | Div4, | ||
| 418 | Div5, | ||
| 419 | Div6, | ||
| 420 | Div7, | ||
| 421 | Div8, | ||
| 422 | Div9, | ||
| 423 | Div10, | ||
| 424 | Div11, | ||
| 425 | Div12, | ||
| 426 | Div13, | ||
| 427 | Div14, | ||
| 428 | Div15, | ||
| 429 | Div16, | ||
| 430 | Div17, | ||
| 431 | Div18, | ||
| 432 | Div19, | ||
| 433 | Div20, | ||
| 434 | Div21, | ||
| 435 | Div22, | ||
| 436 | Div23, | ||
| 437 | Div24, | ||
| 438 | Div25, | ||
| 439 | Div26, | ||
| 440 | Div27, | ||
| 441 | Div28, | ||
| 442 | Div29, | ||
| 443 | Div30, | ||
| 444 | Div31, | ||
| 445 | Div32, | ||
| 446 | Div33, | ||
| 447 | Div34, | ||
| 448 | Div35, | ||
| 449 | Div36, | ||
| 450 | Div37, | ||
| 451 | Div38, | ||
| 452 | Div39, | ||
| 453 | Div40, | ||
| 454 | Div41, | ||
| 455 | Div42, | ||
| 456 | Div43, | ||
| 457 | Div44, | ||
| 458 | Div45, | ||
| 459 | Div46, | ||
| 460 | Div47, | ||
| 461 | Div48, | ||
| 462 | Div49, | ||
| 463 | Div50, | ||
| 464 | Div51, | ||
| 465 | Div52, | ||
| 466 | Div53, | ||
| 467 | Div54, | ||
| 468 | Div55, | ||
| 469 | Div56, | ||
| 470 | Div57, | ||
| 471 | Div58, | ||
| 472 | Div59, | ||
| 473 | Div60, | ||
| 474 | Div61, | ||
| 475 | Div62, | ||
| 476 | Div63, | ||
| 477 | } | ||
| 478 | |||
| 409 | impl MasterClockDivider { | 479 | impl MasterClockDivider { |
| 410 | #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 480 | #[cfg(any(sai_v1, sai_v2))] |
| 411 | const fn mckdiv(&self) -> u8 { | 481 | const fn mckdiv(&self) -> u8 { |
| 412 | match self { | 482 | match self { |
| 413 | MasterClockDivider::MasterClockDisabled => 0, | 483 | MasterClockDivider::MasterClockDisabled => 0, |
| @@ -429,6 +499,76 @@ impl MasterClockDivider { | |||
| 429 | MasterClockDivider::Div30 => 15, | 499 | MasterClockDivider::Div30 => 15, |
| 430 | } | 500 | } |
| 431 | } | 501 | } |
| 502 | |||
| 503 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 504 | const fn mckdiv(&self) -> u8 { | ||
| 505 | match self { | ||
| 506 | MasterClockDivider::MasterClockDisabled => 0, | ||
| 507 | MasterClockDivider::Div1 => 1, | ||
| 508 | MasterClockDivider::Div2 => 2, | ||
| 509 | MasterClockDivider::Div3 => 3, | ||
| 510 | MasterClockDivider::Div4 => 4, | ||
| 511 | MasterClockDivider::Div5 => 5, | ||
| 512 | MasterClockDivider::Div6 => 6, | ||
| 513 | MasterClockDivider::Div7 => 7, | ||
| 514 | MasterClockDivider::Div8 => 8, | ||
| 515 | MasterClockDivider::Div9 => 9, | ||
| 516 | MasterClockDivider::Div10 => 10, | ||
| 517 | MasterClockDivider::Div11 => 11, | ||
| 518 | MasterClockDivider::Div12 => 12, | ||
| 519 | MasterClockDivider::Div13 => 13, | ||
| 520 | MasterClockDivider::Div14 => 14, | ||
| 521 | MasterClockDivider::Div15 => 15, | ||
| 522 | MasterClockDivider::Div16 => 16, | ||
| 523 | MasterClockDivider::Div17 => 17, | ||
| 524 | MasterClockDivider::Div18 => 18, | ||
| 525 | MasterClockDivider::Div19 => 19, | ||
| 526 | MasterClockDivider::Div20 => 20, | ||
| 527 | MasterClockDivider::Div21 => 21, | ||
| 528 | MasterClockDivider::Div22 => 22, | ||
| 529 | MasterClockDivider::Div23 => 23, | ||
| 530 | MasterClockDivider::Div24 => 24, | ||
| 531 | MasterClockDivider::Div25 => 25, | ||
| 532 | MasterClockDivider::Div26 => 26, | ||
| 533 | MasterClockDivider::Div27 => 27, | ||
| 534 | MasterClockDivider::Div28 => 28, | ||
| 535 | MasterClockDivider::Div29 => 29, | ||
| 536 | MasterClockDivider::Div30 => 30, | ||
| 537 | MasterClockDivider::Div31 => 31, | ||
| 538 | MasterClockDivider::Div32 => 32, | ||
| 539 | MasterClockDivider::Div33 => 33, | ||
| 540 | MasterClockDivider::Div34 => 34, | ||
| 541 | MasterClockDivider::Div35 => 35, | ||
| 542 | MasterClockDivider::Div36 => 36, | ||
| 543 | MasterClockDivider::Div37 => 37, | ||
| 544 | MasterClockDivider::Div38 => 38, | ||
| 545 | MasterClockDivider::Div39 => 39, | ||
| 546 | MasterClockDivider::Div40 => 40, | ||
| 547 | MasterClockDivider::Div41 => 41, | ||
| 548 | MasterClockDivider::Div42 => 42, | ||
| 549 | MasterClockDivider::Div43 => 43, | ||
| 550 | MasterClockDivider::Div44 => 44, | ||
| 551 | MasterClockDivider::Div45 => 45, | ||
| 552 | MasterClockDivider::Div46 => 46, | ||
| 553 | MasterClockDivider::Div47 => 47, | ||
| 554 | MasterClockDivider::Div48 => 48, | ||
| 555 | MasterClockDivider::Div49 => 49, | ||
| 556 | MasterClockDivider::Div50 => 50, | ||
| 557 | MasterClockDivider::Div51 => 51, | ||
| 558 | MasterClockDivider::Div52 => 52, | ||
| 559 | MasterClockDivider::Div53 => 53, | ||
| 560 | MasterClockDivider::Div54 => 54, | ||
| 561 | MasterClockDivider::Div55 => 55, | ||
| 562 | MasterClockDivider::Div56 => 56, | ||
| 563 | MasterClockDivider::Div57 => 57, | ||
| 564 | MasterClockDivider::Div58 => 58, | ||
| 565 | MasterClockDivider::Div59 => 59, | ||
| 566 | MasterClockDivider::Div60 => 60, | ||
| 567 | MasterClockDivider::Div61 => 61, | ||
| 568 | MasterClockDivider::Div62 => 62, | ||
| 569 | MasterClockDivider::Div63 => 63, | ||
| 570 | } | ||
| 571 | } | ||
| 432 | } | 572 | } |
| 433 | 573 | ||
| 434 | /// [`SAI`] configuration. | 574 | /// [`SAI`] configuration. |
| @@ -899,43 +1039,42 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> { | |||
| 899 | } | 1039 | } |
| 900 | } | 1040 | } |
| 901 | 1041 | ||
| 902 | pub(crate) mod sealed { | 1042 | trait SealedInstance { |
| 903 | use super::*; | 1043 | const REGS: Regs; |
| 904 | 1044 | } | |
| 905 | pub trait Instance { | ||
| 906 | const REGS: Regs; | ||
| 907 | } | ||
| 908 | 1045 | ||
| 909 | #[derive(Copy, Clone)] | 1046 | #[derive(Copy, Clone)] |
| 910 | pub enum WhichSubBlock { | 1047 | enum WhichSubBlock { |
| 911 | A = 0, | 1048 | A = 0, |
| 912 | B = 1, | 1049 | B = 1, |
| 913 | } | 1050 | } |
| 914 | 1051 | ||
| 915 | pub trait SubBlock { | 1052 | trait SealedSubBlock { |
| 916 | const WHICH: WhichSubBlock; | 1053 | const WHICH: WhichSubBlock; |
| 917 | } | ||
| 918 | } | 1054 | } |
| 919 | 1055 | ||
| 920 | /// Sub-block instance trait. | 1056 | /// Sub-block instance trait. |
| 921 | pub trait SubBlockInstance: sealed::SubBlock {} | 1057 | #[allow(private_bounds)] |
| 1058 | pub trait SubBlockInstance: SealedSubBlock {} | ||
| 922 | 1059 | ||
| 923 | /// Sub-block A. | 1060 | /// Sub-block A. |
| 924 | pub enum A {} | 1061 | pub enum A {} |
| 925 | impl sealed::SubBlock for A { | 1062 | impl SealedSubBlock for A { |
| 926 | const WHICH: WhichSubBlock = WhichSubBlock::A; | 1063 | const WHICH: WhichSubBlock = WhichSubBlock::A; |
| 927 | } | 1064 | } |
| 928 | impl SubBlockInstance for A {} | 1065 | impl SubBlockInstance for A {} |
| 929 | 1066 | ||
| 930 | /// Sub-block B. | 1067 | /// Sub-block B. |
| 931 | pub enum B {} | 1068 | pub enum B {} |
| 932 | impl sealed::SubBlock for B { | 1069 | impl SealedSubBlock for B { |
| 933 | const WHICH: WhichSubBlock = WhichSubBlock::B; | 1070 | const WHICH: WhichSubBlock = WhichSubBlock::B; |
| 934 | } | 1071 | } |
| 935 | impl SubBlockInstance for B {} | 1072 | impl SubBlockInstance for B {} |
| 936 | 1073 | ||
| 937 | /// SAI instance trait. | 1074 | /// SAI instance trait. |
| 938 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 1075 | #[allow(private_bounds)] |
| 1076 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 1077 | |||
| 939 | pin_trait!(SckPin, Instance, SubBlockInstance); | 1078 | pin_trait!(SckPin, Instance, SubBlockInstance); |
| 940 | pin_trait!(FsPin, Instance, SubBlockInstance); | 1079 | pin_trait!(FsPin, Instance, SubBlockInstance); |
| 941 | pin_trait!(SdPin, Instance, SubBlockInstance); | 1080 | pin_trait!(SdPin, Instance, SubBlockInstance); |
| @@ -945,7 +1084,7 @@ dma_trait!(Dma, Instance, SubBlockInstance); | |||
| 945 | 1084 | ||
| 946 | foreach_peripheral!( | 1085 | foreach_peripheral!( |
| 947 | (sai, $inst:ident) => { | 1086 | (sai, $inst:ident) => { |
| 948 | impl sealed::Instance for peripherals::$inst { | 1087 | impl SealedInstance for peripherals::$inst { |
| 949 | const REGS: Regs = crate::pac::$inst; | 1088 | const REGS: Regs = crate::pac::$inst; |
| 950 | } | 1089 | } |
| 951 | 1090 | ||
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index bf1d2ca9b..f79a11606 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -13,8 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 13 | use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; | 13 | use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; |
| 14 | 14 | ||
| 15 | use crate::dma::NoDma; | 15 | use crate::dma::NoDma; |
| 16 | use crate::gpio::sealed::{AFType, Pin}; | 16 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; |
| 17 | use crate::gpio::{AnyPin, Pull, Speed}; | ||
| 18 | use crate::interrupt::typelevel::Interrupt; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 18 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 20 | use crate::rcc::RccPeripheral; | 19 | use crate::rcc::RccPeripheral; |
| @@ -240,12 +239,14 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp | |||
| 240 | mburst: crate::dma::Burst::Incr4, | 239 | mburst: crate::dma::Burst::Incr4, |
| 241 | flow_ctrl: crate::dma::FlowControl::Peripheral, | 240 | flow_ctrl: crate::dma::FlowControl::Peripheral, |
| 242 | fifo_threshold: Some(crate::dma::FifoThreshold::Full), | 241 | fifo_threshold: Some(crate::dma::FifoThreshold::Full), |
| 242 | priority: crate::dma::Priority::VeryHigh, | ||
| 243 | circular: false, | 243 | circular: false, |
| 244 | half_transfer_ir: false, | 244 | half_transfer_ir: false, |
| 245 | complete_transfer_ir: true, | 245 | complete_transfer_ir: true, |
| 246 | }; | 246 | }; |
| 247 | #[cfg(all(sdmmc_v1, not(dma)))] | 247 | #[cfg(all(sdmmc_v1, not(dma)))] |
| 248 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { | 248 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { |
| 249 | priority: crate::dma::Priority::VeryHigh, | ||
| 249 | circular: false, | 250 | circular: false, |
| 250 | half_transfer_ir: false, | 251 | half_transfer_ir: false, |
| 251 | complete_transfer_ir: true, | 252 | complete_transfer_ir: true, |
| @@ -1416,21 +1417,17 @@ impl Cmd { | |||
| 1416 | 1417 | ||
| 1417 | ////////////////////////////////////////////////////// | 1418 | ////////////////////////////////////////////////////// |
| 1418 | 1419 | ||
| 1419 | pub(crate) mod sealed { | 1420 | trait SealedInstance { |
| 1420 | use super::*; | 1421 | fn regs() -> RegBlock; |
| 1421 | 1422 | fn state() -> &'static AtomicWaker; | |
| 1422 | pub trait Instance { | ||
| 1423 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1424 | |||
| 1425 | fn regs() -> RegBlock; | ||
| 1426 | fn state() -> &'static AtomicWaker; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | pub trait Pins<T: Instance> {} | ||
| 1430 | } | 1423 | } |
| 1431 | 1424 | ||
| 1432 | /// SDMMC instance trait. | 1425 | /// SDMMC instance trait. |
| 1433 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 1426 | #[allow(private_bounds)] |
| 1427 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 1428 | /// Interrupt for this instance. | ||
| 1429 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1430 | } | ||
| 1434 | 1431 | ||
| 1435 | pin_trait!(CkPin, Instance); | 1432 | pin_trait!(CkPin, Instance); |
| 1436 | pin_trait!(CmdPin, Instance); | 1433 | pin_trait!(CmdPin, Instance); |
| @@ -1457,9 +1454,7 @@ impl<T: Instance> SdmmcDma<T> for NoDma {} | |||
| 1457 | 1454 | ||
| 1458 | foreach_peripheral!( | 1455 | foreach_peripheral!( |
| 1459 | (sdmmc, $inst:ident) => { | 1456 | (sdmmc, $inst:ident) => { |
| 1460 | impl sealed::Instance for peripherals::$inst { | 1457 | impl SealedInstance for peripherals::$inst { |
| 1461 | type Interrupt = crate::interrupt::typelevel::$inst; | ||
| 1462 | |||
| 1463 | fn regs() -> RegBlock { | 1458 | fn regs() -> RegBlock { |
| 1464 | crate::pac::$inst | 1459 | crate::pac::$inst |
| 1465 | } | 1460 | } |
| @@ -1470,6 +1465,8 @@ foreach_peripheral!( | |||
| 1470 | } | 1465 | } |
| 1471 | } | 1466 | } |
| 1472 | 1467 | ||
| 1473 | impl Instance for peripherals::$inst {} | 1468 | impl Instance for peripherals::$inst { |
| 1469 | type Interrupt = crate::interrupt::typelevel::$inst; | ||
| 1470 | } | ||
| 1474 | }; | 1471 | }; |
| 1475 | ); | 1472 | ); |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 172bc8112..0b38c4288 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -9,8 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 9 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 9 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 10 | 10 | ||
| 11 | use crate::dma::{slice_ptr_parts, word, Transfer}; | 11 | use crate::dma::{slice_ptr_parts, word, Transfer}; |
| 12 | use crate::gpio::sealed::{AFType, Pin as _}; | 12 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; |
| 13 | use crate::gpio::{AnyPin, Pull}; | ||
| 14 | use crate::pac::spi::{regs, vals, Spi as Regs}; | 13 | use crate::pac::spi::{regs, vals, Spi as Regs}; |
| 15 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 16 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| @@ -210,7 +209,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 210 | // see RM0453 rev 1 section 7.2.13 page 291 | 209 | // see RM0453 rev 1 section 7.2.13 page 291 |
| 211 | // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. | 210 | // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. |
| 212 | // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. | 211 | // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. |
| 213 | let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::sealed::RccPeripheral>::frequency().0; | 212 | let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0; |
| 214 | let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); | 213 | let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); |
| 215 | let mut config = Config::default(); | 214 | let mut config = Config::default(); |
| 216 | config.mode = MODE_0; | 215 | config.mode = MODE_0; |
| @@ -271,13 +270,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 271 | if mosi.is_none() { | 270 | if mosi.is_none() { |
| 272 | w.set_rxonly(vals::Rxonly::OUTPUTDISABLED); | 271 | w.set_rxonly(vals::Rxonly::OUTPUTDISABLED); |
| 273 | } | 272 | } |
| 274 | w.set_dff(<u8 as sealed::Word>::CONFIG) | 273 | w.set_dff(<u8 as SealedWord>::CONFIG) |
| 275 | }); | 274 | }); |
| 276 | } | 275 | } |
| 277 | #[cfg(spi_v2)] | 276 | #[cfg(spi_v2)] |
| 278 | { | 277 | { |
| 279 | T::REGS.cr2().modify(|w| { | 278 | T::REGS.cr2().modify(|w| { |
| 280 | let (ds, frxth) = <u8 as sealed::Word>::CONFIG; | 279 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; |
| 281 | w.set_frxth(frxth); | 280 | w.set_frxth(frxth); |
| 282 | w.set_ds(ds); | 281 | w.set_ds(ds); |
| 283 | w.set_ssoe(false); | 282 | w.set_ssoe(false); |
| @@ -317,7 +316,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 317 | T::REGS.cfg1().modify(|w| { | 316 | T::REGS.cfg1().modify(|w| { |
| 318 | w.set_crcen(false); | 317 | w.set_crcen(false); |
| 319 | w.set_mbr(br); | 318 | w.set_mbr(br); |
| 320 | w.set_dsize(<u8 as sealed::Word>::CONFIG); | 319 | w.set_dsize(<u8 as SealedWord>::CONFIG); |
| 321 | w.set_fthlv(vals::Fthlv::ONEFRAME); | 320 | w.set_fthlv(vals::Fthlv::ONEFRAME); |
| 322 | }); | 321 | }); |
| 323 | T::REGS.cr2().modify(|w| { | 322 | T::REGS.cr2().modify(|w| { |
| @@ -336,7 +335,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 336 | miso, | 335 | miso, |
| 337 | txdma, | 336 | txdma, |
| 338 | rxdma, | 337 | rxdma, |
| 339 | current_word_size: <u8 as sealed::Word>::CONFIG, | 338 | current_word_size: <u8 as SealedWord>::CONFIG, |
| 340 | } | 339 | } |
| 341 | } | 340 | } |
| 342 | 341 | ||
| @@ -700,7 +699,7 @@ use vals::Mbr as Br; | |||
| 700 | 699 | ||
| 701 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { | 700 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { |
| 702 | let val = match clocks.0 / freq.0 { | 701 | let val = match clocks.0 / freq.0 { |
| 703 | 0 => unreachable!(), | 702 | 0 => panic!("You are trying to reach a frequency higher than the clock"), |
| 704 | 1..=2 => 0b000, | 703 | 1..=2 => 0b000, |
| 705 | 3..=5 => 0b001, | 704 | 3..=5 => 0b001, |
| 706 | 6..=11 => 0b010, | 705 | 6..=11 => 0b010, |
| @@ -975,24 +974,21 @@ impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::s | |||
| 975 | } | 974 | } |
| 976 | } | 975 | } |
| 977 | 976 | ||
| 978 | pub(crate) mod sealed { | 977 | pub(crate) trait SealedInstance { |
| 979 | use super::*; | 978 | const REGS: Regs; |
| 980 | 979 | } | |
| 981 | pub trait Instance { | ||
| 982 | const REGS: Regs; | ||
| 983 | } | ||
| 984 | 980 | ||
| 985 | pub trait Word { | 981 | trait SealedWord { |
| 986 | const CONFIG: word_impl::Config; | 982 | const CONFIG: word_impl::Config; |
| 987 | } | ||
| 988 | } | 983 | } |
| 989 | 984 | ||
| 990 | /// Word sizes usable for SPI. | 985 | /// Word sizes usable for SPI. |
| 991 | pub trait Word: word::Word + sealed::Word {} | 986 | #[allow(private_bounds)] |
| 987 | pub trait Word: word::Word + SealedWord {} | ||
| 992 | 988 | ||
| 993 | macro_rules! impl_word { | 989 | macro_rules! impl_word { |
| 994 | ($T:ty, $config:expr) => { | 990 | ($T:ty, $config:expr) => { |
| 995 | impl sealed::Word for $T { | 991 | impl SealedWord for $T { |
| 996 | const CONFIG: Config = $config; | 992 | const CONFIG: Config = $config; |
| 997 | } | 993 | } |
| 998 | impl Word for $T {} | 994 | impl Word for $T {} |
| @@ -1068,7 +1064,8 @@ mod word_impl { | |||
| 1068 | } | 1064 | } |
| 1069 | 1065 | ||
| 1070 | /// SPI instance trait. | 1066 | /// SPI instance trait. |
| 1071 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 1067 | #[allow(private_bounds)] |
| 1068 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 1072 | 1069 | ||
| 1073 | pin_trait!(SckPin, Instance); | 1070 | pin_trait!(SckPin, Instance); |
| 1074 | pin_trait!(MosiPin, Instance); | 1071 | pin_trait!(MosiPin, Instance); |
| @@ -1082,7 +1079,7 @@ dma_trait!(TxDma, Instance); | |||
| 1082 | 1079 | ||
| 1083 | foreach_peripheral!( | 1080 | foreach_peripheral!( |
| 1084 | (spi, $inst:ident) => { | 1081 | (spi, $inst:ident) => { |
| 1085 | impl sealed::Instance for peripherals::$inst { | 1082 | impl SealedInstance for peripherals::$inst { |
| 1086 | const REGS: Regs = crate::pac::$inst; | 1083 | const REGS: Regs = crate::pac::$inst; |
| 1087 | } | 1084 | } |
| 1088 | 1085 | ||
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 37b2e7526..cc8161276 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | #![allow(non_snake_case)] | 1 | #![allow(non_snake_case)] |
| 2 | 2 | ||
| 3 | use core::cell::Cell; | 3 | use core::cell::Cell; |
| 4 | use core::convert::TryInto; | ||
| 5 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; |
| 6 | use core::{mem, ptr}; | 5 | use core::{mem, ptr}; |
| 7 | 6 | ||
| @@ -9,16 +8,16 @@ use critical_section::CriticalSection; | |||
| 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 10 | use embassy_sync::blocking_mutex::Mutex; | 9 | use embassy_sync::blocking_mutex::Mutex; |
| 11 | use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; | 10 | use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; |
| 12 | use stm32_metapac::timer::regs; | 11 | use stm32_metapac::timer::{regs, TimGp16}; |
| 13 | 12 | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::pac::timer::vals; | 14 | use crate::pac::timer::vals; |
| 16 | use crate::rcc::sealed::RccPeripheral; | 15 | use crate::rcc::SealedRccPeripheral; |
| 17 | #[cfg(feature = "low-power")] | 16 | #[cfg(feature = "low-power")] |
| 18 | use crate::rtc::Rtc; | 17 | use crate::rtc::Rtc; |
| 19 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] | 18 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] |
| 20 | use crate::timer::sealed::AdvancedControlInstance; | 19 | use crate::timer::AdvancedInstance1Channel; |
| 21 | use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; | 20 | use crate::timer::CoreInstance; |
| 22 | use crate::{interrupt, peripherals}; | 21 | use crate::{interrupt, peripherals}; |
| 23 | 22 | ||
| 24 | // NOTE regarding ALARM_COUNT: | 23 | // NOTE regarding ALARM_COUNT: |
| @@ -208,6 +207,10 @@ foreach_interrupt! { | |||
| 208 | }; | 207 | }; |
| 209 | } | 208 | } |
| 210 | 209 | ||
| 210 | fn regs_gp16() -> TimGp16 { | ||
| 211 | unsafe { TimGp16::from_ptr(T::regs()) } | ||
| 212 | } | ||
| 213 | |||
| 211 | // Clock timekeeping works with something we call "periods", which are time intervals | 214 | // Clock timekeeping works with something we call "periods", which are time intervals |
| 212 | // of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. | 215 | // of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. |
| 213 | // | 216 | // |
| @@ -272,9 +275,9 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 272 | 275 | ||
| 273 | impl RtcDriver { | 276 | impl RtcDriver { |
| 274 | fn init(&'static self, cs: critical_section::CriticalSection) { | 277 | fn init(&'static self, cs: critical_section::CriticalSection) { |
| 275 | let r = T::regs_gp16(); | 278 | let r = regs_gp16(); |
| 276 | 279 | ||
| 277 | <T as RccPeripheral>::enable_and_reset_with_cs(cs); | 280 | <T as SealedRccPeripheral>::enable_and_reset_with_cs(cs); |
| 278 | 281 | ||
| 279 | let timer_freq = T::frequency(); | 282 | let timer_freq = T::frequency(); |
| 280 | 283 | ||
| @@ -287,7 +290,7 @@ impl RtcDriver { | |||
| 287 | Ok(n) => n, | 290 | Ok(n) => n, |
| 288 | }; | 291 | }; |
| 289 | 292 | ||
| 290 | r.psc().write(|w| w.set_psc(psc)); | 293 | r.psc().write_value(psc); |
| 291 | r.arr().write(|w| w.set_arr(u16::MAX)); | 294 | r.arr().write(|w| w.set_arr(u16::MAX)); |
| 292 | 295 | ||
| 293 | // Set URS, generate update and clear URS | 296 | // Set URS, generate update and clear URS |
| @@ -309,9 +312,9 @@ impl RtcDriver { | |||
| 309 | 312 | ||
| 310 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] | 313 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] |
| 311 | { | 314 | { |
| 312 | <T as AdvancedControlInstance>::CaptureCompareInterrupt::unpend(); | 315 | <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::unpend(); |
| 313 | unsafe { | 316 | unsafe { |
| 314 | <T as AdvancedControlInstance>::CaptureCompareInterrupt::enable(); | 317 | <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::enable(); |
| 315 | } | 318 | } |
| 316 | } | 319 | } |
| 317 | 320 | ||
| @@ -319,7 +322,7 @@ impl RtcDriver { | |||
| 319 | } | 322 | } |
| 320 | 323 | ||
| 321 | fn on_interrupt(&self) { | 324 | fn on_interrupt(&self) { |
| 322 | let r = T::regs_gp16(); | 325 | let r = regs_gp16(); |
| 323 | 326 | ||
| 324 | // XXX: reduce the size of this critical section ? | 327 | // XXX: reduce the size of this critical section ? |
| 325 | critical_section::with(|cs| { | 328 | critical_section::with(|cs| { |
| @@ -350,7 +353,7 @@ impl RtcDriver { | |||
| 350 | } | 353 | } |
| 351 | 354 | ||
| 352 | fn next_period(&self) { | 355 | fn next_period(&self) { |
| 353 | let r = T::regs_gp16(); | 356 | let r = regs_gp16(); |
| 354 | 357 | ||
| 355 | // We only modify the period from the timer interrupt, so we know this can't race. | 358 | // We only modify the period from the timer interrupt, so we know this can't race. |
| 356 | let period = self.period.load(Ordering::Relaxed) + 1; | 359 | let period = self.period.load(Ordering::Relaxed) + 1; |
| @@ -414,7 +417,7 @@ impl RtcDriver { | |||
| 414 | /// Add the given offset to the current time | 417 | /// Add the given offset to the current time |
| 415 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { | 418 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { |
| 416 | let offset = offset.as_ticks(); | 419 | let offset = offset.as_ticks(); |
| 417 | let cnt = T::regs_gp16().cnt().read().cnt() as u32; | 420 | let cnt = regs_gp16().cnt().read().cnt() as u32; |
| 418 | let period = self.period.load(Ordering::SeqCst); | 421 | let period = self.period.load(Ordering::SeqCst); |
| 419 | 422 | ||
| 420 | // Correct the race, if it exists | 423 | // Correct the race, if it exists |
| @@ -440,7 +443,7 @@ impl RtcDriver { | |||
| 440 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; | 443 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; |
| 441 | 444 | ||
| 442 | self.period.store(period, Ordering::SeqCst); | 445 | self.period.store(period, Ordering::SeqCst); |
| 443 | T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | 446 | regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); |
| 444 | 447 | ||
| 445 | // Now, recompute all alarms | 448 | // Now, recompute all alarms |
| 446 | for i in 0..ALARM_COUNT { | 449 | for i in 0..ALARM_COUNT { |
| @@ -497,7 +500,7 @@ impl RtcDriver { | |||
| 497 | .unwrap() | 500 | .unwrap() |
| 498 | .start_wakeup_alarm(time_until_next_alarm, cs); | 501 | .start_wakeup_alarm(time_until_next_alarm, cs); |
| 499 | 502 | ||
| 500 | T::regs_gp16().cr1().modify(|w| w.set_cen(false)); | 503 | regs_gp16().cr1().modify(|w| w.set_cen(false)); |
| 501 | 504 | ||
| 502 | Ok(()) | 505 | Ok(()) |
| 503 | } | 506 | } |
| @@ -507,7 +510,7 @@ impl RtcDriver { | |||
| 507 | #[cfg(feature = "low-power")] | 510 | #[cfg(feature = "low-power")] |
| 508 | /// Resume the timer with the given offset | 511 | /// Resume the timer with the given offset |
| 509 | pub(crate) fn resume_time(&self) { | 512 | pub(crate) fn resume_time(&self) { |
| 510 | if T::regs_gp16().cr1().read().cen() { | 513 | if regs_gp16().cr1().read().cen() { |
| 511 | // Time isn't currently stopped | 514 | // Time isn't currently stopped |
| 512 | 515 | ||
| 513 | return; | 516 | return; |
| @@ -516,14 +519,14 @@ impl RtcDriver { | |||
| 516 | critical_section::with(|cs| { | 519 | critical_section::with(|cs| { |
| 517 | self.stop_wakeup_alarm(cs); | 520 | self.stop_wakeup_alarm(cs); |
| 518 | 521 | ||
| 519 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | 522 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 520 | }) | 523 | }) |
| 521 | } | 524 | } |
| 522 | } | 525 | } |
| 523 | 526 | ||
| 524 | impl Driver for RtcDriver { | 527 | impl Driver for RtcDriver { |
| 525 | fn now(&self) -> u64 { | 528 | fn now(&self) -> u64 { |
| 526 | let r = T::regs_gp16(); | 529 | let r = regs_gp16(); |
| 527 | 530 | ||
| 528 | let period = self.period.load(Ordering::Relaxed); | 531 | let period = self.period.load(Ordering::Relaxed); |
| 529 | compiler_fence(Ordering::Acquire); | 532 | compiler_fence(Ordering::Acquire); |
| @@ -554,7 +557,7 @@ impl Driver for RtcDriver { | |||
| 554 | 557 | ||
| 555 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { | 558 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 556 | critical_section::with(|cs| { | 559 | critical_section::with(|cs| { |
| 557 | let r = T::regs_gp16(); | 560 | let r = regs_gp16(); |
| 558 | 561 | ||
| 559 | let n = alarm.id() as usize; | 562 | let n = alarm.id() as usize; |
| 560 | let alarm = self.get_alarm(cs, alarm); | 563 | let alarm = self.get_alarm(cs, alarm); |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 72f1ec864..a892646cf 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -5,12 +5,15 @@ use core::marker::PhantomData; | |||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | use stm32_metapac::timer::vals::Ckd; | 6 | use stm32_metapac::timer::vals::Ckd; |
| 7 | 7 | ||
| 8 | use super::simple_pwm::*; | 8 | use super::low_level::{CountingMode, OutputPolarity, Timer}; |
| 9 | use super::*; | 9 | use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; |
| 10 | #[allow(unused_imports)] | 10 | use super::{ |
| 11 | use crate::gpio::sealed::{AFType, Pin}; | 11 | AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin, |
| 12 | Channel4ComplementaryPin, | ||
| 13 | }; | ||
| 12 | use crate::gpio::{AnyPin, OutputType}; | 14 | use crate::gpio::{AnyPin, OutputType}; |
| 13 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| 16 | use crate::timer::low_level::OutputCompareMode; | ||
| 14 | use crate::Peripheral; | 17 | use crate::Peripheral; |
| 15 | 18 | ||
| 16 | /// Complementary PWM pin wrapper. | 19 | /// Complementary PWM pin wrapper. |
| @@ -23,7 +26,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { | |||
| 23 | 26 | ||
| 24 | macro_rules! complementary_channel_impl { | 27 | macro_rules! complementary_channel_impl { |
| 25 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 28 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 26 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { | 29 | impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { |
| 27 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] | 30 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 28 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | 31 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { |
| 29 | into_ref!(pin); | 32 | into_ref!(pin); |
| @@ -48,11 +51,11 @@ complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | |||
| 48 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | 51 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); |
| 49 | 52 | ||
| 50 | /// PWM driver with support for standard and complementary outputs. | 53 | /// PWM driver with support for standard and complementary outputs. |
| 51 | pub struct ComplementaryPwm<'d, T> { | 54 | pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { |
| 52 | inner: PeripheralRef<'d, T>, | 55 | inner: Timer<'d, T>, |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | 58 | impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { |
| 56 | /// Create a new complementary PWM driver. | 59 | /// Create a new complementary PWM driver. |
| 57 | #[allow(clippy::too_many_arguments)] | 60 | #[allow(clippy::too_many_arguments)] |
| 58 | pub fn new( | 61 | pub fn new( |
| @@ -72,11 +75,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 72 | } | 75 | } |
| 73 | 76 | ||
| 74 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { | 77 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { |
| 75 | into_ref!(tim); | 78 | let mut this = Self { inner: Timer::new(tim) }; |
| 76 | |||
| 77 | T::enable_and_reset(); | ||
| 78 | |||
| 79 | let mut this = Self { inner: tim }; | ||
| 80 | 79 | ||
| 81 | this.inner.set_counting_mode(counting_mode); | 80 | this.inner.set_counting_mode(counting_mode); |
| 82 | this.set_frequency(freq); | 81 | this.set_frequency(freq); |
| @@ -123,7 +122,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 123 | /// | 122 | /// |
| 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 123 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 125 | pub fn get_max_duty(&self) -> u16 { | 124 | pub fn get_max_duty(&self) -> u16 { |
| 126 | self.inner.get_max_compare_value() + 1 | 125 | self.inner.get_max_compare_value() as u16 + 1 |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | /// Set the duty for a given channel. | 128 | /// Set the duty for a given channel. |
| @@ -131,7 +130,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 130 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 132 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 131 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 133 | assert!(duty <= self.get_max_duty()); | 132 | assert!(duty <= self.get_max_duty()); |
| 134 | self.inner.set_compare_value(channel, duty) | 133 | self.inner.set_compare_value(channel, duty as _) |
| 135 | } | 134 | } |
| 136 | 135 | ||
| 137 | /// Set the output polarity for a given channel. | 136 | /// Set the output polarity for a given channel. |
| @@ -149,7 +148,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 149 | } | 148 | } |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { | 151 | impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { |
| 153 | type Channel = Channel; | 152 | type Channel = Channel; |
| 154 | type Time = Hertz; | 153 | type Time = Hertz; |
| 155 | type Duty = u16; | 154 | type Duty = u16; |
| @@ -169,16 +168,16 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C | |||
| 169 | } | 168 | } |
| 170 | 169 | ||
| 171 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { | 170 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { |
| 172 | self.inner.get_compare_value(channel) | 171 | self.inner.get_compare_value(channel) as u16 |
| 173 | } | 172 | } |
| 174 | 173 | ||
| 175 | fn get_max_duty(&self) -> Self::Duty { | 174 | fn get_max_duty(&self) -> Self::Duty { |
| 176 | self.inner.get_max_compare_value() + 1 | 175 | self.inner.get_max_compare_value() as u16 + 1 |
| 177 | } | 176 | } |
| 178 | 177 | ||
| 179 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 178 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
| 180 | assert!(duty <= self.get_max_duty()); | 179 | assert!(duty <= self.get_max_duty()); |
| 181 | self.inner.set_compare_value(channel, duty) | 180 | self.inner.set_compare_value(channel, duty as u32) |
| 182 | } | 181 | } |
| 183 | 182 | ||
| 184 | fn set_period<P>(&mut self, period: P) | 183 | fn set_period<P>(&mut self, period: P) |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs new file mode 100644 index 000000000..a5d942314 --- /dev/null +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -0,0 +1,638 @@ | |||
| 1 | //! Low-level timer driver. | ||
| 2 | //! | ||
| 3 | //! This is an unopinionated, very low-level driver for all STM32 timers. It allows direct register | ||
| 4 | //! manipulation with the `regs_*()` methods, and has utility functions that are thin wrappers | ||
| 5 | //! over the registers. | ||
| 6 | //! | ||
| 7 | //! The available functionality depends on the timer type. | ||
| 8 | |||
| 9 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 10 | |||
| 11 | use super::*; | ||
| 12 | use crate::pac::timer::vals; | ||
| 13 | use crate::time::Hertz; | ||
| 14 | |||
| 15 | /// Input capture mode. | ||
| 16 | #[derive(Clone, Copy)] | ||
| 17 | pub enum InputCaptureMode { | ||
| 18 | /// Rising edge only. | ||
| 19 | Rising, | ||
| 20 | /// Falling edge only. | ||
| 21 | Falling, | ||
| 22 | /// Both rising or falling edges. | ||
| 23 | BothEdges, | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Input TI selection. | ||
| 27 | #[derive(Clone, Copy)] | ||
| 28 | pub enum InputTISelection { | ||
| 29 | /// Normal | ||
| 30 | Normal, | ||
| 31 | /// Alternate | ||
| 32 | Alternate, | ||
| 33 | /// TRC | ||
| 34 | TRC, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | ||
| 38 | fn from(tisel: InputTISelection) -> Self { | ||
| 39 | match tisel { | ||
| 40 | InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, | ||
| 41 | InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, | ||
| 42 | InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Timer counting mode. | ||
| 48 | #[repr(u8)] | ||
| 49 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
| 50 | pub enum CountingMode { | ||
| 51 | #[default] | ||
| 52 | /// The timer counts up to the reload value and then resets back to 0. | ||
| 53 | EdgeAlignedUp, | ||
| 54 | /// The timer counts down to 0 and then resets back to the reload value. | ||
| 55 | EdgeAlignedDown, | ||
| 56 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 57 | /// | ||
| 58 | /// The output compare interrupt flags of channels configured in output are | ||
| 59 | /// set when the counter is counting down. | ||
| 60 | CenterAlignedDownInterrupts, | ||
| 61 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 62 | /// | ||
| 63 | /// The output compare interrupt flags of channels configured in output are | ||
| 64 | /// set when the counter is counting up. | ||
| 65 | CenterAlignedUpInterrupts, | ||
| 66 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 67 | /// | ||
| 68 | /// The output compare interrupt flags of channels configured in output are | ||
| 69 | /// set when the counter is counting both up or down. | ||
| 70 | CenterAlignedBothInterrupts, | ||
| 71 | } | ||
| 72 | |||
| 73 | impl CountingMode { | ||
| 74 | /// Return whether this mode is edge-aligned (up or down). | ||
| 75 | pub fn is_edge_aligned(&self) -> bool { | ||
| 76 | matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Return whether this mode is center-aligned. | ||
| 80 | pub fn is_center_aligned(&self) -> bool { | ||
| 81 | matches!( | ||
| 82 | self, | ||
| 83 | CountingMode::CenterAlignedDownInterrupts | ||
| 84 | | CountingMode::CenterAlignedUpInterrupts | ||
| 85 | | CountingMode::CenterAlignedBothInterrupts | ||
| 86 | ) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | impl From<CountingMode> for (vals::Cms, vals::Dir) { | ||
| 91 | fn from(value: CountingMode) -> Self { | ||
| 92 | match value { | ||
| 93 | CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), | ||
| 94 | CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), | ||
| 95 | CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), | ||
| 96 | CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), | ||
| 97 | CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | impl From<(vals::Cms, vals::Dir)> for CountingMode { | ||
| 103 | fn from(value: (vals::Cms, vals::Dir)) -> Self { | ||
| 104 | match value { | ||
| 105 | (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, | ||
| 106 | (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, | ||
| 107 | (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, | ||
| 108 | (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, | ||
| 109 | (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Output compare mode. | ||
| 115 | #[derive(Clone, Copy)] | ||
| 116 | pub enum OutputCompareMode { | ||
| 117 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 118 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 119 | /// (this mode is used to generate a timing base). | ||
| 120 | Frozen, | ||
| 121 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 122 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 123 | ActiveOnMatch, | ||
| 124 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 125 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 126 | InactiveOnMatch, | ||
| 127 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 128 | Toggle, | ||
| 129 | /// Force inactive level - OCxREF is forced low. | ||
| 130 | ForceInactive, | ||
| 131 | /// Force active level - OCxREF is forced high. | ||
| 132 | ForceActive, | ||
| 133 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 134 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 135 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 136 | PwmMode1, | ||
| 137 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 138 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 139 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 140 | PwmMode2, | ||
| 141 | // TODO: there's more modes here depending on the chip family. | ||
| 142 | } | ||
| 143 | |||
| 144 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | ||
| 145 | fn from(mode: OutputCompareMode) -> Self { | ||
| 146 | match mode { | ||
| 147 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | ||
| 148 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, | ||
| 149 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, | ||
| 150 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | ||
| 151 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, | ||
| 152 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, | ||
| 153 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, | ||
| 154 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Timer output pin polarity. | ||
| 160 | #[derive(Clone, Copy)] | ||
| 161 | pub enum OutputPolarity { | ||
| 162 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 163 | ActiveHigh, | ||
| 164 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 165 | ActiveLow, | ||
| 166 | } | ||
| 167 | |||
| 168 | impl From<OutputPolarity> for bool { | ||
| 169 | fn from(mode: OutputPolarity) -> Self { | ||
| 170 | match mode { | ||
| 171 | OutputPolarity::ActiveHigh => false, | ||
| 172 | OutputPolarity::ActiveLow => true, | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Low-level timer driver. | ||
| 178 | pub struct Timer<'d, T: CoreInstance> { | ||
| 179 | tim: PeripheralRef<'d, T>, | ||
| 180 | } | ||
| 181 | |||
| 182 | impl<'d, T: CoreInstance> Drop for Timer<'d, T> { | ||
| 183 | fn drop(&mut self) { | ||
| 184 | T::disable() | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | impl<'d, T: CoreInstance> Timer<'d, T> { | ||
| 189 | /// Create a new timer driver. | ||
| 190 | pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self { | ||
| 191 | into_ref!(tim); | ||
| 192 | |||
| 193 | T::enable_and_reset(); | ||
| 194 | |||
| 195 | Self { tim } | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Get access to the virutal core 16bit timer registers. | ||
| 199 | /// | ||
| 200 | /// Note: This works even if the timer is more capable, because registers | ||
| 201 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 202 | /// for a given set of capabilities, and having it transparently work with | ||
| 203 | /// more capable timers. | ||
| 204 | pub fn regs_core(&self) -> crate::pac::timer::TimCore { | ||
| 205 | unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) } | ||
| 206 | } | ||
| 207 | |||
| 208 | #[cfg(not(stm32l0))] | ||
| 209 | fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 { | ||
| 210 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Start the timer. | ||
| 214 | pub fn start(&self) { | ||
| 215 | self.regs_core().cr1().modify(|r| r.set_cen(true)); | ||
| 216 | } | ||
| 217 | |||
| 218 | /// Stop the timer. | ||
| 219 | pub fn stop(&self) { | ||
| 220 | self.regs_core().cr1().modify(|r| r.set_cen(false)); | ||
| 221 | } | ||
| 222 | |||
| 223 | /// Reset the counter value to 0 | ||
| 224 | pub fn reset(&self) { | ||
| 225 | self.regs_core().cnt().write(|r| r.set_cnt(0)); | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. | ||
| 229 | /// | ||
| 230 | /// This means that in the default edge-aligned mode, | ||
| 231 | /// the timer counter will wrap around at the same frequency as is being set. | ||
| 232 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | ||
| 233 | /// because it needs to count up and down. | ||
| 234 | pub fn set_frequency(&self, frequency: Hertz) { | ||
| 235 | let f = frequency.0; | ||
| 236 | assert!(f > 0); | ||
| 237 | let timer_f = T::frequency().0; | ||
| 238 | |||
| 239 | match T::BITS { | ||
| 240 | TimerBits::Bits16 => { | ||
| 241 | let pclk_ticks_per_timer_period = timer_f / f; | ||
| 242 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); | ||
| 243 | let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); | ||
| 244 | |||
| 245 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 246 | let arr = unwrap!(u16::try_from(divide_by - 1)); | ||
| 247 | |||
| 248 | let regs = self.regs_core(); | ||
| 249 | regs.psc().write_value(psc); | ||
| 250 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 251 | |||
| 252 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 253 | regs.egr().write(|r| r.set_ug(true)); | ||
| 254 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 255 | } | ||
| 256 | #[cfg(not(stm32l0))] | ||
| 257 | TimerBits::Bits32 => { | ||
| 258 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; | ||
| 259 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); | ||
| 260 | let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); | ||
| 261 | |||
| 262 | let regs = self.regs_gp32_unchecked(); | ||
| 263 | regs.psc().write_value(psc); | ||
| 264 | regs.arr().write_value(arr); | ||
| 265 | |||
| 266 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 267 | regs.egr().write(|r| r.set_ug(true)); | ||
| 268 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Clear update interrupt. | ||
| 274 | /// | ||
| 275 | /// Returns whether the update interrupt flag was set. | ||
| 276 | pub fn clear_update_interrupt(&self) -> bool { | ||
| 277 | let regs = self.regs_core(); | ||
| 278 | let sr = regs.sr().read(); | ||
| 279 | if sr.uif() { | ||
| 280 | regs.sr().modify(|r| { | ||
| 281 | r.set_uif(false); | ||
| 282 | }); | ||
| 283 | true | ||
| 284 | } else { | ||
| 285 | false | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Enable/disable the update interrupt. | ||
| 290 | pub fn enable_update_interrupt(&self, enable: bool) { | ||
| 291 | self.regs_core().dier().modify(|r| r.set_uie(enable)); | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Enable/disable autoreload preload. | ||
| 295 | pub fn set_autoreload_preload(&self, enable: bool) { | ||
| 296 | self.regs_core().cr1().modify(|r| r.set_arpe(enable)); | ||
| 297 | } | ||
| 298 | |||
| 299 | /// Get the timer frequency. | ||
| 300 | pub fn get_frequency(&self) -> Hertz { | ||
| 301 | let timer_f = T::frequency(); | ||
| 302 | |||
| 303 | match T::BITS { | ||
| 304 | TimerBits::Bits16 => { | ||
| 305 | let regs = self.regs_core(); | ||
| 306 | let arr = regs.arr().read().arr(); | ||
| 307 | let psc = regs.psc().read(); | ||
| 308 | |||
| 309 | timer_f / arr / (psc + 1) | ||
| 310 | } | ||
| 311 | #[cfg(not(stm32l0))] | ||
| 312 | TimerBits::Bits32 => { | ||
| 313 | let regs = self.regs_gp32_unchecked(); | ||
| 314 | let arr = regs.arr().read(); | ||
| 315 | let psc = regs.psc().read(); | ||
| 316 | |||
| 317 | timer_f / arr / (psc + 1) | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | impl<'d, T: BasicNoCr2Instance> Timer<'d, T> { | ||
| 324 | /// Get access to the Baisc 16bit timer registers. | ||
| 325 | /// | ||
| 326 | /// Note: This works even if the timer is more capable, because registers | ||
| 327 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 328 | /// for a given set of capabilities, and having it transparently work with | ||
| 329 | /// more capable timers. | ||
| 330 | pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 { | ||
| 331 | unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) } | ||
| 332 | } | ||
| 333 | |||
| 334 | /// Enable/disable the update dma. | ||
| 335 | pub fn enable_update_dma(&self, enable: bool) { | ||
| 336 | self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Get the update dma enable/disable state. | ||
| 340 | pub fn get_update_dma_state(&self) -> bool { | ||
| 341 | self.regs_basic_no_cr2().dier().read().ude() | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | impl<'d, T: BasicInstance> Timer<'d, T> { | ||
| 346 | /// Get access to the Baisc 16bit timer registers. | ||
| 347 | /// | ||
| 348 | /// Note: This works even if the timer is more capable, because registers | ||
| 349 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 350 | /// for a given set of capabilities, and having it transparently work with | ||
| 351 | /// more capable timers. | ||
| 352 | pub fn regs_basic(&self) -> crate::pac::timer::TimBasic { | ||
| 353 | unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | impl<'d, T: GeneralInstance1Channel> Timer<'d, T> { | ||
| 358 | /// Get access to the general purpose 1 channel 16bit timer registers. | ||
| 359 | /// | ||
| 360 | /// Note: This works even if the timer is more capable, because registers | ||
| 361 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 362 | /// for a given set of capabilities, and having it transparently work with | ||
| 363 | /// more capable timers. | ||
| 364 | pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch { | ||
| 365 | unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) } | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Set clock divider. | ||
| 369 | pub fn set_clock_division(&self, ckd: vals::Ckd) { | ||
| 370 | self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 371 | } | ||
| 372 | |||
| 373 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 374 | pub fn get_max_compare_value(&self) -> u32 { | ||
| 375 | match T::BITS { | ||
| 376 | TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, | ||
| 377 | #[cfg(not(stm32l0))] | ||
| 378 | TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | impl<'d, T: GeneralInstance2Channel> Timer<'d, T> { | ||
| 384 | /// Get access to the general purpose 2 channel 16bit timer registers. | ||
| 385 | /// | ||
| 386 | /// Note: This works even if the timer is more capable, because registers | ||
| 387 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 388 | /// for a given set of capabilities, and having it transparently work with | ||
| 389 | /// more capable timers. | ||
| 390 | pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch { | ||
| 391 | unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | ||
| 396 | /// Get access to the general purpose 16bit timer registers. | ||
| 397 | /// | ||
| 398 | /// Note: This works even if the timer is more capable, because registers | ||
| 399 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 400 | /// for a given set of capabilities, and having it transparently work with | ||
| 401 | /// more capable timers. | ||
| 402 | pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { | ||
| 403 | unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) } | ||
| 404 | } | ||
| 405 | |||
| 406 | /// Enable timer outputs. | ||
| 407 | pub fn enable_outputs(&self) { | ||
| 408 | self.tim.enable_outputs() | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Set counting mode. | ||
| 412 | pub fn set_counting_mode(&self, mode: CountingMode) { | ||
| 413 | let (cms, dir) = mode.into(); | ||
| 414 | |||
| 415 | let timer_enabled = self.regs_core().cr1().read().cen(); | ||
| 416 | // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. | ||
| 417 | // Changing direction is discouraged while the timer is running. | ||
| 418 | assert!(!timer_enabled); | ||
| 419 | |||
| 420 | self.regs_gp16().cr1().modify(|r| r.set_dir(dir)); | ||
| 421 | self.regs_gp16().cr1().modify(|r| r.set_cms(cms)) | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Get counting mode. | ||
| 425 | pub fn get_counting_mode(&self) -> CountingMode { | ||
| 426 | let cr1 = self.regs_gp16().cr1().read(); | ||
| 427 | (cr1.cms(), cr1.dir()).into() | ||
| 428 | } | ||
| 429 | |||
| 430 | /// Set input capture filter. | ||
| 431 | pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { | ||
| 432 | let raw_channel = channel.index(); | ||
| 433 | self.regs_gp16() | ||
| 434 | .ccmr_input(raw_channel / 2) | ||
| 435 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 436 | } | ||
| 437 | |||
| 438 | /// Clear input interrupt. | ||
| 439 | pub fn clear_input_interrupt(&self, channel: Channel) { | ||
| 440 | self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); | ||
| 441 | } | ||
| 442 | |||
| 443 | /// Enable input interrupt. | ||
| 444 | pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) { | ||
| 445 | self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); | ||
| 446 | } | ||
| 447 | |||
| 448 | /// Set input capture prescaler. | ||
| 449 | pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { | ||
| 450 | let raw_channel = channel.index(); | ||
| 451 | self.regs_gp16() | ||
| 452 | .ccmr_input(raw_channel / 2) | ||
| 453 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Set input TI selection. | ||
| 457 | pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { | ||
| 458 | let raw_channel = channel.index(); | ||
| 459 | self.regs_gp16() | ||
| 460 | .ccmr_input(raw_channel / 2) | ||
| 461 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 462 | } | ||
| 463 | |||
| 464 | /// Set input capture mode. | ||
| 465 | pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { | ||
| 466 | self.regs_gp16().ccer().modify(|r| match mode { | ||
| 467 | InputCaptureMode::Rising => { | ||
| 468 | r.set_ccnp(channel.index(), false); | ||
| 469 | r.set_ccp(channel.index(), false); | ||
| 470 | } | ||
| 471 | InputCaptureMode::Falling => { | ||
| 472 | r.set_ccnp(channel.index(), false); | ||
| 473 | r.set_ccp(channel.index(), true); | ||
| 474 | } | ||
| 475 | InputCaptureMode::BothEdges => { | ||
| 476 | r.set_ccnp(channel.index(), true); | ||
| 477 | r.set_ccp(channel.index(), true); | ||
| 478 | } | ||
| 479 | }); | ||
| 480 | } | ||
| 481 | |||
| 482 | /// Set output compare mode. | ||
| 483 | pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { | ||
| 484 | let raw_channel: usize = channel.index(); | ||
| 485 | self.regs_gp16() | ||
| 486 | .ccmr_output(raw_channel / 2) | ||
| 487 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Set output polarity. | ||
| 491 | pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 492 | self.regs_gp16() | ||
| 493 | .ccer() | ||
| 494 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); | ||
| 495 | } | ||
| 496 | |||
| 497 | /// Enable/disable a channel. | ||
| 498 | pub fn enable_channel(&self, channel: Channel, enable: bool) { | ||
| 499 | self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); | ||
| 500 | } | ||
| 501 | |||
| 502 | /// Get enable/disable state of a channel | ||
| 503 | pub fn get_channel_enable_state(&self, channel: Channel) -> bool { | ||
| 504 | self.regs_gp16().ccer().read().cce(channel.index()) | ||
| 505 | } | ||
| 506 | |||
| 507 | /// Set compare value for a channel. | ||
| 508 | pub fn set_compare_value(&self, channel: Channel, value: u32) { | ||
| 509 | match T::BITS { | ||
| 510 | TimerBits::Bits16 => { | ||
| 511 | let value = unwrap!(u16::try_from(value)); | ||
| 512 | self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | ||
| 513 | } | ||
| 514 | #[cfg(not(stm32l0))] | ||
| 515 | TimerBits::Bits32 => { | ||
| 516 | self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | /// Get compare value for a channel. | ||
| 522 | pub fn get_compare_value(&self, channel: Channel) -> u32 { | ||
| 523 | match T::BITS { | ||
| 524 | TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, | ||
| 525 | #[cfg(not(stm32l0))] | ||
| 526 | TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | /// Get capture value for a channel. | ||
| 531 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | ||
| 532 | self.get_compare_value(channel) | ||
| 533 | } | ||
| 534 | |||
| 535 | /// Set output compare preload. | ||
| 536 | pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) { | ||
| 537 | let channel_index = channel.index(); | ||
| 538 | self.regs_gp16() | ||
| 539 | .ccmr_output(channel_index / 2) | ||
| 540 | .modify(|w| w.set_ocpe(channel_index % 2, preload)); | ||
| 541 | } | ||
| 542 | |||
| 543 | /// Get capture compare DMA selection | ||
| 544 | pub fn get_cc_dma_selection(&self) -> vals::Ccds { | ||
| 545 | self.regs_gp16().cr2().read().ccds() | ||
| 546 | } | ||
| 547 | |||
| 548 | /// Set capture compare DMA selection | ||
| 549 | pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) { | ||
| 550 | self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) | ||
| 551 | } | ||
| 552 | |||
| 553 | /// Get capture compare DMA enable state | ||
| 554 | pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { | ||
| 555 | self.regs_gp16().dier().read().ccde(channel.index()) | ||
| 556 | } | ||
| 557 | |||
| 558 | /// Set capture compare DMA enable state | ||
| 559 | pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { | ||
| 560 | self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | #[cfg(not(stm32l0))] | ||
| 565 | impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> { | ||
| 566 | /// Get access to the general purpose 32bit timer registers. | ||
| 567 | /// | ||
| 568 | /// Note: This works even if the timer is more capable, because registers | ||
| 569 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 570 | /// for a given set of capabilities, and having it transparently work with | ||
| 571 | /// more capable timers. | ||
| 572 | pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 { | ||
| 573 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | #[cfg(not(stm32l0))] | ||
| 578 | impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> { | ||
| 579 | /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. | ||
| 580 | /// | ||
| 581 | /// Note: This works even if the timer is more capable, because registers | ||
| 582 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 583 | /// for a given set of capabilities, and having it transparently work with | ||
| 584 | /// more capable timers. | ||
| 585 | pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp { | ||
| 586 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } | ||
| 587 | } | ||
| 588 | |||
| 589 | /// Set clock divider for the dead time. | ||
| 590 | pub fn set_dead_time_clock_division(&self, value: vals::Ckd) { | ||
| 591 | self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); | ||
| 592 | } | ||
| 593 | |||
| 594 | /// Set dead time, as a fraction of the max duty value. | ||
| 595 | pub fn set_dead_time_value(&self, value: u8) { | ||
| 596 | self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); | ||
| 597 | } | ||
| 598 | |||
| 599 | /// Set state of MOE-bit in BDTR register to en-/disable output | ||
| 600 | pub fn set_moe(&self, enable: bool) { | ||
| 601 | self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | #[cfg(not(stm32l0))] | ||
| 606 | impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> { | ||
| 607 | /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. | ||
| 608 | /// | ||
| 609 | /// Note: This works even if the timer is more capable, because registers | ||
| 610 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 611 | /// for a given set of capabilities, and having it transparently work with | ||
| 612 | /// more capable timers. | ||
| 613 | pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp { | ||
| 614 | unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) } | ||
| 615 | } | ||
| 616 | } | ||
| 617 | |||
| 618 | #[cfg(not(stm32l0))] | ||
| 619 | impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> { | ||
| 620 | /// Get access to the advanced timer registers. | ||
| 621 | pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv { | ||
| 622 | unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) } | ||
| 623 | } | ||
| 624 | |||
| 625 | /// Set complementary output polarity. | ||
| 626 | pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 627 | self.regs_advanced() | ||
| 628 | .ccer() | ||
| 629 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); | ||
| 630 | } | ||
| 631 | |||
| 632 | /// Enable/disable a complementary channel. | ||
| 633 | pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) { | ||
| 634 | self.regs_advanced() | ||
| 635 | .ccer() | ||
| 636 | .modify(|w| w.set_ccne(channel.index(), enable)); | ||
| 637 | } | ||
| 638 | } | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 8530c5229..2ba6b3f11 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,490 +1,13 @@ | |||
| 1 | //! Timers, PWM, quadrature decoder. | 1 | //! Timers, PWM, quadrature decoder. |
| 2 | //! | ||
| 3 | |||
| 4 | //! Timer inheritance | ||
| 5 | //! | ||
| 6 | |||
| 7 | // sealed: | ||
| 8 | // | ||
| 9 | // Core -------------------------> 1CH -------------------------> 1CH_CMP | ||
| 10 | // | | ^ | | ||
| 11 | // +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV | ||
| 12 | // | | | ^ | | ^ ^ | ||
| 13 | // | | +------|--|--------------|-----------+ | | ||
| 14 | // | +--------------------+ +--------------|-----------|---------+ | ||
| 15 | // | | | | | ||
| 16 | // | +--------------------------------------|-----------+ | ||
| 17 | // +----------------------------------------------------+ | ||
| 18 | |||
| 19 | //! ```text | ||
| 20 | //! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance | ||
| 21 | //! | | ||
| 22 | //! +--> CaptureCompare32bitInstance | ||
| 23 | //! ``` | ||
| 24 | //! | ||
| 25 | //! Mapping: | ||
| 26 | //! | ||
| 27 | //! | trait | timer | | ||
| 28 | //! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- | | ||
| 29 | //! | [BasicInstance] | Basic Timer | | ||
| 30 | //! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer | | ||
| 31 | //! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer | | ||
| 32 | //! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer | | ||
| 33 | 2 | ||
| 34 | #[cfg(not(stm32l0))] | 3 | #[cfg(not(stm32l0))] |
| 35 | pub mod complementary_pwm; | 4 | pub mod complementary_pwm; |
| 5 | pub mod low_level; | ||
| 36 | pub mod qei; | 6 | pub mod qei; |
| 37 | pub mod simple_pwm; | 7 | pub mod simple_pwm; |
| 38 | 8 | ||
| 39 | use stm32_metapac::timer::vals; | ||
| 40 | |||
| 41 | use crate::interrupt; | 9 | use crate::interrupt; |
| 42 | use crate::rcc::RccPeripheral; | 10 | use crate::rcc::RccPeripheral; |
| 43 | use crate::time::Hertz; | ||
| 44 | |||
| 45 | /// Low-level timer access. | ||
| 46 | #[cfg(feature = "unstable-pac")] | ||
| 47 | pub mod low_level { | ||
| 48 | pub use super::sealed::*; | ||
| 49 | } | ||
| 50 | |||
| 51 | pub(crate) mod sealed { | ||
| 52 | use super::*; | ||
| 53 | |||
| 54 | /// Virtual Core 16-bit timer instance. | ||
| 55 | pub trait CoreInstance: RccPeripheral { | ||
| 56 | /// Interrupt for this timer. | ||
| 57 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 58 | |||
| 59 | /// Get access to the virutal core 16bit timer registers. | ||
| 60 | /// | ||
| 61 | /// Note: This works even if the timer is more capable, because registers | ||
| 62 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 63 | /// for a given set of capabilities, and having it transparently work with | ||
| 64 | /// more capable timers. | ||
| 65 | fn regs_core() -> crate::pac::timer::TimCore; | ||
| 66 | |||
| 67 | /// Start the timer. | ||
| 68 | fn start(&self) { | ||
| 69 | Self::regs_core().cr1().modify(|r| r.set_cen(true)); | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Stop the timer. | ||
| 73 | fn stop(&self) { | ||
| 74 | Self::regs_core().cr1().modify(|r| r.set_cen(false)); | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Reset the counter value to 0 | ||
| 78 | fn reset(&self) { | ||
| 79 | Self::regs_core().cnt().write(|r| r.set_cnt(0)); | ||
| 80 | } | ||
| 81 | |||
| 82 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. | ||
| 83 | /// | ||
| 84 | /// This means that in the default edge-aligned mode, | ||
| 85 | /// the timer counter will wrap around at the same frequency as is being set. | ||
| 86 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | ||
| 87 | /// because it needs to count up and down. | ||
| 88 | fn set_frequency(&self, frequency: Hertz) { | ||
| 89 | let f = frequency.0; | ||
| 90 | let timer_f = Self::frequency().0; | ||
| 91 | assert!(f > 0); | ||
| 92 | let pclk_ticks_per_timer_period = timer_f / f; | ||
| 93 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); | ||
| 94 | let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); | ||
| 95 | |||
| 96 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 97 | let arr = unwrap!(u16::try_from(divide_by - 1)); | ||
| 98 | |||
| 99 | let regs = Self::regs_core(); | ||
| 100 | regs.psc().write(|r| r.set_psc(psc)); | ||
| 101 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 102 | |||
| 103 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 104 | regs.egr().write(|r| r.set_ug(true)); | ||
| 105 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 106 | } | ||
| 107 | |||
| 108 | /// Clear update interrupt. | ||
| 109 | /// | ||
| 110 | /// Returns whether the update interrupt flag was set. | ||
| 111 | fn clear_update_interrupt(&self) -> bool { | ||
| 112 | let regs = Self::regs_core(); | ||
| 113 | let sr = regs.sr().read(); | ||
| 114 | if sr.uif() { | ||
| 115 | regs.sr().modify(|r| { | ||
| 116 | r.set_uif(false); | ||
| 117 | }); | ||
| 118 | true | ||
| 119 | } else { | ||
| 120 | false | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Enable/disable the update interrupt. | ||
| 125 | fn enable_update_interrupt(&self, enable: bool) { | ||
| 126 | Self::regs_core().dier().modify(|r| r.set_uie(enable)); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Enable/disable autoreload preload. | ||
| 130 | fn set_autoreload_preload(&self, enable: bool) { | ||
| 131 | Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Get the timer frequency. | ||
| 135 | fn get_frequency(&self) -> Hertz { | ||
| 136 | let timer_f = Self::frequency(); | ||
| 137 | |||
| 138 | let regs = Self::regs_core(); | ||
| 139 | let arr = regs.arr().read().arr(); | ||
| 140 | let psc = regs.psc().read().psc(); | ||
| 141 | |||
| 142 | timer_f / arr / (psc + 1) | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Virtual Basic without CR2 16-bit timer instance. | ||
| 147 | pub trait BasicNoCr2Instance: CoreInstance { | ||
| 148 | /// Get access to the Baisc 16bit timer registers. | ||
| 149 | /// | ||
| 150 | /// Note: This works even if the timer is more capable, because registers | ||
| 151 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 152 | /// for a given set of capabilities, and having it transparently work with | ||
| 153 | /// more capable timers. | ||
| 154 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; | ||
| 155 | |||
| 156 | /// Enable/disable the update dma. | ||
| 157 | fn enable_update_dma(&self, enable: bool) { | ||
| 158 | Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Get the update dma enable/disable state. | ||
| 162 | fn get_update_dma_state(&self) -> bool { | ||
| 163 | Self::regs_basic_no_cr2().dier().read().ude() | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Basic 16-bit timer instance. | ||
| 168 | pub trait BasicInstance: BasicNoCr2Instance { | ||
| 169 | /// Get access to the Baisc 16bit timer registers. | ||
| 170 | /// | ||
| 171 | /// Note: This works even if the timer is more capable, because registers | ||
| 172 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 173 | /// for a given set of capabilities, and having it transparently work with | ||
| 174 | /// more capable timers. | ||
| 175 | fn regs_basic() -> crate::pac::timer::TimBasic; | ||
| 176 | } | ||
| 177 | |||
| 178 | /// Gneral-purpose 1 channel 16-bit timer instance. | ||
| 179 | pub trait GeneralPurpose1ChannelInstance: CoreInstance { | ||
| 180 | /// Get access to the general purpose 1 channel 16bit timer registers. | ||
| 181 | /// | ||
| 182 | /// Note: This works even if the timer is more capable, because registers | ||
| 183 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 184 | /// for a given set of capabilities, and having it transparently work with | ||
| 185 | /// more capable timers. | ||
| 186 | fn regs_1ch() -> crate::pac::timer::Tim1ch; | ||
| 187 | |||
| 188 | /// Set clock divider. | ||
| 189 | fn set_clock_division(&self, ckd: vals::Ckd) { | ||
| 190 | Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 194 | fn get_max_compare_value(&self) -> u16 { | ||
| 195 | Self::regs_1ch().arr().read().arr() | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Gneral-purpose 1 channel 16-bit timer instance. | ||
| 200 | pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance { | ||
| 201 | /// Get access to the general purpose 2 channel 16bit timer registers. | ||
| 202 | /// | ||
| 203 | /// Note: This works even if the timer is more capable, because registers | ||
| 204 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 205 | /// for a given set of capabilities, and having it transparently work with | ||
| 206 | /// more capable timers. | ||
| 207 | fn regs_2ch() -> crate::pac::timer::Tim2ch; | ||
| 208 | } | ||
| 209 | |||
| 210 | /// Gneral-purpose 16-bit timer instance. | ||
| 211 | pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance { | ||
| 212 | /// Get access to the general purpose 16bit timer registers. | ||
| 213 | /// | ||
| 214 | /// Note: This works even if the timer is more capable, because registers | ||
| 215 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 216 | /// for a given set of capabilities, and having it transparently work with | ||
| 217 | /// more capable timers. | ||
| 218 | fn regs_gp16() -> crate::pac::timer::TimGp16; | ||
| 219 | |||
| 220 | /// Set counting mode. | ||
| 221 | fn set_counting_mode(&self, mode: CountingMode) { | ||
| 222 | let (cms, dir) = mode.into(); | ||
| 223 | |||
| 224 | let timer_enabled = Self::regs_core().cr1().read().cen(); | ||
| 225 | // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. | ||
| 226 | // Changing direction is discouraged while the timer is running. | ||
| 227 | assert!(!timer_enabled); | ||
| 228 | |||
| 229 | Self::regs_gp16().cr1().modify(|r| r.set_dir(dir)); | ||
| 230 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) | ||
| 231 | } | ||
| 232 | |||
| 233 | /// Get counting mode. | ||
| 234 | fn get_counting_mode(&self) -> CountingMode { | ||
| 235 | let cr1 = Self::regs_gp16().cr1().read(); | ||
| 236 | (cr1.cms(), cr1.dir()).into() | ||
| 237 | } | ||
| 238 | |||
| 239 | /// Set input capture filter. | ||
| 240 | fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { | ||
| 241 | let raw_channel = channel.index(); | ||
| 242 | Self::regs_gp16() | ||
| 243 | .ccmr_input(raw_channel / 2) | ||
| 244 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Clear input interrupt. | ||
| 248 | fn clear_input_interrupt(&self, channel: Channel) { | ||
| 249 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Enable input interrupt. | ||
| 253 | fn enable_input_interrupt(&self, channel: Channel, enable: bool) { | ||
| 254 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Set input capture prescaler. | ||
| 258 | fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { | ||
| 259 | let raw_channel = channel.index(); | ||
| 260 | Self::regs_gp16() | ||
| 261 | .ccmr_input(raw_channel / 2) | ||
| 262 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 263 | } | ||
| 264 | |||
| 265 | /// Set input TI selection. | ||
| 266 | fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { | ||
| 267 | let raw_channel = channel.index(); | ||
| 268 | Self::regs_gp16() | ||
| 269 | .ccmr_input(raw_channel / 2) | ||
| 270 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Set input capture mode. | ||
| 274 | fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { | ||
| 275 | Self::regs_gp16().ccer().modify(|r| match mode { | ||
| 276 | InputCaptureMode::Rising => { | ||
| 277 | r.set_ccnp(channel.index(), false); | ||
| 278 | r.set_ccp(channel.index(), false); | ||
| 279 | } | ||
| 280 | InputCaptureMode::Falling => { | ||
| 281 | r.set_ccnp(channel.index(), false); | ||
| 282 | r.set_ccp(channel.index(), true); | ||
| 283 | } | ||
| 284 | InputCaptureMode::BothEdges => { | ||
| 285 | r.set_ccnp(channel.index(), true); | ||
| 286 | r.set_ccp(channel.index(), true); | ||
| 287 | } | ||
| 288 | }); | ||
| 289 | } | ||
| 290 | |||
| 291 | /// Set output compare mode. | ||
| 292 | fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { | ||
| 293 | let raw_channel: usize = channel.index(); | ||
| 294 | Self::regs_gp16() | ||
| 295 | .ccmr_output(raw_channel / 2) | ||
| 296 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 297 | } | ||
| 298 | |||
| 299 | /// Set output polarity. | ||
| 300 | fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 301 | Self::regs_gp16() | ||
| 302 | .ccer() | ||
| 303 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); | ||
| 304 | } | ||
| 305 | |||
| 306 | /// Enable/disable a channel. | ||
| 307 | fn enable_channel(&self, channel: Channel, enable: bool) { | ||
| 308 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); | ||
| 309 | } | ||
| 310 | |||
| 311 | /// Get enable/disable state of a channel | ||
| 312 | fn get_channel_enable_state(&self, channel: Channel) -> bool { | ||
| 313 | Self::regs_gp16().ccer().read().cce(channel.index()) | ||
| 314 | } | ||
| 315 | |||
| 316 | /// Set compare value for a channel. | ||
| 317 | fn set_compare_value(&self, channel: Channel, value: u16) { | ||
| 318 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | ||
| 319 | } | ||
| 320 | |||
| 321 | /// Get capture value for a channel. | ||
| 322 | fn get_capture_value(&self, channel: Channel) -> u16 { | ||
| 323 | Self::regs_gp16().ccr(channel.index()).read().ccr() | ||
| 324 | } | ||
| 325 | |||
| 326 | /// Get compare value for a channel. | ||
| 327 | fn get_compare_value(&self, channel: Channel) -> u16 { | ||
| 328 | Self::regs_gp16().ccr(channel.index()).read().ccr() | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Set output compare preload. | ||
| 332 | fn set_output_compare_preload(&self, channel: Channel, preload: bool) { | ||
| 333 | let channel_index = channel.index(); | ||
| 334 | Self::regs_gp16() | ||
| 335 | .ccmr_output(channel_index / 2) | ||
| 336 | .modify(|w| w.set_ocpe(channel_index % 2, preload)); | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Get capture compare DMA selection | ||
| 340 | fn get_cc_dma_selection(&self) -> super::vals::Ccds { | ||
| 341 | Self::regs_gp16().cr2().read().ccds() | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Set capture compare DMA selection | ||
| 345 | fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) { | ||
| 346 | Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) | ||
| 347 | } | ||
| 348 | |||
| 349 | /// Get capture compare DMA enable state | ||
| 350 | fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { | ||
| 351 | Self::regs_gp16().dier().read().ccde(channel.index()) | ||
| 352 | } | ||
| 353 | |||
| 354 | /// Set capture compare DMA enable state | ||
| 355 | fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { | ||
| 356 | Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | #[cfg(not(stm32l0))] | ||
| 361 | /// Gneral-purpose 32-bit timer instance. | ||
| 362 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | ||
| 363 | /// Get access to the general purpose 32bit timer registers. | ||
| 364 | /// | ||
| 365 | /// Note: This works even if the timer is more capable, because registers | ||
| 366 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 367 | /// for a given set of capabilities, and having it transparently work with | ||
| 368 | /// more capable timers. | ||
| 369 | fn regs_gp32() -> crate::pac::timer::TimGp32; | ||
| 370 | |||
| 371 | /// Set timer frequency. | ||
| 372 | fn set_frequency(&self, frequency: Hertz) { | ||
| 373 | let f = frequency.0; | ||
| 374 | assert!(f > 0); | ||
| 375 | let timer_f = Self::frequency().0; | ||
| 376 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; | ||
| 377 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); | ||
| 378 | let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); | ||
| 379 | |||
| 380 | let regs = Self::regs_gp32(); | ||
| 381 | regs.psc().write(|r| r.set_psc(psc)); | ||
| 382 | regs.arr().write_value(arr); | ||
| 383 | |||
| 384 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 385 | regs.egr().write(|r| r.set_ug(true)); | ||
| 386 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 387 | } | ||
| 388 | |||
| 389 | /// Get timer frequency. | ||
| 390 | fn get_frequency(&self) -> Hertz { | ||
| 391 | let timer_f = Self::frequency(); | ||
| 392 | |||
| 393 | let regs = Self::regs_gp32(); | ||
| 394 | let arr = regs.arr().read(); | ||
| 395 | let psc = regs.psc().read().psc(); | ||
| 396 | |||
| 397 | timer_f / arr / (psc + 1) | ||
| 398 | } | ||
| 399 | |||
| 400 | /// Set comapre value for a channel. | ||
| 401 | fn set_compare_value(&self, channel: Channel, value: u32) { | ||
| 402 | Self::regs_gp32().ccr(channel.index()).write_value(value); | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Get capture value for a channel. | ||
| 406 | fn get_capture_value(&self, channel: Channel) -> u32 { | ||
| 407 | Self::regs_gp32().ccr(channel.index()).read() | ||
| 408 | } | ||
| 409 | |||
| 410 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 411 | fn get_max_compare_value(&self) -> u32 { | ||
| 412 | Self::regs_gp32().arr().read() | ||
| 413 | } | ||
| 414 | |||
| 415 | /// Get compare value for a channel. | ||
| 416 | fn get_compare_value(&self, channel: Channel) -> u32 { | ||
| 417 | Self::regs_gp32().ccr(channel.index()).read() | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | #[cfg(not(stm32l0))] | ||
| 422 | /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. | ||
| 423 | pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { | ||
| 424 | /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. | ||
| 425 | /// | ||
| 426 | /// Note: This works even if the timer is more capable, because registers | ||
| 427 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 428 | /// for a given set of capabilities, and having it transparently work with | ||
| 429 | /// more capable timers. | ||
| 430 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; | ||
| 431 | |||
| 432 | /// Set clock divider for the dead time. | ||
| 433 | fn set_dead_time_clock_division(&self, value: vals::Ckd) { | ||
| 434 | Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); | ||
| 435 | } | ||
| 436 | |||
| 437 | /// Set dead time, as a fraction of the max duty value. | ||
| 438 | fn set_dead_time_value(&self, value: u8) { | ||
| 439 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); | ||
| 440 | } | ||
| 441 | |||
| 442 | /// Enable timer outputs. | ||
| 443 | fn enable_outputs(&self) { | ||
| 444 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | #[cfg(not(stm32l0))] | ||
| 449 | /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. | ||
| 450 | pub trait GeneralPurpose2ChannelComplementaryInstance: | ||
| 451 | BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance | ||
| 452 | { | ||
| 453 | /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. | ||
| 454 | /// | ||
| 455 | /// Note: This works even if the timer is more capable, because registers | ||
| 456 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 457 | /// for a given set of capabilities, and having it transparently work with | ||
| 458 | /// more capable timers. | ||
| 459 | fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; | ||
| 460 | } | ||
| 461 | |||
| 462 | #[cfg(not(stm32l0))] | ||
| 463 | /// Advanced control timer instance. | ||
| 464 | pub trait AdvancedControlInstance: | ||
| 465 | GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance | ||
| 466 | { | ||
| 467 | /// Capture compare interrupt for this timer. | ||
| 468 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; | ||
| 469 | |||
| 470 | /// Get access to the advanced timer registers. | ||
| 471 | fn regs_advanced() -> crate::pac::timer::TimAdv; | ||
| 472 | |||
| 473 | /// Set complementary output polarity. | ||
| 474 | fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 475 | Self::regs_advanced() | ||
| 476 | .ccer() | ||
| 477 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); | ||
| 478 | } | ||
| 479 | |||
| 480 | /// Enable/disable a complementary channel. | ||
| 481 | fn enable_complementary_channel(&self, channel: Channel, enable: bool) { | ||
| 482 | Self::regs_advanced() | ||
| 483 | .ccer() | ||
| 484 | .modify(|w| w.set_ccne(channel.index(), enable)); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | } | ||
| 488 | 11 | ||
| 489 | /// Timer channel. | 12 | /// Timer channel. |
| 490 | #[derive(Clone, Copy)] | 13 | #[derive(Clone, Copy)] |
| @@ -511,454 +34,195 @@ impl Channel { | |||
| 511 | } | 34 | } |
| 512 | } | 35 | } |
| 513 | 36 | ||
| 514 | /// Input capture mode. | 37 | /// Amount of bits of a timer. |
| 515 | #[derive(Clone, Copy)] | 38 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 516 | pub enum InputCaptureMode { | 39 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 517 | /// Rising edge only. | 40 | pub enum TimerBits { |
| 518 | Rising, | 41 | /// 16 bits. |
| 519 | /// Falling edge only. | 42 | Bits16, |
| 520 | Falling, | 43 | /// 32 bits. |
| 521 | /// Both rising or falling edges. | 44 | #[cfg(not(stm32l0))] |
| 522 | BothEdges, | 45 | Bits32, |
| 523 | } | 46 | } |
| 524 | 47 | ||
| 525 | /// Input TI selection. | 48 | /// Core timer instance. |
| 526 | #[derive(Clone, Copy)] | 49 | pub trait CoreInstance: RccPeripheral + 'static { |
| 527 | pub enum InputTISelection { | 50 | /// Interrupt for this timer. |
| 528 | /// Normal | 51 | type Interrupt: interrupt::typelevel::Interrupt; |
| 529 | Normal, | ||
| 530 | /// Alternate | ||
| 531 | Alternate, | ||
| 532 | /// TRC | ||
| 533 | TRC, | ||
| 534 | } | ||
| 535 | 52 | ||
| 536 | impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | 53 | /// Amount of bits this timer has. |
| 537 | fn from(tisel: InputTISelection) -> Self { | 54 | const BITS: TimerBits; |
| 538 | match tisel { | ||
| 539 | InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, | ||
| 540 | InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, | ||
| 541 | InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, | ||
| 542 | } | ||
| 543 | } | ||
| 544 | } | ||
| 545 | 55 | ||
| 546 | /// Timer counting mode. | 56 | /// Registers for this timer. |
| 547 | #[repr(u8)] | ||
| 548 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
| 549 | pub enum CountingMode { | ||
| 550 | #[default] | ||
| 551 | /// The timer counts up to the reload value and then resets back to 0. | ||
| 552 | EdgeAlignedUp, | ||
| 553 | /// The timer counts down to 0 and then resets back to the reload value. | ||
| 554 | EdgeAlignedDown, | ||
| 555 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 556 | /// | 57 | /// |
| 557 | /// The output compare interrupt flags of channels configured in output are | 58 | /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type. |
| 558 | /// set when the counter is counting down. | 59 | fn regs() -> *mut (); |
| 559 | CenterAlignedDownInterrupts, | ||
| 560 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 561 | /// | ||
| 562 | /// The output compare interrupt flags of channels configured in output are | ||
| 563 | /// set when the counter is counting up. | ||
| 564 | CenterAlignedUpInterrupts, | ||
| 565 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 566 | /// | ||
| 567 | /// The output compare interrupt flags of channels configured in output are | ||
| 568 | /// set when the counter is counting both up or down. | ||
| 569 | CenterAlignedBothInterrupts, | ||
| 570 | } | 60 | } |
| 61 | /// Cut-down basic timer instance. | ||
| 62 | pub trait BasicNoCr2Instance: CoreInstance {} | ||
| 63 | /// Basic timer instance. | ||
| 64 | pub trait BasicInstance: BasicNoCr2Instance {} | ||
| 571 | 65 | ||
| 572 | impl CountingMode { | 66 | /// General-purpose 16-bit timer with 1 channel instance. |
| 573 | /// Return whether this mode is edge-aligned (up or down). | 67 | pub trait GeneralInstance1Channel: CoreInstance {} |
| 574 | pub fn is_edge_aligned(&self) -> bool { | ||
| 575 | matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) | ||
| 576 | } | ||
| 577 | 68 | ||
| 578 | /// Return whether this mode is center-aligned. | 69 | /// General-purpose 16-bit timer with 2 channels instance. |
| 579 | pub fn is_center_aligned(&self) -> bool { | 70 | pub trait GeneralInstance2Channel: GeneralInstance1Channel {} |
| 580 | matches!( | ||
| 581 | self, | ||
| 582 | CountingMode::CenterAlignedDownInterrupts | ||
| 583 | | CountingMode::CenterAlignedUpInterrupts | ||
| 584 | | CountingMode::CenterAlignedBothInterrupts | ||
| 585 | ) | ||
| 586 | } | ||
| 587 | } | ||
| 588 | 71 | ||
| 589 | impl From<CountingMode> for (vals::Cms, vals::Dir) { | 72 | /// General-purpose 16-bit timer with 4 channels instance. |
| 590 | fn from(value: CountingMode) -> Self { | 73 | pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel { |
| 591 | match value { | 74 | // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel |
| 592 | CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), | 75 | // Advanced timers implement this trait, but the output needs to be |
| 593 | CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), | 76 | // enabled explicitly. |
| 594 | CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), | 77 | // To support general-purpose and advanced timers, this function is added |
| 595 | CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), | 78 | // here defaulting to noop and overwritten for advanced timers. |
| 596 | CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), | 79 | /// Enable timer outputs. |
| 597 | } | 80 | fn enable_outputs(&self) {} |
| 598 | } | ||
| 599 | } | 81 | } |
| 600 | 82 | ||
| 601 | impl From<(vals::Cms, vals::Dir)> for CountingMode { | 83 | /// General-purpose 32-bit timer with 4 channels instance. |
| 602 | fn from(value: (vals::Cms, vals::Dir)) -> Self { | 84 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} |
| 603 | match value { | ||
| 604 | (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, | ||
| 605 | (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, | ||
| 606 | (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, | ||
| 607 | (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, | ||
| 608 | (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | /// Output compare mode. | ||
| 614 | #[derive(Clone, Copy)] | ||
| 615 | pub enum OutputCompareMode { | ||
| 616 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 617 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 618 | /// (this mode is used to generate a timing base). | ||
| 619 | Frozen, | ||
| 620 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 621 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 622 | ActiveOnMatch, | ||
| 623 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 624 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 625 | InactiveOnMatch, | ||
| 626 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 627 | Toggle, | ||
| 628 | /// Force inactive level - OCxREF is forced low. | ||
| 629 | ForceInactive, | ||
| 630 | /// Force active level - OCxREF is forced high. | ||
| 631 | ForceActive, | ||
| 632 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 633 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 634 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 635 | PwmMode1, | ||
| 636 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 637 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 638 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 639 | PwmMode2, | ||
| 640 | // TODO: there's more modes here depending on the chip family. | ||
| 641 | } | ||
| 642 | |||
| 643 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | ||
| 644 | fn from(mode: OutputCompareMode) -> Self { | ||
| 645 | match mode { | ||
| 646 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | ||
| 647 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, | ||
| 648 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, | ||
| 649 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | ||
| 650 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, | ||
| 651 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, | ||
| 652 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, | ||
| 653 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, | ||
| 654 | } | ||
| 655 | } | ||
| 656 | } | ||
| 657 | 85 | ||
| 658 | /// Timer output pin polarity. | 86 | /// Advanced 16-bit timer with 1 channel instance. |
| 659 | #[derive(Clone, Copy)] | 87 | pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { |
| 660 | pub enum OutputPolarity { | 88 | /// Capture compare interrupt for this timer. |
| 661 | /// Active high (higher duty value makes the pin spend more time high). | 89 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; |
| 662 | ActiveHigh, | ||
| 663 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 664 | ActiveLow, | ||
| 665 | } | 90 | } |
| 91 | /// Advanced 16-bit timer with 2 channels instance. | ||
| 666 | 92 | ||
| 667 | impl From<OutputPolarity> for bool { | 93 | pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} |
| 668 | fn from(mode: OutputPolarity) -> Self { | ||
| 669 | match mode { | ||
| 670 | OutputPolarity::ActiveHigh => false, | ||
| 671 | OutputPolarity::ActiveLow => true, | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | 94 | ||
| 676 | /// Basic 16-bit timer instance. | 95 | /// Advanced 16-bit timer with 4 channels instance. |
| 677 | pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} | 96 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} |
| 678 | |||
| 679 | // It's just a General-purpose 16-bit timer instance. | ||
| 680 | /// Capture Compare timer instance. | ||
| 681 | pub trait CaptureCompare16bitInstance: | ||
| 682 | BasicInstance | ||
| 683 | + sealed::GeneralPurpose2ChannelInstance | ||
| 684 | + sealed::GeneralPurpose1ChannelInstance | ||
| 685 | + sealed::GeneralPurpose16bitInstance | ||
| 686 | + 'static | ||
| 687 | { | ||
| 688 | } | ||
| 689 | 97 | ||
| 690 | #[cfg(not(stm32l0))] | 98 | pin_trait!(Channel1Pin, GeneralInstance4Channel); |
| 691 | // It's just a General-purpose 32-bit timer instance. | 99 | pin_trait!(Channel2Pin, GeneralInstance4Channel); |
| 692 | /// Capture Compare 32-bit timer instance. | 100 | pin_trait!(Channel3Pin, GeneralInstance4Channel); |
| 693 | pub trait CaptureCompare32bitInstance: | 101 | pin_trait!(Channel4Pin, GeneralInstance4Channel); |
| 694 | CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static | 102 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); |
| 695 | { | ||
| 696 | } | ||
| 697 | 103 | ||
| 698 | #[cfg(not(stm32l0))] | 104 | pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); |
| 699 | // It's just a Advanced Control timer instance. | 105 | pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); |
| 700 | /// Complementary Capture Compare 32-bit timer instance. | 106 | pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); |
| 701 | pub trait ComplementaryCaptureCompare16bitInstance: | 107 | pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); |
| 702 | CaptureCompare16bitInstance | ||
| 703 | + sealed::GeneralPurpose1ChannelComplementaryInstance | ||
| 704 | + sealed::GeneralPurpose2ChannelComplementaryInstance | ||
| 705 | + sealed::AdvancedControlInstance | ||
| 706 | + 'static | ||
| 707 | { | ||
| 708 | } | ||
| 709 | 108 | ||
| 710 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); | 109 | pin_trait!(BreakInputPin, AdvancedInstance4Channel); |
| 711 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); | 110 | pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); |
| 712 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); | ||
| 713 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); | ||
| 714 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); | ||
| 715 | 111 | ||
| 716 | cfg_if::cfg_if! { | 112 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); |
| 717 | if #[cfg(not(stm32l0))] { | 113 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); |
| 718 | pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 719 | pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 720 | pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 721 | pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 722 | 114 | ||
| 723 | pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); | 115 | pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); |
| 724 | pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); | 116 | pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); |
| 725 | 117 | ||
| 726 | pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); | 118 | // Update Event trigger DMA for every timer |
| 727 | pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); | 119 | dma_trait!(UpDma, BasicInstance); |
| 728 | 120 | ||
| 729 | pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); | 121 | dma_trait!(Ch1Dma, GeneralInstance4Channel); |
| 730 | pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); | 122 | dma_trait!(Ch2Dma, GeneralInstance4Channel); |
| 731 | } | 123 | dma_trait!(Ch3Dma, GeneralInstance4Channel); |
| 732 | } | 124 | dma_trait!(Ch4Dma, GeneralInstance4Channel); |
| 733 | 125 | ||
| 734 | #[allow(unused)] | 126 | #[allow(unused)] |
| 735 | macro_rules! impl_core_timer { | 127 | macro_rules! impl_core_timer { |
| 736 | ($inst:ident, $irq:ident) => { | 128 | ($inst:ident, $bits:expr) => { |
| 737 | impl sealed::CoreInstance for crate::peripherals::$inst { | 129 | impl CoreInstance for crate::peripherals::$inst { |
| 738 | type Interrupt = crate::interrupt::typelevel::$irq; | 130 | type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP; |
| 739 | |||
| 740 | fn regs_core() -> crate::pac::timer::TimCore { | ||
| 741 | unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 742 | } | ||
| 743 | } | ||
| 744 | }; | ||
| 745 | } | ||
| 746 | |||
| 747 | #[allow(unused)] | ||
| 748 | macro_rules! impl_basic_no_cr2_timer { | ||
| 749 | ($inst:ident) => { | ||
| 750 | impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { | ||
| 751 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { | ||
| 752 | unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 753 | } | ||
| 754 | } | ||
| 755 | }; | ||
| 756 | } | ||
| 757 | |||
| 758 | #[allow(unused)] | ||
| 759 | macro_rules! impl_basic_timer { | ||
| 760 | ($inst:ident) => { | ||
| 761 | impl sealed::BasicInstance for crate::peripherals::$inst { | ||
| 762 | fn regs_basic() -> crate::pac::timer::TimBasic { | ||
| 763 | unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 764 | } | ||
| 765 | } | ||
| 766 | }; | ||
| 767 | } | ||
| 768 | |||
| 769 | #[allow(unused)] | ||
| 770 | macro_rules! impl_1ch_timer { | ||
| 771 | ($inst:ident) => { | ||
| 772 | impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst { | ||
| 773 | fn regs_1ch() -> crate::pac::timer::Tim1ch { | ||
| 774 | unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 775 | } | ||
| 776 | } | ||
| 777 | }; | ||
| 778 | } | ||
| 779 | |||
| 780 | #[allow(unused)] | ||
| 781 | macro_rules! impl_2ch_timer { | ||
| 782 | ($inst:ident) => { | ||
| 783 | impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst { | ||
| 784 | fn regs_2ch() -> crate::pac::timer::Tim2ch { | ||
| 785 | unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 786 | } | ||
| 787 | } | ||
| 788 | }; | ||
| 789 | } | ||
| 790 | |||
| 791 | #[allow(unused)] | ||
| 792 | macro_rules! impl_gp16_timer { | ||
| 793 | ($inst:ident) => { | ||
| 794 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 795 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | ||
| 796 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 797 | } | ||
| 798 | } | ||
| 799 | }; | ||
| 800 | } | ||
| 801 | |||
| 802 | #[allow(unused)] | ||
| 803 | macro_rules! impl_gp32_timer { | ||
| 804 | ($inst:ident) => { | ||
| 805 | impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { | ||
| 806 | fn regs_gp32() -> crate::pac::timer::TimGp32 { | ||
| 807 | crate::pac::$inst | ||
| 808 | } | ||
| 809 | } | ||
| 810 | }; | ||
| 811 | } | ||
| 812 | |||
| 813 | #[allow(unused)] | ||
| 814 | macro_rules! impl_1ch_cmp_timer { | ||
| 815 | ($inst:ident) => { | ||
| 816 | impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { | ||
| 817 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp { | ||
| 818 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 819 | } | ||
| 820 | } | ||
| 821 | }; | ||
| 822 | } | ||
| 823 | 131 | ||
| 824 | #[allow(unused)] | 132 | const BITS: TimerBits = $bits; |
| 825 | macro_rules! impl_2ch_cmp_timer { | ||
| 826 | ($inst:ident) => { | ||
| 827 | impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { | ||
| 828 | fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { | ||
| 829 | unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 830 | } | ||
| 831 | } | ||
| 832 | }; | ||
| 833 | } | ||
| 834 | |||
| 835 | #[allow(unused)] | ||
| 836 | macro_rules! impl_adv_timer { | ||
| 837 | ($inst:ident, $irq:ident) => { | ||
| 838 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { | ||
| 839 | type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq; | ||
| 840 | 133 | ||
| 841 | fn regs_advanced() -> crate::pac::timer::TimAdv { | 134 | fn regs() -> *mut () { |
| 842 | unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } | 135 | crate::pac::$inst.as_ptr() |
| 843 | } | 136 | } |
| 844 | } | 137 | } |
| 845 | }; | 138 | }; |
| 846 | } | 139 | } |
| 847 | 140 | ||
| 848 | foreach_interrupt! { | 141 | foreach_interrupt! { |
| 849 | |||
| 850 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 142 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 851 | impl_core_timer!($inst, $irq); | 143 | impl_core_timer!($inst, TimerBits::Bits16); |
| 852 | impl_basic_no_cr2_timer!($inst); | 144 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 853 | impl_basic_timer!($inst); | ||
| 854 | impl BasicInstance for crate::peripherals::$inst {} | 145 | impl BasicInstance for crate::peripherals::$inst {} |
| 855 | }; | 146 | }; |
| 856 | 147 | ||
| 857 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { | 148 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { |
| 858 | impl_core_timer!($inst, $irq); | 149 | impl_core_timer!($inst, TimerBits::Bits16); |
| 859 | impl_basic_no_cr2_timer!($inst); | 150 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 860 | impl_basic_timer!($inst); | ||
| 861 | impl_1ch_timer!($inst); | ||
| 862 | impl_2ch_timer!($inst); | ||
| 863 | impl_gp16_timer!($inst); | ||
| 864 | impl BasicInstance for crate::peripherals::$inst {} | 151 | impl BasicInstance for crate::peripherals::$inst {} |
| 865 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 152 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 153 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 154 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 866 | }; | 155 | }; |
| 867 | 156 | ||
| 868 | |||
| 869 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { | 157 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { |
| 870 | impl_core_timer!($inst, $irq); | 158 | impl_core_timer!($inst, TimerBits::Bits16); |
| 871 | impl_basic_no_cr2_timer!($inst); | 159 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 872 | impl_basic_timer!($inst); | ||
| 873 | impl_1ch_timer!($inst); | ||
| 874 | impl_2ch_timer!($inst); | ||
| 875 | impl_gp16_timer!($inst); | ||
| 876 | impl BasicInstance for crate::peripherals::$inst {} | 160 | impl BasicInstance for crate::peripherals::$inst {} |
| 877 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 161 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 162 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 163 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 878 | }; | 164 | }; |
| 879 | 165 | ||
| 880 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { | 166 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 881 | impl_core_timer!($inst, $irq); | 167 | impl_core_timer!($inst, TimerBits::Bits16); |
| 882 | impl_basic_no_cr2_timer!($inst); | 168 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 883 | impl_basic_timer!($inst); | ||
| 884 | impl_1ch_timer!($inst); | ||
| 885 | impl_2ch_timer!($inst); | ||
| 886 | impl_gp16_timer!($inst); | ||
| 887 | impl BasicInstance for crate::peripherals::$inst {} | 169 | impl BasicInstance for crate::peripherals::$inst {} |
| 888 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 170 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 171 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 172 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 889 | }; | 173 | }; |
| 890 | 174 | ||
| 891 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 175 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 892 | impl_core_timer!($inst, $irq); | 176 | impl_core_timer!($inst, TimerBits::Bits32); |
| 893 | impl_basic_no_cr2_timer!($inst); | 177 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 894 | impl_basic_timer!($inst); | ||
| 895 | impl_1ch_timer!($inst); | ||
| 896 | impl_2ch_timer!($inst); | ||
| 897 | impl_gp16_timer!($inst); | ||
| 898 | impl_gp32_timer!($inst); | ||
| 899 | impl BasicInstance for crate::peripherals::$inst {} | 178 | impl BasicInstance for crate::peripherals::$inst {} |
| 900 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 179 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 901 | impl CaptureCompare32bitInstance for crate::peripherals::$inst {} | 180 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 181 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 182 | impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} | ||
| 902 | }; | 183 | }; |
| 903 | 184 | ||
| 904 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { | 185 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { |
| 905 | impl_core_timer!($inst, $irq); | 186 | impl_core_timer!($inst, TimerBits::Bits16); |
| 906 | impl_basic_no_cr2_timer!($inst); | 187 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 907 | impl_basic_timer!($inst); | ||
| 908 | impl_1ch_timer!($inst); | ||
| 909 | impl_2ch_timer!($inst); | ||
| 910 | impl_gp16_timer!($inst); | ||
| 911 | impl_1ch_cmp_timer!($inst); | ||
| 912 | impl_2ch_cmp_timer!($inst); | ||
| 913 | impl BasicInstance for crate::peripherals::$inst {} | 188 | impl BasicInstance for crate::peripherals::$inst {} |
| 914 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 189 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 915 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | 190 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 191 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} | ||
| 192 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } | ||
| 193 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} | ||
| 194 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} | ||
| 916 | }; | 195 | }; |
| 917 | ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { | ||
| 918 | impl_adv_timer!($inst, $irq); | ||
| 919 | }; | ||
| 920 | |||
| 921 | 196 | ||
| 922 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { | 197 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { |
| 923 | impl_core_timer!($inst, $irq); | 198 | impl_core_timer!($inst, TimerBits::Bits16); |
| 924 | impl_basic_no_cr2_timer!($inst); | 199 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 925 | impl_basic_timer!($inst); | ||
| 926 | impl_1ch_timer!($inst); | ||
| 927 | impl_2ch_timer!($inst); | ||
| 928 | impl_gp16_timer!($inst); | ||
| 929 | impl_1ch_cmp_timer!($inst); | ||
| 930 | impl_2ch_cmp_timer!($inst); | ||
| 931 | impl BasicInstance for crate::peripherals::$inst {} | 200 | impl BasicInstance for crate::peripherals::$inst {} |
| 932 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 201 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 933 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | 202 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 203 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} | ||
| 204 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } | ||
| 205 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} | ||
| 206 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} | ||
| 934 | }; | 207 | }; |
| 935 | ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { | ||
| 936 | impl_adv_timer!($inst, $irq); | ||
| 937 | }; | ||
| 938 | |||
| 939 | 208 | ||
| 940 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 209 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 941 | impl_core_timer!($inst, $irq); | 210 | impl_core_timer!($inst, TimerBits::Bits16); |
| 942 | impl_basic_no_cr2_timer!($inst); | 211 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 943 | impl_basic_timer!($inst); | ||
| 944 | impl_1ch_timer!($inst); | ||
| 945 | impl_2ch_timer!($inst); | ||
| 946 | impl_gp16_timer!($inst); | ||
| 947 | impl_1ch_cmp_timer!($inst); | ||
| 948 | impl_2ch_cmp_timer!($inst); | ||
| 949 | impl BasicInstance for crate::peripherals::$inst {} | 212 | impl BasicInstance for crate::peripherals::$inst {} |
| 950 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 213 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 951 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | 214 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 952 | }; | 215 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 953 | ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { | 216 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 954 | impl_adv_timer!($inst, $irq); | 217 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 218 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} | ||
| 955 | }; | 219 | }; |
| 956 | } | 220 | } |
| 957 | 221 | ||
| 958 | // Update Event trigger DMA for every timer | 222 | #[cfg(not(stm32l0))] |
| 959 | dma_trait!(UpDma, BasicInstance); | 223 | #[allow(unused)] |
| 960 | 224 | fn set_moe<T: GeneralInstance4Channel>() { | |
| 961 | dma_trait!(Ch1Dma, CaptureCompare16bitInstance); | 225 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } |
| 962 | dma_trait!(Ch2Dma, CaptureCompare16bitInstance); | 226 | .bdtr() |
| 963 | dma_trait!(Ch3Dma, CaptureCompare16bitInstance); | 227 | .modify(|w| w.set_moe(true)); |
| 964 | dma_trait!(Ch4Dma, CaptureCompare16bitInstance); | 228 | } |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 59efb72ba..ab9879be6 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -3,10 +3,11 @@ | |||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | use stm32_metapac::timer::vals; | ||
| 6 | 7 | ||
| 7 | use super::*; | 8 | use super::low_level::Timer; |
| 8 | use crate::gpio::sealed::AFType; | 9 | use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; |
| 9 | use crate::gpio::AnyPin; | 10 | use crate::gpio::{AFType, AnyPin}; |
| 10 | use crate::Peripheral; | 11 | use crate::Peripheral; |
| 11 | 12 | ||
| 12 | /// Counting direction | 13 | /// Counting direction |
| @@ -30,7 +31,7 @@ pub struct QeiPin<'d, T, Channel> { | |||
| 30 | 31 | ||
| 31 | macro_rules! channel_impl { | 32 | macro_rules! channel_impl { |
| 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 33 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 33 | impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { | 34 | impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { |
| 34 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] | 35 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | 36 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { |
| 36 | into_ref!(pin); | 37 | into_ref!(pin); |
| @@ -53,29 +54,28 @@ channel_impl!(new_ch1, Ch1, Channel1Pin); | |||
| 53 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 54 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
| 54 | 55 | ||
| 55 | /// Quadrature decoder driver. | 56 | /// Quadrature decoder driver. |
| 56 | pub struct Qei<'d, T> { | 57 | pub struct Qei<'d, T: GeneralInstance4Channel> { |
| 57 | _inner: PeripheralRef<'d, T>, | 58 | inner: Timer<'d, T>, |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | 61 | impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { |
| 61 | /// Create a new quadrature decoder driver. | 62 | /// Create a new quadrature decoder driver. |
| 62 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | 63 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { |
| 63 | Self::new_inner(tim) | 64 | Self::new_inner(tim) |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { | 67 | fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { |
| 67 | into_ref!(tim); | 68 | let inner = Timer::new(tim); |
| 68 | 69 | let r = inner.regs_gp16(); | |
| 69 | T::enable_and_reset(); | ||
| 70 | 70 | ||
| 71 | // Configure TxC1 and TxC2 as captures | 71 | // Configure TxC1 and TxC2 as captures |
| 72 | T::regs_gp16().ccmr_input(0).modify(|w| { | 72 | r.ccmr_input(0).modify(|w| { |
| 73 | w.set_ccs(0, vals::CcmrInputCcs::TI4); | 73 | w.set_ccs(0, vals::CcmrInputCcs::TI4); |
| 74 | w.set_ccs(1, vals::CcmrInputCcs::TI4); | 74 | w.set_ccs(1, vals::CcmrInputCcs::TI4); |
| 75 | }); | 75 | }); |
| 76 | 76 | ||
| 77 | // enable and configure to capture on rising edge | 77 | // enable and configure to capture on rising edge |
| 78 | T::regs_gp16().ccer().modify(|w| { | 78 | r.ccer().modify(|w| { |
| 79 | w.set_cce(0, true); | 79 | w.set_cce(0, true); |
| 80 | w.set_cce(1, true); | 80 | w.set_cce(1, true); |
| 81 | 81 | ||
| @@ -83,19 +83,19 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 83 | w.set_ccp(1, false); | 83 | w.set_ccp(1, false); |
| 84 | }); | 84 | }); |
| 85 | 85 | ||
| 86 | T::regs_gp16().smcr().modify(|w| { | 86 | r.smcr().modify(|w| { |
| 87 | w.set_sms(vals::Sms::ENCODER_MODE_3); | 87 | w.set_sms(vals::Sms::ENCODER_MODE_3); |
| 88 | }); | 88 | }); |
| 89 | 89 | ||
| 90 | T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); | 90 | r.arr().modify(|w| w.set_arr(u16::MAX)); |
| 91 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | 91 | r.cr1().modify(|w| w.set_cen(true)); |
| 92 | 92 | ||
| 93 | Self { _inner: tim } | 93 | Self { inner } |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | /// Get direction. | 96 | /// Get direction. |
| 97 | pub fn read_direction(&self) -> Direction { | 97 | pub fn read_direction(&self) -> Direction { |
| 98 | match T::regs_gp16().cr1().read().dir() { | 98 | match self.inner.regs_gp16().cr1().read().dir() { |
| 99 | vals::Dir::DOWN => Direction::Downcounting, | 99 | vals::Dir::DOWN => Direction::Downcounting, |
| 100 | vals::Dir::UP => Direction::Upcounting, | 100 | vals::Dir::UP => Direction::Upcounting, |
| 101 | } | 101 | } |
| @@ -103,6 +103,6 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 103 | 103 | ||
| 104 | /// Get count. | 104 | /// Get count. |
| 105 | pub fn count(&self) -> u16 { | 105 | pub fn count(&self) -> u16 { |
| 106 | T::regs_gp16().cnt().read().cnt() | 106 | self.inner.regs_gp16().cnt().read().cnt() |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1acba504e..b54e9a0d6 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -4,9 +4,8 @@ use core::marker::PhantomData; | |||
| 4 | 4 | ||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | 6 | ||
| 7 | use super::*; | 7 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; |
| 8 | #[allow(unused_imports)] | 8 | use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; |
| 9 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 10 | use crate::gpio::{AnyPin, OutputType}; | 9 | use crate::gpio::{AnyPin, OutputType}; |
| 11 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 11 | use crate::Peripheral; |
| @@ -30,7 +29,7 @@ pub struct PwmPin<'d, T, C> { | |||
| 30 | 29 | ||
| 31 | macro_rules! channel_impl { | 30 | macro_rules! channel_impl { |
| 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 31 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 33 | impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { | 32 | impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { |
| 34 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] | 33 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | 34 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { |
| 36 | into_ref!(pin); | 35 | into_ref!(pin); |
| @@ -55,11 +54,11 @@ channel_impl!(new_ch3, Ch3, Channel3Pin); | |||
| 55 | channel_impl!(new_ch4, Ch4, Channel4Pin); | 54 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
| 56 | 55 | ||
| 57 | /// Simple PWM driver. | 56 | /// Simple PWM driver. |
| 58 | pub struct SimplePwm<'d, T> { | 57 | pub struct SimplePwm<'d, T: GeneralInstance4Channel> { |
| 59 | inner: PeripheralRef<'d, T>, | 58 | inner: Timer<'d, T>, |
| 60 | } | 59 | } |
| 61 | 60 | ||
| 62 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 61 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 63 | /// Create a new simple PWM driver. | 62 | /// Create a new simple PWM driver. |
| 64 | pub fn new( | 63 | pub fn new( |
| 65 | tim: impl Peripheral<P = T> + 'd, | 64 | tim: impl Peripheral<P = T> + 'd, |
| @@ -74,14 +73,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 74 | } | 73 | } |
| 75 | 74 | ||
| 76 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { | 75 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { |
| 77 | into_ref!(tim); | 76 | let mut this = Self { inner: Timer::new(tim) }; |
| 78 | |||
| 79 | T::enable_and_reset(); | ||
| 80 | |||
| 81 | let mut this = Self { inner: tim }; | ||
| 82 | 77 | ||
| 83 | this.inner.set_counting_mode(counting_mode); | 78 | this.inner.set_counting_mode(counting_mode); |
| 84 | this.set_frequency(freq); | 79 | this.set_frequency(freq); |
| 80 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | ||
| 85 | this.inner.start(); | 81 | this.inner.start(); |
| 86 | 82 | ||
| 87 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 83 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| @@ -126,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 126 | /// Get max duty value. | 122 | /// Get max duty value. |
| 127 | /// | 123 | /// |
| 128 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 129 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u32 { |
| 130 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 131 | } | 127 | } |
| 132 | 128 | ||
| 133 | /// Set the duty for a given channel. | 129 | /// Set the duty for a given channel. |
| 134 | /// | 130 | /// |
| 135 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 136 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 137 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 138 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 139 | } | 135 | } |
| @@ -141,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 141 | /// Get the duty for a given channel. | 137 | /// Get the duty for a given channel. |
| 142 | /// | 138 | /// |
| 143 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 139 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 144 | pub fn get_duty(&self, channel: Channel) -> u16 { | 140 | pub fn get_duty(&self, channel: Channel) -> u32 { |
| 145 | self.inner.get_compare_value(channel) | 141 | self.inner.get_compare_value(channel) |
| 146 | } | 142 | } |
| 147 | 143 | ||
| @@ -165,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 165 | channel: Channel, | 161 | channel: Channel, |
| 166 | duty: &[u16], | 162 | duty: &[u16], |
| 167 | ) { | 163 | ) { |
| 168 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 169 | |||
| 170 | into_ref!(dma); | 164 | into_ref!(dma); |
| 171 | 165 | ||
| 172 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 166 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| @@ -201,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 201 | &mut dma, | 195 | &mut dma, |
| 202 | req, | 196 | req, |
| 203 | duty, | 197 | duty, |
| 204 | T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, | 198 | self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, |
| 205 | dma_transfer_option, | 199 | dma_transfer_option, |
| 206 | ) | 200 | ) |
| 207 | .await | 201 | .await |
| @@ -227,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 227 | 221 | ||
| 228 | macro_rules! impl_waveform_chx { | 222 | macro_rules! impl_waveform_chx { |
| 229 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { | 223 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { |
| 230 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 224 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 231 | /// Generate a sequence of PWM waveform | 225 | /// Generate a sequence of PWM waveform |
| 232 | /// | 226 | /// |
| 233 | /// Note: | 227 | /// Note: |
| 234 | /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. | 228 | /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. |
| 235 | pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { | 229 | pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { |
| 236 | use super::vals::Ccds; | 230 | use crate::pac::timer::vals::Ccds; |
| 237 | |||
| 238 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 239 | 231 | ||
| 240 | into_ref!(dma); | 232 | into_ref!(dma); |
| 241 | 233 | ||
| 242 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 234 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 243 | let req = dma.request(); | 235 | let req = dma.request(); |
| 244 | 236 | ||
| 245 | let cc_channel = super::Channel::$cc_ch; | 237 | let cc_channel = Channel::$cc_ch; |
| 246 | 238 | ||
| 247 | let original_duty_state = self.get_duty(cc_channel); | 239 | let original_duty_state = self.get_duty(cc_channel); |
| 248 | let original_enable_state = self.is_enabled(cc_channel); | 240 | let original_enable_state = self.is_enabled(cc_channel); |
| @@ -279,7 +271,7 @@ macro_rules! impl_waveform_chx { | |||
| 279 | &mut dma, | 271 | &mut dma, |
| 280 | req, | 272 | req, |
| 281 | duty, | 273 | duty, |
| 282 | T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, | 274 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, |
| 283 | dma_transfer_option, | 275 | dma_transfer_option, |
| 284 | ) | 276 | ) |
| 285 | .await | 277 | .await |
| @@ -314,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); | |||
| 314 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); | 306 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); |
| 315 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); | 307 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); |
| 316 | 308 | ||
| 317 | impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { | 309 | impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { |
| 318 | type Channel = Channel; | 310 | type Channel = Channel; |
| 319 | type Time = Hertz; | 311 | type Time = Hertz; |
| 320 | type Duty = u16; | 312 | type Duty = u32; |
| 321 | 313 | ||
| 322 | fn disable(&mut self, channel: Self::Channel) { | 314 | fn disable(&mut self, channel: Self::Channel) { |
| 323 | self.inner.enable_channel(channel, false); | 315 | self.inner.enable_channel(channel, false); |
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs new file mode 100644 index 000000000..fe614b811 --- /dev/null +++ b/embassy-stm32/src/ucpd.rs | |||
| @@ -0,0 +1,607 @@ | |||
| 1 | //! USB Type-C/USB Power Delivery Interface (UCPD) | ||
| 2 | |||
| 3 | // Implementation Notes | ||
| 4 | // | ||
| 5 | // As of Feb. 2024 the UCPD peripheral is availalbe on: G0, G4, H5, L5, U5 | ||
| 6 | // | ||
| 7 | // Cube HAL LL Driver (g0): | ||
| 8 | // https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Inc/stm32g0xx_ll_ucpd.h | ||
| 9 | // https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Src/stm32g0xx_ll_ucpd.c | ||
| 10 | // Except for a the `LL_UCPD_RxAnalogFilterEnable/Disable()` functions the Cube HAL implementation of | ||
| 11 | // all families is the same. | ||
| 12 | // | ||
| 13 | // Dead battery pull-down resistors functionality is enabled by default on startup and must | ||
| 14 | // be disabled by setting a bit in PWR/SYSCFG registers. The exact name and location for that | ||
| 15 | // bit is different for each familily. | ||
| 16 | |||
| 17 | use core::future::poll_fn; | ||
| 18 | use core::marker::PhantomData; | ||
| 19 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 20 | use core::task::Poll; | ||
| 21 | |||
| 22 | use embassy_hal_internal::drop::OnDrop; | ||
| 23 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 24 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 25 | |||
| 26 | use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; | ||
| 27 | use crate::interrupt; | ||
| 28 | use crate::interrupt::typelevel::Interrupt; | ||
| 29 | use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; | ||
| 30 | pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; | ||
| 31 | use crate::rcc::RccPeripheral; | ||
| 32 | |||
| 33 | pub(crate) fn init( | ||
| 34 | _cs: critical_section::CriticalSection, | ||
| 35 | #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, | ||
| 36 | #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, | ||
| 37 | ) { | ||
| 38 | #[cfg(stm32g0x1)] | ||
| 39 | { | ||
| 40 | // according to RM0444 (STM32G0x1) section 8.1.1: | ||
| 41 | // when UCPD is disabled setting the strobe will disable dead battery | ||
| 42 | // (which is enabled after reset) but if UCPD is enabled, setting the | ||
| 43 | // strobe will apply the CC pin configuration from the control register | ||
| 44 | // (which is why we need to be careful about when we call this) | ||
| 45 | crate::pac::SYSCFG.cfgr1().modify(|w| { | ||
| 46 | w.set_ucpd1_strobe(!ucpd1_db_enable); | ||
| 47 | w.set_ucpd2_strobe(!ucpd2_db_enable); | ||
| 48 | }); | ||
| 49 | } | ||
| 50 | |||
| 51 | #[cfg(any(stm32g4, stm32l5))] | ||
| 52 | { | ||
| 53 | crate::pac::PWR.cr3().modify(|w| { | ||
| 54 | #[cfg(stm32g4)] | ||
| 55 | w.set_ucpd1_dbdis(!ucpd1_db_enable); | ||
| 56 | #[cfg(stm32l5)] | ||
| 57 | w.set_ucpd_dbdis(!ucpd1_db_enable); | ||
| 58 | }) | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg(any(stm32h5, stm32u5))] | ||
| 62 | { | ||
| 63 | crate::pac::PWR.ucpdr().modify(|w| { | ||
| 64 | w.set_ucpd_dbdis(!ucpd1_db_enable); | ||
| 65 | }) | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Pull-up or Pull-down resistor state of both CC lines. | ||
| 70 | #[derive(Debug, Clone, Copy, PartialEq)] | ||
| 71 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 72 | pub enum CcPull { | ||
| 73 | /// Analog PHY for CC pin disabled. | ||
| 74 | Disabled, | ||
| 75 | |||
| 76 | /// Rd=5.1k pull-down resistor. | ||
| 77 | Sink, | ||
| 78 | |||
| 79 | /// Rp=56k pull-up resistor to indicate default USB power. | ||
| 80 | SourceDefaultUsb, | ||
| 81 | |||
| 82 | /// Rp=22k pull-up resistor to indicate support for up to 1.5A. | ||
| 83 | Source1_5A, | ||
| 84 | |||
| 85 | /// Rp=10k pull-up resistor to indicate support for up to 3.0A. | ||
| 86 | Source3_0A, | ||
| 87 | } | ||
| 88 | |||
| 89 | /// UCPD driver. | ||
| 90 | pub struct Ucpd<'d, T: Instance> { | ||
| 91 | cc_phy: CcPhy<'d, T>, | ||
| 92 | } | ||
| 93 | |||
| 94 | impl<'d, T: Instance> Ucpd<'d, T> { | ||
| 95 | /// Creates a new UCPD driver instance. | ||
| 96 | pub fn new( | ||
| 97 | _peri: impl Peripheral<P = T> + 'd, | ||
| 98 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 99 | cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd, | ||
| 100 | cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd, | ||
| 101 | ) -> Self { | ||
| 102 | into_ref!(cc1, cc2); | ||
| 103 | cc1.set_as_analog(); | ||
| 104 | cc2.set_as_analog(); | ||
| 105 | |||
| 106 | T::enable_and_reset(); | ||
| 107 | T::Interrupt::unpend(); | ||
| 108 | unsafe { T::Interrupt::enable() }; | ||
| 109 | |||
| 110 | let r = T::REGS; | ||
| 111 | r.cfgr1().write(|w| { | ||
| 112 | // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz. | ||
| 113 | // However, the optimum performance is ensured in the range from 6 to 12 MHz" | ||
| 114 | // UCPD is driven by HSI16 (16MHz internal oscillator), which we need to divide by 2. | ||
| 115 | w.set_psc_usbpdclk(PscUsbpdclk::DIV2); | ||
| 116 | |||
| 117 | // Prescaler to produce a target half-bit frequency of 600kHz which is required | ||
| 118 | // to produce transmit with a nominal nominal bit rate of 300Kbps+-10% using | ||
| 119 | // biphase mark coding (BMC, aka differential manchester coding). | ||
| 120 | // A divider of 13 gives the target frequency closest to spec (~615kHz, 1.625us). | ||
| 121 | w.set_hbitclkdiv(13 - 1); | ||
| 122 | |||
| 123 | // Time window for detecting non-idle (12-20us). | ||
| 124 | // 1.75us * 8 = 14us. | ||
| 125 | w.set_transwin(8 - 1); | ||
| 126 | |||
| 127 | // Time from the end of last bit of a Frame until the start of the first bit of the | ||
| 128 | // next Preamble (min 25us). | ||
| 129 | // 1.75us * 17 = ~30us | ||
| 130 | w.set_ifrgap(17 - 1); | ||
| 131 | |||
| 132 | // TODO: Currently only hard reset and SOP messages can be received. | ||
| 133 | // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). | ||
| 134 | w.set_rxordseten(0b1001); | ||
| 135 | |||
| 136 | // Enable DMA | ||
| 137 | w.set_txdmaen(true); | ||
| 138 | w.set_rxdmaen(true); | ||
| 139 | |||
| 140 | w.set_ucpden(true); | ||
| 141 | }); | ||
| 142 | |||
| 143 | Self { | ||
| 144 | cc_phy: CcPhy { _lifetime: PhantomData }, | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /// Returns the TypeC CC PHY. | ||
| 149 | pub fn cc_phy(&mut self) -> &mut CcPhy<'d, T> { | ||
| 150 | &mut self.cc_phy | ||
| 151 | } | ||
| 152 | |||
| 153 | /// Splits the UCPD driver into a TypeC PHY to control and monitor CC voltage | ||
| 154 | /// and a Power Delivery (PD) PHY with receiver and transmitter. | ||
| 155 | pub fn split_pd_phy( | ||
| 156 | self, | ||
| 157 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, | ||
| 158 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, | ||
| 159 | cc_sel: CcSel, | ||
| 160 | ) -> (CcPhy<'d, T>, PdPhy<'d, T>) { | ||
| 161 | let r = T::REGS; | ||
| 162 | |||
| 163 | // TODO: Currently only SOP messages are supported. | ||
| 164 | r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); | ||
| 165 | |||
| 166 | // Enable the receiver on one of the two CC lines. | ||
| 167 | r.cr().modify(|w| w.set_phyccsel(cc_sel)); | ||
| 168 | |||
| 169 | // Enable hard reset receive interrupt. | ||
| 170 | r.imr().modify(|w| w.set_rxhrstdetie(true)); | ||
| 171 | |||
| 172 | // Both parts must be dropped before the peripheral can be disabled. | ||
| 173 | T::state().drop_not_ready.store(true, Ordering::Relaxed); | ||
| 174 | |||
| 175 | into_ref!(rx_dma, tx_dma); | ||
| 176 | let rx_dma_req = rx_dma.request(); | ||
| 177 | let tx_dma_req = tx_dma.request(); | ||
| 178 | ( | ||
| 179 | self.cc_phy, | ||
| 180 | PdPhy { | ||
| 181 | _lifetime: PhantomData, | ||
| 182 | rx_dma_ch: rx_dma.map_into(), | ||
| 183 | rx_dma_req, | ||
| 184 | tx_dma_ch: tx_dma.map_into(), | ||
| 185 | tx_dma_req, | ||
| 186 | }, | ||
| 187 | ) | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | /// Control and monitoring of TypeC CC pin functionailty. | ||
| 192 | pub struct CcPhy<'d, T: Instance> { | ||
| 193 | _lifetime: PhantomData<&'d mut T>, | ||
| 194 | } | ||
| 195 | |||
| 196 | impl<'d, T: Instance> Drop for CcPhy<'d, T> { | ||
| 197 | fn drop(&mut self) { | ||
| 198 | let r = T::REGS; | ||
| 199 | r.cr().modify(|w| { | ||
| 200 | w.set_cc1tcdis(true); | ||
| 201 | w.set_cc2tcdis(true); | ||
| 202 | w.set_ccenable(Ccenable::DISABLED); | ||
| 203 | }); | ||
| 204 | |||
| 205 | // Check if the PdPhy part was dropped already. | ||
| 206 | let drop_not_ready = &T::state().drop_not_ready; | ||
| 207 | if drop_not_ready.load(Ordering::Relaxed) { | ||
| 208 | drop_not_ready.store(true, Ordering::Relaxed); | ||
| 209 | } else { | ||
| 210 | r.cfgr1().write(|w| w.set_ucpden(false)); | ||
| 211 | T::disable(); | ||
| 212 | T::Interrupt::disable(); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<'d, T: Instance> CcPhy<'d, T> { | ||
| 218 | /// Sets the pull-up/pull-down resistor values exposed on the CC pins. | ||
| 219 | pub fn set_pull(&mut self, cc_pull: CcPull) { | ||
| 220 | T::REGS.cr().modify(|w| { | ||
| 221 | w.set_anamode(if cc_pull == CcPull::Sink { | ||
| 222 | Anamode::SINK | ||
| 223 | } else { | ||
| 224 | Anamode::SOURCE | ||
| 225 | }); | ||
| 226 | w.set_anasubmode(match cc_pull { | ||
| 227 | CcPull::SourceDefaultUsb => 1, | ||
| 228 | CcPull::Source1_5A => 2, | ||
| 229 | CcPull::Source3_0A => 3, | ||
| 230 | _ => 0, | ||
| 231 | }); | ||
| 232 | w.set_ccenable(if cc_pull == CcPull::Disabled { | ||
| 233 | Ccenable::DISABLED | ||
| 234 | } else { | ||
| 235 | Ccenable::BOTH | ||
| 236 | }); | ||
| 237 | }); | ||
| 238 | |||
| 239 | // Disable dead-battery pull-down resistors which are enabled by default on boot. | ||
| 240 | critical_section::with(|cs| { | ||
| 241 | init( | ||
| 242 | cs, | ||
| 243 | false, | ||
| 244 | #[cfg(peri_ucpd2)] | ||
| 245 | false, | ||
| 246 | ); | ||
| 247 | }); | ||
| 248 | } | ||
| 249 | |||
| 250 | /// Returns the current voltage level of CC1 and CC2 pin as tuple. | ||
| 251 | /// | ||
| 252 | /// Interpretation of the voltage levels depends on the configured CC line | ||
| 253 | /// pull-up/pull-down resistance. | ||
| 254 | pub fn vstate(&self) -> (CcVState, CcVState) { | ||
| 255 | let sr = T::REGS.sr().read(); | ||
| 256 | (sr.typec_vstate_cc1(), sr.typec_vstate_cc2()) | ||
| 257 | } | ||
| 258 | |||
| 259 | /// Waits for a change in voltage state on either CC line. | ||
| 260 | pub async fn wait_for_vstate_change(&self) -> (CcVState, CcVState) { | ||
| 261 | let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false)); | ||
| 262 | let prev_vstate = self.vstate(); | ||
| 263 | poll_fn(|cx| { | ||
| 264 | let vstate = self.vstate(); | ||
| 265 | if vstate != prev_vstate { | ||
| 266 | Poll::Ready(vstate) | ||
| 267 | } else { | ||
| 268 | T::state().waker.register(cx.waker()); | ||
| 269 | self.enable_cc_interrupts(true); | ||
| 270 | Poll::Pending | ||
| 271 | } | ||
| 272 | }) | ||
| 273 | .await | ||
| 274 | } | ||
| 275 | |||
| 276 | fn enable_cc_interrupts(&self, enable: bool) { | ||
| 277 | T::REGS.imr().modify(|w| { | ||
| 278 | w.set_typecevt1ie(enable); | ||
| 279 | w.set_typecevt2ie(enable); | ||
| 280 | }); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | /// Receive Error. | ||
| 285 | #[derive(Debug, Clone, Copy)] | ||
| 286 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 287 | pub enum RxError { | ||
| 288 | /// Incorrect CRC or truncated message (a line becoming static before EOP is met). | ||
| 289 | Crc, | ||
| 290 | |||
| 291 | /// Provided buffer was too small for the received message. | ||
| 292 | Overrun, | ||
| 293 | |||
| 294 | /// Hard Reset received before or during reception. | ||
| 295 | HardReset, | ||
| 296 | } | ||
| 297 | |||
| 298 | /// Transmit Error. | ||
| 299 | #[derive(Debug, Clone, Copy)] | ||
| 300 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 301 | pub enum TxError { | ||
| 302 | /// Concurrent receive in progress or excessive noise on the line. | ||
| 303 | Discarded, | ||
| 304 | |||
| 305 | /// Hard Reset received before or during transmission. | ||
| 306 | HardReset, | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Power Delivery (PD) PHY. | ||
| 310 | pub struct PdPhy<'d, T: Instance> { | ||
| 311 | _lifetime: PhantomData<&'d mut T>, | ||
| 312 | rx_dma_ch: PeripheralRef<'d, AnyChannel>, | ||
| 313 | rx_dma_req: Request, | ||
| 314 | tx_dma_ch: PeripheralRef<'d, AnyChannel>, | ||
| 315 | tx_dma_req: Request, | ||
| 316 | } | ||
| 317 | |||
| 318 | impl<'d, T: Instance> Drop for PdPhy<'d, T> { | ||
| 319 | fn drop(&mut self) { | ||
| 320 | // Check if the Type-C part was dropped already. | ||
| 321 | let drop_not_ready = &T::state().drop_not_ready; | ||
| 322 | if drop_not_ready.load(Ordering::Relaxed) { | ||
| 323 | drop_not_ready.store(true, Ordering::Relaxed); | ||
| 324 | } else { | ||
| 325 | T::REGS.cfgr1().write(|w| w.set_ucpden(false)); | ||
| 326 | T::disable(); | ||
| 327 | T::Interrupt::disable(); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | impl<'d, T: Instance> PdPhy<'d, T> { | ||
| 333 | /// Receives a PD message into the provided buffer. | ||
| 334 | /// | ||
| 335 | /// Returns the number of received bytes or an error. | ||
| 336 | pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> { | ||
| 337 | let r = T::REGS; | ||
| 338 | |||
| 339 | let dma = unsafe { | ||
| 340 | Transfer::new_read( | ||
| 341 | &self.rx_dma_ch, | ||
| 342 | self.rx_dma_req, | ||
| 343 | r.rxdr().as_ptr() as *mut u8, | ||
| 344 | buf, | ||
| 345 | TransferOptions::default(), | ||
| 346 | ) | ||
| 347 | }; | ||
| 348 | |||
| 349 | // Clear interrupt flags (possibly set from last receive). | ||
| 350 | r.icr().write(|w| { | ||
| 351 | w.set_rxorddetcf(true); | ||
| 352 | w.set_rxovrcf(true); | ||
| 353 | w.set_rxmsgendcf(true); | ||
| 354 | }); | ||
| 355 | |||
| 356 | r.cr().modify(|w| w.set_phyrxen(true)); | ||
| 357 | let _on_drop = OnDrop::new(|| { | ||
| 358 | r.cr().modify(|w| w.set_phyrxen(false)); | ||
| 359 | self.enable_rx_interrupt(false); | ||
| 360 | }); | ||
| 361 | |||
| 362 | poll_fn(|cx| { | ||
| 363 | let sr = r.sr().read(); | ||
| 364 | if sr.rxhrstdet() { | ||
| 365 | // Clean and re-enable hard reset receive interrupt. | ||
| 366 | r.icr().write(|w| w.set_rxhrstdetcf(true)); | ||
| 367 | r.imr().modify(|w| w.set_rxhrstdetie(true)); | ||
| 368 | Poll::Ready(Err(RxError::HardReset)) | ||
| 369 | } else if sr.rxmsgend() { | ||
| 370 | let ret = if sr.rxovr() { | ||
| 371 | Err(RxError::Overrun) | ||
| 372 | } else if sr.rxerr() { | ||
| 373 | Err(RxError::Crc) | ||
| 374 | } else { | ||
| 375 | Ok(()) | ||
| 376 | }; | ||
| 377 | Poll::Ready(ret) | ||
| 378 | } else { | ||
| 379 | T::state().waker.register(cx.waker()); | ||
| 380 | self.enable_rx_interrupt(true); | ||
| 381 | Poll::Pending | ||
| 382 | } | ||
| 383 | }) | ||
| 384 | .await?; | ||
| 385 | |||
| 386 | // Make sure that the last byte was fetched by DMA. | ||
| 387 | while r.sr().read().rxne() { | ||
| 388 | if dma.get_remaining_transfers() == 0 { | ||
| 389 | return Err(RxError::Overrun); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | Ok(r.rx_payszr().read().rxpaysz().into()) | ||
| 394 | } | ||
| 395 | |||
| 396 | fn enable_rx_interrupt(&self, enable: bool) { | ||
| 397 | T::REGS.imr().modify(|w| w.set_rxmsgendie(enable)); | ||
| 398 | } | ||
| 399 | |||
| 400 | /// Transmits a PD message. | ||
| 401 | pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> { | ||
| 402 | let r = T::REGS; | ||
| 403 | |||
| 404 | // When a previous transmission was dropped before it had finished it | ||
| 405 | // might still be running because there is no way to abort an ongoing | ||
| 406 | // message transmission. Wait for it to finish but ignore errors. | ||
| 407 | if r.cr().read().txsend() { | ||
| 408 | if let Err(TxError::HardReset) = self.wait_tx_done().await { | ||
| 409 | return Err(TxError::HardReset); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | // Clear the TX interrupt flags. | ||
| 414 | T::REGS.icr().write(|w| { | ||
| 415 | w.set_txmsgdisccf(true); | ||
| 416 | w.set_txmsgsentcf(true); | ||
| 417 | }); | ||
| 418 | |||
| 419 | // Start the DMA and let it do its thing in the background. | ||
| 420 | let _dma = unsafe { | ||
| 421 | Transfer::new_write( | ||
| 422 | &self.tx_dma_ch, | ||
| 423 | self.tx_dma_req, | ||
| 424 | buf, | ||
| 425 | r.txdr().as_ptr() as *mut u8, | ||
| 426 | TransferOptions::default(), | ||
| 427 | ) | ||
| 428 | }; | ||
| 429 | |||
| 430 | // Configure and start the transmission. | ||
| 431 | r.tx_payszr().write(|w| w.set_txpaysz(buf.len() as _)); | ||
| 432 | r.cr().modify(|w| { | ||
| 433 | w.set_txmode(Txmode::PACKET); | ||
| 434 | w.set_txsend(true); | ||
| 435 | }); | ||
| 436 | |||
| 437 | self.wait_tx_done().await | ||
| 438 | } | ||
| 439 | |||
| 440 | async fn wait_tx_done(&self) -> Result<(), TxError> { | ||
| 441 | let _on_drop = OnDrop::new(|| self.enable_tx_interrupts(false)); | ||
| 442 | poll_fn(|cx| { | ||
| 443 | let r = T::REGS; | ||
| 444 | let sr = r.sr().read(); | ||
| 445 | if sr.rxhrstdet() { | ||
| 446 | // Clean and re-enable hard reset receive interrupt. | ||
| 447 | r.icr().write(|w| w.set_rxhrstdetcf(true)); | ||
| 448 | r.imr().modify(|w| w.set_rxhrstdetie(true)); | ||
| 449 | Poll::Ready(Err(TxError::HardReset)) | ||
| 450 | } else if sr.txmsgdisc() { | ||
| 451 | Poll::Ready(Err(TxError::Discarded)) | ||
| 452 | } else if sr.txmsgsent() { | ||
| 453 | Poll::Ready(Ok(())) | ||
| 454 | } else { | ||
| 455 | T::state().waker.register(cx.waker()); | ||
| 456 | self.enable_tx_interrupts(true); | ||
| 457 | Poll::Pending | ||
| 458 | } | ||
| 459 | }) | ||
| 460 | .await | ||
| 461 | } | ||
| 462 | |||
| 463 | fn enable_tx_interrupts(&self, enable: bool) { | ||
| 464 | T::REGS.imr().modify(|w| { | ||
| 465 | w.set_txmsgdiscie(enable); | ||
| 466 | w.set_txmsgsentie(enable); | ||
| 467 | }); | ||
| 468 | } | ||
| 469 | |||
| 470 | /// Transmit a hard reset. | ||
| 471 | pub async fn transmit_hardreset(&mut self) -> Result<(), TxError> { | ||
| 472 | let r = T::REGS; | ||
| 473 | |||
| 474 | // Clear the hardreset interrupt flags. | ||
| 475 | T::REGS.icr().write(|w| { | ||
| 476 | w.set_hrstdisccf(true); | ||
| 477 | w.set_hrstsentcf(true); | ||
| 478 | }); | ||
| 479 | |||
| 480 | // Trigger hard reset transmission. | ||
| 481 | r.cr().modify(|w| { | ||
| 482 | w.set_txhrst(true); | ||
| 483 | }); | ||
| 484 | |||
| 485 | let _on_drop = OnDrop::new(|| self.enable_hardreset_interrupts(false)); | ||
| 486 | poll_fn(|cx| { | ||
| 487 | let r = T::REGS; | ||
| 488 | let sr = r.sr().read(); | ||
| 489 | if sr.rxhrstdet() { | ||
| 490 | // Clean and re-enable hard reset receive interrupt. | ||
| 491 | r.icr().write(|w| w.set_rxhrstdetcf(true)); | ||
| 492 | r.imr().modify(|w| w.set_rxhrstdetie(true)); | ||
| 493 | Poll::Ready(Err(TxError::HardReset)) | ||
| 494 | } else if sr.hrstdisc() { | ||
| 495 | Poll::Ready(Err(TxError::Discarded)) | ||
| 496 | } else if sr.hrstsent() { | ||
| 497 | Poll::Ready(Ok(())) | ||
| 498 | } else { | ||
| 499 | T::state().waker.register(cx.waker()); | ||
| 500 | self.enable_hardreset_interrupts(true); | ||
| 501 | Poll::Pending | ||
| 502 | } | ||
| 503 | }) | ||
| 504 | .await | ||
| 505 | } | ||
| 506 | |||
| 507 | fn enable_hardreset_interrupts(&self, enable: bool) { | ||
| 508 | T::REGS.imr().modify(|w| { | ||
| 509 | w.set_hrstdiscie(enable); | ||
| 510 | w.set_hrstsentie(enable); | ||
| 511 | }); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | /// Interrupt handler. | ||
| 516 | pub struct InterruptHandler<T: Instance> { | ||
| 517 | _phantom: PhantomData<T>, | ||
| 518 | } | ||
| 519 | |||
| 520 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 521 | unsafe fn on_interrupt() { | ||
| 522 | let r = T::REGS; | ||
| 523 | let sr = r.sr().read(); | ||
| 524 | |||
| 525 | if sr.typecevt1() || sr.typecevt2() { | ||
| 526 | r.icr().write(|w| { | ||
| 527 | w.set_typecevt1cf(true); | ||
| 528 | w.set_typecevt2cf(true); | ||
| 529 | }); | ||
| 530 | } | ||
| 531 | |||
| 532 | if sr.rxhrstdet() { | ||
| 533 | r.imr().modify(|w| w.set_rxhrstdetie(false)); | ||
| 534 | } | ||
| 535 | |||
| 536 | if sr.rxmsgend() { | ||
| 537 | r.imr().modify(|w| w.set_rxmsgendie(false)); | ||
| 538 | } | ||
| 539 | |||
| 540 | if sr.txmsgdisc() || sr.txmsgsent() { | ||
| 541 | r.imr().modify(|w| { | ||
| 542 | w.set_txmsgdiscie(false); | ||
| 543 | w.set_txmsgsentie(false); | ||
| 544 | }); | ||
| 545 | } | ||
| 546 | |||
| 547 | if sr.hrstdisc() || sr.hrstsent() { | ||
| 548 | r.imr().modify(|w| { | ||
| 549 | w.set_hrstdiscie(false); | ||
| 550 | w.set_hrstsentie(false); | ||
| 551 | }); | ||
| 552 | } | ||
| 553 | |||
| 554 | // Wake the task to clear and re-enabled interrupts. | ||
| 555 | T::state().waker.wake(); | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | struct State { | ||
| 560 | waker: AtomicWaker, | ||
| 561 | // Inverted logic for a default state of 0 so that the data goes into the .bss section. | ||
| 562 | drop_not_ready: AtomicBool, | ||
| 563 | } | ||
| 564 | |||
| 565 | impl State { | ||
| 566 | pub const fn new() -> Self { | ||
| 567 | Self { | ||
| 568 | waker: AtomicWaker::new(), | ||
| 569 | drop_not_ready: AtomicBool::new(false), | ||
| 570 | } | ||
| 571 | } | ||
| 572 | } | ||
| 573 | |||
| 574 | trait SealedInstance { | ||
| 575 | const REGS: crate::pac::ucpd::Ucpd; | ||
| 576 | fn state() -> &'static State; | ||
| 577 | } | ||
| 578 | |||
| 579 | /// UCPD instance trait. | ||
| 580 | #[allow(private_bounds)] | ||
| 581 | pub trait Instance: SealedInstance + RccPeripheral { | ||
| 582 | /// Interrupt for this instance. | ||
| 583 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 584 | } | ||
| 585 | |||
| 586 | foreach_interrupt!( | ||
| 587 | ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => { | ||
| 588 | impl SealedInstance for crate::peripherals::$inst { | ||
| 589 | const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; | ||
| 590 | |||
| 591 | fn state() -> &'static State { | ||
| 592 | static STATE: State = State::new(); | ||
| 593 | &STATE | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | impl Instance for crate::peripherals::$inst { | ||
| 598 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 599 | } | ||
| 600 | }; | ||
| 601 | ); | ||
| 602 | |||
| 603 | pin_trait!(Cc1Pin, Instance); | ||
| 604 | pin_trait!(Cc2Pin, Instance); | ||
| 605 | |||
| 606 | dma_trait!(TxDma, Instance); | ||
| 607 | dma_trait!(RxDma, Instance); | ||
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index aa13586f8..5e38532bd 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs | |||
| @@ -27,5 +27,5 @@ pub fn uid_hex_bytes() -> &'static [u8; 24] { | |||
| 27 | LOADED = true; | 27 | LOADED = true; |
| 28 | } | 28 | } |
| 29 | }); | 29 | }); |
| 30 | unsafe { &UID_HEX } | 30 | unsafe { &*core::ptr::addr_of!(UID_HEX) } |
| 31 | } | 31 | } |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c11e3382f..51862e185 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -1,13 +1,10 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::slice; | 1 | use core::slice; |
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | 2 | use core::sync::atomic::AtomicBool; |
| 4 | use core::task::Poll; | ||
| 5 | 3 | ||
| 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 4 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 5 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 6 | ||
| 9 | use super::*; | 7 | use super::*; |
| 10 | use crate::interrupt::typelevel::Interrupt; | ||
| 11 | 8 | ||
| 12 | /// Interrupt handler. | 9 | /// Interrupt handler. |
| 13 | pub struct InterruptHandler<T: BasicInstance> { | 10 | pub struct InterruptHandler<T: BasicInstance> { |
| @@ -55,7 +52,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 55 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. | 52 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. |
| 56 | } | 53 | } |
| 57 | 54 | ||
| 58 | if state.rx_buf.is_full() { | 55 | if !state.rx_buf.is_empty() { |
| 59 | state.rx_waker.wake(); | 56 | state.rx_waker.wake(); |
| 60 | } | 57 | } |
| 61 | } | 58 | } |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ea727b010..7c0523a25 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -10,10 +10,11 @@ use core::task::Poll; | |||
| 10 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_hal_internal::drop::OnDrop; | 11 | use embassy_hal_internal::drop::OnDrop; |
| 12 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 12 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 13 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 13 | use futures::future::{select, Either}; | 14 | use futures::future::{select, Either}; |
| 14 | 15 | ||
| 15 | use crate::dma::{NoDma, Transfer}; | 16 | use crate::dma::{NoDma, Transfer}; |
| 16 | use crate::gpio::sealed::AFType; | 17 | use crate::gpio::AFType; |
| 17 | use crate::interrupt::typelevel::Interrupt; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 18 | #[allow(unused_imports)] | 19 | #[allow(unused_imports)] |
| 19 | #[cfg(not(any(usart_v1, usart_v2)))] | 20 | #[cfg(not(any(usart_v1, usart_v2)))] |
| @@ -208,7 +209,14 @@ enum ReadCompletionEvent { | |||
| 208 | Idle(usize), | 209 | Idle(usize), |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | /// Bidirectional UART Driver | 212 | /// Bidirectional UART Driver, which acts as a combination of [`UartTx`] and [`UartRx`]. |
| 213 | /// | ||
| 214 | /// ### Notes on [`embedded_io::Read`] | ||
| 215 | /// | ||
| 216 | /// `embedded_io::Read` requires guarantees that the base [`UartRx`] cannot provide. | ||
| 217 | /// | ||
| 218 | /// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] | ||
| 219 | /// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. | ||
| 212 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 220 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { |
| 213 | tx: UartTx<'d, T, TxDma>, | 221 | tx: UartTx<'d, T, TxDma>, |
| 214 | rx: UartRx<'d, T, RxDma>, | 222 | rx: UartRx<'d, T, RxDma>, |
| @@ -224,7 +232,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> | |||
| 224 | } | 232 | } |
| 225 | } | 233 | } |
| 226 | 234 | ||
| 227 | /// Tx-only UART Driver | 235 | /// Tx-only UART Driver. |
| 236 | /// | ||
| 237 | /// Can be obtained from [`Uart::split`], or can be constructed independently, | ||
| 238 | /// if you do not need the receiving half of the driver. | ||
| 228 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | 239 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { |
| 229 | phantom: PhantomData<&'d mut T>, | 240 | phantom: PhantomData<&'d mut T>, |
| 230 | tx_dma: PeripheralRef<'d, TxDma>, | 241 | tx_dma: PeripheralRef<'d, TxDma>, |
| @@ -239,7 +250,35 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { | |||
| 239 | } | 250 | } |
| 240 | } | 251 | } |
| 241 | 252 | ||
| 242 | /// Rx-only UART Driver | 253 | /// Rx-only UART Driver. |
| 254 | /// | ||
| 255 | /// Can be obtained from [`Uart::split`], or can be constructed independently, | ||
| 256 | /// if you do not need the transmitting half of the driver. | ||
| 257 | /// | ||
| 258 | /// ### Notes on [`embedded_io::Read`] | ||
| 259 | /// | ||
| 260 | /// `embedded_io::Read` requires guarantees that this struct cannot provide: | ||
| 261 | /// | ||
| 262 | /// - Any data received between calls to [`UartRx::read`] or [`UartRx::blocking_read`] | ||
| 263 | /// will be thrown away, as `UartRx` is unbuffered. | ||
| 264 | /// Users of `embedded_io::Read` are likely to not expect this behavior | ||
| 265 | /// (for instance if they read multiple small chunks in a row). | ||
| 266 | /// - [`UartRx::read`] and [`UartRx::blocking_read`] only return once the entire buffer has been | ||
| 267 | /// filled, whereas `embedded_io::Read` requires us to fill the buffer with what we already | ||
| 268 | /// received, and only block/wait until the first byte arrived. | ||
| 269 | /// <br /> | ||
| 270 | /// While [`UartRx::read_until_idle`] does return early, it will still eagerly wait for data until | ||
| 271 | /// the buffer is full or no data has been transmitted in a while, | ||
| 272 | /// which may not be what users of `embedded_io::Read` expect. | ||
| 273 | /// | ||
| 274 | /// [`UartRx::into_ring_buffered`] can be called to equip `UartRx` with a buffer, | ||
| 275 | /// that it can then use to store data received between calls to `read`, | ||
| 276 | /// provided you are using DMA already. | ||
| 277 | /// | ||
| 278 | /// Alternatively, you can use [`BufferedUartRx`], which is interrupt-based and which can also | ||
| 279 | /// store data received between calls. | ||
| 280 | /// | ||
| 281 | /// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043). | ||
| 243 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 282 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { |
| 244 | _peri: PeripheralRef<'d, T>, | 283 | _peri: PeripheralRef<'d, T>, |
| 245 | rx_dma: PeripheralRef<'d, RxDma>, | 284 | rx_dma: PeripheralRef<'d, RxDma>, |
| @@ -1259,7 +1298,6 @@ where | |||
| 1259 | impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> | 1298 | impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> |
| 1260 | where | 1299 | where |
| 1261 | T: BasicInstance, | 1300 | T: BasicInstance, |
| 1262 | TxDma: crate::usart::TxDma<T>, | ||
| 1263 | { | 1301 | { |
| 1264 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | 1302 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 1265 | self.blocking_write(buf)?; | 1303 | self.blocking_write(buf)?; |
| @@ -1274,7 +1312,6 @@ where | |||
| 1274 | impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> | 1312 | impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> |
| 1275 | where | 1313 | where |
| 1276 | T: BasicInstance, | 1314 | T: BasicInstance, |
| 1277 | TxDma: crate::usart::TxDma<T>, | ||
| 1278 | { | 1315 | { |
| 1279 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | 1316 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 1280 | self.blocking_write(buf)?; | 1317 | self.blocking_write(buf)?; |
| @@ -1326,8 +1363,6 @@ mod ringbuffered; | |||
| 1326 | #[cfg(not(gpdma))] | 1363 | #[cfg(not(gpdma))] |
| 1327 | pub use ringbuffered::RingBufferedUartRx; | 1364 | pub use ringbuffered::RingBufferedUartRx; |
| 1328 | 1365 | ||
| 1329 | use self::sealed::Kind; | ||
| 1330 | |||
| 1331 | #[cfg(any(usart_v1, usart_v2))] | 1366 | #[cfg(any(usart_v1, usart_v2))] |
| 1332 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | 1367 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { |
| 1333 | r.dr().as_ptr() as _ | 1368 | r.dr().as_ptr() as _ |
| @@ -1370,52 +1405,50 @@ fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | |||
| 1370 | r.icr().write(|w| *w = regs::Icr(sr.0)); | 1405 | r.icr().write(|w| *w = regs::Icr(sr.0)); |
| 1371 | } | 1406 | } |
| 1372 | 1407 | ||
| 1373 | pub(crate) mod sealed { | 1408 | #[derive(Clone, Copy, PartialEq, Eq)] |
| 1374 | use embassy_sync::waitqueue::AtomicWaker; | 1409 | enum Kind { |
| 1375 | 1410 | Uart, | |
| 1376 | use super::*; | 1411 | #[cfg(any(usart_v3, usart_v4))] |
| 1377 | 1412 | #[allow(unused)] | |
| 1378 | #[derive(Clone, Copy, PartialEq, Eq)] | 1413 | Lpuart, |
| 1379 | pub enum Kind { | 1414 | } |
| 1380 | Uart, | ||
| 1381 | #[cfg(any(usart_v3, usart_v4))] | ||
| 1382 | Lpuart, | ||
| 1383 | } | ||
| 1384 | 1415 | ||
| 1385 | pub struct State { | 1416 | struct State { |
| 1386 | pub rx_waker: AtomicWaker, | 1417 | rx_waker: AtomicWaker, |
| 1387 | pub tx_waker: AtomicWaker, | 1418 | } |
| 1388 | } | ||
| 1389 | 1419 | ||
| 1390 | impl State { | 1420 | impl State { |
| 1391 | pub const fn new() -> Self { | 1421 | const fn new() -> Self { |
| 1392 | Self { | 1422 | Self { |
| 1393 | rx_waker: AtomicWaker::new(), | 1423 | rx_waker: AtomicWaker::new(), |
| 1394 | tx_waker: AtomicWaker::new(), | ||
| 1395 | } | ||
| 1396 | } | 1424 | } |
| 1397 | } | 1425 | } |
| 1426 | } | ||
| 1398 | 1427 | ||
| 1399 | pub trait BasicInstance: crate::rcc::RccPeripheral { | 1428 | trait SealedBasicInstance: crate::rcc::RccPeripheral { |
| 1400 | const KIND: Kind; | 1429 | const KIND: Kind; |
| 1401 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1402 | 1430 | ||
| 1403 | fn regs() -> Regs; | 1431 | fn regs() -> Regs; |
| 1404 | fn state() -> &'static State; | 1432 | fn state() -> &'static State; |
| 1405 | 1433 | ||
| 1406 | fn buffered_state() -> &'static buffered::State; | 1434 | fn buffered_state() -> &'static buffered::State; |
| 1407 | } | 1435 | } |
| 1408 | 1436 | ||
| 1409 | pub trait FullInstance: BasicInstance { | 1437 | trait SealedFullInstance: SealedBasicInstance { |
| 1410 | fn regs_uart() -> crate::pac::usart::Usart; | 1438 | #[allow(unused)] |
| 1411 | } | 1439 | fn regs_uart() -> crate::pac::usart::Usart; |
| 1412 | } | 1440 | } |
| 1413 | 1441 | ||
| 1414 | /// Basic UART driver instance | 1442 | /// Basic UART driver instance |
| 1415 | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} | 1443 | #[allow(private_bounds)] |
| 1444 | pub trait BasicInstance: Peripheral<P = Self> + SealedBasicInstance + 'static + Send { | ||
| 1445 | /// Interrupt for this instance. | ||
| 1446 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1447 | } | ||
| 1416 | 1448 | ||
| 1417 | /// Full UART driver instance | 1449 | /// Full UART driver instance |
| 1418 | pub trait FullInstance: sealed::FullInstance {} | 1450 | #[allow(private_bounds)] |
| 1451 | pub trait FullInstance: SealedFullInstance {} | ||
| 1419 | 1452 | ||
| 1420 | pin_trait!(RxPin, BasicInstance); | 1453 | pin_trait!(RxPin, BasicInstance); |
| 1421 | pin_trait!(TxPin, BasicInstance); | 1454 | pin_trait!(TxPin, BasicInstance); |
| @@ -1429,16 +1462,15 @@ dma_trait!(RxDma, BasicInstance); | |||
| 1429 | 1462 | ||
| 1430 | macro_rules! impl_usart { | 1463 | macro_rules! impl_usart { |
| 1431 | ($inst:ident, $irq:ident, $kind:expr) => { | 1464 | ($inst:ident, $irq:ident, $kind:expr) => { |
| 1432 | impl sealed::BasicInstance for crate::peripherals::$inst { | 1465 | impl SealedBasicInstance for crate::peripherals::$inst { |
| 1433 | const KIND: Kind = $kind; | 1466 | const KIND: Kind = $kind; |
| 1434 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1435 | 1467 | ||
| 1436 | fn regs() -> Regs { | 1468 | fn regs() -> Regs { |
| 1437 | unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) } | 1469 | unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) } |
| 1438 | } | 1470 | } |
| 1439 | 1471 | ||
| 1440 | fn state() -> &'static crate::usart::sealed::State { | 1472 | fn state() -> &'static crate::usart::State { |
| 1441 | static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); | 1473 | static STATE: crate::usart::State = crate::usart::State::new(); |
| 1442 | &STATE | 1474 | &STATE |
| 1443 | } | 1475 | } |
| 1444 | 1476 | ||
| @@ -1448,7 +1480,9 @@ macro_rules! impl_usart { | |||
| 1448 | } | 1480 | } |
| 1449 | } | 1481 | } |
| 1450 | 1482 | ||
| 1451 | impl BasicInstance for peripherals::$inst {} | 1483 | impl BasicInstance for peripherals::$inst { |
| 1484 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1485 | } | ||
| 1452 | }; | 1486 | }; |
| 1453 | } | 1487 | } |
| 1454 | 1488 | ||
| @@ -1460,7 +1494,7 @@ foreach_interrupt!( | |||
| 1460 | ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { | 1494 | ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { |
| 1461 | impl_usart!($inst, $irq, Kind::Uart); | 1495 | impl_usart!($inst, $irq, Kind::Uart); |
| 1462 | 1496 | ||
| 1463 | impl sealed::FullInstance for peripherals::$inst { | 1497 | impl SealedFullInstance for peripherals::$inst { |
| 1464 | fn regs_uart() -> crate::pac::usart::Usart { | 1498 | fn regs_uart() -> crate::pac::usart::Usart { |
| 1465 | crate::pac::$inst | 1499 | crate::pac::$inst |
| 1466 | } | 1500 | } |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 4debd4e54..1e3c44167 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -1,37 +1,69 @@ | |||
| 1 | //! Universal Serial Bus (USB) | 1 | //! Universal Serial Bus (USB) |
| 2 | 2 | ||
| 3 | use crate::interrupt; | 3 | #[cfg_attr(usb, path = "usb.rs")] |
| 4 | use crate::rcc::RccPeripheral; | 4 | #[cfg_attr(otg, path = "otg.rs")] |
| 5 | mod _version; | ||
| 6 | pub use _version::*; | ||
| 5 | 7 | ||
| 6 | mod usb; | 8 | use crate::interrupt::typelevel::Interrupt; |
| 7 | pub use usb::*; | 9 | use crate::rcc::SealedRccPeripheral; |
| 8 | 10 | ||
| 9 | pub(crate) mod sealed { | 11 | /// clock, power initialization stuff that's common for USB and OTG. |
| 10 | pub trait Instance { | 12 | fn common_init<T: Instance>() { |
| 11 | fn regs() -> crate::pac::usb::Usb; | 13 | // Check the USB clock is enabled and running at exactly 48 MHz. |
| 14 | // frequency() will panic if not enabled | ||
| 15 | let freq = T::frequency(); | ||
| 16 | // Check frequency is within the 0.25% tolerance allowed by the spec. | ||
| 17 | // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user | ||
| 18 | // has tight clock restrictions due to something else (like audio). | ||
| 19 | if freq.0.abs_diff(48_000_000) > 120_000 { | ||
| 20 | panic!( | ||
| 21 | "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", | ||
| 22 | freq.0 | ||
| 23 | ) | ||
| 12 | } | 24 | } |
| 13 | } | ||
| 14 | 25 | ||
| 15 | /// USB instance trait. | 26 | #[cfg(any(stm32l4, stm32l5, stm32wb))] |
| 16 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 27 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); |
| 17 | /// Interrupt for this USB instance. | 28 | |
| 18 | type Interrupt: interrupt::typelevel::Interrupt; | 29 | #[cfg(pwr_h5)] |
| 19 | } | 30 | critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))); |
| 31 | |||
| 32 | #[cfg(stm32h7)] | ||
| 33 | { | ||
| 34 | // If true, VDD33USB is generated by internal regulator from VDD50USB | ||
| 35 | // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||
| 36 | // TODO: unhardcode | ||
| 37 | let internal_regulator = false; | ||
| 38 | |||
| 39 | // Enable USB power | ||
| 40 | critical_section::with(|_| { | ||
| 41 | crate::pac::PWR.cr3().modify(|w| { | ||
| 42 | w.set_usb33den(true); | ||
| 43 | w.set_usbregen(internal_regulator); | ||
| 44 | }) | ||
| 45 | }); | ||
| 46 | |||
| 47 | // Wait for USB power to stabilize | ||
| 48 | while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||
| 49 | } | ||
| 50 | |||
| 51 | #[cfg(stm32u5)] | ||
| 52 | { | ||
| 53 | // Enable USB power | ||
| 54 | critical_section::with(|_| { | ||
| 55 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 56 | w.set_usv(true); | ||
| 57 | w.set_uvmen(true); | ||
| 58 | }) | ||
| 59 | }); | ||
| 60 | |||
| 61 | // Wait for USB power to stabilize | ||
| 62 | while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||
| 63 | } | ||
| 64 | |||
| 65 | T::Interrupt::unpend(); | ||
| 66 | unsafe { T::Interrupt::enable() }; | ||
| 20 | 67 | ||
| 21 | // Internal PHY pins | 68 | <T as SealedRccPeripheral>::enable_and_reset(); |
| 22 | pin_trait!(DpPin, Instance); | 69 | } |
| 23 | pin_trait!(DmPin, Instance); | ||
| 24 | |||
| 25 | foreach_interrupt!( | ||
| 26 | ($inst:ident, usb, $block:ident, LP, $irq:ident) => { | ||
| 27 | impl sealed::Instance for crate::peripherals::$inst { | ||
| 28 | fn regs() -> crate::pac::usb::Usb { | ||
| 29 | crate::pac::$inst | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | impl Instance for crate::peripherals::$inst { | ||
| 34 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | ); | ||
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb/otg.rs index 373697ec8..b0e7067bd 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -6,17 +6,16 @@ use core::task::Poll; | |||
| 6 | use embassy_hal_internal::{into_ref, Peripheral}; | 6 | use embassy_hal_internal::{into_ref, Peripheral}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embassy_usb_driver::{ | 8 | use embassy_usb_driver::{ |
| 9 | self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, | 9 | Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, |
| 10 | EndpointOut, EndpointType, Event, Unsupported, | 10 | EndpointType, Event, Unsupported, |
| 11 | }; | 11 | }; |
| 12 | use futures::future::poll_fn; | 12 | use futures::future::poll_fn; |
| 13 | 13 | ||
| 14 | use super::*; | 14 | use crate::gpio::AFType; |
| 15 | use crate::gpio::sealed::AFType; | ||
| 16 | use crate::interrupt; | 15 | use crate::interrupt; |
| 17 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::otg::{regs, vals}; | 17 | use crate::pac::otg::{regs, vals}; |
| 19 | use crate::rcc::sealed::RccPeripheral; | 18 | use crate::rcc::{RccPeripheral, SealedRccPeripheral}; |
| 20 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| 21 | 20 | ||
| 22 | /// Interrupt handler. | 21 | /// Interrupt handler. |
| @@ -561,8 +560,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 561 | 560 | ||
| 562 | impl<'d, T: Instance> Bus<'d, T> { | 561 | impl<'d, T: Instance> Bus<'d, T> { |
| 563 | fn init(&mut self) { | 562 | fn init(&mut self) { |
| 564 | #[cfg(stm32l4)] | 563 | super::common_init::<T>(); |
| 565 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||
| 566 | 564 | ||
| 567 | #[cfg(stm32f7)] | 565 | #[cfg(stm32f7)] |
| 568 | { | 566 | { |
| @@ -590,22 +588,6 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 590 | 588 | ||
| 591 | #[cfg(stm32h7)] | 589 | #[cfg(stm32h7)] |
| 592 | { | 590 | { |
| 593 | // If true, VDD33USB is generated by internal regulator from VDD50USB | ||
| 594 | // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||
| 595 | // TODO: unhardcode | ||
| 596 | let internal_regulator = false; | ||
| 597 | |||
| 598 | // Enable USB power | ||
| 599 | critical_section::with(|_| { | ||
| 600 | crate::pac::PWR.cr3().modify(|w| { | ||
| 601 | w.set_usb33den(true); | ||
| 602 | w.set_usbregen(internal_regulator); | ||
| 603 | }) | ||
| 604 | }); | ||
| 605 | |||
| 606 | // Wait for USB power to stabilize | ||
| 607 | while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||
| 608 | |||
| 609 | // Enable ULPI clock if external PHY is used | 591 | // Enable ULPI clock if external PHY is used |
| 610 | let ulpien = !self.phy_type.internal(); | 592 | let ulpien = !self.phy_type.internal(); |
| 611 | critical_section::with(|_| { | 593 | critical_section::with(|_| { |
| @@ -626,25 +608,6 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 626 | }); | 608 | }); |
| 627 | } | 609 | } |
| 628 | 610 | ||
| 629 | #[cfg(stm32u5)] | ||
| 630 | { | ||
| 631 | // Enable USB power | ||
| 632 | critical_section::with(|_| { | ||
| 633 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 634 | w.set_usv(true); | ||
| 635 | w.set_uvmen(true); | ||
| 636 | }) | ||
| 637 | }); | ||
| 638 | |||
| 639 | // Wait for USB power to stabilize | ||
| 640 | while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||
| 641 | } | ||
| 642 | |||
| 643 | <T as RccPeripheral>::enable_and_reset(); | ||
| 644 | |||
| 645 | T::Interrupt::unpend(); | ||
| 646 | unsafe { T::Interrupt::enable() }; | ||
| 647 | |||
| 648 | let r = T::regs(); | 611 | let r = T::regs(); |
| 649 | let core_id = r.cid().read().0; | 612 | let core_id = r.cid().read().0; |
| 650 | trace!("Core id {:08x}", core_id); | 613 | trace!("Core id {:08x}", core_id); |
| @@ -846,7 +809,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 846 | fn disable(&mut self) { | 809 | fn disable(&mut self) { |
| 847 | T::Interrupt::disable(); | 810 | T::Interrupt::disable(); |
| 848 | 811 | ||
| 849 | <T as RccPeripheral>::disable(); | 812 | <T as SealedRccPeripheral>::disable(); |
| 850 | 813 | ||
| 851 | #[cfg(stm32l4)] | 814 | #[cfg(stm32l4)] |
| 852 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); | 815 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); |
| @@ -1469,3 +1432,158 @@ fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 { | |||
| 1469 | fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { | 1432 | fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { |
| 1470 | r.cid().read().0 & 0xf000 == 0x1000 | 1433 | r.cid().read().0 & 0xf000 == 0x1000 |
| 1471 | } | 1434 | } |
| 1435 | |||
| 1436 | // Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps | ||
| 1437 | const MAX_EP_COUNT: usize = 9; | ||
| 1438 | |||
| 1439 | trait SealedInstance { | ||
| 1440 | const HIGH_SPEED: bool; | ||
| 1441 | const FIFO_DEPTH_WORDS: u16; | ||
| 1442 | const ENDPOINT_COUNT: usize; | ||
| 1443 | |||
| 1444 | fn regs() -> crate::pac::otg::Otg; | ||
| 1445 | fn state() -> &'static super::State<{ MAX_EP_COUNT }>; | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | /// USB instance trait. | ||
| 1449 | #[allow(private_bounds)] | ||
| 1450 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 1451 | /// Interrupt for this USB instance. | ||
| 1452 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | // Internal PHY pins | ||
| 1456 | pin_trait!(DpPin, Instance); | ||
| 1457 | pin_trait!(DmPin, Instance); | ||
| 1458 | |||
| 1459 | // External PHY pins | ||
| 1460 | pin_trait!(UlpiClkPin, Instance); | ||
| 1461 | pin_trait!(UlpiDirPin, Instance); | ||
| 1462 | pin_trait!(UlpiNxtPin, Instance); | ||
| 1463 | pin_trait!(UlpiStpPin, Instance); | ||
| 1464 | pin_trait!(UlpiD0Pin, Instance); | ||
| 1465 | pin_trait!(UlpiD1Pin, Instance); | ||
| 1466 | pin_trait!(UlpiD2Pin, Instance); | ||
| 1467 | pin_trait!(UlpiD3Pin, Instance); | ||
| 1468 | pin_trait!(UlpiD4Pin, Instance); | ||
| 1469 | pin_trait!(UlpiD5Pin, Instance); | ||
| 1470 | pin_trait!(UlpiD6Pin, Instance); | ||
| 1471 | pin_trait!(UlpiD7Pin, Instance); | ||
| 1472 | |||
| 1473 | foreach_interrupt!( | ||
| 1474 | (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { | ||
| 1475 | impl SealedInstance for crate::peripherals::USB_OTG_FS { | ||
| 1476 | const HIGH_SPEED: bool = false; | ||
| 1477 | |||
| 1478 | cfg_if::cfg_if! { | ||
| 1479 | if #[cfg(stm32f1)] { | ||
| 1480 | const FIFO_DEPTH_WORDS: u16 = 128; | ||
| 1481 | const ENDPOINT_COUNT: usize = 8; | ||
| 1482 | } else if #[cfg(any( | ||
| 1483 | stm32f2, | ||
| 1484 | stm32f401, | ||
| 1485 | stm32f405, | ||
| 1486 | stm32f407, | ||
| 1487 | stm32f411, | ||
| 1488 | stm32f415, | ||
| 1489 | stm32f417, | ||
| 1490 | stm32f427, | ||
| 1491 | stm32f429, | ||
| 1492 | stm32f437, | ||
| 1493 | stm32f439, | ||
| 1494 | ))] { | ||
| 1495 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 1496 | const ENDPOINT_COUNT: usize = 4; | ||
| 1497 | } else if #[cfg(any( | ||
| 1498 | stm32f412, | ||
| 1499 | stm32f413, | ||
| 1500 | stm32f423, | ||
| 1501 | stm32f446, | ||
| 1502 | stm32f469, | ||
| 1503 | stm32f479, | ||
| 1504 | stm32f7, | ||
| 1505 | stm32l4, | ||
| 1506 | stm32u5, | ||
| 1507 | ))] { | ||
| 1508 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 1509 | const ENDPOINT_COUNT: usize = 6; | ||
| 1510 | } else if #[cfg(stm32g0x1)] { | ||
| 1511 | const FIFO_DEPTH_WORDS: u16 = 512; | ||
| 1512 | const ENDPOINT_COUNT: usize = 8; | ||
| 1513 | } else if #[cfg(stm32h7)] { | ||
| 1514 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 1515 | const ENDPOINT_COUNT: usize = 9; | ||
| 1516 | } else if #[cfg(stm32u5)] { | ||
| 1517 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 1518 | const ENDPOINT_COUNT: usize = 6; | ||
| 1519 | } else { | ||
| 1520 | compile_error!("USB_OTG_FS peripheral is not supported by this chip."); | ||
| 1521 | } | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | fn regs() -> crate::pac::otg::Otg { | ||
| 1525 | crate::pac::USB_OTG_FS | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | fn state() -> &'static State<MAX_EP_COUNT> { | ||
| 1529 | static STATE: State<MAX_EP_COUNT> = State::new(); | ||
| 1530 | &STATE | ||
| 1531 | } | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | impl Instance for crate::peripherals::USB_OTG_FS { | ||
| 1535 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1536 | } | ||
| 1537 | }; | ||
| 1538 | |||
| 1539 | (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { | ||
| 1540 | impl SealedInstance for crate::peripherals::USB_OTG_HS { | ||
| 1541 | const HIGH_SPEED: bool = true; | ||
| 1542 | |||
| 1543 | cfg_if::cfg_if! { | ||
| 1544 | if #[cfg(any( | ||
| 1545 | stm32f2, | ||
| 1546 | stm32f405, | ||
| 1547 | stm32f407, | ||
| 1548 | stm32f415, | ||
| 1549 | stm32f417, | ||
| 1550 | stm32f427, | ||
| 1551 | stm32f429, | ||
| 1552 | stm32f437, | ||
| 1553 | stm32f439, | ||
| 1554 | ))] { | ||
| 1555 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 1556 | const ENDPOINT_COUNT: usize = 6; | ||
| 1557 | } else if #[cfg(any( | ||
| 1558 | stm32f446, | ||
| 1559 | stm32f469, | ||
| 1560 | stm32f479, | ||
| 1561 | stm32f7, | ||
| 1562 | stm32h7, | ||
| 1563 | ))] { | ||
| 1564 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 1565 | const ENDPOINT_COUNT: usize = 9; | ||
| 1566 | } else if #[cfg(stm32u5)] { | ||
| 1567 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 1568 | const ENDPOINT_COUNT: usize = 9; | ||
| 1569 | } else { | ||
| 1570 | compile_error!("USB_OTG_HS peripheral is not supported by this chip."); | ||
| 1571 | } | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | fn regs() -> crate::pac::otg::Otg { | ||
| 1575 | // OTG HS registers are a superset of FS registers | ||
| 1576 | unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | fn state() -> &'static State<MAX_EP_COUNT> { | ||
| 1580 | static STATE: State<MAX_EP_COUNT> = State::new(); | ||
| 1581 | &STATE | ||
| 1582 | } | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | impl Instance for crate::peripherals::USB_OTG_HS { | ||
| 1586 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1587 | } | ||
| 1588 | }; | ||
| 1589 | ); | ||
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index be321a19b..f48808cb3 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -12,12 +12,10 @@ use embassy_usb_driver::{ | |||
| 12 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | 12 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, |
| 13 | }; | 13 | }; |
| 14 | 14 | ||
| 15 | use super::{DmPin, DpPin, Instance}; | ||
| 16 | use crate::interrupt::typelevel::Interrupt; | ||
| 17 | use crate::pac::usb::regs; | 15 | use crate::pac::usb::regs; |
| 18 | use crate::pac::usb::vals::{EpType, Stat}; | 16 | use crate::pac::usb::vals::{EpType, Stat}; |
| 19 | use crate::pac::USBRAM; | 17 | use crate::pac::USBRAM; |
| 20 | use crate::rcc::sealed::RccPeripheral; | 18 | use crate::rcc::RccPeripheral; |
| 21 | use crate::{interrupt, Peripheral}; | 19 | use crate::{interrupt, Peripheral}; |
| 22 | 20 | ||
| 23 | /// Interrupt handler. | 21 | /// Interrupt handler. |
| @@ -259,18 +257,10 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 259 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, | 257 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, |
| 260 | ) -> Self { | 258 | ) -> Self { |
| 261 | into_ref!(dp, dm); | 259 | into_ref!(dp, dm); |
| 262 | T::Interrupt::unpend(); | ||
| 263 | unsafe { T::Interrupt::enable() }; | ||
| 264 | 260 | ||
| 265 | let regs = T::regs(); | 261 | super::common_init::<T>(); |
| 266 | |||
| 267 | #[cfg(any(stm32l4, stm32l5, stm32wb))] | ||
| 268 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||
| 269 | |||
| 270 | #[cfg(pwr_h5)] | ||
| 271 | crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); | ||
| 272 | 262 | ||
| 273 | <T as RccPeripheral>::enable_and_reset(); | 263 | let regs = T::regs(); |
| 274 | 264 | ||
| 275 | regs.cntr().write(|w| { | 265 | regs.cntr().write(|w| { |
| 276 | w.set_pdwn(false); | 266 | w.set_pdwn(false); |
| @@ -287,8 +277,8 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 287 | 277 | ||
| 288 | #[cfg(not(stm32l1))] | 278 | #[cfg(not(stm32l1))] |
| 289 | { | 279 | { |
| 290 | dp.set_as_af(dp.af_num(), crate::gpio::sealed::AFType::OutputPushPull); | 280 | dp.set_as_af(dp.af_num(), crate::gpio::AFType::OutputPushPull); |
| 291 | dm.set_as_af(dm.af_num(), crate::gpio::sealed::AFType::OutputPushPull); | 281 | dm.set_as_af(dm.af_num(), crate::gpio::AFType::OutputPushPull); |
| 292 | } | 282 | } |
| 293 | #[cfg(stm32l1)] | 283 | #[cfg(stm32l1)] |
| 294 | let _ = (dp, dm); // suppress "unused" warnings. | 284 | let _ = (dp, dm); // suppress "unused" warnings. |
| @@ -647,7 +637,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 647 | 637 | ||
| 648 | trait Dir { | 638 | trait Dir { |
| 649 | fn dir() -> Direction; | 639 | fn dir() -> Direction; |
| 650 | fn waker(i: usize) -> &'static AtomicWaker; | ||
| 651 | } | 640 | } |
| 652 | 641 | ||
| 653 | /// Marker type for the "IN" direction. | 642 | /// Marker type for the "IN" direction. |
| @@ -656,11 +645,6 @@ impl Dir for In { | |||
| 656 | fn dir() -> Direction { | 645 | fn dir() -> Direction { |
| 657 | Direction::In | 646 | Direction::In |
| 658 | } | 647 | } |
| 659 | |||
| 660 | #[inline] | ||
| 661 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 662 | &EP_IN_WAKERS[i] | ||
| 663 | } | ||
| 664 | } | 648 | } |
| 665 | 649 | ||
| 666 | /// Marker type for the "OUT" direction. | 650 | /// Marker type for the "OUT" direction. |
| @@ -669,11 +653,6 @@ impl Dir for Out { | |||
| 669 | fn dir() -> Direction { | 653 | fn dir() -> Direction { |
| 670 | Direction::Out | 654 | Direction::Out |
| 671 | } | 655 | } |
| 672 | |||
| 673 | #[inline] | ||
| 674 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 675 | &EP_OUT_WAKERS[i] | ||
| 676 | } | ||
| 677 | } | 656 | } |
| 678 | 657 | ||
| 679 | /// USB endpoint. | 658 | /// USB endpoint. |
| @@ -1057,3 +1036,32 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1057 | }); | 1036 | }); |
| 1058 | } | 1037 | } |
| 1059 | } | 1038 | } |
| 1039 | |||
| 1040 | trait SealedInstance { | ||
| 1041 | fn regs() -> crate::pac::usb::Usb; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /// USB instance trait. | ||
| 1045 | #[allow(private_bounds)] | ||
| 1046 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 1047 | /// Interrupt for this USB instance. | ||
| 1048 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | // Internal PHY pins | ||
| 1052 | pin_trait!(DpPin, Instance); | ||
| 1053 | pin_trait!(DmPin, Instance); | ||
| 1054 | |||
| 1055 | foreach_interrupt!( | ||
| 1056 | ($inst:ident, usb, $block:ident, LP, $irq:ident) => { | ||
| 1057 | impl SealedInstance for crate::peripherals::$inst { | ||
| 1058 | fn regs() -> crate::pac::usb::Usb { | ||
| 1059 | crate::pac::$inst | ||
| 1060 | } | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | impl Instance for crate::peripherals::$inst { | ||
| 1064 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1065 | } | ||
| 1066 | }; | ||
| 1067 | ); | ||
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs deleted file mode 100644 index 0649e684b..000000000 --- a/embassy-stm32/src/usb_otg/mod.rs +++ /dev/null | |||
| @@ -1,163 +0,0 @@ | |||
| 1 | //! USB On The Go (OTG) | ||
| 2 | |||
| 3 | use crate::rcc::RccPeripheral; | ||
| 4 | use crate::{interrupt, peripherals}; | ||
| 5 | |||
| 6 | mod usb; | ||
| 7 | pub use usb::*; | ||
| 8 | |||
| 9 | // Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps | ||
| 10 | const MAX_EP_COUNT: usize = 9; | ||
| 11 | |||
| 12 | pub(crate) mod sealed { | ||
| 13 | pub trait Instance { | ||
| 14 | const HIGH_SPEED: bool; | ||
| 15 | const FIFO_DEPTH_WORDS: u16; | ||
| 16 | const ENDPOINT_COUNT: usize; | ||
| 17 | |||
| 18 | fn regs() -> crate::pac::otg::Otg; | ||
| 19 | fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>; | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | /// USB OTG instance. | ||
| 24 | pub trait Instance: sealed::Instance + RccPeripheral { | ||
| 25 | /// Interrupt for this USB OTG instance. | ||
| 26 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 27 | } | ||
| 28 | |||
| 29 | // Internal PHY pins | ||
| 30 | pin_trait!(DpPin, Instance); | ||
| 31 | pin_trait!(DmPin, Instance); | ||
| 32 | |||
| 33 | // External PHY pins | ||
| 34 | pin_trait!(UlpiClkPin, Instance); | ||
| 35 | pin_trait!(UlpiDirPin, Instance); | ||
| 36 | pin_trait!(UlpiNxtPin, Instance); | ||
| 37 | pin_trait!(UlpiStpPin, Instance); | ||
| 38 | pin_trait!(UlpiD0Pin, Instance); | ||
| 39 | pin_trait!(UlpiD1Pin, Instance); | ||
| 40 | pin_trait!(UlpiD2Pin, Instance); | ||
| 41 | pin_trait!(UlpiD3Pin, Instance); | ||
| 42 | pin_trait!(UlpiD4Pin, Instance); | ||
| 43 | pin_trait!(UlpiD5Pin, Instance); | ||
| 44 | pin_trait!(UlpiD6Pin, Instance); | ||
| 45 | pin_trait!(UlpiD7Pin, Instance); | ||
| 46 | |||
| 47 | foreach_interrupt!( | ||
| 48 | (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { | ||
| 49 | impl sealed::Instance for peripherals::USB_OTG_FS { | ||
| 50 | const HIGH_SPEED: bool = false; | ||
| 51 | |||
| 52 | cfg_if::cfg_if! { | ||
| 53 | if #[cfg(stm32f1)] { | ||
| 54 | const FIFO_DEPTH_WORDS: u16 = 128; | ||
| 55 | const ENDPOINT_COUNT: usize = 8; | ||
| 56 | } else if #[cfg(any( | ||
| 57 | stm32f2, | ||
| 58 | stm32f401, | ||
| 59 | stm32f405, | ||
| 60 | stm32f407, | ||
| 61 | stm32f411, | ||
| 62 | stm32f415, | ||
| 63 | stm32f417, | ||
| 64 | stm32f427, | ||
| 65 | stm32f429, | ||
| 66 | stm32f437, | ||
| 67 | stm32f439, | ||
| 68 | ))] { | ||
| 69 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 70 | const ENDPOINT_COUNT: usize = 4; | ||
| 71 | } else if #[cfg(any( | ||
| 72 | stm32f412, | ||
| 73 | stm32f413, | ||
| 74 | stm32f423, | ||
| 75 | stm32f446, | ||
| 76 | stm32f469, | ||
| 77 | stm32f479, | ||
| 78 | stm32f7, | ||
| 79 | stm32l4, | ||
| 80 | stm32u5, | ||
| 81 | ))] { | ||
| 82 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 83 | const ENDPOINT_COUNT: usize = 6; | ||
| 84 | } else if #[cfg(stm32g0x1)] { | ||
| 85 | const FIFO_DEPTH_WORDS: u16 = 512; | ||
| 86 | const ENDPOINT_COUNT: usize = 8; | ||
| 87 | } else if #[cfg(stm32h7)] { | ||
| 88 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 89 | const ENDPOINT_COUNT: usize = 9; | ||
| 90 | } else if #[cfg(stm32u5)] { | ||
| 91 | const FIFO_DEPTH_WORDS: u16 = 320; | ||
| 92 | const ENDPOINT_COUNT: usize = 6; | ||
| 93 | } else { | ||
| 94 | compile_error!("USB_OTG_FS peripheral is not supported by this chip."); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | fn regs() -> crate::pac::otg::Otg { | ||
| 99 | crate::pac::USB_OTG_FS | ||
| 100 | } | ||
| 101 | |||
| 102 | fn state() -> &'static State<MAX_EP_COUNT> { | ||
| 103 | static STATE: State<MAX_EP_COUNT> = State::new(); | ||
| 104 | &STATE | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | impl Instance for peripherals::USB_OTG_FS { | ||
| 109 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | |||
| 113 | (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { | ||
| 114 | impl sealed::Instance for peripherals::USB_OTG_HS { | ||
| 115 | const HIGH_SPEED: bool = true; | ||
| 116 | |||
| 117 | cfg_if::cfg_if! { | ||
| 118 | if #[cfg(any( | ||
| 119 | stm32f2, | ||
| 120 | stm32f405, | ||
| 121 | stm32f407, | ||
| 122 | stm32f415, | ||
| 123 | stm32f417, | ||
| 124 | stm32f427, | ||
| 125 | stm32f429, | ||
| 126 | stm32f437, | ||
| 127 | stm32f439, | ||
| 128 | ))] { | ||
| 129 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 130 | const ENDPOINT_COUNT: usize = 6; | ||
| 131 | } else if #[cfg(any( | ||
| 132 | stm32f446, | ||
| 133 | stm32f469, | ||
| 134 | stm32f479, | ||
| 135 | stm32f7, | ||
| 136 | stm32h7, | ||
| 137 | ))] { | ||
| 138 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 139 | const ENDPOINT_COUNT: usize = 9; | ||
| 140 | } else if #[cfg(stm32u5)] { | ||
| 141 | const FIFO_DEPTH_WORDS: u16 = 1024; | ||
| 142 | const ENDPOINT_COUNT: usize = 9; | ||
| 143 | } else { | ||
| 144 | compile_error!("USB_OTG_HS peripheral is not supported by this chip."); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | fn regs() -> crate::pac::otg::Otg { | ||
| 149 | // OTG HS registers are a superset of FS registers | ||
| 150 | unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } | ||
| 151 | } | ||
| 152 | |||
| 153 | fn state() -> &'static State<MAX_EP_COUNT> { | ||
| 154 | static STATE: State<MAX_EP_COUNT> = State::new(); | ||
| 155 | &STATE | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | impl Instance for peripherals::USB_OTG_HS { | ||
| 160 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 161 | } | ||
| 162 | }; | ||
| 163 | ); | ||
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 2ff0db09e..ab21c4b6b 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs | |||
| @@ -80,18 +80,17 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | |||
| 80 | } | 80 | } |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | mod sealed { | 83 | trait SealedInstance { |
| 84 | pub trait Instance { | 84 | fn regs() -> crate::pac::iwdg::Iwdg; |
| 85 | fn regs() -> crate::pac::iwdg::Iwdg; | ||
| 86 | } | ||
| 87 | } | 85 | } |
| 88 | 86 | ||
| 89 | /// IWDG instance trait. | 87 | /// IWDG instance trait. |
| 90 | pub trait Instance: sealed::Instance {} | 88 | #[allow(private_bounds)] |
| 89 | pub trait Instance: SealedInstance {} | ||
| 91 | 90 | ||
| 92 | foreach_peripheral!( | 91 | foreach_peripheral!( |
| 93 | (iwdg, $inst:ident) => { | 92 | (iwdg, $inst:ident) => { |
| 94 | impl sealed::Instance for crate::peripherals::$inst { | 93 | impl SealedInstance for crate::peripherals::$inst { |
| 95 | fn regs() -> crate::pac::iwdg::Iwdg { | 94 | fn regs() -> crate::pac::iwdg::Iwdg { |
| 96 | crate::pac::$inst | 95 | crate::pac::$inst |
| 97 | } | 96 | } |
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 85673026c..aaf6fab1d 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml | |||
| @@ -20,7 +20,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/ | |||
| 20 | target = "thumbv7em-none-eabi" | 20 | target = "thumbv7em-none-eabi" |
| 21 | 21 | ||
| 22 | [features] | 22 | [features] |
| 23 | std = [] | 23 | std = ["critical-section/std"] |
| 24 | turbowakers = [] | 24 | turbowakers = [] |
| 25 | 25 | ||
| 26 | [dependencies] | 26 | [dependencies] |
diff --git a/embassy-sync/README.md b/embassy-sync/README.md index c2e13799e..2c1c0cf68 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md | |||
| @@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project. | |||
| 5 | Synchronization primitives and data structures with async support: | 5 | Synchronization primitives and data structures with async support: |
| 6 | 6 | ||
| 7 | - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. | 7 | - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. |
| 8 | - [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are sifted to the front of the channel. | 8 | - [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. |
| 9 | - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. | 9 | - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. |
| 10 | - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. | 10 | - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. |
| 11 | - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. | 11 | - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. |
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 01db0d09a..48f4dafd6 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs | |||
| @@ -263,6 +263,12 @@ impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> { | |||
| 263 | } | 263 | } |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | impl<'ch, M: RawMutex, T, const N: usize> From<ReceiveFuture<'ch, M, T, N>> for DynamicReceiveFuture<'ch, T> { | ||
| 267 | fn from(value: ReceiveFuture<'ch, M, T, N>) -> Self { | ||
| 268 | Self { channel: value.channel } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 266 | /// Future returned by [`Channel::send`] and [`Sender::send`]. | 272 | /// Future returned by [`Channel::send`] and [`Sender::send`]. |
| 267 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 273 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 268 | pub struct SendFuture<'ch, M, T, const N: usize> | 274 | pub struct SendFuture<'ch, M, T, const N: usize> |
| @@ -321,6 +327,15 @@ impl<'ch, T> Future for DynamicSendFuture<'ch, T> { | |||
| 321 | 327 | ||
| 322 | impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} | 328 | impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} |
| 323 | 329 | ||
| 330 | impl<'ch, M: RawMutex, T, const N: usize> From<SendFuture<'ch, M, T, N>> for DynamicSendFuture<'ch, T> { | ||
| 331 | fn from(value: SendFuture<'ch, M, T, N>) -> Self { | ||
| 332 | Self { | ||
| 333 | channel: value.channel, | ||
| 334 | message: value.message, | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 324 | pub(crate) trait DynamicChannel<T> { | 339 | pub(crate) trait DynamicChannel<T> { |
| 325 | fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; | 340 | fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; |
| 326 | 341 | ||
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-sync/src/fmt.rs +++ b/embassy-sync/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index d88c76db5..1873483f9 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs | |||
| @@ -13,9 +13,11 @@ mod ring_buffer; | |||
| 13 | pub mod blocking_mutex; | 13 | pub mod blocking_mutex; |
| 14 | pub mod channel; | 14 | pub mod channel; |
| 15 | pub mod mutex; | 15 | pub mod mutex; |
| 16 | pub mod once_lock; | ||
| 16 | pub mod pipe; | 17 | pub mod pipe; |
| 17 | pub mod priority_channel; | 18 | pub mod priority_channel; |
| 18 | pub mod pubsub; | 19 | pub mod pubsub; |
| 20 | pub mod semaphore; | ||
| 19 | pub mod signal; | 21 | pub mod signal; |
| 20 | pub mod waitqueue; | 22 | pub mod waitqueue; |
| 21 | pub mod zerocopy_channel; | 23 | pub mod zerocopy_channel; |
diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs new file mode 100644 index 000000000..31cc99711 --- /dev/null +++ b/embassy-sync/src/once_lock.rs | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | //! Syncronization primitive for initializing a value once, allowing others to await a reference to the value. | ||
| 2 | |||
| 3 | use core::cell::Cell; | ||
| 4 | use core::future::poll_fn; | ||
| 5 | use core::mem::MaybeUninit; | ||
| 6 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 7 | use core::task::Poll; | ||
| 8 | |||
| 9 | /// The `OnceLock` is a synchronization primitive that allows for | ||
| 10 | /// initializing a value once, and allowing others to `.await` a | ||
| 11 | /// reference to the value. This is useful for lazy initialization of | ||
| 12 | /// a static value. | ||
| 13 | /// | ||
| 14 | /// **Note**: this implementation uses a busy loop to poll the value, | ||
| 15 | /// which is not as efficient as registering a dedicated `Waker`. | ||
| 16 | /// However, the if the usecase for is to initialize a static variable | ||
| 17 | /// relatively early in the program life cycle, it should be fine. | ||
| 18 | /// | ||
| 19 | /// # Example | ||
| 20 | /// ``` | ||
| 21 | /// use futures_executor::block_on; | ||
| 22 | /// use embassy_sync::once_lock::OnceLock; | ||
| 23 | /// | ||
| 24 | /// // Define a static value that will be lazily initialized | ||
| 25 | /// static VALUE: OnceLock<u32> = OnceLock::new(); | ||
| 26 | /// | ||
| 27 | /// let f = async { | ||
| 28 | /// | ||
| 29 | /// // Initialize the value | ||
| 30 | /// let reference = VALUE.get_or_init(|| 20); | ||
| 31 | /// assert_eq!(reference, &20); | ||
| 32 | /// | ||
| 33 | /// // Wait for the value to be initialized | ||
| 34 | /// // and get a static reference it | ||
| 35 | /// assert_eq!(VALUE.get().await, &20); | ||
| 36 | /// | ||
| 37 | /// }; | ||
| 38 | /// block_on(f) | ||
| 39 | /// ``` | ||
| 40 | pub struct OnceLock<T> { | ||
| 41 | init: AtomicBool, | ||
| 42 | data: Cell<MaybeUninit<T>>, | ||
| 43 | } | ||
| 44 | |||
| 45 | unsafe impl<T> Sync for OnceLock<T> {} | ||
| 46 | |||
| 47 | impl<T> OnceLock<T> { | ||
| 48 | /// Create a new uninitialized `OnceLock`. | ||
| 49 | pub const fn new() -> Self { | ||
| 50 | Self { | ||
| 51 | init: AtomicBool::new(false), | ||
| 52 | data: Cell::new(MaybeUninit::zeroed()), | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Get a reference to the underlying value, waiting for it to be set. | ||
| 57 | /// If the value is already set, this will return immediately. | ||
| 58 | pub async fn get(&self) -> &T { | ||
| 59 | poll_fn(|cx| match self.try_get() { | ||
| 60 | Some(data) => Poll::Ready(data), | ||
| 61 | None => { | ||
| 62 | cx.waker().wake_by_ref(); | ||
| 63 | Poll::Pending | ||
| 64 | } | ||
| 65 | }) | ||
| 66 | .await | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Try to get a reference to the underlying value if it exists. | ||
| 70 | pub fn try_get(&self) -> Option<&T> { | ||
| 71 | if self.init.load(Ordering::Relaxed) { | ||
| 72 | Some(unsafe { self.get_ref_unchecked() }) | ||
| 73 | } else { | ||
| 74 | None | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Set the underlying value. If the value is already set, this will return an error with the given value. | ||
| 79 | pub fn init(&self, value: T) -> Result<(), T> { | ||
| 80 | // Critical section is required to ensure that the value is | ||
| 81 | // not simultaniously initialized elsewhere at the same time. | ||
| 82 | critical_section::with(|_| { | ||
| 83 | // If the value is not set, set it and return Ok. | ||
| 84 | if !self.init.load(Ordering::Relaxed) { | ||
| 85 | self.data.set(MaybeUninit::new(value)); | ||
| 86 | self.init.store(true, Ordering::Relaxed); | ||
| 87 | Ok(()) | ||
| 88 | |||
| 89 | // Otherwise return an error with the given value. | ||
| 90 | } else { | ||
| 91 | Err(value) | ||
| 92 | } | ||
| 93 | }) | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Get a reference to the underlying value, initializing it if it does not exist. | ||
| 97 | pub fn get_or_init<F>(&self, f: F) -> &T | ||
| 98 | where | ||
| 99 | F: FnOnce() -> T, | ||
| 100 | { | ||
| 101 | // Critical section is required to ensure that the value is | ||
| 102 | // not simultaniously initialized elsewhere at the same time. | ||
| 103 | critical_section::with(|_| { | ||
| 104 | // If the value is not set, set it. | ||
| 105 | if !self.init.load(Ordering::Relaxed) { | ||
| 106 | self.data.set(MaybeUninit::new(f())); | ||
| 107 | self.init.store(true, Ordering::Relaxed); | ||
| 108 | } | ||
| 109 | }); | ||
| 110 | |||
| 111 | // Return a reference to the value. | ||
| 112 | unsafe { self.get_ref_unchecked() } | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Consume the `OnceLock`, returning the underlying value if it was initialized. | ||
| 116 | pub fn into_inner(self) -> Option<T> { | ||
| 117 | if self.init.load(Ordering::Relaxed) { | ||
| 118 | Some(unsafe { self.data.into_inner().assume_init() }) | ||
| 119 | } else { | ||
| 120 | None | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Take the underlying value if it was initialized, uninitializing the `OnceLock` in the process. | ||
| 125 | pub fn take(&mut self) -> Option<T> { | ||
| 126 | // If the value is set, uninitialize the lock and return the value. | ||
| 127 | critical_section::with(|_| { | ||
| 128 | if self.init.load(Ordering::Relaxed) { | ||
| 129 | let val = unsafe { self.data.replace(MaybeUninit::zeroed()).assume_init() }; | ||
| 130 | self.init.store(false, Ordering::Relaxed); | ||
| 131 | Some(val) | ||
| 132 | |||
| 133 | // Otherwise return None. | ||
| 134 | } else { | ||
| 135 | None | ||
| 136 | } | ||
| 137 | }) | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Check if the value has been set. | ||
| 141 | pub fn is_set(&self) -> bool { | ||
| 142 | self.init.load(Ordering::Relaxed) | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Get a reference to the underlying value. | ||
| 146 | /// # Safety | ||
| 147 | /// Must only be used if a value has been set. | ||
| 148 | unsafe fn get_ref_unchecked(&self) -> &T { | ||
| 149 | (*self.data.as_ptr()).assume_init_ref() | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | #[cfg(test)] | ||
| 154 | mod tests { | ||
| 155 | use super::*; | ||
| 156 | |||
| 157 | #[test] | ||
| 158 | fn once_lock() { | ||
| 159 | let lock = OnceLock::new(); | ||
| 160 | assert_eq!(lock.try_get(), None); | ||
| 161 | assert_eq!(lock.is_set(), false); | ||
| 162 | |||
| 163 | let v = 42; | ||
| 164 | assert_eq!(lock.init(v), Ok(())); | ||
| 165 | assert_eq!(lock.is_set(), true); | ||
| 166 | assert_eq!(lock.try_get(), Some(&v)); | ||
| 167 | assert_eq!(lock.try_get(), Some(&v)); | ||
| 168 | |||
| 169 | let v = 43; | ||
| 170 | assert_eq!(lock.init(v), Err(v)); | ||
| 171 | assert_eq!(lock.is_set(), true); | ||
| 172 | assert_eq!(lock.try_get(), Some(&42)); | ||
| 173 | } | ||
| 174 | |||
| 175 | #[test] | ||
| 176 | fn once_lock_get_or_init() { | ||
| 177 | let lock = OnceLock::new(); | ||
| 178 | assert_eq!(lock.try_get(), None); | ||
| 179 | assert_eq!(lock.is_set(), false); | ||
| 180 | |||
| 181 | let v = lock.get_or_init(|| 42); | ||
| 182 | assert_eq!(v, &42); | ||
| 183 | assert_eq!(lock.is_set(), true); | ||
| 184 | assert_eq!(lock.try_get(), Some(&42)); | ||
| 185 | |||
| 186 | let v = lock.get_or_init(|| 43); | ||
| 187 | assert_eq!(v, &42); | ||
| 188 | assert_eq!(lock.is_set(), true); | ||
| 189 | assert_eq!(lock.try_get(), Some(&42)); | ||
| 190 | } | ||
| 191 | |||
| 192 | #[test] | ||
| 193 | fn once_lock_static() { | ||
| 194 | static LOCK: OnceLock<i32> = OnceLock::new(); | ||
| 195 | |||
| 196 | let v: &'static i32 = LOCK.get_or_init(|| 42); | ||
| 197 | assert_eq!(v, &42); | ||
| 198 | |||
| 199 | let v: &'static i32 = LOCK.get_or_init(|| 43); | ||
| 200 | assert_eq!(v, &42); | ||
| 201 | } | ||
| 202 | |||
| 203 | #[futures_test::test] | ||
| 204 | async fn once_lock_async() { | ||
| 205 | static LOCK: OnceLock<i32> = OnceLock::new(); | ||
| 206 | |||
| 207 | assert!(LOCK.init(42).is_ok()); | ||
| 208 | |||
| 209 | let v: &'static i32 = LOCK.get().await; | ||
| 210 | assert_eq!(v, &42); | ||
| 211 | } | ||
| 212 | |||
| 213 | #[test] | ||
| 214 | fn once_lock_into_inner() { | ||
| 215 | let lock: OnceLock<i32> = OnceLock::new(); | ||
| 216 | |||
| 217 | let v = lock.get_or_init(|| 42); | ||
| 218 | assert_eq!(v, &42); | ||
| 219 | |||
| 220 | assert_eq!(lock.into_inner(), Some(42)); | ||
| 221 | } | ||
| 222 | |||
| 223 | #[test] | ||
| 224 | fn once_lock_take_init() { | ||
| 225 | let mut lock: OnceLock<i32> = OnceLock::new(); | ||
| 226 | |||
| 227 | assert_eq!(lock.get_or_init(|| 42), &42); | ||
| 228 | assert_eq!(lock.is_set(), true); | ||
| 229 | |||
| 230 | assert_eq!(lock.take(), Some(42)); | ||
| 231 | assert_eq!(lock.is_set(), false); | ||
| 232 | |||
| 233 | assert_eq!(lock.get_or_init(|| 43), &43); | ||
| 234 | assert_eq!(lock.is_set(), true); | ||
| 235 | } | ||
| 236 | } | ||
diff --git a/embassy-sync/src/semaphore.rs b/embassy-sync/src/semaphore.rs new file mode 100644 index 000000000..52c468b4a --- /dev/null +++ b/embassy-sync/src/semaphore.rs | |||
| @@ -0,0 +1,704 @@ | |||
| 1 | //! A synchronization primitive for controlling access to a pool of resources. | ||
| 2 | use core::cell::{Cell, RefCell}; | ||
| 3 | use core::convert::Infallible; | ||
| 4 | use core::future::poll_fn; | ||
| 5 | use core::mem::MaybeUninit; | ||
| 6 | use core::task::{Poll, Waker}; | ||
| 7 | |||
| 8 | use heapless::Deque; | ||
| 9 | |||
| 10 | use crate::blocking_mutex::raw::RawMutex; | ||
| 11 | use crate::blocking_mutex::Mutex; | ||
| 12 | use crate::waitqueue::WakerRegistration; | ||
| 13 | |||
| 14 | /// An asynchronous semaphore. | ||
| 15 | /// | ||
| 16 | /// A semaphore tracks a number of permits, typically representing a pool of shared resources. | ||
| 17 | /// Users can acquire permits to synchronize access to those resources. The semaphore does not | ||
| 18 | /// contain the resources themselves, only the count of available permits. | ||
| 19 | pub trait Semaphore: Sized { | ||
| 20 | /// The error returned when the semaphore is unable to acquire the requested permits. | ||
| 21 | type Error; | ||
| 22 | |||
| 23 | /// Asynchronously acquire one or more permits from the semaphore. | ||
| 24 | async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>; | ||
| 25 | |||
| 26 | /// Try to immediately acquire one or more permits from the semaphore. | ||
| 27 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>>; | ||
| 28 | |||
| 29 | /// Asynchronously acquire all permits controlled by the semaphore. | ||
| 30 | /// | ||
| 31 | /// This method will wait until at least `min` permits are available, then acquire all available permits | ||
| 32 | /// from the semaphore. Note that other tasks may have already acquired some permits which could be released | ||
| 33 | /// back to the semaphore at any time. The number of permits actually acquired may be determined by calling | ||
| 34 | /// [`SemaphoreReleaser::permits`]. | ||
| 35 | async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>; | ||
| 36 | |||
| 37 | /// Try to immediately acquire all available permits from the semaphore, if at least `min` permits are available. | ||
| 38 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>>; | ||
| 39 | |||
| 40 | /// Release `permits` back to the semaphore, making them available to be acquired. | ||
| 41 | fn release(&self, permits: usize); | ||
| 42 | |||
| 43 | /// Reset the number of available permints in the semaphore to `permits`. | ||
| 44 | fn set(&self, permits: usize); | ||
| 45 | } | ||
| 46 | |||
| 47 | /// A representation of a number of acquired permits. | ||
| 48 | /// | ||
| 49 | /// The acquired permits will be released back to the [`Semaphore`] when this is dropped. | ||
| 50 | pub struct SemaphoreReleaser<'a, S: Semaphore> { | ||
| 51 | semaphore: &'a S, | ||
| 52 | permits: usize, | ||
| 53 | } | ||
| 54 | |||
| 55 | impl<'a, S: Semaphore> Drop for SemaphoreReleaser<'a, S> { | ||
| 56 | fn drop(&mut self) { | ||
| 57 | self.semaphore.release(self.permits); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<'a, S: Semaphore> SemaphoreReleaser<'a, S> { | ||
| 62 | /// The number of acquired permits. | ||
| 63 | pub fn permits(&self) -> usize { | ||
| 64 | self.permits | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Prevent the acquired permits from being released on drop. | ||
| 68 | /// | ||
| 69 | /// Returns the number of acquired permits. | ||
| 70 | pub fn disarm(self) -> usize { | ||
| 71 | let permits = self.permits; | ||
| 72 | core::mem::forget(self); | ||
| 73 | permits | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | /// A greedy [`Semaphore`] implementation. | ||
| 78 | /// | ||
| 79 | /// Tasks can acquire permits as soon as they become available, even if another task | ||
| 80 | /// is waiting on a larger number of permits. | ||
| 81 | pub struct GreedySemaphore<M: RawMutex> { | ||
| 82 | state: Mutex<M, Cell<SemaphoreState>>, | ||
| 83 | } | ||
| 84 | |||
| 85 | impl<M: RawMutex> Default for GreedySemaphore<M> { | ||
| 86 | fn default() -> Self { | ||
| 87 | Self::new(0) | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | impl<M: RawMutex> GreedySemaphore<M> { | ||
| 92 | /// Create a new `Semaphore`. | ||
| 93 | pub const fn new(permits: usize) -> Self { | ||
| 94 | Self { | ||
| 95 | state: Mutex::new(Cell::new(SemaphoreState { | ||
| 96 | permits, | ||
| 97 | waker: WakerRegistration::new(), | ||
| 98 | })), | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | #[cfg(test)] | ||
| 103 | fn permits(&self) -> usize { | ||
| 104 | self.state.lock(|cell| { | ||
| 105 | let state = cell.replace(SemaphoreState::EMPTY); | ||
| 106 | let permits = state.permits; | ||
| 107 | cell.replace(state); | ||
| 108 | permits | ||
| 109 | }) | ||
| 110 | } | ||
| 111 | |||
| 112 | fn poll_acquire( | ||
| 113 | &self, | ||
| 114 | permits: usize, | ||
| 115 | acquire_all: bool, | ||
| 116 | waker: Option<&Waker>, | ||
| 117 | ) -> Poll<Result<SemaphoreReleaser<'_, Self>, Infallible>> { | ||
| 118 | self.state.lock(|cell| { | ||
| 119 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 120 | if let Some(permits) = state.take(permits, acquire_all) { | ||
| 121 | cell.set(state); | ||
| 122 | Poll::Ready(Ok(SemaphoreReleaser { | ||
| 123 | semaphore: self, | ||
| 124 | permits, | ||
| 125 | })) | ||
| 126 | } else { | ||
| 127 | if let Some(waker) = waker { | ||
| 128 | state.register(waker); | ||
| 129 | } | ||
| 130 | cell.set(state); | ||
| 131 | Poll::Pending | ||
| 132 | } | ||
| 133 | }) | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | impl<M: RawMutex> Semaphore for GreedySemaphore<M> { | ||
| 138 | type Error = Infallible; | ||
| 139 | |||
| 140 | async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 141 | poll_fn(|cx| self.poll_acquire(permits, false, Some(cx.waker()))).await | ||
| 142 | } | ||
| 143 | |||
| 144 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 145 | match self.poll_acquire(permits, false, None) { | ||
| 146 | Poll::Ready(Ok(n)) => Some(n), | ||
| 147 | _ => None, | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 152 | poll_fn(|cx| self.poll_acquire(min, true, Some(cx.waker()))).await | ||
| 153 | } | ||
| 154 | |||
| 155 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 156 | match self.poll_acquire(min, true, None) { | ||
| 157 | Poll::Ready(Ok(n)) => Some(n), | ||
| 158 | _ => None, | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | fn release(&self, permits: usize) { | ||
| 163 | if permits > 0 { | ||
| 164 | self.state.lock(|cell| { | ||
| 165 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 166 | state.permits += permits; | ||
| 167 | state.wake(); | ||
| 168 | cell.set(state); | ||
| 169 | }); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | fn set(&self, permits: usize) { | ||
| 174 | self.state.lock(|cell| { | ||
| 175 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 176 | if permits > state.permits { | ||
| 177 | state.wake(); | ||
| 178 | } | ||
| 179 | state.permits = permits; | ||
| 180 | cell.set(state); | ||
| 181 | }); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | struct SemaphoreState { | ||
| 186 | permits: usize, | ||
| 187 | waker: WakerRegistration, | ||
| 188 | } | ||
| 189 | |||
| 190 | impl SemaphoreState { | ||
| 191 | const EMPTY: SemaphoreState = SemaphoreState { | ||
| 192 | permits: 0, | ||
| 193 | waker: WakerRegistration::new(), | ||
| 194 | }; | ||
| 195 | |||
| 196 | fn register(&mut self, w: &Waker) { | ||
| 197 | self.waker.register(w); | ||
| 198 | } | ||
| 199 | |||
| 200 | fn take(&mut self, mut permits: usize, acquire_all: bool) -> Option<usize> { | ||
| 201 | if self.permits < permits { | ||
| 202 | None | ||
| 203 | } else { | ||
| 204 | if acquire_all { | ||
| 205 | permits = self.permits; | ||
| 206 | } | ||
| 207 | self.permits -= permits; | ||
| 208 | Some(permits) | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | fn wake(&mut self) { | ||
| 213 | self.waker.wake(); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | /// A fair [`Semaphore`] implementation. | ||
| 218 | /// | ||
| 219 | /// Tasks are allowed to acquire permits in FIFO order. A task waiting to acquire | ||
| 220 | /// a large number of permits will prevent other tasks from acquiring any permits | ||
| 221 | /// until its request is satisfied. | ||
| 222 | /// | ||
| 223 | /// Up to `N` tasks may attempt to acquire permits concurrently. If additional | ||
| 224 | /// tasks attempt to acquire a permit, a [`WaitQueueFull`] error will be returned. | ||
| 225 | pub struct FairSemaphore<M, const N: usize> | ||
| 226 | where | ||
| 227 | M: RawMutex, | ||
| 228 | { | ||
| 229 | state: Mutex<M, RefCell<FairSemaphoreState<N>>>, | ||
| 230 | } | ||
| 231 | |||
| 232 | impl<M, const N: usize> Default for FairSemaphore<M, N> | ||
| 233 | where | ||
| 234 | M: RawMutex, | ||
| 235 | { | ||
| 236 | fn default() -> Self { | ||
| 237 | Self::new(0) | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | impl<M, const N: usize> FairSemaphore<M, N> | ||
| 242 | where | ||
| 243 | M: RawMutex, | ||
| 244 | { | ||
| 245 | /// Create a new `FairSemaphore`. | ||
| 246 | pub const fn new(permits: usize) -> Self { | ||
| 247 | Self { | ||
| 248 | state: Mutex::new(RefCell::new(FairSemaphoreState::new(permits))), | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | #[cfg(test)] | ||
| 253 | fn permits(&self) -> usize { | ||
| 254 | self.state.lock(|cell| cell.borrow().permits) | ||
| 255 | } | ||
| 256 | |||
| 257 | fn poll_acquire( | ||
| 258 | &self, | ||
| 259 | permits: usize, | ||
| 260 | acquire_all: bool, | ||
| 261 | cx: Option<(&Cell<Option<usize>>, &Waker)>, | ||
| 262 | ) -> Poll<Result<SemaphoreReleaser<'_, Self>, WaitQueueFull>> { | ||
| 263 | let ticket = cx.as_ref().map(|(cell, _)| cell.get()).unwrap_or(None); | ||
| 264 | self.state.lock(|cell| { | ||
| 265 | let mut state = cell.borrow_mut(); | ||
| 266 | if let Some(permits) = state.take(ticket, permits, acquire_all) { | ||
| 267 | Poll::Ready(Ok(SemaphoreReleaser { | ||
| 268 | semaphore: self, | ||
| 269 | permits, | ||
| 270 | })) | ||
| 271 | } else if let Some((cell, waker)) = cx { | ||
| 272 | match state.register(ticket, waker) { | ||
| 273 | Ok(ticket) => { | ||
| 274 | cell.set(Some(ticket)); | ||
| 275 | Poll::Pending | ||
| 276 | } | ||
| 277 | Err(err) => Poll::Ready(Err(err)), | ||
| 278 | } | ||
| 279 | } else { | ||
| 280 | Poll::Pending | ||
| 281 | } | ||
| 282 | }) | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | /// An error indicating the [`FairSemaphore`]'s wait queue is full. | ||
| 287 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 288 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 289 | pub struct WaitQueueFull; | ||
| 290 | |||
| 291 | impl<M: RawMutex, const N: usize> Semaphore for FairSemaphore<M, N> { | ||
| 292 | type Error = WaitQueueFull; | ||
| 293 | |||
| 294 | async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 295 | let ticket = Cell::new(None); | ||
| 296 | let _guard = OnDrop::new(|| self.state.lock(|cell| cell.borrow_mut().cancel(ticket.get()))); | ||
| 297 | poll_fn(|cx| self.poll_acquire(permits, false, Some((&ticket, cx.waker())))).await | ||
| 298 | } | ||
| 299 | |||
| 300 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 301 | match self.poll_acquire(permits, false, None) { | ||
| 302 | Poll::Ready(Ok(x)) => Some(x), | ||
| 303 | _ => None, | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 308 | let ticket = Cell::new(None); | ||
| 309 | let _guard = OnDrop::new(|| self.state.lock(|cell| cell.borrow_mut().cancel(ticket.get()))); | ||
| 310 | poll_fn(|cx| self.poll_acquire(min, true, Some((&ticket, cx.waker())))).await | ||
| 311 | } | ||
| 312 | |||
| 313 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 314 | match self.poll_acquire(min, true, None) { | ||
| 315 | Poll::Ready(Ok(x)) => Some(x), | ||
| 316 | _ => None, | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | fn release(&self, permits: usize) { | ||
| 321 | if permits > 0 { | ||
| 322 | self.state.lock(|cell| { | ||
| 323 | let mut state = cell.borrow_mut(); | ||
| 324 | state.permits += permits; | ||
| 325 | state.wake(); | ||
| 326 | }); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | fn set(&self, permits: usize) { | ||
| 331 | self.state.lock(|cell| { | ||
| 332 | let mut state = cell.borrow_mut(); | ||
| 333 | if permits > state.permits { | ||
| 334 | state.wake(); | ||
| 335 | } | ||
| 336 | state.permits = permits; | ||
| 337 | }); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | struct FairSemaphoreState<const N: usize> { | ||
| 342 | permits: usize, | ||
| 343 | next_ticket: usize, | ||
| 344 | wakers: Deque<Option<Waker>, N>, | ||
| 345 | } | ||
| 346 | |||
| 347 | impl<const N: usize> FairSemaphoreState<N> { | ||
| 348 | /// Create a new empty instance | ||
| 349 | const fn new(permits: usize) -> Self { | ||
| 350 | Self { | ||
| 351 | permits, | ||
| 352 | next_ticket: 0, | ||
| 353 | wakers: Deque::new(), | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | /// Register a waker. If the queue is full the function returns an error | ||
| 358 | fn register(&mut self, ticket: Option<usize>, w: &Waker) -> Result<usize, WaitQueueFull> { | ||
| 359 | self.pop_canceled(); | ||
| 360 | |||
| 361 | match ticket { | ||
| 362 | None => { | ||
| 363 | let ticket = self.next_ticket.wrapping_add(self.wakers.len()); | ||
| 364 | self.wakers.push_back(Some(w.clone())).or(Err(WaitQueueFull))?; | ||
| 365 | Ok(ticket) | ||
| 366 | } | ||
| 367 | Some(ticket) => { | ||
| 368 | self.set_waker(ticket, Some(w.clone())); | ||
| 369 | Ok(ticket) | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | fn cancel(&mut self, ticket: Option<usize>) { | ||
| 375 | if let Some(ticket) = ticket { | ||
| 376 | self.set_waker(ticket, None); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | fn set_waker(&mut self, ticket: usize, waker: Option<Waker>) { | ||
| 381 | let i = ticket.wrapping_sub(self.next_ticket); | ||
| 382 | if i < self.wakers.len() { | ||
| 383 | let (a, b) = self.wakers.as_mut_slices(); | ||
| 384 | let x = if i < a.len() { &mut a[i] } else { &mut b[i - a.len()] }; | ||
| 385 | *x = waker; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | fn take(&mut self, ticket: Option<usize>, mut permits: usize, acquire_all: bool) -> Option<usize> { | ||
| 390 | self.pop_canceled(); | ||
| 391 | |||
| 392 | if permits > self.permits { | ||
| 393 | return None; | ||
| 394 | } | ||
| 395 | |||
| 396 | match ticket { | ||
| 397 | Some(n) if n != self.next_ticket => return None, | ||
| 398 | None if !self.wakers.is_empty() => return None, | ||
| 399 | _ => (), | ||
| 400 | } | ||
| 401 | |||
| 402 | if acquire_all { | ||
| 403 | permits = self.permits; | ||
| 404 | } | ||
| 405 | self.permits -= permits; | ||
| 406 | |||
| 407 | if ticket.is_some() { | ||
| 408 | self.pop(); | ||
| 409 | } | ||
| 410 | |||
| 411 | Some(permits) | ||
| 412 | } | ||
| 413 | |||
| 414 | fn pop_canceled(&mut self) { | ||
| 415 | while let Some(None) = self.wakers.front() { | ||
| 416 | self.pop(); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | /// Panics if `self.wakers` is empty | ||
| 421 | fn pop(&mut self) { | ||
| 422 | self.wakers.pop_front().unwrap(); | ||
| 423 | self.next_ticket = self.next_ticket.wrapping_add(1); | ||
| 424 | } | ||
| 425 | |||
| 426 | fn wake(&mut self) { | ||
| 427 | self.pop_canceled(); | ||
| 428 | |||
| 429 | if let Some(Some(waker)) = self.wakers.front() { | ||
| 430 | waker.wake_by_ref(); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | /// A type to delay the drop handler invocation. | ||
| 436 | #[must_use = "to delay the drop handler invocation to the end of the scope"] | ||
| 437 | struct OnDrop<F: FnOnce()> { | ||
| 438 | f: MaybeUninit<F>, | ||
| 439 | } | ||
| 440 | |||
| 441 | impl<F: FnOnce()> OnDrop<F> { | ||
| 442 | /// Create a new instance. | ||
| 443 | pub fn new(f: F) -> Self { | ||
| 444 | Self { f: MaybeUninit::new(f) } | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | impl<F: FnOnce()> Drop for OnDrop<F> { | ||
| 449 | fn drop(&mut self) { | ||
| 450 | unsafe { self.f.as_ptr().read()() } | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | #[cfg(test)] | ||
| 455 | mod tests { | ||
| 456 | mod greedy { | ||
| 457 | use core::pin::pin; | ||
| 458 | |||
| 459 | use futures_util::poll; | ||
| 460 | |||
| 461 | use super::super::*; | ||
| 462 | use crate::blocking_mutex::raw::NoopRawMutex; | ||
| 463 | |||
| 464 | #[test] | ||
| 465 | fn try_acquire() { | ||
| 466 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 467 | |||
| 468 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 469 | assert_eq!(a.permits(), 1); | ||
| 470 | assert_eq!(semaphore.permits(), 2); | ||
| 471 | |||
| 472 | core::mem::drop(a); | ||
| 473 | assert_eq!(semaphore.permits(), 3); | ||
| 474 | } | ||
| 475 | |||
| 476 | #[test] | ||
| 477 | fn disarm() { | ||
| 478 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 479 | |||
| 480 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 481 | assert_eq!(a.disarm(), 1); | ||
| 482 | assert_eq!(semaphore.permits(), 2); | ||
| 483 | } | ||
| 484 | |||
| 485 | #[futures_test::test] | ||
| 486 | async fn acquire() { | ||
| 487 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 488 | |||
| 489 | let a = semaphore.acquire(1).await.unwrap(); | ||
| 490 | assert_eq!(a.permits(), 1); | ||
| 491 | assert_eq!(semaphore.permits(), 2); | ||
| 492 | |||
| 493 | core::mem::drop(a); | ||
| 494 | assert_eq!(semaphore.permits(), 3); | ||
| 495 | } | ||
| 496 | |||
| 497 | #[test] | ||
| 498 | fn try_acquire_all() { | ||
| 499 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 500 | |||
| 501 | let a = semaphore.try_acquire_all(1).unwrap(); | ||
| 502 | assert_eq!(a.permits(), 3); | ||
| 503 | assert_eq!(semaphore.permits(), 0); | ||
| 504 | } | ||
| 505 | |||
| 506 | #[futures_test::test] | ||
| 507 | async fn acquire_all() { | ||
| 508 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 509 | |||
| 510 | let a = semaphore.acquire_all(1).await.unwrap(); | ||
| 511 | assert_eq!(a.permits(), 3); | ||
| 512 | assert_eq!(semaphore.permits(), 0); | ||
| 513 | } | ||
| 514 | |||
| 515 | #[test] | ||
| 516 | fn release() { | ||
| 517 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 518 | assert_eq!(semaphore.permits(), 3); | ||
| 519 | semaphore.release(2); | ||
| 520 | assert_eq!(semaphore.permits(), 5); | ||
| 521 | } | ||
| 522 | |||
| 523 | #[test] | ||
| 524 | fn set() { | ||
| 525 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 526 | assert_eq!(semaphore.permits(), 3); | ||
| 527 | semaphore.set(2); | ||
| 528 | assert_eq!(semaphore.permits(), 2); | ||
| 529 | } | ||
| 530 | |||
| 531 | #[test] | ||
| 532 | fn contested() { | ||
| 533 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 534 | |||
| 535 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 536 | let b = semaphore.try_acquire(3); | ||
| 537 | assert!(b.is_none()); | ||
| 538 | |||
| 539 | core::mem::drop(a); | ||
| 540 | |||
| 541 | let b = semaphore.try_acquire(3); | ||
| 542 | assert!(b.is_some()); | ||
| 543 | } | ||
| 544 | |||
| 545 | #[futures_test::test] | ||
| 546 | async fn greedy() { | ||
| 547 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 548 | |||
| 549 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 550 | |||
| 551 | let b_fut = semaphore.acquire(3); | ||
| 552 | let mut b_fut = pin!(b_fut); | ||
| 553 | let b = poll!(b_fut.as_mut()); | ||
| 554 | assert!(b.is_pending()); | ||
| 555 | |||
| 556 | // Succeed even through `b` is waiting | ||
| 557 | let c = semaphore.try_acquire(1); | ||
| 558 | assert!(c.is_some()); | ||
| 559 | |||
| 560 | let b = poll!(b_fut.as_mut()); | ||
| 561 | assert!(b.is_pending()); | ||
| 562 | |||
| 563 | core::mem::drop(a); | ||
| 564 | |||
| 565 | let b = poll!(b_fut.as_mut()); | ||
| 566 | assert!(b.is_pending()); | ||
| 567 | |||
| 568 | core::mem::drop(c); | ||
| 569 | |||
| 570 | let b = poll!(b_fut.as_mut()); | ||
| 571 | assert!(b.is_ready()); | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | mod fair { | ||
| 576 | use core::pin::pin; | ||
| 577 | |||
| 578 | use futures_util::poll; | ||
| 579 | |||
| 580 | use super::super::*; | ||
| 581 | use crate::blocking_mutex::raw::NoopRawMutex; | ||
| 582 | |||
| 583 | #[test] | ||
| 584 | fn try_acquire() { | ||
| 585 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 586 | |||
| 587 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 588 | assert_eq!(a.permits(), 1); | ||
| 589 | assert_eq!(semaphore.permits(), 2); | ||
| 590 | |||
| 591 | core::mem::drop(a); | ||
| 592 | assert_eq!(semaphore.permits(), 3); | ||
| 593 | } | ||
| 594 | |||
| 595 | #[test] | ||
| 596 | fn disarm() { | ||
| 597 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 598 | |||
| 599 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 600 | assert_eq!(a.disarm(), 1); | ||
| 601 | assert_eq!(semaphore.permits(), 2); | ||
| 602 | } | ||
| 603 | |||
| 604 | #[futures_test::test] | ||
| 605 | async fn acquire() { | ||
| 606 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 607 | |||
| 608 | let a = semaphore.acquire(1).await.unwrap(); | ||
| 609 | assert_eq!(a.permits(), 1); | ||
| 610 | assert_eq!(semaphore.permits(), 2); | ||
| 611 | |||
| 612 | core::mem::drop(a); | ||
| 613 | assert_eq!(semaphore.permits(), 3); | ||
| 614 | } | ||
| 615 | |||
| 616 | #[test] | ||
| 617 | fn try_acquire_all() { | ||
| 618 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 619 | |||
| 620 | let a = semaphore.try_acquire_all(1).unwrap(); | ||
| 621 | assert_eq!(a.permits(), 3); | ||
| 622 | assert_eq!(semaphore.permits(), 0); | ||
| 623 | } | ||
| 624 | |||
| 625 | #[futures_test::test] | ||
| 626 | async fn acquire_all() { | ||
| 627 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 628 | |||
| 629 | let a = semaphore.acquire_all(1).await.unwrap(); | ||
| 630 | assert_eq!(a.permits(), 3); | ||
| 631 | assert_eq!(semaphore.permits(), 0); | ||
| 632 | } | ||
| 633 | |||
| 634 | #[test] | ||
| 635 | fn release() { | ||
| 636 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 637 | assert_eq!(semaphore.permits(), 3); | ||
| 638 | semaphore.release(2); | ||
| 639 | assert_eq!(semaphore.permits(), 5); | ||
| 640 | } | ||
| 641 | |||
| 642 | #[test] | ||
| 643 | fn set() { | ||
| 644 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 645 | assert_eq!(semaphore.permits(), 3); | ||
| 646 | semaphore.set(2); | ||
| 647 | assert_eq!(semaphore.permits(), 2); | ||
| 648 | } | ||
| 649 | |||
| 650 | #[test] | ||
| 651 | fn contested() { | ||
| 652 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 653 | |||
| 654 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 655 | let b = semaphore.try_acquire(3); | ||
| 656 | assert!(b.is_none()); | ||
| 657 | |||
| 658 | core::mem::drop(a); | ||
| 659 | |||
| 660 | let b = semaphore.try_acquire(3); | ||
| 661 | assert!(b.is_some()); | ||
| 662 | } | ||
| 663 | |||
| 664 | #[futures_test::test] | ||
| 665 | async fn fairness() { | ||
| 666 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 667 | |||
| 668 | let a = semaphore.try_acquire(1); | ||
| 669 | assert!(a.is_some()); | ||
| 670 | |||
| 671 | let b_fut = semaphore.acquire(3); | ||
| 672 | let mut b_fut = pin!(b_fut); | ||
| 673 | let b = poll!(b_fut.as_mut()); // Poll `b_fut` once so it is registered | ||
| 674 | assert!(b.is_pending()); | ||
| 675 | |||
| 676 | let c = semaphore.try_acquire(1); | ||
| 677 | assert!(c.is_none()); | ||
| 678 | |||
| 679 | let c_fut = semaphore.acquire(1); | ||
| 680 | let mut c_fut = pin!(c_fut); | ||
| 681 | let c = poll!(c_fut.as_mut()); // Poll `c_fut` once so it is registered | ||
| 682 | assert!(c.is_pending()); // `c` is blocked behind `b` | ||
| 683 | |||
| 684 | let d = semaphore.acquire(1).await; | ||
| 685 | assert!(matches!(d, Err(WaitQueueFull))); | ||
| 686 | |||
| 687 | core::mem::drop(a); | ||
| 688 | |||
| 689 | let c = poll!(c_fut.as_mut()); | ||
| 690 | assert!(c.is_pending()); // `c` is still blocked behind `b` | ||
| 691 | |||
| 692 | let b = poll!(b_fut.as_mut()); | ||
| 693 | assert!(b.is_ready()); | ||
| 694 | |||
| 695 | let c = poll!(c_fut.as_mut()); | ||
| 696 | assert!(c.is_pending()); // `c` is still blocked behind `b` | ||
| 697 | |||
| 698 | core::mem::drop(b); | ||
| 699 | |||
| 700 | let c = poll!(c_fut.as_mut()); | ||
| 701 | assert!(c.is_ready()); | ||
| 702 | } | ||
| 703 | } | ||
| 704 | } | ||
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index d75750ce7..520f1a896 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs | |||
| @@ -125,7 +125,7 @@ where | |||
| 125 | }) | 125 | }) |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /// non-blocking method to check whether this signal has been signaled. | 128 | /// non-blocking method to check whether this signal has been signaled. This does not clear the signal. |
| 129 | pub fn signaled(&self) -> bool { | 129 | pub fn signaled(&self) -> bool { |
| 130 | self.state.lock(|cell| { | 130 | self.state.lock(|cell| { |
| 131 | let state = cell.replace(State::None); | 131 | let state = cell.replace(State::None); |
diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-time/src/fmt.rs +++ b/embassy-time/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index daa4c1699..757c3ff00 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs | |||
| @@ -190,8 +190,20 @@ impl Ticker { | |||
| 190 | self.expires_at = Instant::now() + self.duration; | 190 | self.expires_at = Instant::now() + self.duration; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | /// Reset the ticker at the deadline. | ||
| 194 | /// If the deadline is in the past, the ticker will fire instantly. | ||
| 195 | pub fn reset_at(&mut self, deadline: Instant) { | ||
| 196 | self.expires_at = deadline + self.duration; | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Resets the ticker, after the specified duration has passed. | ||
| 200 | /// If the specified duration is zero, the next tick will be after the duration of the ticker. | ||
| 201 | pub fn reset_after(&mut self, after: Duration) { | ||
| 202 | self.expires_at = Instant::now() + after + self.duration; | ||
| 203 | } | ||
| 204 | |||
| 193 | /// Waits for the next tick. | 205 | /// Waits for the next tick. |
| 194 | pub fn next(&mut self) -> impl Future<Output = ()> + '_ { | 206 | pub fn next(&mut self) -> impl Future<Output = ()> + Send + Sync + '_ { |
| 195 | poll_fn(|cx| { | 207 | poll_fn(|cx| { |
| 196 | if self.expires_at <= Instant::now() { | 208 | if self.expires_at <= Instant::now() { |
| 197 | let dur = self.duration; | 209 | let dur = self.duration; |
diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-usb-dfu/src/fmt.rs +++ b/embassy-usb-dfu/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index da5ff0f36..34d1ca663 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs | |||
| @@ -16,7 +16,6 @@ type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 16 | /// The logger state containing buffers that must live as long as the USB peripheral. | 16 | /// The logger state containing buffers that must live as long as the USB peripheral. |
| 17 | pub struct LoggerState<'d> { | 17 | pub struct LoggerState<'d> { |
| 18 | state: State<'d>, | 18 | state: State<'d>, |
| 19 | device_descriptor: [u8; 32], | ||
| 20 | config_descriptor: [u8; 128], | 19 | config_descriptor: [u8; 128], |
| 21 | bos_descriptor: [u8; 16], | 20 | bos_descriptor: [u8; 16], |
| 22 | msos_descriptor: [u8; 256], | 21 | msos_descriptor: [u8; 256], |
| @@ -28,7 +27,6 @@ impl<'d> LoggerState<'d> { | |||
| 28 | pub fn new() -> Self { | 27 | pub fn new() -> Self { |
| 29 | Self { | 28 | Self { |
| 30 | state: State::new(), | 29 | state: State::new(), |
| 31 | device_descriptor: [0; 32], | ||
| 32 | config_descriptor: [0; 128], | 30 | config_descriptor: [0; 128], |
| 33 | bos_descriptor: [0; 16], | 31 | bos_descriptor: [0; 16], |
| 34 | msos_descriptor: [0; 256], | 32 | msos_descriptor: [0; 256], |
| @@ -74,7 +72,6 @@ impl<const N: usize> UsbLogger<N> { | |||
| 74 | let mut builder = Builder::new( | 72 | let mut builder = Builder::new( |
| 75 | driver, | 73 | driver, |
| 76 | config, | 74 | config, |
| 77 | &mut state.device_descriptor, | ||
| 78 | &mut state.config_descriptor, | 75 | &mut state.config_descriptor, |
| 79 | &mut state.bos_descriptor, | 76 | &mut state.bos_descriptor, |
| 80 | &mut state.msos_descriptor, | 77 | &mut state.msos_descriptor, |
| @@ -151,7 +148,17 @@ struct Writer<'d, const N: usize>(&'d Pipe<CS, N>); | |||
| 151 | 148 | ||
| 152 | impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { | 149 | impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { |
| 153 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { | 150 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { |
| 154 | let _ = self.0.try_write(s.as_bytes()); | 151 | // The Pipe is implemented in such way that we cannot |
| 152 | // write across the wraparound discontinuity. | ||
| 153 | let b = s.as_bytes(); | ||
| 154 | if let Ok(n) = self.0.try_write(b) { | ||
| 155 | if n < b.len() { | ||
| 156 | // We wrote some data but not all, attempt again | ||
| 157 | // as the reason might be a wraparound in the | ||
| 158 | // ring buffer, which resolves on second attempt. | ||
| 159 | let _ = self.0.try_write(&b[n..]); | ||
| 160 | } | ||
| 161 | } | ||
| 155 | Ok(()) | 162 | Ok(()) |
| 156 | } | 163 | } |
| 157 | } | 164 | } |
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c4705d041..c06107396 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs | |||
| @@ -128,7 +128,6 @@ pub struct Builder<'d, D: Driver<'d>> { | |||
| 128 | driver: D, | 128 | driver: D, |
| 129 | next_string_index: u8, | 129 | next_string_index: u8, |
| 130 | 130 | ||
| 131 | device_descriptor: DescriptorWriter<'d>, | ||
| 132 | config_descriptor: DescriptorWriter<'d>, | 131 | config_descriptor: DescriptorWriter<'d>, |
| 133 | bos_descriptor: BosWriter<'d>, | 132 | bos_descriptor: BosWriter<'d>, |
| 134 | 133 | ||
| @@ -144,7 +143,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 144 | pub fn new( | 143 | pub fn new( |
| 145 | driver: D, | 144 | driver: D, |
| 146 | config: Config<'d>, | 145 | config: Config<'d>, |
| 147 | device_descriptor_buf: &'d mut [u8], | ||
| 148 | config_descriptor_buf: &'d mut [u8], | 146 | config_descriptor_buf: &'d mut [u8], |
| 149 | bos_descriptor_buf: &'d mut [u8], | 147 | bos_descriptor_buf: &'d mut [u8], |
| 150 | msos_descriptor_buf: &'d mut [u8], | 148 | msos_descriptor_buf: &'d mut [u8], |
| @@ -167,11 +165,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 167 | _ => panic!("invalid max_packet_size_0, the allowed values are 8, 16, 32 or 64"), | 165 | _ => panic!("invalid max_packet_size_0, the allowed values are 8, 16, 32 or 64"), |
| 168 | } | 166 | } |
| 169 | 167 | ||
| 170 | let mut device_descriptor = DescriptorWriter::new(device_descriptor_buf); | ||
| 171 | let mut config_descriptor = DescriptorWriter::new(config_descriptor_buf); | 168 | let mut config_descriptor = DescriptorWriter::new(config_descriptor_buf); |
| 172 | let mut bos_descriptor = BosWriter::new(DescriptorWriter::new(bos_descriptor_buf)); | 169 | let mut bos_descriptor = BosWriter::new(DescriptorWriter::new(bos_descriptor_buf)); |
| 173 | 170 | ||
| 174 | device_descriptor.device(&config); | ||
| 175 | config_descriptor.configuration(&config); | 171 | config_descriptor.configuration(&config); |
| 176 | bos_descriptor.bos(); | 172 | bos_descriptor.bos(); |
| 177 | 173 | ||
| @@ -183,7 +179,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 183 | control_buf, | 179 | control_buf, |
| 184 | next_string_index: STRING_INDEX_CUSTOM_START, | 180 | next_string_index: STRING_INDEX_CUSTOM_START, |
| 185 | 181 | ||
| 186 | device_descriptor, | ||
| 187 | config_descriptor, | 182 | config_descriptor, |
| 188 | bos_descriptor, | 183 | bos_descriptor, |
| 189 | 184 | ||
| @@ -199,7 +194,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 199 | self.bos_descriptor.end_bos(); | 194 | self.bos_descriptor.end_bos(); |
| 200 | 195 | ||
| 201 | // Log the number of allocator bytes actually used in descriptor buffers | 196 | // Log the number of allocator bytes actually used in descriptor buffers |
| 202 | info!("USB: device_descriptor used: {}", self.device_descriptor.position()); | ||
| 203 | info!("USB: config_descriptor used: {}", self.config_descriptor.position()); | 197 | info!("USB: config_descriptor used: {}", self.config_descriptor.position()); |
| 204 | info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); | 198 | info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); |
| 205 | info!("USB: msos_descriptor used: {}", msos_descriptor.len()); | 199 | info!("USB: msos_descriptor used: {}", msos_descriptor.len()); |
| @@ -209,7 +203,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 209 | self.driver, | 203 | self.driver, |
| 210 | self.config, | 204 | self.config, |
| 211 | self.handlers, | 205 | self.handlers, |
| 212 | self.device_descriptor.into_buf(), | ||
| 213 | self.config_descriptor.into_buf(), | 206 | self.config_descriptor.into_buf(), |
| 214 | self.bos_descriptor.writer.into_buf(), | 207 | self.bos_descriptor.writer.into_buf(), |
| 215 | msos_descriptor, | 208 | msos_descriptor, |
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index fa83ef583..eb3d1f53a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs | |||
| @@ -82,30 +82,6 @@ impl<'a> DescriptorWriter<'a> { | |||
| 82 | self.position = start + length; | 82 | self.position = start + length; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | pub(crate) fn device(&mut self, config: &Config) { | ||
| 86 | self.write( | ||
| 87 | descriptor_type::DEVICE, | ||
| 88 | &[ | ||
| 89 | 0x10, | ||
| 90 | 0x02, // bcdUSB 2.1 | ||
| 91 | config.device_class, // bDeviceClass | ||
| 92 | config.device_sub_class, // bDeviceSubClass | ||
| 93 | config.device_protocol, // bDeviceProtocol | ||
| 94 | config.max_packet_size_0, // bMaxPacketSize0 | ||
| 95 | config.vendor_id as u8, | ||
| 96 | (config.vendor_id >> 8) as u8, // idVendor | ||
| 97 | config.product_id as u8, | ||
| 98 | (config.product_id >> 8) as u8, // idProduct | ||
| 99 | config.device_release as u8, | ||
| 100 | (config.device_release >> 8) as u8, // bcdDevice | ||
| 101 | config.manufacturer.map_or(0, |_| 1), // iManufacturer | ||
| 102 | config.product.map_or(0, |_| 2), // iProduct | ||
| 103 | config.serial_number.map_or(0, |_| 3), // iSerialNumber | ||
| 104 | 1, // bNumConfigurations | ||
| 105 | ], | ||
| 106 | ); | ||
| 107 | } | ||
| 108 | |||
| 109 | pub(crate) fn configuration(&mut self, config: &Config) { | 85 | pub(crate) fn configuration(&mut self, config: &Config) { |
| 110 | self.num_interfaces_mark = Some(self.position + 4); | 86 | self.num_interfaces_mark = Some(self.position + 4); |
| 111 | 87 | ||
| @@ -269,6 +245,33 @@ impl<'a> DescriptorWriter<'a> { | |||
| 269 | } | 245 | } |
| 270 | } | 246 | } |
| 271 | 247 | ||
| 248 | /// Create a new Device Descriptor array. | ||
| 249 | /// | ||
| 250 | /// All device descriptors are always 18 bytes, so there's no need for | ||
| 251 | /// a variable-length buffer or DescriptorWriter. | ||
| 252 | pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { | ||
| 253 | [ | ||
| 254 | 18, // bLength | ||
| 255 | 0x01, // bDescriptorType | ||
| 256 | 0x10, | ||
| 257 | 0x02, // bcdUSB 2.1 | ||
| 258 | config.device_class, // bDeviceClass | ||
| 259 | config.device_sub_class, // bDeviceSubClass | ||
| 260 | config.device_protocol, // bDeviceProtocol | ||
| 261 | config.max_packet_size_0, // bMaxPacketSize0 | ||
| 262 | config.vendor_id as u8, | ||
| 263 | (config.vendor_id >> 8) as u8, // idVendor | ||
| 264 | config.product_id as u8, | ||
| 265 | (config.product_id >> 8) as u8, // idProduct | ||
| 266 | config.device_release as u8, | ||
| 267 | (config.device_release >> 8) as u8, // bcdDevice | ||
| 268 | config.manufacturer.map_or(0, |_| 1), // iManufacturer | ||
| 269 | config.product.map_or(0, |_| 2), // iProduct | ||
| 270 | config.serial_number.map_or(0, |_| 3), // iSerialNumber | ||
| 271 | 1, // bNumConfigurations | ||
| 272 | ] | ||
| 273 | } | ||
| 274 | |||
| 272 | /// A writer for Binary Object Store descriptor. | 275 | /// A writer for Binary Object Store descriptor. |
| 273 | pub struct BosWriter<'a> { | 276 | pub struct BosWriter<'a> { |
| 274 | pub(crate) writer: DescriptorWriter<'a>, | 277 | pub(crate) writer: DescriptorWriter<'a>, |
diff --git a/embassy-usb/src/fmt.rs b/embassy-usb/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-usb/src/fmt.rs +++ b/embassy-usb/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 241e33a78..d58950838 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -168,8 +168,6 @@ struct Interface { | |||
| 168 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] | 168 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
| 169 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 169 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 170 | pub struct UsbBufferReport { | 170 | pub struct UsbBufferReport { |
| 171 | /// Number of device descriptor bytes used | ||
| 172 | pub device_descriptor_used: usize, | ||
| 173 | /// Number of config descriptor bytes used | 171 | /// Number of config descriptor bytes used |
| 174 | pub config_descriptor_used: usize, | 172 | pub config_descriptor_used: usize, |
| 175 | /// Number of bos descriptor bytes used | 173 | /// Number of bos descriptor bytes used |
| @@ -191,7 +189,7 @@ struct Inner<'d, D: Driver<'d>> { | |||
| 191 | bus: D::Bus, | 189 | bus: D::Bus, |
| 192 | 190 | ||
| 193 | config: Config<'d>, | 191 | config: Config<'d>, |
| 194 | device_descriptor: &'d [u8], | 192 | device_descriptor: [u8; 18], |
| 195 | config_descriptor: &'d [u8], | 193 | config_descriptor: &'d [u8], |
| 196 | bos_descriptor: &'d [u8], | 194 | bos_descriptor: &'d [u8], |
| 197 | msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, | 195 | msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, |
| @@ -217,7 +215,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 217 | driver: D, | 215 | driver: D, |
| 218 | config: Config<'d>, | 216 | config: Config<'d>, |
| 219 | handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>, | 217 | handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>, |
| 220 | device_descriptor: &'d [u8], | ||
| 221 | config_descriptor: &'d [u8], | 218 | config_descriptor: &'d [u8], |
| 222 | bos_descriptor: &'d [u8], | 219 | bos_descriptor: &'d [u8], |
| 223 | msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, | 220 | msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, |
| @@ -227,6 +224,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 227 | // Start the USB bus. | 224 | // Start the USB bus. |
| 228 | // This prevent further allocation by consuming the driver. | 225 | // This prevent further allocation by consuming the driver. |
| 229 | let (bus, control) = driver.start(config.max_packet_size_0 as u16); | 226 | let (bus, control) = driver.start(config.max_packet_size_0 as u16); |
| 227 | let device_descriptor = descriptor::device_descriptor(&config); | ||
| 230 | 228 | ||
| 231 | Self { | 229 | Self { |
| 232 | control_buf, | 230 | control_buf, |
| @@ -256,7 +254,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 256 | /// Useful for tuning buffer sizes for actual usage | 254 | /// Useful for tuning buffer sizes for actual usage |
| 257 | pub fn buffer_usage(&self) -> UsbBufferReport { | 255 | pub fn buffer_usage(&self) -> UsbBufferReport { |
| 258 | UsbBufferReport { | 256 | UsbBufferReport { |
| 259 | device_descriptor_used: self.inner.device_descriptor.len(), | ||
| 260 | config_descriptor_used: self.inner.config_descriptor.len(), | 257 | config_descriptor_used: self.inner.config_descriptor.len(), |
| 261 | bos_descriptor_used: self.inner.bos_descriptor.len(), | 258 | bos_descriptor_used: self.inner.bos_descriptor.len(), |
| 262 | msos_descriptor_used: self.inner.msos_descriptor.len(), | 259 | msos_descriptor_used: self.inner.msos_descriptor.len(), |
| @@ -720,7 +717,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { | |||
| 720 | 717 | ||
| 721 | match dtype { | 718 | match dtype { |
| 722 | descriptor_type::BOS => InResponse::Accepted(self.bos_descriptor), | 719 | descriptor_type::BOS => InResponse::Accepted(self.bos_descriptor), |
| 723 | descriptor_type::DEVICE => InResponse::Accepted(self.device_descriptor), | 720 | descriptor_type::DEVICE => InResponse::Accepted(&self.device_descriptor), |
| 724 | descriptor_type::CONFIGURATION => InResponse::Accepted(self.config_descriptor), | 721 | descriptor_type::CONFIGURATION => InResponse::Accepted(self.config_descriptor), |
| 725 | descriptor_type::STRING => { | 722 | descriptor_type::STRING => { |
| 726 | if index == 0 { | 723 | if index == 0 { |
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 3858c0f51..25936d084 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs | |||
| @@ -226,27 +226,21 @@ pub mod windows_version { | |||
| 226 | pub const WIN10: u32 = 0x0A000000; | 226 | pub const WIN10: u32 = 0x0A000000; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | mod sealed { | 229 | /// A trait for descriptors |
| 230 | use core::mem::size_of; | 230 | trait Descriptor: Sized { |
| 231 | const TYPE: DescriptorType; | ||
| 231 | 232 | ||
| 232 | /// A trait for descriptors | 233 | /// The size of the descriptor's header. |
| 233 | pub trait Descriptor: Sized { | 234 | fn size(&self) -> usize { |
| 234 | const TYPE: super::DescriptorType; | 235 | size_of::<Self>() |
| 235 | |||
| 236 | /// The size of the descriptor's header. | ||
| 237 | fn size(&self) -> usize { | ||
| 238 | size_of::<Self>() | ||
| 239 | } | ||
| 240 | |||
| 241 | fn write_to(&self, buf: &mut [u8]); | ||
| 242 | } | 236 | } |
| 243 | 237 | ||
| 244 | pub trait DescriptorSet: Descriptor { | 238 | fn write_to(&self, buf: &mut [u8]); |
| 245 | const LENGTH_OFFSET: usize; | ||
| 246 | } | ||
| 247 | } | 239 | } |
| 248 | 240 | ||
| 249 | use sealed::*; | 241 | trait DescriptorSet: Descriptor { |
| 242 | const LENGTH_OFFSET: usize; | ||
| 243 | } | ||
| 250 | 244 | ||
| 251 | /// Copies the data of `t` into `buf`. | 245 | /// Copies the data of `t` into `buf`. |
| 252 | /// | 246 | /// |
| @@ -255,7 +249,7 @@ use sealed::*; | |||
| 255 | unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { | 249 | unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { |
| 256 | let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>()); | 250 | let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>()); |
| 257 | assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full"); | 251 | assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full"); |
| 258 | (&mut buf[..bytes.len()]).copy_from_slice(bytes); | 252 | buf[..bytes.len()].copy_from_slice(bytes); |
| 259 | } | 253 | } |
| 260 | 254 | ||
| 261 | /// Table 9. Microsoft OS 2.0 descriptor wDescriptorType values. | 255 | /// Table 9. Microsoft OS 2.0 descriptor wDescriptorType values. |
| @@ -412,9 +406,11 @@ impl DescriptorSet for FunctionSubsetHeader { | |||
| 412 | // Feature Descriptors | 406 | // Feature Descriptors |
| 413 | 407 | ||
| 414 | /// A marker trait for feature descriptors that are valid at the device level. | 408 | /// A marker trait for feature descriptors that are valid at the device level. |
| 409 | #[allow(private_bounds)] | ||
| 415 | pub trait DeviceLevelDescriptor: Descriptor {} | 410 | pub trait DeviceLevelDescriptor: Descriptor {} |
| 416 | 411 | ||
| 417 | /// A marker trait for feature descriptors that are valid at the function level. | 412 | /// A marker trait for feature descriptors that are valid at the function level. |
| 413 | #[allow(private_bounds)] | ||
| 418 | pub trait FunctionLevelDescriptor: Descriptor {} | 414 | pub trait FunctionLevelDescriptor: Descriptor {} |
| 419 | 415 | ||
| 420 | /// Table 13. Microsoft OS 2.0 compatible ID descriptor. | 416 | /// Table 13. Microsoft OS 2.0 compatible ID descriptor. |
| @@ -444,9 +440,9 @@ impl CompatibleIdFeatureDescriptor { | |||
| 444 | pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self { | 440 | pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self { |
| 445 | assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8); | 441 | assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8); |
| 446 | let mut cid = [0u8; 8]; | 442 | let mut cid = [0u8; 8]; |
| 447 | (&mut cid[..compatible_id.len()]).copy_from_slice(compatible_id.as_bytes()); | 443 | cid[..compatible_id.len()].copy_from_slice(compatible_id.as_bytes()); |
| 448 | let mut scid = [0u8; 8]; | 444 | let mut scid = [0u8; 8]; |
| 449 | (&mut scid[..sub_compatible_id.len()]).copy_from_slice(sub_compatible_id.as_bytes()); | 445 | scid[..sub_compatible_id.len()].copy_from_slice(sub_compatible_id.as_bytes()); |
| 450 | Self::new_raw(cid, scid) | 446 | Self::new_raw(cid, scid) |
| 451 | } | 447 | } |
| 452 | 448 | ||
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 37c3d7d90..929d6802c 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs | |||
| @@ -41,7 +41,6 @@ async fn main(_spawner: Spawner) { | |||
| 41 | config.product = Some("USB-DFU Runtime example"); | 41 | config.product = Some("USB-DFU Runtime example"); |
| 42 | config.serial_number = Some("1235678"); | 42 | config.serial_number = Some("1235678"); |
| 43 | 43 | ||
| 44 | let mut device_descriptor = [0; 256]; | ||
| 45 | let mut config_descriptor = [0; 256]; | 44 | let mut config_descriptor = [0; 256]; |
| 46 | let mut bos_descriptor = [0; 256]; | 45 | let mut bos_descriptor = [0; 256]; |
| 47 | let mut control_buf = [0; 64]; | 46 | let mut control_buf = [0; 64]; |
| @@ -49,7 +48,6 @@ async fn main(_spawner: Spawner) { | |||
| 49 | let mut builder = Builder::new( | 48 | let mut builder = Builder::new( |
| 50 | driver, | 49 | driver, |
| 51 | config, | 50 | config, |
| 52 | &mut device_descriptor, | ||
| 53 | &mut config_descriptor, | 51 | &mut config_descriptor, |
| 54 | &mut bos_descriptor, | 52 | &mut bos_descriptor, |
| 55 | &mut [], | 53 | &mut [], |
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index d989fbfdf..093b39f9d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs | |||
| @@ -49,7 +49,6 @@ fn main() -> ! { | |||
| 49 | let mut buffer = AlignedBuffer([0; WRITE_SIZE]); | 49 | let mut buffer = AlignedBuffer([0; WRITE_SIZE]); |
| 50 | let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); | 50 | let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); |
| 51 | 51 | ||
| 52 | let mut device_descriptor = [0; 256]; | ||
| 53 | let mut config_descriptor = [0; 256]; | 52 | let mut config_descriptor = [0; 256]; |
| 54 | let mut bos_descriptor = [0; 256]; | 53 | let mut bos_descriptor = [0; 256]; |
| 55 | let mut control_buf = [0; 4096]; | 54 | let mut control_buf = [0; 4096]; |
| @@ -57,7 +56,6 @@ fn main() -> ! { | |||
| 57 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 58 | driver, | 57 | driver, |
| 59 | config, | 58 | config, |
| 60 | &mut device_descriptor, | ||
| 61 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 63 | &mut [], | 61 | &mut [], |
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 3469c6e5f..a7e5c2668 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs | |||
| @@ -70,7 +70,6 @@ async fn main(spawner: Spawner) { | |||
| 70 | config.device_protocol = 0x01; | 70 | config.device_protocol = 0x01; |
| 71 | 71 | ||
| 72 | // Create embassy-usb DeviceBuilder using the driver and config. | 72 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 73 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 74 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 73 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 75 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 74 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 76 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); | 75 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); |
| @@ -78,7 +77,6 @@ async fn main(spawner: Spawner) { | |||
| 78 | let mut builder = Builder::new( | 77 | let mut builder = Builder::new( |
| 79 | driver, | 78 | driver, |
| 80 | config, | 79 | config, |
| 81 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 82 | &mut CONFIG_DESC.init([0; 256])[..], | 80 | &mut CONFIG_DESC.init([0; 256])[..], |
| 83 | &mut BOS_DESC.init([0; 256])[..], | 81 | &mut BOS_DESC.init([0; 256])[..], |
| 84 | &mut MSOS_DESC.init([0; 128])[..], | 82 | &mut MSOS_DESC.init([0; 128])[..], |
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 3e86590c4..52f081487 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs | |||
| @@ -50,7 +50,6 @@ async fn main(_spawner: Spawner) { | |||
| 50 | 50 | ||
| 51 | // Create embassy-usb DeviceBuilder using the driver and config. | 51 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 52 | // It needs some buffers for building the descriptors. | 52 | // It needs some buffers for building the descriptors. |
| 53 | let mut device_descriptor = [0; 256]; | ||
| 54 | let mut config_descriptor = [0; 256]; | 53 | let mut config_descriptor = [0; 256]; |
| 55 | let mut bos_descriptor = [0; 256]; | 54 | let mut bos_descriptor = [0; 256]; |
| 56 | let mut msos_descriptor = [0; 256]; | 55 | let mut msos_descriptor = [0; 256]; |
| @@ -63,7 +62,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | let mut builder = Builder::new( | 62 | let mut builder = Builder::new( |
| 64 | driver, | 63 | driver, |
| 65 | config, | 64 | config, |
| 66 | &mut device_descriptor, | ||
| 67 | &mut config_descriptor, | 65 | &mut config_descriptor, |
| 68 | &mut bos_descriptor, | 66 | &mut bos_descriptor, |
| 69 | &mut msos_descriptor, | 67 | &mut msos_descriptor, |
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 04ad841b7..5d2837793 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs | |||
| @@ -43,7 +43,6 @@ async fn main(_spawner: Spawner) { | |||
| 43 | 43 | ||
| 44 | // Create embassy-usb DeviceBuilder using the driver and config. | 44 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 45 | // It needs some buffers for building the descriptors. | 45 | // It needs some buffers for building the descriptors. |
| 46 | let mut device_descriptor = [0; 256]; | ||
| 47 | let mut config_descriptor = [0; 256]; | 46 | let mut config_descriptor = [0; 256]; |
| 48 | let mut bos_descriptor = [0; 256]; | 47 | let mut bos_descriptor = [0; 256]; |
| 49 | let mut msos_descriptor = [0; 256]; | 48 | let mut msos_descriptor = [0; 256]; |
| @@ -55,7 +54,6 @@ async fn main(_spawner: Spawner) { | |||
| 55 | let mut builder = Builder::new( | 54 | let mut builder = Builder::new( |
| 56 | driver, | 55 | driver, |
| 57 | config, | 56 | config, |
| 58 | &mut device_descriptor, | ||
| 59 | &mut config_descriptor, | 57 | &mut config_descriptor, |
| 60 | &mut bos_descriptor, | 58 | &mut bos_descriptor, |
| 61 | &mut msos_descriptor, | 59 | &mut msos_descriptor, |
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index aff539b1b..02048e692 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs | |||
| @@ -48,7 +48,6 @@ async fn main(_spawner: Spawner) { | |||
| 48 | 48 | ||
| 49 | // Create embassy-usb DeviceBuilder using the driver and config. | 49 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 50 | // It needs some buffers for building the descriptors. | 50 | // It needs some buffers for building the descriptors. |
| 51 | let mut device_descriptor = [0; 256]; | ||
| 52 | let mut config_descriptor = [0; 256]; | 51 | let mut config_descriptor = [0; 256]; |
| 53 | let mut bos_descriptor = [0; 256]; | 52 | let mut bos_descriptor = [0; 256]; |
| 54 | let mut msos_descriptor = [0; 256]; | 53 | let mut msos_descriptor = [0; 256]; |
| @@ -59,7 +58,6 @@ async fn main(_spawner: Spawner) { | |||
| 59 | let mut builder = Builder::new( | 58 | let mut builder = Builder::new( |
| 60 | driver, | 59 | driver, |
| 61 | config, | 60 | config, |
| 62 | &mut device_descriptor, | ||
| 63 | &mut config_descriptor, | 61 | &mut config_descriptor, |
| 64 | &mut bos_descriptor, | 62 | &mut bos_descriptor, |
| 65 | &mut msos_descriptor, | 63 | &mut msos_descriptor, |
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 4e8118fb8..895cca8b9 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs | |||
| @@ -67,7 +67,6 @@ async fn main(spawner: Spawner) { | |||
| 67 | let state = STATE.init(State::new()); | 67 | let state = STATE.init(State::new()); |
| 68 | 68 | ||
| 69 | // Create embassy-usb DeviceBuilder using the driver and config. | 69 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 70 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 71 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 70 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 72 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 71 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 73 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); | 72 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); |
| @@ -75,7 +74,6 @@ async fn main(spawner: Spawner) { | |||
| 75 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 76 | driver, | 75 | driver, |
| 77 | config, | 76 | config, |
| 78 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 79 | &mut CONFIG_DESC.init([0; 256])[..], | 77 | &mut CONFIG_DESC.init([0; 256])[..], |
| 80 | &mut BOS_DESC.init([0; 256])[..], | 78 | &mut BOS_DESC.init([0; 256])[..], |
| 81 | &mut MSOS_DESC.init([0; 128])[..], | 79 | &mut MSOS_DESC.init([0; 128])[..], |
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 060f9ba94..c6675a3d3 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs | |||
| @@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | 53 | ||
| 54 | // Create embassy-usb DeviceBuilder using the driver and config. | 54 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 55 | // It needs some buffers for building the descriptors. | 55 | // It needs some buffers for building the descriptors. |
| 56 | let mut device_descriptor = [0; 256]; | ||
| 57 | let mut config_descriptor = [0; 256]; | 56 | let mut config_descriptor = [0; 256]; |
| 58 | let mut bos_descriptor = [0; 256]; | 57 | let mut bos_descriptor = [0; 256]; |
| 59 | let mut msos_descriptor = [0; 256]; | 58 | let mut msos_descriptor = [0; 256]; |
| @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | let mut builder = Builder::new( | 63 | let mut builder = Builder::new( |
| 65 | driver, | 64 | driver, |
| 66 | config, | 65 | config, |
| 67 | &mut device_descriptor, | ||
| 68 | &mut config_descriptor, | 66 | &mut config_descriptor, |
| 69 | &mut bos_descriptor, | 67 | &mut bos_descriptor, |
| 70 | &mut msos_descriptor, | 68 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index c7b087476..7cb546c91 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs | |||
| @@ -30,10 +30,14 @@ fn main() -> ! { | |||
| 30 | let p = embassy_rp::init(Default::default()); | 30 | let p = embassy_rp::init(Default::default()); |
| 31 | let led = Output::new(p.PIN_25, Level::Low); | 31 | let led = Output::new(p.PIN_25, Level::Low); |
| 32 | 32 | ||
| 33 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | 33 | spawn_core1( |
| 34 | let executor1 = EXECUTOR1.init(Executor::new()); | 34 | p.CORE1, |
| 35 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); | 35 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, |
| 36 | }); | 36 | move || { |
| 37 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 38 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); | ||
| 39 | }, | ||
| 40 | ); | ||
| 37 | 41 | ||
| 38 | let executor0 = EXECUTOR0.init(Executor::new()); | 42 | let executor0 = EXECUTOR0.init(Executor::new()); |
| 39 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); | 43 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); |
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 3fab7b5f2..6c02630e0 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs | |||
| @@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) { | |||
| 35 | // allowing direct connection of the display to the RP2040 without level shifters. | 35 | // allowing direct connection of the display to the RP2040 without level shifters. |
| 36 | let p = embassy_rp::init(Default::default()); | 36 | let p = embassy_rp::init(Default::default()); |
| 37 | 37 | ||
| 38 | let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { | 38 | let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, { |
| 39 | let mut c = pwm::Config::default(); | 39 | let mut c = pwm::Config::default(); |
| 40 | c.divider = 125.into(); | 40 | c.divider = 125.into(); |
| 41 | c.top = 100; | 41 | c.top = 100; |
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index a07f1c180..53b696309 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs | |||
| @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { | |||
| 60 | 60 | ||
| 61 | // Create embassy-usb DeviceBuilder using the driver and config. | 61 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 62 | // It needs some buffers for building the descriptors. | 62 | // It needs some buffers for building the descriptors. |
| 63 | let mut device_descriptor = [0; 256]; | ||
| 64 | let mut config_descriptor = [0; 256]; | 63 | let mut config_descriptor = [0; 256]; |
| 65 | let mut bos_descriptor = [0; 256]; | 64 | let mut bos_descriptor = [0; 256]; |
| 66 | let mut control_buf = [0; 64]; | 65 | let mut control_buf = [0; 64]; |
| @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 70 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 71 | driver, | 70 | driver, |
| 72 | config, | 71 | config, |
| 73 | &mut device_descriptor, | ||
| 74 | &mut config_descriptor, | 72 | &mut config_descriptor, |
| 75 | &mut bos_descriptor, | 73 | &mut bos_descriptor, |
| 76 | &mut [], // no msos descriptors | 74 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 4fb62546d..26e233260 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs | |||
| @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let mut c: Config = Default::default(); | 18 | let mut c: Config = Default::default(); |
| 19 | c.top = 0x8000; | 19 | c.top = 0x8000; |
| 20 | c.compare_b = 8; | 20 | c.compare_b = 8; |
| 21 | let mut pwm = Pwm::new_output_b(p.PWM_CH4, p.PIN_25, c.clone()); | 21 | let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); |
| 22 | 22 | ||
| 23 | loop { | 23 | loop { |
| 24 | info!("current LED duty cycle: {}/32768", c.compare_b); | 24 | info!("current LED duty cycle: {}/32768", c.compare_b); |
diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs index e7bcbfbd4..0652dc42b 100644 --- a/examples/rp/src/bin/pwm_input.rs +++ b/examples/rp/src/bin/pwm_input.rs | |||
| @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { | |||
| 14 | let p = embassy_rp::init(Default::default()); | 14 | let p = embassy_rp::init(Default::default()); |
| 15 | 15 | ||
| 16 | let cfg: Config = Default::default(); | 16 | let cfg: Config = Default::default(); |
| 17 | let pwm = Pwm::new_input(p.PWM_CH2, p.PIN_5, InputMode::RisingEdge, cfg); | 17 | let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, InputMode::RisingEdge, cfg); |
| 18 | 18 | ||
| 19 | let mut ticker = Ticker::every(Duration::from_secs(1)); | 19 | let mut ticker = Ticker::every(Duration::from_secs(1)); |
| 20 | loop { | 20 | loop { |
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 01f0d5967..f1b124efa 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs | |||
| @@ -64,14 +64,12 @@ async fn main(spawner: Spawner) { | |||
| 64 | config.device_protocol = 0x01; | 64 | config.device_protocol = 0x01; |
| 65 | 65 | ||
| 66 | // Create embassy-usb DeviceBuilder using the driver and config. | 66 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 67 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 68 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 67 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 69 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 68 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 70 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 69 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 71 | let mut builder = Builder::new( | 70 | let mut builder = Builder::new( |
| 72 | driver, | 71 | driver, |
| 73 | config, | 72 | config, |
| 74 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 75 | &mut CONFIG_DESC.init([0; 256])[..], | 73 | &mut CONFIG_DESC.init([0; 256])[..], |
| 76 | &mut BOS_DESC.init([0; 256])[..], | 74 | &mut BOS_DESC.init([0; 256])[..], |
| 77 | &mut [], // no msos descriptors | 75 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index b5ac16245..710be8d13 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs | |||
| @@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) { | |||
| 36 | 36 | ||
| 37 | // Create embassy-usb DeviceBuilder using the driver and config. | 37 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 38 | // It needs some buffers for building the descriptors. | 38 | // It needs some buffers for building the descriptors. |
| 39 | let mut device_descriptor = [0; 256]; | ||
| 40 | let mut config_descriptor = [0; 256]; | 39 | let mut config_descriptor = [0; 256]; |
| 41 | let mut bos_descriptor = [0; 256]; | 40 | let mut bos_descriptor = [0; 256]; |
| 42 | // You can also add a Microsoft OS descriptor. | 41 | // You can also add a Microsoft OS descriptor. |
| @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { | |||
| 50 | let mut builder = Builder::new( | 49 | let mut builder = Builder::new( |
| 51 | driver, | 50 | driver, |
| 52 | config, | 51 | config, |
| 53 | &mut device_descriptor, | ||
| 54 | &mut config_descriptor, | 52 | &mut config_descriptor, |
| 55 | &mut bos_descriptor, | 53 | &mut bos_descriptor, |
| 56 | &mut msos_descriptor, | 54 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index afebd8813..e8b399cb1 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs | |||
| @@ -39,7 +39,6 @@ async fn main(_spawner: Spawner) { | |||
| 39 | 39 | ||
| 40 | // Create embassy-usb DeviceBuilder using the driver and config. | 40 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 41 | // It needs some buffers for building the descriptors. | 41 | // It needs some buffers for building the descriptors. |
| 42 | let mut device_descriptor = [0; 256]; | ||
| 43 | let mut config_descriptor = [0; 256]; | 42 | let mut config_descriptor = [0; 256]; |
| 44 | let mut bos_descriptor = [0; 256]; | 43 | let mut bos_descriptor = [0; 256]; |
| 45 | // You can also add a Microsoft OS descriptor. | 44 | // You can also add a Microsoft OS descriptor. |
| @@ -53,7 +52,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let mut builder = Builder::new( | 52 | let mut builder = Builder::new( |
| 54 | driver, | 53 | driver, |
| 55 | config, | 54 | config, |
| 56 | &mut device_descriptor, | ||
| 57 | &mut config_descriptor, | 55 | &mut config_descriptor, |
| 58 | &mut bos_descriptor, | 56 | &mut bos_descriptor, |
| 59 | &mut msos_descriptor, | 57 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index 95306a35c..11db1b2e1 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 47 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 48 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -54,7 +53,6 @@ async fn main(_spawner: Spawner) { | |||
| 54 | let mut builder = Builder::new( | 53 | let mut builder = Builder::new( |
| 55 | driver, | 54 | driver, |
| 56 | config, | 55 | config, |
| 57 | &mut device_descriptor, | ||
| 58 | &mut config_descriptor, | 56 | &mut config_descriptor, |
| 59 | &mut bos_descriptor, | 57 | &mut bos_descriptor, |
| 60 | &mut [], // no msos descriptors | 58 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index a6c8a5b2e..97e7e0244 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs | |||
| @@ -93,7 +93,6 @@ async fn main(_spawner: Spawner) { | |||
| 93 | 93 | ||
| 94 | // Create embassy-usb DeviceBuilder using the driver and config. | 94 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 95 | // It needs some buffers for building the descriptors. | 95 | // It needs some buffers for building the descriptors. |
| 96 | let mut device_descriptor = [0; 256]; | ||
| 97 | let mut config_descriptor = [0; 256]; | 96 | let mut config_descriptor = [0; 256]; |
| 98 | let mut bos_descriptor = [0; 256]; | 97 | let mut bos_descriptor = [0; 256]; |
| 99 | let mut msos_descriptor = [0; 256]; | 98 | let mut msos_descriptor = [0; 256]; |
| @@ -106,7 +105,6 @@ async fn main(_spawner: Spawner) { | |||
| 106 | let mut builder = Builder::new( | 105 | let mut builder = Builder::new( |
| 107 | driver, | 106 | driver, |
| 108 | config, | 107 | config, |
| 109 | &mut device_descriptor, | ||
| 110 | &mut config_descriptor, | 108 | &mut config_descriptor, |
| 111 | &mut bos_descriptor, | 109 | &mut bos_descriptor, |
| 112 | &mut msos_descriptor, | 110 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 0dc8e9f72..331c3da4c 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs | |||
| @@ -71,7 +71,6 @@ async fn main(_spawner: Spawner) { | |||
| 71 | 71 | ||
| 72 | // Create embassy-usb DeviceBuilder using the driver and config. | 72 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 73 | // It needs some buffers for building the descriptors. | 73 | // It needs some buffers for building the descriptors. |
| 74 | let mut device_descriptor = [0; 256]; | ||
| 75 | let mut config_descriptor = [0; 256]; | 74 | let mut config_descriptor = [0; 256]; |
| 76 | let mut bos_descriptor = [0; 256]; | 75 | let mut bos_descriptor = [0; 256]; |
| 77 | let mut msos_descriptor = [0; 256]; | 76 | let mut msos_descriptor = [0; 256]; |
| @@ -80,7 +79,6 @@ async fn main(_spawner: Spawner) { | |||
| 80 | let mut builder = Builder::new( | 79 | let mut builder = Builder::new( |
| 81 | driver, | 80 | driver, |
| 82 | config, | 81 | config, |
| 83 | &mut device_descriptor, | ||
| 84 | &mut config_descriptor, | 82 | &mut config_descriptor, |
| 85 | &mut bos_descriptor, | 83 | &mut bos_descriptor, |
| 86 | &mut msos_descriptor, | 84 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index ab24a994c..3c9bc96dd 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 47 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 48 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) { | |||
| 56 | let mut builder = Builder::new( | 55 | let mut builder = Builder::new( |
| 57 | driver, | 56 | driver, |
| 58 | config, | 57 | config, |
| 59 | &mut device_descriptor, | ||
| 60 | &mut config_descriptor, | 58 | &mut config_descriptor, |
| 61 | &mut bos_descriptor, | 59 | &mut bos_descriptor, |
| 62 | &mut [], // no msos descriptors | 60 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs index 4ba4fc25c..f9cfdef94 100644 --- a/examples/rp/src/bin/usb_serial_with_logger.rs +++ b/examples/rp/src/bin/usb_serial_with_logger.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 47 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 48 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -57,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 57 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 58 | driver, | 57 | driver, |
| 59 | config, | 58 | config, |
| 60 | &mut device_descriptor, | ||
| 61 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 63 | &mut [], // no msos descriptors | 61 | &mut [], // no msos descriptors |
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index dad93d0a1..59813d8cb 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | use std::default::Default; | ||
| 2 | |||
| 3 | use clap::Parser; | 1 | use clap::Parser; |
| 4 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 5 | use embassy_net::tcp::TcpSocket; | 3 | use embassy_net::tcp::TcpSocket; |
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index fca1e076e..3b6a3de37 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | use std::default::Default; | ||
| 2 | |||
| 3 | use clap::Parser; | 1 | use clap::Parser; |
| 4 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 5 | use embassy_net::dns::DnsQueryType; | 3 | use embassy_net::dns::DnsQueryType; |
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 00ccd83a7..e8b6eaa6c 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | use core::fmt::Write as _; | 1 | use core::fmt::Write as _; |
| 2 | use std::default::Default; | ||
| 3 | 2 | ||
| 4 | use clap::Parser; | 3 | use clap::Parser; |
| 5 | use embassy_executor::{Executor, Spawner}; | 4 | use embassy_executor::{Executor, Spawner}; |
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index df5d32f70..4f282f326 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml | |||
| @@ -23,6 +23,7 @@ panic-probe = { version = "0.3", 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 | heapless = { version = "0.8", default-features = false } | 24 | heapless = { version = "0.8", default-features = false } |
| 25 | nb = "1.0.0" | 25 | nb = "1.0.0" |
| 26 | static_cell = "2.0.0" | ||
| 26 | 27 | ||
| 27 | [profile.dev] | 28 | [profile.dev] |
| 28 | opt-level = "s" | 29 | opt-level = "s" |
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index c1c4f8359..1c13d623d 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs | |||
| @@ -3,11 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::can::bxcan::filter::Mask32; | 6 | use embassy_stm32::can::frame::Envelope; |
| 7 | use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; | 7 | use embassy_stm32::can::{ |
| 8 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 8 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 9 | TxInterruptHandler, | ||
| 10 | }; | ||
| 9 | use embassy_stm32::peripherals::CAN; | 11 | use embassy_stm32::peripherals::CAN; |
| 10 | use embassy_stm32::{bind_interrupts, Config}; | 12 | use embassy_stm32::{bind_interrupts, Config}; |
| 13 | use static_cell::StaticCell; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 15 | ||
| 13 | bind_interrupts!(struct Irqs { | 16 | bind_interrupts!(struct Irqs { |
| @@ -20,6 +23,27 @@ bind_interrupts!(struct Irqs { | |||
| 20 | // This example is configured to work with real CAN transceivers on B8/B9. | 23 | // This example is configured to work with real CAN transceivers on B8/B9. |
| 21 | // See other examples for loopback. | 24 | // See other examples for loopback. |
| 22 | 25 | ||
| 26 | fn handle_frame(env: Envelope, read_mode: &str) { | ||
| 27 | match env.frame.id() { | ||
| 28 | Id::Extended(id) => { | ||
| 29 | defmt::println!( | ||
| 30 | "{} Extended Frame id={:x} {:02x}", | ||
| 31 | read_mode, | ||
| 32 | id.as_raw(), | ||
| 33 | env.frame.data() | ||
| 34 | ); | ||
| 35 | } | ||
| 36 | Id::Standard(id) => { | ||
| 37 | defmt::println!( | ||
| 38 | "{} Standard Frame id={:x} {:02x}", | ||
| 39 | read_mode, | ||
| 40 | id.as_raw(), | ||
| 41 | env.frame.data() | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 23 | #[embassy_executor::main] | 47 | #[embassy_executor::main] |
| 24 | async fn main(_spawner: Spawner) { | 48 | async fn main(_spawner: Spawner) { |
| 25 | let p = embassy_stm32::init(Config::default()); | 49 | let p = embassy_stm32::init(Config::default()); |
| @@ -27,36 +51,86 @@ async fn main(_spawner: Spawner) { | |||
| 27 | // Set alternate pin mapping to B8/B9 | 51 | // Set alternate pin mapping to B8/B9 |
| 28 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); | 52 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); |
| 29 | 53 | ||
| 54 | static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new(); | ||
| 55 | static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new(); | ||
| 56 | |||
| 30 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); | 57 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); |
| 31 | 58 | ||
| 32 | can.as_mut() | 59 | can.modify_filters() |
| 33 | .modify_filters() | 60 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); |
| 34 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 35 | 61 | ||
| 36 | can.as_mut() | 62 | can.modify_config() |
| 37 | .modify_config() | ||
| 38 | .set_loopback(false) | 63 | .set_loopback(false) |
| 39 | .set_silent(false) | 64 | .set_silent(false) |
| 40 | .leave_disabled(); | 65 | .set_bitrate(250_000); |
| 41 | |||
| 42 | can.set_bitrate(250_000); | ||
| 43 | 66 | ||
| 44 | can.enable().await; | 67 | can.enable().await; |
| 45 | |||
| 46 | let mut i: u8 = 0; | 68 | let mut i: u8 = 0; |
| 69 | |||
| 70 | /* | ||
| 71 | // Example for using buffered Tx and Rx without needing to | ||
| 72 | // split first as is done below. | ||
| 73 | let mut can = can.buffered( | ||
| 74 | TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()), | ||
| 75 | RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); | ||
| 76 | loop { | ||
| 77 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 78 | can.write(&tx_frame).await; | ||
| 79 | |||
| 80 | match can.read().await { | ||
| 81 | Ok((frame, ts)) => { | ||
| 82 | handle_frame(Envelope { ts, frame }, "Buf"); | ||
| 83 | } | ||
| 84 | Err(err) => { | ||
| 85 | defmt::println!("Error {}", err); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | i += 1; | ||
| 89 | } | ||
| 90 | |||
| 91 | */ | ||
| 92 | let (mut tx, mut rx) = can.split(); | ||
| 93 | |||
| 94 | // This example shows using the wait_not_empty API before try read | ||
| 95 | while i < 3 { | ||
| 96 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 97 | tx.write(&tx_frame).await; | ||
| 98 | |||
| 99 | rx.wait_not_empty().await; | ||
| 100 | let env = rx.try_read().unwrap(); | ||
| 101 | handle_frame(env, "Wait"); | ||
| 102 | i += 1; | ||
| 103 | } | ||
| 104 | |||
| 105 | // This example shows using the full async non-buffered API | ||
| 106 | while i < 6 { | ||
| 107 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 108 | tx.write(&tx_frame).await; | ||
| 109 | |||
| 110 | match rx.read().await { | ||
| 111 | Ok(env) => { | ||
| 112 | handle_frame(env, "NoBuf"); | ||
| 113 | } | ||
| 114 | Err(err) => { | ||
| 115 | defmt::println!("Error {}", err); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | i += 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | // This example shows using buffered RX and TX. User passes in desired buffer (size) | ||
| 122 | // It's possible this way to have just RX or TX buffered. | ||
| 123 | let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); | ||
| 124 | let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new())); | ||
| 125 | |||
| 47 | loop { | 126 | loop { |
| 48 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); | 127 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); |
| 49 | can.write(&tx_frame).await; | 128 | tx.write(&tx_frame).await; |
| 50 | 129 | ||
| 51 | match can.read().await { | 130 | match rx.read().await { |
| 52 | Ok(env) => match env.frame.id() { | 131 | Ok(envelope) => { |
| 53 | Id::Extended(id) => { | 132 | handle_frame(envelope, "Buf"); |
| 54 | defmt::println!("Extended Frame id={:x}", id.as_raw()); | 133 | } |
| 55 | } | ||
| 56 | Id::Standard(id) => { | ||
| 57 | defmt::println!("Standard Frame id={:x}", id.as_raw()); | ||
| 58 | } | ||
| 59 | }, | ||
| 60 | Err(err) => { | 134 | Err(err) => { |
| 61 | defmt::println!("Error {}", err); | 135 | defmt::println!("Error {}", err); |
| 62 | } | 136 | } |
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 1ae6c1dee..ee99acf41 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs | |||
| @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { | |||
| 60 | 60 | ||
| 61 | // Create embassy-usb DeviceBuilder using the driver and config. | 61 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 62 | // It needs some buffers for building the descriptors. | 62 | // It needs some buffers for building the descriptors. |
| 63 | let mut device_descriptor = [0; 256]; | ||
| 64 | let mut config_descriptor = [0; 256]; | 63 | let mut config_descriptor = [0; 256]; |
| 65 | let mut bos_descriptor = [0; 256]; | 64 | let mut bos_descriptor = [0; 256]; |
| 66 | let mut control_buf = [0; 7]; | 65 | let mut control_buf = [0; 7]; |
| @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 70 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 71 | driver, | 70 | driver, |
| 72 | config, | 71 | config, |
| 73 | &mut device_descriptor, | ||
| 74 | &mut config_descriptor, | 72 | &mut config_descriptor, |
| 75 | &mut bos_descriptor, | 73 | &mut bos_descriptor, |
| 76 | &mut [], // no msos descriptors | 74 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index e32f283d1..e39e2daec 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::convert::TryFrom; | ||
| 5 | |||
| 6 | use defmt::*; | 4 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::time::Hertz; | 6 | use embassy_stm32::time::Hertz; |
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index ee1c43afd..5760f2c1c 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs | |||
| @@ -54,7 +54,6 @@ async fn main(_spawner: Spawner) { | |||
| 54 | 54 | ||
| 55 | // Create embassy-usb DeviceBuilder using the driver and config. | 55 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 56 | // It needs some buffers for building the descriptors. | 56 | // It needs some buffers for building the descriptors. |
| 57 | let mut device_descriptor = [0; 256]; | ||
| 58 | let mut config_descriptor = [0; 256]; | 57 | let mut config_descriptor = [0; 256]; |
| 59 | let mut bos_descriptor = [0; 256]; | 58 | let mut bos_descriptor = [0; 256]; |
| 60 | let mut control_buf = [0; 7]; | 59 | let mut control_buf = [0; 7]; |
| @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | let mut builder = Builder::new( | 63 | let mut builder = Builder::new( |
| 65 | driver, | 64 | driver, |
| 66 | config, | 65 | config, |
| 67 | &mut device_descriptor, | ||
| 68 | &mut config_descriptor, | 66 | &mut config_descriptor, |
| 69 | &mut bos_descriptor, | 67 | &mut bos_descriptor, |
| 70 | &mut [], // no msos descriptors | 68 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index d074b4265..cedc057a7 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs | |||
| @@ -4,9 +4,10 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::bind_interrupts; | 6 | use embassy_stm32::bind_interrupts; |
| 7 | use embassy_stm32::can::bxcan::filter::Mask32; | 7 | use embassy_stm32::can::filter::Mask32; |
| 8 | use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; | 8 | use embassy_stm32::can::{ |
| 9 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 9 | Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler, |
| 10 | }; | ||
| 10 | use embassy_stm32::gpio::{Input, Pull}; | 11 | use embassy_stm32::gpio::{Input, Pull}; |
| 11 | use embassy_stm32::peripherals::CAN1; | 12 | use embassy_stm32::peripherals::CAN1; |
| 12 | use embassy_time::Instant; | 13 | use embassy_time::Instant; |
| @@ -34,23 +35,18 @@ async fn main(_spawner: Spawner) { | |||
| 34 | 35 | ||
| 35 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); | 36 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); |
| 36 | 37 | ||
| 37 | can.as_mut() | 38 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 38 | .modify_filters() | ||
| 39 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 40 | 39 | ||
| 41 | can.as_mut() | 40 | can.modify_config() |
| 42 | .modify_config() | ||
| 43 | .set_loopback(true) // Receive own frames | 41 | .set_loopback(true) // Receive own frames |
| 44 | .set_silent(true) | 42 | .set_silent(true) |
| 45 | .leave_disabled(); | 43 | .set_bitrate(1_000_000); |
| 46 | |||
| 47 | can.set_bitrate(1_000_000); | ||
| 48 | 44 | ||
| 49 | can.enable().await; | 45 | can.enable().await; |
| 50 | 46 | ||
| 51 | let mut i: u8 = 0; | 47 | let mut i: u8 = 0; |
| 52 | loop { | 48 | loop { |
| 53 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); | 49 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); |
| 54 | let tx_ts = Instant::now(); | 50 | let tx_ts = Instant::now(); |
| 55 | can.write(&tx_frame).await; | 51 | can.write(&tx_frame).await; |
| 56 | 52 | ||
| @@ -64,7 +60,7 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 60 | ||
| 65 | info!( | 61 | info!( |
| 66 | "loopback frame {=u8}, latency: {} us", | 62 | "loopback frame {=u8}, latency: {} us", |
| 67 | unwrap!(envelope.frame.data())[0], | 63 | envelope.frame.data()[0], |
| 68 | latency.as_micros() | 64 | latency.as_micros() |
| 69 | ); | 65 | ); |
| 70 | i += 1; | 66 | i += 1; |
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index a196259a8..d2cbeea1b 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -7,8 +7,8 @@ use embassy_net::tcp::TcpSocket; | |||
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::{Stack, StackResources}; |
| 8 | use embassy_stm32::rng::{self, Rng}; | 8 | use embassy_stm32::rng::{self, Rng}; |
| 9 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::usb_otg::Driver; | 10 | use embassy_stm32::usb::Driver; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 11 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 14 | use embassy_usb::{Builder, UsbDevice}; | 14 | use embassy_usb::{Builder, UsbDevice}; |
| @@ -36,7 +36,7 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bind_interrupts!(struct Irqs { | 38 | bind_interrupts!(struct Irqs { |
| 39 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 39 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 40 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | 40 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; |
| 41 | }); | 41 | }); |
| 42 | 42 | ||
| @@ -63,13 +63,14 @@ async fn main(spawner: Spawner) { | |||
| 63 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 63 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 64 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 64 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 65 | config.rcc.sys = Sysclk::PLL1_P; | 65 | config.rcc.sys = Sysclk::PLL1_P; |
| 66 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 66 | } | 67 | } |
| 67 | let p = embassy_stm32::init(config); | 68 | let p = embassy_stm32::init(config); |
| 68 | 69 | ||
| 69 | // Create the driver, from the HAL. | 70 | // Create the driver, from the HAL. |
| 70 | static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); | 71 | static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); |
| 71 | let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; | 72 | let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; |
| 72 | let mut config = embassy_stm32::usb_otg::Config::default(); | 73 | let mut config = embassy_stm32::usb::Config::default(); |
| 73 | config.vbus_detection = true; | 74 | config.vbus_detection = true; |
| 74 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); | 75 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); |
| 75 | 76 | ||
| @@ -88,14 +89,12 @@ async fn main(spawner: Spawner) { | |||
| 88 | config.device_protocol = 0x01; | 89 | config.device_protocol = 0x01; |
| 89 | 90 | ||
| 90 | // Create embassy-usb DeviceBuilder using the driver and config. | 91 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 91 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 92 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 92 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 93 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 93 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 94 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 94 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 95 | let mut builder = Builder::new( | 95 | let mut builder = Builder::new( |
| 96 | driver, | 96 | driver, |
| 97 | config, | 97 | config, |
| 98 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 99 | &mut CONFIG_DESC.init([0; 256])[..], | 98 | &mut CONFIG_DESC.init([0; 256])[..], |
| 100 | &mut BOS_DESC.init([0; 256])[..], | 99 | &mut BOS_DESC.init([0; 256])[..], |
| 101 | &mut [], // no msos descriptors | 100 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs new file mode 100644 index 000000000..a799b4e72 --- /dev/null +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_stm32::exti::ExtiInput; | ||
| 9 | use embassy_stm32::gpio::Pull; | ||
| 10 | use embassy_stm32::time::Hertz; | ||
| 11 | use embassy_stm32::usb::Driver; | ||
| 12 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 13 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||
| 14 | use embassy_usb::control::OutResponse; | ||
| 15 | use embassy_usb::{Builder, Handler}; | ||
| 16 | use futures::future::join; | ||
| 17 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | bind_interrupts!(struct Irqs { | ||
| 21 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; | ||
| 22 | }); | ||
| 23 | |||
| 24 | #[embassy_executor::main] | ||
| 25 | async fn main(_spawner: Spawner) { | ||
| 26 | let mut config = Config::default(); | ||
| 27 | { | ||
| 28 | use embassy_stm32::rcc::*; | ||
| 29 | config.rcc.hse = Some(Hse { | ||
| 30 | freq: Hertz(8_000_000), | ||
| 31 | mode: HseMode::Bypass, | ||
| 32 | }); | ||
| 33 | config.rcc.pll_src = PllSource::HSE; | ||
| 34 | config.rcc.pll = Some(Pll { | ||
| 35 | prediv: PllPreDiv::DIV4, | ||
| 36 | mul: PllMul::MUL168, | ||
| 37 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 38 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 39 | divr: None, | ||
| 40 | }); | ||
| 41 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 42 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 43 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 44 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 45 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 46 | } | ||
| 47 | let p = embassy_stm32::init(config); | ||
| 48 | |||
| 49 | // Create the driver, from the HAL. | ||
| 50 | let mut ep_out_buffer = [0u8; 256]; | ||
| 51 | let mut config = embassy_stm32::usb::Config::default(); | ||
| 52 | config.vbus_detection = true; | ||
| 53 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||
| 54 | |||
| 55 | // Create embassy-usb Config | ||
| 56 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 57 | config.manufacturer = Some("Embassy"); | ||
| 58 | config.product = Some("HID keyboard example"); | ||
| 59 | config.serial_number = Some("12345678"); | ||
| 60 | config.max_power = 100; | ||
| 61 | config.max_packet_size_0 = 64; | ||
| 62 | |||
| 63 | // Required for windows compatibility. | ||
| 64 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 65 | config.device_class = 0xEF; | ||
| 66 | config.device_sub_class = 0x02; | ||
| 67 | config.device_protocol = 0x01; | ||
| 68 | config.composite_with_iads = true; | ||
| 69 | |||
| 70 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 71 | // It needs some buffers for building the descriptors. | ||
| 72 | let mut config_descriptor = [0; 256]; | ||
| 73 | let mut bos_descriptor = [0; 256]; | ||
| 74 | // You can also add a Microsoft OS descriptor. | ||
| 75 | let mut msos_descriptor = [0; 256]; | ||
| 76 | let mut control_buf = [0; 64]; | ||
| 77 | |||
| 78 | let request_handler = MyRequestHandler {}; | ||
| 79 | let mut device_handler = MyDeviceHandler::new(); | ||
| 80 | |||
| 81 | let mut state = State::new(); | ||
| 82 | |||
| 83 | let mut builder = Builder::new( | ||
| 84 | driver, | ||
| 85 | config, | ||
| 86 | &mut config_descriptor, | ||
| 87 | &mut bos_descriptor, | ||
| 88 | &mut msos_descriptor, | ||
| 89 | &mut control_buf, | ||
| 90 | ); | ||
| 91 | |||
| 92 | builder.handler(&mut device_handler); | ||
| 93 | |||
| 94 | // Create classes on the builder. | ||
| 95 | let config = embassy_usb::class::hid::Config { | ||
| 96 | report_descriptor: KeyboardReport::desc(), | ||
| 97 | request_handler: Some(&request_handler), | ||
| 98 | poll_ms: 60, | ||
| 99 | max_packet_size: 8, | ||
| 100 | }; | ||
| 101 | |||
| 102 | let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); | ||
| 103 | |||
| 104 | // Build the builder. | ||
| 105 | let mut usb = builder.build(); | ||
| 106 | |||
| 107 | // Run the USB device. | ||
| 108 | let usb_fut = usb.run(); | ||
| 109 | |||
| 110 | let (reader, mut writer) = hid.split(); | ||
| 111 | |||
| 112 | let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); | ||
| 113 | |||
| 114 | // Do stuff with the class! | ||
| 115 | let in_fut = async { | ||
| 116 | loop { | ||
| 117 | button.wait_for_rising_edge().await; | ||
| 118 | // signal_pin.wait_for_high().await; | ||
| 119 | info!("Button pressed!"); | ||
| 120 | // Create a report with the A key pressed. (no shift modifier) | ||
| 121 | let report = KeyboardReport { | ||
| 122 | keycodes: [4, 0, 0, 0, 0, 0], | ||
| 123 | leds: 0, | ||
| 124 | modifier: 0, | ||
| 125 | reserved: 0, | ||
| 126 | }; | ||
| 127 | // Send the report. | ||
| 128 | match writer.write_serialize(&report).await { | ||
| 129 | Ok(()) => {} | ||
| 130 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 131 | }; | ||
| 132 | |||
| 133 | button.wait_for_falling_edge().await; | ||
| 134 | // signal_pin.wait_for_low().await; | ||
| 135 | info!("Button released!"); | ||
| 136 | let report = KeyboardReport { | ||
| 137 | keycodes: [0, 0, 0, 0, 0, 0], | ||
| 138 | leds: 0, | ||
| 139 | modifier: 0, | ||
| 140 | reserved: 0, | ||
| 141 | }; | ||
| 142 | match writer.write_serialize(&report).await { | ||
| 143 | Ok(()) => {} | ||
| 144 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 145 | }; | ||
| 146 | } | ||
| 147 | }; | ||
| 148 | |||
| 149 | let out_fut = async { | ||
| 150 | reader.run(false, &request_handler).await; | ||
| 151 | }; | ||
| 152 | |||
| 153 | // Run everything concurrently. | ||
| 154 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 155 | join(usb_fut, join(in_fut, out_fut)).await; | ||
| 156 | } | ||
| 157 | |||
| 158 | struct MyRequestHandler {} | ||
| 159 | |||
| 160 | impl RequestHandler for MyRequestHandler { | ||
| 161 | fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | ||
| 162 | info!("Get report for {:?}", id); | ||
| 163 | None | ||
| 164 | } | ||
| 165 | |||
| 166 | fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { | ||
| 167 | info!("Set report for {:?}: {=[u8]}", id, data); | ||
| 168 | OutResponse::Accepted | ||
| 169 | } | ||
| 170 | |||
| 171 | fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { | ||
| 172 | info!("Set idle rate for {:?} to {:?}", id, dur); | ||
| 173 | } | ||
| 174 | |||
| 175 | fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { | ||
| 176 | info!("Get idle rate for {:?}", id); | ||
| 177 | None | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | struct MyDeviceHandler { | ||
| 182 | configured: AtomicBool, | ||
| 183 | } | ||
| 184 | |||
| 185 | impl MyDeviceHandler { | ||
| 186 | fn new() -> Self { | ||
| 187 | MyDeviceHandler { | ||
| 188 | configured: AtomicBool::new(false), | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | impl Handler for MyDeviceHandler { | ||
| 194 | fn enabled(&mut self, enabled: bool) { | ||
| 195 | self.configured.store(false, Ordering::Relaxed); | ||
| 196 | if enabled { | ||
| 197 | info!("Device enabled"); | ||
| 198 | } else { | ||
| 199 | info!("Device disabled"); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | fn reset(&mut self) { | ||
| 204 | self.configured.store(false, Ordering::Relaxed); | ||
| 205 | info!("Bus reset, the Vbus current limit is 100mA"); | ||
| 206 | } | ||
| 207 | |||
| 208 | fn addressed(&mut self, addr: u8) { | ||
| 209 | self.configured.store(false, Ordering::Relaxed); | ||
| 210 | info!("USB address set to: {}", addr); | ||
| 211 | } | ||
| 212 | |||
| 213 | fn configured(&mut self, configured: bool) { | ||
| 214 | self.configured.store(configured, Ordering::Relaxed); | ||
| 215 | if configured { | ||
| 216 | info!("Device configured, it may now draw up to the configured current limit from Vbus.") | ||
| 217 | } else { | ||
| 218 | info!("Device is no longer configured, the Vbus current limit is 100mA."); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index c98792880..0bc236119 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | 6 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb_otg::Driver; | 7 | use embassy_stm32::usb::Driver; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| 10 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 10 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; |
| 11 | use embassy_usb::control::OutResponse; | 11 | use embassy_usb::control::OutResponse; |
| @@ -15,7 +15,7 @@ use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | bind_interrupts!(struct Irqs { | 17 | bind_interrupts!(struct Irqs { |
| 18 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 18 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 19 | }); | 19 | }); |
| 20 | 20 | ||
| 21 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| @@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) { | |||
| 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 41 | config.rcc.sys = Sysclk::PLL1_P; | 41 | config.rcc.sys = Sysclk::PLL1_P; |
| 42 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 42 | } | 43 | } |
| 43 | let p = embassy_stm32::init(config); | 44 | let p = embassy_stm32::init(config); |
| 44 | 45 | ||
| 45 | // Create the driver, from the HAL. | 46 | // Create the driver, from the HAL. |
| 46 | let mut ep_out_buffer = [0u8; 256]; | 47 | let mut ep_out_buffer = [0u8; 256]; |
| 47 | let mut config = embassy_stm32::usb_otg::Config::default(); | 48 | let mut config = embassy_stm32::usb::Config::default(); |
| 48 | config.vbus_detection = true; | 49 | config.vbus_detection = true; |
| 49 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 50 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 50 | 51 | ||
| @@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | 64 | ||
| 64 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 65 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 66 | let mut device_descriptor = [0; 256]; | ||
| 67 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 68 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 69 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -75,7 +75,6 @@ async fn main(_spawner: Spawner) { | |||
| 75 | let mut builder = Builder::new( | 75 | let mut builder = Builder::new( |
| 76 | driver, | 76 | driver, |
| 77 | config, | 77 | config, |
| 78 | &mut device_descriptor, | ||
| 79 | &mut config_descriptor, | 78 | &mut config_descriptor, |
| 80 | &mut bos_descriptor, | 79 | &mut bos_descriptor, |
| 81 | &mut [], // no msos descriptors | 80 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index afff55187..4e583aeb8 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs | |||
| @@ -52,8 +52,8 @@ | |||
| 52 | use defmt::*; | 52 | use defmt::*; |
| 53 | use embassy_executor::Spawner; | 53 | use embassy_executor::Spawner; |
| 54 | use embassy_stm32::time::Hertz; | 54 | use embassy_stm32::time::Hertz; |
| 55 | use embassy_stm32::usb_otg::Driver; | 55 | use embassy_stm32::usb::Driver; |
| 56 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 56 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; | 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; |
| 58 | use embassy_usb::msos::{self, windows_version}; | 58 | use embassy_usb::msos::{self, windows_version}; |
| 59 | use embassy_usb::types::InterfaceNumber; | 59 | use embassy_usb::types::InterfaceNumber; |
| @@ -66,7 +66,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 66 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; | 66 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; |
| 67 | 67 | ||
| 68 | bind_interrupts!(struct Irqs { | 68 | bind_interrupts!(struct Irqs { |
| 69 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 69 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 70 | }); | 70 | }); |
| 71 | 71 | ||
| 72 | #[embassy_executor::main] | 72 | #[embassy_executor::main] |
| @@ -92,12 +92,13 @@ async fn main(_spawner: Spawner) { | |||
| 92 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 92 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 93 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 93 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 94 | config.rcc.sys = Sysclk::PLL1_P; | 94 | config.rcc.sys = Sysclk::PLL1_P; |
| 95 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 95 | } | 96 | } |
| 96 | let p = embassy_stm32::init(config); | 97 | let p = embassy_stm32::init(config); |
| 97 | 98 | ||
| 98 | // Create the driver, from the HAL. | 99 | // Create the driver, from the HAL. |
| 99 | let mut ep_out_buffer = [0u8; 256]; | 100 | let mut ep_out_buffer = [0u8; 256]; |
| 100 | let mut config = embassy_stm32::usb_otg::Config::default(); | 101 | let mut config = embassy_stm32::usb::Config::default(); |
| 101 | config.vbus_detection = true; | 102 | config.vbus_detection = true; |
| 102 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 103 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 103 | 104 | ||
| @@ -116,7 +117,6 @@ async fn main(_spawner: Spawner) { | |||
| 116 | 117 | ||
| 117 | // Create embassy-usb DeviceBuilder using the driver and config. | 118 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 118 | // It needs some buffers for building the descriptors. | 119 | // It needs some buffers for building the descriptors. |
| 119 | let mut device_descriptor = [0; 256]; | ||
| 120 | let mut config_descriptor = [0; 256]; | 120 | let mut config_descriptor = [0; 256]; |
| 121 | let mut bos_descriptor = [0; 256]; | 121 | let mut bos_descriptor = [0; 256]; |
| 122 | let mut msos_descriptor = [0; 256]; | 122 | let mut msos_descriptor = [0; 256]; |
| @@ -129,7 +129,6 @@ async fn main(_spawner: Spawner) { | |||
| 129 | let mut builder = Builder::new( | 129 | let mut builder = Builder::new( |
| 130 | driver, | 130 | driver, |
| 131 | config, | 131 | config, |
| 132 | &mut device_descriptor, | ||
| 133 | &mut config_descriptor, | 132 | &mut config_descriptor, |
| 134 | &mut bos_descriptor, | 133 | &mut bos_descriptor, |
| 135 | &mut msos_descriptor, | 134 | &mut msos_descriptor, |
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 58d994a61..f3a375d31 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | 6 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb_otg::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| @@ -13,7 +13,7 @@ use futures::future::join; | |||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) { | |||
| 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 41 | config.rcc.sys = Sysclk::PLL1_P; | 41 | config.rcc.sys = Sysclk::PLL1_P; |
| 42 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 42 | } | 43 | } |
| 43 | let p = embassy_stm32::init(config); | 44 | let p = embassy_stm32::init(config); |
| 44 | 45 | ||
| 45 | // Create the driver, from the HAL. | 46 | // Create the driver, from the HAL. |
| 46 | let mut ep_out_buffer = [0u8; 256]; | 47 | let mut ep_out_buffer = [0u8; 256]; |
| 47 | let mut config = embassy_stm32::usb_otg::Config::default(); | 48 | let mut config = embassy_stm32::usb::Config::default(); |
| 48 | config.vbus_detection = true; | 49 | config.vbus_detection = true; |
| 49 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 50 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 50 | 51 | ||
| @@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | 64 | ||
| 64 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 65 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 66 | let mut device_descriptor = [0; 256]; | ||
| 67 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 68 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 69 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -73,7 +73,6 @@ async fn main(_spawner: Spawner) { | |||
| 73 | let mut builder = Builder::new( | 73 | let mut builder = Builder::new( |
| 74 | driver, | 74 | driver, |
| 75 | config, | 75 | config, |
| 76 | &mut device_descriptor, | ||
| 77 | &mut config_descriptor, | 76 | &mut config_descriptor, |
| 78 | &mut bos_descriptor, | 77 | &mut bos_descriptor, |
| 79 | &mut [], // no msos descriptors | 78 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 6122cea2d..cbaff75fc 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs | |||
| @@ -15,8 +15,9 @@ | |||
| 15 | use embassy_executor::Spawner; | 15 | use embassy_executor::Spawner; |
| 16 | use embassy_stm32::gpio::OutputType; | 16 | use embassy_stm32::gpio::OutputType; |
| 17 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 18 | use embassy_stm32::timer::low_level::CountingMode; | ||
| 18 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | 19 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; |
| 19 | use embassy_stm32::timer::{Channel, CountingMode}; | 20 | use embassy_stm32::timer::Channel; |
| 20 | use embassy_time::{Duration, Ticker, Timer}; | 21 | use embassy_time::{Duration, Ticker, Timer}; |
| 21 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 23 | ||
| @@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) { | |||
| 60 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit | 61 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit |
| 61 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low | 62 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low |
| 62 | 63 | ||
| 63 | let max_duty = ws2812_pwm.get_max_duty(); | 64 | let max_duty = ws2812_pwm.get_max_duty() as u16; |
| 64 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing | 65 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing |
| 65 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing | 66 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing |
| 66 | 67 | ||
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index bcfdb67a8..e32b4d3df 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::num::{NonZeroU16, NonZeroU8}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::bind_interrupts; | 8 | use embassy_stm32::can::filter::Mask32; |
| 7 | use embassy_stm32::can::bxcan::filter::Mask32; | ||
| 8 | use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; | ||
| 9 | use embassy_stm32::can::{ | 9 | use embassy_stm32::can::{ |
| 10 | Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, | 10 | Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 11 | TxInterruptHandler, | ||
| 11 | }; | 12 | }; |
| 12 | use embassy_stm32::gpio::{Input, Pull}; | 13 | use embassy_stm32::gpio::{Input, Pull}; |
| 13 | use embassy_stm32::peripherals::CAN3; | 14 | use embassy_stm32::peripherals::CAN3; |
| 15 | use embassy_stm32::{bind_interrupts, can}; | ||
| 14 | use static_cell::StaticCell; | 16 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 18 | ||
| @@ -22,9 +24,9 @@ bind_interrupts!(struct Irqs { | |||
| 22 | }); | 24 | }); |
| 23 | 25 | ||
| 24 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 25 | pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { | 27 | pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { |
| 26 | loop { | 28 | loop { |
| 27 | let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); | 29 | let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap(); |
| 28 | tx.write(&frame).await; | 30 | tx.write(&frame).await; |
| 29 | embassy_time::Timer::after_secs(1).await; | 31 | embassy_time::Timer::after_secs(1).await; |
| 30 | } | 32 | } |
| @@ -45,19 +47,22 @@ async fn main(spawner: Spawner) { | |||
| 45 | 47 | ||
| 46 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); | 48 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); |
| 47 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); | 49 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); |
| 48 | can.as_mut() | 50 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 49 | .modify_filters() | 51 | |
| 50 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | 52 | can.modify_config() |
| 53 | .set_bit_timing(can::util::NominalBitTiming { | ||
| 54 | prescaler: NonZeroU16::new(2).unwrap(), | ||
| 55 | seg1: NonZeroU8::new(13).unwrap(), | ||
| 56 | seg2: NonZeroU8::new(2).unwrap(), | ||
| 57 | sync_jump_width: NonZeroU8::new(1).unwrap(), | ||
| 58 | }) // http://www.bittiming.can-wiki.info/ | ||
| 59 | .set_loopback(true); | ||
| 51 | 60 | ||
| 52 | can.as_mut() | 61 | can.enable().await; |
| 53 | .modify_config() | ||
| 54 | .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ | ||
| 55 | .set_loopback(true) | ||
| 56 | .enable(); | ||
| 57 | 62 | ||
| 58 | let (tx, mut rx) = can.split(); | 63 | let (tx, mut rx) = can.split(); |
| 59 | 64 | ||
| 60 | static CAN_TX: StaticCell<CanTx<'static, 'static, CAN3>> = StaticCell::new(); | 65 | static CAN_TX: StaticCell<CanTx<'static, CAN3>> = StaticCell::new(); |
| 61 | let tx = CAN_TX.init(tx); | 66 | let tx = CAN_TX.init(tx); |
| 62 | spawner.spawn(send_can_message(tx)).unwrap(); | 67 | spawner.spawn(send_can_message(tx)).unwrap(); |
| 63 | 68 | ||
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index 04927841a..235853cb9 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs | |||
| @@ -6,11 +6,15 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; | |||
| 6 | use aes_gcm::Aes128Gcm; | 6 | use aes_gcm::Aes128Gcm; |
| 7 | use defmt::info; | 7 | use defmt::info; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::cryp::*; | 9 | use embassy_stm32::cryp::{self, *}; |
| 10 | use embassy_stm32::Config; | 10 | use embassy_stm32::{bind_interrupts, peripherals, Config}; |
| 11 | use embassy_time::Instant; | 11 | use embassy_time::Instant; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | CRYP => cryp::InterruptHandler<peripherals::CRYP>; | ||
| 16 | }); | ||
| 17 | |||
| 14 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 15 | async fn main(_spawner: Spawner) -> ! { | 19 | async fn main(_spawner: Spawner) -> ! { |
| 16 | let config = Config::default(); | 20 | let config = Config::default(); |
| @@ -19,7 +23,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 19 | let payload: &[u8] = b"hello world"; | 23 | let payload: &[u8] = b"hello world"; |
| 20 | let aad: &[u8] = b"additional data"; | 24 | let aad: &[u8] = b"additional data"; |
| 21 | 25 | ||
| 22 | let hw_cryp = Cryp::new(p.CRYP); | 26 | let mut hw_cryp = Cryp::new(p.CRYP, p.DMA2_CH6, p.DMA2_CH5, Irqs); |
| 23 | let key: [u8; 16] = [0; 16]; | 27 | let key: [u8; 16] = [0; 16]; |
| 24 | let mut ciphertext: [u8; 11] = [0; 11]; | 28 | let mut ciphertext: [u8; 11] = [0; 11]; |
| 25 | let mut plaintext: [u8; 11] = [0; 11]; | 29 | let mut plaintext: [u8; 11] = [0; 11]; |
| @@ -29,16 +33,18 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 29 | 33 | ||
| 30 | // Encrypt in hardware using AES-GCM 128-bit | 34 | // Encrypt in hardware using AES-GCM 128-bit |
| 31 | let aes_gcm = AesGcm::new(&key, &iv); | 35 | let aes_gcm = AesGcm::new(&key, &iv); |
| 32 | let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); | 36 | let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt).await; |
| 33 | hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true); | 37 | hw_cryp.aad(&mut gcm_encrypt, aad, true).await; |
| 34 | hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true); | 38 | hw_cryp.payload(&mut gcm_encrypt, payload, &mut ciphertext, true).await; |
| 35 | let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); | 39 | let encrypt_tag = hw_cryp.finish(gcm_encrypt).await; |
| 36 | 40 | ||
| 37 | // Decrypt in hardware using AES-GCM 128-bit | 41 | // Decrypt in hardware using AES-GCM 128-bit |
| 38 | let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); | 42 | let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; |
| 39 | hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true); | 43 | hw_cryp.aad(&mut gcm_decrypt, aad, true).await; |
| 40 | hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); | 44 | hw_cryp |
| 41 | let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); | 45 | .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true) |
| 46 | .await; | ||
| 47 | let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; | ||
| 42 | 48 | ||
| 43 | let hw_end_time = Instant::now(); | 49 | let hw_end_time = Instant::now(); |
| 44 | let hw_execution_time = hw_end_time - hw_start_time; | 50 | let hw_execution_time = hw_end_time - hw_start_time; |
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 97daf6bd1..39a5512f4 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | 6 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb_otg::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| @@ -13,7 +13,7 @@ use futures::future::join; | |||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) { | |||
| 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 41 | config.rcc.sys = Sysclk::PLL1_P; | 41 | config.rcc.sys = Sysclk::PLL1_P; |
| 42 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 42 | } | 43 | } |
| 43 | let p = embassy_stm32::init(config); | 44 | let p = embassy_stm32::init(config); |
| 44 | 45 | ||
| 45 | // Create the driver, from the HAL. | 46 | // Create the driver, from the HAL. |
| 46 | let mut ep_out_buffer = [0u8; 256]; | 47 | let mut ep_out_buffer = [0u8; 256]; |
| 47 | let mut config = embassy_stm32::usb_otg::Config::default(); | 48 | let mut config = embassy_stm32::usb::Config::default(); |
| 48 | config.vbus_detection = true; | 49 | config.vbus_detection = true; |
| 49 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 50 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 50 | 51 | ||
| @@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | 64 | ||
| 64 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 65 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 66 | let mut device_descriptor = [0; 256]; | ||
| 67 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 68 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 69 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -73,7 +73,6 @@ async fn main(_spawner: Spawner) { | |||
| 73 | let mut builder = Builder::new( | 73 | let mut builder = Builder::new( |
| 74 | driver, | 74 | driver, |
| 75 | config, | 75 | config, |
| 76 | &mut device_descriptor, | ||
| 77 | &mut config_descriptor, | 76 | &mut config_descriptor, |
| 78 | &mut bos_descriptor, | 77 | &mut bos_descriptor, |
| 79 | &mut [], // no msos descriptors | 78 | &mut [], // no msos descriptors |
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index 8b9915626..162dfd86b 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs | |||
| @@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) { | |||
| 36 | 36 | ||
| 37 | // Create embassy-usb DeviceBuilder using the driver and config. | 37 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 38 | // It needs some buffers for building the descriptors. | 38 | // It needs some buffers for building the descriptors. |
| 39 | let mut device_descriptor = [0; 256]; | ||
| 40 | let mut config_descriptor = [0; 256]; | 39 | let mut config_descriptor = [0; 256]; |
| 41 | let mut bos_descriptor = [0; 256]; | 40 | let mut bos_descriptor = [0; 256]; |
| 42 | let mut control_buf = [0; 7]; | 41 | let mut control_buf = [0; 7]; |
| @@ -46,7 +45,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | let mut builder = Builder::new( | 45 | let mut builder = Builder::new( |
| 47 | driver, | 46 | driver, |
| 48 | config, | 47 | config, |
| 49 | &mut device_descriptor, | ||
| 50 | &mut config_descriptor, | 48 | &mut config_descriptor, |
| 51 | &mut bos_descriptor, | 49 | &mut bos_descriptor, |
| 52 | &mut [], // no msos descriptors | 50 | &mut [], // no msos descriptors |
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 4373a89a8..2ed632a93 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs | |||
| @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { | |||
| 36 | } | 36 | } |
| 37 | let peripherals = embassy_stm32::init(config); | 37 | let peripherals = embassy_stm32::init(config); |
| 38 | 38 | ||
| 39 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 39 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 40 | 40 | ||
| 41 | can.set_extended_filter( | 41 | can.set_extended_filter( |
| 42 | can::filter::ExtendedFilterSlot::_0, | 42 | can::filter::ExtendedFilterSlot::_0, |
| @@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) { | |||
| 56 | info!("Configured"); | 56 | info!("Configured"); |
| 57 | 57 | ||
| 58 | let mut can = can.start(match use_fd { | 58 | let mut can = can.start(match use_fd { |
| 59 | true => can::FdcanOperatingMode::InternalLoopbackMode, | 59 | true => can::OperatingMode::InternalLoopbackMode, |
| 60 | false => can::FdcanOperatingMode::NormalOperationMode, | 60 | false => can::OperatingMode::NormalOperationMode, |
| 61 | }); | 61 | }); |
| 62 | 62 | ||
| 63 | let mut i = 0; | 63 | let mut i = 0; |
| 64 | let mut last_read_ts = embassy_time::Instant::now(); | 64 | let mut last_read_ts = embassy_time::Instant::now(); |
| 65 | 65 | ||
| 66 | loop { | 66 | loop { |
| 67 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 67 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 68 | info!("Writing frame"); | 68 | info!("Writing frame"); |
| 69 | 69 | ||
| 70 | _ = can.write(&frame).await; | 70 | _ = can.write(&frame).await; |
| 71 | 71 | ||
| 72 | match can.read().await { | 72 | match can.read().await { |
| 73 | Ok((rx_frame, ts)) => { | 73 | Ok(envelope) => { |
| 74 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 74 | let delta = (ts - last_read_ts).as_millis(); | 75 | let delta = (ts - last_read_ts).as_millis(); |
| 75 | last_read_ts = ts; | 76 | last_read_ts = ts; |
| 76 | info!( | 77 | info!( |
| @@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) { | |||
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | match can.read_fd().await { | 108 | match can.read_fd().await { |
| 108 | Ok((rx_frame, ts)) => { | 109 | Ok(envelope) => { |
| 110 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 109 | let delta = (ts - last_read_ts).as_millis(); | 111 | let delta = (ts - last_read_ts).as_millis(); |
| 110 | last_read_ts = ts; | 112 | last_read_ts = ts; |
| 111 | info!( | 113 | info!( |
| @@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) { | |||
| 129 | let (mut tx, mut rx) = can.split(); | 131 | let (mut tx, mut rx) = can.split(); |
| 130 | // With split | 132 | // With split |
| 131 | loop { | 133 | loop { |
| 132 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 134 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 133 | info!("Writing frame"); | 135 | info!("Writing frame"); |
| 134 | _ = tx.write(&frame).await; | 136 | _ = tx.write(&frame).await; |
| 135 | 137 | ||
| 136 | match rx.read().await { | 138 | match rx.read().await { |
| 137 | Ok((rx_frame, ts)) => { | 139 | Ok(envelope) => { |
| 140 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 138 | let delta = (ts - last_read_ts).as_millis(); | 141 | let delta = (ts - last_read_ts).as_millis(); |
| 139 | last_read_ts = ts; | 142 | last_read_ts = ts; |
| 140 | info!( | 143 | info!( |
| @@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) { | |||
| 156 | } | 159 | } |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | let can = can::Fdcan::join(tx, rx); | 162 | let can = can::Can::join(tx, rx); |
| 160 | 163 | ||
| 161 | info!("\n\n\nBuffered\n"); | 164 | info!("\n\n\nBuffered\n"); |
| 162 | if use_fd { | 165 | if use_fd { |
| @@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) { | |||
| 173 | _ = can.write(frame).await; | 176 | _ = can.write(frame).await; |
| 174 | 177 | ||
| 175 | match can.read().await { | 178 | match can.read().await { |
| 176 | Ok((rx_frame, ts)) => { | 179 | Ok(envelope) => { |
| 180 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 177 | let delta = (ts - last_read_ts).as_millis(); | 181 | let delta = (ts - last_read_ts).as_millis(); |
| 178 | last_read_ts = ts; | 182 | last_read_ts = ts; |
| 179 | info!( | 183 | info!( |
| @@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) { | |||
| 198 | RX_BUF.init(can::RxBuf::<10>::new()), | 202 | RX_BUF.init(can::RxBuf::<10>::new()), |
| 199 | ); | 203 | ); |
| 200 | loop { | 204 | loop { |
| 201 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 205 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 202 | info!("Writing frame"); | 206 | info!("Writing frame"); |
| 203 | 207 | ||
| 204 | // You can use any of these approaches to send. The writer makes it | 208 | // You can use any of these approaches to send. The writer makes it |
| @@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) { | |||
| 208 | can.writer().write(frame).await; | 212 | can.writer().write(frame).await; |
| 209 | 213 | ||
| 210 | match can.read().await { | 214 | match can.read().await { |
| 211 | Ok((rx_frame, ts)) => { | 215 | Ok(envelope) => { |
| 216 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 212 | let delta = (ts - last_read_ts).as_millis(); | 217 | let delta = (ts - last_read_ts).as_millis(); |
| 213 | last_read_ts = ts; | 218 | last_read_ts = ts; |
| 214 | info!( | 219 | info!( |
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs new file mode 100644 index 000000000..7caea634f --- /dev/null +++ b/examples/stm32g4/src/bin/usb_c_pd.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{error, info, Format}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, Config}; | ||
| 8 | use embassy_time::{with_timeout, Duration}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | #[derive(Debug, Format)] | ||
| 16 | enum CableOrientation { | ||
| 17 | Normal, | ||
| 18 | Flipped, | ||
| 19 | DebugAccessoryMode, | ||
| 20 | } | ||
| 21 | |||
| 22 | // Returns true when the cable | ||
| 23 | async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation { | ||
| 24 | loop { | ||
| 25 | let (cc1, cc2) = cc_phy.vstate(); | ||
| 26 | if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { | ||
| 27 | // Detached, wait until attached by monitoring the CC lines. | ||
| 28 | cc_phy.wait_for_vstate_change().await; | ||
| 29 | continue; | ||
| 30 | } | ||
| 31 | |||
| 32 | // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). | ||
| 33 | if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change()) | ||
| 34 | .await | ||
| 35 | .is_ok() | ||
| 36 | { | ||
| 37 | // State has changed, restart detection procedure. | ||
| 38 | continue; | ||
| 39 | }; | ||
| 40 | |||
| 41 | // State was stable for the complete debounce period, check orientation. | ||
| 42 | return match (cc1, cc2) { | ||
| 43 | (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected | ||
| 44 | (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected | ||
| 45 | _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable) | ||
| 46 | }; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | #[embassy_executor::main] | ||
| 51 | async fn main(_spawner: Spawner) { | ||
| 52 | let mut config = Config::default(); | ||
| 53 | config.enable_ucpd1_dead_battery = true; | ||
| 54 | let p = embassy_stm32::init(config); | ||
| 55 | |||
| 56 | info!("Hello World!"); | ||
| 57 | |||
| 58 | let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); | ||
| 59 | ucpd.cc_phy().set_pull(CcPull::Sink); | ||
| 60 | |||
| 61 | info!("Waiting for USB connection..."); | ||
| 62 | let cable_orientation = wait_attached(ucpd.cc_phy()).await; | ||
| 63 | info!("USB cable connected, orientation: {}", cable_orientation); | ||
| 64 | |||
| 65 | let cc_sel = match cable_orientation { | ||
| 66 | CableOrientation::Normal => { | ||
| 67 | info!("Starting PD communication on CC1 pin"); | ||
| 68 | CcSel::CC1 | ||
| 69 | } | ||
| 70 | CableOrientation::Flipped => { | ||
| 71 | info!("Starting PD communication on CC2 pin"); | ||
| 72 | CcSel::CC2 | ||
| 73 | } | ||
| 74 | CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), | ||
| 75 | }; | ||
| 76 | let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); | ||
| 77 | |||
| 78 | loop { | ||
| 79 | // Enough space for the longest non-extended data message. | ||
| 80 | let mut buf = [0_u8; 30]; | ||
| 81 | match pd_phy.receive(buf.as_mut()).await { | ||
| 82 | Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]), | ||
| 83 | Err(e) => error!("USB PD RX: {}", e), | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index dc95aa6e5..dbe8f27c1 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs | |||
| @@ -56,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 56 | config.device_protocol = 0x01; | 56 | config.device_protocol = 0x01; |
| 57 | config.composite_with_iads = true; | 57 | config.composite_with_iads = true; |
| 58 | 58 | ||
| 59 | let mut device_descriptor = [0; 256]; | ||
| 60 | let mut config_descriptor = [0; 256]; | 59 | let mut config_descriptor = [0; 256]; |
| 61 | let mut bos_descriptor = [0; 256]; | 60 | let mut bos_descriptor = [0; 256]; |
| 62 | let mut control_buf = [0; 64]; | 61 | let mut control_buf = [0; 64]; |
| @@ -66,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 66 | let mut builder = Builder::new( | 65 | let mut builder = Builder::new( |
| 67 | driver, | 66 | driver, |
| 68 | config, | 67 | config, |
| 69 | &mut device_descriptor, | ||
| 70 | &mut config_descriptor, | 68 | &mut config_descriptor, |
| 71 | &mut bos_descriptor, | 69 | &mut bos_descriptor, |
| 72 | &mut [], // no msos descriptors | 70 | &mut [], // no msos descriptors |
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 643df27f9..dd625c90a 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | 24 | ||
| 25 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 26 | 26 | ||
| 27 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 28 | 28 | ||
| 29 | // 250k bps | 29 | // 250k bps |
| 30 | can.set_bitrate(250_000); | 30 | can.set_bitrate(250_000); |
| @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { | |||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | 38 | let mut last_read_ts = embassy_time::Instant::now(); |
| 39 | 39 | ||
| 40 | loop { | 40 | loop { |
| 41 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 42 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 43 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 44 | 44 | ||
| 45 | match can.read().await { | 45 | match can.read().await { |
| 46 | Ok((rx_frame, ts)) => { | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 47 | let delta = (ts - last_read_ts).as_millis(); | 48 | let delta = (ts - last_read_ts).as_millis(); |
| 48 | last_read_ts = ts; | 49 | last_read_ts = ts; |
| 49 | info!( | 50 | info!( |
| @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { | |||
| 69 | let (mut tx, mut rx) = can.split(); | 70 | let (mut tx, mut rx) = can.split(); |
| 70 | // With split | 71 | // With split |
| 71 | loop { | 72 | loop { |
| 72 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 73 | info!("Writing frame"); | 74 | info!("Writing frame"); |
| 74 | _ = tx.write(&frame).await; | 75 | _ = tx.write(&frame).await; |
| 75 | 76 | ||
| 76 | match rx.read().await { | 77 | match rx.read().await { |
| 77 | Ok((rx_frame, ts)) => { | 78 | Ok(envelope) => { |
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 78 | let delta = (ts - last_read_ts).as_millis(); | 80 | let delta = (ts - last_read_ts).as_millis(); |
| 79 | last_read_ts = ts; | 81 | last_read_ts = ts; |
| 80 | info!( | 82 | info!( |
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 83477c8fa..4f86bb342 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs | |||
| @@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 65 | 65 | ||
| 66 | // Create embassy-usb DeviceBuilder using the driver and config. | 66 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 67 | // It needs some buffers for building the descriptors. | 67 | // It needs some buffers for building the descriptors. |
| 68 | let mut device_descriptor = [0; 256]; | ||
| 69 | let mut config_descriptor = [0; 256]; | 68 | let mut config_descriptor = [0; 256]; |
| 70 | let mut bos_descriptor = [0; 256]; | 69 | let mut bos_descriptor = [0; 256]; |
| 71 | let mut control_buf = [0; 64]; | 70 | let mut control_buf = [0; 64]; |
| @@ -75,7 +74,6 @@ async fn main(_spawner: Spawner) { | |||
| 75 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 76 | driver, | 75 | driver, |
| 77 | config, | 76 | config, |
| 78 | &mut device_descriptor, | ||
| 79 | &mut config_descriptor, | 77 | &mut config_descriptor, |
| 80 | &mut bos_descriptor, | 78 | &mut bos_descriptor, |
| 81 | &mut [], // no msos descriptors | 79 | &mut [], // no msos descriptors |
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index e5a104baf..170a5aa28 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs | |||
| @@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) { | |||
| 78 | ); | 78 | ); |
| 79 | 79 | ||
| 80 | defmt::info!("attempting capture"); | 80 | defmt::info!("attempting capture"); |
| 81 | defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); | 81 | defmt::unwrap!(dcmi.capture(unsafe { &mut *core::ptr::addr_of_mut!(FRAME) }).await); |
| 82 | 82 | ||
| 83 | defmt::info!("captured frame: {:x}", unsafe { &FRAME }); | 83 | defmt::info!("captured frame: {:x}", unsafe { &*core::ptr::addr_of!(FRAME) }); |
| 84 | 84 | ||
| 85 | defmt::info!("main loop running"); | 85 | defmt::info!("main loop running"); |
| 86 | loop { | 86 | loop { |
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 13a6a5051..22cb27481 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | 24 | ||
| 25 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 26 | 26 | ||
| 27 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 28 | 28 | ||
| 29 | // 250k bps | 29 | // 250k bps |
| 30 | can.set_bitrate(250_000); | 30 | can.set_bitrate(250_000); |
| @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { | |||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | 38 | let mut last_read_ts = embassy_time::Instant::now(); |
| 39 | 39 | ||
| 40 | loop { | 40 | loop { |
| 41 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 42 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 43 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 44 | 44 | ||
| 45 | match can.read().await { | 45 | match can.read().await { |
| 46 | Ok((rx_frame, ts)) => { | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 47 | let delta = (ts - last_read_ts).as_millis(); | 48 | let delta = (ts - last_read_ts).as_millis(); |
| 48 | last_read_ts = ts; | 49 | last_read_ts = ts; |
| 49 | info!( | 50 | info!( |
| @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { | |||
| 69 | let (mut tx, mut rx) = can.split(); | 70 | let (mut tx, mut rx) = can.split(); |
| 70 | // With split | 71 | // With split |
| 71 | loop { | 72 | loop { |
| 72 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 73 | info!("Writing frame"); | 74 | info!("Writing frame"); |
| 74 | _ = tx.write(&frame).await; | 75 | _ = tx.write(&frame).await; |
| 75 | 76 | ||
| 76 | match rx.read().await { | 77 | match rx.read().await { |
| 77 | Ok((rx_frame, ts)) => { | 78 | Ok(envelope) => { |
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 78 | let delta = (ts - last_read_ts).as_millis(); | 80 | let delta = (ts - last_read_ts).as_millis(); |
| 79 | last_read_ts = ts; | 81 | last_read_ts = ts; |
| 80 | info!( | 82 | info!( |
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index feec28993..3a9887e3c 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs | |||
| @@ -6,9 +6,9 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; | 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 7 | use embassy_stm32::pac::timer::vals::Mms; | 7 | use embassy_stm32::pac::timer::vals::Mms; |
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::frequency; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -51,19 +51,19 @@ async fn main(spawner: Spawner) { | |||
| 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 53 | 53 | ||
| 54 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 54 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 55 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 55 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | #[embassy_executor::task] | 58 | #[embassy_executor::task] |
| 59 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 59 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 60 | let data: &[u8; 256] = &calculate_array::<256>(); | 60 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 61 | 61 | ||
| 62 | info!("TIM6 frequency is {}", TIM6::frequency()); | 62 | info!("TIM6 frequency is {}", frequency::<TIM6>()); |
| 63 | const FREQUENCY: Hertz = Hertz::hz(200); | 63 | const FREQUENCY: Hertz = Hertz::hz(200); |
| 64 | 64 | ||
| 65 | // Compute the reload value such that we obtain the FREQUENCY for the sine | 65 | // Compute the reload value such that we obtain the FREQUENCY for the sine |
| 66 | let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; | 66 | let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32; |
| 67 | 67 | ||
| 68 | // Depends on your clock and on the specific chip used, you may need higher or lower values here | 68 | // Depends on your clock and on the specific chip used, you may need higher or lower values here |
| 69 | if reload < 10 { | 69 | if reload < 10 { |
| @@ -74,17 +74,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 74 | dac.set_triggering(true); | 74 | dac.set_triggering(true); |
| 75 | dac.enable(); | 75 | dac.enable(); |
| 76 | 76 | ||
| 77 | TIM6::enable_and_reset(); | 77 | let tim = Timer::new(tim); |
| 78 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 78 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 79 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 79 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 80 | TIM6::regs_basic().cr1().modify(|w| { | 80 | tim.regs_basic().cr1().modify(|w| { |
| 81 | w.set_opm(false); | 81 | w.set_opm(false); |
| 82 | w.set_cen(true); | 82 | w.set_cen(true); |
| 83 | }); | 83 | }); |
| 84 | 84 | ||
| 85 | debug!( | 85 | debug!( |
| 86 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 86 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 87 | TIM6::frequency(), | 87 | frequency::<TIM6>(), |
| 88 | FREQUENCY, | 88 | FREQUENCY, |
| 89 | reload, | 89 | reload, |
| 90 | reload as u16, | 90 | reload as u16, |
| @@ -99,22 +99,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | #[embassy_executor::task] | 101 | #[embassy_executor::task] |
| 102 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 102 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 103 | let data: &[u8; 256] = &calculate_array::<256>(); | 103 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 104 | 104 | ||
| 105 | info!("TIM7 frequency is {}", TIM7::frequency()); | 105 | info!("TIM7 frequency is {}", frequency::<TIM6>()); |
| 106 | 106 | ||
| 107 | const FREQUENCY: Hertz = Hertz::hz(600); | 107 | const FREQUENCY: Hertz = Hertz::hz(600); |
| 108 | let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; | 108 | let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32; |
| 109 | 109 | ||
| 110 | if reload < 10 { | 110 | if reload < 10 { |
| 111 | error!("Reload value {} below threshold!", reload); | 111 | error!("Reload value {} below threshold!", reload); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | TIM7::enable_and_reset(); | 114 | let tim = Timer::new(tim); |
| 115 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 115 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 116 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 116 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 117 | TIM7::regs_basic().cr1().modify(|w| { | 117 | tim.regs_basic().cr1().modify(|w| { |
| 118 | w.set_opm(false); | 118 | w.set_opm(false); |
| 119 | w.set_cen(true); | 119 | w.set_cen(true); |
| 120 | }); | 120 | }); |
| @@ -125,7 +125,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 125 | 125 | ||
| 126 | debug!( | 126 | debug!( |
| 127 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 127 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 128 | TIM7::frequency(), | 128 | frequency::<TIM7>(), |
| 129 | FREQUENCY, | 129 | FREQUENCY, |
| 130 | reload, | 130 | reload, |
| 131 | reload as u16, | 131 | reload as u16, |
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index cd9a27fcd..7c7964ecd 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs | |||
| @@ -64,19 +64,21 @@ async fn main(spawner: Spawner) -> ! { | |||
| 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 65 | 65 | ||
| 66 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); | 66 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 67 | // warning: Not all STM32H7 devices have the exact same pins here | ||
| 68 | // for STM32H747XIH, replace p.PB13 for PG12 | ||
| 67 | let device = Ethernet::new( | 69 | let device = Ethernet::new( |
| 68 | PACKETS.init(PacketQueue::<4, 4>::new()), | 70 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 69 | p.ETH, | 71 | p.ETH, |
| 70 | Irqs, | 72 | Irqs, |
| 71 | p.PA1, | 73 | p.PA1, // ref_clk |
| 72 | p.PA2, | 74 | p.PA2, // mdio |
| 73 | p.PC1, | 75 | p.PC1, // eth_mdc |
| 74 | p.PA7, | 76 | p.PA7, // CRS_DV: Carrier Sense |
| 75 | p.PC4, | 77 | p.PC4, // RX_D0: Received Bit 0 |
| 76 | p.PC5, | 78 | p.PC5, // RX_D1: Received Bit 1 |
| 77 | p.PG13, | 79 | p.PG13, // TX_D0: Transmit Bit 0 |
| 78 | p.PB13, | 80 | p.PB13, // TX_D1: Transmit Bit 1 |
| 79 | p.PG11, | 81 | p.PG11, // TX_EN: Transmit Enable |
| 80 | GenericSMI::new(0), | 82 | GenericSMI::new(0), |
| 81 | mac_addr, | 83 | mac_addr, |
| 82 | ); | 84 | ); |
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 049d9967d..a95b44b74 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::low_level::AFType; | 6 | use embassy_stm32::gpio::{AFType, Flex, Pull, Speed}; |
| 7 | use embassy_stm32::gpio::Speed; | ||
| 8 | use embassy_stm32::time::{khz, Hertz}; | 7 | use embassy_stm32::time::{khz, Hertz}; |
| 9 | use embassy_stm32::timer::*; | 8 | use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; |
| 10 | use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; | 9 | use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; |
| 10 | use embassy_stm32::{into_ref, Config, Peripheral}; | ||
| 11 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| @@ -56,11 +56,15 @@ async fn main(_spawner: Spawner) { | |||
| 56 | Timer::after_millis(300).await; | 56 | Timer::after_millis(300).await; |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { | 59 | pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { |
| 60 | inner: PeripheralRef<'d, T>, | 60 | tim: LLTimer<'d, T>, |
| 61 | _ch1: Flex<'d>, | ||
| 62 | _ch2: Flex<'d>, | ||
| 63 | _ch3: Flex<'d>, | ||
| 64 | _ch4: Flex<'d>, | ||
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | 67 | impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { |
| 64 | pub fn new( | 68 | pub fn new( |
| 65 | tim: impl Peripheral<P = T> + 'd, | 69 | tim: impl Peripheral<P = T> + 'd, |
| 66 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, | 70 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, |
| @@ -69,25 +73,33 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 69 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, | 73 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, |
| 70 | freq: Hertz, | 74 | freq: Hertz, |
| 71 | ) -> Self { | 75 | ) -> Self { |
| 72 | into_ref!(tim, ch1, ch2, ch3, ch4); | 76 | into_ref!(ch1, ch2, ch3, ch4); |
| 73 | 77 | ||
| 74 | T::enable_and_reset(); | 78 | let af1 = ch1.af_num(); |
| 75 | 79 | let af2 = ch2.af_num(); | |
| 76 | ch1.set_speed(Speed::VeryHigh); | 80 | let af3 = ch3.af_num(); |
| 77 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 81 | let af4 = ch4.af_num(); |
| 78 | ch2.set_speed(Speed::VeryHigh); | 82 | let mut ch1 = Flex::new(ch1); |
| 79 | ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 83 | let mut ch2 = Flex::new(ch2); |
| 80 | ch3.set_speed(Speed::VeryHigh); | 84 | let mut ch3 = Flex::new(ch3); |
| 81 | ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 85 | let mut ch4 = Flex::new(ch4); |
| 82 | ch4.set_speed(Speed::VeryHigh); | 86 | ch1.set_as_af_unchecked(af1, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); |
| 83 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 87 | ch2.set_as_af_unchecked(af2, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); |
| 84 | 88 | ch3.set_as_af_unchecked(af3, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); | |
| 85 | let mut this = Self { inner: tim }; | 89 | ch4.set_as_af_unchecked(af4, AFType::OutputPushPull, Pull::None, Speed::VeryHigh); |
| 90 | |||
| 91 | let mut this = Self { | ||
| 92 | tim: LLTimer::new(tim), | ||
| 93 | _ch1: ch1, | ||
| 94 | _ch2: ch2, | ||
| 95 | _ch3: ch3, | ||
| 96 | _ch4: ch4, | ||
| 97 | }; | ||
| 86 | 98 | ||
| 87 | this.set_frequency(freq); | 99 | this.set_frequency(freq); |
| 88 | this.inner.start(); | 100 | this.tim.start(); |
| 89 | 101 | ||
| 90 | let r = T::regs_gp32(); | 102 | let r = this.tim.regs_gp32(); |
| 91 | r.ccmr_output(0) | 103 | r.ccmr_output(0) |
| 92 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | 104 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); |
| 93 | r.ccmr_output(0) | 105 | r.ccmr_output(0) |
| @@ -101,23 +113,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 101 | } | 113 | } |
| 102 | 114 | ||
| 103 | pub fn enable(&mut self, channel: Channel) { | 115 | pub fn enable(&mut self, channel: Channel) { |
| 104 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); | 116 | self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); |
| 105 | } | 117 | } |
| 106 | 118 | ||
| 107 | pub fn disable(&mut self, channel: Channel) { | 119 | pub fn disable(&mut self, channel: Channel) { |
| 108 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); | 120 | self.tim |
| 121 | .regs_gp32() | ||
| 122 | .ccer() | ||
| 123 | .modify(|w| w.set_cce(channel.index(), false)); | ||
| 109 | } | 124 | } |
| 110 | 125 | ||
| 111 | pub fn set_frequency(&mut self, freq: Hertz) { | 126 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 112 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); | 127 | self.tim.set_frequency(freq); |
| 113 | } | 128 | } |
| 114 | 129 | ||
| 115 | pub fn get_max_duty(&self) -> u32 { | 130 | pub fn get_max_duty(&self) -> u32 { |
| 116 | T::regs_gp32().arr().read() | 131 | self.tim.regs_gp32().arr().read() |
| 117 | } | 132 | } |
| 118 | 133 | ||
| 119 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | 134 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 120 | defmt::assert!(duty < self.get_max_duty()); | 135 | defmt::assert!(duty < self.get_max_duty()); |
| 121 | T::regs_gp32().ccr(channel.index()).write_value(duty) | 136 | self.tim.regs_gp32().ccr(channel.index()).write_value(duty) |
| 122 | } | 137 | } |
| 123 | } | 138 | } |
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index d81efb541..576506ad3 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::usb_otg::{Driver, Instance}; | 6 | use embassy_stm32::usb::{Driver, Instance}; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 7 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 8 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 8 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 9 | use embassy_usb::driver::EndpointError; | 9 | use embassy_usb::driver::EndpointError; |
| 10 | use embassy_usb::Builder; | 10 | use embassy_usb::Builder; |
| @@ -12,7 +12,7 @@ use futures::future::join; | |||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | bind_interrupts!(struct Irqs { | 14 | bind_interrupts!(struct Irqs { |
| 15 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 15 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 16 | }); | 16 | }); |
| 17 | 17 | ||
| 18 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| @@ -40,12 +40,13 @@ async fn main(_spawner: Spawner) { | |||
| 40 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | 40 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz |
| 41 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | 41 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz |
| 42 | config.rcc.voltage_scale = VoltageScale::Scale1; | 42 | config.rcc.voltage_scale = VoltageScale::Scale1; |
| 43 | config.rcc.mux.usbsel = mux::Usbsel::HSI48; | ||
| 43 | } | 44 | } |
| 44 | let p = embassy_stm32::init(config); | 45 | let p = embassy_stm32::init(config); |
| 45 | 46 | ||
| 46 | // Create the driver, from the HAL. | 47 | // Create the driver, from the HAL. |
| 47 | let mut ep_out_buffer = [0u8; 256]; | 48 | let mut ep_out_buffer = [0u8; 256]; |
| 48 | let mut config = embassy_stm32::usb_otg::Config::default(); | 49 | let mut config = embassy_stm32::usb::Config::default(); |
| 49 | config.vbus_detection = true; | 50 | config.vbus_detection = true; |
| 50 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 51 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 51 | 52 | ||
| @@ -64,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 65 | ||
| 65 | // Create embassy-usb DeviceBuilder using the driver and config. | 66 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 66 | // It needs some buffers for building the descriptors. | 67 | // It needs some buffers for building the descriptors. |
| 67 | let mut device_descriptor = [0; 256]; | ||
| 68 | let mut config_descriptor = [0; 256]; | 68 | let mut config_descriptor = [0; 256]; |
| 69 | let mut bos_descriptor = [0; 256]; | 69 | let mut bos_descriptor = [0; 256]; |
| 70 | let mut control_buf = [0; 64]; | 70 | let mut control_buf = [0; 64]; |
| @@ -74,7 +74,6 @@ async fn main(_spawner: Spawner) { | |||
| 74 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 75 | driver, | 75 | driver, |
| 76 | config, | 76 | config, |
| 77 | &mut device_descriptor, | ||
| 78 | &mut config_descriptor, | 77 | &mut config_descriptor, |
| 79 | &mut bos_descriptor, | 78 | &mut bos_descriptor, |
| 80 | &mut [], // no msos descriptors | 79 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index f738ea358..653bbd6d2 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | config.device_protocol = 0x01; | 46 | config.device_protocol = 0x01; |
| 47 | config.composite_with_iads = true; | 47 | config.composite_with_iads = true; |
| 48 | 48 | ||
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) { | |||
| 56 | let mut builder = Builder::new( | 55 | let mut builder = Builder::new( |
| 57 | driver, | 56 | driver, |
| 58 | config, | 57 | config, |
| 59 | &mut device_descriptor, | ||
| 60 | &mut config_descriptor, | 58 | &mut config_descriptor, |
| 61 | &mut bos_descriptor, | 59 | &mut bos_descriptor, |
| 62 | &mut [], // no msos descriptors | 60 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index f227812cd..d01b016c0 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs | |||
| @@ -6,9 +6,9 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; | 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 7 | use embassy_stm32::pac::timer::vals::Mms; | 7 | use embassy_stm32::pac::timer::vals::Mms; |
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::frequency; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -22,19 +22,19 @@ async fn main(spawner: Spawner) { | |||
| 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 24 | 24 | ||
| 25 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 25 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 26 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 26 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 30 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 30 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 31 | let data: &[u8; 256] = &calculate_array::<256>(); | 31 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 32 | 32 | ||
| 33 | info!("TIM6 frequency is {}", TIM6::frequency()); | 33 | info!("TIM6 frequency is {}", frequency::<TIM6>()); |
| 34 | const FREQUENCY: Hertz = Hertz::hz(200); | 34 | const FREQUENCY: Hertz = Hertz::hz(200); |
| 35 | 35 | ||
| 36 | // Compute the reload value such that we obtain the FREQUENCY for the sine | 36 | // Compute the reload value such that we obtain the FREQUENCY for the sine |
| 37 | let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; | 37 | let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32; |
| 38 | 38 | ||
| 39 | // Depends on your clock and on the specific chip used, you may need higher or lower values here | 39 | // Depends on your clock and on the specific chip used, you may need higher or lower values here |
| 40 | if reload < 10 { | 40 | if reload < 10 { |
| @@ -45,17 +45,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 45 | dac.set_triggering(true); | 45 | dac.set_triggering(true); |
| 46 | dac.enable(); | 46 | dac.enable(); |
| 47 | 47 | ||
| 48 | TIM6::enable_and_reset(); | 48 | let tim = Timer::new(tim); |
| 49 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 49 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 50 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 50 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 51 | TIM6::regs_basic().cr1().modify(|w| { | 51 | tim.regs_basic().cr1().modify(|w| { |
| 52 | w.set_opm(false); | 52 | w.set_opm(false); |
| 53 | w.set_cen(true); | 53 | w.set_cen(true); |
| 54 | }); | 54 | }); |
| 55 | 55 | ||
| 56 | debug!( | 56 | debug!( |
| 57 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 57 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 58 | TIM6::frequency(), | 58 | frequency::<TIM6>(), |
| 59 | FREQUENCY, | 59 | FREQUENCY, |
| 60 | reload, | 60 | reload, |
| 61 | reload as u16, | 61 | reload as u16, |
| @@ -70,22 +70,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | #[embassy_executor::task] | 72 | #[embassy_executor::task] |
| 73 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 73 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 74 | let data: &[u8; 256] = &calculate_array::<256>(); | 74 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 75 | 75 | ||
| 76 | info!("TIM7 frequency is {}", TIM7::frequency()); | 76 | info!("TIM7 frequency is {}", frequency::<TIM7>()); |
| 77 | 77 | ||
| 78 | const FREQUENCY: Hertz = Hertz::hz(600); | 78 | const FREQUENCY: Hertz = Hertz::hz(600); |
| 79 | let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; | 79 | let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32; |
| 80 | 80 | ||
| 81 | if reload < 10 { | 81 | if reload < 10 { |
| 82 | error!("Reload value {} below threshold!", reload); | 82 | error!("Reload value {} below threshold!", reload); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | TIM7::enable_and_reset(); | 85 | let tim = Timer::new(tim); |
| 86 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 86 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 87 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 87 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 88 | TIM7::regs_basic().cr1().modify(|w| { | 88 | tim.regs_basic().cr1().modify(|w| { |
| 89 | w.set_opm(false); | 89 | w.set_opm(false); |
| 90 | w.set_cen(true); | 90 | w.set_cen(true); |
| 91 | }); | 91 | }); |
| @@ -96,7 +96,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 96 | 96 | ||
| 97 | debug!( | 97 | debug!( |
| 98 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 98 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 99 | TIM7::frequency(), | 99 | frequency::<TIM7>(), |
| 100 | FREQUENCY, | 100 | FREQUENCY, |
| 101 | reload, | 101 | reload, |
| 102 | reload as u16, | 102 | reload as u16, |
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 32bfab6eb..77aa929ab 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs | |||
| @@ -42,7 +42,7 @@ bind_interrupts!(struct Irqs { | |||
| 42 | RNG => rng::InterruptHandler<peripherals::RNG>; | 42 | RNG => rng::InterruptHandler<peripherals::RNG>; |
| 43 | }); | 43 | }); |
| 44 | 44 | ||
| 45 | use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; | 45 | use embassy_net_adin1110::{Device, Runner, ADIN1110}; |
| 46 | use embedded_hal_bus::spi::ExclusiveDevice; | 46 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 47 | use hal::gpio::Pull; | 47 | use hal::gpio::Pull; |
| 48 | use hal::i2c::Config as I2C_Config; | 48 | use hal::i2c::Config as I2C_Config; |
| @@ -93,12 +93,6 @@ async fn main(spawner: Spawner) { | |||
| 93 | 93 | ||
| 94 | let dp = embassy_stm32::init(config); | 94 | let dp = embassy_stm32::init(config); |
| 95 | 95 | ||
| 96 | // RM0432rev9, 5.1.2: Independent I/O supply rail | ||
| 97 | // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and | ||
| 98 | // therefore are not available. The isolation must be removed before using any I/O from | ||
| 99 | // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present | ||
| 100 | pac::PWR.cr2().modify(|w| w.set_iosv(true)); | ||
| 101 | |||
| 102 | let reset_status = pac::RCC.bdcr().read().0; | 96 | let reset_status = pac::RCC.bdcr().read().0; |
| 103 | defmt::println!("bdcr before: 0x{:X}", reset_status); | 97 | defmt::println!("bdcr before: 0x{:X}", reset_status); |
| 104 | 98 | ||
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 9247e56a1..198504b59 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use defmt_rtt as _; // global logger | 5 | use defmt_rtt as _; // global logger |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::*; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | ||
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 11 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| @@ -14,7 +13,7 @@ use futures::future::join; | |||
| 14 | use panic_probe as _; | 13 | use panic_probe as _; |
| 15 | 14 | ||
| 16 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 17 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 18 | }); | 17 | }); |
| 19 | 18 | ||
| 20 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -22,23 +21,26 @@ async fn main(_spawner: Spawner) { | |||
| 22 | info!("Hello World!"); | 21 | info!("Hello World!"); |
| 23 | 22 | ||
| 24 | let mut config = Config::default(); | 23 | let mut config = Config::default(); |
| 25 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | 24 | { |
| 26 | config.rcc.sys = Sysclk::PLL1_R; | 25 | use embassy_stm32::rcc::*; |
| 27 | config.rcc.hsi = true; | 26 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB |
| 28 | config.rcc.pll = Some(Pll { | 27 | config.rcc.sys = Sysclk::PLL1_R; |
| 29 | source: PllSource::HSI, | 28 | config.rcc.hsi = true; |
| 30 | prediv: PllPreDiv::DIV1, | 29 | config.rcc.pll = Some(Pll { |
| 31 | mul: PllMul::MUL10, | 30 | source: PllSource::HSI, |
| 32 | divp: None, | 31 | prediv: PllPreDiv::DIV1, |
| 33 | divq: None, | 32 | mul: PllMul::MUL10, |
| 34 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) | 33 | divp: None, |
| 35 | }); | 34 | divq: None, |
| 36 | 35 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) | |
| 36 | }); | ||
| 37 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 38 | } | ||
| 37 | let p = embassy_stm32::init(config); | 39 | let p = embassy_stm32::init(config); |
| 38 | 40 | ||
| 39 | // Create the driver, from the HAL. | 41 | // Create the driver, from the HAL. |
| 40 | let mut ep_out_buffer = [0u8; 256]; | 42 | let mut ep_out_buffer = [0u8; 256]; |
| 41 | let mut config = embassy_stm32::usb_otg::Config::default(); | 43 | let mut config = embassy_stm32::usb::Config::default(); |
| 42 | config.vbus_detection = true; | 44 | config.vbus_detection = true; |
| 43 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 45 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 44 | 46 | ||
| @@ -58,7 +60,6 @@ async fn main(_spawner: Spawner) { | |||
| 58 | 60 | ||
| 59 | // Create embassy-usb DeviceBuilder using the driver and config. | 61 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 60 | // It needs some buffers for building the descriptors. | 62 | // It needs some buffers for building the descriptors. |
| 61 | let mut device_descriptor = [0; 256]; | ||
| 62 | let mut config_descriptor = [0; 256]; | 63 | let mut config_descriptor = [0; 256]; |
| 63 | let mut bos_descriptor = [0; 256]; | 64 | let mut bos_descriptor = [0; 256]; |
| 64 | let mut control_buf = [0; 64]; | 65 | let mut control_buf = [0; 64]; |
| @@ -68,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 68 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 69 | driver, | 70 | driver, |
| 70 | config, | 71 | config, |
| 71 | &mut device_descriptor, | ||
| 72 | &mut config_descriptor, | 72 | &mut config_descriptor, |
| 73 | &mut bos_descriptor, | 73 | &mut bos_descriptor, |
| 74 | &mut [], // no msos descriptors | 74 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index f6d8b16d0..7f73fd677 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -5,7 +5,6 @@ use defmt::*; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::{Stack, StackResources}; |
| 8 | use embassy_stm32::rcc::*; | ||
| 9 | use embassy_stm32::rng::Rng; | 8 | use embassy_stm32::rng::Rng; |
| 10 | use embassy_stm32::usb::Driver; | 9 | use embassy_stm32::usb::Driver; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; |
| @@ -44,17 +43,22 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | |||
| 44 | #[embassy_executor::main] | 43 | #[embassy_executor::main] |
| 45 | async fn main(spawner: Spawner) { | 44 | async fn main(spawner: Spawner) { |
| 46 | let mut config = Config::default(); | 45 | let mut config = Config::default(); |
| 47 | config.rcc.hsi = true; | 46 | { |
| 48 | config.rcc.sys = Sysclk::PLL1_R; | 47 | use embassy_stm32::rcc::*; |
| 49 | config.rcc.pll = Some(Pll { | 48 | config.rcc.hsi = true; |
| 50 | // 80Mhz clock (16 / 1 * 10 / 2) | 49 | config.rcc.sys = Sysclk::PLL1_R; |
| 51 | source: PllSource::HSI, | 50 | config.rcc.pll = Some(Pll { |
| 52 | prediv: PllPreDiv::DIV1, | 51 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 53 | mul: PllMul::MUL10, | 52 | source: PllSource::HSI, |
| 54 | divp: None, | 53 | prediv: PllPreDiv::DIV1, |
| 55 | divq: None, | 54 | mul: PllMul::MUL10, |
| 56 | divr: Some(PllRDiv::DIV2), | 55 | divp: None, |
| 57 | }); | 56 | divq: None, |
| 57 | divr: Some(PllRDiv::DIV2), | ||
| 58 | }); | ||
| 59 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 60 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 61 | } | ||
| 58 | let p = embassy_stm32::init(config); | 62 | let p = embassy_stm32::init(config); |
| 59 | 63 | ||
| 60 | // Create the driver, from the HAL. | 64 | // Create the driver, from the HAL. |
| @@ -75,14 +79,12 @@ async fn main(spawner: Spawner) { | |||
| 75 | config.device_protocol = 0x01; | 79 | config.device_protocol = 0x01; |
| 76 | 80 | ||
| 77 | // Create embassy-usb DeviceBuilder using the driver and config. | 81 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 78 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 79 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 82 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 80 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 83 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 81 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 84 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 82 | let mut builder = Builder::new( | 85 | let mut builder = Builder::new( |
| 83 | driver, | 86 | driver, |
| 84 | config, | 87 | config, |
| 85 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 86 | &mut CONFIG_DESC.init([0; 256])[..], | 88 | &mut CONFIG_DESC.init([0; 256])[..], |
| 87 | &mut BOS_DESC.init([0; 256])[..], | 89 | &mut BOS_DESC.init([0; 256])[..], |
| 88 | &mut [], // no msos descriptors | 90 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index c51ed96e0..9d30205bb 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::rcc::*; | ||
| 8 | use embassy_stm32::usb::Driver; | 7 | use embassy_stm32::usb::Driver; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| @@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs { | |||
| 21 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 22 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 23 | let mut config = Config::default(); | 22 | let mut config = Config::default(); |
| 24 | config.rcc.hsi = true; | 23 | { |
| 25 | config.rcc.sys = Sysclk::PLL1_R; | 24 | use embassy_stm32::rcc::*; |
| 26 | config.rcc.pll = Some(Pll { | 25 | config.rcc.hsi = true; |
| 27 | // 80Mhz clock (16 / 1 * 10 / 2) | 26 | config.rcc.sys = Sysclk::PLL1_R; |
| 28 | source: PllSource::HSI, | 27 | config.rcc.pll = Some(Pll { |
| 29 | prediv: PllPreDiv::DIV1, | 28 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 30 | mul: PllMul::MUL10, | 29 | source: PllSource::HSI, |
| 31 | divp: None, | 30 | prediv: PllPreDiv::DIV1, |
| 32 | divq: None, | 31 | mul: PllMul::MUL10, |
| 33 | divr: Some(PllRDiv::DIV2), | 32 | divp: None, |
| 34 | }); | 33 | divq: None, |
| 34 | divr: Some(PllRDiv::DIV2), | ||
| 35 | }); | ||
| 36 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 37 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 38 | } | ||
| 35 | let p = embassy_stm32::init(config); | 39 | let p = embassy_stm32::init(config); |
| 36 | 40 | ||
| 37 | // Create the driver, from the HAL. | 41 | // Create the driver, from the HAL. |
| @@ -47,7 +51,6 @@ async fn main(_spawner: Spawner) { | |||
| 47 | 51 | ||
| 48 | // Create embassy-usb DeviceBuilder using the driver and config. | 52 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 49 | // It needs some buffers for building the descriptors. | 53 | // It needs some buffers for building the descriptors. |
| 50 | let mut device_descriptor = [0; 256]; | ||
| 51 | let mut config_descriptor = [0; 256]; | 54 | let mut config_descriptor = [0; 256]; |
| 52 | let mut bos_descriptor = [0; 256]; | 55 | let mut bos_descriptor = [0; 256]; |
| 53 | let mut control_buf = [0; 64]; | 56 | let mut control_buf = [0; 64]; |
| @@ -58,7 +61,6 @@ async fn main(_spawner: Spawner) { | |||
| 58 | let mut builder = Builder::new( | 61 | let mut builder = Builder::new( |
| 59 | driver, | 62 | driver, |
| 60 | config, | 63 | config, |
| 61 | &mut device_descriptor, | ||
| 62 | &mut config_descriptor, | 64 | &mut config_descriptor, |
| 63 | &mut bos_descriptor, | 65 | &mut bos_descriptor, |
| 64 | &mut [], // no msos descriptors | 66 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 87987f2ce..a64bda31b 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::rcc::*; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs { | |||
| 19 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.rcc.hsi = true; | 21 | { |
| 23 | config.rcc.sys = Sysclk::PLL1_R; | 22 | use embassy_stm32::rcc::*; |
| 24 | config.rcc.pll = Some(Pll { | 23 | config.rcc.hsi = true; |
| 25 | // 80Mhz clock (16 / 1 * 10 / 2) | 24 | config.rcc.sys = Sysclk::PLL1_R; |
| 26 | source: PllSource::HSI, | 25 | config.rcc.pll = Some(Pll { |
| 27 | prediv: PllPreDiv::DIV1, | 26 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 28 | mul: PllMul::MUL10, | 27 | source: PllSource::HSI, |
| 29 | divp: None, | 28 | prediv: PllPreDiv::DIV1, |
| 30 | divq: None, | 29 | mul: PllMul::MUL10, |
| 31 | divr: Some(PllRDiv::DIV2), | 30 | divp: None, |
| 32 | }); | 31 | divq: None, |
| 32 | divr: Some(PllRDiv::DIV2), | ||
| 33 | }); | ||
| 34 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 35 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 36 | } | ||
| 33 | let p = embassy_stm32::init(config); | 37 | let p = embassy_stm32::init(config); |
| 34 | 38 | ||
| 35 | info!("Hello World!"); | 39 | info!("Hello World!"); |
| @@ -43,7 +47,6 @@ async fn main(_spawner: Spawner) { | |||
| 43 | 47 | ||
| 44 | // Create embassy-usb DeviceBuilder using the driver and config. | 48 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 45 | // It needs some buffers for building the descriptors. | 49 | // It needs some buffers for building the descriptors. |
| 46 | let mut device_descriptor = [0; 256]; | ||
| 47 | let mut config_descriptor = [0; 256]; | 50 | let mut config_descriptor = [0; 256]; |
| 48 | let mut bos_descriptor = [0; 256]; | 51 | let mut bos_descriptor = [0; 256]; |
| 49 | let mut control_buf = [0; 7]; | 52 | let mut control_buf = [0; 7]; |
| @@ -53,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 54 | driver, | 57 | driver, |
| 55 | config, | 58 | config, |
| 56 | &mut device_descriptor, | ||
| 57 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 58 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 59 | &mut [], // no msos descriptors | 61 | &mut [], // no msos descriptors |
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 61851e5a2..6a313efb0 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use defmt_rtt as _; // global logger | 5 | use defmt_rtt as _; // global logger |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::usb_otg::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| @@ -13,7 +13,7 @@ use futures::future::join; | |||
| 13 | use panic_probe as _; | 13 | use panic_probe as _; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -35,13 +35,14 @@ async fn main(_spawner: Spawner) { | |||
| 35 | config.rcc.sys = Sysclk::PLL1_R; | 35 | config.rcc.sys = Sysclk::PLL1_R; |
| 36 | config.rcc.voltage_range = VoltageScale::RANGE1; | 36 | config.rcc.voltage_range = VoltageScale::RANGE1; |
| 37 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | 37 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB |
| 38 | config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | let p = embassy_stm32::init(config); | 41 | let p = embassy_stm32::init(config); |
| 41 | 42 | ||
| 42 | // Create the driver, from the HAL. | 43 | // Create the driver, from the HAL. |
| 43 | let mut ep_out_buffer = [0u8; 256]; | 44 | let mut ep_out_buffer = [0u8; 256]; |
| 44 | let mut config = embassy_stm32::usb_otg::Config::default(); | 45 | let mut config = embassy_stm32::usb::Config::default(); |
| 45 | config.vbus_detection = false; | 46 | config.vbus_detection = false; |
| 46 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 47 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 47 | 48 | ||
| @@ -60,7 +61,6 @@ async fn main(_spawner: Spawner) { | |||
| 60 | 61 | ||
| 61 | // Create embassy-usb DeviceBuilder using the driver and config. | 62 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 62 | // It needs some buffers for building the descriptors. | 63 | // It needs some buffers for building the descriptors. |
| 63 | let mut device_descriptor = [0; 256]; | ||
| 64 | let mut config_descriptor = [0; 256]; | 64 | let mut config_descriptor = [0; 256]; |
| 65 | let mut bos_descriptor = [0; 256]; | 65 | let mut bos_descriptor = [0; 256]; |
| 66 | let mut control_buf = [0; 64]; | 66 | let mut control_buf = [0; 64]; |
| @@ -70,7 +70,6 @@ async fn main(_spawner: Spawner) { | |||
| 70 | let mut builder = Builder::new( | 70 | let mut builder = Builder::new( |
| 71 | driver, | 71 | driver, |
| 72 | config, | 72 | config, |
| 73 | &mut device_descriptor, | ||
| 74 | &mut config_descriptor, | 73 | &mut config_descriptor, |
| 75 | &mut bos_descriptor, | 74 | &mut bos_descriptor, |
| 76 | &mut [], // no msos descriptors | 75 | &mut [], // no msos descriptors |
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index b8a7db353..98696fd2b 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | [toolchain] | 1 | [toolchain] |
| 2 | channel = "nightly-2023-12-20" | 2 | channel = "nightly-2024-03-20" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] |
| 4 | targets = [ | 4 | targets = [ |
| 5 | "thumbv7em-none-eabi", | 5 | "thumbv7em-none-eabi", |
diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a6fe52ee2..2f5d17069 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | [toolchain] | 1 | [toolchain] |
| 2 | channel = "1.75" | 2 | channel = "1.77" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools" ] |
| 4 | targets = [ | 4 | targets = [ |
| 5 | "thumbv7em-none-eabi", | 5 | "thumbv7em-none-eabi", |
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index 8aed9b80c..e9c6f3122 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs | |||
| @@ -21,10 +21,14 @@ static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new(); | |||
| 21 | #[cortex_m_rt::entry] | 21 | #[cortex_m_rt::entry] |
| 22 | fn main() -> ! { | 22 | fn main() -> ! { |
| 23 | let p = embassy_rp::init(Default::default()); | 23 | let p = embassy_rp::init(Default::default()); |
| 24 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | 24 | spawn_core1( |
| 25 | let executor1 = EXECUTOR1.init(Executor::new()); | 25 | p.CORE1, |
| 26 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); | 26 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, |
| 27 | }); | 27 | move || { |
| 28 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 29 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); | ||
| 30 | }, | ||
| 31 | ); | ||
| 28 | let executor0 = EXECUTOR0.init(Executor::new()); | 32 | let executor0 = EXECUTOR0.init(Executor::new()); |
| 29 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0)))); | 33 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0)))); |
| 30 | } | 34 | } |
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 153b37999..9615007bd 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs | |||
| @@ -210,10 +210,14 @@ async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { | |||
| 210 | config.addr = DEV_ADDR as u16; | 210 | config.addr = DEV_ADDR as u16; |
| 211 | let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); | 211 | let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); |
| 212 | 212 | ||
| 213 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | 213 | spawn_core1( |
| 214 | let executor1 = EXECUTOR1.init(Executor::new()); | 214 | p.CORE1, |
| 215 | executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); | 215 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, |
| 216 | }); | 216 | move || { |
| 217 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 218 | executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); | ||
| 219 | }, | ||
| 220 | ); | ||
| 217 | 221 | ||
| 218 | let c_sda = p.PIN_21; | 222 | let c_sda = p.PIN_21; |
| 219 | let c_scl = p.PIN_20; | 223 | let c_scl = p.PIN_20; |
diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 60d9f85ec..783ea0f27 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs | |||
| @@ -19,10 +19,14 @@ static CHANNEL1: Channel<CriticalSectionRawMutex, bool, 1> = Channel::new(); | |||
| 19 | #[cortex_m_rt::entry] | 19 | #[cortex_m_rt::entry] |
| 20 | fn main() -> ! { | 20 | fn main() -> ! { |
| 21 | let p = embassy_rp::init(Default::default()); | 21 | let p = embassy_rp::init(Default::default()); |
| 22 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | 22 | spawn_core1( |
| 23 | let executor1 = EXECUTOR1.init(Executor::new()); | 23 | p.CORE1, |
| 24 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); | 24 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, |
| 25 | }); | 25 | move || { |
| 26 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 27 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); | ||
| 28 | }, | ||
| 29 | ); | ||
| 26 | let executor0 = EXECUTOR0.init(Executor::new()); | 30 | let executor0 = EXECUTOR0.init(Executor::new()); |
| 27 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); | 31 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); |
| 28 | } | 32 | } |
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index e71d9e610..4b02e5bab 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs | |||
| @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { | |||
| 28 | 28 | ||
| 29 | // Test free-running clock | 29 | // Test free-running clock |
| 30 | { | 30 | { |
| 31 | let pwm = Pwm::new_free(&mut p.PWM_CH3, cfg.clone()); | 31 | let pwm = Pwm::new_free(&mut p.PWM_SLICE3, cfg.clone()); |
| 32 | cortex_m::asm::delay(125); | 32 | cortex_m::asm::delay(125); |
| 33 | let ctr = pwm.counter(); | 33 | let ctr = pwm.counter(); |
| 34 | assert!(ctr > 0); | 34 | assert!(ctr > 0); |
| @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { | |||
| 46 | // Test output from A | 46 | // Test output from A |
| 47 | { | 47 | { |
| 48 | let pin1 = Input::new(&mut p9, Pull::None); | 48 | let pin1 = Input::new(&mut p9, Pull::None); |
| 49 | let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone()); | 49 | let _pwm = Pwm::new_output_a(&mut p.PWM_SLICE3, &mut p6, cfg.clone()); |
| 50 | Timer::after_millis(1).await; | 50 | Timer::after_millis(1).await; |
| 51 | assert_eq!(pin1.is_low(), invert_a); | 51 | assert_eq!(pin1.is_low(), invert_a); |
| 52 | Timer::after_millis(5).await; | 52 | Timer::after_millis(5).await; |
| @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { | |||
| 60 | // Test output from B | 60 | // Test output from B |
| 61 | { | 61 | { |
| 62 | let pin2 = Input::new(&mut p11, Pull::None); | 62 | let pin2 = Input::new(&mut p11, Pull::None); |
| 63 | let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone()); | 63 | let _pwm = Pwm::new_output_b(&mut p.PWM_SLICE3, &mut p7, cfg.clone()); |
| 64 | Timer::after_millis(1).await; | 64 | Timer::after_millis(1).await; |
| 65 | assert_ne!(pin2.is_low(), invert_a); | 65 | assert_ne!(pin2.is_low(), invert_a); |
| 66 | Timer::after_millis(5).await; | 66 | Timer::after_millis(5).await; |
| @@ -75,7 +75,7 @@ async fn main(_spawner: Spawner) { | |||
| 75 | { | 75 | { |
| 76 | let pin1 = Input::new(&mut p9, Pull::None); | 76 | let pin1 = Input::new(&mut p9, Pull::None); |
| 77 | let pin2 = Input::new(&mut p11, Pull::None); | 77 | let pin2 = Input::new(&mut p11, Pull::None); |
| 78 | let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone()); | 78 | let _pwm = Pwm::new_output_ab(&mut p.PWM_SLICE3, &mut p6, &mut p7, cfg.clone()); |
| 79 | Timer::after_millis(1).await; | 79 | Timer::after_millis(1).await; |
| 80 | assert_eq!(pin1.is_low(), invert_a); | 80 | assert_eq!(pin1.is_low(), invert_a); |
| 81 | assert_ne!(pin2.is_low(), invert_a); | 81 | assert_ne!(pin2.is_low(), invert_a); |
| @@ -94,7 +94,7 @@ async fn main(_spawner: Spawner) { | |||
| 94 | // Test level-gated | 94 | // Test level-gated |
| 95 | { | 95 | { |
| 96 | let mut pin2 = Output::new(&mut p11, Level::Low); | 96 | let mut pin2 = Output::new(&mut p11, Level::Low); |
| 97 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::Level, cfg.clone()); | 97 | let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::Level, cfg.clone()); |
| 98 | assert_eq!(pwm.counter(), 0); | 98 | assert_eq!(pwm.counter(), 0); |
| 99 | Timer::after_millis(5).await; | 99 | Timer::after_millis(5).await; |
| 100 | assert_eq!(pwm.counter(), 0); | 100 | assert_eq!(pwm.counter(), 0); |
| @@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) { | |||
| 110 | // Test rising-gated | 110 | // Test rising-gated |
| 111 | { | 111 | { |
| 112 | let mut pin2 = Output::new(&mut p11, Level::Low); | 112 | let mut pin2 = Output::new(&mut p11, Level::Low); |
| 113 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::RisingEdge, cfg.clone()); | 113 | let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::RisingEdge, cfg.clone()); |
| 114 | assert_eq!(pwm.counter(), 0); | 114 | assert_eq!(pwm.counter(), 0); |
| 115 | Timer::after_millis(5).await; | 115 | Timer::after_millis(5).await; |
| 116 | assert_eq!(pwm.counter(), 0); | 116 | assert_eq!(pwm.counter(), 0); |
| @@ -125,7 +125,7 @@ async fn main(_spawner: Spawner) { | |||
| 125 | // Test falling-gated | 125 | // Test falling-gated |
| 126 | { | 126 | { |
| 127 | let mut pin2 = Output::new(&mut p11, Level::High); | 127 | let mut pin2 = Output::new(&mut p11, Level::High); |
| 128 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::FallingEdge, cfg.clone()); | 128 | let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::FallingEdge, cfg.clone()); |
| 129 | assert_eq!(pwm.counter(), 0); | 129 | assert_eq!(pwm.counter(), 0); |
| 130 | Timer::after_millis(5).await; | 130 | Timer::after_millis(5).await; |
| 131 | assert_eq!(pwm.counter(), 0); | 131 | assert_eq!(pwm.counter(), 0); |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bfe003a11..e42470004 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -13,7 +13,7 @@ stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] | |||
| 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] | 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] |
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] |
| @@ -47,6 +47,7 @@ mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] | |||
| 47 | embassy-stm32-wpan = [] | 47 | embassy-stm32-wpan = [] |
| 48 | not-gpdma = [] | 48 | not-gpdma = [] |
| 49 | dac = [] | 49 | dac = [] |
| 50 | ucpd = [] | ||
| 50 | 51 | ||
| 51 | cm0 = ["portable-atomic/unsafe-assume-single-core"] | 52 | cm0 = ["portable-atomic/unsafe-assume-single-core"] |
| 52 | 53 | ||
| @@ -161,6 +162,11 @@ path = "src/bin/timer.rs" | |||
| 161 | required-features = [] | 162 | required-features = [] |
| 162 | 163 | ||
| 163 | [[bin]] | 164 | [[bin]] |
| 165 | name = "ucpd" | ||
| 166 | path = "src/bin/ucpd.rs" | ||
| 167 | required-features = [ "ucpd",] | ||
| 168 | |||
| 169 | [[bin]] | ||
| 164 | name = "usart" | 170 | name = "usart" |
| 165 | path = "src/bin/usart.rs" | 171 | path = "src/bin/usart.rs" |
| 166 | required-features = [] | 172 | required-features = [] |
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index f4effa244..551764458 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs | |||
| @@ -6,17 +6,20 @@ | |||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| 8 | use common::*; | 8 | use common::*; |
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::bind_interrupts; | 10 | use embassy_stm32::bind_interrupts; |
| 12 | use embassy_stm32::can::bxcan::filter::Mask32; | 11 | use embassy_stm32::can::filter::Mask32; |
| 13 | use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; | 12 | use embassy_stm32::can::{ |
| 14 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 13 | Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, |
| 14 | }; | ||
| 15 | use embassy_stm32::gpio::{Input, Pull}; | 15 | use embassy_stm32::gpio::{Input, Pull}; |
| 16 | use embassy_stm32::peripherals::CAN1; | 16 | use embassy_stm32::peripherals::CAN1; |
| 17 | use embassy_time::{Duration, Instant}; | 17 | use embassy_time::Duration; |
| 18 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 19 | 19 | ||
| 20 | mod can_common; | ||
| 21 | use can_common::*; | ||
| 22 | |||
| 20 | bind_interrupts!(struct Irqs { | 23 | bind_interrupts!(struct Irqs { |
| 21 | CAN1_RX0 => Rx0InterruptHandler<CAN1>; | 24 | CAN1_RX0 => Rx0InterruptHandler<CAN1>; |
| 22 | CAN1_RX1 => Rx1InterruptHandler<CAN1>; | 25 | CAN1_RX1 => Rx1InterruptHandler<CAN1>; |
| @@ -29,6 +32,11 @@ async fn main(_spawner: Spawner) { | |||
| 29 | let p = embassy_stm32::init(config()); | 32 | let p = embassy_stm32::init(config()); |
| 30 | info!("Hello World!"); | 33 | info!("Hello World!"); |
| 31 | 34 | ||
| 35 | let options = TestOptions { | ||
| 36 | max_latency: Duration::from_micros(1200), | ||
| 37 | max_buffered: 2, | ||
| 38 | }; | ||
| 39 | |||
| 32 | let can = peri!(p, CAN); | 40 | let can = peri!(p, CAN); |
| 33 | let tx = peri!(p, CAN_TX); | 41 | let tx = peri!(p, CAN_TX); |
| 34 | let mut rx = peri!(p, CAN_RX); | 42 | let mut rx = peri!(p, CAN_RX); |
| @@ -44,54 +52,25 @@ async fn main(_spawner: Spawner) { | |||
| 44 | 52 | ||
| 45 | info!("Configuring can..."); | 53 | info!("Configuring can..."); |
| 46 | 54 | ||
| 47 | can.as_mut() | 55 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 48 | .modify_filters() | ||
| 49 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 50 | 56 | ||
| 51 | can.set_bitrate(1_000_000); | 57 | can.modify_config() |
| 52 | can.as_mut() | ||
| 53 | .modify_config() | ||
| 54 | .set_loopback(true) // Receive own frames | 58 | .set_loopback(true) // Receive own frames |
| 55 | .set_silent(true) | 59 | .set_silent(true) |
| 56 | // .set_bit_timing(0x001c0003) | 60 | // .set_bit_timing(0x001c0003) |
| 57 | .enable(); | 61 | .set_bitrate(1_000_000); |
| 58 | |||
| 59 | info!("Can configured"); | ||
| 60 | |||
| 61 | let mut i: u8 = 0; | ||
| 62 | loop { | ||
| 63 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); | ||
| 64 | 62 | ||
| 65 | info!("Transmitting frame..."); | 63 | can.enable().await; |
| 66 | let tx_ts = Instant::now(); | ||
| 67 | can.write(&tx_frame).await; | ||
| 68 | 64 | ||
| 69 | let envelope = can.read().await.unwrap(); | 65 | info!("Can configured"); |
| 70 | info!("Frame received!"); | ||
| 71 | |||
| 72 | info!("loopback time {}", envelope.ts); | ||
| 73 | info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]); | ||
| 74 | |||
| 75 | let latency = envelope.ts.saturating_duration_since(tx_ts); | ||
| 76 | info!("loopback latency {} us", latency.as_micros()); | ||
| 77 | 66 | ||
| 78 | // Theoretical minimum latency is 55us, actual is usually ~80us | 67 | run_can_tests(&mut can, &options).await; |
| 79 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 80 | const MAX_LATENCY: Duration = Duration::from_micros(150); | ||
| 81 | assert!( | ||
| 82 | MIN_LATENCY <= latency && latency <= MAX_LATENCY, | ||
| 83 | "{} <= {} <= {}", | ||
| 84 | MIN_LATENCY, | ||
| 85 | latency, | ||
| 86 | MAX_LATENCY | ||
| 87 | ); | ||
| 88 | 68 | ||
| 89 | i += 1; | 69 | // Test again with a split |
| 90 | if i > 10 { | 70 | let (mut tx, mut rx) = can.split(); |
| 91 | break; | 71 | run_split_can_tests(&mut tx, &mut rx, &options).await; |
| 92 | } | ||
| 93 | } | ||
| 94 | 72 | ||
| 95 | info!("Test OK"); | 73 | info!("Test OK"); |
| 74 | |||
| 96 | cortex_m::asm::bkpt(); | 75 | cortex_m::asm::bkpt(); |
| 97 | } | 76 | } |
diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs new file mode 100644 index 000000000..4b39269cc --- /dev/null +++ b/tests/stm32/src/bin/can_common.rs | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | use defmt::{assert, *}; | ||
| 2 | use embassy_stm32::can; | ||
| 3 | use embassy_time::{Duration, Instant}; | ||
| 4 | |||
| 5 | #[derive(Clone, Copy, Debug)] | ||
| 6 | pub struct TestOptions { | ||
| 7 | pub max_latency: Duration, | ||
| 8 | pub max_buffered: u8, | ||
| 9 | } | ||
| 10 | |||
| 11 | pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { | ||
| 12 | let mut i: u8 = 0; | ||
| 13 | loop { | ||
| 14 | //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap(); | ||
| 15 | let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 16 | |||
| 17 | //info!("Transmitting frame..."); | ||
| 18 | let tx_ts = Instant::now(); | ||
| 19 | can.write(&tx_frame).await; | ||
| 20 | |||
| 21 | let (frame, timestamp) = can.read().await.unwrap().parts(); | ||
| 22 | //info!("Frame received!"); | ||
| 23 | |||
| 24 | // Check data. | ||
| 25 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 26 | |||
| 27 | //info!("loopback time {}", timestamp); | ||
| 28 | //info!("loopback frame {=u8}", frame.data()[0]); | ||
| 29 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 30 | info!("loopback latency {} us", latency.as_micros()); | ||
| 31 | |||
| 32 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 33 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 34 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 35 | // sure if there are other delays | ||
| 36 | assert!( | ||
| 37 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 38 | "{} <= {} <= {}", | ||
| 39 | MIN_LATENCY, | ||
| 40 | latency, | ||
| 41 | options.max_latency | ||
| 42 | ); | ||
| 43 | |||
| 44 | i += 1; | ||
| 45 | if i > 5 { | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | // Below here, check that we can receive from both FIFO0 and FIFO1 | ||
| 51 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 52 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 53 | for i in 0..options.max_buffered { | ||
| 54 | // Try filling up the RX FIFO0 buffers | ||
| 55 | //let tx_frame = if 0 != (i & 0x01) { | ||
| 56 | let tx_frame = if i < options.max_buffered / 2 { | ||
| 57 | info!("Transmitting standard frame {}", i); | ||
| 58 | can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() | ||
| 59 | } else { | ||
| 60 | info!("Transmitting extended frame {}", i); | ||
| 61 | can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() | ||
| 62 | }; | ||
| 63 | can.write(&tx_frame).await; | ||
| 64 | } | ||
| 65 | |||
| 66 | // Try and receive all 6 packets | ||
| 67 | for _i in 0..options.max_buffered { | ||
| 68 | let (frame, _ts) = can.read().await.unwrap().parts(); | ||
| 69 | match frame.id() { | ||
| 70 | embedded_can::Id::Extended(_id) => { | ||
| 71 | info!("Extended received! {}", frame.data()[0]); | ||
| 72 | //info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 73 | } | ||
| 74 | embedded_can::Id::Standard(_id) => { | ||
| 75 | info!("Standard received! {}", frame.data()[0]); | ||
| 76 | //info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | pub async fn run_split_can_tests<'d, T: can::Instance>( | ||
| 83 | tx: &mut can::CanTx<'d, T>, | ||
| 84 | rx: &mut can::CanRx<'d, T>, | ||
| 85 | options: &TestOptions, | ||
| 86 | ) { | ||
| 87 | for i in 0..options.max_buffered { | ||
| 88 | // Try filling up the RX FIFO0 buffers | ||
| 89 | //let tx_frame = if 0 != (i & 0x01) { | ||
| 90 | let tx_frame = if i < options.max_buffered / 2 { | ||
| 91 | info!("Transmitting standard frame {}", i); | ||
| 92 | can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() | ||
| 93 | } else { | ||
| 94 | info!("Transmitting extended frame {}", i); | ||
| 95 | can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() | ||
| 96 | }; | ||
| 97 | tx.write(&tx_frame).await; | ||
| 98 | } | ||
| 99 | |||
| 100 | // Try and receive all 6 packets | ||
| 101 | for _i in 0..options.max_buffered { | ||
| 102 | let (frame, _ts) = rx.read().await.unwrap().parts(); | ||
| 103 | match frame.id() { | ||
| 104 | embedded_can::Id::Extended(_id) => { | ||
| 105 | info!("Extended received! {}", frame.data()[0]); | ||
| 106 | } | ||
| 107 | embedded_can::Id::Standard(_id) => { | ||
| 108 | info!("Standard received! {}", frame.data()[0]); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index f105abf26..60778bdaa 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs | |||
| @@ -10,9 +10,14 @@ use aes_gcm::aead::{AeadInPlace, KeyInit}; | |||
| 10 | use aes_gcm::Aes128Gcm; | 10 | use aes_gcm::Aes128Gcm; |
| 11 | use common::*; | 11 | use common::*; |
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_stm32::cryp::*; | 13 | use embassy_stm32::cryp::{self, *}; |
| 14 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 16 | ||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | CRYP => cryp::InterruptHandler<peripherals::CRYP>; | ||
| 19 | }); | ||
| 20 | |||
| 16 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 22 | async fn main(_spawner: Spawner) { |
| 18 | let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); | 23 | let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); |
| @@ -22,27 +27,32 @@ async fn main(_spawner: Spawner) { | |||
| 22 | const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; | 27 | const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; |
| 23 | const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; | 28 | const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; |
| 24 | 29 | ||
| 25 | let hw_cryp = Cryp::new(p.CRYP); | 30 | let in_dma = peri!(p, CRYP_IN_DMA); |
| 31 | let out_dma = peri!(p, CRYP_OUT_DMA); | ||
| 32 | |||
| 33 | let mut hw_cryp = Cryp::new(p.CRYP, in_dma, out_dma, Irqs); | ||
| 26 | let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | 34 | let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
| 27 | let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; | 35 | let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; |
| 28 | let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; | 36 | let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; |
| 29 | let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; | 37 | let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; |
| 30 | 38 | ||
| 31 | // Encrypt in hardware using AES-GCM 128-bit | 39 | // Encrypt in hardware using AES-GCM 128-bit in blocking mode. |
| 32 | let aes_gcm = AesGcm::new(&key, &iv); | 40 | let aes_gcm = AesGcm::new(&key, &iv); |
| 33 | let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); | 41 | let mut gcm_encrypt = hw_cryp.start_blocking(&aes_gcm, Direction::Encrypt); |
| 34 | hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); | 42 | hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); |
| 35 | hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); | 43 | hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); |
| 36 | hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); | 44 | hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); |
| 37 | hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); | 45 | hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); |
| 38 | let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); | 46 | let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); |
| 39 | 47 | ||
| 40 | // Decrypt in hardware using AES-GCM 128-bit | 48 | // Decrypt in hardware using AES-GCM 128-bit in async (DMA) mode. |
| 41 | let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); | 49 | let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; |
| 42 | hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false); | 50 | hw_cryp.aad(&mut gcm_decrypt, AAD1, false).await; |
| 43 | hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true); | 51 | hw_cryp.aad(&mut gcm_decrypt, AAD2, true).await; |
| 44 | hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); | 52 | hw_cryp |
| 45 | let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); | 53 | .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true) |
| 54 | .await; | ||
| 55 | let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; | ||
| 46 | 56 | ||
| 47 | info!("AES-GCM Ciphertext: {:?}", ciphertext); | 57 | info!("AES-GCM Ciphertext: {:?}", ciphertext); |
| 48 | info!("AES-GCM Plaintext: {:?}", plaintext); | 58 | info!("AES-GCM Plaintext: {:?}", plaintext); |
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index dd78d7fb3..27bdd038a 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs | |||
| @@ -6,26 +6,26 @@ | |||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| 8 | use common::*; | 8 | use common::*; |
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::peripherals::*; | 10 | use embassy_stm32::peripherals::*; |
| 12 | use embassy_stm32::{bind_interrupts, can, Config}; | 11 | use embassy_stm32::{bind_interrupts, can, Config}; |
| 13 | use embassy_time::{Duration, Instant}; | 12 | use embassy_time::Duration; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 14 | ||
| 16 | bind_interrupts!(struct Irqs { | 15 | mod can_common; |
| 16 | use can_common::*; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs2 { | ||
| 19 | FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; | ||
| 20 | FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; | ||
| 21 | }); | ||
| 22 | bind_interrupts!(struct Irqs1 { | ||
| 17 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | 23 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; |
| 18 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | 24 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; |
| 19 | }); | 25 | }); |
| 20 | 26 | ||
| 21 | struct TestOptions { | ||
| 22 | config: Config, | ||
| 23 | max_latency: Duration, | ||
| 24 | second_fifo_working: bool, | ||
| 25 | } | ||
| 26 | |||
| 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] | 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] |
| 28 | fn options() -> TestOptions { | 28 | fn options() -> (Config, TestOptions) { |
| 29 | use embassy_stm32::rcc; | 29 | use embassy_stm32::rcc; |
| 30 | info!("H75 config"); | 30 | info!("H75 config"); |
| 31 | let mut c = config(); | 31 | let mut c = config(); |
| @@ -34,15 +34,17 @@ fn options() -> TestOptions { | |||
| 34 | mode: rcc::HseMode::Oscillator, | 34 | mode: rcc::HseMode::Oscillator, |
| 35 | }); | 35 | }); |
| 36 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 36 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 37 | TestOptions { | 37 | ( |
| 38 | config: c, | 38 | c, |
| 39 | max_latency: Duration::from_micros(1200), | 39 | TestOptions { |
| 40 | second_fifo_working: false, | 40 | max_latency: Duration::from_micros(1200), |
| 41 | } | 41 | max_buffered: 3, |
| 42 | }, | ||
| 43 | ) | ||
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | #[cfg(any(feature = "stm32h7a3zi"))] | 46 | #[cfg(any(feature = "stm32h7a3zi"))] |
| 45 | fn options() -> TestOptions { | 47 | fn options() -> (Config, TestOptions) { |
| 46 | use embassy_stm32::rcc; | 48 | use embassy_stm32::rcc; |
| 47 | info!("H7a config"); | 49 | info!("H7a config"); |
| 48 | let mut c = config(); | 50 | let mut c = config(); |
| @@ -51,139 +53,63 @@ fn options() -> TestOptions { | |||
| 51 | mode: rcc::HseMode::Oscillator, | 53 | mode: rcc::HseMode::Oscillator, |
| 52 | }); | 54 | }); |
| 53 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 55 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 54 | TestOptions { | 56 | ( |
| 55 | config: c, | 57 | c, |
| 56 | max_latency: Duration::from_micros(1200), | 58 | TestOptions { |
| 57 | second_fifo_working: false, | 59 | max_latency: Duration::from_micros(1200), |
| 58 | } | 60 | max_buffered: 3, |
| 61 | }, | ||
| 62 | ) | ||
| 59 | } | 63 | } |
| 60 | 64 | ||
| 61 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] | 65 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] |
| 62 | fn options() -> TestOptions { | 66 | fn options() -> (Config, TestOptions) { |
| 63 | info!("G4 config"); | 67 | info!("G4 config"); |
| 64 | TestOptions { | 68 | ( |
| 65 | config: config(), | 69 | config(), |
| 66 | max_latency: Duration::from_micros(500), | 70 | TestOptions { |
| 67 | second_fifo_working: true, | 71 | max_latency: Duration::from_micros(500), |
| 68 | } | 72 | max_buffered: 6, |
| 73 | }, | ||
| 74 | ) | ||
| 69 | } | 75 | } |
| 70 | 76 | ||
| 71 | #[embassy_executor::main] | 77 | #[embassy_executor::main] |
| 72 | async fn main(_spawner: Spawner) { | 78 | async fn main(_spawner: Spawner) { |
| 73 | //let peripherals = embassy_stm32::init(config()); | 79 | //let peripherals = embassy_stm32::init(config()); |
| 74 | 80 | ||
| 75 | let options = options(); | 81 | let (config, options) = options(); |
| 76 | let peripherals = embassy_stm32::init(options.config); | 82 | let peripherals = embassy_stm32::init(config); |
| 77 | 83 | ||
| 78 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); | 84 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); |
| 85 | let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); | ||
| 79 | 86 | ||
| 80 | // 250k bps | 87 | // 250k bps |
| 81 | can.set_bitrate(250_000); | 88 | can.set_bitrate(250_000); |
| 89 | can2.set_bitrate(250_000); | ||
| 82 | 90 | ||
| 83 | can.set_extended_filter( | 91 | can.set_extended_filter( |
| 84 | can::filter::ExtendedFilterSlot::_0, | 92 | can::filter::ExtendedFilterSlot::_0, |
| 85 | can::filter::ExtendedFilter::accept_all_into_fifo1(), | 93 | can::filter::ExtendedFilter::accept_all_into_fifo1(), |
| 86 | ); | 94 | ); |
| 95 | can2.set_extended_filter( | ||
| 96 | can::filter::ExtendedFilterSlot::_0, | ||
| 97 | can::filter::ExtendedFilter::accept_all_into_fifo1(), | ||
| 98 | ); | ||
| 87 | 99 | ||
| 88 | let mut can = can.into_internal_loopback_mode(); | 100 | let mut can = can.into_internal_loopback_mode(); |
| 101 | let mut can2 = can2.into_internal_loopback_mode(); | ||
| 89 | 102 | ||
| 90 | info!("CAN Configured"); | 103 | run_can_tests(&mut can, &options).await; |
| 104 | run_can_tests(&mut can2, &options).await; | ||
| 91 | 105 | ||
| 92 | let mut i: u8 = 0; | 106 | info!("CAN Configured"); |
| 93 | loop { | ||
| 94 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 95 | |||
| 96 | info!("Transmitting frame..."); | ||
| 97 | let tx_ts = Instant::now(); | ||
| 98 | can.write(&tx_frame).await; | ||
| 99 | |||
| 100 | let (frame, timestamp) = can.read().await.unwrap(); | ||
| 101 | info!("Frame received!"); | ||
| 102 | |||
| 103 | // Check data. | ||
| 104 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 105 | |||
| 106 | info!("loopback time {}", timestamp); | ||
| 107 | info!("loopback frame {=u8}", frame.data()[0]); | ||
| 108 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 109 | info!("loopback latency {} us", latency.as_micros()); | ||
| 110 | |||
| 111 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 112 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 113 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 114 | // sure if there are other delays | ||
| 115 | assert!( | ||
| 116 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 117 | "{} <= {} <= {}", | ||
| 118 | MIN_LATENCY, | ||
| 119 | latency, | ||
| 120 | options.max_latency | ||
| 121 | ); | ||
| 122 | |||
| 123 | i += 1; | ||
| 124 | if i > 10 { | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | let max_buffered = if options.second_fifo_working { 6 } else { 3 }; | ||
| 130 | |||
| 131 | // Below here, check that we can receive from both FIFO0 and FIFO0 | ||
| 132 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 133 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 134 | for i in 0..3 { | ||
| 135 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 136 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 137 | info!("Transmitting frame {}", i); | ||
| 138 | can.write(&tx_frame).await; | ||
| 139 | } | ||
| 140 | for i in 3..max_buffered { | ||
| 141 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 142 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 143 | info!("Transmitting frame {}", i); | ||
| 144 | can.write(&tx_frame).await; | ||
| 145 | } | ||
| 146 | |||
| 147 | // Try and receive all 6 packets | ||
| 148 | for i in 0..max_buffered { | ||
| 149 | let (frame, _ts) = can.read().await.unwrap(); | ||
| 150 | match frame.id() { | ||
| 151 | embedded_can::Id::Extended(id) => { | ||
| 152 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 153 | } | ||
| 154 | embedded_can::Id::Standard(id) => { | ||
| 155 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | 107 | ||
| 160 | // Test again with a split | 108 | // Test again with a split |
| 161 | let (mut tx, mut rx) = can.split(); | 109 | let (mut tx, mut rx) = can.split(); |
| 162 | for i in 0..3 { | 110 | let (mut tx2, mut rx2) = can2.split(); |
| 163 | // Try filling up the RX FIFO0 buffers with standard packets | 111 | run_split_can_tests(&mut tx, &mut rx, &options).await; |
| 164 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | 112 | run_split_can_tests(&mut tx2, &mut rx2, &options).await; |
| 165 | info!("Transmitting frame {}", i); | ||
| 166 | tx.write(&tx_frame).await; | ||
| 167 | } | ||
| 168 | for i in 3..max_buffered { | ||
| 169 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 170 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 171 | info!("Transmitting frame {}", i); | ||
| 172 | tx.write(&tx_frame).await; | ||
| 173 | } | ||
| 174 | |||
| 175 | // Try and receive all 6 packets | ||
| 176 | for i in 0..max_buffered { | ||
| 177 | let (frame, _ts) = rx.read().await.unwrap(); | ||
| 178 | match frame.id() { | ||
| 179 | embedded_can::Id::Extended(id) => { | ||
| 180 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 181 | } | ||
| 182 | embedded_can::Id::Standard(id) => { | ||
| 183 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | 113 | ||
| 188 | info!("Test OK"); | 114 | info!("Test OK"); |
| 189 | cortex_m::asm::bkpt(); | 115 | cortex_m::asm::bkpt(); |
diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs new file mode 100644 index 000000000..c09334ec8 --- /dev/null +++ b/tests/stm32/src/bin/ucpd.rs | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | // required-features: ucpd | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use common::*; | ||
| 8 | use defmt::{assert, assert_eq}; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_futures::join::join; | ||
| 11 | use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd}; | ||
| 12 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | UCPD1_2 => ucpd::InterruptHandler<peripherals::UCPD1>, ucpd::InterruptHandler<peripherals::UCPD2>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | static SRC_TO_SNK: [u8; 6] = [0, 1, 2, 3, 4, 5]; | ||
| 20 | static SNK_TO_SRC: [u8; 4] = [9, 8, 7, 6]; | ||
| 21 | |||
| 22 | async fn wait_for_vstate<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>, vstate: CcVState) { | ||
| 23 | let (mut cc1, mut _cc2) = cc_phy.vstate(); | ||
| 24 | while cc1 != vstate { | ||
| 25 | (cc1, _cc2) = cc_phy.wait_for_vstate_change().await; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | async fn source( | ||
| 30 | mut ucpd: Ucpd<'static, peripherals::UCPD1>, | ||
| 31 | rx_dma: peripherals::DMA1_CH1, | ||
| 32 | tx_dma: peripherals::DMA1_CH2, | ||
| 33 | ) { | ||
| 34 | debug!("source: setting default current pull-up"); | ||
| 35 | ucpd.cc_phy().set_pull(CcPull::SourceDefaultUsb); | ||
| 36 | |||
| 37 | // Wait for default sink. | ||
| 38 | debug!("source: wait for sink"); | ||
| 39 | wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await; | ||
| 40 | |||
| 41 | // Advertise a higher current by changing the pull-up resistor. | ||
| 42 | debug!("source: sink detected, setting 3.0A current pull-up"); | ||
| 43 | ucpd.cc_phy().set_pull(CcPull::Source3_0A); | ||
| 44 | |||
| 45 | let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1); | ||
| 46 | |||
| 47 | // Listen for an incoming message | ||
| 48 | debug!("source: wait for message from sink"); | ||
| 49 | let mut snk_to_src_buf = [0_u8; 30]; | ||
| 50 | let n = unwrap!(pd_phy.receive(snk_to_src_buf.as_mut()).await); | ||
| 51 | assert_eq!(n, SNK_TO_SRC.len()); | ||
| 52 | assert_eq!(&snk_to_src_buf[..n], SNK_TO_SRC.as_slice()); | ||
| 53 | |||
| 54 | // Send message | ||
| 55 | debug!("source: message received, sending message"); | ||
| 56 | unwrap!(pd_phy.transmit(SRC_TO_SNK.as_slice()).await); | ||
| 57 | |||
| 58 | // Wait for hard-reset | ||
| 59 | debug!("source: message sent, waiting for hard-reset"); | ||
| 60 | assert!(matches!( | ||
| 61 | pd_phy.receive(snk_to_src_buf.as_mut()).await, | ||
| 62 | Err(RxError::HardReset) | ||
| 63 | )); | ||
| 64 | } | ||
| 65 | |||
| 66 | async fn sink( | ||
| 67 | mut ucpd: Ucpd<'static, peripherals::UCPD2>, | ||
| 68 | rx_dma: peripherals::DMA1_CH3, | ||
| 69 | tx_dma: peripherals::DMA1_CH4, | ||
| 70 | ) { | ||
| 71 | debug!("sink: setting pull down"); | ||
| 72 | ucpd.cc_phy().set_pull(CcPull::Sink); | ||
| 73 | |||
| 74 | // Wait for default source. | ||
| 75 | debug!("sink: waiting for default vstate"); | ||
| 76 | wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await; | ||
| 77 | |||
| 78 | // Wait higher current pull-up. | ||
| 79 | //debug!("sink: source default vstate detected, waiting for 3.0A vstate"); | ||
| 80 | //wait_for_vstate(ucpd.cc_phy(), CcVState::HIGHEST).await; | ||
| 81 | //debug!("sink: source 3.0A vstate detected"); | ||
| 82 | // TODO: not working yet, why? no idea, replace with timer for now | ||
| 83 | Timer::after_millis(100).await; | ||
| 84 | |||
| 85 | let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1); | ||
| 86 | |||
| 87 | // Send message | ||
| 88 | debug!("sink: sending message"); | ||
| 89 | unwrap!(pd_phy.transmit(SNK_TO_SRC.as_slice()).await); | ||
| 90 | |||
| 91 | // Listen for an incoming message | ||
| 92 | debug!("sink: message sent, waiting for message from source"); | ||
| 93 | let mut src_to_snk_buf = [0_u8; 30]; | ||
| 94 | let n = unwrap!(pd_phy.receive(src_to_snk_buf.as_mut()).await); | ||
| 95 | assert_eq!(n, SRC_TO_SNK.len()); | ||
| 96 | assert_eq!(&src_to_snk_buf[..n], SRC_TO_SNK.as_slice()); | ||
| 97 | |||
| 98 | // Send hard reset | ||
| 99 | debug!("sink: message received, sending hard-reset"); | ||
| 100 | unwrap!(pd_phy.transmit_hardreset().await); | ||
| 101 | } | ||
| 102 | |||
| 103 | #[embassy_executor::main] | ||
| 104 | async fn main(_spawner: Spawner) { | ||
| 105 | let p = embassy_stm32::init(config()); | ||
| 106 | info!("Hello World!"); | ||
| 107 | |||
| 108 | // Wire between PD0 and PA8 | ||
| 109 | let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); | ||
| 110 | let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); | ||
| 111 | |||
| 112 | join( | ||
| 113 | source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), | ||
| 114 | sink(ucpd2, p.DMA1_CH3, p.DMA1_CH4), | ||
| 115 | ) | ||
| 116 | .await; | ||
| 117 | |||
| 118 | info!("Test OK"); | ||
| 119 | cortex_m::asm::bkpt(); | ||
| 120 | } | ||
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 3297ea7e2..0e555efc8 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -140,6 +140,7 @@ define_peris!( | |||
| 140 | ); | 140 | ); |
| 141 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] | 141 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] |
| 142 | define_peris!( | 142 | define_peris!( |
| 143 | CRYP_IN_DMA = DMA1_CH0, CRYP_OUT_DMA = DMA1_CH1, | ||
| 143 | UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, | 144 | UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, |
| 144 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, | 145 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, |
| 145 | ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, | 146 | ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, |
| @@ -250,13 +251,6 @@ define_peris!( | |||
| 250 | ); | 251 | ); |
| 251 | 252 | ||
| 252 | pub fn config() -> Config { | 253 | pub fn config() -> Config { |
| 253 | // Setting this bit is mandatory to use PG[15:2]. | ||
| 254 | #[cfg(feature = "stm32u5a5zj")] | ||
| 255 | embassy_stm32::pac::PWR.svmcr().modify(|w| { | ||
| 256 | w.set_io2sv(true); | ||
| 257 | w.set_io2vmen(true); | ||
| 258 | }); | ||
| 259 | |||
| 260 | #[allow(unused_mut)] | 254 | #[allow(unused_mut)] |
| 261 | let mut config = Config::default(); | 255 | let mut config = Config::default(); |
| 262 | 256 | ||
