aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Toft <[email protected]>2024-04-04 15:52:44 +0200
committerGustav Toft <[email protected]>2024-04-04 15:52:44 +0200
commita373633d0dbc352de1b488bf15e383f8ef1d4a8c (patch)
treea4590f26bd3252445e2adfa6d271a6f1cf74d54b
parent0427c442ea531673e18da304c7402927589b8d0b (diff)
parent067e422863674762c0ee20178f3671ce16a5986c (diff)
Merge branch 'main' of https://github.com/GustavToft/embassy
-rwxr-xr-xci.sh1
-rw-r--r--cyw43/src/fmt.rs3
-rw-r--r--docs/modules/ROOT/pages/faq.adoc23
-rw-r--r--embassy-boot-nrf/src/fmt.rs3
-rw-r--r--embassy-boot-rp/src/fmt.rs3
-rw-r--r--embassy-boot-stm32/src/fmt.rs3
-rw-r--r--embassy-boot/src/boot_loader.rs24
-rw-r--r--embassy-boot/src/fmt.rs3
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/i2c.rs5
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs5
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/i2c.rs5
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/spi.rs5
-rw-r--r--embassy-executor-macros/src/macros/task.rs17
-rw-r--r--embassy-executor-macros/src/util/ctxt.rs1
-rw-r--r--embassy-executor/src/fmt.rs3
-rw-r--r--embassy-executor/src/raw/mod.rs2
-rw-r--r--embassy-executor/tests/test.rs2
-rw-r--r--embassy-futures/src/fmt.rs3
-rw-r--r--embassy-hal-internal/src/fmt.rs3
-rw-r--r--embassy-hal-internal/src/interrupt.rs8
-rw-r--r--embassy-net-adin1110/src/fmt.rs29
-rw-r--r--embassy-net-driver-channel/src/fmt.rs3
-rw-r--r--embassy-net-enc28j60/src/fmt.rs3
-rw-r--r--embassy-net-enc28j60/src/lib.rs7
-rw-r--r--embassy-net-esp-hosted/src/fmt.rs3
-rw-r--r--embassy-net-ppp/src/fmt.rs3
-rw-r--r--embassy-net-tuntap/src/lib.rs2
-rw-r--r--embassy-net-wiznet/src/chip/mod.rs73
-rw-r--r--embassy-net-wiznet/src/chip/w5100s.rs2
-rw-r--r--embassy-net-wiznet/src/chip/w5500.rs2
-rw-r--r--embassy-net/src/fmt.rs3
-rw-r--r--embassy-nrf/src/fmt.rs3
-rw-r--r--embassy-nrf/src/gpio.rs2
-rw-r--r--embassy-nrf/src/gpiote.rs2
-rw-r--r--embassy-nrf/src/lib.rs39
-rw-r--r--embassy-nrf/src/timer.rs2
-rw-r--r--embassy-rp/src/adc.rs11
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/dma.rs2
-rw-r--r--embassy-rp/src/flash.rs6
-rw-r--r--embassy-rp/src/float/mod.rs1
-rw-r--r--embassy-rp/src/fmt.rs3
-rw-r--r--embassy-rp/src/gpio.rs8
-rw-r--r--embassy-rp/src/i2c.rs6
-rw-r--r--embassy-rp/src/i2c_slave.rs16
-rw-r--r--embassy-rp/src/lib.rs19
-rw-r--r--embassy-rp/src/multicore.rs2
-rw-r--r--embassy-rp/src/pio/mod.rs10
-rw-r--r--embassy-rp/src/pwm.rs134
-rw-r--r--embassy-rp/src/relocate.rs8
-rw-r--r--embassy-rp/src/rtc/mod.rs3
-rw-r--r--embassy-rp/src/uart/buffered.rs14
-rw-r--r--embassy-rp/src/uart/mod.rs2
-rw-r--r--embassy-rp/src/usb.rs11
-rw-r--r--embassy-stm32-wpan/src/consts.rs2
-rw-r--r--embassy-stm32-wpan/src/fmt.rs3
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/adc/f1.rs4
-rw-r--r--embassy-stm32/src/adc/f3.rs6
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs4
-rw-r--r--embassy-stm32/src/adc/mod.rs100
-rw-r--r--embassy-stm32/src/adc/v1.rs6
-rw-r--r--embassy-stm32/src/adc/v2.rs6
-rw-r--r--embassy-stm32/src/adc/v3.rs8
-rw-r--r--embassy-stm32/src/adc/v4.rs8
-rw-r--r--embassy-stm32/src/can/bx/mod.rs971
-rw-r--r--embassy-stm32/src/can/bxcan.rs627
-rw-r--r--embassy-stm32/src/can/bxcan/filter.rs (renamed from embassy-stm32/src/can/bx/filter.rs)2
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs989
-rw-r--r--embassy-stm32/src/can/bxcan/registers.rs510
-rw-r--r--embassy-stm32/src/can/common.rs52
-rw-r--r--embassy-stm32/src/can/enums.rs10
-rw-r--r--embassy-stm32/src/can/fd/message_ram/mod.rs20
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs73
-rw-r--r--embassy-stm32/src/can/fdcan.rs489
-rw-r--r--embassy-stm32/src/can/frame.rs67
-rw-r--r--embassy-stm32/src/can/mod.rs9
-rw-r--r--embassy-stm32/src/crc/v1.rs2
-rw-r--r--embassy-stm32/src/crc/v2v3.rs2
-rw-r--r--embassy-stm32/src/cryp/mod.rs13
-rw-r--r--embassy-stm32/src/dac/mod.rs17
-rw-r--r--embassy-stm32/src/dcmi.rs14
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs63
-rw-r--r--embassy-stm32/src/dma/dmamux.rs9
-rw-r--r--embassy-stm32/src/dma/mod.rs23
-rw-r--r--embassy-stm32/src/dma/word.rs9
-rw-r--r--embassy-stm32/src/eth/mod.rs11
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs23
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs29
-rw-r--r--embassy-stm32/src/exti.rs11
-rw-r--r--embassy-stm32/src/flash/f0.rs1
-rw-r--r--embassy-stm32/src/flash/f1f3.rs1
-rw-r--r--embassy-stm32/src/flash/f4.rs1
-rw-r--r--embassy-stm32/src/flash/f7.rs1
-rw-r--r--embassy-stm32/src/flash/g.rs1
-rw-r--r--embassy-stm32/src/flash/h7.rs1
-rw-r--r--embassy-stm32/src/flash/u5.rs1
-rw-r--r--embassy-stm32/src/fmc.rs18
-rw-r--r--embassy-stm32/src/fmt.rs3
-rw-r--r--embassy-stm32/src/gpio.rs306
-rw-r--r--embassy-stm32/src/hash/mod.rs15
-rw-r--r--embassy-stm32/src/hrtim/mod.rs17
-rw-r--r--embassy-stm32/src/hrtim/traits.rs128
-rw-r--r--embassy-stm32/src/i2c/mod.rs40
-rw-r--r--embassy-stm32/src/i2c/v1.rs1
-rw-r--r--embassy-stm32/src/i2c/v2.rs1
-rw-r--r--embassy-stm32/src/i2s.rs3
-rw-r--r--embassy-stm32/src/ipcc.rs83
-rw-r--r--embassy-stm32/src/lib.rs32
-rw-r--r--embassy-stm32/src/opamp.rs54
-rw-r--r--embassy-stm32/src/qspi/mod.rs16
-rw-r--r--embassy-stm32/src/rcc/bd.rs2
-rw-r--r--embassy-stm32/src/rcc/hsi48.rs2
-rw-r--r--embassy-stm32/src/rcc/mco.rs27
-rw-r--r--embassy-stm32/src/rcc/mod.rs41
-rw-r--r--embassy-stm32/src/rng.rs13
-rw-r--r--embassy-stm32/src/rtc/datetime.rs7
-rw-r--r--embassy-stm32/src/rtc/mod.rs53
-rw-r--r--embassy-stm32/src/rtc/v2.rs5
-rw-r--r--embassy-stm32/src/rtc/v3.rs6
-rw-r--r--embassy-stm32/src/sai/mod.rs41
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs31
-rw-r--r--embassy-stm32/src/spi/mod.rs37
-rw-r--r--embassy-stm32/src/time_driver.rs41
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs37
-rw-r--r--embassy-stm32/src/timer/low_level.rs638
-rw-r--r--embassy-stm32/src/timer/mod.rs1005
-rw-r--r--embassy-stm32/src/timer/qei.rs36
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs45
-rw-r--r--embassy-stm32/src/ucpd.rs60
-rw-r--r--embassy-stm32/src/uid.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs7
-rw-r--r--embassy-stm32/src/usart/mod.rs128
-rw-r--r--embassy-stm32/src/usb/mod.rs4
-rw-r--r--embassy-stm32/src/usb/otg.rs31
-rw-r--r--embassy-stm32/src/usb/usb.rs28
-rw-r--r--embassy-stm32/src/wdg/mod.rs11
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/README.md2
-rw-r--r--embassy-sync/src/fmt.rs3
-rw-r--r--embassy-sync/src/lib.rs2
-rw-r--r--embassy-sync/src/once_lock.rs236
-rw-r--r--embassy-sync/src/semaphore.rs772
-rw-r--r--embassy-time/src/fmt.rs3
-rw-r--r--embassy-time/src/timer.rs14
-rw-r--r--embassy-usb-dfu/src/fmt.rs3
-rw-r--r--embassy-usb-logger/src/lib.rs15
-rw-r--r--embassy-usb/src/builder.rs7
-rw-r--r--embassy-usb/src/descriptor.rs51
-rw-r--r--embassy-usb/src/fmt.rs3
-rw-r--r--embassy-usb/src/lib.rs9
-rw-r--r--embassy-usb/src/msos.rs34
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs2
-rw-r--r--examples/rp/src/bin/multicore.rs12
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs2
-rw-r--r--examples/rp/src/bin/pio_uart.rs2
-rw-r--r--examples/rp/src/bin/pwm.rs2
-rw-r--r--examples/rp/src/bin/pwm_input.rs2
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs2
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs2
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/rp/src/bin/usb_midi.rs2
-rw-r--r--examples/rp/src/bin/usb_raw.rs2
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs2
-rw-r--r--examples/rp/src/bin/usb_serial.rs2
-rw-r--r--examples/rp/src/bin/usb_serial_with_logger.rs2
-rw-r--r--examples/std/src/bin/net.rs2
-rw-r--r--examples/std/src/bin/net_dns.rs2
-rw-r--r--examples/std/src/bin/tcp_accept.rs1
-rw-r--r--examples/stm32f1/Cargo.toml1
-rw-r--r--examples/stm32f1/src/bin/can.rs111
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f2/src/bin/pll.rs2
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f4/src/bin/can.rs11
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs5
-rw-r--r--examples/stm32f7/src/bin/can.rs12
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32g0/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32g4/src/bin/can.rs29
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32h5/src/bin/can.rs12
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h7/src/bin/camera.rs4
-rw-r--r--examples/stm32h7/src/bin/can.rs12
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs40
-rw-r--r--examples/stm32h7/src/bin/eth.rs20
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs71
-rw-r--r--examples/stm32h7/src/bin/multiprio.rs145
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l1/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs40
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs8
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs2
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/rp/src/bin/gpio_multicore.rs12
-rw-r--r--tests/rp/src/bin/i2c.rs12
-rw-r--r--tests/rp/src/bin/multicore.rs12
-rw-r--r--tests/rp/src/bin/pwm.rs14
-rw-r--r--tests/stm32/src/bin/can.rs67
-rw-r--r--tests/stm32/src/bin/can_common.rs112
-rw-r--r--tests/stm32/src/bin/fdcan.rs199
-rw-r--r--tests/stm32/src/common.rs7
222 files changed, 5519 insertions, 4516 deletions
diff --git a/ci.sh b/ci.sh
index cd82af2f1..d17f4e13e 100755
--- a/ci.sh
+++ b/ci.sh
@@ -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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
210Check 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. 210Check 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
214It could happen that your project compiles, flashes but fails to run. The following situation can be true for your setup:
215
216The `memory.x` is generated automatically when enabling the `memory-x` feature on the `embassy-stm32` crate in the `Cargo.toml` file.
217This, 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
219You can override this by adding your own `memory.x` file. Such a file could look like this:
220```
221MEMORY
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
230Please 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.
231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start.
232
233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise.
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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
111impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS> 116impl<'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
127impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> 132impl<'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
137impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> 142impl<'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
152impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS> 157impl<'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
8use proc_macro2::TokenStream; 8use proc_macro2::TokenStream;
9use quote::{quote, ToTokens}; 9use quote::{quote, ToTokens};
10use 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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;
30use core::task::{Context, Poll}; 30use core::task::{Context, Poll};
31 31
32#[cfg(feature = "integrated-timers")] 32#[cfg(feature = "integrated-timers")]
33use embassy_time_driver::{self, AlarmHandle}; 33use embassy_time_driver::AlarmHandle;
34#[cfg(feature = "rtos-trace")] 34#[cfg(feature = "rtos-trace")]
35use rtos_trace::trace; 35use 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
3use std::boxed::Box; 3use std::boxed::Box;
4use std::future::poll_fn; 4use 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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"))]
86macro_rules! unreachable { 87macro_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 } 94macro_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
229pub struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
230 233
231impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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;
17mod traits; 17mod traits;
18 18
19use core::cmp; 19use core::cmp;
20use core::convert::TryInto;
21 20
22use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; 21use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
23use embassy_time::Duration; 22use 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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};
6use std::task::Context; 6use std::task::Context;
7 7
8use async_io::Async; 8use async_io::Async;
9use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; 9use embassy_net_driver::{Capabilities, Driver, HardwareAddress, LinkState};
10use log::*; 10use 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 @@
2mod w5500; 2mod w5500;
3pub use w5500::W5500; 3pub use w5500::W5500;
4mod w5100s; 4mod w5100s;
5use embedded_hal_async::spi::SpiDevice;
5pub use w5100s::W5100S; 6pub use w5100s::W5100S;
6 7
7pub(crate) mod sealed { 8pub(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.
50pub trait Chip: sealed::Chip {} 40#[allow(private_bounds)]
41pub 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;
8pub enum W5100S {} 8pub enum W5100S {}
9 9
10impl super::Chip for W5100S {} 10impl super::Chip for W5100S {}
11impl super::sealed::Chip for W5100S { 11impl 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 {
12pub enum W5500 {} 12pub enum W5500 {}
13 13
14impl super::Chip for W5500 {} 14impl super::Chip for W5500 {}
15impl super::sealed::Chip for W5500 { 15impl 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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"))]
476pub(crate) trait PselBits { 477pub(crate) trait PselBits {
477 fn psel_bits(&self) -> u32; 478 fn psel_bits(&self) -> u32;
478} 479}
479 480
481#[cfg(not(feature = "_nrf51"))]
480impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> { 482impl<'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"))]
170struct BitIter(u32); 171struct BitIter(u32);
171 172
173#[cfg(not(feature = "_nrf51"))]
172impl Iterator for BitIter { 174impl 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)]
22pub struct Config {} 23pub struct Config {}
23 24
24impl Default for Config {
25 fn default() -> Self {
26 Self {}
27 }
28}
29
30enum Source<'p> { 25enum 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)]
422mod ram_helpers { 422mod 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
978mod eh02 { 978mod 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
355pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P) 355pub(crate) fn set_up_i2c_pin<P, T>(pin: &P)
356where 356where
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.
356trait RegExt<T: Copy> { 356trait 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)]
61fn core1_setup(stack_bottom: *mut usize) { 61fn 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
466fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) { 466fn 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.
85pub struct Pwm<'d, T: Channel> { 85pub 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
91impl<'d, T: Channel> Pwm<'d, T> { 91impl<'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.
269pub struct PwmBatch(u32); 269pub struct PwmBatch(u32);
270 270
271impl PwmBatch { 271impl 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
291impl<'d, T: Channel> Drop for Pwm<'d, T> { 291impl<'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
303mod sealed { 303mod sealed {
304 pub trait Channel {} 304 pub trait Slice {}
305} 305}
306 306
307/// PWM Channel. 307/// PWM Slice.
308pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static { 308pub 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
318macro_rules! channel { 318macro_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
329channel!(PWM_CH0, 0); 329slice!(PWM_SLICE0, 0);
330channel!(PWM_CH1, 1); 330slice!(PWM_SLICE1, 1);
331channel!(PWM_CH2, 2); 331slice!(PWM_SLICE2, 2);
332channel!(PWM_CH3, 3); 332slice!(PWM_SLICE3, 3);
333channel!(PWM_CH4, 4); 333slice!(PWM_SLICE4, 4);
334channel!(PWM_CH5, 5); 334slice!(PWM_SLICE5, 5);
335channel!(PWM_CH6, 6); 335slice!(PWM_SLICE6, 6);
336channel!(PWM_CH7, 7); 336slice!(PWM_SLICE7, 7);
337 337
338/// PWM Pin A. 338/// PWM Channel A.
339pub trait PwmPinA<T: Channel>: GpioPin {} 339pub trait ChannelAPin<T: Slice>: GpioPin {}
340/// PWM Pin B. 340/// PWM Channel B.
341pub trait PwmPinB<T: Channel>: GpioPin {} 341pub trait ChannelBPin<T: Slice>: GpioPin {}
342 342
343macro_rules! impl_pin { 343macro_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
349impl_pin!(PIN_0, PWM_CH0, PwmPinA); 349impl_pin!(PIN_0, PWM_SLICE0, ChannelAPin);
350impl_pin!(PIN_1, PWM_CH0, PwmPinB); 350impl_pin!(PIN_1, PWM_SLICE0, ChannelBPin);
351impl_pin!(PIN_2, PWM_CH1, PwmPinA); 351impl_pin!(PIN_2, PWM_SLICE1, ChannelAPin);
352impl_pin!(PIN_3, PWM_CH1, PwmPinB); 352impl_pin!(PIN_3, PWM_SLICE1, ChannelBPin);
353impl_pin!(PIN_4, PWM_CH2, PwmPinA); 353impl_pin!(PIN_4, PWM_SLICE2, ChannelAPin);
354impl_pin!(PIN_5, PWM_CH2, PwmPinB); 354impl_pin!(PIN_5, PWM_SLICE2, ChannelBPin);
355impl_pin!(PIN_6, PWM_CH3, PwmPinA); 355impl_pin!(PIN_6, PWM_SLICE3, ChannelAPin);
356impl_pin!(PIN_7, PWM_CH3, PwmPinB); 356impl_pin!(PIN_7, PWM_SLICE3, ChannelBPin);
357impl_pin!(PIN_8, PWM_CH4, PwmPinA); 357impl_pin!(PIN_8, PWM_SLICE4, ChannelAPin);
358impl_pin!(PIN_9, PWM_CH4, PwmPinB); 358impl_pin!(PIN_9, PWM_SLICE4, ChannelBPin);
359impl_pin!(PIN_10, PWM_CH5, PwmPinA); 359impl_pin!(PIN_10, PWM_SLICE5, ChannelAPin);
360impl_pin!(PIN_11, PWM_CH5, PwmPinB); 360impl_pin!(PIN_11, PWM_SLICE5, ChannelBPin);
361impl_pin!(PIN_12, PWM_CH6, PwmPinA); 361impl_pin!(PIN_12, PWM_SLICE6, ChannelAPin);
362impl_pin!(PIN_13, PWM_CH6, PwmPinB); 362impl_pin!(PIN_13, PWM_SLICE6, ChannelBPin);
363impl_pin!(PIN_14, PWM_CH7, PwmPinA); 363impl_pin!(PIN_14, PWM_SLICE7, ChannelAPin);
364impl_pin!(PIN_15, PWM_CH7, PwmPinB); 364impl_pin!(PIN_15, PWM_SLICE7, ChannelBPin);
365impl_pin!(PIN_16, PWM_CH0, PwmPinA); 365impl_pin!(PIN_16, PWM_SLICE0, ChannelAPin);
366impl_pin!(PIN_17, PWM_CH0, PwmPinB); 366impl_pin!(PIN_17, PWM_SLICE0, ChannelBPin);
367impl_pin!(PIN_18, PWM_CH1, PwmPinA); 367impl_pin!(PIN_18, PWM_SLICE1, ChannelAPin);
368impl_pin!(PIN_19, PWM_CH1, PwmPinB); 368impl_pin!(PIN_19, PWM_SLICE1, ChannelBPin);
369impl_pin!(PIN_20, PWM_CH2, PwmPinA); 369impl_pin!(PIN_20, PWM_SLICE2, ChannelAPin);
370impl_pin!(PIN_21, PWM_CH2, PwmPinB); 370impl_pin!(PIN_21, PWM_SLICE2, ChannelBPin);
371impl_pin!(PIN_22, PWM_CH3, PwmPinA); 371impl_pin!(PIN_22, PWM_SLICE3, ChannelAPin);
372impl_pin!(PIN_23, PWM_CH3, PwmPinB); 372impl_pin!(PIN_23, PWM_SLICE3, ChannelBPin);
373impl_pin!(PIN_24, PWM_CH4, PwmPinA); 373impl_pin!(PIN_24, PWM_SLICE4, ChannelAPin);
374impl_pin!(PIN_25, PWM_CH4, PwmPinB); 374impl_pin!(PIN_25, PWM_SLICE4, ChannelBPin);
375impl_pin!(PIN_26, PWM_CH5, PwmPinA); 375impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin);
376impl_pin!(PIN_27, PWM_CH5, PwmPinB); 376impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin);
377impl_pin!(PIN_28, PWM_CH6, PwmPinA); 377impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin);
378impl_pin!(PIN_29, PWM_CH6, PwmPinB); 378impl_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 @@
1use core::iter::Iterator;
2
3use pio::{Program, SideSet, Wrap}; 1use pio::{Program, SideSet, Wrap};
4 2
5pub struct CodeIterator<'a, I> 3pub 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.
2use core::future::{poll_fn, Future}; 2use core::future::Future;
3use core::slice; 3use core::slice;
4use core::task::Poll;
5 4
6use atomic_polyfill::{AtomicU8, Ordering}; 5use atomic_polyfill::AtomicU8;
7use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 6use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
8use embassy_sync::waitqueue::AtomicWaker;
9use embassy_time::Timer;
10 7
11use super::*; 8use super::*;
12use crate::clocks::clk_peri_freq;
13use crate::interrupt::typelevel::{Binding, Interrupt};
14use crate::{interrupt, RegExt};
15 9
16pub struct State { 10pub 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
323impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { 323impl<'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
466trait Dir { 466trait 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 @@
1use core::convert::TryFrom;
2
3use crate::evt::CsEvt; 1use crate::evt::CsEvt;
4use crate::PacketHeader; 2use 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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"
70sdio-host = "0.5.0" 70sdio-host = "0.5.0"
71critical-section = "1.1" 71critical-section = "1.1"
72#stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd" }
74vcell = "0.1.3" 74vcell = "0.1.3"
75nb = "1.0.0" 75nb = "1.0.0"
76stm32-fmc = "0.3.0" 76stm32-fmc = "0.3.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
94proc-macro2 = "1.0.36" 94proc-macro2 = "1.0.36"
95quote = "1.0.15" 95quote = "1.0.15"
96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c8b32ecae7d70cea2705095c4fc6bd5f59d238d5", default-features = false, features = ["metadata"]} 97stm32-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
34pub struct Vref; 34pub struct Vref;
35impl<T: Instance> AdcPin<T> for Vref {} 35impl<T: Instance> AdcPin<T> for Vref {}
36impl<T: Instance> super::sealed::AdcPin<T> for Vref { 36impl<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
42pub struct Temperature; 42pub struct Temperature;
43impl<T: Instance> AdcPin<T> for Temperature {} 43impl<T: Instance> AdcPin<T> for Temperature {}
44impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 44impl<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
34pub struct Vref; 34pub struct Vref;
35impl<T: Instance> AdcPin<T> for Vref {} 35impl<T: Instance> AdcPin<T> for Vref {}
36impl<T: Instance> super::sealed::AdcPin<T> for Vref { 36impl<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
49pub struct Temperature; 49pub struct Temperature;
50impl<T: Instance> AdcPin<T> for Temperature {} 50impl<T: Instance> AdcPin<T> for Temperature {}
51impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 51impl<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
66pub struct Vref<T: Instance>(core::marker::PhantomData<T>); 66pub struct Vref<T: Instance>(core::marker::PhantomData<T>);
67impl<T: Instance> AdcPin<T> for Vref<T> {} 67impl<T: Instance> AdcPin<T> for Vref<T> {}
68impl<T: Instance> super::sealed::AdcPin<T> for Vref<T> { 68impl<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
125pub struct Temperature<T: Instance>(core::marker::PhantomData<T>); 125pub struct Temperature<T: Instance>(core::marker::PhantomData<T>);
126impl<T: Instance> AdcPin<T> for Temperature<T> {} 126impl<T: Instance> AdcPin<T> for Temperature<T> {}
127impl<T: Instance> super::sealed::AdcPin<T> for Temperature<T> { 127impl<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))]
19pub use _version::*; 19pub use _version::*;
20#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
21use embassy_sync::waitqueue::AtomicWaker;
20 22
21#[cfg(not(any(adc_f1, adc_f3_v2)))] 23#[cfg(not(any(adc_f1, adc_f3_v2)))]
22pub use crate::pac::adc::vals::Res as Resolution; 24pub 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
34pub(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))] 37pub 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 { 42impl 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 { 50trait 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> { 59pub(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> { 67trait 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)))]
78pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 74#[allow(private_bounds)]
75pub 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))]
81pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 80#[allow(private_bounds)]
81pub 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.
84pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 86#[allow(private_bounds)]
87pub trait AdcPin<T: Instance>: SealedAdcPin<T> {}
85/// ADC internal channel. 88/// ADC internal channel.
86pub trait InternalChannel<T>: sealed::InternalChannel<T> {} 89#[allow(private_bounds)]
90pub trait InternalChannel<T>: SealedInternalChannel<T> {}
87 91
88foreach_adc!( 92foreach_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;
39impl AdcPin<ADC> for Vbat {} 39impl AdcPin<ADC> for Vbat {}
40 40
41#[cfg(not(adc_l0))] 41#[cfg(not(adc_l0))]
42impl super::sealed::AdcPin<ADC> for Vbat { 42impl 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
48pub struct Vref; 48pub struct Vref;
49impl AdcPin<ADC> for Vref {} 49impl AdcPin<ADC> for Vref {}
50impl super::sealed::AdcPin<ADC> for Vref { 50impl 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
56pub struct Temperature; 56pub struct Temperature;
57impl AdcPin<ADC> for Temperature {} 57impl AdcPin<ADC> for Temperature {}
58impl super::sealed::AdcPin<ADC> for Temperature { 58impl 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
17pub struct VrefInt; 17pub struct VrefInt;
18impl AdcPin<ADC1> for VrefInt {} 18impl AdcPin<ADC1> for VrefInt {}
19impl super::sealed::AdcPin<ADC1> for VrefInt { 19impl 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
32pub struct Temperature; 32pub struct Temperature;
33impl AdcPin<ADC1> for Temperature {} 33impl AdcPin<ADC1> for Temperature {}
34impl super::sealed::AdcPin<ADC1> for Temperature { 34impl 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
53pub struct Vbat; 53pub struct Vbat;
54impl AdcPin<ADC1> for Vbat {} 54impl AdcPin<ADC1> for Vbat {}
55impl super::sealed::AdcPin<ADC1> for Vbat { 55impl 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
13pub struct VrefInt; 13pub struct VrefInt;
14impl<T: Instance> AdcPin<T> for VrefInt {} 14impl<T: Instance> AdcPin<T> for VrefInt {}
15impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { 15impl<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
30pub struct Temperature; 30pub struct Temperature;
31impl<T: Instance> AdcPin<T> for Temperature {} 31impl<T: Instance> AdcPin<T> for Temperature {}
32impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 32impl<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
47pub struct Vbat; 47pub struct Vbat;
48impl<T: Instance> AdcPin<T> for Vbat {} 48impl<T: Instance> AdcPin<T> for Vbat {}
49impl<T: Instance> super::sealed::AdcPin<T> for Vbat { 49impl<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.
36pub struct VrefInt; 36pub struct VrefInt;
37impl<T: Instance> InternalChannel<T> for VrefInt {} 37impl<T: Instance> InternalChannel<T> for VrefInt {}
38impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { 38impl<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.
45pub struct Temperature; 45pub struct Temperature;
46impl<T: Instance> InternalChannel<T> for Temperature {} 46impl<T: Instance> InternalChannel<T> for Temperature {}
47impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { 47impl<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.
54pub struct Vbat; 54pub struct Vbat;
55impl<T: Instance> InternalChannel<T> for Vbat {} 55impl<T: Instance> InternalChannel<T> for Vbat {}
56impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { 56impl<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;
27pub mod filter;
28
29#[allow(clippy::all)] // generated code
30use core::cmp::{Ord, Ordering};
31use core::convert::{Infallible, Into, TryInto};
32use core::marker::PhantomData;
33use core::mem;
34
35pub use embedded_can::{ExtendedId, Id, StandardId};
36
37/// CAN Header: includes ID and length
38pub type Header = crate::can::frame::Header;
39
40/// Data for a CAN Frame
41pub type Data = crate::can::frame::ClassicData;
42
43/// CAN Frame
44pub type Frame = crate::can::frame::ClassicFrame;
45
46use 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.
61pub 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.
77pub 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.
91pub unsafe trait MasterInstance: FilterOwner {}
92
93// TODO: what to do with these?
94/*
95#[derive(Debug, Copy, Clone, Eq, PartialEq, Format)]
96pub 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))]
109pub 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))]
125pub(crate) struct IdReg(u32);
126
127impl 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
187impl 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
196impl From<IdReg> for embedded_can::Id {
197 fn from(idr: IdReg) -> Self {
198 idr.id()
199 }
200}
201
202/// `IdReg` is ordered by priority.
203impl 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
230impl 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"]
238pub struct CanConfig<'a, I: Instance> {
239 can: &'a mut Can<I>,
240}
241
242impl<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
330impl<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`"]
339pub struct CanBuilder<I: Instance> {
340 can: Can<I>,
341}
342
343impl<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.
432pub struct Can<I: Instance> {
433 instance: I,
434 canregs: crate::pac::can::Can,
435}
436
437impl<I> Can<I>
438where
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
655impl<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.
666pub struct Tx<I> {
667 _can: PhantomData<I>,
668 canregs: crate::pac::can::Can,
669}
670
671impl<I> Tx<I>
672where
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.
848pub struct Rx0<I> {
849 _can: PhantomData<I>,
850 canregs: crate::pac::can::Can,
851}
852
853impl<I> Rx0<I>
854where
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.
873pub struct Rx1<I> {
874 _can: PhantomData<I>,
875 canregs: crate::pac::can::Can,
876}
877
878impl<I> Rx1<I>
879where
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
897fn 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))]
933pub 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))]
943pub 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`].
954pub struct TransmitStatus {
955 dequeued_frame: Option<Frame>,
956 mailbox: Mailbox,
957}
958
959impl 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 @@
1use core::convert::AsMut;
2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::task::Poll;
6
7pub mod bx;
8
9pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId};
10use embassy_hal_internal::{into_ref, PeripheralRef};
11use futures::FutureExt;
12
13use crate::gpio::sealed::AFType;
14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::can::vals::{Ide, Lec};
16use crate::rcc::RccPeripheral;
17use crate::{interrupt, peripherals, Peripheral};
18
19pub mod enums;
20use enums::*;
21pub mod frame;
22pub 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))]
29pub 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.
38pub struct TxInterruptHandler<T: Instance> {
39 _phantom: PhantomData<T>,
40}
41
42impl<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.
55pub struct Rx0InterruptHandler<T: Instance> {
56 _phantom: PhantomData<T>,
57}
58
59impl<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.
67pub struct Rx1InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>,
69}
70
71impl<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.
79pub struct SceInterruptHandler<T: Instance> {
80 _phantom: PhantomData<T>,
81}
82
83impl<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
97pub 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))]
104pub 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))]
114pub enum TryWriteError {
115 /// All transmit mailboxes are full
116 Full,
117}
118
119impl<'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
302impl<'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.
310pub struct CanTx<'d, T: Instance> {
311 tx: crate::can::bx::Tx<BxcanInstance<'d, T>>,
312}
313
314impl<'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)]
401pub 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
406impl<'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
461enum RxFifo {
462 Fifo0,
463 Fifo1,
464}
465
466impl<'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
475impl<'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
483impl<'d, T: Instance> DerefMut for Can<'d, T> {
484 fn deref_mut(&mut self) -> &mut Self::Target {
485 &mut self.can
486 }
487}
488
489pub(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.
519pub 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.
531pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
532
533unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {}
534
535foreach_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
558foreach_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
593pin_trait!(RxPin, Instance);
594pin_trait!(TxPin, Instance);
595
596trait Index {
597 fn index(&self) -> usize;
598}
599
600impl 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
610trait IntoBusError {
611 fn into_bus_err(self) -> Option<BusError>;
612}
613
614impl 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
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; 5use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
6 6
7const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames 7const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
8const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers 8const 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 @@
1pub mod filter;
2mod registers;
3
4use core::future::poll_fn;
5use core::marker::PhantomData;
6use core::task::Poll;
7
8use embassy_hal_internal::{into_ref, PeripheralRef};
9use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy_sync::channel::Channel;
11use embassy_sync::waitqueue::AtomicWaker;
12pub use embedded_can::{ExtendedId, Id, StandardId};
13
14use self::filter::MasterFilters;
15use self::registers::{Registers, RxFifo};
16pub use super::common::{BufferedCanReceiver, BufferedCanSender};
17use super::frame::{Envelope, Frame};
18use super::util;
19use crate::can::enums::{BusError, TryReadError};
20use crate::gpio::AFType;
21use crate::interrupt::typelevel::Interrupt;
22use crate::rcc::RccPeripheral;
23use crate::{interrupt, peripherals, Peripheral};
24
25/// Interrupt handler.
26pub struct TxInterruptHandler<T: Instance> {
27 _phantom: PhantomData<T>,
28}
29
30impl<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.
42pub struct Rx0InterruptHandler<T: Instance> {
43 _phantom: PhantomData<T>,
44}
45
46impl<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.
53pub struct Rx1InterruptHandler<T: Instance> {
54 _phantom: PhantomData<T>,
55}
56
57impl<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.
64pub struct SceInterruptHandler<T: Instance> {
65 _phantom: PhantomData<T>,
66}
67
68impl<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`].
82pub struct CanConfig<'a, T: Instance> {
83 can: PhantomData<&'a mut T>,
84}
85
86impl<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
137impl<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
145pub 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))]
152pub enum TryWriteError {
153 /// All transmit mailboxes are full
154 Full,
155}
156
157impl<'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
336impl<'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.
347pub 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
352impl<'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.
387pub struct CanTx<'d, T: Instance> {
388 _peri: PeripheralRef<'d, T>,
389}
390
391impl<'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
501pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
502
503/// Buffered CAN driver, transmit half.
504pub 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
509impl<'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
540impl<'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)]
550pub struct CanRx<'d, T: Instance> {
551 peri: PeripheralRef<'d, T>,
552}
553
554impl<'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
586pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
587
588/// CAN driver, receive half in Buffered mode.
589pub 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
594impl<'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
651impl<'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
659impl<'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))]
671pub 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))]
681pub 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`].
692pub struct TransmitStatus {
693 dequeued_frame: Option<Frame>,
694 mailbox: Mailbox,
695}
696
697impl 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
711pub(crate) enum RxMode {
712 NonBuffered(AtomicWaker),
713 Buffered(super::common::ClassicBufferedRxInner),
714}
715
716impl 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
808enum TxMode {
809 NonBuffered(AtomicWaker),
810 Buffered(super::common::ClassicBufferedTxInner),
811}
812
813impl 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
848struct State {
849 pub(crate) rx_mode: RxMode,
850 pub(crate) tx_mode: TxMode,
851 pub err_waker: AtomicWaker,
852}
853
854impl 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
864trait 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)]
872pub 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.
897pub 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.
911pub unsafe trait MasterInstance: FilterOwner {}
912
913foreach_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
939foreach_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
974pin_trait!(RxPin, Instance);
975pin_trait!(TxPin, Instance);
976
977trait Index {
978 fn index(&self) -> usize;
979}
980
981impl 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 @@
1use core::cmp::Ordering;
2use core::convert::Infallible;
3
4pub use embedded_can::{ExtendedId, Id, StandardId};
5use stm32_metapac::can::vals::Lec;
6
7use super::{Mailbox, TransmitStatus};
8use crate::can::enums::BusError;
9use crate::can::frame::{Envelope, Frame, Header};
10
11pub(crate) struct Registers(pub crate::pac::can::Can);
12
13impl 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))]
395pub(crate) struct IdReg(u32);
396
397impl 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
457impl 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
466impl From<IdReg> for embedded_can::Id {
467 fn from(idr: IdReg) -> Self {
468 idr.id()
469 }
470}
471
472/// `IdReg` is ordered by priority.
473impl 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
500impl 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)]
507pub(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 @@
1use embassy_sync::channel::{DynamicReceiver, DynamicSender};
2
3use super::enums::*;
4use super::frame::*;
5
6pub(crate) struct ClassicBufferedRxInner {
7 pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
8}
9pub(crate) struct ClassicBufferedTxInner {
10 pub tx_receiver: DynamicReceiver<'static, Frame>,
11}
12
13#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
14
15pub(crate) struct FdBufferedRxInner {
16 pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>,
17}
18
19#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
20pub(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)]
26pub struct BufferedCanSender {
27 pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
28 pub(crate) waker: fn(),
29}
30
31impl 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.
52pub 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))]
47pub 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;
140impl generic::Readable for TxBufferElementHeader {} 140impl generic::Readable for TxBufferElementHeader {}
141impl generic::Writable for TxBufferElementHeader {} 141impl 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.
153pub 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.
164static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); 144static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]);
165static_assertions::assert_eq_size!(Receive, [u32; 54]); 145static_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
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::{into_ref, PeripheralRef};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::Channel; 8use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender};
9use embassy_sync::waitqueue::AtomicWaker;
9 10
10use crate::can::fd::peripheral::Registers; 11use crate::can::fd::peripheral::Registers;
11use crate::gpio::sealed::AFType; 12use crate::gpio::AFType;
12use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
13use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
14use crate::{interrupt, peripherals, Peripheral}; 15use crate::{interrupt, peripherals, Peripheral};
15 16
16pub mod enums;
17pub(crate) mod fd; 17pub(crate) mod fd;
18pub mod frame;
19mod util;
20 18
21use enums::*; 19use self::fd::config::*;
22use fd::config::*; 20use self::fd::filter::*;
23use fd::filter::*; 21pub use self::fd::{config, filter};
24pub use fd::{config, filter}; 22pub use super::common::{BufferedCanReceiver, BufferedCanSender};
25use frame::*; 23use super::enums::*;
24use super::frame::*;
25use 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
109pub enum FdcanOperatingMode { 109pub 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
147pub struct FdcanConfigurator<'d, T: Instance> { 147pub 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
168impl<'d, T: Instance> FdcanConfigurator<'d, T> { 168impl<'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
303pub struct Fdcan<'d, T: Instance> { 303pub 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
310impl<'d, T: Instance> Fdcan<'d, T> { 310impl<'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
401pub type RxBuf<const BUF_SIZE: usize> = 401pub 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
405pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>; 404pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
406 405
407/// Buffered FDCAN Instance 406/// Buffered FDCAN Instance
408pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 407pub 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)]
418pub struct BufferedCanSender {
419 tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
420 waker: fn(),
421}
422
423impl 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.
444pub type BufferedCanReceiver =
445 embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>;
446
447impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 415impl<'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
519pub type RxFdBuf<const BUF_SIZE: usize> = 487pub 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
523pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; 490pub 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
526pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 493pub 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)]
536pub struct BufferedFdCanSender { 503pub 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.
562pub type BufferedFdCanReceiver = 529pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
563 embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
564 530
565impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 531impl<'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
637pub struct FdcanRx<'d, T: Instance> { 603pub 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
644pub struct FdcanTx<'d, T: Instance> { 610pub 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
650impl<'c, 'd, T: Instance> FdcanTx<'d, T> { 616impl<'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
668impl<'c, 'd, T: Instance> FdcanRx<'d, T> { 634impl<'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
680pub(crate) mod sealed { 646enum 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 { 652impl 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 { 755enum 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 _ => { 761impl 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 { 809struct 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 { 817impl 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 { 828trait 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
862pub trait Instance: sealed::Instance + RccPeripheral + 'static { 839#[allow(private_bounds)]
840pub 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
872macro_rules! impl_fdcan { 850macro_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
4use crate::can::enums::FrameCreateError; 4use crate::can::enums::FrameCreateError;
5 5
6/// Calculate proper timestamp when available.
7#[cfg(feature = "time")]
8pub type Timestamp = embassy_time::Instant;
9
10/// Raw register timestamp
11#[cfg(not(feature = "time"))]
12pub 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)]
8pub struct Header { 16pub 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))]
142pub struct ClassicFrame { 151pub struct Frame {
143 can_header: Header, 152 can_header: Header,
144 data: ClassicData, 153 data: ClassicData,
145} 154}
146 155
147impl ClassicFrame { 156impl 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
209impl embedded_can::Frame for ClassicFrame { 218impl 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
248impl CanHeader for ClassicFrame { 257impl 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))]
273pub struct Envelope {
274 /// Reception time.
275 pub ts: Timestamp,
276 /// The actual CAN frame.
277 pub frame: Frame,
278}
279
280impl 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))]
262pub struct FdData { 292pub 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))]
311pub struct FdFrame { 342pub 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))]
450pub struct FdEnvelope {
451 /// Reception time.
452 pub ts: Timestamp,
453
454 /// The actual CAN frame.
455 pub frame: FdFrame,
456}
457
458impl 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")]
6mod _version; 6mod _version;
7pub use _version::*; 7pub use _version::*;
8
9mod common;
10pub mod enums;
11pub mod frame;
12pub mod util;
13
14pub 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
3use crate::pac::CRC as PAC_CRC; 3use crate::pac::CRC as PAC_CRC;
4use crate::peripherals::CRC; 4use crate::peripherals::CRC;
5use crate::rcc::sealed::RccPeripheral; 5use crate::rcc::SealedRccPeripheral;
6use crate::Peripheral; 6use 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};
3use crate::pac::crc::vals; 3use crate::pac::crc::vals;
4use crate::pac::CRC as PAC_CRC; 4use crate::pac::CRC as PAC_CRC;
5use crate::peripherals::CRC; 5use crate::peripherals::CRC;
6use crate::rcc::sealed::RccPeripheral; 6use crate::rcc::SealedRccPeripheral;
7use crate::Peripheral; 7use 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
1888pub(crate) mod sealed { 1888trait 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.
1897pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 1893#[allow(private_bounds)]
1894pub 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
491pub(crate) mod sealed { 491trait 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.
498pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 496#[allow(private_bounds)]
497pub trait Instance: SealedInstance + RccPeripheral + 'static {}
499dma_trait!(DacDma1, Instance); 498dma_trait!(DacDma1, Instance);
500dma_trait!(DacDma2, Instance); 499dma_trait!(DacDma2, Instance);
501 500
@@ -504,7 +503,7 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
504 503
505foreach_peripheral!( 504foreach_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};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::sealed::AFType; 10use crate::gpio::{AFType, Speed};
11use crate::gpio::Speed;
12use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, Peripheral}; 12use crate::{interrupt, Peripheral};
14 13
@@ -431,14 +430,13 @@ where
431 } 430 }
432} 431}
433 432
434mod sealed { 433trait 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.
441pub trait Instance: sealed::Instance + 'static { 438#[allow(private_bounds)]
439pub 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)]
466macro_rules! impl_peripheral { 464macro_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 @@
1use core::future::Future; 1use core::future::{poll_fn, Future};
2use core::pin::Pin; 2use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering}; 3use core::sync::atomic::{fence, AtomicUsize, Ordering};
4use core::task::{Context, Poll, Waker}; 4use 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
834impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { 878impl<'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
945impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { 1006impl<'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
22pub(crate) mod dmamux_sealed { 22pub(crate) trait SealedMuxChannel {}
23 pub trait MuxChannel {}
24}
25 23
26/// DMAMUX1 instance. 24/// DMAMUX1 instance.
27pub struct DMAMUX1; 25pub struct DMAMUX1;
@@ -30,14 +28,15 @@ pub struct DMAMUX1;
30pub struct DMAMUX2; 28pub struct DMAMUX2;
31 29
32/// DMAMUX channel trait. 30/// DMAMUX channel trait.
33pub trait MuxChannel: dmamux_sealed::MuxChannel { 31#[allow(private_bounds)]
32pub 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
38macro_rules! dmamux_channel_impl { 37macro_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)))]
40pub type Request = (); 40pub type Request = ();
41 41
42pub(crate) mod sealed { 42pub(crate) trait SealedChannel {
43 pub trait Channel { 43 fn id(&self) -> u8;
44 fn id(&self) -> u8; 44}
45 } 45
46 pub trait ChannelInterrupt { 46pub(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.
52pub trait Channel: sealed::Channel + Peripheral<P = Self> + Into<AnyChannel> + 'static { 52#[allow(private_bounds)]
53pub 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
64macro_rules! dma_channel_impl { 65macro_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
99impl sealed::Channel for AnyChannel { 100impl 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
23mod sealed { 23trait 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.
30pub trait Word: sealed::Word + Default + Copy + 'static { 28#[allow(private_bounds)]
29pub 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
37macro_rules! impl_word { 36macro_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
180pub(crate) mod sealed { 180trait 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.
187pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {} 185#[allow(private_bounds)]
186pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {}
188 187
189impl sealed::Instance for crate::peripherals::ETH { 188impl 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
12pub(crate) use self::rx_desc::{RDes, RDesRing}; 12pub(crate) use self::rx_desc::{RDes, RDesRing};
13pub(crate) use self::tx_desc::{TDes, TDesRing}; 13pub(crate) use self::tx_desc::{TDes, TDesRing};
14use super::*; 14use super::*;
15use crate::gpio::sealed::{AFType, Pin as __GpioPin}; 15use crate::gpio::{AFType, AnyPin, SealedPin};
16use crate::gpio::AnyPin;
17use crate::interrupt::InterruptExt; 16use crate::interrupt::InterruptExt;
18#[cfg(eth_v1a)] 17#[cfg(eth_v1a)]
19use crate::pac::AFIO; 18use crate::pac::AFIO;
20#[cfg(any(eth_v1b, eth_v1c))] 19#[cfg(any(eth_v1b, eth_v1c))]
21use crate::pac::SYSCFG; 20use crate::pac::SYSCFG;
22use crate::pac::{ETH, RCC}; 21use crate::pac::{ETH, RCC};
23use crate::rcc::sealed::RccPeripheral; 22use crate::rcc::SealedRccPeripheral;
24use crate::{interrupt, Peripheral}; 23use 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
276unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { 275unsafe 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
306impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 305impl<'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
8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; 8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::*; 9use super::*;
10use crate::gpio::sealed::{AFType, Pin as _}; 10use crate::gpio::{AFType, AnyPin, SealedPin as _, Speed};
11use crate::gpio::{AnyPin, Speed};
12use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
13use crate::pac::ETH; 12use crate::pac::ETH;
14use crate::rcc::sealed::RccPeripheral; 13use crate::rcc::SealedRccPeripheral;
15use crate::{interrupt, Peripheral}; 14use 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
335unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { 334unsafe 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
365impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 364impl<'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
331foreach_exti_irq!(impl_irq); 331foreach_exti_irq!(impl_irq);
332 332
333pub(crate) mod sealed { 333trait SealedChannel {}
334 pub trait Channel {}
335}
336 334
337/// EXTI channel trait. 335/// EXTI channel trait.
338pub trait Channel: sealed::Channel + Sized { 336#[allow(private_bounds)]
337pub 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
361impl_peripheral!(AnyChannel); 360impl_peripheral!(AnyChannel);
362impl sealed::Channel for AnyChannel {} 361impl SealedChannel for AnyChannel {}
363impl Channel for AnyChannel { 362impl 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
369macro_rules! impl_exti { 368macro_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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile; 1use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 2use 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
4use embassy_hal_internal::into_ref; 4use embassy_hal_internal::into_ref;
5 5
6use crate::gpio::sealed::AFType; 6use crate::gpio::{AFType, Pull, Speed};
7use crate::gpio::{Pull, Speed};
8use crate::Peripheral; 7use 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
204pub(crate) mod sealed { 203trait 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.
211pub trait Instance: sealed::Instance + 'static {} 208#[allow(private_bounds)]
209pub trait Instance: SealedInstance + 'static {}
212 210
213foreach_peripheral!( 211foreach_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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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;
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
8 8
9use self::sealed::Pin as _;
10use crate::pac::gpio::{self, vals}; 9use crate::pac::gpio::{self, vals};
11use crate::{pac, peripherals, Peripheral}; 10use 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
511impl From<OutputType> for sealed::AFType { 522impl 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
521pub(crate) mod sealed { 532#[derive(Debug, Copy, Clone)]
522 use super::*; 533#[cfg_attr(feature = "defmt", derive(defmt::Format))]
523 534pub 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] 543pub(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.
676pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 682#[allow(private_bounds)]
683pub 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}
740impl sealed::Pin for AnyPin { 747impl 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
770pub(crate) unsafe fn init(_cs: CriticalSection) { 777pub(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
784impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { 784impl<'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")]
1067pub 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;
17use crate::dma::Transfer; 17use crate::dma::Transfer;
18use crate::interrupt::typelevel::Interrupt; 18use crate::interrupt::typelevel::Interrupt;
19use crate::peripherals::HASH; 19use crate::peripherals::HASH;
20use crate::rcc::sealed::RccPeripheral; 20use crate::rcc::SealedRccPeripheral;
21use crate::{interrupt, pac, peripherals, Peripheral}; 21use 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
564pub(crate) mod sealed { 564trait 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.
573pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 569#[allow(private_bounds)]
570pub 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;
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8pub use traits::Instance; 8pub use traits::Instance;
9 9
10#[allow(unused_imports)] 10use crate::gpio::{AFType, AnyPin};
11use crate::gpio::sealed::{AFType, Pin};
12use crate::gpio::AnyPin;
13use crate::time::Hertz; 11use crate::time::Hertz;
14use crate::Peripheral; 12use 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
57mod sealed { 55trait 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.
66pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 60#[allow(private_bounds)]
61pub trait AdvancedChannel<T: Instance>: SealedAdvancedChannel<T> {}
67 62
68/// HRTIM PWM pin. 63/// HRTIM PWM pin.
69pub struct PwmPin<'d, T, C> { 64pub 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 @@
1use crate::rcc::sealed::RccPeripheral; 1use crate::rcc::RccPeripheral;
2use crate::time::Hertz; 2use crate::time::Hertz;
3 3
4#[repr(u8)] 4#[repr(u8)]
@@ -72,94 +72,92 @@ impl Prescaler {
72 } 72 }
73} 73}
74 74
75pub(crate) mod sealed { 75pub(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.
158pub trait Instance: sealed::Instance + 'static {} 155#[allow(private_bounds)]
156pub trait Instance: SealedInstance + 'static {}
159 157
160foreach_interrupt! { 158foreach_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;
14use embassy_time::{Duration, Instant}; 14use embassy_time::{Duration, Instant};
15 15
16use crate::dma::NoDma; 16use crate::dma::NoDma;
17use crate::gpio::sealed::AFType; 17use crate::gpio::{AFType, Pull};
18use crate::gpio::Pull;
19use crate::interrupt::typelevel::Interrupt; 18use crate::interrupt::typelevel::Interrupt;
20use crate::time::Hertz; 19use crate::time::Hertz;
21use crate::{interrupt, peripherals}; 20use crate::{interrupt, peripherals};
@@ -175,30 +174,27 @@ impl Timeout {
175 } 174 }
176} 175}
177 176
178pub(crate) mod sealed { 177struct 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 { 182impl 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 { 190trait 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
201pub trait Instance: sealed::Instance + 'static { 196#[allow(private_bounds)]
197pub 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
235foreach_peripheral!( 231foreach_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;
15use super::*; 15use super::*;
16use crate::dma::Transfer; 16use crate::dma::Transfer;
17use crate::pac::i2c; 17use crate::pac::i2c;
18use 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;
9use super::*; 9use super::*;
10use crate::dma::Transfer; 10use crate::dma::Transfer;
11use crate::pac::i2c; 11use crate::pac::i2c;
12use crate::time::Hertz;
13 12
14pub(crate) unsafe fn on_interrupt<T: Instance>() { 13pub(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)
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use crate::gpio::sealed::{AFType, Pin as _}; 4use crate::gpio::{AFType, AnyPin, SealedPin};
5use crate::gpio::AnyPin;
6use crate::pac::spi::vals; 5use crate::pac::spi::vals;
7use crate::spi::{Config as SpiConfig, *}; 6use crate::spi::{Config as SpiConfig, *};
8use crate::time::Hertz; 7use 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;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use self::sealed::Instance; 7use embassy_sync::waitqueue::AtomicWaker;
8
8use crate::interrupt; 9use crate::interrupt;
9use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
10use crate::peripherals::IPCC; 11use crate::peripherals::IPCC;
11use crate::rcc::sealed::RccPeripheral; 12use crate::rcc::SealedRccPeripheral;
12 13
13/// Interrupt handler. 14/// Interrupt handler.
14pub struct ReceiveInterruptHandler {} 15pub struct ReceiveInterruptHandler {}
@@ -207,7 +208,7 @@ impl Ipcc {
207 } 208 }
208} 209}
209 210
210impl sealed::Instance for crate::peripherals::IPCC { 211impl 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
225pub(crate) mod sealed { 226struct 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 { 231impl 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 { 264trait 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;
158use crate::interrupt::Priority; 158use crate::interrupt::Priority;
159#[cfg(feature = "rt")] 159#[cfg(feature = "rt")]
160pub use crate::pac::NVIC_PRIO_BITS; 160pub use crate::pac::NVIC_PRIO_BITS;
161use crate::rcc::sealed::RccPeripheral; 161use 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. 169pub(crate) trait SealedInstance {
170pub trait Instance: sealed::Instance + 'static {} 170 fn regs() -> crate::pac::opamp::Opamp;
171 171}
172pub(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> { 173pub(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> {} 177pub(crate) trait SealedInvertingPin<T: Instance> {
178 #[allow(unused)]
179 fn channel(&self) -> u8;
186} 180}
187 181
182pub(crate) trait SealedOutputPin<T: Instance> {}
183
184/// Opamp instance trait.
185#[allow(private_bounds)]
186pub trait Instance: SealedInstance + 'static {}
188/// Non-inverting pin trait. 187/// Non-inverting pin trait.
189pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} 188#[allow(private_bounds)]
189pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {}
190/// Inverting pin trait. 190/// Inverting pin trait.
191pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} 191#[allow(private_bounds)]
192pub trait InvertingPin<T: Instance>: SealedInvertingPin<T> {}
192/// Output pin trait. 193/// Output pin trait.
193pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} 194#[allow(private_bounds)]
195pub trait OutputPin<T: Instance>: SealedOutputPin<T> {}
194 196
195macro_rules! impl_opamp_external_output { 197macro_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
292foreach_peripheral! { 294foreach_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! {
306macro_rules! impl_opamp_vp_pin { 308macro_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 {
318macro_rules! impl_opamp_vout_pin { 320macro_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};
8use enums::*; 8use enums::*;
9 9
10use crate::dma::Transfer; 10use crate::dma::Transfer;
11use crate::gpio::sealed::AFType; 11use crate::gpio::{AFType, AnyPin, Pull};
12use crate::gpio::{AnyPin, Pull};
13use crate::pac::quadspi::Quadspi as Regs; 12use crate::pac::quadspi::Quadspi as Regs;
14use crate::rcc::RccPeripheral; 13use crate::rcc::RccPeripheral;
15use crate::{peripherals, Peripheral}; 14use crate::{peripherals, Peripheral};
@@ -381,16 +380,13 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
381 } 380 }
382} 381}
383 382
384pub(crate) mod sealed { 383trait 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.
393pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 388#[allow(private_bounds)]
389pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
394 390
395pin_trait!(SckPin, Instance); 391pin_trait!(SckPin, Instance);
396pin_trait!(BK1D0Pin, Instance); 392pin_trait!(BK1D0Pin, Instance);
@@ -409,7 +405,7 @@ dma_trait!(QuadDma, Instance);
409 405
410foreach_peripheral!( 406foreach_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)]
26pub enum LseDrive { 26pub 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
3use crate::pac::crs::vals::Syncsrc; 3use crate::pac::crs::vals::Syncsrc;
4use crate::pac::{CRS, RCC}; 4use crate::pac::{CRS, RCC};
5use crate::rcc::sealed::RccPeripheral; 5use crate::rcc::SealedRccPeripheral;
6use crate::time::Hertz; 6use 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
3use embassy_hal_internal::into_ref; 3use embassy_hal_internal::into_ref;
4 4
5use crate::gpio::sealed::AFType; 5use crate::gpio::{AFType, Speed};
6use 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)))]
8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 7pub 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
22pub(crate) mod sealed { 21pub(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
29pub trait McoInstance: sealed::McoInstance + 'static {} 23#[allow(private_bounds)]
24pub 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
31pin_trait!(McoPin, McoInstance); 31pin_trait!(McoPin, McoInstance);
32 32
33macro_rules! impl_peri { 33macro_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))]
12mod mco; 12mod mco;
13use critical_section::CriticalSection;
13#[cfg(any(mco, mco1, mco2))] 14#[cfg(any(mco, mco1, mco2))]
14pub use mco::*; 15pub use mco::*;
15 16
@@ -32,6 +33,7 @@ mod _version;
32pub use _version::*; 33pub use _version::*;
33 34
34pub use crate::_generated::{mux, Clocks}; 35pub use crate::_generated::{mux, Clocks};
36use 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")] 68pub(crate) trait SealedRccPeripheral {
67pub 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
71pub(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
88pub trait RccPeripheral: sealed::RccPeripheral + 'static {} 81#[allow(private_bounds)]
82pub trait RccPeripheral: SealedRccPeripheral + 'static {}
89 83
90#[allow(unused)] 84#[allow(unused)]
91mod util { 85mod 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.
119pub 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
223impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} 223impl<'d, T: Instance> CryptoRng for Rng<'d, T> {}
224 224
225pub(crate) mod sealed { 225trait 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.
234pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 230#[allow(private_bounds)]
231pub 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")]
2use core::convert::From; 2use chrono::{Datelike, NaiveDate, Timelike, Weekday};
3
4#[cfg(feature = "chrono")]
5use chrono::{self, Datelike, NaiveDate, Timelike, Weekday};
6 3
7#[cfg(any(feature = "defmt", feature = "time"))] 4#[cfg(any(feature = "defmt", feature = "time"))]
8use crate::peripherals::RTC; 5use crate::peripherals::RTC;
9#[cfg(any(feature = "defmt", feature = "time"))] 6#[cfg(any(feature = "defmt", feature = "time"))]
10use crate::rtc::sealed::Instance; 7use 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
13pub struct RtcInstant { 10pub 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::*;
31use embassy_hal_internal::Peripheral; 31use embassy_hal_internal::Peripheral;
32 32
33use crate::peripherals::RTC; 33use crate::peripherals::RTC;
34use 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
480pub(crate) mod sealed { 479trait 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 @@
1use stm32_metapac::rtc::vals::{Osel, Pol}; 1use stm32_metapac::rtc::vals::{Osel, Pol};
2 2
3use super::sealed; 3use super::SealedInstance;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC; 5use crate::peripherals::RTC;
6use crate::rtc::sealed::Instance;
7 6
8#[allow(dead_code)] 7#[allow(dead_code)]
9impl super::Rtc { 8impl super::Rtc {
@@ -126,7 +125,7 @@ impl super::Rtc {
126 } 125 }
127} 126}
128 127
129impl sealed::Instance for crate::peripherals::RTC { 128impl 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 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::{sealed, RtcCalibrationCyclePeriod}; 3use super::RtcCalibrationCyclePeriod;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC; 5use crate::peripherals::RTC;
6use crate::rtc::sealed::Instance; 6use crate::rtc::SealedInstance;
7 7
8impl super::Rtc { 8impl 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
129impl sealed::Instance for crate::peripherals::RTC { 129impl 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
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8 8
9use self::sealed::WhichSubBlock;
10pub use crate::dma::word; 9pub use crate::dma::word;
11#[cfg(not(gpdma))] 10#[cfg(not(gpdma))]
12use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 11use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
13use crate::gpio::sealed::{AFType, Pin as _}; 12use crate::gpio::{AFType, AnyPin, SealedPin as _};
14use crate::gpio::AnyPin;
15use crate::pac::sai::{vals, Sai as Regs}; 13use crate::pac::sai::{vals, Sai as Regs};
16use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
17use crate::{peripherals, Peripheral}; 15use 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
1044pub(crate) mod sealed { 1042trait 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 { 1047enum WhichSubBlock {
1053 A = 0, 1048 A = 0,
1054 B = 1, 1049 B = 1,
1055 } 1050}
1056 1051
1057 pub trait SubBlock { 1052trait SealedSubBlock {
1058 const WHICH: WhichSubBlock; 1053 const WHICH: WhichSubBlock;
1059 }
1060} 1054}
1061 1055
1062/// Sub-block instance trait. 1056/// Sub-block instance trait.
1063pub trait SubBlockInstance: sealed::SubBlock {} 1057#[allow(private_bounds)]
1058pub trait SubBlockInstance: SealedSubBlock {}
1064 1059
1065/// Sub-block A. 1060/// Sub-block A.
1066pub enum A {} 1061pub enum A {}
1067impl sealed::SubBlock for A { 1062impl SealedSubBlock for A {
1068 const WHICH: WhichSubBlock = WhichSubBlock::A; 1063 const WHICH: WhichSubBlock = WhichSubBlock::A;
1069} 1064}
1070impl SubBlockInstance for A {} 1065impl SubBlockInstance for A {}
1071 1066
1072/// Sub-block B. 1067/// Sub-block B.
1073pub enum B {} 1068pub enum B {}
1074impl sealed::SubBlock for B { 1069impl SealedSubBlock for B {
1075 const WHICH: WhichSubBlock = WhichSubBlock::B; 1070 const WHICH: WhichSubBlock = WhichSubBlock::B;
1076} 1071}
1077impl SubBlockInstance for B {} 1072impl SubBlockInstance for B {}
1078 1073
1079/// SAI instance trait. 1074/// SAI instance trait.
1080pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1075#[allow(private_bounds)]
1076pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
1077
1081pin_trait!(SckPin, Instance, SubBlockInstance); 1078pin_trait!(SckPin, Instance, SubBlockInstance);
1082pin_trait!(FsPin, Instance, SubBlockInstance); 1079pin_trait!(FsPin, Instance, SubBlockInstance);
1083pin_trait!(SdPin, Instance, SubBlockInstance); 1080pin_trait!(SdPin, Instance, SubBlockInstance);
@@ -1087,7 +1084,7 @@ dma_trait!(Dma, Instance, SubBlockInstance);
1087 1084
1088foreach_peripheral!( 1085foreach_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;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; 13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
14 14
15use crate::dma::NoDma; 15use crate::dma::NoDma;
16use crate::gpio::sealed::{AFType, Pin}; 16use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed};
17use crate::gpio::{AnyPin, Pull, Speed};
18use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
19use crate::pac::sdmmc::Sdmmc as RegBlock; 18use crate::pac::sdmmc::Sdmmc as RegBlock;
20use crate::rcc::RccPeripheral; 19use crate::rcc::RccPeripheral;
@@ -1418,21 +1417,17 @@ impl Cmd {
1418 1417
1419////////////////////////////////////////////////////// 1418//////////////////////////////////////////////////////
1420 1419
1421pub(crate) mod sealed { 1420trait 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.
1435pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 1426#[allow(private_bounds)]
1427pub trait Instance: SealedInstance + RccPeripheral + 'static {
1428 /// Interrupt for this instance.
1429 type Interrupt: interrupt::typelevel::Interrupt;
1430}
1436 1431
1437pin_trait!(CkPin, Instance); 1432pin_trait!(CkPin, Instance);
1438pin_trait!(CmdPin, Instance); 1433pin_trait!(CmdPin, Instance);
@@ -1459,9 +1454,7 @@ impl<T: Instance> SdmmcDma<T> for NoDma {}
1459 1454
1460foreach_peripheral!( 1455foreach_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};
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
10 10
11use crate::dma::{slice_ptr_parts, word, Transfer}; 11use crate::dma::{slice_ptr_parts, word, Transfer};
12use crate::gpio::sealed::{AFType, Pin as _}; 12use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _};
13use crate::gpio::{AnyPin, Pull};
14use crate::pac::spi::{regs, vals, Spi as Regs}; 13use crate::pac::spi::{regs, vals, Spi as Regs};
15use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
16use crate::time::Hertz; 15use 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
978pub(crate) mod sealed { 977pub(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 { 981trait 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.
991pub trait Word: word::Word + sealed::Word {} 986#[allow(private_bounds)]
987pub trait Word: word::Word + SealedWord {}
992 988
993macro_rules! impl_word { 989macro_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.
1071pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1067#[allow(private_bounds)]
1068pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
1072 1069
1073pin_trait!(SckPin, Instance); 1070pin_trait!(SckPin, Instance);
1074pin_trait!(MosiPin, Instance); 1071pin_trait!(MosiPin, Instance);
@@ -1082,7 +1079,7 @@ dma_trait!(TxDma, Instance);
1082 1079
1083foreach_peripheral!( 1080foreach_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
3use core::cell::Cell; 3use core::cell::Cell;
4use core::convert::TryInto;
5use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
6use core::{mem, ptr}; 5use core::{mem, ptr};
7 6
@@ -9,16 +8,16 @@ use critical_section::CriticalSection;
9use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy_sync::blocking_mutex::Mutex; 9use embassy_sync::blocking_mutex::Mutex;
11use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; 10use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ};
12use stm32_metapac::timer::regs; 11use stm32_metapac::timer::{regs, TimGp16};
13 12
14use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
15use crate::pac::timer::vals; 14use crate::pac::timer::vals;
16use crate::rcc::sealed::RccPeripheral; 15use crate::rcc::SealedRccPeripheral;
17#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
18use crate::rtc::Rtc; 17use 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))]
20use crate::timer::sealed::AdvancedControlInstance; 19use crate::timer::AdvancedInstance1Channel;
21use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; 20use crate::timer::CoreInstance;
22use crate::{interrupt, peripherals}; 21use 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
210fn 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
273impl RtcDriver { 276impl 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
524impl Driver for RtcDriver { 527impl 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;
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals::Ckd; 6use stm32_metapac::timer::vals::Ckd;
7 7
8use super::simple_pwm::*; 8use super::low_level::{CountingMode, OutputPolarity, Timer};
9use super::*; 9use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin};
10#[allow(unused_imports)] 10use super::{
11use crate::gpio::sealed::{AFType, Pin}; 11 AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin,
12 Channel4ComplementaryPin,
13};
12use crate::gpio::{AnyPin, OutputType}; 14use crate::gpio::{AnyPin, OutputType};
13use crate::time::Hertz; 15use crate::time::Hertz;
16use crate::timer::low_level::OutputCompareMode;
14use crate::Peripheral; 17use 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
24macro_rules! complementary_channel_impl { 27macro_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);
48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 51complementary_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.
51pub struct ComplementaryPwm<'d, T> { 54pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> {
52 inner: PeripheralRef<'d, T>, 55 inner: Timer<'d, T>,
53} 56}
54 57
55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 58impl<'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
152impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { 151impl<'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
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10
11use super::*;
12use crate::pac::timer::vals;
13use crate::time::Hertz;
14
15/// Input capture mode.
16#[derive(Clone, Copy)]
17pub 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)]
28pub enum InputTISelection {
29 /// Normal
30 Normal,
31 /// Alternate
32 Alternate,
33 /// TRC
34 TRC,
35}
36
37impl 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)]
50pub 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
73impl 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
90impl 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
102impl 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)]
116pub 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
144impl 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)]
161pub 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
168impl 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.
178pub struct Timer<'d, T: CoreInstance> {
179 tim: PeripheralRef<'d, T>,
180}
181
182impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
183 fn drop(&mut self) {
184 T::disable()
185 }
186}
187
188impl<'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
323impl<'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
345impl<'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
357impl<'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
383impl<'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
395impl<'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))]
565impl<'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))]
578impl<'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))]
606impl<'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))]
619impl<'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))]
35pub mod complementary_pwm; 4pub mod complementary_pwm;
5pub mod low_level;
36pub mod qei; 6pub mod qei;
37pub mod simple_pwm; 7pub mod simple_pwm;
38 8
39use stm32_metapac::timer::vals;
40
41use crate::interrupt; 9use crate::interrupt;
42use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
43use crate::time::Hertz;
44
45/// Low-level timer access.
46#[cfg(feature = "unstable-pac")]
47pub mod low_level {
48 pub use super::sealed::*;
49}
50
51pub(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)]
516pub enum InputCaptureMode { 39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
517 /// Rising edge only. 40pub 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)] 49pub trait CoreInstance: RccPeripheral + 'static {
527pub 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
536impl 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)]
549pub 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
572impl 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
589impl 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
601impl 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)]
615pub 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
643impl 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.
62pub trait BasicNoCr2Instance: CoreInstance {}
63/// Basic timer instance.
64pub trait BasicInstance: BasicNoCr2Instance {}
657 65
658/// Timer output pin polarity. 66/// General-purpose 16-bit timer with 1 channel instance.
659#[derive(Clone, Copy)] 67pub trait GeneralInstance1Channel: CoreInstance {}
660pub 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
667impl From<OutputPolarity> for bool { 69/// General-purpose 16-bit timer with 2 channels instance.
668 fn from(mode: OutputPolarity) -> Self { 70pub 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.
677pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} 73pub 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.
681pub 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. 84pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {}
699/// Capture Compare 32-bit timer instance.
700pub 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.
708pub trait ComplementaryCaptureCompare16bitInstance:
709 CaptureCompare16bitInstance
710 + sealed::GeneralPurpose1ChannelComplementaryInstance
711 + sealed::GeneralPurpose2ChannelComplementaryInstance
712 + sealed::AdvancedControlInstance
713 + 'static
714{
715}
716
717pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
718pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
719pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
720pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
721pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
722
723cfg_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); 87pub 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)] 93pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {}
742macro_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()) } 96pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
749 }
750 }
751 };
752}
753 97
754#[allow(unused)] 98pin_trait!(Channel1Pin, GeneralInstance4Channel);
755macro_rules! impl_basic_no_cr2_timer { 99pin_trait!(Channel2Pin, GeneralInstance4Channel);
756 ($inst:ident) => { 100pin_trait!(Channel3Pin, GeneralInstance4Channel);
757 impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { 101pin_trait!(Channel4Pin, GeneralInstance4Channel);
758 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { 102pin_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)] 104pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel);
766macro_rules! impl_basic_timer { 105pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel);
767 ($inst:ident) => { 106pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel);
768 impl sealed::BasicInstance for crate::peripherals::$inst { 107pin_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)] 109pin_trait!(BreakInputPin, AdvancedInstance4Channel);
777macro_rules! impl_1ch_timer { 110pin_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)] 112pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel);
788macro_rules! impl_2ch_timer { 113pin_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)] 115pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel);
799macro_rules! impl_gp16_timer { 116pin_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
810macro_rules! impl_gp32_timer { 119dma_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)] 121dma_trait!(Ch1Dma, GeneralInstance4Channel);
821macro_rules! impl_1ch_cmp_timer { 122dma_trait!(Ch2Dma, GeneralInstance4Channel);
822 ($inst:ident) => { 123dma_trait!(Ch3Dma, GeneralInstance4Channel);
823 impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { 124dma_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)]
832macro_rules! impl_2ch_cmp_timer { 127macro_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;
843macro_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
855foreach_interrupt! { 141foreach_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))]
984dma_trait!(UpDma, BasicInstance); 223#[allow(unused)]
985 224fn set_moe<T: GeneralInstance4Channel>() {
986dma_trait!(Ch1Dma, CaptureCompare16bitInstance); 225 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
987dma_trait!(Ch2Dma, CaptureCompare16bitInstance); 226 .bdtr()
988dma_trait!(Ch3Dma, CaptureCompare16bitInstance); 227 .modify(|w| w.set_moe(true));
989dma_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 @@
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals;
6 7
7use super::*; 8use super::low_level::Timer;
8use crate::gpio::sealed::AFType; 9use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel};
9use crate::gpio::AnyPin; 10use crate::gpio::{AFType, AnyPin};
10use crate::Peripheral; 11use crate::Peripheral;
11 12
12/// Counting direction 13/// Counting direction
@@ -30,7 +31,7 @@ pub struct QeiPin<'d, T, Channel> {
30 31
31macro_rules! channel_impl { 32macro_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);
53channel_impl!(new_ch2, Ch2, Channel2Pin); 54channel_impl!(new_ch2, Ch2, Channel2Pin);
54 55
55/// Quadrature decoder driver. 56/// Quadrature decoder driver.
56pub struct Qei<'d, T> { 57pub struct Qei<'d, T: GeneralInstance4Channel> {
57 _inner: PeripheralRef<'d, T>, 58 inner: Timer<'d, T>,
58} 59}
59 60
60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 61impl<'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
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6 6
7use super::*; 7use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
8#[allow(unused_imports)] 8use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel};
9use crate::gpio::sealed::{AFType, Pin};
10use crate::gpio::{AnyPin, OutputType}; 9use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 10use crate::time::Hertz;
12use crate::Peripheral; 11use crate::Peripheral;
@@ -30,7 +29,7 @@ pub struct PwmPin<'d, T, C> {
30 29
31macro_rules! channel_impl { 30macro_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);
55channel_impl!(new_ch4, Ch4, Channel4Pin); 54channel_impl!(new_ch4, Ch4, Channel4Pin);
56 55
57/// Simple PWM driver. 56/// Simple PWM driver.
58pub struct SimplePwm<'d, T> { 57pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
59 inner: PeripheralRef<'d, T>, 58 inner: Timer<'d, T>,
60} 59}
61 60
62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 61impl<'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
229macro_rules! impl_waveform_chx { 222macro_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);
315impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); 306impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
316impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); 307impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
317 308
318impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 309impl<'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
17use core::future::poll_fn; 17use core::future::poll_fn;
18use core::marker::PhantomData; 18use core::marker::PhantomData;
19use core::sync::atomic::Ordering; 19use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
22use embassy_hal_internal::drop::OnDrop; 22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 23use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
24use embassy_sync::waitqueue::AtomicWaker;
24 25
25use crate::dma::{AnyChannel, Request, Transfer, TransferOptions}; 26use crate::dma::{AnyChannel, Request, Transfer, TransferOptions};
26use crate::interrupt; 27use 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. 559struct State {
559pub 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.
561mod 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 { 565impl 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 { 574trait 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)]
581pub trait Instance: SealedInstance + RccPeripheral {
582 /// Interrupt for this instance.
583 type Interrupt: crate::interrupt::typelevel::Interrupt;
586} 584}
587 585
588foreach_interrupt!( 586foreach_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 @@
1use core::future::poll_fn;
2use core::slice; 1use core::slice;
3use core::sync::atomic::{AtomicBool, Ordering}; 2use core::sync::atomic::AtomicBool;
4use core::task::Poll;
5 3
6use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 4use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
8 6
9use super::*; 7use super::*;
10use crate::interrupt::typelevel::Interrupt;
11 8
12/// Interrupt handler. 9/// Interrupt handler.
13pub struct InterruptHandler<T: BasicInstance> { 10pub 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;
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::drop::OnDrop; 11use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::{into_ref, PeripheralRef}; 12use embassy_hal_internal::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker;
13use futures::future::{select, Either}; 14use futures::future::{select, Either};
14 15
15use crate::dma::{NoDma, Transfer}; 16use crate::dma::{NoDma, Transfer};
16use crate::gpio::sealed::AFType; 17use crate::gpio::AFType;
17use crate::interrupt::typelevel::Interrupt; 18use 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`.
212pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 220pub 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.
228pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 239pub 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).
243pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 282pub 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
1259impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> 1298impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma>
1260where 1299where
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
1274impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> 1312impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma>
1275where 1313where
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))]
1327pub use ringbuffered::RingBufferedUartRx; 1364pub use ringbuffered::RingBufferedUartRx;
1328 1365
1329use self::sealed::Kind;
1330
1331#[cfg(any(usart_v1, usart_v2))] 1366#[cfg(any(usart_v1, usart_v2))]
1332fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { 1367fn 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
1373pub(crate) mod sealed { 1408#[derive(Clone, Copy, PartialEq, Eq)]
1374 use embassy_sync::waitqueue::AtomicWaker; 1409enum 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 { 1416struct State {
1386 pub rx_waker: AtomicWaker, 1417 rx_waker: AtomicWaker,
1387 pub tx_waker: AtomicWaker, 1418}
1388 }
1389 1419
1390 impl State { 1420impl 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 { 1428trait 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 { 1437trait 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
1415pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} 1443#[allow(private_bounds)]
1444pub 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
1418pub trait FullInstance: sealed::FullInstance {} 1450#[allow(private_bounds)]
1451pub trait FullInstance: SealedFullInstance {}
1419 1452
1420pin_trait!(RxPin, BasicInstance); 1453pin_trait!(RxPin, BasicInstance);
1421pin_trait!(TxPin, BasicInstance); 1454pin_trait!(TxPin, BasicInstance);
@@ -1429,16 +1462,15 @@ dma_trait!(RxDma, BasicInstance);
1429 1462
1430macro_rules! impl_usart { 1463macro_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;
6pub use _version::*; 6pub use _version::*;
7 7
8use crate::interrupt::typelevel::Interrupt; 8use crate::interrupt::typelevel::Interrupt;
9use crate::rcc::sealed::RccPeripheral; 9use 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.
12fn common_init<T: Instance>() { 12fn 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;
6use embassy_hal_internal::{into_ref, Peripheral}; 6use embassy_hal_internal::{into_ref, Peripheral};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embassy_usb_driver::{ 8use 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};
12use futures::future::poll_fn; 12use futures::future::poll_fn;
13 13
14use crate::gpio::sealed::AFType; 14use crate::gpio::AFType;
15use crate::interrupt; 15use crate::interrupt;
16use crate::interrupt::typelevel::Interrupt; 16use crate::interrupt::typelevel::Interrupt;
17use crate::pac::otg::{regs, vals}; 17use crate::pac::otg::{regs, vals};
18use crate::rcc::sealed::RccPeripheral; 18use crate::rcc::{RccPeripheral, SealedRccPeripheral};
19use crate::time::Hertz; 19use 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
1437const MAX_EP_COUNT: usize = 9; 1437const MAX_EP_COUNT: usize = 9;
1438 1438
1439pub(crate) mod sealed { 1439trait 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.
1451pub trait Instance: sealed::Instance + RccPeripheral + 'static { 1449#[allow(private_bounds)]
1450pub 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
1474foreach_interrupt!( 1473foreach_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::{
15use crate::pac::usb::regs; 15use crate::pac::usb::regs;
16use crate::pac::usb::vals::{EpType, Stat}; 16use crate::pac::usb::vals::{EpType, Stat};
17use crate::pac::USBRAM; 17use crate::pac::USBRAM;
18use crate::rcc::sealed::RccPeripheral; 18use crate::rcc::RccPeripheral;
19use crate::{interrupt, Peripheral}; 19use 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
638trait Dir { 638trait 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
1051pub(crate) mod sealed { 1040trait 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.
1058pub trait Instance: sealed::Instance + RccPeripheral + 'static { 1045#[allow(private_bounds)]
1046pub 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
1067foreach_interrupt!( 1055foreach_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
83mod sealed { 83trait 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.
90pub trait Instance: sealed::Instance {} 88#[allow(private_bounds)]
89pub trait Instance: SealedInstance {}
91 90
92foreach_peripheral!( 91foreach_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/
20target = "thumbv7em-none-eabi" 20target = "thumbv7em-none-eabi"
21 21
22[features] 22[features]
23std = [] 23std = ["critical-section/std"]
24turbowakers = [] 24turbowakers = []
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.
5Synchronization primitives and data structures with async support: 5Synchronization 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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;
13pub mod blocking_mutex; 13pub mod blocking_mutex;
14pub mod channel; 14pub mod channel;
15pub mod mutex; 15pub mod mutex;
16pub mod once_lock;
16pub mod pipe; 17pub mod pipe;
17pub mod priority_channel; 18pub mod priority_channel;
18pub mod pubsub; 19pub mod pubsub;
20pub mod semaphore;
19pub mod signal; 21pub mod signal;
20pub mod waitqueue; 22pub mod waitqueue;
21pub mod zerocopy_channel; 23pub 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
3use core::cell::Cell;
4use core::future::poll_fn;
5use core::mem::MaybeUninit;
6use core::sync::atomic::{AtomicBool, Ordering};
7use 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/// ```
40pub struct OnceLock<T> {
41 init: AtomicBool,
42 data: Cell<MaybeUninit<T>>,
43}
44
45unsafe impl<T> Sync for OnceLock<T> {}
46
47impl<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)]
154mod 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.
2use core::cell::{Cell, RefCell};
3use core::convert::Infallible;
4use core::future::{poll_fn, Future};
5use core::task::{Poll, Waker};
6
7use heapless::Deque;
8
9use crate::blocking_mutex::raw::RawMutex;
10use crate::blocking_mutex::Mutex;
11use 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.
18pub 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.
49pub struct SemaphoreReleaser<'a, S: Semaphore> {
50 semaphore: &'a S,
51 permits: usize,
52}
53
54impl<'a, S: Semaphore> Drop for SemaphoreReleaser<'a, S> {
55 fn drop(&mut self) {
56 self.semaphore.release(self.permits);
57 }
58}
59
60impl<'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.
80pub struct GreedySemaphore<M: RawMutex> {
81 state: Mutex<M, Cell<SemaphoreState>>,
82}
83
84impl<M: RawMutex> Default for GreedySemaphore<M> {
85 fn default() -> Self {
86 Self::new(0)
87 }
88}
89
90impl<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
136impl<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
184struct SemaphoreState {
185 permits: usize,
186 waker: WakerRegistration,
187}
188
189impl 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.
224pub struct FairSemaphore<M, const N: usize>
225where
226 M: RawMutex,
227{
228 state: Mutex<M, RefCell<FairSemaphoreState<N>>>,
229}
230
231impl<M, const N: usize> Default for FairSemaphore<M, N>
232where
233 M: RawMutex,
234{
235 fn default() -> Self {
236 Self::new(0)
237 }
238}
239
240impl<M, const N: usize> FairSemaphore<M, N>
241where
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))]
288pub struct WaitQueueFull;
289
290impl<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
344struct FairAcquire<'a, M: RawMutex, const N: usize> {
345 sema: &'a FairSemaphore<M, N>,
346 permits: usize,
347 ticket: Option<usize>,
348}
349
350impl<'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
358impl<'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
367struct FairAcquireAll<'a, M: RawMutex, const N: usize> {
368 sema: &'a FairSemaphore<M, N>,
369 min: usize,
370 ticket: Option<usize>,
371}
372
373impl<'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
381impl<'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
390struct FairSemaphoreState<const N: usize> {
391 permits: usize,
392 next_ticket: usize,
393 wakers: Deque<Option<Waker>, N>,
394}
395
396impl<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)]
488mod 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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.
17pub struct LoggerState<'d> { 17pub 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
152impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { 149impl<'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.
252pub(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.
273pub struct BosWriter<'a> { 276pub 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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))]
170pub struct UsbBufferReport { 170pub 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
229mod sealed { 229/// A trait for descriptors
230 use core::mem::size_of; 230trait 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
249use sealed::*; 241trait 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::*;
255unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { 249unsafe 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)]
415pub trait DeviceLevelDescriptor: Descriptor {} 410pub 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)]
418pub trait FunctionLevelDescriptor: Descriptor {} 414pub 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 @@
1use std::default::Default;
2
3use clap::Parser; 1use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
5use embassy_net::tcp::TcpSocket; 3use 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 @@
1use std::default::Default;
2
3use clap::Parser; 1use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
5use embassy_net::dns::DnsQueryType; 3use 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 @@
1use core::fmt::Write as _; 1use core::fmt::Write as _;
2use std::default::Default;
3 2
4use clap::Parser; 3use clap::Parser;
5use embassy_executor::{Executor, Spawner}; 4use 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"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
25nb = "1.0.0" 25nb = "1.0.0"
26static_cell = "2.0.0"
26 27
27[profile.dev] 28[profile.dev]
28opt-level = "s" 29opt-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
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::can::frame::Envelope;
6use embassy_stm32::can::{ 7use 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};
10use embassy_stm32::peripherals::CAN; 11use embassy_stm32::peripherals::CAN;
11use embassy_stm32::{bind_interrupts, Config}; 12use embassy_stm32::{bind_interrupts, Config};
13use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
13 15
14bind_interrupts!(struct Irqs { 16bind_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
26fn 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]
25async fn main(_spawner: Spawner) { 48async 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
4use core::convert::TryFrom;
5
6use defmt::*; 4use defmt::*;
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_stm32::time::Hertz; 6use 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 @@
15use embassy_executor::Spawner; 15use embassy_executor::Spawner;
16use embassy_stm32::gpio::OutputType; 16use embassy_stm32::gpio::OutputType;
17use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
18use embassy_stm32::timer::low_level::CountingMode;
18use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 19use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
19use embassy_stm32::timer::{Channel, CountingMode}; 20use embassy_stm32::timer::Channel;
20use embassy_time::{Duration, Ticker, Timer}; 21use embassy_time::{Duration, Ticker, Timer};
21use {defmt_rtt as _, panic_probe as _}; 22use {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.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-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;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::pac::timer::vals::Mms; 7use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {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]
59async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 59async 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]
102async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 102async 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
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::low_level::AFType; 6use embassy_stm32::gpio::{AFType, Flex, Pull, Speed};
7use embassy_stm32::gpio::Speed;
8use embassy_stm32::time::{khz, Hertz}; 7use embassy_stm32::time::{khz, Hertz};
9use embassy_stm32::timer::*; 8use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer};
10use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; 9use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel};
10use embassy_stm32::{into_ref, Config, Peripheral};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {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}
59pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { 59pub 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
63impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { 67impl<'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
59use cortex_m_rt::entry;
60use defmt::*;
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_stm32::interrupt;
63use embassy_stm32::interrupt::{InterruptExt, Priority};
64use embassy_time::{Instant, Timer};
65use static_cell::StaticCell;
66use {defmt_rtt as _, panic_probe as _};
67
68#[embassy_executor::task]
69async fn run_high() {
70 loop {
71 info!(" [high] tick!");
72 Timer::after_ticks(27374).await;
73 }
74}
75
76#[embassy_executor::task]
77async 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]
94async 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
110static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
111static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113
114#[interrupt]
115unsafe fn UART4() {
116 EXECUTOR_HIGH.on_interrupt()
117}
118
119#[interrupt]
120unsafe fn UART5() {
121 EXECUTOR_MED.on_interrupt()
122}
123
124#[entry]
125fn 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;
6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
7use embassy_stm32::pac::timer::vals::Mms; 7use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::frequency;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {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]
30async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 30async 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]
73async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 73async 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
45use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; 45use embassy_net_adin1110::{Device, Runner, ADIN1110};
46use embedded_hal_bus::spi::ExclusiveDevice; 46use embedded_hal_bus::spi::ExclusiveDevice;
47use hal::gpio::Pull; 47use hal::gpio::Pull;
48use hal::i2c::Config as I2C_Config; 48use 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]
2channel = "nightly-2023-12-20" 2channel = "nightly-2024-03-20"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/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]
2channel = "1.75" 2channel = "1.77"
3components = [ "rust-src", "rustfmt", "llvm-tools" ] 3components = [ "rust-src", "rustfmt", "llvm-tools" ]
4targets = [ 4targets = [
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]
22fn main() -> ! { 22fn 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]
20fn main() -> ! { 20fn 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"]
7mod common; 7mod common;
8use common::*; 8use common::*;
9use defmt::assert;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts; 10use embassy_stm32::bind_interrupts;
12use embassy_stm32::can::bx::filter::Mask32; 11use embassy_stm32::can::filter::Mask32;
13use embassy_stm32::can::bx::{Fifo, Frame, StandardId}; 12use embassy_stm32::can::{
14use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; 13 Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
14};
15use embassy_stm32::gpio::{Input, Pull}; 15use embassy_stm32::gpio::{Input, Pull};
16use embassy_stm32::peripherals::CAN1; 16use embassy_stm32::peripherals::CAN1;
17use embassy_time::{Duration, Instant}; 17use embassy_time::Duration;
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
20mod can_common;
21use can_common::*;
22
20bind_interrupts!(struct Irqs { 23bind_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 @@
1use defmt::{assert, *};
2use embassy_stm32::can;
3use embassy_time::{Duration, Instant};
4
5#[derive(Clone, Copy, Debug)]
6pub struct TestOptions {
7 pub max_latency: Duration,
8 pub max_buffered: u8,
9}
10
11pub 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
82pub 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"]
7mod common; 7mod common;
8use common::*; 8use common::*;
9use defmt::assert;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
11use embassy_stm32::peripherals::*; 10use embassy_stm32::peripherals::*;
12use embassy_stm32::{bind_interrupts, can, Config}; 11use embassy_stm32::{bind_interrupts, can, Config};
13use embassy_time::{Duration, Instant}; 12use embassy_time::Duration;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
15mod can_common;
16use can_common::*;
17
16bind_interrupts!(struct Irqs2 { 18bind_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
25struct 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"))]
32fn options() -> TestOptions { 28fn 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"))]
49fn options() -> TestOptions { 47fn 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"))]
66fn options() -> TestOptions { 66fn 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]
76async fn main(_spawner: Spawner) { 78async 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
253pub fn config() -> Config { 253pub 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