diff options
| author | Gustav Toft <[email protected]> | 2024-04-04 15:52:44 +0200 |
|---|---|---|
| committer | Gustav Toft <[email protected]> | 2024-04-04 15:52:44 +0200 |
| commit | a373633d0dbc352de1b488bf15e383f8ef1d4a8c (patch) | |
| tree | a4590f26bd3252445e2adfa6d271a6f1cf74d54b | |
| parent | 0427c442ea531673e18da304c7402927589b8d0b (diff) | |
| parent | 067e422863674762c0ee20178f3671ce16a5986c (diff) | |
Merge branch 'main' of https://github.com/GustavToft/embassy
222 files changed, 5519 insertions, 4516 deletions
| @@ -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/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 6b5e6d009..c6b893de5 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc | |||
| @@ -208,3 +208,26 @@ Tools like `cargo size` and `cargo nm` can tell you the size of any globals or o | |||
| 208 | === For Max Stack Usage | 208 | === For Max Stack Usage |
| 209 | 209 | ||
| 210 | Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. See link:https://github.com/dirbaio/cargo-call-stack#known-limitations[the README] for more details. | 210 | Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. See link:https://github.com/dirbaio/cargo-call-stack#known-limitations[the README] for more details. |
| 211 | |||
| 212 | == The memory definition for my STM chip seems wrong, how do I define a `memory.x` file? | ||
| 213 | |||
| 214 | It could happen that your project compiles, flashes but fails to run. The following situation can be true for your setup: | ||
| 215 | |||
| 216 | The `memory.x` is generated automatically when enabling the `memory-x` feature on the `embassy-stm32` crate in the `Cargo.toml` file. | ||
| 217 | This, in turn, uses `stm32-metapac` to generate the `memory.x` file for you. Unfortunately, more often than not this memory definition is not correct. | ||
| 218 | |||
| 219 | You can override this by adding your own `memory.x` file. Such a file could look like this: | ||
| 220 | ``` | ||
| 221 | MEMORY | ||
| 222 | { | ||
| 223 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K | ||
| 224 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K | ||
| 225 | } | ||
| 226 | |||
| 227 | _stack_start = ORIGIN(RAM) + LENGTH(RAM); | ||
| 228 | ``` | ||
| 229 | |||
| 230 | Please refer to the STM32 documentation for the specific values suitable for your board and setup. The STM32 Cube examples often contain a linker script `.ld` file. | ||
| 231 | Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start. | ||
| 232 | |||
| 233 | If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise. | ||
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/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 1b08cb28e..627767c8a 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs | |||
| @@ -132,6 +132,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { | |||
| 132 | 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 { |
| 133 | Self { bus, config } | 133 | Self { bus, config } |
| 134 | } | 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 | } | ||
| 135 | } | 140 | } |
| 136 | 141 | ||
| 137 | impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> | 142 | impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> |
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 7092b3fab..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 | ||
| @@ -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 d3626610e..7c6312f6c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -70,7 +70,7 @@ rand_core = "0.6.3" | |||
| 70 | sdio-host = "0.5.0" | 70 | 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-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5" } | 73 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd" } |
| 74 | vcell = "0.1.3" | 74 | vcell = "0.1.3" |
| 75 | nb = "1.0.0" | 75 | nb = "1.0.0" |
| 76 | stm32-fmc = "0.3.0" | 76 | stm32-fmc = "0.3.0" |
| @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 94 | proc-macro2 = "1.0.36" | 94 | proc-macro2 = "1.0.36" |
| 95 | quote = "1.0.15" | 95 | quote = "1.0.15" |
| 96 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 96 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 97 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5", default-features = false, features = ["metadata"]} | 97 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd", default-features = false, features = ["metadata"]} |
| 98 | 98 | ||
| 99 | 99 | ||
| 100 | [features] | 100 | [features] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ee224da67..15bb8ea62 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -584,7 +584,7 @@ fn main() { | |||
| 584 | }; | 584 | }; |
| 585 | 585 | ||
| 586 | g.extend(quote! { | 586 | g.extend(quote! { |
| 587 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { | 587 | impl crate::rcc::SealedRccPeripheral for peripherals::#pname { |
| 588 | fn frequency() -> crate::time::Hertz { | 588 | fn frequency() -> crate::time::Hertz { |
| 589 | #clock_frequency | 589 | #clock_frequency |
| 590 | } | 590 | } |
| @@ -1486,7 +1486,7 @@ fn main() { | |||
| 1486 | #[crate::interrupt] | 1486 | #[crate::interrupt] |
| 1487 | unsafe fn #irq () { | 1487 | unsafe fn #irq () { |
| 1488 | #( | 1488 | #( |
| 1489 | <crate::peripherals::#channels as crate::dma::sealed::ChannelInterrupt>::on_irq(); | 1489 | <crate::peripherals::#channels as crate::dma::ChannelInterrupt>::on_irq(); |
| 1490 | )* | 1490 | )* |
| 1491 | } | 1491 | } |
| 1492 | } | 1492 | } |
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/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs deleted file mode 100644 index 33e702c6e..000000000 --- a/embassy-stm32/src/can/bx/mod.rs +++ /dev/null | |||
| @@ -1,971 +0,0 @@ | |||
| 1 | //! Driver for the STM32 bxCAN peripheral. | ||
| 2 | //! | ||
| 3 | //! This crate provides a reusable driver for the bxCAN peripheral found in many low- to middle-end | ||
| 4 | //! STM32 microcontrollers. HALs for compatible chips can reexport this crate and implement its | ||
| 5 | //! traits to easily expose a featureful CAN driver. | ||
| 6 | //! | ||
| 7 | //! # Features | ||
| 8 | //! | ||
| 9 | //! - Supports both single- and dual-peripheral configurations (where one bxCAN instance manages the | ||
| 10 | //! filters of a secondary instance). | ||
| 11 | //! - Handles standard and extended frames, and data and remote frames. | ||
| 12 | //! - Support for interrupts emitted by the bxCAN peripheral. | ||
| 13 | //! - Transmission respects CAN IDs and protects against priority inversion (a lower-priority frame | ||
| 14 | //! may be dequeued when enqueueing a higher-priority one). | ||
| 15 | //! - Implements the [`embedded-hal`] traits for interoperability. | ||
| 16 | //! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]). | ||
| 17 | //! | ||
| 18 | //! # Limitations | ||
| 19 | //! | ||
| 20 | //! - Support for querying error states and handling error interrupts is incomplete. | ||
| 21 | //! | ||
| 22 | |||
| 23 | // Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default | ||
| 24 | #![allow(clippy::unnecessary_operation)] // lint is bugged | ||
| 25 | |||
| 26 | //mod embedded_hal; | ||
| 27 | pub mod filter; | ||
| 28 | |||
| 29 | #[allow(clippy::all)] // generated code | ||
| 30 | use core::cmp::{Ord, Ordering}; | ||
| 31 | use core::convert::{Infallible, Into, TryInto}; | ||
| 32 | use core::marker::PhantomData; | ||
| 33 | use core::mem; | ||
| 34 | |||
| 35 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 36 | |||
| 37 | /// CAN Header: includes ID and length | ||
| 38 | pub type Header = crate::can::frame::Header; | ||
| 39 | |||
| 40 | /// Data for a CAN Frame | ||
| 41 | pub type Data = crate::can::frame::ClassicData; | ||
| 42 | |||
| 43 | /// CAN Frame | ||
| 44 | pub type Frame = crate::can::frame::ClassicFrame; | ||
| 45 | |||
| 46 | use crate::can::bx::filter::MasterFilters; | ||
| 47 | |||
| 48 | /// A bxCAN peripheral instance. | ||
| 49 | /// | ||
| 50 | /// This trait is meant to be implemented for a HAL-specific type that represent ownership of | ||
| 51 | /// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL). | ||
| 52 | /// | ||
| 53 | /// # Safety | ||
| 54 | /// | ||
| 55 | /// It is only safe to implement this trait, when: | ||
| 56 | /// | ||
| 57 | /// * The implementing type has ownership of the peripheral, preventing any other accesses to the | ||
| 58 | /// register block. | ||
| 59 | /// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as | ||
| 60 | /// long as ownership or a borrow of the implementing type is present. | ||
| 61 | pub unsafe trait Instance {} | ||
| 62 | |||
| 63 | /// A bxCAN instance that owns filter banks. | ||
| 64 | /// | ||
| 65 | /// In master-slave-instance setups, only the master instance owns the filter banks, and needs to | ||
| 66 | /// split some of them off for use by the slave instance. In that case, the master instance should | ||
| 67 | /// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement | ||
| 68 | /// [`Instance`]. | ||
| 69 | /// | ||
| 70 | /// In single-instance configurations, the instance owns all filter banks and they can not be split | ||
| 71 | /// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. | ||
| 72 | /// | ||
| 73 | /// # Safety | ||
| 74 | /// | ||
| 75 | /// This trait must only be implemented if the instance does, in fact, own its associated filter | ||
| 76 | /// banks, and `NUM_FILTER_BANKS` must be correct. | ||
| 77 | pub unsafe trait FilterOwner: Instance { | ||
| 78 | /// The total number of filter banks available to the instance. | ||
| 79 | /// | ||
| 80 | /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. | ||
| 81 | const NUM_FILTER_BANKS: u8; | ||
| 82 | } | ||
| 83 | |||
| 84 | /// A bxCAN master instance that shares filter banks with a slave instance. | ||
| 85 | /// | ||
| 86 | /// In master-slave-instance setups, this trait should be implemented for the master instance. | ||
| 87 | /// | ||
| 88 | /// # Safety | ||
| 89 | /// | ||
| 90 | /// This trait must only be implemented when there is actually an associated slave instance. | ||
| 91 | pub unsafe trait MasterInstance: FilterOwner {} | ||
| 92 | |||
| 93 | // TODO: what to do with these? | ||
| 94 | /* | ||
| 95 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Format)] | ||
| 96 | pub enum Error { | ||
| 97 | Stuff, | ||
| 98 | Form, | ||
| 99 | Acknowledgement, | ||
| 100 | BitRecessive, | ||
| 101 | BitDominant, | ||
| 102 | Crc, | ||
| 103 | Software, | ||
| 104 | }*/ | ||
| 105 | |||
| 106 | /// Error that indicates that an incoming message has been lost due to buffer overrun. | ||
| 107 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 108 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 109 | pub struct OverrunError { | ||
| 110 | _priv: (), | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Identifier of a CAN message. | ||
| 114 | /// | ||
| 115 | /// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a | ||
| 116 | /// extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 117 | /// | ||
| 118 | /// The `Ord` trait can be used to determine the frame’s priority this ID | ||
| 119 | /// belongs to. | ||
| 120 | /// Lower identifier values have a higher priority. Additionally standard frames | ||
| 121 | /// have a higher priority than extended frames and data frames have a higher | ||
| 122 | /// priority than remote frames. | ||
| 123 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 124 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 125 | pub(crate) struct IdReg(u32); | ||
| 126 | |||
| 127 | impl IdReg { | ||
| 128 | const STANDARD_SHIFT: u32 = 21; | ||
| 129 | |||
| 130 | const EXTENDED_SHIFT: u32 = 3; | ||
| 131 | |||
| 132 | const IDE_MASK: u32 = 0x0000_0004; | ||
| 133 | |||
| 134 | const RTR_MASK: u32 = 0x0000_0002; | ||
| 135 | |||
| 136 | /// Creates a new standard identifier (11bit, Range: 0..0x7FF) | ||
| 137 | /// | ||
| 138 | /// Panics for IDs outside the allowed range. | ||
| 139 | fn new_standard(id: StandardId) -> Self { | ||
| 140 | Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 144 | /// | ||
| 145 | /// Panics for IDs outside the allowed range. | ||
| 146 | fn new_extended(id: ExtendedId) -> IdReg { | ||
| 147 | Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) | ||
| 148 | } | ||
| 149 | |||
| 150 | fn from_register(reg: u32) -> IdReg { | ||
| 151 | Self(reg & 0xFFFF_FFFE) | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Returns the identifier. | ||
| 155 | fn to_id(self) -> Id { | ||
| 156 | if self.is_extended() { | ||
| 157 | Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) | ||
| 158 | } else { | ||
| 159 | Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Returns the identifier. | ||
| 164 | fn id(self) -> embedded_can::Id { | ||
| 165 | if self.is_extended() { | ||
| 166 | embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) | ||
| 167 | .unwrap() | ||
| 168 | .into() | ||
| 169 | } else { | ||
| 170 | embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) | ||
| 171 | .unwrap() | ||
| 172 | .into() | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Returns `true` if the identifier is an extended identifier. | ||
| 177 | fn is_extended(self) -> bool { | ||
| 178 | self.0 & Self::IDE_MASK != 0 | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Returns `true` if the identifer is part of a remote frame (RTR bit set). | ||
| 182 | fn rtr(self) -> bool { | ||
| 183 | self.0 & Self::RTR_MASK != 0 | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | impl From<&embedded_can::Id> for IdReg { | ||
| 188 | fn from(eid: &embedded_can::Id) -> Self { | ||
| 189 | match eid { | ||
| 190 | embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), | ||
| 191 | embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), | ||
| 192 | } | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | impl From<IdReg> for embedded_can::Id { | ||
| 197 | fn from(idr: IdReg) -> Self { | ||
| 198 | idr.id() | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | /// `IdReg` is ordered by priority. | ||
| 203 | impl Ord for IdReg { | ||
| 204 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 205 | // When the IDs match, data frames have priority over remote frames. | ||
| 206 | let rtr = self.rtr().cmp(&other.rtr()).reverse(); | ||
| 207 | |||
| 208 | let id_a = self.to_id(); | ||
| 209 | let id_b = other.to_id(); | ||
| 210 | match (id_a, id_b) { | ||
| 211 | (Id::Standard(a), Id::Standard(b)) => { | ||
| 212 | // Lower IDs have priority over higher IDs. | ||
| 213 | a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) | ||
| 214 | } | ||
| 215 | (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), | ||
| 216 | (Id::Standard(a), Id::Extended(b)) => { | ||
| 217 | // Standard frames have priority over extended frames if their Base IDs match. | ||
| 218 | a.as_raw() | ||
| 219 | .cmp(&b.standard_id().as_raw()) | ||
| 220 | .reverse() | ||
| 221 | .then(Ordering::Greater) | ||
| 222 | } | ||
| 223 | (Id::Extended(a), Id::Standard(b)) => { | ||
| 224 | a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | impl PartialOrd for IdReg { | ||
| 231 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 232 | Some(self.cmp(other)) | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Configuration proxy returned by [`Can::modify_config`]. | ||
| 237 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] | ||
| 238 | pub struct CanConfig<'a, I: Instance> { | ||
| 239 | can: &'a mut Can<I>, | ||
| 240 | } | ||
| 241 | |||
| 242 | impl<I: Instance> CanConfig<'_, I> { | ||
| 243 | /// Configures the bit timings. | ||
| 244 | /// | ||
| 245 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 246 | /// parameters as follows: | ||
| 247 | /// | ||
| 248 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 249 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 250 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 251 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 252 | /// | ||
| 253 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 254 | /// parameter to this method. | ||
| 255 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 256 | self.can.set_bit_timing(bt); | ||
| 257 | self | ||
| 258 | } | ||
| 259 | |||
| 260 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 261 | /// signals together. | ||
| 262 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 263 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 264 | self | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 268 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 269 | let mode = match enabled { | ||
| 270 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 271 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 272 | }; | ||
| 273 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 274 | self | ||
| 275 | } | ||
| 276 | |||
| 277 | /// Enables or disables automatic retransmission of messages. | ||
| 278 | /// | ||
| 279 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 280 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 281 | /// | ||
| 282 | /// Automatic retransmission is enabled by default. | ||
| 283 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 284 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 285 | self | ||
| 286 | } | ||
| 287 | |||
| 288 | /// Leaves initialization mode and enables the peripheral. | ||
| 289 | /// | ||
| 290 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 291 | /// on the bus. | ||
| 292 | /// | ||
| 293 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 294 | /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. | ||
| 295 | pub fn enable(mut self) { | ||
| 296 | self.leave_init_mode(); | ||
| 297 | |||
| 298 | match nb::block!(self.can.enable_non_blocking()) { | ||
| 299 | Ok(()) => {} | ||
| 300 | Err(void) => match void {}, | ||
| 301 | } | ||
| 302 | |||
| 303 | // Don't run the destructor. | ||
| 304 | mem::forget(self); | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Leaves initialization mode, but keeps the peripheral in sleep mode. | ||
| 308 | /// | ||
| 309 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 310 | /// [`Can::enable_non_blocking`]. | ||
| 311 | pub fn leave_disabled(mut self) { | ||
| 312 | self.leave_init_mode(); | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Leaves initialization mode, enters sleep mode. | ||
| 316 | fn leave_init_mode(&mut self) { | ||
| 317 | self.can.canregs.mcr().modify(|reg| { | ||
| 318 | reg.set_sleep(true); | ||
| 319 | reg.set_inrq(false); | ||
| 320 | }); | ||
| 321 | loop { | ||
| 322 | let msr = self.can.canregs.msr().read(); | ||
| 323 | if msr.slak() && !msr.inak() { | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | impl<I: Instance> Drop for CanConfig<'_, I> { | ||
| 331 | #[inline] | ||
| 332 | fn drop(&mut self) { | ||
| 333 | self.leave_init_mode(); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Builder returned by [`Can::builder`]. | ||
| 338 | #[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] | ||
| 339 | pub struct CanBuilder<I: Instance> { | ||
| 340 | can: Can<I>, | ||
| 341 | } | ||
| 342 | |||
| 343 | impl<I: Instance> CanBuilder<I> { | ||
| 344 | /// Configures the bit timings. | ||
| 345 | /// | ||
| 346 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 347 | /// parameters as follows: | ||
| 348 | /// | ||
| 349 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 350 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 351 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 352 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 353 | /// | ||
| 354 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 355 | /// parameter to this method. | ||
| 356 | pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 357 | self.can.set_bit_timing(bt); | ||
| 358 | self | ||
| 359 | } | ||
| 360 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 361 | /// signals together. | ||
| 362 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 363 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 364 | self | ||
| 365 | } | ||
| 366 | |||
| 367 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 368 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 369 | let mode = match enabled { | ||
| 370 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 371 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 372 | }; | ||
| 373 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 374 | self | ||
| 375 | } | ||
| 376 | |||
| 377 | /// Enables or disables automatic retransmission of messages. | ||
| 378 | /// | ||
| 379 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 380 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 381 | /// | ||
| 382 | /// Automatic retransmission is enabled by default. | ||
| 383 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 384 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 385 | self | ||
| 386 | } | ||
| 387 | |||
| 388 | /// Leaves initialization mode and enables the peripheral. | ||
| 389 | /// | ||
| 390 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 391 | /// on the bus. | ||
| 392 | /// | ||
| 393 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 394 | /// [`CanBuilder::leave_disabled`] instead. | ||
| 395 | pub fn enable(mut self) -> Can<I> { | ||
| 396 | self.leave_init_mode(); | ||
| 397 | |||
| 398 | match nb::block!(self.can.enable_non_blocking()) { | ||
| 399 | Ok(()) => self.can, | ||
| 400 | Err(void) => match void {}, | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /// Returns the [`Can`] interface without enabling it. | ||
| 405 | /// | ||
| 406 | /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling | ||
| 407 | /// it. | ||
| 408 | /// | ||
| 409 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 410 | /// [`Can::enable_non_blocking`]. | ||
| 411 | pub fn leave_disabled(mut self) -> Can<I> { | ||
| 412 | self.leave_init_mode(); | ||
| 413 | self.can | ||
| 414 | } | ||
| 415 | |||
| 416 | /// Leaves initialization mode, enters sleep mode. | ||
| 417 | fn leave_init_mode(&mut self) { | ||
| 418 | self.can.canregs.mcr().modify(|reg| { | ||
| 419 | reg.set_sleep(true); | ||
| 420 | reg.set_inrq(false); | ||
| 421 | }); | ||
| 422 | loop { | ||
| 423 | let msr = self.can.canregs.msr().read(); | ||
| 424 | if msr.slak() && !msr.inak() { | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Interface to a bxCAN peripheral. | ||
| 432 | pub struct Can<I: Instance> { | ||
| 433 | instance: I, | ||
| 434 | canregs: crate::pac::can::Can, | ||
| 435 | } | ||
| 436 | |||
| 437 | impl<I> Can<I> | ||
| 438 | where | ||
| 439 | I: Instance, | ||
| 440 | { | ||
| 441 | /// Creates a [`CanBuilder`] for constructing a CAN interface. | ||
| 442 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { | ||
| 443 | let can_builder = CanBuilder { | ||
| 444 | can: Can { instance, canregs }, | ||
| 445 | }; | ||
| 446 | |||
| 447 | canregs.mcr().modify(|reg| { | ||
| 448 | reg.set_sleep(false); | ||
| 449 | reg.set_inrq(true); | ||
| 450 | }); | ||
| 451 | loop { | ||
| 452 | let msr = canregs.msr().read(); | ||
| 453 | if !msr.slak() && msr.inak() { | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | can_builder | ||
| 459 | } | ||
| 460 | |||
| 461 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 462 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 463 | let seg1 = u8::from(bt.seg1); | ||
| 464 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 465 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 466 | self.canregs.btr().modify(|reg| { | ||
| 467 | reg.set_brp(prescaler - 1); | ||
| 468 | reg.set_ts(0, seg1 - 1); | ||
| 469 | reg.set_ts(1, seg2 - 1); | ||
| 470 | reg.set_sjw(sync_jump_width - 1); | ||
| 471 | }); | ||
| 472 | } | ||
| 473 | |||
| 474 | /// Returns a reference to the peripheral instance. | ||
| 475 | /// | ||
| 476 | /// This allows accessing HAL-specific data stored in the instance type. | ||
| 477 | pub fn instance(&mut self) -> &mut I { | ||
| 478 | &mut self.instance | ||
| 479 | } | ||
| 480 | |||
| 481 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | ||
| 482 | /// | ||
| 483 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | ||
| 484 | /// enter sleep mode. | ||
| 485 | pub fn free(self) -> I { | ||
| 486 | self.canregs.mcr().write(|reg| reg.set_reset(true)); | ||
| 487 | self.instance | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Configure bit timings and silent/loop-back mode. | ||
| 491 | /// | ||
| 492 | /// Calling this method will enter initialization mode. | ||
| 493 | pub fn modify_config(&mut self) -> CanConfig<'_, I> { | ||
| 494 | self.canregs.mcr().modify(|reg| { | ||
| 495 | reg.set_sleep(false); | ||
| 496 | reg.set_inrq(true); | ||
| 497 | }); | ||
| 498 | loop { | ||
| 499 | let msr = self.canregs.msr().read(); | ||
| 500 | if !msr.slak() && msr.inak() { | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | CanConfig { can: self } | ||
| 506 | } | ||
| 507 | |||
| 508 | /// Configures the automatic wake-up feature. | ||
| 509 | /// | ||
| 510 | /// This is turned off by default. | ||
| 511 | /// | ||
| 512 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 513 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 514 | /// frame. | ||
| 515 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 516 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 517 | } | ||
| 518 | |||
| 519 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 520 | /// | ||
| 521 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 522 | /// if you want non-blocking initialization. | ||
| 523 | /// | ||
| 524 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 525 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 526 | /// successfully. | ||
| 527 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 528 | let msr = self.canregs.msr().read(); | ||
| 529 | if msr.slak() { | ||
| 530 | self.canregs.mcr().modify(|reg| { | ||
| 531 | reg.set_abom(true); | ||
| 532 | reg.set_sleep(false); | ||
| 533 | }); | ||
| 534 | Err(nb::Error::WouldBlock) | ||
| 535 | } else { | ||
| 536 | Ok(()) | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | /// Puts the peripheral in a sleep mode to save power. | ||
| 541 | /// | ||
| 542 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 543 | pub fn sleep(&mut self) { | ||
| 544 | self.canregs.mcr().modify(|reg| { | ||
| 545 | reg.set_sleep(true); | ||
| 546 | reg.set_inrq(false); | ||
| 547 | }); | ||
| 548 | loop { | ||
| 549 | let msr = self.canregs.msr().read(); | ||
| 550 | if msr.slak() && !msr.inak() { | ||
| 551 | break; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | /// Wakes up from sleep mode. | ||
| 557 | /// | ||
| 558 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 559 | /// frame will cause that interrupt. | ||
| 560 | pub fn wakeup(&mut self) { | ||
| 561 | self.canregs.mcr().modify(|reg| { | ||
| 562 | reg.set_sleep(false); | ||
| 563 | reg.set_inrq(false); | ||
| 564 | }); | ||
| 565 | loop { | ||
| 566 | let msr = self.canregs.msr().read(); | ||
| 567 | if !msr.slak() && !msr.inak() { | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. | ||
| 574 | /// | ||
| 575 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 576 | /// Transmit order is preserved for frames with identical priority. | ||
| 577 | /// | ||
| 578 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 579 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 580 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 581 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 582 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 583 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 584 | unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) } | ||
| 585 | } | ||
| 586 | |||
| 587 | /// Returns `true` if no frame is pending for transmission. | ||
| 588 | pub fn is_transmitter_idle(&self) -> bool { | ||
| 589 | // Safety: Read-only operation. | ||
| 590 | unsafe { Tx::<I>::conjure(self.canregs).is_idle() } | ||
| 591 | } | ||
| 592 | |||
| 593 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 594 | /// | ||
| 595 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 596 | /// aborted, this function has no effect and returns `false`. | ||
| 597 | /// | ||
| 598 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 599 | /// returns `true`. | ||
| 600 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 601 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 602 | unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) } | ||
| 603 | } | ||
| 604 | |||
| 605 | /// Returns a received frame if available. | ||
| 606 | /// | ||
| 607 | /// This will first check FIFO 0 for a message or error. If none are available, FIFO 1 is | ||
| 608 | /// checked. | ||
| 609 | /// | ||
| 610 | /// Returns `Err` when a frame was lost due to buffer overrun. | ||
| 611 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | ||
| 612 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 613 | let mut rx0 = unsafe { Rx0::<I>::conjure(self.canregs) }; | ||
| 614 | let mut rx1 = unsafe { Rx1::<I>::conjure(self.canregs) }; | ||
| 615 | |||
| 616 | match rx0.receive() { | ||
| 617 | Err(nb::Error::WouldBlock) => rx1.receive(), | ||
| 618 | result => result, | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | /// Returns a reference to the RX FIFO 0. | ||
| 623 | pub fn rx0(&mut self) -> Rx0<I> { | ||
| 624 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 625 | unsafe { Rx0::conjure(self.canregs) } | ||
| 626 | } | ||
| 627 | |||
| 628 | /// Returns a reference to the RX FIFO 1. | ||
| 629 | pub fn rx1(&mut self) -> Rx1<I> { | ||
| 630 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 631 | unsafe { Rx1::conjure(self.canregs) } | ||
| 632 | } | ||
| 633 | |||
| 634 | pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx0<I>, Rx1<I>) { | ||
| 635 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 636 | let tx = unsafe { Tx::conjure(self.canregs) }; | ||
| 637 | let rx0 = unsafe { Rx0::conjure(self.canregs) }; | ||
| 638 | let rx1 = unsafe { Rx1::conjure(self.canregs) }; | ||
| 639 | (tx, rx0, rx1) | ||
| 640 | } | ||
| 641 | |||
| 642 | /// Consumes this `Can` instance and splits it into transmitting and receiving halves. | ||
| 643 | pub fn split(self) -> (Tx<I>, Rx0<I>, Rx1<I>) { | ||
| 644 | // Safety: `Self` is not `Copy` and is destroyed by moving it into this method. | ||
| 645 | unsafe { | ||
| 646 | ( | ||
| 647 | Tx::conjure(self.canregs), | ||
| 648 | Rx0::conjure(self.canregs), | ||
| 649 | Rx1::conjure(self.canregs), | ||
| 650 | ) | ||
| 651 | } | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | impl<I: FilterOwner> Can<I> { | ||
| 656 | /// Accesses the filter banks owned by this CAN peripheral. | ||
| 657 | /// | ||
| 658 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | ||
| 659 | /// peripheral instead. | ||
| 660 | pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { | ||
| 661 | unsafe { MasterFilters::new(self.canregs) } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | /// Interface to the CAN transmitter part. | ||
| 666 | pub struct Tx<I> { | ||
| 667 | _can: PhantomData<I>, | ||
| 668 | canregs: crate::pac::can::Can, | ||
| 669 | } | ||
| 670 | |||
| 671 | impl<I> Tx<I> | ||
| 672 | where | ||
| 673 | I: Instance, | ||
| 674 | { | ||
| 675 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | ||
| 676 | Self { | ||
| 677 | _can: PhantomData, | ||
| 678 | canregs, | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 682 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 683 | /// | ||
| 684 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 685 | /// Transmit order is preserved for frames with identical priority. | ||
| 686 | /// | ||
| 687 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 688 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 689 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 690 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 691 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 692 | // Get the index of the next free mailbox or the one with the lowest priority. | ||
| 693 | let tsr = self.canregs.tsr().read(); | ||
| 694 | let idx = tsr.code() as usize; | ||
| 695 | |||
| 696 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 697 | let pending_frame = if frame_is_pending { | ||
| 698 | // High priority frames are transmitted first by the mailbox system. | ||
| 699 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 700 | // The controller schedules pending frames of same priority based on the | ||
| 701 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 702 | // and only accept higher priority frames. | ||
| 703 | self.check_priority(0, frame.id().into())?; | ||
| 704 | self.check_priority(1, frame.id().into())?; | ||
| 705 | self.check_priority(2, frame.id().into())?; | ||
| 706 | |||
| 707 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 708 | if all_frames_are_pending { | ||
| 709 | // No free mailbox is available. This can only happen when three frames with | ||
| 710 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 711 | // of them are blocked by bus traffic with even higher priority. | ||
| 712 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 713 | self.read_pending_mailbox(idx) | ||
| 714 | } else { | ||
| 715 | // There was a free mailbox. | ||
| 716 | None | ||
| 717 | } | ||
| 718 | } else { | ||
| 719 | // All mailboxes are available: Send frame without performing any checks. | ||
| 720 | None | ||
| 721 | }; | ||
| 722 | |||
| 723 | self.write_mailbox(idx, frame); | ||
| 724 | |||
| 725 | let mailbox = match idx { | ||
| 726 | 0 => Mailbox::Mailbox0, | ||
| 727 | 1 => Mailbox::Mailbox1, | ||
| 728 | 2 => Mailbox::Mailbox2, | ||
| 729 | _ => unreachable!(), | ||
| 730 | }; | ||
| 731 | Ok(TransmitStatus { | ||
| 732 | dequeued_frame: pending_frame, | ||
| 733 | mailbox, | ||
| 734 | }) | ||
| 735 | } | ||
| 736 | |||
| 737 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 738 | /// lower priority (higher ID) than the identifier `id`. | ||
| 739 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 740 | // Read the pending frame's id to check its priority. | ||
| 741 | assert!(idx < 3); | ||
| 742 | let tir = &self.canregs.tx(idx).tir().read(); | ||
| 743 | //let tir = &can.tx[idx].tir.read(); | ||
| 744 | |||
| 745 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 746 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 747 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 748 | // There's a mailbox whose priority is higher or equal | ||
| 749 | // the priority of the new frame. | ||
| 750 | return Err(nb::Error::WouldBlock); | ||
| 751 | } | ||
| 752 | |||
| 753 | Ok(()) | ||
| 754 | } | ||
| 755 | |||
| 756 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 757 | debug_assert!(idx < 3); | ||
| 758 | |||
| 759 | let mb = self.canregs.tx(idx); | ||
| 760 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 761 | |||
| 762 | mb.tdlr() | ||
| 763 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 764 | mb.tdhr() | ||
| 765 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 766 | let id: IdReg = frame.id().into(); | ||
| 767 | mb.tir().write(|w| { | ||
| 768 | w.0 = id.0; | ||
| 769 | w.set_txrq(true); | ||
| 770 | }); | ||
| 771 | } | ||
| 772 | |||
| 773 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 774 | if self.abort_by_index(idx) { | ||
| 775 | debug_assert!(idx < 3); | ||
| 776 | |||
| 777 | let mb = self.canregs.tx(idx); | ||
| 778 | |||
| 779 | let id = IdReg(mb.tir().read().0).id(); | ||
| 780 | let mut data = [0xff; 8]; | ||
| 781 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 782 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 783 | let len = mb.tdtr().read().dlc(); | ||
| 784 | |||
| 785 | Some(Frame::new(Header::new(id, len, false), &data).unwrap()) | ||
| 786 | } else { | ||
| 787 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 788 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 789 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 790 | // has preempted the execution. | ||
| 791 | None | ||
| 792 | } | ||
| 793 | } | ||
| 794 | |||
| 795 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 796 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 797 | self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 798 | |||
| 799 | // Wait for the abort request to be finished. | ||
| 800 | loop { | ||
| 801 | let tsr = self.canregs.tsr().read(); | ||
| 802 | if false == tsr.abrq(idx) { | ||
| 803 | break tsr.txok(idx) == false; | ||
| 804 | } | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 809 | /// | ||
| 810 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 811 | /// aborted, this function has no effect and returns `false`. | ||
| 812 | /// | ||
| 813 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 814 | /// returns `true`. | ||
| 815 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 816 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | ||
| 817 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 818 | let tsr = self.canregs.tsr().read(); | ||
| 819 | let mailbox_empty = match mailbox { | ||
| 820 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 821 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 822 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 823 | }; | ||
| 824 | if mailbox_empty { | ||
| 825 | false | ||
| 826 | } else { | ||
| 827 | self.abort_by_index(mailbox as usize) | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | /// Returns `true` if no frame is pending for transmission. | ||
| 832 | pub fn is_idle(&self) -> bool { | ||
| 833 | let tsr = self.canregs.tsr().read(); | ||
| 834 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 835 | } | ||
| 836 | |||
| 837 | /// Clears the request complete flag for all mailboxes. | ||
| 838 | pub fn clear_interrupt_flags(&mut self) { | ||
| 839 | self.canregs.tsr().write(|reg| { | ||
| 840 | reg.set_rqcp(0, true); | ||
| 841 | reg.set_rqcp(1, true); | ||
| 842 | reg.set_rqcp(2, true); | ||
| 843 | }); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 847 | /// Interface to receiver FIFO 0. | ||
| 848 | pub struct Rx0<I> { | ||
| 849 | _can: PhantomData<I>, | ||
| 850 | canregs: crate::pac::can::Can, | ||
| 851 | } | ||
| 852 | |||
| 853 | impl<I> Rx0<I> | ||
| 854 | where | ||
| 855 | I: Instance, | ||
| 856 | { | ||
| 857 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | ||
| 858 | Self { | ||
| 859 | _can: PhantomData, | ||
| 860 | canregs, | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 864 | /// Returns a received frame if available. | ||
| 865 | /// | ||
| 866 | /// Returns `Err` when a frame was lost due to buffer overrun. | ||
| 867 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | ||
| 868 | receive_fifo(self.canregs, 0) | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 872 | /// Interface to receiver FIFO 1. | ||
| 873 | pub struct Rx1<I> { | ||
| 874 | _can: PhantomData<I>, | ||
| 875 | canregs: crate::pac::can::Can, | ||
| 876 | } | ||
| 877 | |||
| 878 | impl<I> Rx1<I> | ||
| 879 | where | ||
| 880 | I: Instance, | ||
| 881 | { | ||
| 882 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | ||
| 883 | Self { | ||
| 884 | _can: PhantomData, | ||
| 885 | canregs, | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | /// Returns a received frame if available. | ||
| 890 | /// | ||
| 891 | /// Returns `Err` when a frame was lost due to buffer overrun. | ||
| 892 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | ||
| 893 | receive_fifo(self.canregs, 1) | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 897 | fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Frame, OverrunError> { | ||
| 898 | assert!(fifo_nr < 2); | ||
| 899 | let rfr = canregs.rfr(fifo_nr); | ||
| 900 | let rx = canregs.rx(fifo_nr); | ||
| 901 | |||
| 902 | //let rfr = &can.rfr[fifo_nr]; | ||
| 903 | //let rx = &can.rx[fifo_nr]; | ||
| 904 | |||
| 905 | // Check if a frame is available in the mailbox. | ||
| 906 | let rfr_read = rfr.read(); | ||
| 907 | if rfr_read.fmp() == 0 { | ||
| 908 | return Err(nb::Error::WouldBlock); | ||
| 909 | } | ||
| 910 | |||
| 911 | // Check for RX FIFO overrun. | ||
| 912 | if rfr_read.fovr() { | ||
| 913 | rfr.write(|w| w.set_fovr(true)); | ||
| 914 | return Err(nb::Error::Other(OverrunError { _priv: () })); | ||
| 915 | } | ||
| 916 | |||
| 917 | // Read the frame. | ||
| 918 | let id = IdReg(rx.rir().read().0).id(); | ||
| 919 | let mut data = [0xff; 8]; | ||
| 920 | data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); | ||
| 921 | data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes()); | ||
| 922 | let len = rx.rdtr().read().dlc(); | ||
| 923 | |||
| 924 | // Release the mailbox. | ||
| 925 | rfr.write(|w| w.set_rfom(true)); | ||
| 926 | |||
| 927 | Ok(Frame::new(Header::new(id, len, false), &data).unwrap()) | ||
| 928 | } | ||
| 929 | |||
| 930 | /// Identifies one of the two receive FIFOs. | ||
| 931 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
| 932 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 933 | pub enum Fifo { | ||
| 934 | /// First receive FIFO | ||
| 935 | Fifo0 = 0, | ||
| 936 | /// Second receive FIFO | ||
| 937 | Fifo1 = 1, | ||
| 938 | } | ||
| 939 | |||
| 940 | /// Identifies one of the three transmit mailboxes. | ||
| 941 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] | ||
| 942 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 943 | pub enum Mailbox { | ||
| 944 | /// Transmit mailbox 0 | ||
| 945 | Mailbox0 = 0, | ||
| 946 | /// Transmit mailbox 1 | ||
| 947 | Mailbox1 = 1, | ||
| 948 | /// Transmit mailbox 2 | ||
| 949 | Mailbox2 = 2, | ||
| 950 | } | ||
| 951 | |||
| 952 | /// Contains information about a frame enqueued for transmission via [`Can::transmit`] or | ||
| 953 | /// [`Tx::transmit`]. | ||
| 954 | pub struct TransmitStatus { | ||
| 955 | dequeued_frame: Option<Frame>, | ||
| 956 | mailbox: Mailbox, | ||
| 957 | } | ||
| 958 | |||
| 959 | impl TransmitStatus { | ||
| 960 | /// Returns the lower-priority frame that was dequeued to make space for the new frame. | ||
| 961 | #[inline] | ||
| 962 | pub fn dequeued_frame(&self) -> Option<&Frame> { | ||
| 963 | self.dequeued_frame.as_ref() | ||
| 964 | } | ||
| 965 | |||
| 966 | /// Returns the [`Mailbox`] the frame was enqueued in. | ||
| 967 | #[inline] | ||
| 968 | pub fn mailbox(&self) -> Mailbox { | ||
| 969 | self.mailbox | ||
| 970 | } | ||
| 971 | } | ||
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs deleted file mode 100644 index bb7cc3d7f..000000000 --- a/embassy-stm32/src/can/bxcan.rs +++ /dev/null | |||
| @@ -1,627 +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 mod bx; | ||
| 8 | |||
| 9 | pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId}; | ||
| 10 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 11 | use futures::FutureExt; | ||
| 12 | |||
| 13 | use crate::gpio::sealed::AFType; | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | ||
| 15 | use crate::pac::can::vals::{Ide, Lec}; | ||
| 16 | use crate::rcc::RccPeripheral; | ||
| 17 | use crate::{interrupt, peripherals, Peripheral}; | ||
| 18 | |||
| 19 | pub mod enums; | ||
| 20 | use enums::*; | ||
| 21 | pub mod frame; | ||
| 22 | pub mod util; | ||
| 23 | |||
| 24 | /// Contains CAN frame and additional metadata. | ||
| 25 | /// | ||
| 26 | /// Timestamp is available if `time` feature is enabled. | ||
| 27 | #[derive(Debug, Clone)] | ||
| 28 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 29 | pub struct Envelope { | ||
| 30 | /// Reception time. | ||
| 31 | #[cfg(feature = "time")] | ||
| 32 | pub ts: embassy_time::Instant, | ||
| 33 | /// The actual CAN frame. | ||
| 34 | pub frame: Frame, | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Interrupt handler. | ||
| 38 | pub struct TxInterruptHandler<T: Instance> { | ||
| 39 | _phantom: PhantomData<T>, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> { | ||
| 43 | unsafe fn on_interrupt() { | ||
| 44 | T::regs().tsr().write(|v| { | ||
| 45 | v.set_rqcp(0, true); | ||
| 46 | v.set_rqcp(1, true); | ||
| 47 | v.set_rqcp(2, true); | ||
| 48 | }); | ||
| 49 | |||
| 50 | T::state().tx_waker.wake(); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | /// RX0 interrupt handler. | ||
| 55 | pub struct Rx0InterruptHandler<T: Instance> { | ||
| 56 | _phantom: PhantomData<T>, | ||
| 57 | } | ||
| 58 | |||
| 59 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | ||
| 60 | unsafe fn on_interrupt() { | ||
| 61 | // info!("rx0 irq"); | ||
| 62 | Can::<T>::receive_fifo(RxFifo::Fifo0); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | /// RX1 interrupt handler. | ||
| 67 | pub struct Rx1InterruptHandler<T: Instance> { | ||
| 68 | _phantom: PhantomData<T>, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | ||
| 72 | unsafe fn on_interrupt() { | ||
| 73 | // info!("rx1 irq"); | ||
| 74 | Can::<T>::receive_fifo(RxFifo::Fifo1); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// SCE interrupt handler. | ||
| 79 | pub struct SceInterruptHandler<T: Instance> { | ||
| 80 | _phantom: PhantomData<T>, | ||
| 81 | } | ||
| 82 | |||
| 83 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | ||
| 84 | unsafe fn on_interrupt() { | ||
| 85 | // info!("sce irq"); | ||
| 86 | let msr = T::regs().msr(); | ||
| 87 | let msr_val = msr.read(); | ||
| 88 | |||
| 89 | if msr_val.erri() { | ||
| 90 | msr.modify(|v| v.set_erri(true)); | ||
| 91 | T::state().err_waker.wake(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /// CAN driver | ||
| 97 | pub struct Can<'d, T: Instance> { | ||
| 98 | can: crate::can::bx::Can<BxcanInstance<'d, T>>, | ||
| 99 | } | ||
| 100 | |||
| 101 | /// Error returned by `try_read` | ||
| 102 | #[derive(Debug)] | ||
| 103 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 104 | pub enum TryReadError { | ||
| 105 | /// Bus error | ||
| 106 | BusError(BusError), | ||
| 107 | /// Receive buffer is empty | ||
| 108 | Empty, | ||
| 109 | } | ||
| 110 | |||
| 111 | /// Error returned by `try_write` | ||
| 112 | #[derive(Debug)] | ||
| 113 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 114 | pub enum TryWriteError { | ||
| 115 | /// All transmit mailboxes are full | ||
| 116 | Full, | ||
| 117 | } | ||
| 118 | |||
| 119 | impl<'d, T: Instance> Can<'d, T> { | ||
| 120 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | ||
| 121 | /// You must call [Can::enable_non_blocking] to use the peripheral. | ||
| 122 | pub fn new( | ||
| 123 | peri: impl Peripheral<P = T> + 'd, | ||
| 124 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 125 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 126 | _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> | ||
| 127 | + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> | ||
| 128 | + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> | ||
| 129 | + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> | ||
| 130 | + 'd, | ||
| 131 | ) -> Self { | ||
| 132 | into_ref!(peri, rx, tx); | ||
| 133 | |||
| 134 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 135 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 136 | |||
| 137 | T::enable_and_reset(); | ||
| 138 | |||
| 139 | { | ||
| 140 | T::regs().ier().write(|w| { | ||
| 141 | w.set_errie(true); | ||
| 142 | w.set_fmpie(0, true); | ||
| 143 | w.set_fmpie(1, true); | ||
| 144 | w.set_tmeie(true); | ||
| 145 | }); | ||
| 146 | |||
| 147 | T::regs().mcr().write(|w| { | ||
| 148 | // Enable timestamps on rx messages | ||
| 149 | |||
| 150 | w.set_ttcm(true); | ||
| 151 | }); | ||
| 152 | } | ||
| 153 | |||
| 154 | unsafe { | ||
| 155 | T::TXInterrupt::unpend(); | ||
| 156 | T::TXInterrupt::enable(); | ||
| 157 | |||
| 158 | T::RX0Interrupt::unpend(); | ||
| 159 | T::RX0Interrupt::enable(); | ||
| 160 | |||
| 161 | T::RX1Interrupt::unpend(); | ||
| 162 | T::RX1Interrupt::enable(); | ||
| 163 | |||
| 164 | T::SCEInterrupt::unpend(); | ||
| 165 | T::SCEInterrupt::enable(); | ||
| 166 | } | ||
| 167 | |||
| 168 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 169 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 170 | |||
| 171 | let can = crate::can::bx::Can::builder(BxcanInstance(peri), T::regs()).leave_disabled(); | ||
| 172 | Self { can } | ||
| 173 | } | ||
| 174 | |||
| 175 | /// Set CAN bit rate. | ||
| 176 | pub fn set_bitrate(&mut self, bitrate: u32) { | ||
| 177 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 178 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Enables the peripheral and synchronizes with the bus. | ||
| 182 | /// | ||
| 183 | /// This will wait for 11 consecutive recessive bits (bus idle state). | ||
| 184 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | ||
| 185 | pub async fn enable(&mut self) { | ||
| 186 | while self.enable_non_blocking().is_err() { | ||
| 187 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | ||
| 188 | // Yield to allow other tasks to execute while can bus is initializing. | ||
| 189 | embassy_futures::yield_now().await; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Queues the message to be sent. | ||
| 194 | /// | ||
| 195 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 196 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | ||
| 197 | self.split().0.write(frame).await | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Attempts to transmit a frame without blocking. | ||
| 201 | /// | ||
| 202 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 203 | pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> { | ||
| 204 | self.split().0.try_write(frame) | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Waits for a specific transmit mailbox to become empty | ||
| 208 | pub async fn flush(&self, mb: crate::can::bx::Mailbox) { | ||
| 209 | CanTx::<T>::flush_inner(mb).await | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Waits until any of the transmit mailboxes become empty | ||
| 213 | pub async fn flush_any(&self) { | ||
| 214 | CanTx::<T>::flush_any_inner().await | ||
| 215 | } | ||
| 216 | |||
| 217 | /// Waits until all of the transmit mailboxes become empty | ||
| 218 | pub async fn flush_all(&self) { | ||
| 219 | CanTx::<T>::flush_all_inner().await | ||
| 220 | } | ||
| 221 | |||
| 222 | /// Read a CAN frame. | ||
| 223 | /// | ||
| 224 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 225 | /// | ||
| 226 | /// Returns a tuple of the time the message was received and the message frame | ||
| 227 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 228 | self.split().1.read().await | ||
| 229 | } | ||
| 230 | |||
| 231 | /// Attempts to read a CAN frame without blocking. | ||
| 232 | /// | ||
| 233 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 234 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 235 | self.split().1.try_read() | ||
| 236 | } | ||
| 237 | |||
| 238 | /// Waits while receive queue is empty. | ||
| 239 | pub async fn wait_not_empty(&mut self) { | ||
| 240 | self.split().1.wait_not_empty().await | ||
| 241 | } | ||
| 242 | |||
| 243 | unsafe fn receive_fifo(fifo: RxFifo) { | ||
| 244 | // Generate timestamp as early as possible | ||
| 245 | #[cfg(feature = "time")] | ||
| 246 | let ts = embassy_time::Instant::now(); | ||
| 247 | |||
| 248 | let state = T::state(); | ||
| 249 | let regs = T::regs(); | ||
| 250 | let fifo_idx = match fifo { | ||
| 251 | RxFifo::Fifo0 => 0usize, | ||
| 252 | RxFifo::Fifo1 => 1usize, | ||
| 253 | }; | ||
| 254 | let rfr = regs.rfr(fifo_idx); | ||
| 255 | let fifo = regs.rx(fifo_idx); | ||
| 256 | |||
| 257 | loop { | ||
| 258 | // If there are no pending messages, there is nothing to do | ||
| 259 | if rfr.read().fmp() == 0 { | ||
| 260 | return; | ||
| 261 | } | ||
| 262 | |||
| 263 | let rir = fifo.rir().read(); | ||
| 264 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 265 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 266 | } else { | ||
| 267 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 268 | let exid = rir.exid() & 0x3FFFF; | ||
| 269 | let id = (stid << 18) | (exid); | ||
| 270 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 271 | }; | ||
| 272 | let data_len = fifo.rdtr().read().dlc(); | ||
| 273 | let mut data: [u8; 8] = [0; 8]; | ||
| 274 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 275 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 276 | |||
| 277 | let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); | ||
| 278 | let envelope = Envelope { | ||
| 279 | #[cfg(feature = "time")] | ||
| 280 | ts, | ||
| 281 | frame, | ||
| 282 | }; | ||
| 283 | |||
| 284 | rfr.modify(|v| v.set_rfom(true)); | ||
| 285 | |||
| 286 | /* | ||
| 287 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 288 | */ | ||
| 289 | let _ = state.rx_queue.try_send(envelope); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /// Split the CAN driver into transmit and receive halves. | ||
| 294 | /// | ||
| 295 | /// Useful for doing separate transmit/receive tasks. | ||
| 296 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { | ||
| 297 | let (tx, rx0, rx1) = self.can.split_by_ref(); | ||
| 298 | (CanTx { tx }, CanRx { rx0, rx1 }) | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | impl<'d, T: Instance> AsMut<crate::can::bx::Can<BxcanInstance<'d, T>>> for Can<'d, T> { | ||
| 303 | /// Get mutable access to the lower-level driver from the `bxcan` crate. | ||
| 304 | fn as_mut(&mut self) -> &mut crate::can::bx::Can<BxcanInstance<'d, T>> { | ||
| 305 | &mut self.can | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | /// CAN driver, transmit half. | ||
| 310 | pub struct CanTx<'d, T: Instance> { | ||
| 311 | tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | ||
| 312 | } | ||
| 313 | |||
| 314 | impl<'d, T: Instance> CanTx<'d, T> { | ||
| 315 | /// Queues the message to be sent. | ||
| 316 | /// | ||
| 317 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 318 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | ||
| 319 | poll_fn(|cx| { | ||
| 320 | T::state().tx_waker.register(cx.waker()); | ||
| 321 | if let Ok(status) = self.tx.transmit(frame) { | ||
| 322 | return Poll::Ready(status); | ||
| 323 | } | ||
| 324 | |||
| 325 | Poll::Pending | ||
| 326 | }) | ||
| 327 | .await | ||
| 328 | } | ||
| 329 | |||
| 330 | /// Attempts to transmit a frame without blocking. | ||
| 331 | /// | ||
| 332 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 333 | pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> { | ||
| 334 | self.tx.transmit(frame).map_err(|_| TryWriteError::Full) | ||
| 335 | } | ||
| 336 | |||
| 337 | async fn flush_inner(mb: crate::can::bx::Mailbox) { | ||
| 338 | poll_fn(|cx| { | ||
| 339 | T::state().tx_waker.register(cx.waker()); | ||
| 340 | if T::regs().tsr().read().tme(mb.index()) { | ||
| 341 | return Poll::Ready(()); | ||
| 342 | } | ||
| 343 | |||
| 344 | Poll::Pending | ||
| 345 | }) | ||
| 346 | .await; | ||
| 347 | } | ||
| 348 | |||
| 349 | /// Waits for a specific transmit mailbox to become empty | ||
| 350 | pub async fn flush(&self, mb: crate::can::bx::Mailbox) { | ||
| 351 | Self::flush_inner(mb).await | ||
| 352 | } | ||
| 353 | |||
| 354 | async fn flush_any_inner() { | ||
| 355 | poll_fn(|cx| { | ||
| 356 | T::state().tx_waker.register(cx.waker()); | ||
| 357 | |||
| 358 | let tsr = T::regs().tsr().read(); | ||
| 359 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | ||
| 360 | || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | ||
| 361 | || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | ||
| 362 | { | ||
| 363 | return Poll::Ready(()); | ||
| 364 | } | ||
| 365 | |||
| 366 | Poll::Pending | ||
| 367 | }) | ||
| 368 | .await; | ||
| 369 | } | ||
| 370 | |||
| 371 | /// Waits until any of the transmit mailboxes become empty | ||
| 372 | pub async fn flush_any(&self) { | ||
| 373 | Self::flush_any_inner().await | ||
| 374 | } | ||
| 375 | |||
| 376 | async fn flush_all_inner() { | ||
| 377 | poll_fn(|cx| { | ||
| 378 | T::state().tx_waker.register(cx.waker()); | ||
| 379 | |||
| 380 | let tsr = T::regs().tsr().read(); | ||
| 381 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | ||
| 382 | && tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | ||
| 383 | && tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | ||
| 384 | { | ||
| 385 | return Poll::Ready(()); | ||
| 386 | } | ||
| 387 | |||
| 388 | Poll::Pending | ||
| 389 | }) | ||
| 390 | .await; | ||
| 391 | } | ||
| 392 | |||
| 393 | /// Waits until all of the transmit mailboxes become empty | ||
| 394 | pub async fn flush_all(&self) { | ||
| 395 | Self::flush_all_inner().await | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | /// CAN driver, receive half. | ||
| 400 | #[allow(dead_code)] | ||
| 401 | pub struct CanRx<'d, T: Instance> { | ||
| 402 | rx0: crate::can::bx::Rx0<BxcanInstance<'d, T>>, | ||
| 403 | rx1: crate::can::bx::Rx1<BxcanInstance<'d, T>>, | ||
| 404 | } | ||
| 405 | |||
| 406 | impl<'d, T: Instance> CanRx<'d, T> { | ||
| 407 | /// Read a CAN frame. | ||
| 408 | /// | ||
| 409 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 410 | /// | ||
| 411 | /// Returns a tuple of the time the message was received and the message frame | ||
| 412 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 413 | poll_fn(|cx| { | ||
| 414 | T::state().err_waker.register(cx.waker()); | ||
| 415 | if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { | ||
| 416 | return Poll::Ready(Ok(envelope)); | ||
| 417 | } else if let Some(err) = self.curr_error() { | ||
| 418 | return Poll::Ready(Err(err)); | ||
| 419 | } | ||
| 420 | |||
| 421 | Poll::Pending | ||
| 422 | }) | ||
| 423 | .await | ||
| 424 | } | ||
| 425 | |||
| 426 | /// Attempts to read a CAN frame without blocking. | ||
| 427 | /// | ||
| 428 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 429 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 430 | if let Ok(envelope) = T::state().rx_queue.try_receive() { | ||
| 431 | return Ok(envelope); | ||
| 432 | } | ||
| 433 | |||
| 434 | if let Some(err) = self.curr_error() { | ||
| 435 | return Err(TryReadError::BusError(err)); | ||
| 436 | } | ||
| 437 | |||
| 438 | Err(TryReadError::Empty) | ||
| 439 | } | ||
| 440 | |||
| 441 | /// Waits while receive queue is empty. | ||
| 442 | pub async fn wait_not_empty(&mut self) { | ||
| 443 | poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await | ||
| 444 | } | ||
| 445 | |||
| 446 | fn curr_error(&self) -> Option<BusError> { | ||
| 447 | let err = { T::regs().esr().read() }; | ||
| 448 | if err.boff() { | ||
| 449 | return Some(BusError::BusOff); | ||
| 450 | } else if err.epvf() { | ||
| 451 | return Some(BusError::BusPassive); | ||
| 452 | } else if err.ewgf() { | ||
| 453 | return Some(BusError::BusWarning); | ||
| 454 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 455 | return Some(err); | ||
| 456 | } | ||
| 457 | None | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | enum RxFifo { | ||
| 462 | Fifo0, | ||
| 463 | Fifo1, | ||
| 464 | } | ||
| 465 | |||
| 466 | impl<'d, T: Instance> Drop for Can<'d, T> { | ||
| 467 | fn drop(&mut self) { | ||
| 468 | // Cannot call `free()` because it moves the instance. | ||
| 469 | // Manually reset the peripheral. | ||
| 470 | T::regs().mcr().write(|w| w.set_reset(true)); | ||
| 471 | T::disable(); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | impl<'d, T: Instance> Deref for Can<'d, T> { | ||
| 476 | type Target = crate::can::bx::Can<BxcanInstance<'d, T>>; | ||
| 477 | |||
| 478 | fn deref(&self) -> &Self::Target { | ||
| 479 | &self.can | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | impl<'d, T: Instance> DerefMut for Can<'d, T> { | ||
| 484 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 485 | &mut self.can | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | pub(crate) mod sealed { | ||
| 490 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 491 | use embassy_sync::channel::Channel; | ||
| 492 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 493 | |||
| 494 | use super::Envelope; | ||
| 495 | |||
| 496 | pub struct State { | ||
| 497 | pub tx_waker: AtomicWaker, | ||
| 498 | pub err_waker: AtomicWaker, | ||
| 499 | pub rx_queue: Channel<CriticalSectionRawMutex, Envelope, 32>, | ||
| 500 | } | ||
| 501 | |||
| 502 | impl State { | ||
| 503 | pub const fn new() -> Self { | ||
| 504 | Self { | ||
| 505 | tx_waker: AtomicWaker::new(), | ||
| 506 | err_waker: AtomicWaker::new(), | ||
| 507 | rx_queue: Channel::new(), | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | pub trait Instance { | ||
| 513 | fn regs() -> crate::pac::can::Can; | ||
| 514 | fn state() -> &'static State; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | /// CAN instance trait. | ||
| 519 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | ||
| 520 | /// TX interrupt for this instance. | ||
| 521 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 522 | /// RX0 interrupt for this instance. | ||
| 523 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 524 | /// RX1 interrupt for this instance. | ||
| 525 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 526 | /// SCE interrupt for this instance. | ||
| 527 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 528 | } | ||
| 529 | |||
| 530 | /// BXCAN instance newtype. | ||
| 531 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | ||
| 532 | |||
| 533 | unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {} | ||
| 534 | |||
| 535 | foreach_peripheral!( | ||
| 536 | (can, $inst:ident) => { | ||
| 537 | impl sealed::Instance for peripherals::$inst { | ||
| 538 | |||
| 539 | fn regs() -> crate::pac::can::Can { | ||
| 540 | crate::pac::$inst | ||
| 541 | } | ||
| 542 | |||
| 543 | fn state() -> &'static sealed::State { | ||
| 544 | static STATE: sealed::State = sealed::State::new(); | ||
| 545 | &STATE | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | impl Instance for peripherals::$inst { | ||
| 550 | type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; | ||
| 551 | type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; | ||
| 552 | type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; | ||
| 553 | type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; | ||
| 554 | } | ||
| 555 | }; | ||
| 556 | ); | ||
| 557 | |||
| 558 | foreach_peripheral!( | ||
| 559 | (can, CAN) => { | ||
| 560 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> { | ||
| 561 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 562 | } | ||
| 563 | }; | ||
| 564 | // CAN1 and CAN2 is a combination of master and slave instance. | ||
| 565 | // CAN1 owns the filter bank and needs to be enabled in order | ||
| 566 | // for CAN2 to receive messages. | ||
| 567 | (can, CAN1) => { | ||
| 568 | cfg_if::cfg_if! { | ||
| 569 | if #[cfg(all( | ||
| 570 | any(stm32l4, stm32f72, stm32f73), | ||
| 571 | not(any(stm32l49, stm32l4a)) | ||
| 572 | ))] { | ||
| 573 | // Most L4 devices and some F7 devices use the name "CAN1" | ||
| 574 | // even if there is no "CAN2" peripheral. | ||
| 575 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | ||
| 576 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 577 | } | ||
| 578 | } else { | ||
| 579 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | ||
| 580 | const NUM_FILTER_BANKS: u8 = 28; | ||
| 581 | } | ||
| 582 | unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} | ||
| 583 | } | ||
| 584 | } | ||
| 585 | }; | ||
| 586 | (can, CAN3) => { | ||
| 587 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { | ||
| 588 | const NUM_FILTER_BANKS: u8 = 14; | ||
| 589 | } | ||
| 590 | }; | ||
| 591 | ); | ||
| 592 | |||
| 593 | pin_trait!(RxPin, Instance); | ||
| 594 | pin_trait!(TxPin, Instance); | ||
| 595 | |||
| 596 | trait Index { | ||
| 597 | fn index(&self) -> usize; | ||
| 598 | } | ||
| 599 | |||
| 600 | impl Index for crate::can::bx::Mailbox { | ||
| 601 | fn index(&self) -> usize { | ||
| 602 | match self { | ||
| 603 | crate::can::bx::Mailbox::Mailbox0 => 0, | ||
| 604 | crate::can::bx::Mailbox::Mailbox1 => 1, | ||
| 605 | crate::can::bx::Mailbox::Mailbox2 => 2, | ||
| 606 | } | ||
| 607 | } | ||
| 608 | } | ||
| 609 | |||
| 610 | trait IntoBusError { | ||
| 611 | fn into_bus_err(self) -> Option<BusError>; | ||
| 612 | } | ||
| 613 | |||
| 614 | impl IntoBusError for Lec { | ||
| 615 | fn into_bus_err(self) -> Option<BusError> { | ||
| 616 | match self { | ||
| 617 | Lec::STUFF => Some(BusError::Stuff), | ||
| 618 | Lec::FORM => Some(BusError::Form), | ||
| 619 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 620 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 621 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 622 | Lec::CRC => Some(BusError::Crc), | ||
| 623 | Lec::CUSTOM => Some(BusError::Software), | ||
| 624 | _ => None, | ||
| 625 | } | ||
| 626 | } | ||
| 627 | } | ||
diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs index 51766aa31..9940c7f50 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bxcan/filter.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; | 5 | use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; |
| 6 | 6 | ||
| 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames | 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 | 8 | const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers |
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 651de9194..4d89c84d1 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -40,3 +40,13 @@ pub enum FrameCreateError { | |||
| 40 | /// Invalid ID. | 40 | /// Invalid ID. |
| 41 | InvalidCanId, | 41 | InvalidCanId, |
| 42 | } | 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 682e13f4b..e32f19d91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs | |||
| @@ -325,17 +325,6 @@ impl Registers { | |||
| 325 | */ | 325 | */ |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | ||
| 329 | #[inline] | ||
| 330 | pub fn free(mut self) { | ||
| 331 | //self.disable_interrupts(Interrupts::all()); | ||
| 332 | |||
| 333 | //TODO check this! | ||
| 334 | self.enter_init_mode(); | ||
| 335 | self.set_power_down_mode(true); | ||
| 336 | //self.control.instance | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] | 328 | /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] |
| 340 | #[inline] | 329 | #[inline] |
| 341 | pub fn apply_config(&mut self, config: FdCanConfig) { | 330 | pub fn apply_config(&mut self, config: FdCanConfig) { |
| @@ -408,66 +397,17 @@ impl Registers { | |||
| 408 | 397 | ||
| 409 | /// Moves out of ConfigMode and into specified mode | 398 | /// Moves out of ConfigMode and into specified mode |
| 410 | #[inline] | 399 | #[inline] |
| 411 | 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) { |
| 412 | match mode { | 401 | match mode { |
| 413 | crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), | 402 | crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), |
| 414 | crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), | 403 | crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), |
| 415 | crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), | 404 | crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true), |
| 416 | crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), | 405 | crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), |
| 417 | crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), | 406 | crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), |
| 418 | } | 407 | } |
| 419 | self.leave_init_mode(config); | 408 | self.leave_init_mode(config); |
| 420 | } | 409 | } |
| 421 | 410 | ||
| 422 | /// Moves out of ConfigMode and into InternalLoopbackMode | ||
| 423 | #[inline] | ||
| 424 | pub fn into_internal_loopback(mut self, config: FdCanConfig) { | ||
| 425 | self.set_loopback_mode(LoopbackMode::Internal); | ||
| 426 | self.leave_init_mode(config); | ||
| 427 | } | ||
| 428 | |||
| 429 | /// Moves out of ConfigMode and into ExternalLoopbackMode | ||
| 430 | #[inline] | ||
| 431 | pub fn into_external_loopback(mut self, config: FdCanConfig) { | ||
| 432 | self.set_loopback_mode(LoopbackMode::External); | ||
| 433 | self.leave_init_mode(config); | ||
| 434 | } | ||
| 435 | |||
| 436 | /// Moves out of ConfigMode and into RestrictedOperationMode | ||
| 437 | #[inline] | ||
| 438 | pub fn into_restricted(mut self, config: FdCanConfig) { | ||
| 439 | self.set_restricted_operations(true); | ||
| 440 | self.leave_init_mode(config); | ||
| 441 | } | ||
| 442 | |||
| 443 | /// Moves out of ConfigMode and into NormalOperationMode | ||
| 444 | #[inline] | ||
| 445 | pub fn into_normal(mut self, config: FdCanConfig) { | ||
| 446 | self.set_normal_operations(true); | ||
| 447 | self.leave_init_mode(config); | ||
| 448 | } | ||
| 449 | |||
| 450 | /// Moves out of ConfigMode and into BusMonitoringMode | ||
| 451 | #[inline] | ||
| 452 | pub fn into_bus_monitoring(mut self, config: FdCanConfig) { | ||
| 453 | self.set_bus_monitoring_mode(true); | ||
| 454 | self.leave_init_mode(config); | ||
| 455 | } | ||
| 456 | |||
| 457 | /// Moves out of ConfigMode and into Testmode | ||
| 458 | #[inline] | ||
| 459 | pub fn into_test_mode(mut self, config: FdCanConfig) { | ||
| 460 | self.set_test_mode(true); | ||
| 461 | self.leave_init_mode(config); | ||
| 462 | } | ||
| 463 | |||
| 464 | /// Moves out of ConfigMode and into PoweredDownmode | ||
| 465 | #[inline] | ||
| 466 | pub fn into_powered_down(mut self, config: FdCanConfig) { | ||
| 467 | self.set_power_down_mode(true); | ||
| 468 | self.leave_init_mode(config); | ||
| 469 | } | ||
| 470 | |||
| 471 | /// Configures the bit timings. | 411 | /// Configures the bit timings. |
| 472 | /// | 412 | /// |
| 473 | /// 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 |
| @@ -565,6 +505,7 @@ impl Registers { | |||
| 565 | 505 | ||
| 566 | /// Configures and resets the timestamp counter | 506 | /// Configures and resets the timestamp counter |
| 567 | #[inline] | 507 | #[inline] |
| 508 | #[allow(unused)] | ||
| 568 | pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { | 509 | pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { |
| 569 | #[cfg(stm32h7)] | 510 | #[cfg(stm32h7)] |
| 570 | let (tcp, tss) = match select { | 511 | let (tcp, tss) = match select { |
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 14fc32c51..d2d1f7aa6 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs | |||
| @@ -3,6 +3,14 @@ use bit_field::BitField; | |||
| 3 | 3 | ||
| 4 | use crate::can::enums::FrameCreateError; | 4 | use crate::can::enums::FrameCreateError; |
| 5 | 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 | |||
| 6 | /// CAN Header, without meta data | 14 | /// CAN Header, without meta data |
| 7 | #[derive(Debug, Copy, Clone)] | 15 | #[derive(Debug, Copy, Clone)] |
| 8 | pub struct Header { | 16 | pub struct Header { |
| @@ -136,19 +144,20 @@ impl ClassicData { | |||
| 136 | } | 144 | } |
| 137 | } | 145 | } |
| 138 | 146 | ||
| 139 | /// 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 | ||
| 140 | #[derive(Debug, Copy, Clone)] | 149 | #[derive(Debug, Copy, Clone)] |
| 141 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 150 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 142 | pub struct ClassicFrame { | 151 | pub struct Frame { |
| 143 | can_header: Header, | 152 | can_header: Header, |
| 144 | data: ClassicData, | 153 | data: ClassicData, |
| 145 | } | 154 | } |
| 146 | 155 | ||
| 147 | impl ClassicFrame { | 156 | impl Frame { |
| 148 | /// Create a new CAN classic Frame | 157 | /// Create a new CAN classic Frame |
| 149 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { | 158 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 150 | let data = ClassicData::new(raw_data)?; | 159 | let data = ClassicData::new(raw_data)?; |
| 151 | Ok(ClassicFrame { can_header, data: data }) | 160 | Ok(Frame { can_header, data: data }) |
| 152 | } | 161 | } |
| 153 | 162 | ||
| 154 | /// Creates a new data frame. | 163 | /// Creates a new data frame. |
| @@ -206,9 +215,9 @@ impl ClassicFrame { | |||
| 206 | } | 215 | } |
| 207 | } | 216 | } |
| 208 | 217 | ||
| 209 | impl embedded_can::Frame for ClassicFrame { | 218 | impl embedded_can::Frame for Frame { |
| 210 | 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> { |
| 211 | let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); | 220 | let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); |
| 212 | match frameopt { | 221 | match frameopt { |
| 213 | Ok(frame) => Some(frame), | 222 | Ok(frame) => Some(frame), |
| 214 | Err(_) => None, | 223 | Err(_) => None, |
| @@ -216,7 +225,7 @@ impl embedded_can::Frame for ClassicFrame { | |||
| 216 | } | 225 | } |
| 217 | 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> { |
| 218 | if len <= 8 { | 227 | if len <= 8 { |
| 219 | let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]); | 228 | let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]); |
| 220 | match frameopt { | 229 | match frameopt { |
| 221 | Ok(frame) => Some(frame), | 230 | Ok(frame) => Some(frame), |
| 222 | Err(_) => None, | 231 | Err(_) => None, |
| @@ -245,7 +254,7 @@ impl embedded_can::Frame for ClassicFrame { | |||
| 245 | } | 254 | } |
| 246 | } | 255 | } |
| 247 | 256 | ||
| 248 | impl CanHeader for ClassicFrame { | 257 | impl CanHeader for Frame { |
| 249 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { | 258 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { |
| 250 | Self::new(header, data) | 259 | Self::new(header, data) |
| 251 | } | 260 | } |
| @@ -255,10 +264,31 @@ impl CanHeader for ClassicFrame { | |||
| 255 | } | 264 | } |
| 256 | } | 265 | } |
| 257 | 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 | |||
| 258 | /// Payload of a (FD)CAN data frame. | 287 | /// Payload of a (FD)CAN data frame. |
| 259 | /// | 288 | /// |
| 260 | /// Contains 0 to 64 Bytes of data. | 289 | /// Contains 0 to 64 Bytes of data. |
| 261 | #[derive(Debug, Copy, Clone)] | 290 | #[derive(Debug, Copy, Clone)] |
| 291 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 262 | pub struct FdData { | 292 | pub struct FdData { |
| 263 | pub(crate) bytes: [u8; 64], | 293 | pub(crate) bytes: [u8; 64], |
| 264 | } | 294 | } |
| @@ -308,6 +338,7 @@ impl FdData { | |||
| 308 | 338 | ||
| 309 | /// 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 |
| 310 | #[derive(Debug, Copy, Clone)] | 340 | #[derive(Debug, Copy, Clone)] |
| 341 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 311 | pub struct FdFrame { | 342 | pub struct FdFrame { |
| 312 | can_header: Header, | 343 | can_header: Header, |
| 313 | data: FdData, | 344 | data: FdData, |
| @@ -410,3 +441,23 @@ impl CanHeader for FdFrame { | |||
| 410 | self.header() | 441 | self.header() |
| 411 | } | 442 | } |
| 412 | } | 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 74b095b6f..18b5ec918 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs | |||
| @@ -1885,16 +1885,13 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { | |||
| 1885 | } | 1885 | } |
| 1886 | } | 1886 | } |
| 1887 | 1887 | ||
| 1888 | pub(crate) mod sealed { | 1888 | trait SealedInstance { |
| 1889 | use super::*; | 1889 | fn regs() -> pac::cryp::Cryp; |
| 1890 | |||
| 1891 | pub trait Instance { | ||
| 1892 | fn regs() -> pac::cryp::Cryp; | ||
| 1893 | } | ||
| 1894 | } | 1890 | } |
| 1895 | 1891 | ||
| 1896 | /// CRYP instance trait. | 1892 | /// CRYP instance trait. |
| 1897 | 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 { | ||
| 1898 | /// Interrupt for this CRYP instance. | 1895 | /// Interrupt for this CRYP instance. |
| 1899 | type Interrupt: interrupt::typelevel::Interrupt; | 1896 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1900 | } | 1897 | } |
| @@ -1905,7 +1902,7 @@ foreach_interrupt!( | |||
| 1905 | type Interrupt = crate::interrupt::typelevel::$irq; | 1902 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 1906 | } | 1903 | } |
| 1907 | 1904 | ||
| 1908 | impl sealed::Instance for peripherals::$inst { | 1905 | impl SealedInstance for peripherals::$inst { |
| 1909 | fn regs() -> crate::pac::cryp::Cryp { | 1906 | fn regs() -> crate::pac::cryp::Cryp { |
| 1910 | crate::pac::$inst | 1907 | crate::pac::$inst |
| 1911 | } | 1908 | } |
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 7b5b3cf58..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}; |
| @@ -510,6 +510,31 @@ impl AnyChannel { | |||
| 510 | DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), | 510 | DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), |
| 511 | } | 511 | } |
| 512 | } | 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 | } | ||
| 513 | } | 538 | } |
| 514 | 539 | ||
| 515 | /// DMA transfer. | 540 | /// DMA transfer. |
| @@ -829,6 +854,25 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 829 | pub fn is_running(&mut self) -> bool { | 854 | pub fn is_running(&mut self) -> bool { |
| 830 | self.channel.is_running() | 855 | self.channel.is_running() |
| 831 | } | 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 | } | ||
| 832 | } | 876 | } |
| 833 | 877 | ||
| 834 | impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { | 878 | impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { |
| @@ -940,6 +984,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 940 | pub fn is_running(&mut self) -> bool { | 984 | pub fn is_running(&mut self) -> bool { |
| 941 | self.channel.is_running() | 985 | self.channel.is_running() |
| 942 | } | 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 | } | ||
| 943 | } | 1004 | } |
| 944 | 1005 | ||
| 945 | 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 d5e88a20a..7e3681469 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -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 | } |
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 7cc28ff56..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> { |
| @@ -1061,9 +1061,3 @@ impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { | |||
| 1061 | Ok((*self).is_set_low()) | 1061 | Ok((*self).is_set_low()) |
| 1062 | } | 1062 | } |
| 1063 | } | 1063 | } |
| 1064 | |||
| 1065 | /// Low-level GPIO manipulation. | ||
| 1066 | #[cfg(feature = "unstable-pac")] | ||
| 1067 | pub mod low_level { | ||
| 1068 | pub use super::sealed::*; | ||
| 1069 | } | ||
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 2c606c3c9..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 | } |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f1ed7ca40..9f29ed5e0 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -15,7 +15,6 @@ use embedded_hal_1::i2c::Operation; | |||
| 15 | use super::*; | 15 | use super::*; |
| 16 | use crate::dma::Transfer; | 16 | use crate::dma::Transfer; |
| 17 | use crate::pac::i2c; | 17 | use crate::pac::i2c; |
| 18 | use crate::time::Hertz; | ||
| 19 | 18 | ||
| 20 | // /!\ /!\ | 19 | // /!\ /!\ |
| 21 | // /!\ Implementation note! /!\ | 20 | // /!\ Implementation note! /!\ |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 1ac2740df..8baf2849d 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -9,7 +9,6 @@ use embedded_hal_1::i2c::Operation; | |||
| 9 | use super::*; | 9 | use super::*; |
| 10 | use crate::dma::Transfer; | 10 | use crate::dma::Transfer; |
| 11 | use crate::pac::i2c; | 11 | use crate::pac::i2c; |
| 12 | use crate::time::Hertz; | ||
| 13 | 12 | ||
| 14 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 13 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
| 15 | let regs = T::regs(); | 14 | let regs = T::regs(); |
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 9e26a3513..8b826e5ac 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -158,7 +158,7 @@ pub(crate) use stm32_metapac as pac; | |||
| 158 | use crate::interrupt::Priority; | 158 | use crate::interrupt::Priority; |
| 159 | #[cfg(feature = "rt")] | 159 | #[cfg(feature = "rt")] |
| 160 | pub use crate::pac::NVIC_PRIO_BITS; | 160 | pub use crate::pac::NVIC_PRIO_BITS; |
| 161 | use crate::rcc::sealed::RccPeripheral; | 161 | use crate::rcc::SealedRccPeripheral; |
| 162 | 162 | ||
| 163 | /// `embassy-stm32` global configuration. | 163 | /// `embassy-stm32` global configuration. |
| 164 | #[non_exhaustive] | 164 | #[non_exhaustive] |
| @@ -168,10 +168,18 @@ pub struct Config { | |||
| 168 | 168 | ||
| 169 | /// Enable debug during sleep and stop. | 169 | /// Enable debug during sleep and stop. |
| 170 | /// | 170 | /// |
| 171 | /// May incrase power consumption. Defaults to true. | 171 | /// May increase power consumption. Defaults to true. |
| 172 | #[cfg(dbgmcu)] | 172 | #[cfg(dbgmcu)] |
| 173 | pub enable_debug_during_sleep: bool, | 173 | pub enable_debug_during_sleep: bool, |
| 174 | 174 | ||
| 175 | /// On low-power boards (eg. `stm32l4`, `stm32l5` and `stm32u5`), | ||
| 176 | /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`), | ||
| 177 | /// which needs to be enabled before these pins can be used. | ||
| 178 | /// | ||
| 179 | /// May increase power consumption. Defaults to true. | ||
| 180 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | ||
| 181 | pub enable_independent_io_supply: bool, | ||
| 182 | |||
| 175 | /// BDMA interrupt priority. | 183 | /// BDMA interrupt priority. |
| 176 | /// | 184 | /// |
| 177 | /// Defaults to P0 (highest). | 185 | /// Defaults to P0 (highest). |
| @@ -209,6 +217,8 @@ impl Default for Config { | |||
| 209 | rcc: Default::default(), | 217 | rcc: Default::default(), |
| 210 | #[cfg(dbgmcu)] | 218 | #[cfg(dbgmcu)] |
| 211 | enable_debug_during_sleep: true, | 219 | enable_debug_during_sleep: true, |
| 220 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | ||
| 221 | enable_independent_io_supply: true, | ||
| 212 | #[cfg(bdma)] | 222 | #[cfg(bdma)] |
| 213 | bdma_interrupt_priority: Priority::P0, | 223 | bdma_interrupt_priority: Priority::P0, |
| 214 | #[cfg(dma)] | 224 | #[cfg(dma)] |
| @@ -270,6 +280,24 @@ pub fn init(config: Config) -> Peripherals { | |||
| 270 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] | 280 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] |
| 271 | peripherals::FLASH::enable_and_reset_with_cs(cs); | 281 | peripherals::FLASH::enable_and_reset_with_cs(cs); |
| 272 | 282 | ||
| 283 | // Enable the VDDIO2 power supply on chips that have it. | ||
| 284 | // Note that this requires the PWR peripheral to be enabled first. | ||
| 285 | #[cfg(any(stm32l4, stm32l5))] | ||
| 286 | { | ||
| 287 | crate::pac::PWR.cr2().modify(|w| { | ||
| 288 | // The official documentation states that we should ideally enable VDDIO2 | ||
| 289 | // through the PVME2 bit, but it looks like this isn't required, | ||
| 290 | // and CubeMX itself skips this step. | ||
| 291 | w.set_iosv(config.enable_independent_io_supply); | ||
| 292 | }); | ||
| 293 | } | ||
| 294 | #[cfg(stm32u5)] | ||
| 295 | { | ||
| 296 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 297 | w.set_io2sv(config.enable_independent_io_supply); | ||
| 298 | }); | ||
| 299 | } | ||
| 300 | |||
| 273 | // dead battery functionality is still present on these | 301 | // dead battery functionality is still present on these |
| 274 | // chips despite them not having UCPD- disable it | 302 | // chips despite them not having UCPD- disable it |
| 275 | #[cfg(any(stm32g070, stm32g0b0))] | 303 | #[cfg(any(stm32g070, stm32g0b0))] |
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/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 294620031..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}; |
| @@ -1041,43 +1039,42 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> { | |||
| 1041 | } | 1039 | } |
| 1042 | } | 1040 | } |
| 1043 | 1041 | ||
| 1044 | pub(crate) mod sealed { | 1042 | trait SealedInstance { |
| 1045 | use super::*; | 1043 | const REGS: Regs; |
| 1046 | 1044 | } | |
| 1047 | pub trait Instance { | ||
| 1048 | const REGS: Regs; | ||
| 1049 | } | ||
| 1050 | 1045 | ||
| 1051 | #[derive(Copy, Clone)] | 1046 | #[derive(Copy, Clone)] |
| 1052 | pub enum WhichSubBlock { | 1047 | enum WhichSubBlock { |
| 1053 | A = 0, | 1048 | A = 0, |
| 1054 | B = 1, | 1049 | B = 1, |
| 1055 | } | 1050 | } |
| 1056 | 1051 | ||
| 1057 | pub trait SubBlock { | 1052 | trait SealedSubBlock { |
| 1058 | const WHICH: WhichSubBlock; | 1053 | const WHICH: WhichSubBlock; |
| 1059 | } | ||
| 1060 | } | 1054 | } |
| 1061 | 1055 | ||
| 1062 | /// Sub-block instance trait. | 1056 | /// Sub-block instance trait. |
| 1063 | pub trait SubBlockInstance: sealed::SubBlock {} | 1057 | #[allow(private_bounds)] |
| 1058 | pub trait SubBlockInstance: SealedSubBlock {} | ||
| 1064 | 1059 | ||
| 1065 | /// Sub-block A. | 1060 | /// Sub-block A. |
| 1066 | pub enum A {} | 1061 | pub enum A {} |
| 1067 | impl sealed::SubBlock for A { | 1062 | impl SealedSubBlock for A { |
| 1068 | const WHICH: WhichSubBlock = WhichSubBlock::A; | 1063 | const WHICH: WhichSubBlock = WhichSubBlock::A; |
| 1069 | } | 1064 | } |
| 1070 | impl SubBlockInstance for A {} | 1065 | impl SubBlockInstance for A {} |
| 1071 | 1066 | ||
| 1072 | /// Sub-block B. | 1067 | /// Sub-block B. |
| 1073 | pub enum B {} | 1068 | pub enum B {} |
| 1074 | impl sealed::SubBlock for B { | 1069 | impl SealedSubBlock for B { |
| 1075 | const WHICH: WhichSubBlock = WhichSubBlock::B; | 1070 | const WHICH: WhichSubBlock = WhichSubBlock::B; |
| 1076 | } | 1071 | } |
| 1077 | impl SubBlockInstance for B {} | 1072 | impl SubBlockInstance for B {} |
| 1078 | 1073 | ||
| 1079 | /// SAI instance trait. | 1074 | /// SAI instance trait. |
| 1080 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 1075 | #[allow(private_bounds)] |
| 1076 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 1077 | |||
| 1081 | pin_trait!(SckPin, Instance, SubBlockInstance); | 1078 | pin_trait!(SckPin, Instance, SubBlockInstance); |
| 1082 | pin_trait!(FsPin, Instance, SubBlockInstance); | 1079 | pin_trait!(FsPin, Instance, SubBlockInstance); |
| 1083 | pin_trait!(SdPin, Instance, SubBlockInstance); | 1080 | pin_trait!(SdPin, Instance, SubBlockInstance); |
| @@ -1087,7 +1084,7 @@ dma_trait!(Dma, Instance, SubBlockInstance); | |||
| 1087 | 1084 | ||
| 1088 | foreach_peripheral!( | 1085 | foreach_peripheral!( |
| 1089 | (sai, $inst:ident) => { | 1086 | (sai, $inst:ident) => { |
| 1090 | impl sealed::Instance for peripherals::$inst { | 1087 | impl SealedInstance for peripherals::$inst { |
| 1091 | const REGS: Regs = crate::pac::$inst; | 1088 | const REGS: Regs = crate::pac::$inst; |
| 1092 | } | 1089 | } |
| 1093 | 1090 | ||
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index fa1f710d8..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; |
| @@ -1418,21 +1417,17 @@ impl Cmd { | |||
| 1418 | 1417 | ||
| 1419 | ////////////////////////////////////////////////////// | 1418 | ////////////////////////////////////////////////////// |
| 1420 | 1419 | ||
| 1421 | pub(crate) mod sealed { | 1420 | trait SealedInstance { |
| 1422 | use super::*; | 1421 | fn regs() -> RegBlock; |
| 1423 | 1422 | fn state() -> &'static AtomicWaker; | |
| 1424 | pub trait Instance { | ||
| 1425 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1426 | |||
| 1427 | fn regs() -> RegBlock; | ||
| 1428 | fn state() -> &'static AtomicWaker; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | pub trait Pins<T: Instance> {} | ||
| 1432 | } | 1423 | } |
| 1433 | 1424 | ||
| 1434 | /// SDMMC instance trait. | 1425 | /// SDMMC instance trait. |
| 1435 | 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 | } | ||
| 1436 | 1431 | ||
| 1437 | pin_trait!(CkPin, Instance); | 1432 | pin_trait!(CkPin, Instance); |
| 1438 | pin_trait!(CmdPin, Instance); | 1433 | pin_trait!(CmdPin, Instance); |
| @@ -1459,9 +1454,7 @@ impl<T: Instance> SdmmcDma<T> for NoDma {} | |||
| 1459 | 1454 | ||
| 1460 | foreach_peripheral!( | 1455 | foreach_peripheral!( |
| 1461 | (sdmmc, $inst:ident) => { | 1456 | (sdmmc, $inst:ident) => { |
| 1462 | impl sealed::Instance for peripherals::$inst { | 1457 | impl SealedInstance for peripherals::$inst { |
| 1463 | type Interrupt = crate::interrupt::typelevel::$inst; | ||
| 1464 | |||
| 1465 | fn regs() -> RegBlock { | 1458 | fn regs() -> RegBlock { |
| 1466 | crate::pac::$inst | 1459 | crate::pac::$inst |
| 1467 | } | 1460 | } |
| @@ -1472,6 +1465,8 @@ foreach_peripheral!( | |||
| 1472 | } | 1465 | } |
| 1473 | } | 1466 | } |
| 1474 | 1467 | ||
| 1475 | impl Instance for peripherals::$inst {} | 1468 | impl Instance for peripherals::$inst { |
| 1469 | type Interrupt = crate::interrupt::typelevel::$inst; | ||
| 1470 | } | ||
| 1476 | }; | 1471 | }; |
| 1477 | ); | 1472 | ); |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index b517f640a..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 | ||
| @@ -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 ef893c7f5..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 | /// Set state of MOE-bit in BDTR register to en-/disable output | ||
| 443 | fn set_moe(&self, enable: bool) { | ||
| 444 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); | ||
| 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,181 +34,44 @@ 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 | } | ||
| 571 | |||
| 572 | impl CountingMode { | ||
| 573 | /// Return whether this mode is edge-aligned (up or down). | ||
| 574 | pub fn is_edge_aligned(&self) -> bool { | ||
| 575 | matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) | ||
| 576 | } | ||
| 577 | |||
| 578 | /// Return whether this mode is center-aligned. | ||
| 579 | pub fn is_center_aligned(&self) -> bool { | ||
| 580 | matches!( | ||
| 581 | self, | ||
| 582 | CountingMode::CenterAlignedDownInterrupts | ||
| 583 | | CountingMode::CenterAlignedUpInterrupts | ||
| 584 | | CountingMode::CenterAlignedBothInterrupts | ||
| 585 | ) | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | impl From<CountingMode> for (vals::Cms, vals::Dir) { | ||
| 590 | fn from(value: CountingMode) -> Self { | ||
| 591 | match value { | ||
| 592 | CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), | ||
| 593 | CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), | ||
| 594 | CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), | ||
| 595 | CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), | ||
| 596 | CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), | ||
| 597 | } | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | impl From<(vals::Cms, vals::Dir)> for CountingMode { | ||
| 602 | fn from(value: (vals::Cms, vals::Dir)) -> Self { | ||
| 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 | } | 60 | } |
| 61 | /// Cut-down basic timer instance. | ||
| 62 | pub trait BasicNoCr2Instance: CoreInstance {} | ||
| 63 | /// Basic timer instance. | ||
| 64 | pub trait BasicInstance: BasicNoCr2Instance {} | ||
| 657 | 65 | ||
| 658 | /// Timer output pin polarity. | 66 | /// General-purpose 16-bit timer with 1 channel instance. |
| 659 | #[derive(Clone, Copy)] | 67 | pub trait GeneralInstance1Channel: CoreInstance {} |
| 660 | pub enum OutputPolarity { | ||
| 661 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 662 | ActiveHigh, | ||
| 663 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 664 | ActiveLow, | ||
| 665 | } | ||
| 666 | 68 | ||
| 667 | impl From<OutputPolarity> for bool { | 69 | /// General-purpose 16-bit timer with 2 channels instance. |
| 668 | fn from(mode: OutputPolarity) -> Self { | 70 | pub trait GeneralInstance2Channel: GeneralInstance1Channel {} |
| 669 | match mode { | ||
| 670 | OutputPolarity::ActiveHigh => false, | ||
| 671 | OutputPolarity::ActiveLow => true, | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | 71 | ||
| 676 | /// Basic 16-bit timer instance. | 72 | /// General-purpose 16-bit timer with 4 channels instance. |
| 677 | pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} | 73 | pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel { |
| 678 | 74 | // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel | |
| 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 | // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance | ||
| 689 | // Advanced timers implement this trait, but the output needs to be | 75 | // Advanced timers implement this trait, but the output needs to be |
| 690 | // enabled explicitly. | 76 | // enabled explicitly. |
| 691 | // To support general-purpose and advanced timers, this function is added | 77 | // To support general-purpose and advanced timers, this function is added |
| @@ -694,296 +80,149 @@ pub trait CaptureCompare16bitInstance: | |||
| 694 | fn enable_outputs(&self) {} | 80 | fn enable_outputs(&self) {} |
| 695 | } | 81 | } |
| 696 | 82 | ||
| 697 | #[cfg(not(stm32l0))] | 83 | /// General-purpose 32-bit timer with 4 channels instance. |
| 698 | // It's just a General-purpose 32-bit timer instance. | 84 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} |
| 699 | /// Capture Compare 32-bit timer instance. | ||
| 700 | pub trait CaptureCompare32bitInstance: | ||
| 701 | CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static | ||
| 702 | { | ||
| 703 | } | ||
| 704 | |||
| 705 | #[cfg(not(stm32l0))] | ||
| 706 | // It's just a Advanced Control timer instance. | ||
| 707 | /// Complementary Capture Compare 32-bit timer instance. | ||
| 708 | pub trait ComplementaryCaptureCompare16bitInstance: | ||
| 709 | CaptureCompare16bitInstance | ||
| 710 | + sealed::GeneralPurpose1ChannelComplementaryInstance | ||
| 711 | + sealed::GeneralPurpose2ChannelComplementaryInstance | ||
| 712 | + sealed::AdvancedControlInstance | ||
| 713 | + 'static | ||
| 714 | { | ||
| 715 | } | ||
| 716 | |||
| 717 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); | ||
| 718 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); | ||
| 719 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); | ||
| 720 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); | ||
| 721 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); | ||
| 722 | |||
| 723 | cfg_if::cfg_if! { | ||
| 724 | if #[cfg(not(stm32l0))] { | ||
| 725 | pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 726 | pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 727 | pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 728 | pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 729 | |||
| 730 | pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); | ||
| 731 | pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); | ||
| 732 | 85 | ||
| 733 | pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); | 86 | /// Advanced 16-bit timer with 1 channel instance. |
| 734 | pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); | 87 | pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { |
| 735 | 88 | /// Capture compare interrupt for this timer. | |
| 736 | pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); | 89 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; |
| 737 | pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); | ||
| 738 | } | ||
| 739 | } | 90 | } |
| 91 | /// Advanced 16-bit timer with 2 channels instance. | ||
| 740 | 92 | ||
| 741 | #[allow(unused)] | 93 | pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} |
| 742 | macro_rules! impl_core_timer { | ||
| 743 | ($inst:ident, $irq:ident) => { | ||
| 744 | impl sealed::CoreInstance for crate::peripherals::$inst { | ||
| 745 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 746 | 94 | ||
| 747 | fn regs_core() -> crate::pac::timer::TimCore { | 95 | /// Advanced 16-bit timer with 4 channels instance. |
| 748 | unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } | 96 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} |
| 749 | } | ||
| 750 | } | ||
| 751 | }; | ||
| 752 | } | ||
| 753 | 97 | ||
| 754 | #[allow(unused)] | 98 | pin_trait!(Channel1Pin, GeneralInstance4Channel); |
| 755 | macro_rules! impl_basic_no_cr2_timer { | 99 | pin_trait!(Channel2Pin, GeneralInstance4Channel); |
| 756 | ($inst:ident) => { | 100 | pin_trait!(Channel3Pin, GeneralInstance4Channel); |
| 757 | impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { | 101 | pin_trait!(Channel4Pin, GeneralInstance4Channel); |
| 758 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { | 102 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); |
| 759 | unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 760 | } | ||
| 761 | } | ||
| 762 | }; | ||
| 763 | } | ||
| 764 | 103 | ||
| 765 | #[allow(unused)] | 104 | pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); |
| 766 | macro_rules! impl_basic_timer { | 105 | pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); |
| 767 | ($inst:ident) => { | 106 | pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); |
| 768 | impl sealed::BasicInstance for crate::peripherals::$inst { | 107 | pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); |
| 769 | fn regs_basic() -> crate::pac::timer::TimBasic { | ||
| 770 | unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 771 | } | ||
| 772 | } | ||
| 773 | }; | ||
| 774 | } | ||
| 775 | 108 | ||
| 776 | #[allow(unused)] | 109 | pin_trait!(BreakInputPin, AdvancedInstance4Channel); |
| 777 | macro_rules! impl_1ch_timer { | 110 | pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); |
| 778 | ($inst:ident) => { | ||
| 779 | impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst { | ||
| 780 | fn regs_1ch() -> crate::pac::timer::Tim1ch { | ||
| 781 | unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 782 | } | ||
| 783 | } | ||
| 784 | }; | ||
| 785 | } | ||
| 786 | 111 | ||
| 787 | #[allow(unused)] | 112 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); |
| 788 | macro_rules! impl_2ch_timer { | 113 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); |
| 789 | ($inst:ident) => { | ||
| 790 | impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst { | ||
| 791 | fn regs_2ch() -> crate::pac::timer::Tim2ch { | ||
| 792 | unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 793 | } | ||
| 794 | } | ||
| 795 | }; | ||
| 796 | } | ||
| 797 | 114 | ||
| 798 | #[allow(unused)] | 115 | pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); |
| 799 | macro_rules! impl_gp16_timer { | 116 | pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); |
| 800 | ($inst:ident) => { | ||
| 801 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 802 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | ||
| 803 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 804 | } | ||
| 805 | } | ||
| 806 | }; | ||
| 807 | } | ||
| 808 | 117 | ||
| 809 | #[allow(unused)] | 118 | // Update Event trigger DMA for every timer |
| 810 | macro_rules! impl_gp32_timer { | 119 | dma_trait!(UpDma, BasicInstance); |
| 811 | ($inst:ident) => { | ||
| 812 | impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { | ||
| 813 | fn regs_gp32() -> crate::pac::timer::TimGp32 { | ||
| 814 | crate::pac::$inst | ||
| 815 | } | ||
| 816 | } | ||
| 817 | }; | ||
| 818 | } | ||
| 819 | 120 | ||
| 820 | #[allow(unused)] | 121 | dma_trait!(Ch1Dma, GeneralInstance4Channel); |
| 821 | macro_rules! impl_1ch_cmp_timer { | 122 | dma_trait!(Ch2Dma, GeneralInstance4Channel); |
| 822 | ($inst:ident) => { | 123 | dma_trait!(Ch3Dma, GeneralInstance4Channel); |
| 823 | impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { | 124 | dma_trait!(Ch4Dma, GeneralInstance4Channel); |
| 824 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp { | ||
| 825 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 826 | } | ||
| 827 | } | ||
| 828 | }; | ||
| 829 | } | ||
| 830 | 125 | ||
| 831 | #[allow(unused)] | 126 | #[allow(unused)] |
| 832 | macro_rules! impl_2ch_cmp_timer { | 127 | macro_rules! impl_core_timer { |
| 833 | ($inst:ident) => { | 128 | ($inst:ident, $bits:expr) => { |
| 834 | impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { | 129 | impl CoreInstance for crate::peripherals::$inst { |
| 835 | fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { | 130 | type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP; |
| 836 | unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 837 | } | ||
| 838 | } | ||
| 839 | }; | ||
| 840 | } | ||
| 841 | 131 | ||
| 842 | #[allow(unused)] | 132 | const BITS: TimerBits = $bits; |
| 843 | macro_rules! impl_adv_timer { | ||
| 844 | ($inst:ident, $irq:ident) => { | ||
| 845 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { | ||
| 846 | type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq; | ||
| 847 | 133 | ||
| 848 | fn regs_advanced() -> crate::pac::timer::TimAdv { | 134 | fn regs() -> *mut () { |
| 849 | unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } | 135 | crate::pac::$inst.as_ptr() |
| 850 | } | 136 | } |
| 851 | } | 137 | } |
| 852 | }; | 138 | }; |
| 853 | } | 139 | } |
| 854 | 140 | ||
| 855 | foreach_interrupt! { | 141 | foreach_interrupt! { |
| 856 | |||
| 857 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 142 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 858 | impl_core_timer!($inst, $irq); | 143 | impl_core_timer!($inst, TimerBits::Bits16); |
| 859 | impl_basic_no_cr2_timer!($inst); | 144 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 860 | impl_basic_timer!($inst); | ||
| 861 | impl BasicInstance for crate::peripherals::$inst {} | 145 | impl BasicInstance for crate::peripherals::$inst {} |
| 862 | }; | 146 | }; |
| 863 | 147 | ||
| 864 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { | 148 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { |
| 865 | impl_core_timer!($inst, $irq); | 149 | impl_core_timer!($inst, TimerBits::Bits16); |
| 866 | impl_basic_no_cr2_timer!($inst); | 150 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 867 | impl_basic_timer!($inst); | ||
| 868 | impl_1ch_timer!($inst); | ||
| 869 | impl_2ch_timer!($inst); | ||
| 870 | impl_gp16_timer!($inst); | ||
| 871 | impl BasicInstance for crate::peripherals::$inst {} | 151 | impl BasicInstance for crate::peripherals::$inst {} |
| 872 | 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 {} | ||
| 873 | }; | 155 | }; |
| 874 | 156 | ||
| 875 | |||
| 876 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { | 157 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { |
| 877 | impl_core_timer!($inst, $irq); | 158 | impl_core_timer!($inst, TimerBits::Bits16); |
| 878 | impl_basic_no_cr2_timer!($inst); | 159 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 879 | impl_basic_timer!($inst); | ||
| 880 | impl_1ch_timer!($inst); | ||
| 881 | impl_2ch_timer!($inst); | ||
| 882 | impl_gp16_timer!($inst); | ||
| 883 | impl BasicInstance for crate::peripherals::$inst {} | 160 | impl BasicInstance for crate::peripherals::$inst {} |
| 884 | 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 {} | ||
| 885 | }; | 164 | }; |
| 886 | 165 | ||
| 887 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { | 166 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 888 | impl_core_timer!($inst, $irq); | 167 | impl_core_timer!($inst, TimerBits::Bits16); |
| 889 | impl_basic_no_cr2_timer!($inst); | 168 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 890 | impl_basic_timer!($inst); | ||
| 891 | impl_1ch_timer!($inst); | ||
| 892 | impl_2ch_timer!($inst); | ||
| 893 | impl_gp16_timer!($inst); | ||
| 894 | impl BasicInstance for crate::peripherals::$inst {} | 169 | impl BasicInstance for crate::peripherals::$inst {} |
| 895 | 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 {} | ||
| 896 | }; | 173 | }; |
| 897 | 174 | ||
| 898 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 175 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 899 | impl_core_timer!($inst, $irq); | 176 | impl_core_timer!($inst, TimerBits::Bits32); |
| 900 | impl_basic_no_cr2_timer!($inst); | 177 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 901 | impl_basic_timer!($inst); | ||
| 902 | impl_1ch_timer!($inst); | ||
| 903 | impl_2ch_timer!($inst); | ||
| 904 | impl_gp16_timer!($inst); | ||
| 905 | impl_gp32_timer!($inst); | ||
| 906 | impl BasicInstance for crate::peripherals::$inst {} | 178 | impl BasicInstance for crate::peripherals::$inst {} |
| 907 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 179 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 908 | 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 {} | ||
| 909 | }; | 183 | }; |
| 910 | 184 | ||
| 911 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { | 185 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { |
| 912 | impl_core_timer!($inst, $irq); | 186 | impl_core_timer!($inst, TimerBits::Bits16); |
| 913 | impl_basic_no_cr2_timer!($inst); | 187 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 914 | impl_basic_timer!($inst); | ||
| 915 | impl_1ch_timer!($inst); | ||
| 916 | impl_2ch_timer!($inst); | ||
| 917 | impl_gp16_timer!($inst); | ||
| 918 | impl_1ch_cmp_timer!($inst); | ||
| 919 | impl_2ch_cmp_timer!($inst); | ||
| 920 | impl BasicInstance for crate::peripherals::$inst {} | 188 | impl BasicInstance for crate::peripherals::$inst {} |
| 921 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 189 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 922 | /// Enable timer outputs. | 190 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 923 | fn enable_outputs(&self) { | 191 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 924 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 192 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 925 | self.set_moe(true); | 193 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 926 | } | 194 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 927 | } | ||
| 928 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 929 | }; | ||
| 930 | ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { | ||
| 931 | impl_adv_timer!($inst, $irq); | ||
| 932 | }; | 195 | }; |
| 933 | 196 | ||
| 934 | |||
| 935 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { | 197 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { |
| 936 | impl_core_timer!($inst, $irq); | 198 | impl_core_timer!($inst, TimerBits::Bits16); |
| 937 | impl_basic_no_cr2_timer!($inst); | 199 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 938 | impl_basic_timer!($inst); | ||
| 939 | impl_1ch_timer!($inst); | ||
| 940 | impl_2ch_timer!($inst); | ||
| 941 | impl_gp16_timer!($inst); | ||
| 942 | impl_1ch_cmp_timer!($inst); | ||
| 943 | impl_2ch_cmp_timer!($inst); | ||
| 944 | impl BasicInstance for crate::peripherals::$inst {} | 200 | impl BasicInstance for crate::peripherals::$inst {} |
| 945 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 201 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 946 | /// Enable timer outputs. | 202 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 947 | fn enable_outputs(&self) { | 203 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 948 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 204 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 949 | self.set_moe(true); | 205 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 950 | } | 206 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 951 | } | ||
| 952 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 953 | }; | ||
| 954 | ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { | ||
| 955 | impl_adv_timer!($inst, $irq); | ||
| 956 | }; | 207 | }; |
| 957 | 208 | ||
| 958 | |||
| 959 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 209 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 960 | impl_core_timer!($inst, $irq); | 210 | impl_core_timer!($inst, TimerBits::Bits16); |
| 961 | impl_basic_no_cr2_timer!($inst); | 211 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 962 | impl_basic_timer!($inst); | ||
| 963 | impl_1ch_timer!($inst); | ||
| 964 | impl_2ch_timer!($inst); | ||
| 965 | impl_gp16_timer!($inst); | ||
| 966 | impl_1ch_cmp_timer!($inst); | ||
| 967 | impl_2ch_cmp_timer!($inst); | ||
| 968 | impl BasicInstance for crate::peripherals::$inst {} | 212 | impl BasicInstance for crate::peripherals::$inst {} |
| 969 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 213 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 970 | /// Enable timer outputs. | 214 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 971 | fn enable_outputs(&self) { | 215 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 972 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 216 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 973 | self.set_moe(true); | 217 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 974 | } | 218 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 975 | } | ||
| 976 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 977 | }; | ||
| 978 | ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { | ||
| 979 | impl_adv_timer!($inst, $irq); | ||
| 980 | }; | 219 | }; |
| 981 | } | 220 | } |
| 982 | 221 | ||
| 983 | // Update Event trigger DMA for every timer | 222 | #[cfg(not(stm32l0))] |
| 984 | dma_trait!(UpDma, BasicInstance); | 223 | #[allow(unused)] |
| 985 | 224 | fn set_moe<T: GeneralInstance4Channel>() { | |
| 986 | dma_trait!(Ch1Dma, CaptureCompare16bitInstance); | 225 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } |
| 987 | dma_trait!(Ch2Dma, CaptureCompare16bitInstance); | 226 | .bdtr() |
| 988 | dma_trait!(Ch3Dma, CaptureCompare16bitInstance); | 227 | .modify(|w| w.set_moe(true)); |
| 989 | 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 6df2f66ec..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,15 +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); |
| 85 | this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details | 80 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 86 | this.inner.start(); | 81 | this.inner.start(); |
| 87 | 82 | ||
| 88 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 83 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| @@ -127,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 127 | /// Get max duty value. | 122 | /// Get max duty value. |
| 128 | /// | 123 | /// |
| 129 | /// 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. |
| 130 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u32 { |
| 131 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 132 | } | 127 | } |
| 133 | 128 | ||
| 134 | /// Set the duty for a given channel. | 129 | /// Set the duty for a given channel. |
| 135 | /// | 130 | /// |
| 136 | /// 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. |
| 137 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 138 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 139 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 140 | } | 135 | } |
| @@ -142,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 142 | /// Get the duty for a given channel. | 137 | /// Get the duty for a given channel. |
| 143 | /// | 138 | /// |
| 144 | /// 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. |
| 145 | pub fn get_duty(&self, channel: Channel) -> u16 { | 140 | pub fn get_duty(&self, channel: Channel) -> u32 { |
| 146 | self.inner.get_compare_value(channel) | 141 | self.inner.get_compare_value(channel) |
| 147 | } | 142 | } |
| 148 | 143 | ||
| @@ -166,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 166 | channel: Channel, | 161 | channel: Channel, |
| 167 | duty: &[u16], | 162 | duty: &[u16], |
| 168 | ) { | 163 | ) { |
| 169 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 170 | |||
| 171 | into_ref!(dma); | 164 | into_ref!(dma); |
| 172 | 165 | ||
| 173 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 166 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| @@ -202,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 202 | &mut dma, | 195 | &mut dma, |
| 203 | req, | 196 | req, |
| 204 | duty, | 197 | duty, |
| 205 | T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, | 198 | self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, |
| 206 | dma_transfer_option, | 199 | dma_transfer_option, |
| 207 | ) | 200 | ) |
| 208 | .await | 201 | .await |
| @@ -228,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 228 | 221 | ||
| 229 | macro_rules! impl_waveform_chx { | 222 | macro_rules! impl_waveform_chx { |
| 230 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { | 223 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { |
| 231 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 224 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 232 | /// Generate a sequence of PWM waveform | 225 | /// Generate a sequence of PWM waveform |
| 233 | /// | 226 | /// |
| 234 | /// Note: | 227 | /// Note: |
| 235 | /// 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. |
| 236 | 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]) { |
| 237 | use super::vals::Ccds; | 230 | use crate::pac::timer::vals::Ccds; |
| 238 | |||
| 239 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 240 | 231 | ||
| 241 | into_ref!(dma); | 232 | into_ref!(dma); |
| 242 | 233 | ||
| 243 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 234 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 244 | let req = dma.request(); | 235 | let req = dma.request(); |
| 245 | 236 | ||
| 246 | let cc_channel = super::Channel::$cc_ch; | 237 | let cc_channel = Channel::$cc_ch; |
| 247 | 238 | ||
| 248 | let original_duty_state = self.get_duty(cc_channel); | 239 | let original_duty_state = self.get_duty(cc_channel); |
| 249 | let original_enable_state = self.is_enabled(cc_channel); | 240 | let original_enable_state = self.is_enabled(cc_channel); |
| @@ -280,7 +271,7 @@ macro_rules! impl_waveform_chx { | |||
| 280 | &mut dma, | 271 | &mut dma, |
| 281 | req, | 272 | req, |
| 282 | duty, | 273 | duty, |
| 283 | T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, | 274 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, |
| 284 | dma_transfer_option, | 275 | dma_transfer_option, |
| 285 | ) | 276 | ) |
| 286 | .await | 277 | .await |
| @@ -315,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); | |||
| 315 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); | 306 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); |
| 316 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); | 307 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); |
| 317 | 308 | ||
| 318 | 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> { |
| 319 | type Channel = Channel; | 310 | type Channel = Channel; |
| 320 | type Time = Hertz; | 311 | type Time = Hertz; |
| 321 | type Duty = u16; | 312 | type Duty = u32; |
| 322 | 313 | ||
| 323 | fn disable(&mut self, channel: Self::Channel) { | 314 | fn disable(&mut self, channel: Self::Channel) { |
| 324 | 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 index 9c37d2c04..fe614b811 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs | |||
| @@ -16,11 +16,12 @@ | |||
| 16 | 16 | ||
| 17 | use core::future::poll_fn; | 17 | use core::future::poll_fn; |
| 18 | use core::marker::PhantomData; | 18 | use core::marker::PhantomData; |
| 19 | use core::sync::atomic::Ordering; | 19 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 20 | use core::task::Poll; | 20 | use core::task::Poll; |
| 21 | 21 | ||
| 22 | use embassy_hal_internal::drop::OnDrop; | 22 | use embassy_hal_internal::drop::OnDrop; |
| 23 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 23 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| 24 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 24 | 25 | ||
| 25 | use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; | 26 | use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; |
| 26 | use crate::interrupt; | 27 | use crate::interrupt; |
| @@ -555,50 +556,47 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 555 | } | 556 | } |
| 556 | } | 557 | } |
| 557 | 558 | ||
| 558 | /// UCPD instance trait. | 559 | struct State { |
| 559 | pub trait Instance: sealed::Instance + RccPeripheral {} | 560 | waker: AtomicWaker, |
| 560 | 561 | // Inverted logic for a default state of 0 so that the data goes into the .bss section. | |
| 561 | mod sealed { | 562 | drop_not_ready: AtomicBool, |
| 562 | use core::sync::atomic::AtomicBool; | 563 | } |
| 563 | |||
| 564 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 565 | |||
| 566 | pub struct State { | ||
| 567 | pub waker: AtomicWaker, | ||
| 568 | // Inverted logic for a default state of 0 so that the data goes into the .bss section. | ||
| 569 | pub drop_not_ready: AtomicBool, | ||
| 570 | } | ||
| 571 | 564 | ||
| 572 | impl State { | 565 | impl State { |
| 573 | pub const fn new() -> Self { | 566 | pub const fn new() -> Self { |
| 574 | Self { | 567 | Self { |
| 575 | waker: AtomicWaker::new(), | 568 | waker: AtomicWaker::new(), |
| 576 | drop_not_ready: AtomicBool::new(false), | 569 | drop_not_ready: AtomicBool::new(false), |
| 577 | } | ||
| 578 | } | 570 | } |
| 579 | } | 571 | } |
| 572 | } | ||
| 580 | 573 | ||
| 581 | pub trait Instance { | 574 | trait SealedInstance { |
| 582 | type Interrupt: crate::interrupt::typelevel::Interrupt; | 575 | const REGS: crate::pac::ucpd::Ucpd; |
| 583 | const REGS: crate::pac::ucpd::Ucpd; | 576 | fn state() -> &'static State; |
| 584 | fn state() -> &'static crate::ucpd::sealed::State; | 577 | } |
| 585 | } | 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; | ||
| 586 | } | 584 | } |
| 587 | 585 | ||
| 588 | foreach_interrupt!( | 586 | foreach_interrupt!( |
| 589 | ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => { | 587 | ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => { |
| 590 | impl sealed::Instance for crate::peripherals::$inst { | 588 | impl SealedInstance for crate::peripherals::$inst { |
| 591 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 592 | |||
| 593 | const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; | 589 | const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst; |
| 594 | 590 | ||
| 595 | fn state() -> &'static crate::ucpd::sealed::State { | 591 | fn state() -> &'static State { |
| 596 | static STATE: crate::ucpd::sealed::State = crate::ucpd::sealed::State::new(); | 592 | static STATE: State = State::new(); |
| 597 | &STATE | 593 | &STATE |
| 598 | } | 594 | } |
| 599 | } | 595 | } |
| 600 | 596 | ||
| 601 | impl Instance for crate::peripherals::$inst {} | 597 | impl Instance for crate::peripherals::$inst { |
| 598 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 599 | } | ||
| 602 | }; | 600 | }; |
| 603 | ); | 601 | ); |
| 604 | 602 | ||
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 788f61f16..1e3c44167 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -6,7 +6,7 @@ mod _version; | |||
| 6 | pub use _version::*; | 6 | pub use _version::*; |
| 7 | 7 | ||
| 8 | use crate::interrupt::typelevel::Interrupt; | 8 | use crate::interrupt::typelevel::Interrupt; |
| 9 | use crate::rcc::sealed::RccPeripheral; | 9 | use crate::rcc::SealedRccPeripheral; |
| 10 | 10 | ||
| 11 | /// clock, power initialization stuff that's common for USB and OTG. | 11 | /// clock, power initialization stuff that's common for USB and OTG. |
| 12 | fn common_init<T: Instance>() { | 12 | fn common_init<T: Instance>() { |
| @@ -65,5 +65,5 @@ fn common_init<T: Instance>() { | |||
| 65 | T::Interrupt::unpend(); | 65 | T::Interrupt::unpend(); |
| 66 | unsafe { T::Interrupt::enable() }; | 66 | unsafe { T::Interrupt::enable() }; |
| 67 | 67 | ||
| 68 | <T as RccPeripheral>::enable_and_reset(); | 68 | <T as SealedRccPeripheral>::enable_and_reset(); |
| 69 | } | 69 | } |
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 80a08f3c5..b0e7067bd 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -6,16 +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 crate::gpio::sealed::AFType; | 14 | use crate::gpio::AFType; |
| 15 | use crate::interrupt; | 15 | use crate::interrupt; |
| 16 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::pac::otg::{regs, vals}; | 17 | use crate::pac::otg::{regs, vals}; |
| 18 | use crate::rcc::sealed::RccPeripheral; | 18 | use crate::rcc::{RccPeripheral, SealedRccPeripheral}; |
| 19 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| 20 | 20 | ||
| 21 | /// Interrupt handler. | 21 | /// Interrupt handler. |
| @@ -809,7 +809,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 809 | fn disable(&mut self) { | 809 | fn disable(&mut self) { |
| 810 | T::Interrupt::disable(); | 810 | T::Interrupt::disable(); |
| 811 | 811 | ||
| 812 | <T as RccPeripheral>::disable(); | 812 | <T as SealedRccPeripheral>::disable(); |
| 813 | 813 | ||
| 814 | #[cfg(stm32l4)] | 814 | #[cfg(stm32l4)] |
| 815 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); | 815 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); |
| @@ -1436,19 +1436,18 @@ fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { | |||
| 1436 | // Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps | 1436 | // Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps |
| 1437 | const MAX_EP_COUNT: usize = 9; | 1437 | const MAX_EP_COUNT: usize = 9; |
| 1438 | 1438 | ||
| 1439 | pub(crate) mod sealed { | 1439 | trait SealedInstance { |
| 1440 | pub trait Instance { | 1440 | const HIGH_SPEED: bool; |
| 1441 | const HIGH_SPEED: bool; | 1441 | const FIFO_DEPTH_WORDS: u16; |
| 1442 | const FIFO_DEPTH_WORDS: u16; | 1442 | const ENDPOINT_COUNT: usize; |
| 1443 | const ENDPOINT_COUNT: usize; | ||
| 1444 | 1443 | ||
| 1445 | fn regs() -> crate::pac::otg::Otg; | 1444 | fn regs() -> crate::pac::otg::Otg; |
| 1446 | fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>; | 1445 | fn state() -> &'static super::State<{ MAX_EP_COUNT }>; |
| 1447 | } | ||
| 1448 | } | 1446 | } |
| 1449 | 1447 | ||
| 1450 | /// USB instance trait. | 1448 | /// USB instance trait. |
| 1451 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 1449 | #[allow(private_bounds)] |
| 1450 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 1452 | /// Interrupt for this USB instance. | 1451 | /// Interrupt for this USB instance. |
| 1453 | type Interrupt: interrupt::typelevel::Interrupt; | 1452 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1454 | } | 1453 | } |
| @@ -1473,7 +1472,7 @@ pin_trait!(UlpiD7Pin, Instance); | |||
| 1473 | 1472 | ||
| 1474 | foreach_interrupt!( | 1473 | foreach_interrupt!( |
| 1475 | (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { | 1474 | (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => { |
| 1476 | impl sealed::Instance for crate::peripherals::USB_OTG_FS { | 1475 | impl SealedInstance for crate::peripherals::USB_OTG_FS { |
| 1477 | const HIGH_SPEED: bool = false; | 1476 | const HIGH_SPEED: bool = false; |
| 1478 | 1477 | ||
| 1479 | cfg_if::cfg_if! { | 1478 | cfg_if::cfg_if! { |
| @@ -1538,7 +1537,7 @@ foreach_interrupt!( | |||
| 1538 | }; | 1537 | }; |
| 1539 | 1538 | ||
| 1540 | (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { | 1539 | (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => { |
| 1541 | impl sealed::Instance for crate::peripherals::USB_OTG_HS { | 1540 | impl SealedInstance for crate::peripherals::USB_OTG_HS { |
| 1542 | const HIGH_SPEED: bool = true; | 1541 | const HIGH_SPEED: bool = true; |
| 1543 | 1542 | ||
| 1544 | cfg_if::cfg_if! { | 1543 | cfg_if::cfg_if! { |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 1fb2c9ebb..f48808cb3 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -15,7 +15,7 @@ use embassy_usb_driver::{ | |||
| 15 | use crate::pac::usb::regs; | 15 | use crate::pac::usb::regs; |
| 16 | use crate::pac::usb::vals::{EpType, Stat}; | 16 | use crate::pac::usb::vals::{EpType, Stat}; |
| 17 | use crate::pac::USBRAM; | 17 | use crate::pac::USBRAM; |
| 18 | use crate::rcc::sealed::RccPeripheral; | 18 | use crate::rcc::RccPeripheral; |
| 19 | use crate::{interrupt, Peripheral}; | 19 | use crate::{interrupt, Peripheral}; |
| 20 | 20 | ||
| 21 | /// Interrupt handler. | 21 | /// Interrupt handler. |
| @@ -277,8 +277,8 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 277 | 277 | ||
| 278 | #[cfg(not(stm32l1))] | 278 | #[cfg(not(stm32l1))] |
| 279 | { | 279 | { |
| 280 | dp.set_as_af(dp.af_num(), crate::gpio::sealed::AFType::OutputPushPull); | 280 | dp.set_as_af(dp.af_num(), crate::gpio::AFType::OutputPushPull); |
| 281 | dm.set_as_af(dm.af_num(), crate::gpio::sealed::AFType::OutputPushPull); | 281 | dm.set_as_af(dm.af_num(), crate::gpio::AFType::OutputPushPull); |
| 282 | } | 282 | } |
| 283 | #[cfg(stm32l1)] | 283 | #[cfg(stm32l1)] |
| 284 | let _ = (dp, dm); // suppress "unused" warnings. | 284 | let _ = (dp, dm); // suppress "unused" warnings. |
| @@ -637,7 +637,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 637 | 637 | ||
| 638 | trait Dir { | 638 | trait Dir { |
| 639 | fn dir() -> Direction; | 639 | fn dir() -> Direction; |
| 640 | fn waker(i: usize) -> &'static AtomicWaker; | ||
| 641 | } | 640 | } |
| 642 | 641 | ||
| 643 | /// Marker type for the "IN" direction. | 642 | /// Marker type for the "IN" direction. |
| @@ -646,11 +645,6 @@ impl Dir for In { | |||
| 646 | fn dir() -> Direction { | 645 | fn dir() -> Direction { |
| 647 | Direction::In | 646 | Direction::In |
| 648 | } | 647 | } |
| 649 | |||
| 650 | #[inline] | ||
| 651 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 652 | &EP_IN_WAKERS[i] | ||
| 653 | } | ||
| 654 | } | 648 | } |
| 655 | 649 | ||
| 656 | /// Marker type for the "OUT" direction. | 650 | /// Marker type for the "OUT" direction. |
| @@ -659,11 +653,6 @@ impl Dir for Out { | |||
| 659 | fn dir() -> Direction { | 653 | fn dir() -> Direction { |
| 660 | Direction::Out | 654 | Direction::Out |
| 661 | } | 655 | } |
| 662 | |||
| 663 | #[inline] | ||
| 664 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 665 | &EP_OUT_WAKERS[i] | ||
| 666 | } | ||
| 667 | } | 656 | } |
| 668 | 657 | ||
| 669 | /// USB endpoint. | 658 | /// USB endpoint. |
| @@ -1048,14 +1037,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1048 | } | 1037 | } |
| 1049 | } | 1038 | } |
| 1050 | 1039 | ||
| 1051 | pub(crate) mod sealed { | 1040 | trait SealedInstance { |
| 1052 | pub trait Instance { | 1041 | fn regs() -> crate::pac::usb::Usb; |
| 1053 | fn regs() -> crate::pac::usb::Usb; | ||
| 1054 | } | ||
| 1055 | } | 1042 | } |
| 1056 | 1043 | ||
| 1057 | /// USB instance trait. | 1044 | /// USB instance trait. |
| 1058 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 1045 | #[allow(private_bounds)] |
| 1046 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | ||
| 1059 | /// Interrupt for this USB instance. | 1047 | /// Interrupt for this USB instance. |
| 1060 | type Interrupt: interrupt::typelevel::Interrupt; | 1048 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1061 | } | 1049 | } |
| @@ -1066,7 +1054,7 @@ pin_trait!(DmPin, Instance); | |||
| 1066 | 1054 | ||
| 1067 | foreach_interrupt!( | 1055 | foreach_interrupt!( |
| 1068 | ($inst:ident, usb, $block:ident, LP, $irq:ident) => { | 1056 | ($inst:ident, usb, $block:ident, LP, $irq:ident) => { |
| 1069 | impl sealed::Instance for crate::peripherals::$inst { | 1057 | impl SealedInstance for crate::peripherals::$inst { |
| 1070 | fn regs() -> crate::pac::usb::Usb { | 1058 | fn regs() -> crate::pac::usb::Usb { |
| 1071 | crate::pac::$inst | 1059 | crate::pac::$inst |
| 1072 | } | 1060 | } |
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/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..d30eee30b --- /dev/null +++ b/embassy-sync/src/semaphore.rs | |||
| @@ -0,0 +1,772 @@ | |||
| 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, Future}; | ||
| 5 | use core::task::{Poll, Waker}; | ||
| 6 | |||
| 7 | use heapless::Deque; | ||
| 8 | |||
| 9 | use crate::blocking_mutex::raw::RawMutex; | ||
| 10 | use crate::blocking_mutex::Mutex; | ||
| 11 | use crate::waitqueue::WakerRegistration; | ||
| 12 | |||
| 13 | /// An asynchronous semaphore. | ||
| 14 | /// | ||
| 15 | /// A semaphore tracks a number of permits, typically representing a pool of shared resources. | ||
| 16 | /// Users can acquire permits to synchronize access to those resources. The semaphore does not | ||
| 17 | /// contain the resources themselves, only the count of available permits. | ||
| 18 | pub trait Semaphore: Sized { | ||
| 19 | /// The error returned when the semaphore is unable to acquire the requested permits. | ||
| 20 | type Error; | ||
| 21 | |||
| 22 | /// Asynchronously acquire one or more permits from the semaphore. | ||
| 23 | async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>; | ||
| 24 | |||
| 25 | /// Try to immediately acquire one or more permits from the semaphore. | ||
| 26 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>>; | ||
| 27 | |||
| 28 | /// Asynchronously acquire all permits controlled by the semaphore. | ||
| 29 | /// | ||
| 30 | /// This method will wait until at least `min` permits are available, then acquire all available permits | ||
| 31 | /// from the semaphore. Note that other tasks may have already acquired some permits which could be released | ||
| 32 | /// back to the semaphore at any time. The number of permits actually acquired may be determined by calling | ||
| 33 | /// [`SemaphoreReleaser::permits`]. | ||
| 34 | async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>; | ||
| 35 | |||
| 36 | /// Try to immediately acquire all available permits from the semaphore, if at least `min` permits are available. | ||
| 37 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>>; | ||
| 38 | |||
| 39 | /// Release `permits` back to the semaphore, making them available to be acquired. | ||
| 40 | fn release(&self, permits: usize); | ||
| 41 | |||
| 42 | /// Reset the number of available permints in the semaphore to `permits`. | ||
| 43 | fn set(&self, permits: usize); | ||
| 44 | } | ||
| 45 | |||
| 46 | /// A representation of a number of acquired permits. | ||
| 47 | /// | ||
| 48 | /// The acquired permits will be released back to the [`Semaphore`] when this is dropped. | ||
| 49 | pub struct SemaphoreReleaser<'a, S: Semaphore> { | ||
| 50 | semaphore: &'a S, | ||
| 51 | permits: usize, | ||
| 52 | } | ||
| 53 | |||
| 54 | impl<'a, S: Semaphore> Drop for SemaphoreReleaser<'a, S> { | ||
| 55 | fn drop(&mut self) { | ||
| 56 | self.semaphore.release(self.permits); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | impl<'a, S: Semaphore> SemaphoreReleaser<'a, S> { | ||
| 61 | /// The number of acquired permits. | ||
| 62 | pub fn permits(&self) -> usize { | ||
| 63 | self.permits | ||
| 64 | } | ||
| 65 | |||
| 66 | /// Prevent the acquired permits from being released on drop. | ||
| 67 | /// | ||
| 68 | /// Returns the number of acquired permits. | ||
| 69 | pub fn disarm(self) -> usize { | ||
| 70 | let permits = self.permits; | ||
| 71 | core::mem::forget(self); | ||
| 72 | permits | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// A greedy [`Semaphore`] implementation. | ||
| 77 | /// | ||
| 78 | /// Tasks can acquire permits as soon as they become available, even if another task | ||
| 79 | /// is waiting on a larger number of permits. | ||
| 80 | pub struct GreedySemaphore<M: RawMutex> { | ||
| 81 | state: Mutex<M, Cell<SemaphoreState>>, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<M: RawMutex> Default for GreedySemaphore<M> { | ||
| 85 | fn default() -> Self { | ||
| 86 | Self::new(0) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | impl<M: RawMutex> GreedySemaphore<M> { | ||
| 91 | /// Create a new `Semaphore`. | ||
| 92 | pub const fn new(permits: usize) -> Self { | ||
| 93 | Self { | ||
| 94 | state: Mutex::new(Cell::new(SemaphoreState { | ||
| 95 | permits, | ||
| 96 | waker: WakerRegistration::new(), | ||
| 97 | })), | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | #[cfg(test)] | ||
| 102 | fn permits(&self) -> usize { | ||
| 103 | self.state.lock(|cell| { | ||
| 104 | let state = cell.replace(SemaphoreState::EMPTY); | ||
| 105 | let permits = state.permits; | ||
| 106 | cell.replace(state); | ||
| 107 | permits | ||
| 108 | }) | ||
| 109 | } | ||
| 110 | |||
| 111 | fn poll_acquire( | ||
| 112 | &self, | ||
| 113 | permits: usize, | ||
| 114 | acquire_all: bool, | ||
| 115 | waker: Option<&Waker>, | ||
| 116 | ) -> Poll<Result<SemaphoreReleaser<'_, Self>, Infallible>> { | ||
| 117 | self.state.lock(|cell| { | ||
| 118 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 119 | if let Some(permits) = state.take(permits, acquire_all) { | ||
| 120 | cell.set(state); | ||
| 121 | Poll::Ready(Ok(SemaphoreReleaser { | ||
| 122 | semaphore: self, | ||
| 123 | permits, | ||
| 124 | })) | ||
| 125 | } else { | ||
| 126 | if let Some(waker) = waker { | ||
| 127 | state.register(waker); | ||
| 128 | } | ||
| 129 | cell.set(state); | ||
| 130 | Poll::Pending | ||
| 131 | } | ||
| 132 | }) | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | impl<M: RawMutex> Semaphore for GreedySemaphore<M> { | ||
| 137 | type Error = Infallible; | ||
| 138 | |||
| 139 | async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 140 | poll_fn(|cx| self.poll_acquire(permits, false, Some(cx.waker()))).await | ||
| 141 | } | ||
| 142 | |||
| 143 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 144 | match self.poll_acquire(permits, false, None) { | ||
| 145 | Poll::Ready(Ok(n)) => Some(n), | ||
| 146 | _ => None, | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> { | ||
| 151 | poll_fn(|cx| self.poll_acquire(min, true, Some(cx.waker()))).await | ||
| 152 | } | ||
| 153 | |||
| 154 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 155 | match self.poll_acquire(min, true, None) { | ||
| 156 | Poll::Ready(Ok(n)) => Some(n), | ||
| 157 | _ => None, | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | fn release(&self, permits: usize) { | ||
| 162 | if permits > 0 { | ||
| 163 | self.state.lock(|cell| { | ||
| 164 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 165 | state.permits += permits; | ||
| 166 | state.wake(); | ||
| 167 | cell.set(state); | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | fn set(&self, permits: usize) { | ||
| 173 | self.state.lock(|cell| { | ||
| 174 | let mut state = cell.replace(SemaphoreState::EMPTY); | ||
| 175 | if permits > state.permits { | ||
| 176 | state.wake(); | ||
| 177 | } | ||
| 178 | state.permits = permits; | ||
| 179 | cell.set(state); | ||
| 180 | }); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | struct SemaphoreState { | ||
| 185 | permits: usize, | ||
| 186 | waker: WakerRegistration, | ||
| 187 | } | ||
| 188 | |||
| 189 | impl SemaphoreState { | ||
| 190 | const EMPTY: SemaphoreState = SemaphoreState { | ||
| 191 | permits: 0, | ||
| 192 | waker: WakerRegistration::new(), | ||
| 193 | }; | ||
| 194 | |||
| 195 | fn register(&mut self, w: &Waker) { | ||
| 196 | self.waker.register(w); | ||
| 197 | } | ||
| 198 | |||
| 199 | fn take(&mut self, mut permits: usize, acquire_all: bool) -> Option<usize> { | ||
| 200 | if self.permits < permits { | ||
| 201 | None | ||
| 202 | } else { | ||
| 203 | if acquire_all { | ||
| 204 | permits = self.permits; | ||
| 205 | } | ||
| 206 | self.permits -= permits; | ||
| 207 | Some(permits) | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | fn wake(&mut self) { | ||
| 212 | self.waker.wake(); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | /// A fair [`Semaphore`] implementation. | ||
| 217 | /// | ||
| 218 | /// Tasks are allowed to acquire permits in FIFO order. A task waiting to acquire | ||
| 219 | /// a large number of permits will prevent other tasks from acquiring any permits | ||
| 220 | /// until its request is satisfied. | ||
| 221 | /// | ||
| 222 | /// Up to `N` tasks may attempt to acquire permits concurrently. If additional | ||
| 223 | /// tasks attempt to acquire a permit, a [`WaitQueueFull`] error will be returned. | ||
| 224 | pub struct FairSemaphore<M, const N: usize> | ||
| 225 | where | ||
| 226 | M: RawMutex, | ||
| 227 | { | ||
| 228 | state: Mutex<M, RefCell<FairSemaphoreState<N>>>, | ||
| 229 | } | ||
| 230 | |||
| 231 | impl<M, const N: usize> Default for FairSemaphore<M, N> | ||
| 232 | where | ||
| 233 | M: RawMutex, | ||
| 234 | { | ||
| 235 | fn default() -> Self { | ||
| 236 | Self::new(0) | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | impl<M, const N: usize> FairSemaphore<M, N> | ||
| 241 | where | ||
| 242 | M: RawMutex, | ||
| 243 | { | ||
| 244 | /// Create a new `FairSemaphore`. | ||
| 245 | pub const fn new(permits: usize) -> Self { | ||
| 246 | Self { | ||
| 247 | state: Mutex::new(RefCell::new(FairSemaphoreState::new(permits))), | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | #[cfg(test)] | ||
| 252 | fn permits(&self) -> usize { | ||
| 253 | self.state.lock(|cell| cell.borrow().permits) | ||
| 254 | } | ||
| 255 | |||
| 256 | fn poll_acquire( | ||
| 257 | &self, | ||
| 258 | permits: usize, | ||
| 259 | acquire_all: bool, | ||
| 260 | cx: Option<(&mut Option<usize>, &Waker)>, | ||
| 261 | ) -> Poll<Result<SemaphoreReleaser<'_, Self>, WaitQueueFull>> { | ||
| 262 | let ticket = cx.as_ref().map(|(x, _)| **x).unwrap_or(None); | ||
| 263 | self.state.lock(|cell| { | ||
| 264 | let mut state = cell.borrow_mut(); | ||
| 265 | if let Some(permits) = state.take(ticket, permits, acquire_all) { | ||
| 266 | Poll::Ready(Ok(SemaphoreReleaser { | ||
| 267 | semaphore: self, | ||
| 268 | permits, | ||
| 269 | })) | ||
| 270 | } else if let Some((ticket_ref, waker)) = cx { | ||
| 271 | match state.register(ticket, waker) { | ||
| 272 | Ok(ticket) => { | ||
| 273 | *ticket_ref = Some(ticket); | ||
| 274 | Poll::Pending | ||
| 275 | } | ||
| 276 | Err(err) => Poll::Ready(Err(err)), | ||
| 277 | } | ||
| 278 | } else { | ||
| 279 | Poll::Pending | ||
| 280 | } | ||
| 281 | }) | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | /// An error indicating the [`FairSemaphore`]'s wait queue is full. | ||
| 286 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 287 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 288 | pub struct WaitQueueFull; | ||
| 289 | |||
| 290 | impl<M: RawMutex, const N: usize> Semaphore for FairSemaphore<M, N> { | ||
| 291 | type Error = WaitQueueFull; | ||
| 292 | |||
| 293 | fn acquire(&self, permits: usize) -> impl Future<Output = Result<SemaphoreReleaser<'_, Self>, Self::Error>> { | ||
| 294 | FairAcquire { | ||
| 295 | sema: self, | ||
| 296 | permits, | ||
| 297 | ticket: None, | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 302 | match self.poll_acquire(permits, false, None) { | ||
| 303 | Poll::Ready(Ok(x)) => Some(x), | ||
| 304 | _ => None, | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | fn acquire_all(&self, min: usize) -> impl Future<Output = Result<SemaphoreReleaser<'_, Self>, Self::Error>> { | ||
| 309 | FairAcquireAll { | ||
| 310 | sema: self, | ||
| 311 | min, | ||
| 312 | ticket: None, | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> { | ||
| 317 | match self.poll_acquire(min, true, None) { | ||
| 318 | Poll::Ready(Ok(x)) => Some(x), | ||
| 319 | _ => None, | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | fn release(&self, permits: usize) { | ||
| 324 | if permits > 0 { | ||
| 325 | self.state.lock(|cell| { | ||
| 326 | let mut state = cell.borrow_mut(); | ||
| 327 | state.permits += permits; | ||
| 328 | state.wake(); | ||
| 329 | }); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | fn set(&self, permits: usize) { | ||
| 334 | self.state.lock(|cell| { | ||
| 335 | let mut state = cell.borrow_mut(); | ||
| 336 | if permits > state.permits { | ||
| 337 | state.wake(); | ||
| 338 | } | ||
| 339 | state.permits = permits; | ||
| 340 | }); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | struct FairAcquire<'a, M: RawMutex, const N: usize> { | ||
| 345 | sema: &'a FairSemaphore<M, N>, | ||
| 346 | permits: usize, | ||
| 347 | ticket: Option<usize>, | ||
| 348 | } | ||
| 349 | |||
| 350 | impl<'a, M: RawMutex, const N: usize> Drop for FairAcquire<'a, M, N> { | ||
| 351 | fn drop(&mut self) { | ||
| 352 | self.sema | ||
| 353 | .state | ||
| 354 | .lock(|cell| cell.borrow_mut().cancel(self.ticket.take())); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | impl<'a, M: RawMutex, const N: usize> core::future::Future for FairAcquire<'a, M, N> { | ||
| 359 | type Output = Result<SemaphoreReleaser<'a, FairSemaphore<M, N>>, WaitQueueFull>; | ||
| 360 | |||
| 361 | fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> Poll<Self::Output> { | ||
| 362 | self.sema | ||
| 363 | .poll_acquire(self.permits, false, Some((&mut self.ticket, cx.waker()))) | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | struct FairAcquireAll<'a, M: RawMutex, const N: usize> { | ||
| 368 | sema: &'a FairSemaphore<M, N>, | ||
| 369 | min: usize, | ||
| 370 | ticket: Option<usize>, | ||
| 371 | } | ||
| 372 | |||
| 373 | impl<'a, M: RawMutex, const N: usize> Drop for FairAcquireAll<'a, M, N> { | ||
| 374 | fn drop(&mut self) { | ||
| 375 | self.sema | ||
| 376 | .state | ||
| 377 | .lock(|cell| cell.borrow_mut().cancel(self.ticket.take())); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | impl<'a, M: RawMutex, const N: usize> core::future::Future for FairAcquireAll<'a, M, N> { | ||
| 382 | type Output = Result<SemaphoreReleaser<'a, FairSemaphore<M, N>>, WaitQueueFull>; | ||
| 383 | |||
| 384 | fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> Poll<Self::Output> { | ||
| 385 | self.sema | ||
| 386 | .poll_acquire(self.min, true, Some((&mut self.ticket, cx.waker()))) | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | struct FairSemaphoreState<const N: usize> { | ||
| 391 | permits: usize, | ||
| 392 | next_ticket: usize, | ||
| 393 | wakers: Deque<Option<Waker>, N>, | ||
| 394 | } | ||
| 395 | |||
| 396 | impl<const N: usize> FairSemaphoreState<N> { | ||
| 397 | /// Create a new empty instance | ||
| 398 | const fn new(permits: usize) -> Self { | ||
| 399 | Self { | ||
| 400 | permits, | ||
| 401 | next_ticket: 0, | ||
| 402 | wakers: Deque::new(), | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | /// Register a waker. If the queue is full the function returns an error | ||
| 407 | fn register(&mut self, ticket: Option<usize>, w: &Waker) -> Result<usize, WaitQueueFull> { | ||
| 408 | self.pop_canceled(); | ||
| 409 | |||
| 410 | match ticket { | ||
| 411 | None => { | ||
| 412 | let ticket = self.next_ticket.wrapping_add(self.wakers.len()); | ||
| 413 | self.wakers.push_back(Some(w.clone())).or(Err(WaitQueueFull))?; | ||
| 414 | Ok(ticket) | ||
| 415 | } | ||
| 416 | Some(ticket) => { | ||
| 417 | self.set_waker(ticket, Some(w.clone())); | ||
| 418 | Ok(ticket) | ||
| 419 | } | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | fn cancel(&mut self, ticket: Option<usize>) { | ||
| 424 | if let Some(ticket) = ticket { | ||
| 425 | self.set_waker(ticket, None); | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | fn set_waker(&mut self, ticket: usize, waker: Option<Waker>) { | ||
| 430 | let i = ticket.wrapping_sub(self.next_ticket); | ||
| 431 | if i < self.wakers.len() { | ||
| 432 | let (a, b) = self.wakers.as_mut_slices(); | ||
| 433 | let x = if i < a.len() { &mut a[i] } else { &mut b[i - a.len()] }; | ||
| 434 | *x = waker; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | fn take(&mut self, ticket: Option<usize>, mut permits: usize, acquire_all: bool) -> Option<usize> { | ||
| 439 | self.pop_canceled(); | ||
| 440 | |||
| 441 | if permits > self.permits { | ||
| 442 | return None; | ||
| 443 | } | ||
| 444 | |||
| 445 | match ticket { | ||
| 446 | Some(n) if n != self.next_ticket => return None, | ||
| 447 | None if !self.wakers.is_empty() => return None, | ||
| 448 | _ => (), | ||
| 449 | } | ||
| 450 | |||
| 451 | if acquire_all { | ||
| 452 | permits = self.permits; | ||
| 453 | } | ||
| 454 | self.permits -= permits; | ||
| 455 | |||
| 456 | if ticket.is_some() { | ||
| 457 | self.pop(); | ||
| 458 | if self.permits > 0 { | ||
| 459 | self.wake(); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | Some(permits) | ||
| 464 | } | ||
| 465 | |||
| 466 | fn pop_canceled(&mut self) { | ||
| 467 | while let Some(None) = self.wakers.front() { | ||
| 468 | self.pop(); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | /// Panics if `self.wakers` is empty | ||
| 473 | fn pop(&mut self) { | ||
| 474 | self.wakers.pop_front().unwrap(); | ||
| 475 | self.next_ticket = self.next_ticket.wrapping_add(1); | ||
| 476 | } | ||
| 477 | |||
| 478 | fn wake(&mut self) { | ||
| 479 | self.pop_canceled(); | ||
| 480 | |||
| 481 | if let Some(Some(waker)) = self.wakers.front() { | ||
| 482 | waker.wake_by_ref(); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | #[cfg(test)] | ||
| 488 | mod tests { | ||
| 489 | mod greedy { | ||
| 490 | use core::pin::pin; | ||
| 491 | |||
| 492 | use futures_util::poll; | ||
| 493 | |||
| 494 | use super::super::*; | ||
| 495 | use crate::blocking_mutex::raw::NoopRawMutex; | ||
| 496 | |||
| 497 | #[test] | ||
| 498 | fn try_acquire() { | ||
| 499 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 500 | |||
| 501 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 502 | assert_eq!(a.permits(), 1); | ||
| 503 | assert_eq!(semaphore.permits(), 2); | ||
| 504 | |||
| 505 | core::mem::drop(a); | ||
| 506 | assert_eq!(semaphore.permits(), 3); | ||
| 507 | } | ||
| 508 | |||
| 509 | #[test] | ||
| 510 | fn disarm() { | ||
| 511 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 512 | |||
| 513 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 514 | assert_eq!(a.disarm(), 1); | ||
| 515 | assert_eq!(semaphore.permits(), 2); | ||
| 516 | } | ||
| 517 | |||
| 518 | #[futures_test::test] | ||
| 519 | async fn acquire() { | ||
| 520 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 521 | |||
| 522 | let a = semaphore.acquire(1).await.unwrap(); | ||
| 523 | assert_eq!(a.permits(), 1); | ||
| 524 | assert_eq!(semaphore.permits(), 2); | ||
| 525 | |||
| 526 | core::mem::drop(a); | ||
| 527 | assert_eq!(semaphore.permits(), 3); | ||
| 528 | } | ||
| 529 | |||
| 530 | #[test] | ||
| 531 | fn try_acquire_all() { | ||
| 532 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 533 | |||
| 534 | let a = semaphore.try_acquire_all(1).unwrap(); | ||
| 535 | assert_eq!(a.permits(), 3); | ||
| 536 | assert_eq!(semaphore.permits(), 0); | ||
| 537 | } | ||
| 538 | |||
| 539 | #[futures_test::test] | ||
| 540 | async fn acquire_all() { | ||
| 541 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 542 | |||
| 543 | let a = semaphore.acquire_all(1).await.unwrap(); | ||
| 544 | assert_eq!(a.permits(), 3); | ||
| 545 | assert_eq!(semaphore.permits(), 0); | ||
| 546 | } | ||
| 547 | |||
| 548 | #[test] | ||
| 549 | fn release() { | ||
| 550 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 551 | assert_eq!(semaphore.permits(), 3); | ||
| 552 | semaphore.release(2); | ||
| 553 | assert_eq!(semaphore.permits(), 5); | ||
| 554 | } | ||
| 555 | |||
| 556 | #[test] | ||
| 557 | fn set() { | ||
| 558 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 559 | assert_eq!(semaphore.permits(), 3); | ||
| 560 | semaphore.set(2); | ||
| 561 | assert_eq!(semaphore.permits(), 2); | ||
| 562 | } | ||
| 563 | |||
| 564 | #[test] | ||
| 565 | fn contested() { | ||
| 566 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 567 | |||
| 568 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 569 | let b = semaphore.try_acquire(3); | ||
| 570 | assert!(b.is_none()); | ||
| 571 | |||
| 572 | core::mem::drop(a); | ||
| 573 | |||
| 574 | let b = semaphore.try_acquire(3); | ||
| 575 | assert!(b.is_some()); | ||
| 576 | } | ||
| 577 | |||
| 578 | #[futures_test::test] | ||
| 579 | async fn greedy() { | ||
| 580 | let semaphore = GreedySemaphore::<NoopRawMutex>::new(3); | ||
| 581 | |||
| 582 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 583 | |||
| 584 | let b_fut = semaphore.acquire(3); | ||
| 585 | let mut b_fut = pin!(b_fut); | ||
| 586 | let b = poll!(b_fut.as_mut()); | ||
| 587 | assert!(b.is_pending()); | ||
| 588 | |||
| 589 | // Succeed even through `b` is waiting | ||
| 590 | let c = semaphore.try_acquire(1); | ||
| 591 | assert!(c.is_some()); | ||
| 592 | |||
| 593 | let b = poll!(b_fut.as_mut()); | ||
| 594 | assert!(b.is_pending()); | ||
| 595 | |||
| 596 | core::mem::drop(a); | ||
| 597 | |||
| 598 | let b = poll!(b_fut.as_mut()); | ||
| 599 | assert!(b.is_pending()); | ||
| 600 | |||
| 601 | core::mem::drop(c); | ||
| 602 | |||
| 603 | let b = poll!(b_fut.as_mut()); | ||
| 604 | assert!(b.is_ready()); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | mod fair { | ||
| 609 | use core::pin::pin; | ||
| 610 | use core::time::Duration; | ||
| 611 | |||
| 612 | use futures_executor::ThreadPool; | ||
| 613 | use futures_timer::Delay; | ||
| 614 | use futures_util::poll; | ||
| 615 | use futures_util::task::SpawnExt; | ||
| 616 | use static_cell::StaticCell; | ||
| 617 | |||
| 618 | use super::super::*; | ||
| 619 | use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | ||
| 620 | |||
| 621 | #[test] | ||
| 622 | fn try_acquire() { | ||
| 623 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 624 | |||
| 625 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 626 | assert_eq!(a.permits(), 1); | ||
| 627 | assert_eq!(semaphore.permits(), 2); | ||
| 628 | |||
| 629 | core::mem::drop(a); | ||
| 630 | assert_eq!(semaphore.permits(), 3); | ||
| 631 | } | ||
| 632 | |||
| 633 | #[test] | ||
| 634 | fn disarm() { | ||
| 635 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 636 | |||
| 637 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 638 | assert_eq!(a.disarm(), 1); | ||
| 639 | assert_eq!(semaphore.permits(), 2); | ||
| 640 | } | ||
| 641 | |||
| 642 | #[futures_test::test] | ||
| 643 | async fn acquire() { | ||
| 644 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 645 | |||
| 646 | let a = semaphore.acquire(1).await.unwrap(); | ||
| 647 | assert_eq!(a.permits(), 1); | ||
| 648 | assert_eq!(semaphore.permits(), 2); | ||
| 649 | |||
| 650 | core::mem::drop(a); | ||
| 651 | assert_eq!(semaphore.permits(), 3); | ||
| 652 | } | ||
| 653 | |||
| 654 | #[test] | ||
| 655 | fn try_acquire_all() { | ||
| 656 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 657 | |||
| 658 | let a = semaphore.try_acquire_all(1).unwrap(); | ||
| 659 | assert_eq!(a.permits(), 3); | ||
| 660 | assert_eq!(semaphore.permits(), 0); | ||
| 661 | } | ||
| 662 | |||
| 663 | #[futures_test::test] | ||
| 664 | async fn acquire_all() { | ||
| 665 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 666 | |||
| 667 | let a = semaphore.acquire_all(1).await.unwrap(); | ||
| 668 | assert_eq!(a.permits(), 3); | ||
| 669 | assert_eq!(semaphore.permits(), 0); | ||
| 670 | } | ||
| 671 | |||
| 672 | #[test] | ||
| 673 | fn release() { | ||
| 674 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 675 | assert_eq!(semaphore.permits(), 3); | ||
| 676 | semaphore.release(2); | ||
| 677 | assert_eq!(semaphore.permits(), 5); | ||
| 678 | } | ||
| 679 | |||
| 680 | #[test] | ||
| 681 | fn set() { | ||
| 682 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 683 | assert_eq!(semaphore.permits(), 3); | ||
| 684 | semaphore.set(2); | ||
| 685 | assert_eq!(semaphore.permits(), 2); | ||
| 686 | } | ||
| 687 | |||
| 688 | #[test] | ||
| 689 | fn contested() { | ||
| 690 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 691 | |||
| 692 | let a = semaphore.try_acquire(1).unwrap(); | ||
| 693 | let b = semaphore.try_acquire(3); | ||
| 694 | assert!(b.is_none()); | ||
| 695 | |||
| 696 | core::mem::drop(a); | ||
| 697 | |||
| 698 | let b = semaphore.try_acquire(3); | ||
| 699 | assert!(b.is_some()); | ||
| 700 | } | ||
| 701 | |||
| 702 | #[futures_test::test] | ||
| 703 | async fn fairness() { | ||
| 704 | let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3); | ||
| 705 | |||
| 706 | let a = semaphore.try_acquire(1); | ||
| 707 | assert!(a.is_some()); | ||
| 708 | |||
| 709 | let b_fut = semaphore.acquire(3); | ||
| 710 | let mut b_fut = pin!(b_fut); | ||
| 711 | let b = poll!(b_fut.as_mut()); // Poll `b_fut` once so it is registered | ||
| 712 | assert!(b.is_pending()); | ||
| 713 | |||
| 714 | let c = semaphore.try_acquire(1); | ||
| 715 | assert!(c.is_none()); | ||
| 716 | |||
| 717 | let c_fut = semaphore.acquire(1); | ||
| 718 | let mut c_fut = pin!(c_fut); | ||
| 719 | let c = poll!(c_fut.as_mut()); // Poll `c_fut` once so it is registered | ||
| 720 | assert!(c.is_pending()); // `c` is blocked behind `b` | ||
| 721 | |||
| 722 | let d = semaphore.acquire(1).await; | ||
| 723 | assert!(matches!(d, Err(WaitQueueFull))); | ||
| 724 | |||
| 725 | core::mem::drop(a); | ||
| 726 | |||
| 727 | let c = poll!(c_fut.as_mut()); | ||
| 728 | assert!(c.is_pending()); // `c` is still blocked behind `b` | ||
| 729 | |||
| 730 | let b = poll!(b_fut.as_mut()); | ||
| 731 | assert!(b.is_ready()); | ||
| 732 | |||
| 733 | let c = poll!(c_fut.as_mut()); | ||
| 734 | assert!(c.is_pending()); // `c` is still blocked behind `b` | ||
| 735 | |||
| 736 | core::mem::drop(b); | ||
| 737 | |||
| 738 | let c = poll!(c_fut.as_mut()); | ||
| 739 | assert!(c.is_ready()); | ||
| 740 | } | ||
| 741 | |||
| 742 | #[futures_test::test] | ||
| 743 | async fn wakers() { | ||
| 744 | let executor = ThreadPool::new().unwrap(); | ||
| 745 | |||
| 746 | static SEMAPHORE: StaticCell<FairSemaphore<CriticalSectionRawMutex, 2>> = StaticCell::new(); | ||
| 747 | let semaphore = &*SEMAPHORE.init(FairSemaphore::new(3)); | ||
| 748 | |||
| 749 | let a = semaphore.try_acquire(2); | ||
| 750 | assert!(a.is_some()); | ||
| 751 | |||
| 752 | let b_task = executor | ||
| 753 | .spawn_with_handle(async move { semaphore.acquire(2).await }) | ||
| 754 | .unwrap(); | ||
| 755 | while semaphore.state.lock(|x| x.borrow().wakers.is_empty()) { | ||
| 756 | Delay::new(Duration::from_millis(50)).await; | ||
| 757 | } | ||
| 758 | |||
| 759 | let c_task = executor | ||
| 760 | .spawn_with_handle(async move { semaphore.acquire(1).await }) | ||
| 761 | .unwrap(); | ||
| 762 | |||
| 763 | core::mem::drop(a); | ||
| 764 | |||
| 765 | let b = b_task.await.unwrap(); | ||
| 766 | assert_eq!(b.permits(), 2); | ||
| 767 | |||
| 768 | let c = c_task.await.unwrap(); | ||
| 769 | assert_eq!(c.permits(), 1); | ||
| 770 | } | ||
| 771 | } | ||
| 772 | } | ||
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 ac337e8a0..1c13d623d 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs | |||
| @@ -3,12 +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::frame::Envelope; | ||
| 6 | use embassy_stm32::can::{ | 7 | use embassy_stm32::can::{ |
| 7 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, | 8 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 8 | TxInterruptHandler, | 9 | TxInterruptHandler, |
| 9 | }; | 10 | }; |
| 10 | use embassy_stm32::peripherals::CAN; | 11 | use embassy_stm32::peripherals::CAN; |
| 11 | use embassy_stm32::{bind_interrupts, Config}; | 12 | use embassy_stm32::{bind_interrupts, Config}; |
| 13 | use static_cell::StaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 15 | ||
| 14 | bind_interrupts!(struct Irqs { | 16 | bind_interrupts!(struct Irqs { |
| @@ -21,6 +23,27 @@ bind_interrupts!(struct Irqs { | |||
| 21 | // 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. |
| 22 | // See other examples for loopback. | 24 | // See other examples for loopback. |
| 23 | 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 | |||
| 24 | #[embassy_executor::main] | 47 | #[embassy_executor::main] |
| 25 | async fn main(_spawner: Spawner) { | 48 | async fn main(_spawner: Spawner) { |
| 26 | let p = embassy_stm32::init(Config::default()); | 49 | let p = embassy_stm32::init(Config::default()); |
| @@ -28,36 +51,86 @@ async fn main(_spawner: Spawner) { | |||
| 28 | // Set alternate pin mapping to B8/B9 | 51 | // Set alternate pin mapping to B8/B9 |
| 29 | 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)); |
| 30 | 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 | |||
| 31 | 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); |
| 32 | 58 | ||
| 33 | can.as_mut() | 59 | can.modify_filters() |
| 34 | .modify_filters() | ||
| 35 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); | 60 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); |
| 36 | 61 | ||
| 37 | can.as_mut() | 62 | can.modify_config() |
| 38 | .modify_config() | ||
| 39 | .set_loopback(false) | 63 | .set_loopback(false) |
| 40 | .set_silent(false) | 64 | .set_silent(false) |
| 41 | .leave_disabled(); | 65 | .set_bitrate(250_000); |
| 42 | |||
| 43 | can.set_bitrate(250_000); | ||
| 44 | 66 | ||
| 45 | can.enable().await; | 67 | can.enable().await; |
| 46 | |||
| 47 | 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 | |||
| 48 | loop { | 126 | loop { |
| 49 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | 127 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); |
| 50 | can.write(&tx_frame).await; | 128 | tx.write(&tx_frame).await; |
| 51 | 129 | ||
| 52 | match can.read().await { | 130 | match rx.read().await { |
| 53 | Ok(env) => match env.frame.id() { | 131 | Ok(envelope) => { |
| 54 | Id::Extended(id) => { | 132 | handle_frame(envelope, "Buf"); |
| 55 | defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); | 133 | } |
| 56 | } | ||
| 57 | Id::Standard(id) => { | ||
| 58 | defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); | ||
| 59 | } | ||
| 60 | }, | ||
| 61 | Err(err) => { | 134 | Err(err) => { |
| 62 | defmt::println!("Error {}", err); | 135 | defmt::println!("Error {}", err); |
| 63 | } | 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 71b9453eb..cedc057a7 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs | |||
| @@ -35,17 +35,12 @@ async fn main(_spawner: Spawner) { | |||
| 35 | 35 | ||
| 36 | 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); |
| 37 | 37 | ||
| 38 | can.as_mut() | 38 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 39 | .modify_filters() | ||
| 40 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 41 | 39 | ||
| 42 | can.as_mut() | 40 | can.modify_config() |
| 43 | .modify_config() | ||
| 44 | .set_loopback(true) // Receive own frames | 41 | .set_loopback(true) // Receive own frames |
| 45 | .set_silent(true) | 42 | .set_silent(true) |
| 46 | .leave_disabled(); | 43 | .set_bitrate(1_000_000); |
| 47 | |||
| 48 | can.set_bitrate(1_000_000); | ||
| 49 | 44 | ||
| 50 | can.enable().await; | 45 | can.enable().await; |
| 51 | 46 | ||
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 405cce6bc..d2cbeea1b 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -89,14 +89,12 @@ async fn main(spawner: Spawner) { | |||
| 89 | config.device_protocol = 0x01; | 89 | config.device_protocol = 0x01; |
| 90 | 90 | ||
| 91 | // Create embassy-usb DeviceBuilder using the driver and config. | 91 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 92 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 93 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 92 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 94 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 93 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 95 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 94 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 96 | let mut builder = Builder::new( | 95 | let mut builder = Builder::new( |
| 97 | driver, | 96 | driver, |
| 98 | config, | 97 | config, |
| 99 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 100 | &mut CONFIG_DESC.init([0; 256])[..], | 98 | &mut CONFIG_DESC.init([0; 256])[..], |
| 101 | &mut BOS_DESC.init([0; 256])[..], | 99 | &mut BOS_DESC.init([0; 256])[..], |
| 102 | &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 index 6c25a0a64..a799b4e72 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs | |||
| @@ -69,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 69 | 69 | ||
| 70 | // Create embassy-usb DeviceBuilder using the driver and config. | 70 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 71 | // It needs some buffers for building the descriptors. | 71 | // It needs some buffers for building the descriptors. |
| 72 | let mut device_descriptor = [0; 256]; | ||
| 73 | let mut config_descriptor = [0; 256]; | 72 | let mut config_descriptor = [0; 256]; |
| 74 | let mut bos_descriptor = [0; 256]; | 73 | let mut bos_descriptor = [0; 256]; |
| 75 | // You can also add a Microsoft OS descriptor. | 74 | // You can also add a Microsoft OS descriptor. |
| @@ -84,7 +83,6 @@ async fn main(_spawner: Spawner) { | |||
| 84 | let mut builder = Builder::new( | 83 | let mut builder = Builder::new( |
| 85 | driver, | 84 | driver, |
| 86 | config, | 85 | config, |
| 87 | &mut device_descriptor, | ||
| 88 | &mut config_descriptor, | 86 | &mut config_descriptor, |
| 89 | &mut bos_descriptor, | 87 | &mut bos_descriptor, |
| 90 | &mut msos_descriptor, | 88 | &mut msos_descriptor, |
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index d4725d597..0bc236119 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs | |||
| @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 64 | ||
| 65 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 66 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 67 | let mut device_descriptor = [0; 256]; | ||
| 68 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 69 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 70 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -76,7 +75,6 @@ async fn main(_spawner: Spawner) { | |||
| 76 | let mut builder = Builder::new( | 75 | let mut builder = Builder::new( |
| 77 | driver, | 76 | driver, |
| 78 | config, | 77 | config, |
| 79 | &mut device_descriptor, | ||
| 80 | &mut config_descriptor, | 78 | &mut config_descriptor, |
| 81 | &mut bos_descriptor, | 79 | &mut bos_descriptor, |
| 82 | &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 15a98ff8b..4e583aeb8 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs | |||
| @@ -117,7 +117,6 @@ async fn main(_spawner: Spawner) { | |||
| 117 | 117 | ||
| 118 | // Create embassy-usb DeviceBuilder using the driver and config. | 118 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 119 | // It needs some buffers for building the descriptors. | 119 | // It needs some buffers for building the descriptors. |
| 120 | let mut device_descriptor = [0; 256]; | ||
| 121 | let mut config_descriptor = [0; 256]; | 120 | let mut config_descriptor = [0; 256]; |
| 122 | let mut bos_descriptor = [0; 256]; | 121 | let mut bos_descriptor = [0; 256]; |
| 123 | let mut msos_descriptor = [0; 256]; | 122 | let mut msos_descriptor = [0; 256]; |
| @@ -130,7 +129,6 @@ async fn main(_spawner: Spawner) { | |||
| 130 | let mut builder = Builder::new( | 129 | let mut builder = Builder::new( |
| 131 | driver, | 130 | driver, |
| 132 | config, | 131 | config, |
| 133 | &mut device_descriptor, | ||
| 134 | &mut config_descriptor, | 132 | &mut config_descriptor, |
| 135 | &mut bos_descriptor, | 133 | &mut bos_descriptor, |
| 136 | &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 6080b34a8..f3a375d31 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs | |||
| @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 64 | ||
| 65 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 66 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 67 | let mut device_descriptor = [0; 256]; | ||
| 68 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 69 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 70 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -74,7 +73,6 @@ async fn main(_spawner: Spawner) { | |||
| 74 | let mut builder = Builder::new( | 73 | let mut builder = Builder::new( |
| 75 | driver, | 74 | driver, |
| 76 | config, | 75 | config, |
| 77 | &mut device_descriptor, | ||
| 78 | &mut config_descriptor, | 76 | &mut config_descriptor, |
| 79 | &mut bos_descriptor, | 77 | &mut bos_descriptor, |
| 80 | &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 221ac2a05..e32b4d3df 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs | |||
| @@ -47,20 +47,18 @@ async fn main(spawner: Spawner) { | |||
| 47 | 47 | ||
| 48 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); | 48 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); |
| 49 | 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)); |
| 50 | can.as_mut() | 50 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 51 | .modify_filters() | ||
| 52 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 53 | 51 | ||
| 54 | can.as_mut() | 52 | can.modify_config() |
| 55 | .modify_config() | ||
| 56 | .set_bit_timing(can::util::NominalBitTiming { | 53 | .set_bit_timing(can::util::NominalBitTiming { |
| 57 | prescaler: NonZeroU16::new(2).unwrap(), | 54 | prescaler: NonZeroU16::new(2).unwrap(), |
| 58 | seg1: NonZeroU8::new(13).unwrap(), | 55 | seg1: NonZeroU8::new(13).unwrap(), |
| 59 | seg2: NonZeroU8::new(2).unwrap(), | 56 | seg2: NonZeroU8::new(2).unwrap(), |
| 60 | sync_jump_width: NonZeroU8::new(1).unwrap(), | 57 | sync_jump_width: NonZeroU8::new(1).unwrap(), |
| 61 | }) // http://www.bittiming.can-wiki.info/ | 58 | }) // http://www.bittiming.can-wiki.info/ |
| 62 | .set_loopback(true) | 59 | .set_loopback(true); |
| 63 | .enable(); | 60 | |
| 61 | can.enable().await; | ||
| 64 | 62 | ||
| 65 | let (tx, mut rx) = can.split(); | 63 | let (tx, mut rx) = can.split(); |
| 66 | 64 | ||
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 26ecf3bc8..39a5512f4 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs | |||
| @@ -64,7 +64,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 64 | ||
| 65 | // Create embassy-usb DeviceBuilder using the driver and config. | 65 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 66 | // It needs some buffers for building the descriptors. | 66 | // It needs some buffers for building the descriptors. |
| 67 | let mut device_descriptor = [0; 256]; | ||
| 68 | let mut config_descriptor = [0; 256]; | 67 | let mut config_descriptor = [0; 256]; |
| 69 | let mut bos_descriptor = [0; 256]; | 68 | let mut bos_descriptor = [0; 256]; |
| 70 | let mut control_buf = [0; 64]; | 69 | let mut control_buf = [0; 64]; |
| @@ -74,7 +73,6 @@ async fn main(_spawner: Spawner) { | |||
| 74 | let mut builder = Builder::new( | 73 | let mut builder = Builder::new( |
| 75 | driver, | 74 | driver, |
| 76 | config, | 75 | config, |
| 77 | &mut device_descriptor, | ||
| 78 | &mut config_descriptor, | 76 | &mut config_descriptor, |
| 79 | &mut bos_descriptor, | 77 | &mut bos_descriptor, |
| 80 | &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_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/Cargo.toml b/examples/stm32h7/Cargo.toml index d9ea2626d..84a89b378 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml | |||
| @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32h743bi to your chip name, if necessary. | 8 | # Change stm32h743bi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
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/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs new file mode 100644 index 000000000..73f8dd092 --- /dev/null +++ b/examples/stm32h7/src/bin/multiprio.rs | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | |||
| 59 | use cortex_m_rt::entry; | ||
| 60 | use defmt::*; | ||
| 61 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 62 | use embassy_stm32::interrupt; | ||
| 63 | use embassy_stm32::interrupt::{InterruptExt, Priority}; | ||
| 64 | use embassy_time::{Instant, Timer}; | ||
| 65 | use static_cell::StaticCell; | ||
| 66 | use {defmt_rtt as _, panic_probe as _}; | ||
| 67 | |||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn run_high() { | ||
| 70 | loop { | ||
| 71 | info!(" [high] tick!"); | ||
| 72 | Timer::after_ticks(27374).await; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | #[embassy_executor::task] | ||
| 77 | async fn run_med() { | ||
| 78 | loop { | ||
| 79 | let start = Instant::now(); | ||
| 80 | info!(" [med] Starting long computation"); | ||
| 81 | |||
| 82 | // Spin-wait to simulate a long CPU computation | ||
| 83 | cortex_m::asm::delay(128_000_000); // ~1 second | ||
| 84 | |||
| 85 | let end = Instant::now(); | ||
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 87 | info!(" [med] done in {} ms", ms); | ||
| 88 | |||
| 89 | Timer::after_ticks(23421).await; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[embassy_executor::task] | ||
| 94 | async fn run_low() { | ||
| 95 | loop { | ||
| 96 | let start = Instant::now(); | ||
| 97 | info!("[low] Starting long computation"); | ||
| 98 | |||
| 99 | // Spin-wait to simulate a long CPU computation | ||
| 100 | cortex_m::asm::delay(256_000_000); // ~2 seconds | ||
| 101 | |||
| 102 | let end = Instant::now(); | ||
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 104 | info!("[low] done in {} ms", ms); | ||
| 105 | |||
| 106 | Timer::after_ticks(32983).await; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); | ||
| 111 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); | ||
| 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 113 | |||
| 114 | #[interrupt] | ||
| 115 | unsafe fn UART4() { | ||
| 116 | EXECUTOR_HIGH.on_interrupt() | ||
| 117 | } | ||
| 118 | |||
| 119 | #[interrupt] | ||
| 120 | unsafe fn UART5() { | ||
| 121 | EXECUTOR_MED.on_interrupt() | ||
| 122 | } | ||
| 123 | |||
| 124 | #[entry] | ||
| 125 | fn main() -> ! { | ||
| 126 | info!("Hello World!"); | ||
| 127 | |||
| 128 | let _p = embassy_stm32::init(Default::default()); | ||
| 129 | |||
| 130 | // High-priority executor: UART4, priority level 6 | ||
| 131 | interrupt::UART4.set_priority(Priority::P6); | ||
| 132 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | ||
| 133 | unwrap!(spawner.spawn(run_high())); | ||
| 134 | |||
| 135 | // Medium-priority executor: UART5, priority level 7 | ||
| 136 | interrupt::UART5.set_priority(Priority::P7); | ||
| 137 | let spawner = EXECUTOR_MED.start(interrupt::UART5); | ||
| 138 | unwrap!(spawner.spawn(run_med())); | ||
| 139 | |||
| 140 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 141 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 142 | executor.run(|spawner| { | ||
| 143 | unwrap!(spawner.spawn(run_low())); | ||
| 144 | }); | ||
| 145 | } | ||
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index c3ddda72a..576506ad3 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/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/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 047234d60..198504b59 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/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; 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/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index dc1e7022d..7f73fd677 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -79,14 +79,12 @@ async fn main(spawner: Spawner) { | |||
| 79 | config.device_protocol = 0x01; | 79 | config.device_protocol = 0x01; |
| 80 | 80 | ||
| 81 | // Create embassy-usb DeviceBuilder using the driver and config. | 81 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 82 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 83 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 82 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 84 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 83 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 85 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 84 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 86 | let mut builder = Builder::new( | 85 | let mut builder = Builder::new( |
| 87 | driver, | 86 | driver, |
| 88 | config, | 87 | config, |
| 89 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 90 | &mut CONFIG_DESC.init([0; 256])[..], | 88 | &mut CONFIG_DESC.init([0; 256])[..], |
| 91 | &mut BOS_DESC.init([0; 256])[..], | 89 | &mut BOS_DESC.init([0; 256])[..], |
| 92 | &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 b86fba455..9d30205bb 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs | |||
| @@ -51,7 +51,6 @@ async fn main(_spawner: Spawner) { | |||
| 51 | 51 | ||
| 52 | // Create embassy-usb DeviceBuilder using the driver and config. | 52 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 53 | // It needs some buffers for building the descriptors. | 53 | // It needs some buffers for building the descriptors. |
| 54 | let mut device_descriptor = [0; 256]; | ||
| 55 | let mut config_descriptor = [0; 256]; | 54 | let mut config_descriptor = [0; 256]; |
| 56 | let mut bos_descriptor = [0; 256]; | 55 | let mut bos_descriptor = [0; 256]; |
| 57 | let mut control_buf = [0; 64]; | 56 | let mut control_buf = [0; 64]; |
| @@ -62,7 +61,6 @@ async fn main(_spawner: Spawner) { | |||
| 62 | let mut builder = Builder::new( | 61 | let mut builder = Builder::new( |
| 63 | driver, | 62 | driver, |
| 64 | config, | 63 | config, |
| 65 | &mut device_descriptor, | ||
| 66 | &mut config_descriptor, | 64 | &mut config_descriptor, |
| 67 | &mut bos_descriptor, | 65 | &mut bos_descriptor, |
| 68 | &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 5e2378b58..a64bda31b 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs | |||
| @@ -47,7 +47,6 @@ async fn main(_spawner: Spawner) { | |||
| 47 | 47 | ||
| 48 | // Create embassy-usb DeviceBuilder using the driver and config. | 48 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 49 | // It needs some buffers for building the descriptors. | 49 | // It needs some buffers for building the descriptors. |
| 50 | let mut device_descriptor = [0; 256]; | ||
| 51 | let mut config_descriptor = [0; 256]; | 50 | let mut config_descriptor = [0; 256]; |
| 52 | let mut bos_descriptor = [0; 256]; | 51 | let mut bos_descriptor = [0; 256]; |
| 53 | let mut control_buf = [0; 7]; | 52 | let mut control_buf = [0; 7]; |
| @@ -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/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 33e02ce3b..6a313efb0 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs | |||
| @@ -61,7 +61,6 @@ async fn main(_spawner: Spawner) { | |||
| 61 | 61 | ||
| 62 | // Create embassy-usb DeviceBuilder using the driver and config. | 62 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 63 | // It needs some buffers for building the descriptors. | 63 | // It needs some buffers for building the descriptors. |
| 64 | let mut device_descriptor = [0; 256]; | ||
| 65 | let mut config_descriptor = [0; 256]; | 64 | let mut config_descriptor = [0; 256]; |
| 66 | let mut bos_descriptor = [0; 256]; | 65 | let mut bos_descriptor = [0; 256]; |
| 67 | let mut control_buf = [0; 64]; | 66 | let mut control_buf = [0; 64]; |
| @@ -71,7 +70,6 @@ async fn main(_spawner: Spawner) { | |||
| 71 | let mut builder = Builder::new( | 70 | let mut builder = Builder::new( |
| 72 | driver, | 71 | driver, |
| 73 | config, | 72 | config, |
| 74 | &mut device_descriptor, | ||
| 75 | &mut config_descriptor, | 73 | &mut config_descriptor, |
| 76 | &mut bos_descriptor, | 74 | &mut bos_descriptor, |
| 77 | &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/src/bin/can.rs b/tests/stm32/src/bin/can.rs index c08c69a3b..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::bx::filter::Mask32; | 11 | use embassy_stm32::can::filter::Mask32; |
| 13 | use embassy_stm32::can::bx::{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]).unwrap(); | ||
| 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()[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/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index c7373e294..27bdd038a 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs | |||
| @@ -6,13 +6,15 @@ | |||
| 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 | ||
| 15 | mod can_common; | ||
| 16 | use can_common::*; | ||
| 17 | |||
| 16 | bind_interrupts!(struct Irqs2 { | 18 | bind_interrupts!(struct Irqs2 { |
| 17 | FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; | 19 | FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; |
| 18 | FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; | 20 | FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; |
| @@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 { | |||
| 22 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | 24 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; |
| 23 | }); | 25 | }); |
| 24 | 26 | ||
| 25 | struct TestOptions { | ||
| 26 | config: Config, | ||
| 27 | max_latency: Duration, | ||
| 28 | second_fifo_working: bool, | ||
| 29 | } | ||
| 30 | |||
| 31 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] | 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] |
| 32 | fn options() -> TestOptions { | 28 | fn options() -> (Config, TestOptions) { |
| 33 | use embassy_stm32::rcc; | 29 | use embassy_stm32::rcc; |
| 34 | info!("H75 config"); | 30 | info!("H75 config"); |
| 35 | let mut c = config(); | 31 | let mut c = config(); |
| @@ -38,15 +34,17 @@ fn options() -> TestOptions { | |||
| 38 | mode: rcc::HseMode::Oscillator, | 34 | mode: rcc::HseMode::Oscillator, |
| 39 | }); | 35 | }); |
| 40 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 36 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 41 | TestOptions { | 37 | ( |
| 42 | config: c, | 38 | c, |
| 43 | max_latency: Duration::from_micros(1200), | 39 | TestOptions { |
| 44 | second_fifo_working: false, | 40 | max_latency: Duration::from_micros(1200), |
| 45 | } | 41 | max_buffered: 3, |
| 42 | }, | ||
| 43 | ) | ||
| 46 | } | 44 | } |
| 47 | 45 | ||
| 48 | #[cfg(any(feature = "stm32h7a3zi"))] | 46 | #[cfg(any(feature = "stm32h7a3zi"))] |
| 49 | fn options() -> TestOptions { | 47 | fn options() -> (Config, TestOptions) { |
| 50 | use embassy_stm32::rcc; | 48 | use embassy_stm32::rcc; |
| 51 | info!("H7a config"); | 49 | info!("H7a config"); |
| 52 | let mut c = config(); | 50 | let mut c = config(); |
| @@ -55,32 +53,36 @@ fn options() -> TestOptions { | |||
| 55 | mode: rcc::HseMode::Oscillator, | 53 | mode: rcc::HseMode::Oscillator, |
| 56 | }); | 54 | }); |
| 57 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 55 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 58 | TestOptions { | 56 | ( |
| 59 | config: c, | 57 | c, |
| 60 | max_latency: Duration::from_micros(1200), | 58 | TestOptions { |
| 61 | second_fifo_working: false, | 59 | max_latency: Duration::from_micros(1200), |
| 62 | } | 60 | max_buffered: 3, |
| 61 | }, | ||
| 62 | ) | ||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] | 65 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] |
| 66 | fn options() -> TestOptions { | 66 | fn options() -> (Config, TestOptions) { |
| 67 | info!("G4 config"); | 67 | info!("G4 config"); |
| 68 | TestOptions { | 68 | ( |
| 69 | config: config(), | 69 | config(), |
| 70 | max_latency: Duration::from_micros(500), | 70 | TestOptions { |
| 71 | second_fifo_working: true, | 71 | max_latency: Duration::from_micros(500), |
| 72 | } | 72 | max_buffered: 6, |
| 73 | }, | ||
| 74 | ) | ||
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | #[embassy_executor::main] | 77 | #[embassy_executor::main] |
| 76 | async fn main(_spawner: Spawner) { | 78 | async fn main(_spawner: Spawner) { |
| 77 | //let peripherals = embassy_stm32::init(config()); | 79 | //let peripherals = embassy_stm32::init(config()); |
| 78 | 80 | ||
| 79 | let options = options(); | 81 | let (config, options) = options(); |
| 80 | let peripherals = embassy_stm32::init(options.config); | 82 | let peripherals = embassy_stm32::init(config); |
| 81 | 83 | ||
| 82 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); | 84 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); |
| 83 | let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); | 85 | let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); |
| 84 | 86 | ||
| 85 | // 250k bps | 87 | // 250k bps |
| 86 | can.set_bitrate(250_000); | 88 | can.set_bitrate(250_000); |
| @@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) { | |||
| 98 | let mut can = can.into_internal_loopback_mode(); | 100 | let mut can = can.into_internal_loopback_mode(); |
| 99 | let mut can2 = can2.into_internal_loopback_mode(); | 101 | let mut can2 = can2.into_internal_loopback_mode(); |
| 100 | 102 | ||
| 101 | info!("CAN Configured"); | 103 | run_can_tests(&mut can, &options).await; |
| 104 | run_can_tests(&mut can2, &options).await; | ||
| 102 | 105 | ||
| 103 | let mut i: u8 = 0; | 106 | info!("CAN Configured"); |
| 104 | loop { | ||
| 105 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 106 | |||
| 107 | info!("Transmitting frame..."); | ||
| 108 | let tx_ts = Instant::now(); | ||
| 109 | can.write(&tx_frame).await; | ||
| 110 | |||
| 111 | let (frame, timestamp) = can.read().await.unwrap(); | ||
| 112 | info!("Frame received!"); | ||
| 113 | |||
| 114 | // Check data. | ||
| 115 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 116 | |||
| 117 | info!("loopback time {}", timestamp); | ||
| 118 | info!("loopback frame {=u8}", frame.data()[0]); | ||
| 119 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 120 | info!("loopback latency {} us", latency.as_micros()); | ||
| 121 | |||
| 122 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 123 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 124 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 125 | // sure if there are other delays | ||
| 126 | assert!( | ||
| 127 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 128 | "{} <= {} <= {}", | ||
| 129 | MIN_LATENCY, | ||
| 130 | latency, | ||
| 131 | options.max_latency | ||
| 132 | ); | ||
| 133 | |||
| 134 | i += 1; | ||
| 135 | if i > 10 { | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | let mut i: u8 = 0; | ||
| 141 | loop { | ||
| 142 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 143 | |||
| 144 | info!("Transmitting frame..."); | ||
| 145 | let tx_ts = Instant::now(); | ||
| 146 | can2.write(&tx_frame).await; | ||
| 147 | |||
| 148 | let (frame, timestamp) = can2.read().await.unwrap(); | ||
| 149 | info!("Frame received!"); | ||
| 150 | |||
| 151 | //print_regs().await; | ||
| 152 | // Check data. | ||
| 153 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 154 | |||
| 155 | info!("loopback time {}", timestamp); | ||
| 156 | info!("loopback frame {=u8}", frame.data()[0]); | ||
| 157 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 158 | info!("loopback latency {} us", latency.as_micros()); | ||
| 159 | |||
| 160 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 161 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 162 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 163 | // sure if there are other delays | ||
| 164 | assert!( | ||
| 165 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 166 | "{} <= {} <= {}", | ||
| 167 | MIN_LATENCY, | ||
| 168 | latency, | ||
| 169 | options.max_latency | ||
| 170 | ); | ||
| 171 | |||
| 172 | i += 1; | ||
| 173 | if i > 10 { | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | let max_buffered = if options.second_fifo_working { 6 } else { 3 }; | ||
| 179 | |||
| 180 | // Below here, check that we can receive from both FIFO0 and FIFO0 | ||
| 181 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 182 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 183 | for i in 0..3 { | ||
| 184 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 185 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 186 | info!("Transmitting frame {}", i); | ||
| 187 | can.write(&tx_frame).await; | ||
| 188 | } | ||
| 189 | for i in 3..max_buffered { | ||
| 190 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 191 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 192 | info!("Transmitting frame {}", i); | ||
| 193 | can.write(&tx_frame).await; | ||
| 194 | } | ||
| 195 | |||
| 196 | // Try and receive all 6 packets | ||
| 197 | for i in 0..max_buffered { | ||
| 198 | let (frame, _ts) = can.read().await.unwrap(); | ||
| 199 | match frame.id() { | ||
| 200 | embedded_can::Id::Extended(id) => { | ||
| 201 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 202 | } | ||
| 203 | embedded_can::Id::Standard(id) => { | ||
| 204 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | 107 | ||
| 209 | // Test again with a split | 108 | // Test again with a split |
| 210 | let (mut tx, mut rx) = can.split(); | 109 | let (mut tx, mut rx) = can.split(); |
| 211 | for i in 0..3 { | 110 | let (mut tx2, mut rx2) = can2.split(); |
| 212 | // Try filling up the RX FIFO0 buffers with standard packets | 111 | run_split_can_tests(&mut tx, &mut rx, &options).await; |
| 213 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | 112 | run_split_can_tests(&mut tx2, &mut rx2, &options).await; |
| 214 | info!("Transmitting frame {}", i); | ||
| 215 | tx.write(&tx_frame).await; | ||
| 216 | } | ||
| 217 | for i in 3..max_buffered { | ||
| 218 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 219 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 220 | info!("Transmitting frame {}", i); | ||
| 221 | tx.write(&tx_frame).await; | ||
| 222 | } | ||
| 223 | |||
| 224 | // Try and receive all 6 packets | ||
| 225 | for i in 0..max_buffered { | ||
| 226 | let (frame, _ts) = rx.read().await.unwrap(); | ||
| 227 | match frame.id() { | ||
| 228 | embedded_can::Id::Extended(id) => { | ||
| 229 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 230 | } | ||
| 231 | embedded_can::Id::Standard(id) => { | ||
| 232 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | 113 | ||
| 237 | info!("Test OK"); | 114 | info!("Test OK"); |
| 238 | cortex_m::asm::bkpt(); | 115 | cortex_m::asm::bkpt(); |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index c379863a8..0e555efc8 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -251,13 +251,6 @@ define_peris!( | |||
| 251 | ); | 251 | ); |
| 252 | 252 | ||
| 253 | pub fn config() -> Config { | 253 | pub fn config() -> Config { |
| 254 | // Setting this bit is mandatory to use PG[15:2]. | ||
| 255 | #[cfg(feature = "stm32u5a5zj")] | ||
| 256 | embassy_stm32::pac::PWR.svmcr().modify(|w| { | ||
| 257 | w.set_io2sv(true); | ||
| 258 | w.set_io2vmen(true); | ||
| 259 | }); | ||
| 260 | |||
| 261 | #[allow(unused_mut)] | 254 | #[allow(unused_mut)] |
| 262 | let mut config = Config::default(); | 255 | let mut config = Config::default(); |
| 263 | 256 | ||
