aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarun Koppula <[email protected]>2024-04-02 15:51:50 -0400
committerGitHub <[email protected]>2024-04-02 15:51:50 -0400
commit9344f55ff3107917ce1b765bc4fa57965ec86ca6 (patch)
tree4ca4936f84d4ad9ecf85a0129159b6d6d20c53cd
parent2caea89b6ab9859470ccf6c7d7414c01251bbecd (diff)
parent990f2717673de5e6de6be6a9fb001bc0c8d34745 (diff)
Merge branch 'main' into karun/main_octospi_implementation
-rw-r--r--.vscode/settings.json1
-rwxr-xr-xci.sh1
-rw-r--r--cyw43/src/fmt.rs3
-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/adapter/blocking_async.rs8
-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.rs21
-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.rs23
-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.toml6
-rw-r--r--embassy-stm32/build.rs80
-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/bxcan.rs637
-rw-r--r--embassy-stm32/src/can/bxcan/filter.rs475
-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.rs22
-rw-r--r--embassy-stm32/src/can/fd/message_ram/mod.rs20
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs87
-rw-r--r--embassy-stm32/src/can/fdcan.rs489
-rw-r--r--embassy-stm32/src/can/frame.rs231
-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.rs886
-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.rs115
-rw-r--r--embassy-stm32/src/dma/dmamux.rs9
-rw-r--r--embassy-stm32/src/dma/mod.rs31
-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.rs318
-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.rs46
-rw-r--r--embassy-stm32/src/i2c/v1.rs266
-rw-r--r--embassy-stm32/src/i2c/v2.rs13
-rw-r--r--embassy-stm32/src/i2s.rs3
-rw-r--r--embassy-stm32/src/ipcc.rs83
-rw-r--r--embassy-stm32/src/lib.rs75
-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/h.rs9
-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.rs185
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs33
-rw-r--r--embassy-stm32/src/spi/mod.rs39
-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.rs990
-rw-r--r--embassy-stm32/src/timer/qei.rs36
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs44
-rw-r--r--embassy-stm32/src/ucpd.rs607
-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.rs92
-rw-r--r--embassy-stm32/src/usb/otg.rs (renamed from embassy-stm32/src/usb_otg/usb.rs)204
-rw-r--r--embassy-stm32/src/usb/usb.rs60
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs163
-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/channel.rs15
-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.rs704
-rw-r--r--embassy-sync/src/signal.rs2
-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.rs122
-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.rs22
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs11
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs221
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs11
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs11
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs11
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs5
-rw-r--r--examples/stm32f7/src/bin/can.rs35
-rw-r--r--examples/stm32f7/src/bin/cryp.rs28
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs11
-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_c_pd.rs86
-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/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/usb_serial.rs11
-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.rs38
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs30
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs30
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs30
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs11
-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/Cargo.toml8
-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/cryp.rs30
-rw-r--r--tests/stm32/src/bin/fdcan.rs172
-rw-r--r--tests/stm32/src/bin/ucpd.rs120
-rw-r--r--tests/stm32/src/common.rs8
229 files changed, 8571 insertions, 4158 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 46d26562c..0c195a13b 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,4 @@
1{ 1{
2 "editor.formatOnSave": true,
3 "[toml]": { 2 "[toml]": {
4 "editor.formatOnSave": false 3 "editor.formatOnSave": false
5 }, 4 },
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/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/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs
index ae0d0a7f9..bafc31583 100644
--- a/embassy-embedded-hal/src/adapter/blocking_async.rs
+++ b/embassy-embedded-hal/src/adapter/blocking_async.rs
@@ -104,8 +104,10 @@ where
104} 104}
105 105
106/// NOR flash wrapper 106/// NOR flash wrapper
107use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 107use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, ReadNorFlash};
108use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; 108use embedded_storage_async::nor_flash::{
109 MultiwriteNorFlash as AsyncMultiwriteNorFlash, NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash,
110};
109 111
110impl<T> ErrorType for BlockingAsync<T> 112impl<T> ErrorType for BlockingAsync<T>
111where 113where
@@ -143,3 +145,5 @@ where
143 self.wrapped.capacity() 145 self.wrapped.capacity()
144 } 146 }
145} 147}
148
149impl<T> AsyncMultiwriteNorFlash for BlockingAsync<T> where T: MultiwriteNorFlash {}
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
index 779c04263..71ce09def 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -106,6 +106,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> {
106 pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self { 106 pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self {
107 Self { bus, config } 107 Self { bus, config }
108 } 108 }
109
110 /// Change the device's config at runtime
111 pub fn set_config(&mut self, config: BUS::Config) {
112 self.config = config;
113 }
109} 114}
110 115
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 233c9e1fd..627767c8a 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
@@ -67,9 +67,11 @@ where
67 } 67 }
68 68
69 fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { 69 fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> {
70 let _ = address; 70 self.bus.lock(|bus| {
71 let _ = operations; 71 bus.borrow_mut()
72 todo!() 72 .transaction(address, operations)
73 .map_err(I2cDeviceError::I2c)
74 })
73 } 75 }
74} 76}
75 77
@@ -130,6 +132,11 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> {
130 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, config: BUS::Config) -> Self { 132 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, config: BUS::Config) -> Self {
131 Self { bus, config } 133 Self { bus, config }
132 } 134 }
135
136 /// Change the device's config at runtime
137 pub fn set_config(&mut self, config: BUS::Config) {
138 self.config = config;
139 }
133} 140}
134 141
135impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> 142impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS>
@@ -171,8 +178,10 @@ where
171 } 178 }
172 179
173 fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { 180 fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> {
174 let _ = address; 181 self.bus.lock(|bus| {
175 let _ = operations; 182 let mut bus = bus.borrow_mut();
176 todo!() 183 bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
184 bus.transaction(address, operations).map_err(I2cDeviceError::I2c)
185 })
177 } 186 }
178} 187}
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index 59b65bfbd..801899f9f 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -147,6 +147,11 @@ impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> {
147 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS, config: BUS::Config) -> Self { 147 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS, config: BUS::Config) -> Self {
148 Self { bus, cs, config } 148 Self { bus, cs, config }
149 } 149 }
150
151 /// Change the device's config at runtime
152 pub fn set_config(&mut self, config: BUS::Config) {
153 self.config = config;
154 }
150} 155}
151 156
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 46973fdc8..1c83e306d 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -183,14 +183,14 @@ embassy_hal_internal::peripherals! {
183 DMA_CH10, 183 DMA_CH10,
184 DMA_CH11, 184 DMA_CH11,
185 185
186 PWM_CH0, 186 PWM_SLICE0,
187 PWM_CH1, 187 PWM_SLICE1,
188 PWM_CH2, 188 PWM_SLICE2,
189 PWM_CH3, 189 PWM_SLICE3,
190 PWM_CH4, 190 PWM_SLICE4,
191 PWM_CH5, 191 PWM_SLICE5,
192 PWM_CH6, 192 PWM_SLICE6,
193 PWM_CH7, 193 PWM_SLICE7,
194 194
195 USB, 195 USB,
196 196
@@ -238,8 +238,8 @@ select_bootloader! {
238} 238}
239 239
240/// Installs a stack guard for the CORE0 stack in MPU region 0. 240/// Installs a stack guard for the CORE0 stack in MPU region 0.
241/// Will fail if the MPU is already confgigured. This function requires 241/// Will fail if the MPU is already configured. This function requires
242/// a `_stack_end` symbol to be defined by the linker script, and expexcts 242/// a `_stack_end` symbol to be defined by the linker script, and expects
243/// `_stack_end` to be located at the lowest address (largest depth) of 243/// `_stack_end` to be located at the lowest address (largest depth) of
244/// the stack. 244/// the stack.
245/// 245///
@@ -274,7 +274,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> {
274 extern "C" { 274 extern "C" {
275 static mut _stack_end: usize; 275 static mut _stack_end: usize;
276 } 276 }
277 unsafe { install_stack_guard(&mut _stack_end as *mut usize) } 277 unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) }
278} 278}
279 279
280#[inline(always)] 280#[inline(always)]
@@ -354,6 +354,7 @@ pub fn init(config: config::Config) -> Peripherals {
354 354
355/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. 355/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
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 158c630b9..d00e7aa55 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -71,8 +71,8 @@ sdio-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-ac187e40aa97da86f7d3cf22abad918f42f01739" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739" }
74
74vcell = "0.1.3" 75vcell = "0.1.3"
75bxcan = "0.7.0"
76nb = "1.0.0" 76nb = "1.0.0"
77stm32-fmc = "0.3.0" 77stm32-fmc = "0.3.0"
78cfg-if = "1.0.0" 78cfg-if = "1.0.0"
@@ -84,6 +84,7 @@ document-features = "0.2.7"
84 84
85static_assertions = { version = "1.1" } 85static_assertions = { version = "1.1" }
86volatile-register = { version = "0.2.1" } 86volatile-register = { version = "0.2.1" }
87bitflags = "2.4.2"
87 88
88 89
89 90
@@ -97,7 +98,6 @@ quote = "1.0.15"
97#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 98#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
98stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739", default-features = false, features = ["metadata"]} 99stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ac187e40aa97da86f7d3cf22abad918f42f01739", default-features = false, features = ["metadata"]}
99 100
100
101[features] 101[features]
102default = ["rt"] 102default = ["rt"]
103 103
@@ -105,7 +105,7 @@ default = ["rt"]
105rt = ["stm32-metapac/rt"] 105rt = ["stm32-metapac/rt"]
106 106
107## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging 107## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging
108defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] 108defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"]
109 109
110exti = [] 110exti = []
111low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 111low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 6217a3309..129c5df76 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -509,25 +509,20 @@ fn main() {
509 if let Some(rcc) = &p.rcc { 509 if let Some(rcc) = &p.rcc {
510 let en = rcc.enable.as_ref().unwrap(); 510 let en = rcc.enable.as_ref().unwrap();
511 511
512 let rst = match &rcc.reset { 512 let (start_rst, end_rst) = match &rcc.reset {
513 Some(rst) => { 513 Some(rst) => {
514 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); 514 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
515 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); 515 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
516 quote! { 516 (
517 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); 517 quote! {
518 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); 518 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
519 } 519 },
520 quote! {
521 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
522 },
523 )
520 } 524 }
521 None => TokenStream::new(), 525 None => (TokenStream::new(), TokenStream::new()),
522 };
523
524 let after_enable = if chip_name.starts_with("stm32f2") {
525 // Errata: ES0005 - 2.1.11 Delay after an RCC peripheral clock enabling
526 quote! {
527 cortex_m::asm::dsb();
528 }
529 } else {
530 TokenStream::new()
531 }; 526 };
532 527
533 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; 528 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
@@ -589,16 +584,29 @@ fn main() {
589 }; 584 };
590 585
591 g.extend(quote! { 586 g.extend(quote! {
592 impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { 587 impl crate::rcc::SealedRccPeripheral for peripherals::#pname {
593 fn frequency() -> crate::time::Hertz { 588 fn frequency() -> crate::time::Hertz {
594 #clock_frequency 589 #clock_frequency
595 } 590 }
596 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { 591 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
597 #before_enable 592 #before_enable
598 #incr_stop_refcount 593 #incr_stop_refcount
594
595 #start_rst
596
599 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); 597 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
600 #after_enable 598
601 #rst 599 // we must wait two peripheral clock cycles before the clock is active
600 // this seems to work, but might be incorrect
601 // see http://efton.sk/STM32/gotcha/g183.html
602
603 // dummy read (like in the ST HALs)
604 let _ = crate::pac::RCC.#en_reg().read();
605
606 // DSB for good measure
607 cortex_m::asm::dsb();
608
609 #end_rst
602 } 610 }
603 fn disable_with_cs(_cs: critical_section::CriticalSection) { 611 fn disable_with_cs(_cs: critical_section::CriticalSection) {
604 #before_disable 612 #before_disable
@@ -764,6 +772,8 @@ fn main() {
764 #[rustfmt::skip] 772 #[rustfmt::skip]
765 let signals: HashMap<_, _> = [ 773 let signals: HashMap<_, _> = [
766 // (kind, signal) => trait 774 // (kind, signal) => trait
775 (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)),
776 (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)),
767 (("usart", "TX"), quote!(crate::usart::TxPin)), 777 (("usart", "TX"), quote!(crate::usart::TxPin)),
768 (("usart", "RX"), quote!(crate::usart::RxPin)), 778 (("usart", "RX"), quote!(crate::usart::RxPin)),
769 (("usart", "CTS"), quote!(crate::usart::CtsPin)), 779 (("usart", "CTS"), quote!(crate::usart::CtsPin)),
@@ -816,20 +826,20 @@ fn main() {
816 (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), 826 (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)),
817 (("usb", "DP"), quote!(crate::usb::DpPin)), 827 (("usb", "DP"), quote!(crate::usb::DpPin)),
818 (("usb", "DM"), quote!(crate::usb::DmPin)), 828 (("usb", "DM"), quote!(crate::usb::DmPin)),
819 (("otg", "DP"), quote!(crate::usb_otg::DpPin)), 829 (("otg", "DP"), quote!(crate::usb::DpPin)),
820 (("otg", "DM"), quote!(crate::usb_otg::DmPin)), 830 (("otg", "DM"), quote!(crate::usb::DmPin)),
821 (("otg", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)), 831 (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)),
822 (("otg", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)), 832 (("otg", "ULPI_DIR"), quote!(crate::usb::UlpiDirPin)),
823 (("otg", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)), 833 (("otg", "ULPI_NXT"), quote!(crate::usb::UlpiNxtPin)),
824 (("otg", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)), 834 (("otg", "ULPI_STP"), quote!(crate::usb::UlpiStpPin)),
825 (("otg", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)), 835 (("otg", "ULPI_D0"), quote!(crate::usb::UlpiD0Pin)),
826 (("otg", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)), 836 (("otg", "ULPI_D1"), quote!(crate::usb::UlpiD1Pin)),
827 (("otg", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)), 837 (("otg", "ULPI_D2"), quote!(crate::usb::UlpiD2Pin)),
828 (("otg", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)), 838 (("otg", "ULPI_D3"), quote!(crate::usb::UlpiD3Pin)),
829 (("otg", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)), 839 (("otg", "ULPI_D4"), quote!(crate::usb::UlpiD4Pin)),
830 (("otg", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)), 840 (("otg", "ULPI_D5"), quote!(crate::usb::UlpiD5Pin)),
831 (("otg", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)), 841 (("otg", "ULPI_D6"), quote!(crate::usb::UlpiD6Pin)),
832 (("otg", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)), 842 (("otg", "ULPI_D7"), quote!(crate::usb::UlpiD7Pin)),
833 (("can", "TX"), quote!(crate::can::TxPin)), 843 (("can", "TX"), quote!(crate::can::TxPin)),
834 (("can", "RX"), quote!(crate::can::RxPin)), 844 (("can", "RX"), quote!(crate::can::RxPin)),
835 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), 845 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),
@@ -1114,6 +1124,8 @@ fn main() {
1114 1124
1115 let signals: HashMap<_, _> = [ 1125 let signals: HashMap<_, _> = [
1116 // (kind, signal) => trait 1126 // (kind, signal) => trait
1127 (("ucpd", "RX"), quote!(crate::ucpd::RxDma)),
1128 (("ucpd", "TX"), quote!(crate::ucpd::TxDma)),
1117 (("usart", "RX"), quote!(crate::usart::RxDma)), 1129 (("usart", "RX"), quote!(crate::usart::RxDma)),
1118 (("usart", "TX"), quote!(crate::usart::TxDma)), 1130 (("usart", "TX"), quote!(crate::usart::TxDma)),
1119 (("lpuart", "RX"), quote!(crate::usart::RxDma)), 1131 (("lpuart", "RX"), quote!(crate::usart::RxDma)),
@@ -1134,6 +1146,8 @@ fn main() {
1134 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1146 (("dac", "CH2"), quote!(crate::dac::DacDma2)),
1135 (("timer", "UP"), quote!(crate::timer::UpDma)), 1147 (("timer", "UP"), quote!(crate::timer::UpDma)),
1136 (("hash", "IN"), quote!(crate::hash::Dma)), 1148 (("hash", "IN"), quote!(crate::hash::Dma)),
1149 (("cryp", "IN"), quote!(crate::cryp::DmaIn)),
1150 (("cryp", "OUT"), quote!(crate::cryp::DmaOut)),
1137 (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), 1151 (("timer", "CH1"), quote!(crate::timer::Ch1Dma)),
1138 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), 1152 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
1139 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), 1153 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
@@ -1485,7 +1499,7 @@ fn main() {
1485 #[crate::interrupt] 1499 #[crate::interrupt]
1486 unsafe fn #irq () { 1500 unsafe fn #irq () {
1487 #( 1501 #(
1488 <crate::peripherals::#channels as crate::dma::sealed::ChannelInterrupt>::on_irq(); 1502 <crate::peripherals::#channels as crate::dma::ChannelInterrupt>::on_irq();
1489 )* 1503 )*
1490 } 1504 }
1491 } 1505 }
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index b27b99827..cecf67947 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -33,7 +33,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
33 33
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/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
deleted file mode 100644
index 7e00eca6f..000000000
--- a/embassy-stm32/src/can/bxcan.rs
+++ /dev/null
@@ -1,637 +0,0 @@
1use core::convert::AsMut;
2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::task::Poll;
6
7pub use bxcan;
8use bxcan::{Data, ExtendedId, Frame, Id, StandardId};
9use embassy_hal_internal::{into_ref, PeripheralRef};
10use futures::FutureExt;
11
12use crate::gpio::sealed::AFType;
13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::can::vals::{Ide, Lec};
15use crate::rcc::RccPeripheral;
16use crate::{interrupt, peripherals, Peripheral};
17
18pub mod enums;
19use enums::*;
20pub mod util;
21
22/// Contains CAN frame and additional metadata.
23///
24/// Timestamp is available if `time` feature is enabled.
25#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub struct Envelope {
28 /// Reception time.
29 #[cfg(feature = "time")]
30 pub ts: embassy_time::Instant,
31 /// The actual CAN frame.
32 pub frame: bxcan::Frame,
33}
34
35/// Interrupt handler.
36pub struct TxInterruptHandler<T: Instance> {
37 _phantom: PhantomData<T>,
38}
39
40impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> {
41 unsafe fn on_interrupt() {
42 T::regs().tsr().write(|v| {
43 v.set_rqcp(0, true);
44 v.set_rqcp(1, true);
45 v.set_rqcp(2, true);
46 });
47
48 T::state().tx_waker.wake();
49 }
50}
51
52/// RX0 interrupt handler.
53pub struct Rx0InterruptHandler<T: Instance> {
54 _phantom: PhantomData<T>,
55}
56
57impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> {
58 unsafe fn on_interrupt() {
59 // info!("rx0 irq");
60 Can::<T>::receive_fifo(RxFifo::Fifo0);
61 }
62}
63
64/// RX1 interrupt handler.
65pub struct Rx1InterruptHandler<T: Instance> {
66 _phantom: PhantomData<T>,
67}
68
69impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> {
70 unsafe fn on_interrupt() {
71 // info!("rx1 irq");
72 Can::<T>::receive_fifo(RxFifo::Fifo1);
73 }
74}
75
76/// SCE interrupt handler.
77pub struct SceInterruptHandler<T: Instance> {
78 _phantom: PhantomData<T>,
79}
80
81impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
82 unsafe fn on_interrupt() {
83 // info!("sce irq");
84 let msr = T::regs().msr();
85 let msr_val = msr.read();
86
87 if msr_val.erri() {
88 msr.modify(|v| v.set_erri(true));
89 T::state().err_waker.wake();
90 }
91 }
92}
93
94/// CAN driver
95pub struct Can<'d, T: Instance> {
96 can: bxcan::Can<BxcanInstance<'d, T>>,
97}
98
99/// Error returned by `try_read`
100#[derive(Debug)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub enum TryReadError {
103 /// Bus error
104 BusError(BusError),
105 /// Receive buffer is empty
106 Empty,
107}
108
109/// Error returned by `try_write`
110#[derive(Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum TryWriteError {
113 /// All transmit mailboxes are full
114 Full,
115}
116
117impl<'d, T: Instance> Can<'d, T> {
118 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
119 /// You must call [Can::enable_non_blocking] to use the peripheral.
120 pub fn new(
121 peri: impl Peripheral<P = T> + 'd,
122 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
123 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
124 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
125 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
126 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
127 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
128 + 'd,
129 ) -> Self {
130 into_ref!(peri, rx, tx);
131
132 rx.set_as_af(rx.af_num(), AFType::Input);
133 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
134
135 T::enable_and_reset();
136
137 {
138 T::regs().ier().write(|w| {
139 w.set_errie(true);
140 w.set_fmpie(0, true);
141 w.set_fmpie(1, true);
142 w.set_tmeie(true);
143 });
144
145 T::regs().mcr().write(|w| {
146 // Enable timestamps on rx messages
147
148 w.set_ttcm(true);
149 });
150 }
151
152 unsafe {
153 T::TXInterrupt::unpend();
154 T::TXInterrupt::enable();
155
156 T::RX0Interrupt::unpend();
157 T::RX0Interrupt::enable();
158
159 T::RX1Interrupt::unpend();
160 T::RX1Interrupt::enable();
161
162 T::SCEInterrupt::unpend();
163 T::SCEInterrupt::enable();
164 }
165
166 rx.set_as_af(rx.af_num(), AFType::Input);
167 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
168
169 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
170 Self { can }
171 }
172
173 /// Set CAN bit rate.
174 pub fn set_bitrate(&mut self, bitrate: u32) {
175 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
176 let sjw = u8::from(bit_timing.sync_jump_width) as u32;
177 let seg1 = u8::from(bit_timing.seg1) as u32;
178 let seg2 = u8::from(bit_timing.seg2) as u32;
179 let prescaler = u16::from(bit_timing.prescaler) as u32;
180 self.can
181 .modify_config()
182 .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1))
183 .leave_disabled();
184 }
185
186 /// Enables the peripheral and synchronizes with the bus.
187 ///
188 /// This will wait for 11 consecutive recessive bits (bus idle state).
189 /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
190 pub async fn enable(&mut self) {
191 while self.enable_non_blocking().is_err() {
192 // SCE interrupt is only generated for entering sleep mode, but not leaving.
193 // Yield to allow other tasks to execute while can bus is initializing.
194 embassy_futures::yield_now().await;
195 }
196 }
197
198 /// Queues the message to be sent.
199 ///
200 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
201 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
202 self.split().0.write(frame).await
203 }
204
205 /// Attempts to transmit a frame without blocking.
206 ///
207 /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
208 pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
209 self.split().0.try_write(frame)
210 }
211
212 /// Waits for a specific transmit mailbox to become empty
213 pub async fn flush(&self, mb: bxcan::Mailbox) {
214 CanTx::<T>::flush_inner(mb).await
215 }
216
217 /// Waits until any of the transmit mailboxes become empty
218 pub async fn flush_any(&self) {
219 CanTx::<T>::flush_any_inner().await
220 }
221
222 /// Waits until all of the transmit mailboxes become empty
223 pub async fn flush_all(&self) {
224 CanTx::<T>::flush_all_inner().await
225 }
226
227 /// Read a CAN frame.
228 ///
229 /// If no CAN frame is in the RX buffer, this will wait until there is one.
230 ///
231 /// Returns a tuple of the time the message was received and the message frame
232 pub async fn read(&mut self) -> Result<Envelope, BusError> {
233 self.split().1.read().await
234 }
235
236 /// Attempts to read a CAN frame without blocking.
237 ///
238 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
239 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
240 self.split().1.try_read()
241 }
242
243 /// Waits while receive queue is empty.
244 pub async fn wait_not_empty(&mut self) {
245 self.split().1.wait_not_empty().await
246 }
247
248 unsafe fn receive_fifo(fifo: RxFifo) {
249 // Generate timestamp as early as possible
250 #[cfg(feature = "time")]
251 let ts = embassy_time::Instant::now();
252
253 let state = T::state();
254 let regs = T::regs();
255 let fifo_idx = match fifo {
256 RxFifo::Fifo0 => 0usize,
257 RxFifo::Fifo1 => 1usize,
258 };
259 let rfr = regs.rfr(fifo_idx);
260 let fifo = regs.rx(fifo_idx);
261
262 loop {
263 // If there are no pending messages, there is nothing to do
264 if rfr.read().fmp() == 0 {
265 return;
266 }
267
268 let rir = fifo.rir().read();
269 let id = if rir.ide() == Ide::STANDARD {
270 Id::from(StandardId::new_unchecked(rir.stid()))
271 } else {
272 let stid = (rir.stid() & 0x7FF) as u32;
273 let exid = rir.exid() & 0x3FFFF;
274 let id = (stid << 18) | (exid);
275 Id::from(ExtendedId::new_unchecked(id))
276 };
277 let data_len = fifo.rdtr().read().dlc() as usize;
278 let mut data: [u8; 8] = [0; 8];
279 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
280 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
281
282 let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap());
283 let envelope = Envelope {
284 #[cfg(feature = "time")]
285 ts,
286 frame,
287 };
288
289 rfr.modify(|v| v.set_rfom(true));
290
291 /*
292 NOTE: consensus was reached that if rx_queue is full, packets should be dropped
293 */
294 let _ = state.rx_queue.try_send(envelope);
295 }
296 }
297
298 /// Split the CAN driver into transmit and receive halves.
299 ///
300 /// Useful for doing separate transmit/receive tasks.
301 pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
302 let (tx, rx0, rx1) = self.can.split_by_ref();
303 (CanTx { tx }, CanRx { rx0, rx1 })
304 }
305}
306
307impl<'d, T: Instance> AsMut<bxcan::Can<BxcanInstance<'d, T>>> for Can<'d, T> {
308 /// Get mutable access to the lower-level driver from the `bxcan` crate.
309 fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> {
310 &mut self.can
311 }
312}
313
314/// CAN driver, transmit half.
315pub struct CanTx<'c, 'd, T: Instance> {
316 tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>,
317}
318
319impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
320 /// Queues the message to be sent.
321 ///
322 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
323 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
324 poll_fn(|cx| {
325 T::state().tx_waker.register(cx.waker());
326 if let Ok(status) = self.tx.transmit(frame) {
327 return Poll::Ready(status);
328 }
329
330 Poll::Pending
331 })
332 .await
333 }
334
335 /// Attempts to transmit a frame without blocking.
336 ///
337 /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
338 pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
339 self.tx.transmit(frame).map_err(|_| TryWriteError::Full)
340 }
341
342 async fn flush_inner(mb: bxcan::Mailbox) {
343 poll_fn(|cx| {
344 T::state().tx_waker.register(cx.waker());
345 if T::regs().tsr().read().tme(mb.index()) {
346 return Poll::Ready(());
347 }
348
349 Poll::Pending
350 })
351 .await;
352 }
353
354 /// Waits for a specific transmit mailbox to become empty
355 pub async fn flush(&self, mb: bxcan::Mailbox) {
356 Self::flush_inner(mb).await
357 }
358
359 async fn flush_any_inner() {
360 poll_fn(|cx| {
361 T::state().tx_waker.register(cx.waker());
362
363 let tsr = T::regs().tsr().read();
364 if tsr.tme(bxcan::Mailbox::Mailbox0.index())
365 || tsr.tme(bxcan::Mailbox::Mailbox1.index())
366 || tsr.tme(bxcan::Mailbox::Mailbox2.index())
367 {
368 return Poll::Ready(());
369 }
370
371 Poll::Pending
372 })
373 .await;
374 }
375
376 /// Waits until any of the transmit mailboxes become empty
377 pub async fn flush_any(&self) {
378 Self::flush_any_inner().await
379 }
380
381 async fn flush_all_inner() {
382 poll_fn(|cx| {
383 T::state().tx_waker.register(cx.waker());
384
385 let tsr = T::regs().tsr().read();
386 if tsr.tme(bxcan::Mailbox::Mailbox0.index())
387 && tsr.tme(bxcan::Mailbox::Mailbox1.index())
388 && tsr.tme(bxcan::Mailbox::Mailbox2.index())
389 {
390 return Poll::Ready(());
391 }
392
393 Poll::Pending
394 })
395 .await;
396 }
397
398 /// Waits until all of the transmit mailboxes become empty
399 pub async fn flush_all(&self) {
400 Self::flush_all_inner().await
401 }
402}
403
404/// CAN driver, receive half.
405#[allow(dead_code)]
406pub struct CanRx<'c, 'd, T: Instance> {
407 rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>,
408 rx1: &'c mut bxcan::Rx1<BxcanInstance<'d, T>>,
409}
410
411impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
412 /// Read a CAN frame.
413 ///
414 /// If no CAN frame is in the RX buffer, this will wait until there is one.
415 ///
416 /// Returns a tuple of the time the message was received and the message frame
417 pub async fn read(&mut self) -> Result<Envelope, BusError> {
418 poll_fn(|cx| {
419 T::state().err_waker.register(cx.waker());
420 if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) {
421 return Poll::Ready(Ok(envelope));
422 } else if let Some(err) = self.curr_error() {
423 return Poll::Ready(Err(err));
424 }
425
426 Poll::Pending
427 })
428 .await
429 }
430
431 /// Attempts to read a CAN frame without blocking.
432 ///
433 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
434 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
435 if let Ok(envelope) = T::state().rx_queue.try_receive() {
436 return Ok(envelope);
437 }
438
439 if let Some(err) = self.curr_error() {
440 return Err(TryReadError::BusError(err));
441 }
442
443 Err(TryReadError::Empty)
444 }
445
446 /// Waits while receive queue is empty.
447 pub async fn wait_not_empty(&mut self) {
448 poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await
449 }
450
451 fn curr_error(&self) -> Option<BusError> {
452 let err = { T::regs().esr().read() };
453 if err.boff() {
454 return Some(BusError::BusOff);
455 } else if err.epvf() {
456 return Some(BusError::BusPassive);
457 } else if err.ewgf() {
458 return Some(BusError::BusWarning);
459 } else if let Some(err) = err.lec().into_bus_err() {
460 return Some(err);
461 }
462 None
463 }
464}
465
466enum RxFifo {
467 Fifo0,
468 Fifo1,
469}
470
471impl<'d, T: Instance> Drop for Can<'d, T> {
472 fn drop(&mut self) {
473 // Cannot call `free()` because it moves the instance.
474 // Manually reset the peripheral.
475 T::regs().mcr().write(|w| w.set_reset(true));
476 T::disable();
477 }
478}
479
480impl<'d, T: Instance> Deref for Can<'d, T> {
481 type Target = bxcan::Can<BxcanInstance<'d, T>>;
482
483 fn deref(&self) -> &Self::Target {
484 &self.can
485 }
486}
487
488impl<'d, T: Instance> DerefMut for Can<'d, T> {
489 fn deref_mut(&mut self) -> &mut Self::Target {
490 &mut self.can
491 }
492}
493
494pub(crate) mod sealed {
495 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
496 use embassy_sync::channel::Channel;
497 use embassy_sync::waitqueue::AtomicWaker;
498
499 use super::Envelope;
500
501 pub struct State {
502 pub tx_waker: AtomicWaker,
503 pub err_waker: AtomicWaker,
504 pub rx_queue: Channel<CriticalSectionRawMutex, Envelope, 32>,
505 }
506
507 impl State {
508 pub const fn new() -> Self {
509 Self {
510 tx_waker: AtomicWaker::new(),
511 err_waker: AtomicWaker::new(),
512 rx_queue: Channel::new(),
513 }
514 }
515 }
516
517 pub trait Instance {
518 const REGISTERS: *mut bxcan::RegisterBlock;
519
520 fn regs() -> crate::pac::can::Can;
521 fn state() -> &'static State;
522 }
523}
524
525/// CAN instance trait.
526pub trait Instance: sealed::Instance + RccPeripheral + 'static {
527 /// TX interrupt for this instance.
528 type TXInterrupt: crate::interrupt::typelevel::Interrupt;
529 /// RX0 interrupt for this instance.
530 type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
531 /// RX1 interrupt for this instance.
532 type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
533 /// SCE interrupt for this instance.
534 type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
535}
536
537/// BXCAN instance newtype.
538pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
539
540unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
541 const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
542}
543
544foreach_peripheral!(
545 (can, $inst:ident) => {
546 impl sealed::Instance for peripherals::$inst {
547 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
548
549 fn regs() -> crate::pac::can::Can {
550 crate::pac::$inst
551 }
552
553 fn state() -> &'static sealed::State {
554 static STATE: sealed::State = sealed::State::new();
555 &STATE
556 }
557 }
558
559 impl Instance for peripherals::$inst {
560 type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX;
561 type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0;
562 type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1;
563 type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE;
564 }
565 };
566);
567
568foreach_peripheral!(
569 (can, CAN) => {
570 unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN> {
571 const NUM_FILTER_BANKS: u8 = 14;
572 }
573 };
574 // CAN1 and CAN2 is a combination of master and slave instance.
575 // CAN1 owns the filter bank and needs to be enabled in order
576 // for CAN2 to receive messages.
577 (can, CAN1) => {
578 cfg_if::cfg_if! {
579 if #[cfg(all(
580 any(stm32l4, stm32f72, stm32f73),
581 not(any(stm32l49, stm32l4a))
582 ))] {
583 // Most L4 devices and some F7 devices use the name "CAN1"
584 // even if there is no "CAN2" peripheral.
585 unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> {
586 const NUM_FILTER_BANKS: u8 = 14;
587 }
588 } else {
589 unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN1> {
590 const NUM_FILTER_BANKS: u8 = 28;
591 }
592 unsafe impl<'d> bxcan::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {}
593 }
594 }
595 };
596 (can, CAN3) => {
597 unsafe impl<'d> bxcan::FilterOwner for BxcanInstance<'d, peripherals::CAN3> {
598 const NUM_FILTER_BANKS: u8 = 14;
599 }
600 };
601);
602
603pin_trait!(RxPin, Instance);
604pin_trait!(TxPin, Instance);
605
606trait Index {
607 fn index(&self) -> usize;
608}
609
610impl Index for bxcan::Mailbox {
611 fn index(&self) -> usize {
612 match self {
613 bxcan::Mailbox::Mailbox0 => 0,
614 bxcan::Mailbox::Mailbox1 => 1,
615 bxcan::Mailbox::Mailbox2 => 2,
616 }
617 }
618}
619
620trait IntoBusError {
621 fn into_bus_err(self) -> Option<BusError>;
622}
623
624impl IntoBusError for Lec {
625 fn into_bus_err(self) -> Option<BusError> {
626 match self {
627 Lec::STUFF => Some(BusError::Stuff),
628 Lec::FORM => Some(BusError::Form),
629 Lec::ACK => Some(BusError::Acknowledge),
630 Lec::BITRECESSIVE => Some(BusError::BitRecessive),
631 Lec::BITDOMINANT => Some(BusError::BitDominant),
632 Lec::CRC => Some(BusError::Crc),
633 Lec::CUSTOM => Some(BusError::Software),
634 _ => None,
635 }
636 }
637}
diff --git a/embassy-stm32/src/can/bxcan/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs
new file mode 100644
index 000000000..9940c7f50
--- /dev/null
+++ b/embassy-stm32/src/can/bxcan/filter.rs
@@ -0,0 +1,475 @@
1//! Filter bank API.
2
3use core::marker::PhantomData;
4
5use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
6
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
9const F16_RTR: u16 = 0b10000;
10const F16_IDE: u16 = 0b01000;
11
12/// A 16-bit filter list entry.
13///
14/// This can match data and remote frames using standard IDs.
15#[derive(Debug, Copy, Clone, Eq, PartialEq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct ListEntry16(u16);
18
19/// A 32-bit filter list entry.
20///
21/// This can match data and remote frames using extended or standard IDs.
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct ListEntry32(u32);
25
26/// A 16-bit identifier mask.
27#[derive(Debug, Copy, Clone)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub struct Mask16 {
30 id: u16,
31 mask: u16,
32}
33
34/// A 32-bit identifier mask.
35#[derive(Debug, Copy, Clone)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub struct Mask32 {
38 id: u32,
39 mask: u32,
40}
41
42impl ListEntry16 {
43 /// Creates a filter list entry that accepts data frames with the given standard ID.
44 ///
45 /// This entry will *not* accept remote frames with the same ID.
46 pub fn data_frames_with_id(id: StandardId) -> Self {
47 Self(id.as_raw() << 5)
48 }
49
50 /// Creates a filter list entry that accepts remote frames with the given standard ID.
51 pub fn remote_frames_with_id(id: StandardId) -> Self {
52 Self(id.as_raw() << 5 | F16_RTR)
53 }
54}
55
56impl ListEntry32 {
57 /// Creates a filter list entry that accepts data frames with the given ID.
58 ///
59 /// This entry will *not* accept remote frames with the same ID.
60 ///
61 /// The filter will only accept *either* standard *or* extended frames, depending on `id`.
62 pub fn data_frames_with_id(id: impl Into<Id>) -> Self {
63 match id.into() {
64 Id::Standard(id) => Self(u32::from(id.as_raw()) << 21),
65 Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE),
66 }
67 }
68
69 /// Creates a filter list entry that accepts remote frames with the given ID.
70 pub fn remote_frames_with_id(id: impl Into<Id>) -> Self {
71 match id.into() {
72 Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR),
73 Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR),
74 }
75 }
76}
77
78impl Mask16 {
79 /// Creates a 16-bit identifier mask that accepts all frames.
80 ///
81 /// This will accept both standard and extended data and remote frames with any ID.
82 pub fn accept_all() -> Self {
83 Self { id: 0, mask: 0 }
84 }
85
86 /// Creates a 16-bit identifier mask that accepts all frames with the given standard
87 /// ID and mask combination.
88 ///
89 /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
90 ///
91 /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs.
92 ///
93 /// Both data and remote frames with `id` will be accepted. Any extended frames will be
94 /// rejected.
95 pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
96 Self {
97 id: id.as_raw() << 5,
98 mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0
99 }
100 }
101
102 /// Make the filter accept data frames only.
103 pub fn data_frames_only(&mut self) -> &mut Self {
104 self.id &= !F16_RTR; // RTR = 0
105 self.mask |= F16_RTR;
106 self
107 }
108
109 /// Make the filter accept remote frames only.
110 pub fn remote_frames_only(&mut self) -> &mut Self {
111 self.id |= F16_RTR; // RTR = 1
112 self.mask |= F16_RTR;
113 self
114 }
115}
116
117impl Mask32 {
118 /// Creates a 32-bit identifier mask that accepts all frames.
119 ///
120 /// This will accept both standard and extended data and remote frames with any ID.
121 pub fn accept_all() -> Self {
122 Self { id: 0, mask: 0 }
123 }
124
125 /// Creates a 32-bit identifier mask that accepts all frames with the given extended
126 /// ID and mask combination.
127 ///
128 /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
129 ///
130 /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs.
131 ///
132 /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected.
133 pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self {
134 Self {
135 id: id.as_raw() << 3 | F32_IDE,
136 mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1
137 }
138 }
139
140 /// Creates a 32-bit identifier mask that accepts all frames with the given standard
141 /// ID and mask combination.
142 ///
143 /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
144 ///
145 /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs.
146 ///
147 /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected.
148 pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
149 Self {
150 id: u32::from(id.as_raw()) << 21,
151 mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0
152 }
153 }
154
155 /// Make the filter accept data frames only.
156 pub fn data_frames_only(&mut self) -> &mut Self {
157 self.id &= !F32_RTR; // RTR = 0
158 self.mask |= F32_RTR;
159 self
160 }
161
162 /// Make the filter accept remote frames only.
163 pub fn remote_frames_only(&mut self) -> &mut Self {
164 self.id |= F32_RTR; // RTR = 1
165 self.mask |= F32_RTR;
166 self
167 }
168}
169
170/// The configuration of a filter bank.
171#[derive(Debug, Copy, Clone)]
172#[cfg_attr(feature = "defmt", derive(defmt::Format))]
173pub enum BankConfig {
174 /// Specify up to 4 exact standard CAN ID's.
175 List16([ListEntry16; 4]),
176 /// Specify up to 2 exact standard or extended CAN ID's.
177 List32([ListEntry32; 2]),
178 /// Specify up to 2 standard ID's with masks.
179 Mask16([Mask16; 2]),
180 /// Specify a single extended ID with mask.
181 Mask32(Mask32),
182}
183
184impl From<[ListEntry16; 4]> for BankConfig {
185 #[inline]
186 fn from(entries: [ListEntry16; 4]) -> Self {
187 Self::List16(entries)
188 }
189}
190
191impl From<[ListEntry32; 2]> for BankConfig {
192 #[inline]
193 fn from(entries: [ListEntry32; 2]) -> Self {
194 Self::List32(entries)
195 }
196}
197
198impl From<[Mask16; 2]> for BankConfig {
199 #[inline]
200 fn from(entries: [Mask16; 2]) -> Self {
201 Self::Mask16(entries)
202 }
203}
204
205impl From<Mask32> for BankConfig {
206 #[inline]
207 fn from(filter: Mask32) -> Self {
208 Self::Mask32(filter)
209 }
210}
211
212/// Interface to the filter banks of a CAN peripheral.
213pub struct MasterFilters<'a, I: FilterOwner> {
214 /// Number of assigned filter banks.
215 ///
216 /// On chips with splittable filter banks, this value can be dynamic.
217 bank_count: u8,
218 _can: PhantomData<&'a mut I>,
219 canregs: crate::pac::can::Can,
220}
221
222// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it
223// exists.
224impl<I: FilterOwner> MasterFilters<'_, I> {
225 pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self {
226 // Enable initialization mode.
227 canregs.fmr().modify(|reg| reg.set_finit(true));
228
229 // Read the filter split value.
230 let bank_count = canregs.fmr().read().can2sb();
231
232 // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all
233 // of them to the master peripheral, and in devices with 28, assigns them 50/50 to
234 // master/slave instances)
235
236 Self {
237 bank_count,
238 _can: PhantomData,
239 canregs,
240 }
241 }
242
243 fn banks_imm(&self) -> FilterBanks {
244 FilterBanks {
245 start_idx: 0,
246 bank_count: self.bank_count,
247 canregs: self.canregs,
248 }
249 }
250
251 /// Returns the number of filter banks currently assigned to this instance.
252 ///
253 /// Chips with splittable filter banks may start out with some banks assigned to the master
254 /// instance and some assigned to the slave instance.
255 pub fn num_banks(&self) -> u8 {
256 self.bank_count
257 }
258
259 /// Disables all enabled filter banks.
260 ///
261 /// This causes all incoming frames to be disposed.
262 pub fn clear(&mut self) -> &mut Self {
263 self.banks_imm().clear();
264 self
265 }
266
267 /// Disables a filter bank.
268 ///
269 /// If `index` is out of bounds, this will panic.
270 pub fn disable_bank(&mut self, index: u8) -> &mut Self {
271 self.banks_imm().disable(index);
272 self
273 }
274
275 /// Configures a filter bank according to `config` and enables it.
276 ///
277 /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`]
278 /// passed to this function. In the event that both FIFOs are configured to accept an incoming
279 /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so
280 /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept
281 /// the frame.
282 ///
283 /// # Parameters
284 ///
285 /// - `index`: the filter index.
286 /// - `fifo`: the receive FIFO the filter should pass accepted messages to.
287 /// - `config`: the filter configuration.
288 pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self {
289 self.banks_imm().enable(index, fifo, config.into());
290 self
291 }
292}
293
294impl<I: MasterInstance> MasterFilters<'_, I> {
295 /// Sets the index at which the filter banks owned by the slave peripheral start.
296 pub fn set_split(&mut self, split_index: u8) -> &mut Self {
297 assert!(split_index <= I::NUM_FILTER_BANKS);
298 self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index));
299 self.bank_count = split_index;
300 self
301 }
302
303 /// Accesses the filters assigned to the slave peripheral.
304 pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> {
305 // NB: This mutably borrows `self`, so it has full access to the filter bank registers.
306 SlaveFilters {
307 start_idx: self.bank_count,
308 bank_count: I::NUM_FILTER_BANKS - self.bank_count,
309 _can: PhantomData,
310 canregs: self.canregs,
311 }
312 }
313}
314
315impl<I: FilterOwner> Drop for MasterFilters<'_, I> {
316 #[inline]
317 fn drop(&mut self) {
318 // Leave initialization mode.
319 self.canregs.fmr().modify(|regs| regs.set_finit(false));
320 }
321}
322
323/// Interface to the filter banks assigned to a slave peripheral.
324pub struct SlaveFilters<'a, I: Instance> {
325 start_idx: u8,
326 bank_count: u8,
327 _can: PhantomData<&'a mut I>,
328 canregs: crate::pac::can::Can,
329}
330
331impl<I: Instance> SlaveFilters<'_, I> {
332 fn banks_imm(&self) -> FilterBanks {
333 FilterBanks {
334 start_idx: self.start_idx,
335 bank_count: self.bank_count,
336 canregs: self.canregs,
337 }
338 }
339
340 /// Returns the number of filter banks currently assigned to this instance.
341 ///
342 /// Chips with splittable filter banks may start out with some banks assigned to the master
343 /// instance and some assigned to the slave instance.
344 pub fn num_banks(&self) -> u8 {
345 self.bank_count
346 }
347
348 /// Disables all enabled filter banks.
349 ///
350 /// This causes all incoming frames to be disposed.
351 pub fn clear(&mut self) -> &mut Self {
352 self.banks_imm().clear();
353 self
354 }
355
356 /// Disables a filter bank.
357 ///
358 /// If `index` is out of bounds, this will panic.
359 pub fn disable_bank(&mut self, index: u8) -> &mut Self {
360 self.banks_imm().disable(index);
361 self
362 }
363
364 /// Configures a filter bank according to `config` and enables it.
365 ///
366 /// # Parameters
367 ///
368 /// - `index`: the filter index.
369 /// - `fifo`: the receive FIFO the filter should pass accepted messages to.
370 /// - `config`: the filter configuration.
371 pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self {
372 self.banks_imm().enable(index, fifo, config.into());
373 self
374 }
375}
376
377struct FilterBanks {
378 start_idx: u8,
379 bank_count: u8,
380 canregs: crate::pac::can::Can,
381}
382
383impl FilterBanks {
384 fn clear(&mut self) {
385 let mask = filter_bitmask(self.start_idx, self.bank_count);
386
387 self.canregs.fa1r().modify(|reg| {
388 for i in 0..28usize {
389 if (0x01u32 << i) & mask != 0 {
390 reg.set_fact(i, false);
391 }
392 }
393 });
394 }
395
396 fn assert_bank_index(&self, index: u8) {
397 assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index));
398 }
399
400 fn disable(&mut self, index: u8) {
401 self.assert_bank_index(index);
402 self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false))
403 }
404
405 fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
406 self.assert_bank_index(index);
407
408 // Configure mode.
409 let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
410 self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
411
412 // Configure scale.
413 let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
414 self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
415
416 // Configure filter register.
417 let (fxr1, fxr2);
418 match config {
419 BankConfig::List16([a, b, c, d]) => {
420 fxr1 = (u32::from(b.0) << 16) | u32::from(a.0);
421 fxr2 = (u32::from(d.0) << 16) | u32::from(c.0);
422 }
423 BankConfig::List32([a, b]) => {
424 fxr1 = a.0;
425 fxr2 = b.0;
426 }
427 BankConfig::Mask16([a, b]) => {
428 fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id);
429 fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id);
430 }
431 BankConfig::Mask32(a) => {
432 fxr1 = a.id;
433 fxr2 = a.mask;
434 }
435 };
436 let bank = self.canregs.fb(index as usize);
437 bank.fr1().write(|w| w.0 = fxr1);
438 bank.fr2().write(|w| w.0 = fxr2);
439
440 // Assign to the right FIFO
441 self.canregs.ffa1r().modify(|reg| {
442 reg.set_ffa(
443 index as usize,
444 match fifo {
445 Fifo::Fifo0 => false,
446 Fifo::Fifo1 => true,
447 },
448 )
449 });
450
451 // Set active.
452 self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true))
453 }
454}
455
456/// Computes a bitmask for per-filter-bank registers that only includes filters in the given range.
457fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 {
458 let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits
459 count_mask << start_idx
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465
466 #[test]
467 fn test_filter_bitmask() {
468 assert_eq!(filter_bitmask(0, 1), 0x1);
469 assert_eq!(filter_bitmask(1, 1), 0b10);
470 assert_eq!(filter_bitmask(0, 4), 0xf);
471 assert_eq!(filter_bitmask(1, 3), 0xe);
472 assert_eq!(filter_bitmask(8, 1), 0x100);
473 assert_eq!(filter_bitmask(8, 4), 0xf00);
474 }
475}
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
new file mode 100644
index 000000000..65fd0e9c2
--- /dev/null
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -0,0 +1,989 @@
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 36139a45c..4d89c84d1 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -28,3 +28,25 @@ pub enum BusError {
28 /// At least one of error counter has reached the Error_Warning limit of 96. 28 /// At least one of error counter has reached the Error_Warning limit of 96.
29 BusWarning, 29 BusWarning,
30} 30}
31
32/// Frame Create Errors
33#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum FrameCreateError {
36 /// Data in header does not match supplied.
37 NotEnoughData,
38 /// Invalid data length not 0-8 for Classic packet or valid for FD.
39 InvalidDataLength,
40 /// Invalid ID.
41 InvalidCanId,
42}
43
44/// Error returned by `try_read`
45#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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 8ec09ac12..e32f19d91 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -30,7 +30,12 @@ impl Registers {
30 &mut self.msg_ram_mut().transmit.tbsa[bufidx] 30 &mut self.msg_ram_mut().transmit.tbsa[bufidx]
31 } 31 }
32 pub fn msg_ram_mut(&self) -> &mut RegisterBlock { 32 pub fn msg_ram_mut(&self) -> &mut RegisterBlock {
33 #[cfg(stm32h7)]
34 let ptr = self.msgram.ram(self.msg_ram_offset / 4).as_ptr() as *mut RegisterBlock;
35
36 #[cfg(not(stm32h7))]
33 let ptr = self.msgram.as_ptr() as *mut RegisterBlock; 37 let ptr = self.msgram.as_ptr() as *mut RegisterBlock;
38
34 unsafe { &mut (*ptr) } 39 unsafe { &mut (*ptr) }
35 } 40 }
36 41
@@ -56,7 +61,10 @@ impl Registers {
56 match maybe_header { 61 match maybe_header {
57 Some((header, ts)) => { 62 Some((header, ts)) => {
58 let data = &buffer[0..header.len() as usize]; 63 let data = &buffer[0..header.len() as usize];
59 Some((F::from_header(header, data)?, ts)) 64 match F::from_header(header, data) {
65 Ok(frame) => Some((frame, ts)),
66 Err(_) => None,
67 }
60 } 68 }
61 None => None, 69 None => None,
62 } 70 }
@@ -182,7 +190,7 @@ impl Registers {
182 DataLength::Fdcan(len) => len, 190 DataLength::Fdcan(len) => len,
183 DataLength::Classic(len) => len, 191 DataLength::Classic(len) => len,
184 }; 192 };
185 if len as usize > ClassicFrame::MAX_DATA_LEN { 193 if len as usize > ClassicData::MAX_DATA_LEN {
186 return None; 194 return None;
187 } 195 }
188 196
@@ -317,17 +325,6 @@ impl Registers {
317 */ 325 */
318 } 326 }
319 327
320 /// Disables the CAN interface and returns back the raw peripheral it was created from.
321 #[inline]
322 pub fn free(mut self) {
323 //self.disable_interrupts(Interrupts::all());
324
325 //TODO check this!
326 self.enter_init_mode();
327 self.set_power_down_mode(true);
328 //self.control.instance
329 }
330
331 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] 328 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
332 #[inline] 329 #[inline]
333 pub fn apply_config(&mut self, config: FdCanConfig) { 330 pub fn apply_config(&mut self, config: FdCanConfig) {
@@ -400,66 +397,17 @@ impl Registers {
400 397
401 /// Moves out of ConfigMode and into specified mode 398 /// Moves out of ConfigMode and into specified mode
402 #[inline] 399 #[inline]
403 pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { 400 pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
404 match mode { 401 match mode {
405 crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), 402 crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
406 crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), 403 crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
407 crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), 404 crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true),
408 crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), 405 crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
409 crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), 406 crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
410 } 407 }
411 self.leave_init_mode(config); 408 self.leave_init_mode(config);
412 } 409 }
413 410
414 /// Moves out of ConfigMode and into InternalLoopbackMode
415 #[inline]
416 pub fn into_internal_loopback(mut self, config: FdCanConfig) {
417 self.set_loopback_mode(LoopbackMode::Internal);
418 self.leave_init_mode(config);
419 }
420
421 /// Moves out of ConfigMode and into ExternalLoopbackMode
422 #[inline]
423 pub fn into_external_loopback(mut self, config: FdCanConfig) {
424 self.set_loopback_mode(LoopbackMode::External);
425 self.leave_init_mode(config);
426 }
427
428 /// Moves out of ConfigMode and into RestrictedOperationMode
429 #[inline]
430 pub fn into_restricted(mut self, config: FdCanConfig) {
431 self.set_restricted_operations(true);
432 self.leave_init_mode(config);
433 }
434
435 /// Moves out of ConfigMode and into NormalOperationMode
436 #[inline]
437 pub fn into_normal(mut self, config: FdCanConfig) {
438 self.set_normal_operations(true);
439 self.leave_init_mode(config);
440 }
441
442 /// Moves out of ConfigMode and into BusMonitoringMode
443 #[inline]
444 pub fn into_bus_monitoring(mut self, config: FdCanConfig) {
445 self.set_bus_monitoring_mode(true);
446 self.leave_init_mode(config);
447 }
448
449 /// Moves out of ConfigMode and into Testmode
450 #[inline]
451 pub fn into_test_mode(mut self, config: FdCanConfig) {
452 self.set_test_mode(true);
453 self.leave_init_mode(config);
454 }
455
456 /// Moves out of ConfigMode and into PoweredDownmode
457 #[inline]
458 pub fn into_powered_down(mut self, config: FdCanConfig) {
459 self.set_power_down_mode(true);
460 self.leave_init_mode(config);
461 }
462
463 /// Configures the bit timings. 411 /// Configures the bit timings.
464 /// 412 ///
465 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter 413 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
@@ -557,6 +505,7 @@ impl Registers {
557 505
558 /// Configures and resets the timestamp counter 506 /// Configures and resets the timestamp counter
559 #[inline] 507 #[inline]
508 #[allow(unused)]
560 pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { 509 pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
561 #[cfg(stm32h7)] 510 #[cfg(stm32h7)]
562 let (tcp, tss) = match select { 511 let (tcp, tss) = match select {
@@ -634,7 +583,7 @@ impl Registers {
634 583
635 use crate::can::fd::message_ram::*; 584 use crate::can::fd::message_ram::*;
636 //use fdcan::message_ram::*; 585 //use fdcan::message_ram::*;
637 let mut offset_words = self.msg_ram_offset as u16; 586 let mut offset_words = (self.msg_ram_offset / 4) as u16;
638 587
639 // 11-bit filter 588 // 11-bit filter
640 r.sidfc().modify(|w| w.set_flssa(offset_words)); 589 r.sidfc().modify(|w| w.set_flssa(offset_words));
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index fe8969a5a..e31821ca2 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -5,24 +5,24 @@ use core::task::Poll;
5 5
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 9c293035d..d2d1f7aa6 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -1,6 +1,16 @@
1//! Definition for CAN Frames 1//! Definition for CAN Frames
2use bit_field::BitField; 2use bit_field::BitField;
3 3
4use crate::can::enums::FrameCreateError;
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
4/// CAN Header, without meta data 14/// CAN Header, without meta data
5#[derive(Debug, Copy, Clone)] 15#[derive(Debug, Copy, Clone)]
6pub struct Header { 16pub struct Header {
@@ -9,6 +19,20 @@ pub struct Header {
9 flags: u8, 19 flags: u8,
10} 20}
11 21
22#[cfg(feature = "defmt")]
23impl defmt::Format for Header {
24 fn format(&self, fmt: defmt::Formatter<'_>) {
25 match self.id() {
26 embedded_can::Id::Standard(id) => {
27 defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,)
28 }
29 embedded_can::Id::Extended(id) => {
30 defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,)
31 }
32 }
33 }
34}
35
12impl Header { 36impl Header {
13 const FLAG_RTR: usize = 0; // Remote 37 const FLAG_RTR: usize = 0; // Remote
14 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN 38 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
@@ -54,13 +78,21 @@ impl Header {
54 pub fn bit_rate_switching(&self) -> bool { 78 pub fn bit_rate_switching(&self) -> bool {
55 self.flags.get_bit(Self::FLAG_BRS) 79 self.flags.get_bit(Self::FLAG_BRS)
56 } 80 }
81
82 /// Get priority of frame
83 pub(crate) fn priority(&self) -> u32 {
84 match self.id() {
85 embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18,
86 embedded_can::Id::Extended(id) => id.as_raw(),
87 }
88 }
57} 89}
58 90
59/// Trait for FDCAN frame types, providing ability to construct from a Header 91/// Trait for FDCAN frame types, providing ability to construct from a Header
60/// and to retrieve the Header from a frame 92/// and to retrieve the Header from a frame
61pub trait CanHeader: Sized { 93pub trait CanHeader: Sized {
62 /// Construct frame from header and payload 94 /// Construct frame from header and payload
63 fn from_header(header: Header, data: &[u8]) -> Option<Self>; 95 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>;
64 96
65 /// Get this frame's header struct 97 /// Get this frame's header struct
66 fn header(&self) -> &Header; 98 fn header(&self) -> &Header;
@@ -70,24 +102,26 @@ pub trait CanHeader: Sized {
70/// 102///
71/// Contains 0 to 8 Bytes of data. 103/// Contains 0 to 8 Bytes of data.
72#[derive(Debug, Copy, Clone)] 104#[derive(Debug, Copy, Clone)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct ClassicData { 106pub struct ClassicData {
74 pub(crate) bytes: [u8; 8], 107 pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
75} 108}
76 109
77impl ClassicData { 110impl ClassicData {
111 pub(crate) const MAX_DATA_LEN: usize = 8;
78 /// Creates a data payload from a raw byte slice. 112 /// Creates a data payload from a raw byte slice.
79 /// 113 ///
80 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 114 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
81 /// cannot be represented with an FDCAN DLC. 115 /// cannot be represented with an FDCAN DLC.
82 pub fn new(data: &[u8]) -> Option<Self> { 116 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
83 if !FdData::is_valid_len(data.len()) { 117 if data.len() > 8 {
84 return None; 118 return Err(FrameCreateError::InvalidDataLength);
85 } 119 }
86 120
87 let mut bytes = [0; 8]; 121 let mut bytes = [0; 8];
88 bytes[..data.len()].copy_from_slice(data); 122 bytes[..data.len()].copy_from_slice(data);
89 123
90 Some(Self { bytes }) 124 Ok(Self { bytes })
91 } 125 }
92 126
93 /// Raw read access to data. 127 /// Raw read access to data.
@@ -110,60 +144,53 @@ impl ClassicData {
110 } 144 }
111} 145}
112 146
113/// Frame with up to 8 bytes of data payload as per Classic CAN 147/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN
148/// For CAN-FD support use FdFrame
114#[derive(Debug, Copy, Clone)] 149#[derive(Debug, Copy, Clone)]
115pub struct ClassicFrame { 150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub struct Frame {
116 can_header: Header, 152 can_header: Header,
117 data: ClassicData, 153 data: ClassicData,
118} 154}
119 155
120impl ClassicFrame { 156impl Frame {
121 pub(crate) const MAX_DATA_LEN: usize = 8;
122
123 /// Create a new CAN classic Frame 157 /// Create a new CAN classic Frame
124 pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { 158 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
125 ClassicFrame { can_header, data } 159 let data = ClassicData::new(raw_data)?;
160 Ok(Frame { can_header, data: data })
161 }
162
163 /// Creates a new data frame.
164 pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> {
165 let eid: embedded_can::Id = id.into();
166 let header = Header::new(eid, data.len() as u8, false);
167 Self::new(header, data)
126 } 168 }
127 169
128 /// Create new extended frame 170 /// Create new extended frame
129 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { 171 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
130 if let Some(id) = embedded_can::ExtendedId::new(raw_id) { 172 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
131 match ClassicData::new(raw_data) { 173 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
132 Some(data) => Some(ClassicFrame::new(
133 Header::new(id.into(), raw_data.len() as u8, false),
134 data,
135 )),
136 None => None,
137 }
138 } else { 174 } else {
139 None 175 Err(FrameCreateError::InvalidCanId)
140 } 176 }
141 } 177 }
142 178
143 /// Create new standard frame 179 /// Create new standard frame
144 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { 180 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
145 if let Some(id) = embedded_can::StandardId::new(raw_id) { 181 if let Some(id) = embedded_can::StandardId::new(raw_id) {
146 match ClassicData::new(raw_data) { 182 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
147 Some(data) => Some(ClassicFrame::new(
148 Header::new(id.into(), raw_data.len() as u8, false),
149 data,
150 )),
151 None => None,
152 }
153 } else { 183 } else {
154 None 184 Err(FrameCreateError::InvalidCanId)
155 } 185 }
156 } 186 }
157 187
158 /// Create new remote frame 188 /// Create new remote frame
159 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 189 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
160 if len <= 8usize { 190 if len <= 8usize {
161 Some(ClassicFrame::new( 191 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
162 Header::new(id.into(), len as u8, true),
163 ClassicData::empty(),
164 ))
165 } else { 192 } else {
166 None 193 Err(FrameCreateError::InvalidDataLength)
167 } 194 }
168 } 195 }
169 196
@@ -181,24 +208,28 @@ impl ClassicFrame {
181 pub fn data(&self) -> &[u8] { 208 pub fn data(&self) -> &[u8] {
182 &self.data.raw() 209 &self.data.raw()
183 } 210 }
211
212 /// Get priority of frame
213 pub fn priority(&self) -> u32 {
214 self.header().priority()
215 }
184} 216}
185 217
186impl embedded_can::Frame for ClassicFrame { 218impl embedded_can::Frame for Frame {
187 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { 219 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
188 match ClassicData::new(raw_data) { 220 let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
189 Some(data) => Some(ClassicFrame::new( 221 match frameopt {
190 Header::new(id.into(), raw_data.len() as u8, false), 222 Ok(frame) => Some(frame),
191 data, 223 Err(_) => None,
192 )),
193 None => None,
194 } 224 }
195 } 225 }
196 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 226 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
197 if len <= 8 { 227 if len <= 8 {
198 Some(ClassicFrame::new( 228 let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
199 Header::new(id.into(), len as u8, true), 229 match frameopt {
200 ClassicData::empty(), 230 Ok(frame) => Some(frame),
201 )) 231 Err(_) => None,
232 }
202 } else { 233 } else {
203 None 234 None
204 } 235 }
@@ -223,9 +254,9 @@ impl embedded_can::Frame for ClassicFrame {
223 } 254 }
224} 255}
225 256
226impl CanHeader for ClassicFrame { 257impl CanHeader for Frame {
227 fn from_header(header: Header, data: &[u8]) -> Option<Self> { 258 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
228 Some(Self::new(header, ClassicData::new(data)?)) 259 Self::new(header, data)
229 } 260 }
230 261
231 fn header(&self) -> &Header { 262 fn header(&self) -> &Header {
@@ -233,10 +264,31 @@ impl CanHeader for ClassicFrame {
233 } 264 }
234} 265}
235 266
267/// Contains CAN frame and additional metadata.
268///
269/// Timestamp is available if `time` feature is enabled.
270/// For CAN-FD support use FdEnvelope
271#[derive(Debug, Clone)]
272#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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
236/// Payload of a (FD)CAN data frame. 287/// Payload of a (FD)CAN data frame.
237/// 288///
238/// Contains 0 to 64 Bytes of data. 289/// Contains 0 to 64 Bytes of data.
239#[derive(Debug, Copy, Clone)] 290#[derive(Debug, Copy, Clone)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
240pub struct FdData { 292pub struct FdData {
241 pub(crate) bytes: [u8; 64], 293 pub(crate) bytes: [u8; 64],
242} 294}
@@ -246,15 +298,15 @@ impl FdData {
246 /// 298 ///
247 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 299 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
248 /// cannot be represented with an FDCAN DLC. 300 /// cannot be represented with an FDCAN DLC.
249 pub fn new(data: &[u8]) -> Option<Self> { 301 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
250 if !FdData::is_valid_len(data.len()) { 302 if !FdData::is_valid_len(data.len()) {
251 return None; 303 return Err(FrameCreateError::InvalidDataLength);
252 } 304 }
253 305
254 let mut bytes = [0; 64]; 306 let mut bytes = [0; 64];
255 bytes[..data.len()].copy_from_slice(data); 307 bytes[..data.len()].copy_from_slice(data);
256 308
257 Some(Self { bytes }) 309 Ok(Self { bytes })
258 } 310 }
259 311
260 /// Raw read access to data. 312 /// Raw read access to data.
@@ -286,6 +338,7 @@ impl FdData {
286 338
287/// Frame with up to 8 bytes of data payload as per Fd CAN 339/// Frame with up to 8 bytes of data payload as per Fd CAN
288#[derive(Debug, Copy, Clone)] 340#[derive(Debug, Copy, Clone)]
341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
289pub struct FdFrame { 342pub struct FdFrame {
290 can_header: Header, 343 can_header: Header,
291 data: FdData, 344 data: FdData,
@@ -293,40 +346,35 @@ pub struct FdFrame {
293 346
294impl FdFrame { 347impl FdFrame {
295 /// Create a new CAN classic Frame 348 /// Create a new CAN classic Frame
296 pub fn new(can_header: Header, data: FdData) -> FdFrame { 349 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
297 FdFrame { can_header, data } 350 let data = FdData::new(raw_data)?;
351 Ok(FdFrame { can_header, data })
298 } 352 }
299 353
300 /// Create new extended frame 354 /// Create new extended frame
301 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { 355 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
302 if let Some(id) = embedded_can::ExtendedId::new(raw_id) { 356 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
303 match FdData::new(raw_data) { 357 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
304 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
305 None => None,
306 }
307 } else { 358 } else {
308 None 359 Err(FrameCreateError::InvalidCanId)
309 } 360 }
310 } 361 }
311 362
312 /// Create new standard frame 363 /// Create new standard frame
313 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { 364 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
314 if let Some(id) = embedded_can::StandardId::new(raw_id) { 365 if let Some(id) = embedded_can::StandardId::new(raw_id) {
315 match FdData::new(raw_data) { 366 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
316 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
317 None => None,
318 }
319 } else { 367 } else {
320 None 368 Err(FrameCreateError::InvalidCanId)
321 } 369 }
322 } 370 }
323 371
324 /// Create new remote frame 372 /// Create new remote frame
325 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 373 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
326 if len <= 8 { 374 if len <= 8 {
327 Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) 375 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
328 } else { 376 } else {
329 None 377 Err(FrameCreateError::InvalidDataLength)
330 } 378 }
331 } 379 }
332 380
@@ -348,20 +396,17 @@ impl FdFrame {
348 396
349impl embedded_can::Frame for FdFrame { 397impl embedded_can::Frame for FdFrame {
350 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { 398 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
351 match FdData::new(raw_data) { 399 match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) {
352 Some(data) => Some(FdFrame::new( 400 Ok(frame) => Some(frame),
353 Header::new_fd(id.into(), raw_data.len() as u8, false, true), 401 Err(_) => None,
354 data,
355 )),
356 None => None,
357 } 402 }
358 } 403 }
359 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 404 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
360 if len <= 8 { 405 if len <= 8 {
361 Some(FdFrame::new( 406 match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) {
362 Header::new_fd(id.into(), len as u8, true, true), 407 Ok(frame) => Some(frame),
363 FdData::empty(), 408 Err(_) => None,
364 )) 409 }
365 } else { 410 } else {
366 None 411 None
367 } 412 }
@@ -388,11 +433,31 @@ impl embedded_can::Frame for FdFrame {
388} 433}
389 434
390impl CanHeader for FdFrame { 435impl CanHeader for FdFrame {
391 fn from_header(header: Header, data: &[u8]) -> Option<Self> { 436 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
392 Some(Self::new(header, FdData::new(data)?)) 437 Self::new(header, data)
393 } 438 }
394 439
395 fn header(&self) -> &Header { 440 fn header(&self) -> &Header {
396 self.header() 441 self.header()
397 } 442 }
398} 443}
444
445/// Contains CAN FD frame and additional metadata.
446///
447/// Timestamp is available if `time` feature is enabled.
448#[derive(Debug, Clone)]
449#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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 8f259520a..18b5ec918 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -2,14 +2,39 @@
2#[cfg(any(cryp_v2, cryp_v3))] 2#[cfg(any(cryp_v2, cryp_v3))]
3use core::cmp::min; 3use core::cmp::min;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::ptr;
5 6
6use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker;
7 9
10use crate::dma::{NoDma, Priority, Transfer, TransferOptions};
11use crate::interrupt::typelevel::Interrupt;
8use crate::{interrupt, pac, peripherals, Peripheral}; 12use crate::{interrupt, pac, peripherals, Peripheral};
9 13
10const DES_BLOCK_SIZE: usize = 8; // 64 bits 14const DES_BLOCK_SIZE: usize = 8; // 64 bits
11const AES_BLOCK_SIZE: usize = 16; // 128 bits 15const AES_BLOCK_SIZE: usize = 16; // 128 bits
12 16
17static CRYP_WAKER: AtomicWaker = AtomicWaker::new();
18
19/// CRYP interrupt handler.
20pub struct InterruptHandler<T: Instance> {
21 _phantom: PhantomData<T>,
22}
23
24impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
25 unsafe fn on_interrupt() {
26 let bits = T::regs().misr().read();
27 if bits.inmis() {
28 T::regs().imscr().modify(|w| w.set_inim(false));
29 CRYP_WAKER.wake();
30 }
31 if bits.outmis() {
32 T::regs().imscr().modify(|w| w.set_outim(false));
33 CRYP_WAKER.wake();
34 }
35 }
36}
37
13/// This trait encapsulates all cipher-specific behavior/ 38/// This trait encapsulates all cipher-specific behavior/
14pub trait Cipher<'c> { 39pub trait Cipher<'c> {
15 /// Processing block size. Determined by the processor and the algorithm. 40 /// Processing block size. Determined by the processor and the algorithm.
@@ -32,17 +57,26 @@ pub trait Cipher<'c> {
32 fn prepare_key(&self, _p: &pac::cryp::Cryp) {} 57 fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
33 58
34 /// Performs any cipher-specific initialization. 59 /// Performs any cipher-specific initialization.
35 fn init_phase(&self, _p: &pac::cryp::Cryp) {} 60 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {}
61
62 /// Performs any cipher-specific initialization.
63 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
64 where
65 DmaIn: crate::cryp::DmaIn<T>,
66 DmaOut: crate::cryp::DmaOut<T>,
67 {
68 }
36 69
37 /// Called prior to processing the last data block for cipher-specific operations. 70 /// Called prior to processing the last data block for cipher-specific operations.
38 fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { 71 fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
39 return [0; 4]; 72 return [0; 4];
40 } 73 }
41 74
42 /// Called after processing the last data block for cipher-specific operations. 75 /// Called after processing the last data block for cipher-specific operations.
43 fn post_final_block( 76 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
44 &self, 77 &self,
45 _p: &pac::cryp::Cryp, 78 _p: &pac::cryp::Cryp,
79 _cryp: &Cryp<T, DmaIn, DmaOut>,
46 _dir: Direction, 80 _dir: Direction,
47 _int_data: &mut [u8; AES_BLOCK_SIZE], 81 _int_data: &mut [u8; AES_BLOCK_SIZE],
48 _temp1: [u32; 4], 82 _temp1: [u32; 4],
@@ -50,7 +84,22 @@ pub trait Cipher<'c> {
50 ) { 84 ) {
51 } 85 }
52 86
53 /// Called prior to processing the first associated data block for cipher-specific operations. 87 /// Called after processing the last data block for cipher-specific operations.
88 async fn post_final<T: Instance, DmaIn, DmaOut>(
89 &self,
90 _p: &pac::cryp::Cryp,
91 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
92 _dir: Direction,
93 _int_data: &mut [u8; AES_BLOCK_SIZE],
94 _temp1: [u32; 4],
95 _padding_mask: [u8; 16],
96 ) where
97 DmaIn: crate::cryp::DmaIn<T>,
98 DmaOut: crate::cryp::DmaOut<T>,
99 {
100 }
101
102 /// Returns the AAD header block as required by the cipher.
54 fn get_header_block(&self) -> &[u8] { 103 fn get_header_block(&self) -> &[u8] {
55 return [0; 0].as_slice(); 104 return [0; 0].as_slice();
56 } 105 }
@@ -425,14 +474,24 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
425 p.cr().modify(|w| w.set_algomode3(true)); 474 p.cr().modify(|w| w.set_algomode3(true));
426 } 475 }
427 476
428 fn init_phase(&self, p: &pac::cryp::Cryp) { 477 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
478 p.cr().modify(|w| w.set_gcm_ccmph(0));
479 p.cr().modify(|w| w.set_crypen(true));
480 while p.cr().read().crypen() {}
481 }
482
483 async fn init_phase<T: Instance, DmaIn, DmaOut>(
484 &self,
485 p: &pac::cryp::Cryp,
486 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
487 ) {
429 p.cr().modify(|w| w.set_gcm_ccmph(0)); 488 p.cr().modify(|w| w.set_gcm_ccmph(0));
430 p.cr().modify(|w| w.set_crypen(true)); 489 p.cr().modify(|w| w.set_crypen(true));
431 while p.cr().read().crypen() {} 490 while p.cr().read().crypen() {}
432 } 491 }
433 492
434 #[cfg(cryp_v2)] 493 #[cfg(cryp_v2)]
435 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 494 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
436 //Handle special GCM partial block process. 495 //Handle special GCM partial block process.
437 if dir == Direction::Encrypt { 496 if dir == Direction::Encrypt {
438 p.cr().modify(|w| w.set_crypen(false)); 497 p.cr().modify(|w| w.set_crypen(false));
@@ -446,16 +505,17 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
446 } 505 }
447 506
448 #[cfg(cryp_v3)] 507 #[cfg(cryp_v3)]
449 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 508 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
450 //Handle special GCM partial block process. 509 //Handle special GCM partial block process.
451 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 510 p.cr().modify(|w| w.set_npblb(padding_len as u8));
452 [0; 4] 511 [0; 4]
453 } 512 }
454 513
455 #[cfg(cryp_v2)] 514 #[cfg(cryp_v2)]
456 fn post_final_block( 515 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
457 &self, 516 &self,
458 p: &pac::cryp::Cryp, 517 p: &pac::cryp::Cryp,
518 cryp: &Cryp<T, DmaIn, DmaOut>,
459 dir: Direction, 519 dir: Direction,
460 int_data: &mut [u8; AES_BLOCK_SIZE], 520 int_data: &mut [u8; AES_BLOCK_SIZE],
461 _temp1: [u32; 4], 521 _temp1: [u32; 4],
@@ -471,17 +531,44 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
471 } 531 }
472 p.cr().modify(|w| w.set_crypen(true)); 532 p.cr().modify(|w| w.set_crypen(true));
473 p.cr().modify(|w| w.set_gcm_ccmph(3)); 533 p.cr().modify(|w| w.set_gcm_ccmph(3));
474 let mut index = 0; 534
475 let end_index = Self::BLOCK_SIZE; 535 cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data);
476 while index < end_index { 536 cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data);
477 let mut in_word: [u8; 4] = [0; 4]; 537 }
478 in_word.copy_from_slice(&int_data[index..index + 4]); 538 }
479 p.din().write_value(u32::from_ne_bytes(in_word)); 539
480 index += 4; 540 #[cfg(cryp_v2)]
481 } 541 async fn post_final<T: Instance, DmaIn, DmaOut>(
482 for _ in 0..4 { 542 &self,
483 p.dout().read(); 543 p: &pac::cryp::Cryp,
544 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
545 dir: Direction,
546 int_data: &mut [u8; AES_BLOCK_SIZE],
547 _temp1: [u32; 4],
548 padding_mask: [u8; AES_BLOCK_SIZE],
549 ) where
550 DmaIn: crate::cryp::DmaIn<T>,
551 DmaOut: crate::cryp::DmaOut<T>,
552 {
553 if dir == Direction::Encrypt {
554 // Handle special GCM partial block process.
555 p.cr().modify(|w| w.set_crypen(false));
556 p.cr().modify(|w| w.set_algomode3(true));
557 p.cr().modify(|w| w.set_algomode0(0));
558 for i in 0..AES_BLOCK_SIZE {
559 int_data[i] = int_data[i] & padding_mask[i];
484 } 560 }
561 p.cr().modify(|w| w.set_crypen(true));
562 p.cr().modify(|w| w.set_gcm_ccmph(3));
563
564 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
565
566 let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data);
567 let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data);
568
569 embassy_futures::join::join(read, write).await;
570
571 int_data.copy_from_slice(&out_data);
485 } 572 }
486 } 573 }
487} 574}
@@ -532,14 +619,24 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
532 p.cr().modify(|w| w.set_algomode3(true)); 619 p.cr().modify(|w| w.set_algomode3(true));
533 } 620 }
534 621
535 fn init_phase(&self, p: &pac::cryp::Cryp) { 622 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
623 p.cr().modify(|w| w.set_gcm_ccmph(0));
624 p.cr().modify(|w| w.set_crypen(true));
625 while p.cr().read().crypen() {}
626 }
627
628 async fn init_phase<T: Instance, DmaIn, DmaOut>(
629 &self,
630 p: &pac::cryp::Cryp,
631 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
632 ) {
536 p.cr().modify(|w| w.set_gcm_ccmph(0)); 633 p.cr().modify(|w| w.set_gcm_ccmph(0));
537 p.cr().modify(|w| w.set_crypen(true)); 634 p.cr().modify(|w| w.set_crypen(true));
538 while p.cr().read().crypen() {} 635 while p.cr().read().crypen() {}
539 } 636 }
540 637
541 #[cfg(cryp_v2)] 638 #[cfg(cryp_v2)]
542 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 639 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
543 //Handle special GCM partial block process. 640 //Handle special GCM partial block process.
544 if dir == Direction::Encrypt { 641 if dir == Direction::Encrypt {
545 p.cr().modify(|w| w.set_crypen(false)); 642 p.cr().modify(|w| w.set_crypen(false));
@@ -553,16 +650,17 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
553 } 650 }
554 651
555 #[cfg(cryp_v3)] 652 #[cfg(cryp_v3)]
556 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 653 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
557 //Handle special GCM partial block process. 654 //Handle special GCM partial block process.
558 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 655 p.cr().modify(|w| w.set_npblb(padding_len as u8));
559 [0; 4] 656 [0; 4]
560 } 657 }
561 658
562 #[cfg(cryp_v2)] 659 #[cfg(cryp_v2)]
563 fn post_final_block( 660 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
564 &self, 661 &self,
565 p: &pac::cryp::Cryp, 662 p: &pac::cryp::Cryp,
663 cryp: &Cryp<T, DmaIn, DmaOut>,
566 dir: Direction, 664 dir: Direction,
567 int_data: &mut [u8; AES_BLOCK_SIZE], 665 int_data: &mut [u8; AES_BLOCK_SIZE],
568 _temp1: [u32; 4], 666 _temp1: [u32; 4],
@@ -578,17 +676,42 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
578 } 676 }
579 p.cr().modify(|w| w.set_crypen(true)); 677 p.cr().modify(|w| w.set_crypen(true));
580 p.cr().modify(|w| w.set_gcm_ccmph(3)); 678 p.cr().modify(|w| w.set_gcm_ccmph(3));
581 let mut index = 0; 679
582 let end_index = Self::BLOCK_SIZE; 680 cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data);
583 while index < end_index { 681 cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data);
584 let mut in_word: [u8; 4] = [0; 4]; 682 }
585 in_word.copy_from_slice(&int_data[index..index + 4]); 683 }
586 p.din().write_value(u32::from_ne_bytes(in_word)); 684
587 index += 4; 685 #[cfg(cryp_v2)]
588 } 686 async fn post_final<T: Instance, DmaIn, DmaOut>(
589 for _ in 0..4 { 687 &self,
590 p.dout().read(); 688 p: &pac::cryp::Cryp,
689 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
690 dir: Direction,
691 int_data: &mut [u8; AES_BLOCK_SIZE],
692 _temp1: [u32; 4],
693 padding_mask: [u8; AES_BLOCK_SIZE],
694 ) where
695 DmaIn: crate::cryp::DmaIn<T>,
696 DmaOut: crate::cryp::DmaOut<T>,
697 {
698 if dir == Direction::Encrypt {
699 // Handle special GCM partial block process.
700 p.cr().modify(|w| w.set_crypen(false));
701 p.cr().modify(|w| w.set_algomode3(true));
702 p.cr().modify(|w| w.set_algomode0(0));
703 for i in 0..AES_BLOCK_SIZE {
704 int_data[i] = int_data[i] & padding_mask[i];
591 } 705 }
706 p.cr().modify(|w| w.set_crypen(true));
707 p.cr().modify(|w| w.set_gcm_ccmph(3));
708
709 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
710
711 let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data);
712 let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data);
713
714 embassy_futures::join::join(read, write).await;
592 } 715 }
593 } 716 }
594} 717}
@@ -697,18 +820,24 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
697 p.cr().modify(|w| w.set_algomode3(true)); 820 p.cr().modify(|w| w.set_algomode3(true));
698 } 821 }
699 822
700 fn init_phase(&self, p: &pac::cryp::Cryp) { 823 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) {
701 p.cr().modify(|w| w.set_gcm_ccmph(0)); 824 p.cr().modify(|w| w.set_gcm_ccmph(0));
702 825
703 let mut index = 0; 826 cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0);
704 let end_index = index + Self::BLOCK_SIZE; 827
705 // Write block in 828 p.cr().modify(|w| w.set_crypen(true));
706 while index < end_index { 829 while p.cr().read().crypen() {}
707 let mut in_word: [u8; 4] = [0; 4]; 830 }
708 in_word.copy_from_slice(&self.block0[index..index + 4]); 831
709 p.din().write_value(u32::from_ne_bytes(in_word)); 832 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
710 index += 4; 833 where
711 } 834 DmaIn: crate::cryp::DmaIn<T>,
835 DmaOut: crate::cryp::DmaOut<T>,
836 {
837 p.cr().modify(|w| w.set_gcm_ccmph(0));
838
839 Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await;
840
712 p.cr().modify(|w| w.set_crypen(true)); 841 p.cr().modify(|w| w.set_crypen(true));
713 while p.cr().read().crypen() {} 842 while p.cr().read().crypen() {}
714 } 843 }
@@ -718,7 +847,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
718 } 847 }
719 848
720 #[cfg(cryp_v2)] 849 #[cfg(cryp_v2)]
721 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 850 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
722 //Handle special CCM partial block process. 851 //Handle special CCM partial block process.
723 let mut temp1 = [0; 4]; 852 let mut temp1 = [0; 4];
724 if dir == Direction::Decrypt { 853 if dir == Direction::Decrypt {
@@ -737,16 +866,17 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
737 } 866 }
738 867
739 #[cfg(cryp_v3)] 868 #[cfg(cryp_v3)]
740 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 869 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
741 //Handle special GCM partial block process. 870 //Handle special GCM partial block process.
742 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 871 p.cr().modify(|w| w.set_npblb(padding_len as u8));
743 [0; 4] 872 [0; 4]
744 } 873 }
745 874
746 #[cfg(cryp_v2)] 875 #[cfg(cryp_v2)]
747 fn post_final_block( 876 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
748 &self, 877 &self,
749 p: &pac::cryp::Cryp, 878 p: &pac::cryp::Cryp,
879 cryp: &Cryp<T, DmaIn, DmaOut>,
750 dir: Direction, 880 dir: Direction,
751 int_data: &mut [u8; AES_BLOCK_SIZE], 881 int_data: &mut [u8; AES_BLOCK_SIZE],
752 temp1: [u32; 4], 882 temp1: [u32; 4],
@@ -774,8 +904,48 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
774 let int_word = u32::from_le_bytes(int_bytes); 904 let int_word = u32::from_le_bytes(int_bytes);
775 in_data[i] = int_word; 905 in_data[i] = int_word;
776 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; 906 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
777 p.din().write_value(in_data[i]);
778 } 907 }
908 cryp.write_words_blocking(Self::BLOCK_SIZE, &in_data);
909 }
910 }
911
912 #[cfg(cryp_v2)]
913 async fn post_final<T: Instance, DmaIn, DmaOut>(
914 &self,
915 p: &pac::cryp::Cryp,
916 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
917 dir: Direction,
918 int_data: &mut [u8; AES_BLOCK_SIZE],
919 temp1: [u32; 4],
920 padding_mask: [u8; 16],
921 ) where
922 DmaIn: crate::cryp::DmaIn<T>,
923 DmaOut: crate::cryp::DmaOut<T>,
924 {
925 if dir == Direction::Decrypt {
926 //Handle special CCM partial block process.
927 let mut temp2 = [0; 4];
928 temp2[0] = p.csgcmccmr(0).read().swap_bytes();
929 temp2[1] = p.csgcmccmr(1).read().swap_bytes();
930 temp2[2] = p.csgcmccmr(2).read().swap_bytes();
931 temp2[3] = p.csgcmccmr(3).read().swap_bytes();
932 p.cr().modify(|w| w.set_algomode3(true));
933 p.cr().modify(|w| w.set_algomode0(1));
934 p.cr().modify(|w| w.set_gcm_ccmph(3));
935 // Header phase
936 p.cr().modify(|w| w.set_gcm_ccmph(1));
937 for i in 0..AES_BLOCK_SIZE {
938 int_data[i] = int_data[i] & padding_mask[i];
939 }
940 let mut in_data: [u32; 4] = [0; 4];
941 for i in 0..in_data.len() {
942 let mut int_bytes: [u8; 4] = [0; 4];
943 int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]);
944 let int_word = u32::from_le_bytes(int_bytes);
945 in_data[i] = int_word;
946 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
947 }
948 Cryp::<T, DmaIn, DmaOut>::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await;
779 } 949 }
780 } 950 }
781} 951}
@@ -845,24 +1015,40 @@ pub enum Direction {
845} 1015}
846 1016
847/// Crypto Accelerator Driver 1017/// Crypto Accelerator Driver
848pub struct Cryp<'d, T: Instance> { 1018pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> {
849 _peripheral: PeripheralRef<'d, T>, 1019 _peripheral: PeripheralRef<'d, T>,
1020 indma: PeripheralRef<'d, DmaIn>,
1021 outdma: PeripheralRef<'d, DmaOut>,
850} 1022}
851 1023
852impl<'d, T: Instance> Cryp<'d, T> { 1024impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
853 /// Create a new CRYP driver. 1025 /// Create a new CRYP driver.
854 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { 1026 pub fn new(
1027 peri: impl Peripheral<P = T> + 'd,
1028 indma: impl Peripheral<P = DmaIn> + 'd,
1029 outdma: impl Peripheral<P = DmaOut> + 'd,
1030 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1031 ) -> Self {
855 T::enable_and_reset(); 1032 T::enable_and_reset();
856 into_ref!(peri); 1033 into_ref!(peri, indma, outdma);
857 let instance = Self { _peripheral: peri }; 1034 let instance = Self {
1035 _peripheral: peri,
1036 indma: indma,
1037 outdma: outdma,
1038 };
1039
1040 T::Interrupt::unpend();
1041 unsafe { T::Interrupt::enable() };
1042
858 instance 1043 instance
859 } 1044 }
860 1045
861 /// Start a new cipher operation. 1046 /// Start a new encrypt or decrypt operation for the given cipher.
862 /// Key size must be 128, 192, or 256 bits. 1047 pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(
863 /// Initialization vector must only be supplied if necessary. 1048 &self,
864 /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. 1049 cipher: &'c C,
865 pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { 1050 dir: Direction,
1051 ) -> Context<'c, C> {
866 let mut ctx: Context<'c, C> = Context { 1052 let mut ctx: Context<'c, C> = Context {
867 dir, 1053 dir,
868 last_block_processed: false, 1054 last_block_processed: false,
@@ -929,7 +1115,90 @@ impl<'d, T: Instance> Cryp<'d, T> {
929 // Flush in/out FIFOs 1115 // Flush in/out FIFOs
930 T::regs().cr().modify(|w| w.fflush()); 1116 T::regs().cr().modify(|w| w.fflush());
931 1117
932 ctx.cipher.init_phase(&T::regs()); 1118 ctx.cipher.init_phase_blocking(&T::regs(), self);
1119
1120 self.store_context(&mut ctx);
1121
1122 ctx
1123 }
1124
1125 /// Start a new encrypt or decrypt operation for the given cipher.
1126 pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(
1127 &mut self,
1128 cipher: &'c C,
1129 dir: Direction,
1130 ) -> Context<'c, C>
1131 where
1132 DmaIn: crate::cryp::DmaIn<T>,
1133 DmaOut: crate::cryp::DmaOut<T>,
1134 {
1135 let mut ctx: Context<'c, C> = Context {
1136 dir,
1137 last_block_processed: false,
1138 cr: 0,
1139 iv: [0; 4],
1140 csgcmccm: [0; 8],
1141 csgcm: [0; 8],
1142 aad_complete: false,
1143 header_len: 0,
1144 payload_len: 0,
1145 cipher: cipher,
1146 phantom_data: PhantomData,
1147 header_processed: false,
1148 aad_buffer: [0; 16],
1149 aad_buffer_len: 0,
1150 };
1151
1152 T::regs().cr().modify(|w| w.set_crypen(false));
1153
1154 let key = ctx.cipher.key();
1155
1156 if key.len() == (128 / 8) {
1157 T::regs().cr().modify(|w| w.set_keysize(0));
1158 } else if key.len() == (192 / 8) {
1159 T::regs().cr().modify(|w| w.set_keysize(1));
1160 } else if key.len() == (256 / 8) {
1161 T::regs().cr().modify(|w| w.set_keysize(2));
1162 }
1163
1164 self.load_key(key);
1165
1166 // Set data type to 8-bit. This will match software implementations.
1167 T::regs().cr().modify(|w| w.set_datatype(2));
1168
1169 ctx.cipher.prepare_key(&T::regs());
1170
1171 ctx.cipher.set_algomode(&T::regs());
1172
1173 // Set encrypt/decrypt
1174 if dir == Direction::Encrypt {
1175 T::regs().cr().modify(|w| w.set_algodir(false));
1176 } else {
1177 T::regs().cr().modify(|w| w.set_algodir(true));
1178 }
1179
1180 // Load the IV into the registers.
1181 let iv = ctx.cipher.iv();
1182 let mut full_iv: [u8; 16] = [0; 16];
1183 full_iv[0..iv.len()].copy_from_slice(iv);
1184 let mut iv_idx = 0;
1185 let mut iv_word: [u8; 4] = [0; 4];
1186 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1187 iv_idx += 4;
1188 T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word));
1189 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1190 iv_idx += 4;
1191 T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
1192 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1193 iv_idx += 4;
1194 T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
1195 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1196 T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
1197
1198 // Flush in/out FIFOs
1199 T::regs().cr().modify(|w| w.fflush());
1200
1201 ctx.cipher.init_phase(&T::regs(), self).await;
933 1202
934 self.store_context(&mut ctx); 1203 self.store_context(&mut ctx);
935 1204
@@ -938,10 +1207,9 @@ impl<'d, T: Instance> Cryp<'d, T> {
938 1207
939 #[cfg(any(cryp_v2, cryp_v3))] 1208 #[cfg(any(cryp_v2, cryp_v3))]
940 /// Controls the header phase of cipher processing. 1209 /// Controls the header phase of cipher processing.
941 /// This function is only valid for GCM, CCM, and GMAC modes. 1210 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC.
942 /// It only needs to be called if using one of these modes and there is associated data. 1211 /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload_blocking`.
943 /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. 1212 /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block.
944 /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
945 /// When supplying the last block of AAD, `last_aad_block` must be `true`. 1213 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
946 pub fn aad_blocking< 1214 pub fn aad_blocking<
947 'c, 1215 'c,
@@ -985,15 +1253,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
985 if ctx.aad_buffer_len < C::BLOCK_SIZE { 1253 if ctx.aad_buffer_len < C::BLOCK_SIZE {
986 // The buffer isn't full and this is the last buffer, so process it as is (already padded). 1254 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
987 if last_aad_block { 1255 if last_aad_block {
988 let mut index = 0; 1256 self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
989 let end_index = C::BLOCK_SIZE;
990 // Write block in
991 while index < end_index {
992 let mut in_word: [u8; 4] = [0; 4];
993 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
994 T::regs().din().write_value(u32::from_ne_bytes(in_word));
995 index += 4;
996 }
997 // Block until input FIFO is empty. 1257 // Block until input FIFO is empty.
998 while !T::regs().sr().read().ifem() {} 1258 while !T::regs().sr().read().ifem() {}
999 1259
@@ -1008,15 +1268,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
1008 } 1268 }
1009 } else { 1269 } else {
1010 // Load the full block from the buffer. 1270 // Load the full block from the buffer.
1011 let mut index = 0; 1271 self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
1012 let end_index = C::BLOCK_SIZE;
1013 // Write block in
1014 while index < end_index {
1015 let mut in_word: [u8; 4] = [0; 4];
1016 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1017 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1018 index += 4;
1019 }
1020 // Block until input FIFO is empty. 1272 // Block until input FIFO is empty.
1021 while !T::regs().sr().read().ifem() {} 1273 while !T::regs().sr().read().ifem() {}
1022 } 1274 }
@@ -1032,33 +1284,108 @@ impl<'d, T: Instance> Cryp<'d, T> {
1032 1284
1033 // Load full data blocks into core. 1285 // Load full data blocks into core.
1034 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; 1286 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1035 for block in 0..num_full_blocks { 1287 let start_index = len_to_copy;
1036 let mut index = len_to_copy + (block * C::BLOCK_SIZE); 1288 let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks);
1037 let end_index = index + C::BLOCK_SIZE; 1289 self.write_bytes_blocking(C::BLOCK_SIZE, &aad[start_index..end_index]);
1038 // Write block in 1290
1039 while index < end_index { 1291 if last_aad_block {
1040 let mut in_word: [u8; 4] = [0; 4]; 1292 if leftovers > 0 {
1041 in_word.copy_from_slice(&aad[index..index + 4]); 1293 self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
1042 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1043 index += 4;
1044 } 1294 }
1045 // Block until input FIFO is empty. 1295 // Switch to payload phase.
1046 while !T::regs().sr().read().ifem() {} 1296 ctx.aad_complete = true;
1297 T::regs().cr().modify(|w| w.set_crypen(false));
1298 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1299 T::regs().cr().modify(|w| w.fflush());
1300 }
1301
1302 self.store_context(ctx);
1303 }
1304
1305 #[cfg(any(cryp_v2, cryp_v3))]
1306 /// Controls the header phase of cipher processing.
1307 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC.
1308 /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`.
1309 /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block.
1310 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
1311 pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>>(
1312 &mut self,
1313 ctx: &mut Context<'c, C>,
1314 aad: &[u8],
1315 last_aad_block: bool,
1316 ) where
1317 DmaIn: crate::cryp::DmaIn<T>,
1318 DmaOut: crate::cryp::DmaOut<T>,
1319 {
1320 self.load_context(ctx);
1321
1322 // Perform checks for correctness.
1323 if ctx.aad_complete {
1324 panic!("Cannot update AAD after starting payload!")
1325 }
1326
1327 ctx.header_len += aad.len() as u64;
1328
1329 // Header phase
1330 T::regs().cr().modify(|w| w.set_crypen(false));
1331 T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
1332 T::regs().cr().modify(|w| w.set_crypen(true));
1333
1334 // First write the header B1 block if not yet written.
1335 if !ctx.header_processed {
1336 ctx.header_processed = true;
1337 let header = ctx.cipher.get_header_block();
1338 ctx.aad_buffer[0..header.len()].copy_from_slice(header);
1339 ctx.aad_buffer_len += header.len();
1340 }
1341
1342 // Fill the header block to make a full block.
1343 let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
1344 ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
1345 ctx.aad_buffer_len += len_to_copy;
1346 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1347 let mut aad_len_remaining = aad.len() - len_to_copy;
1348
1349 if ctx.aad_buffer_len < C::BLOCK_SIZE {
1350 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
1351 if last_aad_block {
1352 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1353 assert_eq!(T::regs().sr().read().ifem(), true);
1354
1355 // Switch to payload phase.
1356 ctx.aad_complete = true;
1357 T::regs().cr().modify(|w| w.set_crypen(false));
1358 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1359 T::regs().cr().modify(|w| w.fflush());
1360 } else {
1361 // Just return because we don't yet have a full block to process.
1362 return;
1363 }
1364 } else {
1365 // Load the full block from the buffer.
1366 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1367 assert_eq!(T::regs().sr().read().ifem(), true);
1047 } 1368 }
1048 1369
1370 // Handle a partial block that is passed in.
1371 ctx.aad_buffer_len = 0;
1372 let leftovers = aad_len_remaining % C::BLOCK_SIZE;
1373 ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
1374 ctx.aad_buffer_len += leftovers;
1375 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1376 aad_len_remaining -= leftovers;
1377 assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
1378
1379 // Load full data blocks into core.
1380 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1381 let start_index = len_to_copy;
1382 let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks);
1383 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await;
1384
1049 if last_aad_block { 1385 if last_aad_block {
1050 if leftovers > 0 { 1386 if leftovers > 0 {
1051 let mut index = 0; 1387 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1052 let end_index = C::BLOCK_SIZE; 1388 assert_eq!(T::regs().sr().read().ifem(), true);
1053 // Write block in
1054 while index < end_index {
1055 let mut in_word: [u8; 4] = [0; 4];
1056 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1057 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1058 index += 4;
1059 }
1060 // Block until input FIFO is empty.
1061 while !T::regs().sr().read().ifem() {}
1062 } 1389 }
1063 // Switch to payload phase. 1390 // Switch to payload phase.
1064 ctx.aad_complete = true; 1391 ctx.aad_complete = true;
@@ -1074,7 +1401,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
1074 /// The context determines algorithm, mode, and state of the crypto accelerator. 1401 /// The context determines algorithm, mode, and state of the crypto accelerator.
1075 /// When the last piece of data is supplied, `last_block` should be `true`. 1402 /// When the last piece of data is supplied, `last_block` should be `true`.
1076 /// This function panics under various mismatches of parameters. 1403 /// This function panics under various mismatches of parameters.
1077 /// Input and output buffer lengths must match. 1404 /// Output buffer must be at least as long as the input buffer.
1078 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. 1405 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1079 /// Padding or ciphertext stealing must be managed by the application for these modes. 1406 /// Padding or ciphertext stealing must be managed by the application for these modes.
1080 /// Data must also be a multiple of block size unless `last_block` is `true`. 1407 /// Data must also be a multiple of block size unless `last_block` is `true`.
@@ -1125,54 +1452,121 @@ impl<'d, T: Instance> Cryp<'d, T> {
1125 // Load data into core, block by block. 1452 // Load data into core, block by block.
1126 let num_full_blocks = input.len() / C::BLOCK_SIZE; 1453 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1127 for block in 0..num_full_blocks { 1454 for block in 0..num_full_blocks {
1128 let mut index = block * C::BLOCK_SIZE; 1455 let index = block * C::BLOCK_SIZE;
1129 let end_index = index + C::BLOCK_SIZE;
1130 // Write block in 1456 // Write block in
1131 while index < end_index { 1457 self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]);
1132 let mut in_word: [u8; 4] = [0; 4];
1133 in_word.copy_from_slice(&input[index..index + 4]);
1134 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1135 index += 4;
1136 }
1137 let mut index = block * C::BLOCK_SIZE;
1138 let end_index = index + C::BLOCK_SIZE;
1139 // Block until there is output to read.
1140 while !T::regs().sr().read().ofne() {}
1141 // Read block out 1458 // Read block out
1142 while index < end_index { 1459 self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]);
1143 let out_word: u32 = T::regs().dout().read();
1144 output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1145 index += 4;
1146 }
1147 } 1460 }
1148 1461
1149 // Handle the final block, which is incomplete. 1462 // Handle the final block, which is incomplete.
1150 if last_block_remainder > 0 { 1463 if last_block_remainder > 0 {
1151 let padding_len = C::BLOCK_SIZE - last_block_remainder; 1464 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1152 let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len); 1465 let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len);
1153 1466
1154 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1467 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1155 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1468 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1156 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); 1469 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1157 let mut index = 0; 1470 self.write_bytes_blocking(C::BLOCK_SIZE, &last_block);
1158 let end_index = C::BLOCK_SIZE; 1471 self.read_bytes_blocking(C::BLOCK_SIZE, &mut intermediate_data);
1159 // Write block in 1472
1160 while index < end_index { 1473 // Handle the last block depending on mode.
1161 let mut in_word: [u8; 4] = [0; 4]; 1474 let output_len = output.len();
1162 in_word.copy_from_slice(&last_block[index..index + 4]); 1475 output[output_len - last_block_remainder..output_len]
1163 T::regs().din().write_value(u32::from_ne_bytes(in_word)); 1476 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
1164 index += 4; 1477
1478 let mut mask: [u8; 16] = [0; 16];
1479 mask[..last_block_remainder].fill(0xFF);
1480 ctx.cipher
1481 .post_final_blocking(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask);
1482 }
1483
1484 ctx.payload_len += input.len() as u64;
1485
1486 self.store_context(ctx);
1487 }
1488
1489 /// Performs encryption/decryption on the provided context.
1490 /// The context determines algorithm, mode, and state of the crypto accelerator.
1491 /// When the last piece of data is supplied, `last_block` should be `true`.
1492 /// This function panics under various mismatches of parameters.
1493 /// Output buffer must be at least as long as the input buffer.
1494 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1495 /// Padding or ciphertext stealing must be managed by the application for these modes.
1496 /// Data must also be a multiple of block size unless `last_block` is `true`.
1497 pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>(
1498 &mut self,
1499 ctx: &mut Context<'c, C>,
1500 input: &[u8],
1501 output: &mut [u8],
1502 last_block: bool,
1503 ) where
1504 DmaIn: crate::cryp::DmaIn<T>,
1505 DmaOut: crate::cryp::DmaOut<T>,
1506 {
1507 self.load_context(ctx);
1508
1509 let last_block_remainder = input.len() % C::BLOCK_SIZE;
1510
1511 // Perform checks for correctness.
1512 if !ctx.aad_complete && ctx.header_len > 0 {
1513 panic!("Additional associated data must be processed first!");
1514 } else if !ctx.aad_complete {
1515 #[cfg(any(cryp_v2, cryp_v3))]
1516 {
1517 ctx.aad_complete = true;
1518 T::regs().cr().modify(|w| w.set_crypen(false));
1519 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1520 T::regs().cr().modify(|w| w.fflush());
1521 T::regs().cr().modify(|w| w.set_crypen(true));
1165 } 1522 }
1166 let mut index = 0; 1523 }
1167 let end_index = C::BLOCK_SIZE; 1524 if ctx.last_block_processed {
1168 // Block until there is output to read. 1525 panic!("The last block has already been processed!");
1169 while !T::regs().sr().read().ofne() {} 1526 }
1170 // Read block out 1527 if input.len() > output.len() {
1171 while index < end_index { 1528 panic!("Output buffer length must match input length.");
1172 let out_word: u32 = T::regs().dout().read(); 1529 }
1173 intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); 1530 if !last_block {
1174 index += 4; 1531 if last_block_remainder != 0 {
1532 panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
1533 }
1534 }
1535 if C::REQUIRES_PADDING {
1536 if last_block_remainder != 0 {
1537 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
1175 } 1538 }
1539 }
1540 if last_block {
1541 ctx.last_block_processed = true;
1542 }
1543
1544 // Load data into core, block by block.
1545 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1546 for block in 0..num_full_blocks {
1547 let index = block * C::BLOCK_SIZE;
1548 // Read block out
1549 let read = Self::read_bytes(
1550 &mut self.outdma,
1551 C::BLOCK_SIZE,
1552 &mut output[index..index + C::BLOCK_SIZE],
1553 );
1554 // Write block in
1555 let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]);
1556 embassy_futures::join::join(read, write).await;
1557 }
1558
1559 // Handle the final block, which is incomplete.
1560 if last_block_remainder > 0 {
1561 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1562 let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len);
1563
1564 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1565 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1566 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1567 let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data);
1568 let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block);
1569 embassy_futures::join::join(read, write).await;
1176 1570
1177 // Handle the last block depending on mode. 1571 // Handle the last block depending on mode.
1178 let output_len = output.len(); 1572 let output_len = output.len();
@@ -1182,7 +1576,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
1182 let mut mask: [u8; 16] = [0; 16]; 1576 let mut mask: [u8; 16] = [0; 16];
1183 mask[..last_block_remainder].fill(0xFF); 1577 mask[..last_block_remainder].fill(0xFF);
1184 ctx.cipher 1578 ctx.cipher
1185 .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); 1579 .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
1580 .await;
1186 } 1581 }
1187 1582
1188 ctx.payload_len += input.len() as u64; 1583 ctx.payload_len += input.len() as u64;
@@ -1191,8 +1586,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
1191 } 1586 }
1192 1587
1193 #[cfg(any(cryp_v2, cryp_v3))] 1588 #[cfg(any(cryp_v2, cryp_v3))]
1194 /// This function only needs to be called for GCM, CCM, and GMAC modes to 1589 /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC.
1195 /// generate an authentication tag. 1590 /// Called after the all data has been encrypted/decrypted by `payload`.
1196 pub fn finish_blocking< 1591 pub fn finish_blocking<
1197 'c, 1592 'c,
1198 const TAG_SIZE: usize, 1593 const TAG_SIZE: usize,
@@ -1213,28 +1608,72 @@ impl<'d, T: Instance> Cryp<'d, T> {
1213 let payloadlen2: u32 = (ctx.payload_len * 8) as u32; 1608 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1214 1609
1215 #[cfg(cryp_v2)] 1610 #[cfg(cryp_v2)]
1216 { 1611 let footer: [u32; 4] = [
1217 T::regs().din().write_value(headerlen1.swap_bytes()); 1612 headerlen1.swap_bytes(),
1218 T::regs().din().write_value(headerlen2.swap_bytes()); 1613 headerlen2.swap_bytes(),
1219 T::regs().din().write_value(payloadlen1.swap_bytes()); 1614 payloadlen1.swap_bytes(),
1220 T::regs().din().write_value(payloadlen2.swap_bytes()); 1615 payloadlen2.swap_bytes(),
1221 } 1616 ];
1222
1223 #[cfg(cryp_v3)] 1617 #[cfg(cryp_v3)]
1224 { 1618 let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2];
1225 T::regs().din().write_value(headerlen1); 1619
1226 T::regs().din().write_value(headerlen2); 1620 self.write_words_blocking(C::BLOCK_SIZE, &footer);
1227 T::regs().din().write_value(payloadlen1);
1228 T::regs().din().write_value(payloadlen2);
1229 }
1230 1621
1231 while !T::regs().sr().read().ofne() {} 1622 while !T::regs().sr().read().ofne() {}
1232 1623
1233 let mut full_tag: [u8; 16] = [0; 16]; 1624 let mut full_tag: [u8; 16] = [0; 16];
1234 full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); 1625 self.read_bytes_blocking(C::BLOCK_SIZE, &mut full_tag);
1235 full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); 1626 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1236 full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); 1627 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1237 full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); 1628
1629 T::regs().cr().modify(|w| w.set_crypen(false));
1630
1631 tag
1632 }
1633
1634 #[cfg(any(cryp_v2, cryp_v3))]
1635 // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC.
1636 /// Called after the all data has been encrypted/decrypted by `payload`.
1637 pub async fn finish<
1638 'c,
1639 const TAG_SIZE: usize,
1640 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1641 >(
1642 &mut self,
1643 mut ctx: Context<'c, C>,
1644 ) -> [u8; TAG_SIZE]
1645 where
1646 DmaIn: crate::cryp::DmaIn<T>,
1647 DmaOut: crate::cryp::DmaOut<T>,
1648 {
1649 self.load_context(&mut ctx);
1650
1651 T::regs().cr().modify(|w| w.set_crypen(false));
1652 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
1653 T::regs().cr().modify(|w| w.set_crypen(true));
1654
1655 let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
1656 let headerlen2: u32 = (ctx.header_len * 8) as u32;
1657 let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
1658 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1659
1660 #[cfg(cryp_v2)]
1661 let footer: [u32; 4] = [
1662 headerlen1.swap_bytes(),
1663 headerlen2.swap_bytes(),
1664 payloadlen1.swap_bytes(),
1665 payloadlen2.swap_bytes(),
1666 ];
1667 #[cfg(cryp_v3)]
1668 let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2];
1669
1670 let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer);
1671
1672 let mut full_tag: [u8; 16] = [0; 16];
1673 let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag);
1674
1675 embassy_futures::join::join(read, write).await;
1676
1238 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; 1677 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1239 tag.copy_from_slice(&full_tag[0..TAG_SIZE]); 1678 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1240 1679
@@ -1325,18 +1764,134 @@ impl<'d, T: Instance> Cryp<'d, T> {
1325 // Enable crypto processor. 1764 // Enable crypto processor.
1326 T::regs().cr().modify(|w| w.set_crypen(true)); 1765 T::regs().cr().modify(|w| w.set_crypen(true));
1327 } 1766 }
1328}
1329 1767
1330pub(crate) mod sealed { 1768 fn write_bytes_blocking(&self, block_size: usize, blocks: &[u8]) {
1331 use super::*; 1769 // Ensure input is a multiple of block size.
1770 assert_eq!(blocks.len() % block_size, 0);
1771 let mut index = 0;
1772 let end_index = blocks.len();
1773 while index < end_index {
1774 let mut in_word: [u8; 4] = [0; 4];
1775 in_word.copy_from_slice(&blocks[index..index + 4]);
1776 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1777 index += 4;
1778 if index % block_size == 0 {
1779 // Block until input FIFO is empty.
1780 while !T::regs().sr().read().ifem() {}
1781 }
1782 }
1783 }
1332 1784
1333 pub trait Instance { 1785 async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8])
1334 fn regs() -> pac::cryp::Cryp; 1786 where
1787 DmaIn: crate::cryp::DmaIn<T>,
1788 {
1789 if blocks.len() == 0 {
1790 return;
1791 }
1792 // Ensure input is a multiple of block size.
1793 assert_eq!(blocks.len() % block_size, 0);
1794 // Configure DMA to transfer input to crypto core.
1795 let dma_request = dma.request();
1796 let dst_ptr = T::regs().din().as_ptr();
1797 let num_words = blocks.len() / 4;
1798 let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
1799 let options = TransferOptions {
1800 priority: Priority::High,
1801 ..Default::default()
1802 };
1803 let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) };
1804 T::regs().dmacr().modify(|w| w.set_dien(true));
1805 // Wait for the transfer to complete.
1806 dma_transfer.await;
1807 }
1808
1809 #[cfg(any(cryp_v2, cryp_v3))]
1810 fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) {
1811 assert_eq!((blocks.len() * 4) % block_size, 0);
1812 let mut byte_counter: usize = 0;
1813 for word in blocks {
1814 T::regs().din().write_value(*word);
1815 byte_counter += 4;
1816 if byte_counter % block_size == 0 {
1817 // Block until input FIFO is empty.
1818 while !T::regs().sr().read().ifem() {}
1819 }
1820 }
1821 }
1822
1823 #[cfg(any(cryp_v2, cryp_v3))]
1824 async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32])
1825 where
1826 DmaIn: crate::cryp::DmaIn<T>,
1827 {
1828 if blocks.len() == 0 {
1829 return;
1830 }
1831 // Ensure input is a multiple of block size.
1832 assert_eq!((blocks.len() * 4) % block_size, 0);
1833 // Configure DMA to transfer input to crypto core.
1834 let dma_request = dma.request();
1835 let dst_ptr = T::regs().din().as_ptr();
1836 let num_words = blocks.len();
1837 let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
1838 let options = TransferOptions {
1839 priority: Priority::High,
1840 ..Default::default()
1841 };
1842 let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) };
1843 T::regs().dmacr().modify(|w| w.set_dien(true));
1844 // Wait for the transfer to complete.
1845 dma_transfer.await;
1846 }
1847
1848 fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) {
1849 // Block until there is output to read.
1850 while !T::regs().sr().read().ofne() {}
1851 // Ensure input is a multiple of block size.
1852 assert_eq!(blocks.len() % block_size, 0);
1853 // Read block out
1854 let mut index = 0;
1855 let end_index = blocks.len();
1856 while index < end_index {
1857 let out_word: u32 = T::regs().dout().read();
1858 blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1859 index += 4;
1860 }
1861 }
1862
1863 async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8])
1864 where
1865 DmaOut: crate::cryp::DmaOut<T>,
1866 {
1867 if blocks.len() == 0 {
1868 return;
1869 }
1870 // Ensure input is a multiple of block size.
1871 assert_eq!(blocks.len() % block_size, 0);
1872 // Configure DMA to get output from crypto core.
1873 let dma_request = dma.request();
1874 let src_ptr = T::regs().dout().as_ptr();
1875 let num_words = blocks.len() / 4;
1876 let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words);
1877 let options = TransferOptions {
1878 priority: Priority::VeryHigh,
1879 ..Default::default()
1880 };
1881 let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) };
1882 T::regs().dmacr().modify(|w| w.set_doen(true));
1883 // Wait for the transfer to complete.
1884 dma_transfer.await;
1335 } 1885 }
1336} 1886}
1337 1887
1888trait SealedInstance {
1889 fn regs() -> pac::cryp::Cryp;
1890}
1891
1338/// CRYP instance trait. 1892/// CRYP instance trait.
1339pub 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 {
1340 /// Interrupt for this CRYP instance. 1895 /// Interrupt for this CRYP instance.
1341 type Interrupt: interrupt::typelevel::Interrupt; 1896 type Interrupt: interrupt::typelevel::Interrupt;
1342} 1897}
@@ -1347,10 +1902,13 @@ foreach_interrupt!(
1347 type Interrupt = crate::interrupt::typelevel::$irq; 1902 type Interrupt = crate::interrupt::typelevel::$irq;
1348 } 1903 }
1349 1904
1350 impl sealed::Instance for peripherals::$inst { 1905 impl SealedInstance for peripherals::$inst {
1351 fn regs() -> crate::pac::cryp::Cryp { 1906 fn regs() -> crate::pac::cryp::Cryp {
1352 crate::pac::$inst 1907 crate::pac::$inst
1353 } 1908 }
1354 } 1909 }
1355 }; 1910 };
1356); 1911);
1912
1913dma_trait!(DmaIn, Instance);
1914dma_trait!(DmaOut, Instance);
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 60f9404c2..acfed8356 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -127,7 +127,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
127 pub fn new( 127 pub fn new(
128 _peri: impl Peripheral<P = T> + 'd, 128 _peri: impl Peripheral<P = T> + 'd,
129 dma: impl Peripheral<P = DMA> + 'd, 129 dma: impl Peripheral<P = DMA> + 'd,
130 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::sealed::Pin> + 'd, 130 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd,
131 ) -> Self { 131 ) -> Self {
132 into_ref!(dma, pin); 132 into_ref!(dma, pin);
133 pin.set_as_analog(); 133 pin.set_as_analog();
@@ -392,8 +392,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
392 _peri: impl Peripheral<P = T> + 'd, 392 _peri: impl Peripheral<P = T> + 'd,
393 dma_ch1: impl Peripheral<P = DMACh1> + 'd, 393 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
394 dma_ch2: impl Peripheral<P = DMACh2> + 'd, 394 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
395 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::sealed::Pin> + 'd, 395 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd,
396 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::sealed::Pin> + 'd, 396 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd,
397 ) -> Self { 397 ) -> Self {
398 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); 398 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
399 pin_ch1.set_as_analog(); 399 pin_ch1.set_as_analog();
@@ -488,14 +488,13 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
488 } 488 }
489} 489}
490 490
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 08aba2795..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};
@@ -10,8 +10,7 @@ use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDm
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::interrupt::Priority; 13use crate::{interrupt, pac};
14use crate::pac;
15 14
16pub(crate) struct ChannelInfo { 15pub(crate) struct ChannelInfo {
17 pub(crate) dma: DmaInfo, 16 pub(crate) dma: DmaInfo,
@@ -45,6 +44,8 @@ pub struct TransferOptions {
45 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. 44 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
46 #[cfg(dma)] 45 #[cfg(dma)]
47 pub fifo_threshold: Option<FifoThreshold>, 46 pub fifo_threshold: Option<FifoThreshold>,
47 /// Request priority level
48 pub priority: Priority,
48 /// Enable circular DMA 49 /// Enable circular DMA
49 /// 50 ///
50 /// Note: 51 /// Note:
@@ -68,6 +69,7 @@ impl Default for TransferOptions {
68 flow_ctrl: FlowControl::Dma, 69 flow_ctrl: FlowControl::Dma,
69 #[cfg(dma)] 70 #[cfg(dma)]
70 fifo_threshold: None, 71 fifo_threshold: None,
72 priority: Priority::VeryHigh,
71 circular: false, 73 circular: false,
72 half_transfer_ir: false, 74 half_transfer_ir: false,
73 complete_transfer_ir: true, 75 complete_transfer_ir: true,
@@ -75,6 +77,44 @@ impl Default for TransferOptions {
75 } 77 }
76} 78}
77 79
80/// DMA request priority
81#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Priority {
84 /// Low Priority
85 Low,
86 /// Medium Priority
87 Medium,
88 /// High Priority
89 High,
90 /// Very High Priority
91 VeryHigh,
92}
93
94#[cfg(dma)]
95impl From<Priority> for pac::dma::vals::Pl {
96 fn from(value: Priority) -> Self {
97 match value {
98 Priority::Low => pac::dma::vals::Pl::LOW,
99 Priority::Medium => pac::dma::vals::Pl::MEDIUM,
100 Priority::High => pac::dma::vals::Pl::HIGH,
101 Priority::VeryHigh => pac::dma::vals::Pl::VERYHIGH,
102 }
103 }
104}
105
106#[cfg(bdma)]
107impl From<Priority> for pac::bdma::vals::Pl {
108 fn from(value: Priority) -> Self {
109 match value {
110 Priority::Low => pac::bdma::vals::Pl::LOW,
111 Priority::Medium => pac::bdma::vals::Pl::MEDIUM,
112 Priority::High => pac::bdma::vals::Pl::HIGH,
113 Priority::VeryHigh => pac::bdma::vals::Pl::VERYHIGH,
114 }
115 }
116}
117
78#[cfg(dma)] 118#[cfg(dma)]
79pub use dma_only::*; 119pub use dma_only::*;
80#[cfg(dma)] 120#[cfg(dma)]
@@ -213,8 +253,8 @@ impl ChannelState {
213/// safety: must be called only once 253/// safety: must be called only once
214pub(crate) unsafe fn init( 254pub(crate) unsafe fn init(
215 cs: critical_section::CriticalSection, 255 cs: critical_section::CriticalSection,
216 #[cfg(dma)] dma_priority: Priority, 256 #[cfg(dma)] dma_priority: interrupt::Priority,
217 #[cfg(bdma)] bdma_priority: Priority, 257 #[cfg(bdma)] bdma_priority: interrupt::Priority,
218) { 258) {
219 foreach_interrupt! { 259 foreach_interrupt! {
220 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 260 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
@@ -334,7 +374,7 @@ impl AnyChannel {
334 w.set_dir(dir.into()); 374 w.set_dir(dir.into());
335 w.set_msize(data_size.into()); 375 w.set_msize(data_size.into());
336 w.set_psize(data_size.into()); 376 w.set_psize(data_size.into());
337 w.set_pl(pac::dma::vals::Pl::VERYHIGH); 377 w.set_pl(options.priority.into());
338 w.set_minc(incr_mem); 378 w.set_minc(incr_mem);
339 w.set_pinc(false); 379 w.set_pinc(false);
340 w.set_teie(true); 380 w.set_teie(true);
@@ -374,7 +414,7 @@ impl AnyChannel {
374 w.set_tcie(options.complete_transfer_ir); 414 w.set_tcie(options.complete_transfer_ir);
375 w.set_htie(options.half_transfer_ir); 415 w.set_htie(options.half_transfer_ir);
376 w.set_circ(options.circular); 416 w.set_circ(options.circular);
377 w.set_pl(pac::bdma::vals::Pl::VERYHIGH); 417 w.set_pl(options.priority.into());
378 w.set_en(false); // don't start yet 418 w.set_en(false); // don't start yet
379 }); 419 });
380 } 420 }
@@ -470,6 +510,31 @@ impl AnyChannel {
470 DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(), 510 DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(),
471 } 511 }
472 } 512 }
513
514 fn disable_circular_mode(&self) {
515 let info = self.info();
516 match self.info().dma {
517 #[cfg(dma)]
518 DmaInfo::Dma(regs) => regs.st(info.num).cr().modify(|w| {
519 w.set_circ(false);
520 }),
521 #[cfg(bdma)]
522 DmaInfo::Bdma(regs) => regs.ch(info.num).cr().modify(|w| {
523 w.set_circ(false);
524 }),
525 }
526 }
527
528 fn poll_stop(&self) -> Poll<()> {
529 use core::sync::atomic::compiler_fence;
530 compiler_fence(Ordering::SeqCst);
531
532 if !self.is_running() {
533 Poll::Ready(())
534 } else {
535 Poll::Pending
536 }
537 }
473} 538}
474 539
475/// DMA transfer. 540/// DMA transfer.
@@ -789,6 +854,25 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
789 pub fn is_running(&mut self) -> bool { 854 pub fn is_running(&mut self) -> bool {
790 self.channel.is_running() 855 self.channel.is_running()
791 } 856 }
857
858 /// Stop the DMA transfer and await until the buffer is full.
859 ///
860 /// This disables the DMA transfer's circular mode so that the transfer
861 /// stops when the buffer is full.
862 ///
863 /// This is designed to be used with streaming input data such as the
864 /// I2S/SAI or ADC.
865 ///
866 /// When using the UART, you probably want `request_stop()`.
867 pub async fn stop(&mut self) {
868 self.channel.disable_circular_mode();
869 //wait until cr.susp reads as true
870 poll_fn(|cx| {
871 self.set_waker(cx.waker());
872 self.channel.poll_stop()
873 })
874 .await
875 }
792} 876}
793 877
794impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { 878impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
@@ -900,6 +984,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
900 pub fn is_running(&mut self) -> bool { 984 pub fn is_running(&mut self) -> bool {
901 self.channel.is_running() 985 self.channel.is_running()
902 } 986 }
987
988 /// Stop the DMA transfer and await until the buffer is empty.
989 ///
990 /// This disables the DMA transfer's circular mode so that the transfer
991 /// stops when all available data has been written.
992 ///
993 /// This is designed to be used with streaming output data such as the
994 /// I2S/SAI or DAC.
995 pub async fn stop(&mut self) {
996 self.channel.disable_circular_mode();
997 //wait until cr.susp reads as true
998 poll_fn(|cx| {
999 self.set_waker(cx.waker());
1000 self.channel.poll_stop()
1001 })
1002 .await
1003 }
903} 1004}
904 1005
905impl<'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 960483f34..7e3681469 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -23,7 +23,7 @@ use core::mem;
23 23
24use embassy_hal_internal::{impl_peripheral, Peripheral}; 24use embassy_hal_internal::{impl_peripheral, Peripheral};
25 25
26use crate::interrupt::Priority; 26use crate::interrupt;
27 27
28#[derive(Debug, Copy, Clone, PartialEq, Eq)] 28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))] 29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -39,17 +39,18 @@ pub type Request = u8;
39#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] 39#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))]
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 }
@@ -131,9 +132,9 @@ pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
131// safety: must be called only once at startup 132// safety: must be called only once at startup
132pub(crate) unsafe fn init( 133pub(crate) unsafe fn init(
133 cs: critical_section::CriticalSection, 134 cs: critical_section::CriticalSection,
134 #[cfg(bdma)] bdma_priority: Priority, 135 #[cfg(bdma)] bdma_priority: interrupt::Priority,
135 #[cfg(dma)] dma_priority: Priority, 136 #[cfg(dma)] dma_priority: interrupt::Priority,
136 #[cfg(gpdma)] gpdma_priority: Priority, 137 #[cfg(gpdma)] gpdma_priority: interrupt::Priority,
137) { 138) {
138 #[cfg(any(dma, bdma))] 139 #[cfg(any(dma, bdma))]
139 dma_bdma::init( 140 dma_bdma::init(
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs
index a72c4b7d9..fb1bde860 100644
--- a/embassy-stm32/src/dma/word.rs
+++ b/embassy-stm32/src/dma/word.rs
@@ -20,14 +20,13 @@ impl WordSize {
20 } 20 }
21} 21}
22 22
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 00e3e1727..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> {
@@ -833,6 +833,18 @@ impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
833 } 833 }
834} 834}
835 835
836impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> {
837 type Error = Infallible;
838
839 fn is_high(&self) -> Result<bool, Self::Error> {
840 Ok(self.is_high())
841 }
842
843 fn is_low(&self) -> Result<bool, Self::Error> {
844 Ok(self.is_low())
845 }
846}
847
836impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { 848impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> {
837 type Error = Infallible; 849 type Error = Infallible;
838 850
@@ -1049,9 +1061,3 @@ impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
1049 Ok((*self).is_set_low()) 1061 Ok((*self).is_set_low())
1050 } 1062 }
1051} 1063}
1052
1053/// Low-level GPIO manipulation.
1054#[cfg(feature = "unstable-pac")]
1055pub mod low_level {
1056 pub use super::sealed::*;
1057}
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index b47814f8b..787d5b1c9 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -17,7 +17,7 @@ use crate::dma::NoDma;
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 2416005b5..f1b11cc44 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -14,8 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker;
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 }
@@ -311,10 +307,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
311 307
312 fn transaction( 308 fn transaction(
313 &mut self, 309 &mut self,
314 _address: u8, 310 address: u8,
315 _operations: &mut [embedded_hal_1::i2c::Operation<'_>], 311 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
316 ) -> Result<(), Self::Error> { 312 ) -> Result<(), Self::Error> {
317 todo!(); 313 self.blocking_transaction(address, operations)
318 } 314 }
319} 315}
320 316
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index cbbc201de..9f29ed5e0 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -10,11 +10,11 @@ use core::task::Poll;
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation;
13 14
14use super::*; 15use super::*;
15use crate::dma::Transfer; 16use crate::dma::Transfer;
16use crate::pac::i2c; 17use crate::pac::i2c;
17use crate::time::Hertz;
18 18
19// /!\ /!\ 19// /!\ /!\
20// /!\ Implementation note! /!\ 20// /!\ Implementation note! /!\
@@ -41,6 +41,68 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44/// Frame type in I2C transaction.
45///
46/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
47/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
48/// ACK or NACK after the last byte received.
49///
50/// For write operations, the following options are identical because they differ only in the (N)ACK
51/// treatment relevant for read operations:
52///
53/// - `FirstFrame` and `FirstAndNextFrame`
54/// - `NextFrame` and `LastFrameNoStop`
55///
56/// Abbreviations used below:
57///
58/// - `ST` = start condition
59/// - `SR` = repeated start condition
60/// - `SP` = stop condition
61#[derive(Copy, Clone)]
62enum FrameOptions {
63 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this
64 /// transaction.
65 FirstAndLastFrame,
66 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
67 /// not the last frame overall.
68 FirstFrame,
69 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
70 /// frame in a read operation.
71 FirstAndNextFrame,
72 /// `[ACK]` Middle frame in a read operation (neither first nor last).
73 NextFrame,
74 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
75 LastFrame,
76 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
77 LastFrameNoStop,
78}
79
80impl FrameOptions {
81 /// Sends start or repeated start condition before transfer.
82 fn send_start(self) -> bool {
83 match self {
84 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
85 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
86 }
87 }
88
89 /// Sends stop condition after transfer.
90 fn send_stop(self) -> bool {
91 match self {
92 Self::FirstAndLastFrame | Self::LastFrame => true,
93 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
94 }
95 }
96
97 /// Sends NACK after last byte received, indicating end of read operation.
98 fn send_nack(self) -> bool {
99 match self {
100 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
101 Self::FirstAndNextFrame | Self::NextFrame => false,
102 }
103 }
104}
105
44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 106impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 107 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
46 T::regs().cr1().modify(|reg| { 108 T::regs().cr1().modify(|reg| {
@@ -124,46 +186,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
124 Ok(sr1) 186 Ok(sr1)
125 } 187 }
126 188
127 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { 189 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> {
128 // Send a START condition 190 if frame.send_start() {
191 // Send a START condition
129 192
130 T::regs().cr1().modify(|reg| { 193 T::regs().cr1().modify(|reg| {
131 reg.set_start(true); 194 reg.set_start(true);
132 }); 195 });
133 196
134 // Wait until START condition was generated 197 // Wait until START condition was generated
135 while !Self::check_and_clear_error_flags()?.start() { 198 while !Self::check_and_clear_error_flags()?.start() {
136 timeout.check()?; 199 timeout.check()?;
137 } 200 }
138 201
139 // Also wait until signalled we're master and everything is waiting for us 202 // Also wait until signalled we're master and everything is waiting for us
140 while { 203 while {
141 Self::check_and_clear_error_flags()?; 204 Self::check_and_clear_error_flags()?;
142 205
143 let sr2 = T::regs().sr2().read(); 206 let sr2 = T::regs().sr2().read();
144 !sr2.msl() && !sr2.busy() 207 !sr2.msl() && !sr2.busy()
145 } { 208 } {
146 timeout.check()?; 209 timeout.check()?;
147 } 210 }
148 211
149 // Set up current address, we're trying to talk to 212 // Set up current address, we're trying to talk to
150 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 213 T::regs().dr().write(|reg| reg.set_dr(addr << 1));
151 214
152 // Wait until address was sent 215 // Wait until address was sent
153 // Wait for the address to be acknowledged 216 // Wait for the address to be acknowledged
154 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 217 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
155 while !Self::check_and_clear_error_flags()?.addr() { 218 while !Self::check_and_clear_error_flags()?.addr() {
156 timeout.check()?; 219 timeout.check()?;
157 } 220 }
158 221
159 // Clear condition by reading SR2 222 // Clear condition by reading SR2
160 let _ = T::regs().sr2().read(); 223 let _ = T::regs().sr2().read();
224 }
161 225
162 // Send bytes 226 // Send bytes
163 for c in bytes { 227 for c in bytes {
164 self.send_byte(*c, timeout)?; 228 self.send_byte(*c, timeout)?;
165 } 229 }
166 230
231 if frame.send_stop() {
232 // Send a STOP condition
233 T::regs().cr1().modify(|reg| reg.set_stop(true));
234 // Wait for STOP condition to transmit.
235 while T::regs().cr1().read().stop() {
236 timeout.check()?;
237 }
238 }
239
167 // Fallthrough is success 240 // Fallthrough is success
168 Ok(()) 241 Ok(())
169 } 242 }
@@ -205,8 +278,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
205 Ok(value) 278 Ok(value)
206 } 279 }
207 280
208 fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { 281 fn blocking_read_timeout(
209 if let Some((last, buffer)) = buffer.split_last_mut() { 282 &mut self,
283 addr: u8,
284 buffer: &mut [u8],
285 timeout: Timeout,
286 frame: FrameOptions,
287 ) -> Result<(), Error> {
288 let Some((last, buffer)) = buffer.split_last_mut() else {
289 return Err(Error::Overrun);
290 };
291
292 if frame.send_start() {
210 // Send a START condition and set ACK bit 293 // Send a START condition and set ACK bit
211 T::regs().cr1().modify(|reg| { 294 T::regs().cr1().modify(|reg| {
212 reg.set_start(true); 295 reg.set_start(true);
@@ -237,49 +320,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
237 320
238 // Clear condition by reading SR2 321 // Clear condition by reading SR2
239 let _ = T::regs().sr2().read(); 322 let _ = T::regs().sr2().read();
323 }
240 324
241 // Receive bytes into buffer 325 // Receive bytes into buffer
242 for c in buffer { 326 for c in buffer {
243 *c = self.recv_byte(timeout)?; 327 *c = self.recv_byte(timeout)?;
244 } 328 }
245 329
246 // Prepare to send NACK then STOP after next byte 330 // Prepare to send NACK then STOP after next byte
247 T::regs().cr1().modify(|reg| { 331 T::regs().cr1().modify(|reg| {
332 if frame.send_nack() {
248 reg.set_ack(false); 333 reg.set_ack(false);
334 }
335 if frame.send_stop() {
249 reg.set_stop(true); 336 reg.set_stop(true);
250 }); 337 }
338 });
251 339
252 // Receive last byte 340 // Receive last byte
253 *last = self.recv_byte(timeout)?; 341 *last = self.recv_byte(timeout)?;
254 342
343 if frame.send_stop() {
255 // Wait for the STOP to be sent. 344 // Wait for the STOP to be sent.
256 while T::regs().cr1().read().stop() { 345 while T::regs().cr1().read().stop() {
257 timeout.check()?; 346 timeout.check()?;
258 } 347 }
259
260 // Fallthrough is success
261 Ok(())
262 } else {
263 Err(Error::Overrun)
264 } 348 }
349
350 // Fallthrough is success
351 Ok(())
265 } 352 }
266 353
267 /// Blocking read. 354 /// Blocking read.
268 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 355 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
269 self.blocking_read_timeout(addr, read, self.timeout()) 356 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame)
270 } 357 }
271 358
272 /// Blocking write. 359 /// Blocking write.
273 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 360 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
274 let timeout = self.timeout(); 361 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?;
275
276 self.write_bytes(addr, write, timeout)?;
277 // Send a STOP condition
278 T::regs().cr1().modify(|reg| reg.set_stop(true));
279 // Wait for STOP condition to transmit.
280 while T::regs().cr1().read().stop() {
281 timeout.check()?;
282 }
283 362
284 // Fallthrough is success 363 // Fallthrough is success
285 Ok(()) 364 Ok(())
@@ -287,10 +366,85 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
287 366
288 /// Blocking write, restart, read. 367 /// Blocking write, restart, read.
289 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 368 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
369 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
370 // stop condition below.
371 if read.is_empty() {
372 return Err(Error::Overrun);
373 }
374
290 let timeout = self.timeout(); 375 let timeout = self.timeout();
291 376
292 self.write_bytes(addr, write, timeout)?; 377 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?;
293 self.blocking_read_timeout(addr, read, timeout)?; 378 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?;
379
380 Ok(())
381 }
382
383 /// Blocking transaction with operations.
384 ///
385 /// Consecutive operations of same type are merged. See [transaction contract] for details.
386 ///
387 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
388 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
389 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
390 // stop condition below.
391 if operations.iter().any(|op| match op {
392 Operation::Read(read) => read.is_empty(),
393 Operation::Write(_) => false,
394 }) {
395 return Err(Error::Overrun);
396 }
397
398 let timeout = self.timeout();
399
400 let mut operations = operations.iter_mut();
401
402 let mut prev_op: Option<&mut Operation<'_>> = None;
403 let mut next_op = operations.next();
404
405 while let Some(op) = next_op {
406 next_op = operations.next();
407
408 // Check if this is the first frame of this type. This is the case for the first overall
409 // frame in the transaction and whenever the type of operation changes.
410 let first_frame =
411 match (prev_op.as_ref(), &op) {
412 (None, _) => true,
413 (Some(Operation::Read(_)), Operation::Write(_))
414 | (Some(Operation::Write(_)), Operation::Read(_)) => true,
415 (Some(Operation::Read(_)), Operation::Read(_))
416 | (Some(Operation::Write(_)), Operation::Write(_)) => false,
417 };
418
419 let frame = match (first_frame, next_op.as_ref()) {
420 // If this is the first frame of this type, we generate a (repeated) start condition
421 // but have to consider the next operation: if it is the last, we generate the final
422 // stop condition. Otherwise, we branch on the operation: with read operations, only
423 // the last byte overall (before a write operation or the end of the transaction) is
424 // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte.
425 (true, None) => FrameOptions::FirstAndLastFrame,
426 // Make sure to keep sending ACK for last byte in read operation when it is followed
427 // by another consecutive read operation. If the current operation is write, this is
428 // identical to `FirstFrame`.
429 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
430 // Otherwise, send NACK for last byte (in read operation). (For write, this does not
431 // matter and could also be `FirstAndNextFrame`.)
432 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
433
434 // If this is not the first frame of its type, we do not generate a (repeated) start
435 // condition. Otherwise, we branch the same way as above.
436 (false, None) => FrameOptions::LastFrame,
437 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
438 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
439 };
440
441 match op {
442 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?,
443 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?,
444 }
445
446 prev_op = Some(op);
447 }
294 448
295 Ok(()) 449 Ok(())
296 } 450 }
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index bd3abaac1..8baf2849d 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -4,11 +4,11 @@ use core::task::Poll;
4 4
5use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7use embedded_hal_1::i2c::Operation;
7 8
8use super::*; 9use super::*;
9use crate::dma::Transfer; 10use crate::dma::Transfer;
10use crate::pac::i2c; 11use crate::pac::i2c;
11use crate::time::Hertz;
12 12
13pub(crate) unsafe fn on_interrupt<T: Instance>() { 13pub(crate) unsafe fn on_interrupt<T: Instance>() {
14 let regs = T::regs(); 14 let regs = T::regs();
@@ -579,6 +579,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
579 // Automatic Stop 579 // Automatic Stop
580 } 580 }
581 581
582 /// Blocking transaction with operations.
583 ///
584 /// Consecutive operations of same type are merged. See [transaction contract] for details.
585 ///
586 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
587 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
588 let _ = addr;
589 let _ = operations;
590 todo!()
591 }
592
582 /// Blocking write multiple buffers. 593 /// Blocking write multiple buffers.
583 /// 594 ///
584 /// The buffers are concatenated in a single write transaction. 595 /// The buffers are concatenated in a single write transaction.
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index fa9ec0532..c5a606b21 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -1,8 +1,7 @@
1//! Inter-IC Sound (I2S) 1//! Inter-IC Sound (I2S)
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 aba53ad80..8f510047f 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -75,14 +75,14 @@ pub mod sai;
75pub mod sdmmc; 75pub mod sdmmc;
76#[cfg(spi)] 76#[cfg(spi)]
77pub mod spi; 77pub mod spi;
78#[cfg(ucpd)]
79pub mod ucpd;
78#[cfg(uid)] 80#[cfg(uid)]
79pub mod uid; 81pub mod uid;
80#[cfg(usart)] 82#[cfg(usart)]
81pub mod usart; 83pub mod usart;
82#[cfg(usb)] 84#[cfg(any(usb, otg))]
83pub mod usb; 85pub mod usb;
84#[cfg(otg)]
85pub mod usb_otg;
86#[cfg(iwdg)] 86#[cfg(iwdg)]
87pub mod wdg; 87pub mod wdg;
88 88
@@ -107,10 +107,10 @@ pub use crate::_generated::interrupt;
107/// Example of how to bind one interrupt: 107/// Example of how to bind one interrupt:
108/// 108///
109/// ```rust,ignore 109/// ```rust,ignore
110/// use embassy_stm32::{bind_interrupts, usb_otg, peripherals}; 110/// use embassy_stm32::{bind_interrupts, usb, peripherals};
111/// 111///
112/// bind_interrupts!(struct Irqs { 112/// bind_interrupts!(struct Irqs {
113/// OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 113/// OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
114/// }); 114/// });
115/// ``` 115/// ```
116/// 116///
@@ -160,7 +160,7 @@ pub(crate) use stm32_metapac as pac;
160use crate::interrupt::Priority; 160use crate::interrupt::Priority;
161#[cfg(feature = "rt")] 161#[cfg(feature = "rt")]
162pub use crate::pac::NVIC_PRIO_BITS; 162pub use crate::pac::NVIC_PRIO_BITS;
163use crate::rcc::sealed::RccPeripheral; 163use crate::rcc::SealedRccPeripheral;
164 164
165/// `embassy-stm32` global configuration. 165/// `embassy-stm32` global configuration.
166#[non_exhaustive] 166#[non_exhaustive]
@@ -174,6 +174,14 @@ pub struct Config {
174 #[cfg(dbgmcu)] 174 #[cfg(dbgmcu)]
175 pub enable_debug_during_sleep: bool, 175 pub enable_debug_during_sleep: bool,
176 176
177 /// On low-power boards (eg. `stm32l4`, `stm32l5` and `stm32u5`),
178 /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`),
179 /// which needs to be enabled before these pins can be used.
180 ///
181 /// May increase power consumption. Defaults to true.
182 #[cfg(any(stm32l4, stm32l5, stm32u5))]
183 pub enable_independent_io_supply: bool,
184
177 /// BDMA interrupt priority. 185 /// BDMA interrupt priority.
178 /// 186 ///
179 /// Defaults to P0 (highest). 187 /// Defaults to P0 (highest).
@@ -191,6 +199,18 @@ pub struct Config {
191 /// Defaults to P0 (highest). 199 /// Defaults to P0 (highest).
192 #[cfg(gpdma)] 200 #[cfg(gpdma)]
193 pub gpdma_interrupt_priority: Priority, 201 pub gpdma_interrupt_priority: Priority,
202
203 /// Enables UCPD1 dead battery functionality.
204 ///
205 /// Defaults to false (disabled).
206 #[cfg(peri_ucpd1)]
207 pub enable_ucpd1_dead_battery: bool,
208
209 /// Enables UCPD2 dead battery functionality.
210 ///
211 /// Defaults to false (disabled).
212 #[cfg(peri_ucpd2)]
213 pub enable_ucpd2_dead_battery: bool,
194} 214}
195 215
196impl Default for Config { 216impl Default for Config {
@@ -199,12 +219,18 @@ impl Default for Config {
199 rcc: Default::default(), 219 rcc: Default::default(),
200 #[cfg(dbgmcu)] 220 #[cfg(dbgmcu)]
201 enable_debug_during_sleep: true, 221 enable_debug_during_sleep: true,
222 #[cfg(any(stm32l4, stm32l5, stm32u5))]
223 enable_independent_io_supply: true,
202 #[cfg(bdma)] 224 #[cfg(bdma)]
203 bdma_interrupt_priority: Priority::P0, 225 bdma_interrupt_priority: Priority::P0,
204 #[cfg(dma)] 226 #[cfg(dma)]
205 dma_interrupt_priority: Priority::P0, 227 dma_interrupt_priority: Priority::P0,
206 #[cfg(gpdma)] 228 #[cfg(gpdma)]
207 gpdma_interrupt_priority: Priority::P0, 229 gpdma_interrupt_priority: Priority::P0,
230 #[cfg(peri_ucpd1)]
231 enable_ucpd1_dead_battery: false,
232 #[cfg(peri_ucpd2)]
233 enable_ucpd2_dead_battery: false,
208 } 234 }
209 } 235 }
210} 236}
@@ -256,7 +282,44 @@ pub fn init(config: Config) -> Peripherals {
256 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] 282 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
257 peripherals::FLASH::enable_and_reset_with_cs(cs); 283 peripherals::FLASH::enable_and_reset_with_cs(cs);
258 284
285 // Enable the VDDIO2 power supply on chips that have it.
286 // Note that this requires the PWR peripheral to be enabled first.
287 #[cfg(any(stm32l4, stm32l5))]
288 {
289 crate::pac::PWR.cr2().modify(|w| {
290 // The official documentation states that we should ideally enable VDDIO2
291 // through the PVME2 bit, but it looks like this isn't required,
292 // and CubeMX itself skips this step.
293 w.set_iosv(config.enable_independent_io_supply);
294 });
295 }
296 #[cfg(stm32u5)]
297 {
298 crate::pac::PWR.svmcr().modify(|w| {
299 w.set_io2sv(config.enable_independent_io_supply);
300 });
301 }
302
303 // dead battery functionality is still present on these
304 // chips despite them not having UCPD- disable it
305 #[cfg(any(stm32g070, stm32g0b0))]
306 {
307 crate::pac::SYSCFG.cfgr1().modify(|w| {
308 w.set_ucpd1_strobe(true);
309 w.set_ucpd2_strobe(true);
310 });
311 }
312
259 unsafe { 313 unsafe {
314 #[cfg(ucpd)]
315 ucpd::init(
316 cs,
317 #[cfg(peri_ucpd1)]
318 config.enable_ucpd1_dead_battery,
319 #[cfg(peri_ucpd2)]
320 config.enable_ucpd2_dead_battery,
321 );
322
260 #[cfg(feature = "_split-pins-enabled")] 323 #[cfg(feature = "_split-pins-enabled")]
261 crate::pac::SYSCFG.pmcr().modify(|pmcr| { 324 crate::pac::SYSCFG.pmcr().modify(|pmcr| {
262 #[cfg(feature = "split-pa0")] 325 #[cfg(feature = "split-pa0")]
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index cf531e266..a3b4352c0 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -81,8 +81,8 @@ impl<'d, T: Instance> OpAmp<'d, T> {
81 /// [`OpAmpOutput`] is dropped. 81 /// [`OpAmpOutput`] is dropped.
82 pub fn buffer_ext( 82 pub fn buffer_ext(
83 &'d mut self, 83 &'d mut self,
84 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, 84 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
85 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::sealed::Pin> + 'd, 85 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd,
86 gain: OpAmpGain, 86 gain: OpAmpGain,
87 ) -> OpAmpOutput<'d, T> { 87 ) -> OpAmpOutput<'d, T> {
88 into_ref!(in_pin); 88 into_ref!(in_pin);
@@ -122,7 +122,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
122 #[cfg(opamp_g4)] 122 #[cfg(opamp_g4)]
123 pub fn buffer_int( 123 pub fn buffer_int(
124 &'d mut self, 124 &'d mut self,
125 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, 125 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
126 gain: OpAmpGain, 126 gain: OpAmpGain,
127 ) -> OpAmpInternalOutput<'d, T> { 127 ) -> OpAmpInternalOutput<'d, T> {
128 into_ref!(pin); 128 into_ref!(pin);
@@ -166,37 +166,39 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
166 } 166 }
167} 167}
168 168
169/// Opamp instance trait. 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/h.rs b/embassy-stm32/src/rcc/h.rs
index bab8bb19e..1949fc891 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -455,7 +455,14 @@ pub(crate) unsafe fn init(config: Config) {
455 }; 455 };
456 #[cfg(pwr_h7rm0468)] 456 #[cfg(pwr_h7rm0468)]
457 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { 457 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
458 VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)), 458 VoltageScale::Scale0 => {
459 let d1cpre_clk_max = if pac::SYSCFG.ur18().read().cpu_freq_boost() {
460 550_000_000
461 } else {
462 520_000_000
463 };
464 (Hertz(d1cpre_clk_max), Hertz(275_000_000), Hertz(137_500_000))
465 }
459 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), 466 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
460 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), 467 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
461 VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), 468 VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)),
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index 19a8c8cb9..6f0d7b379 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -2,7 +2,7 @@
2 2
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 02f96f8a9..54dd81524 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -6,12 +6,10 @@ use core::marker::PhantomData;
6 6
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};
@@ -386,6 +384,7 @@ impl OutputDrive {
386/// Master clock divider. 384/// Master clock divider.
387#[derive(Copy, Clone, PartialEq)] 385#[derive(Copy, Clone, PartialEq)]
388#[allow(missing_docs)] 386#[allow(missing_docs)]
387#[cfg(any(sai_v1, sai_v2))]
389pub enum MasterClockDivider { 388pub enum MasterClockDivider {
390 MasterClockDisabled, 389 MasterClockDisabled,
391 Div1, 390 Div1,
@@ -406,8 +405,79 @@ pub enum MasterClockDivider {
406 Div30, 405 Div30,
407} 406}
408 407
408/// Master clock divider.
409#[derive(Copy, Clone, PartialEq)]
410#[allow(missing_docs)]
411#[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
412pub enum MasterClockDivider {
413 MasterClockDisabled,
414 Div1,
415 Div2,
416 Div3,
417 Div4,
418 Div5,
419 Div6,
420 Div7,
421 Div8,
422 Div9,
423 Div10,
424 Div11,
425 Div12,
426 Div13,
427 Div14,
428 Div15,
429 Div16,
430 Div17,
431 Div18,
432 Div19,
433 Div20,
434 Div21,
435 Div22,
436 Div23,
437 Div24,
438 Div25,
439 Div26,
440 Div27,
441 Div28,
442 Div29,
443 Div30,
444 Div31,
445 Div32,
446 Div33,
447 Div34,
448 Div35,
449 Div36,
450 Div37,
451 Div38,
452 Div39,
453 Div40,
454 Div41,
455 Div42,
456 Div43,
457 Div44,
458 Div45,
459 Div46,
460 Div47,
461 Div48,
462 Div49,
463 Div50,
464 Div51,
465 Div52,
466 Div53,
467 Div54,
468 Div55,
469 Div56,
470 Div57,
471 Div58,
472 Div59,
473 Div60,
474 Div61,
475 Div62,
476 Div63,
477}
478
409impl MasterClockDivider { 479impl MasterClockDivider {
410 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 480 #[cfg(any(sai_v1, sai_v2))]
411 const fn mckdiv(&self) -> u8 { 481 const fn mckdiv(&self) -> u8 {
412 match self { 482 match self {
413 MasterClockDivider::MasterClockDisabled => 0, 483 MasterClockDivider::MasterClockDisabled => 0,
@@ -429,6 +499,76 @@ impl MasterClockDivider {
429 MasterClockDivider::Div30 => 15, 499 MasterClockDivider::Div30 => 15,
430 } 500 }
431 } 501 }
502
503 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
504 const fn mckdiv(&self) -> u8 {
505 match self {
506 MasterClockDivider::MasterClockDisabled => 0,
507 MasterClockDivider::Div1 => 1,
508 MasterClockDivider::Div2 => 2,
509 MasterClockDivider::Div3 => 3,
510 MasterClockDivider::Div4 => 4,
511 MasterClockDivider::Div5 => 5,
512 MasterClockDivider::Div6 => 6,
513 MasterClockDivider::Div7 => 7,
514 MasterClockDivider::Div8 => 8,
515 MasterClockDivider::Div9 => 9,
516 MasterClockDivider::Div10 => 10,
517 MasterClockDivider::Div11 => 11,
518 MasterClockDivider::Div12 => 12,
519 MasterClockDivider::Div13 => 13,
520 MasterClockDivider::Div14 => 14,
521 MasterClockDivider::Div15 => 15,
522 MasterClockDivider::Div16 => 16,
523 MasterClockDivider::Div17 => 17,
524 MasterClockDivider::Div18 => 18,
525 MasterClockDivider::Div19 => 19,
526 MasterClockDivider::Div20 => 20,
527 MasterClockDivider::Div21 => 21,
528 MasterClockDivider::Div22 => 22,
529 MasterClockDivider::Div23 => 23,
530 MasterClockDivider::Div24 => 24,
531 MasterClockDivider::Div25 => 25,
532 MasterClockDivider::Div26 => 26,
533 MasterClockDivider::Div27 => 27,
534 MasterClockDivider::Div28 => 28,
535 MasterClockDivider::Div29 => 29,
536 MasterClockDivider::Div30 => 30,
537 MasterClockDivider::Div31 => 31,
538 MasterClockDivider::Div32 => 32,
539 MasterClockDivider::Div33 => 33,
540 MasterClockDivider::Div34 => 34,
541 MasterClockDivider::Div35 => 35,
542 MasterClockDivider::Div36 => 36,
543 MasterClockDivider::Div37 => 37,
544 MasterClockDivider::Div38 => 38,
545 MasterClockDivider::Div39 => 39,
546 MasterClockDivider::Div40 => 40,
547 MasterClockDivider::Div41 => 41,
548 MasterClockDivider::Div42 => 42,
549 MasterClockDivider::Div43 => 43,
550 MasterClockDivider::Div44 => 44,
551 MasterClockDivider::Div45 => 45,
552 MasterClockDivider::Div46 => 46,
553 MasterClockDivider::Div47 => 47,
554 MasterClockDivider::Div48 => 48,
555 MasterClockDivider::Div49 => 49,
556 MasterClockDivider::Div50 => 50,
557 MasterClockDivider::Div51 => 51,
558 MasterClockDivider::Div52 => 52,
559 MasterClockDivider::Div53 => 53,
560 MasterClockDivider::Div54 => 54,
561 MasterClockDivider::Div55 => 55,
562 MasterClockDivider::Div56 => 56,
563 MasterClockDivider::Div57 => 57,
564 MasterClockDivider::Div58 => 58,
565 MasterClockDivider::Div59 => 59,
566 MasterClockDivider::Div60 => 60,
567 MasterClockDivider::Div61 => 61,
568 MasterClockDivider::Div62 => 62,
569 MasterClockDivider::Div63 => 63,
570 }
571 }
432} 572}
433 573
434/// [`SAI`] configuration. 574/// [`SAI`] configuration.
@@ -899,43 +1039,42 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> {
899 } 1039 }
900} 1040}
901 1041
902pub(crate) mod sealed { 1042trait SealedInstance {
903 use super::*; 1043 const REGS: Regs;
904 1044}
905 pub trait Instance {
906 const REGS: Regs;
907 }
908 1045
909 #[derive(Copy, Clone)] 1046#[derive(Copy, Clone)]
910 pub enum WhichSubBlock { 1047enum WhichSubBlock {
911 A = 0, 1048 A = 0,
912 B = 1, 1049 B = 1,
913 } 1050}
914 1051
915 pub trait SubBlock { 1052trait SealedSubBlock {
916 const WHICH: WhichSubBlock; 1053 const WHICH: WhichSubBlock;
917 }
918} 1054}
919 1055
920/// Sub-block instance trait. 1056/// Sub-block instance trait.
921pub trait SubBlockInstance: sealed::SubBlock {} 1057#[allow(private_bounds)]
1058pub trait SubBlockInstance: SealedSubBlock {}
922 1059
923/// Sub-block A. 1060/// Sub-block A.
924pub enum A {} 1061pub enum A {}
925impl sealed::SubBlock for A { 1062impl SealedSubBlock for A {
926 const WHICH: WhichSubBlock = WhichSubBlock::A; 1063 const WHICH: WhichSubBlock = WhichSubBlock::A;
927} 1064}
928impl SubBlockInstance for A {} 1065impl SubBlockInstance for A {}
929 1066
930/// Sub-block B. 1067/// Sub-block B.
931pub enum B {} 1068pub enum B {}
932impl sealed::SubBlock for B { 1069impl SealedSubBlock for B {
933 const WHICH: WhichSubBlock = WhichSubBlock::B; 1070 const WHICH: WhichSubBlock = WhichSubBlock::B;
934} 1071}
935impl SubBlockInstance for B {} 1072impl SubBlockInstance for B {}
936 1073
937/// SAI instance trait. 1074/// SAI instance trait.
938pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1075#[allow(private_bounds)]
1076pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
1077
939pin_trait!(SckPin, Instance, SubBlockInstance); 1078pin_trait!(SckPin, Instance, SubBlockInstance);
940pin_trait!(FsPin, Instance, SubBlockInstance); 1079pin_trait!(FsPin, Instance, SubBlockInstance);
941pin_trait!(SdPin, Instance, SubBlockInstance); 1080pin_trait!(SdPin, Instance, SubBlockInstance);
@@ -945,7 +1084,7 @@ dma_trait!(Dma, Instance, SubBlockInstance);
945 1084
946foreach_peripheral!( 1085foreach_peripheral!(
947 (sai, $inst:ident) => { 1086 (sai, $inst:ident) => {
948 impl sealed::Instance for peripherals::$inst { 1087 impl SealedInstance for peripherals::$inst {
949 const REGS: Regs = crate::pac::$inst; 1088 const REGS: Regs = crate::pac::$inst;
950 } 1089 }
951 1090
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index bf1d2ca9b..f79a11606 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -13,8 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker;
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;
@@ -240,12 +239,14 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp
240 mburst: crate::dma::Burst::Incr4, 239 mburst: crate::dma::Burst::Incr4,
241 flow_ctrl: crate::dma::FlowControl::Peripheral, 240 flow_ctrl: crate::dma::FlowControl::Peripheral,
242 fifo_threshold: Some(crate::dma::FifoThreshold::Full), 241 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
242 priority: crate::dma::Priority::VeryHigh,
243 circular: false, 243 circular: false,
244 half_transfer_ir: false, 244 half_transfer_ir: false,
245 complete_transfer_ir: true, 245 complete_transfer_ir: true,
246}; 246};
247#[cfg(all(sdmmc_v1, not(dma)))] 247#[cfg(all(sdmmc_v1, not(dma)))]
248const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { 248const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
249 priority: crate::dma::Priority::VeryHigh,
249 circular: false, 250 circular: false,
250 half_transfer_ir: false, 251 half_transfer_ir: false,
251 complete_transfer_ir: true, 252 complete_transfer_ir: true,
@@ -1416,21 +1417,17 @@ impl Cmd {
1416 1417
1417////////////////////////////////////////////////////// 1418//////////////////////////////////////////////////////
1418 1419
1419pub(crate) mod sealed { 1420trait SealedInstance {
1420 use super::*; 1421 fn regs() -> RegBlock;
1421 1422 fn state() -> &'static AtomicWaker;
1422 pub trait Instance {
1423 type Interrupt: interrupt::typelevel::Interrupt;
1424
1425 fn regs() -> RegBlock;
1426 fn state() -> &'static AtomicWaker;
1427 }
1428
1429 pub trait Pins<T: Instance> {}
1430} 1423}
1431 1424
1432/// SDMMC instance trait. 1425/// SDMMC instance trait.
1433pub 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}
1434 1431
1435pin_trait!(CkPin, Instance); 1432pin_trait!(CkPin, Instance);
1436pin_trait!(CmdPin, Instance); 1433pin_trait!(CmdPin, Instance);
@@ -1457,9 +1454,7 @@ impl<T: Instance> SdmmcDma<T> for NoDma {}
1457 1454
1458foreach_peripheral!( 1455foreach_peripheral!(
1459 (sdmmc, $inst:ident) => { 1456 (sdmmc, $inst:ident) => {
1460 impl sealed::Instance for peripherals::$inst { 1457 impl SealedInstance for peripherals::$inst {
1461 type Interrupt = crate::interrupt::typelevel::$inst;
1462
1463 fn regs() -> RegBlock { 1458 fn regs() -> RegBlock {
1464 crate::pac::$inst 1459 crate::pac::$inst
1465 } 1460 }
@@ -1470,6 +1465,8 @@ foreach_peripheral!(
1470 } 1465 }
1471 } 1466 }
1472 1467
1473 impl Instance for peripherals::$inst {} 1468 impl Instance for peripherals::$inst {
1469 type Interrupt = crate::interrupt::typelevel::$inst;
1470 }
1474 }; 1471 };
1475); 1472);
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 172bc8112..0b38c4288 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -9,8 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
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
@@ -700,7 +699,7 @@ use vals::Mbr as Br;
700 699
701fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { 700fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
702 let val = match clocks.0 / freq.0 { 701 let val = match clocks.0 / freq.0 {
703 0 => unreachable!(), 702 0 => panic!("You are trying to reach a frequency higher than the clock"),
704 1..=2 => 0b000, 703 1..=2 => 0b000,
705 3..=5 => 0b001, 704 3..=5 => 0b001,
706 6..=11 => 0b010, 705 6..=11 => 0b010,
@@ -975,24 +974,21 @@ impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::s
975 } 974 }
976} 975}
977 976
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 8530c5229..2ba6b3f11 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,490 +1,13 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2//!
3
4//! Timer inheritance
5//!
6
7// sealed:
8//
9// Core -------------------------> 1CH -------------------------> 1CH_CMP
10// | | ^ |
11// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV
12// | | | ^ | | ^ ^
13// | | +------|--|--------------|-----------+ |
14// | +--------------------+ +--------------|-----------|---------+
15// | | | |
16// | +--------------------------------------|-----------+
17// +----------------------------------------------------+
18
19//! ```text
20//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance
21//! |
22//! +--> CaptureCompare32bitInstance
23//! ```
24//!
25//! Mapping:
26//!
27//! | trait | timer |
28//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- |
29//! | [BasicInstance] | Basic Timer |
30//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer |
31//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer |
32//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer |
33 2
34#[cfg(not(stm32l0))] 3#[cfg(not(stm32l0))]
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 /// Enable timer outputs.
443 fn enable_outputs(&self) {
444 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true));
445 }
446 }
447
448 #[cfg(not(stm32l0))]
449 /// Gneral-purpose 2 channel with one complementary 16-bit timer instance.
450 pub trait GeneralPurpose2ChannelComplementaryInstance:
451 BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance
452 {
453 /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
454 ///
455 /// Note: This works even if the timer is more capable, because registers
456 /// for the less capable timers are a subset. This allows writing a driver
457 /// for a given set of capabilities, and having it transparently work with
458 /// more capable timers.
459 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp;
460 }
461
462 #[cfg(not(stm32l0))]
463 /// Advanced control timer instance.
464 pub trait AdvancedControlInstance:
465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
466 {
467 /// Capture compare interrupt for this timer.
468 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
469
470 /// Get access to the advanced timer registers.
471 fn regs_advanced() -> crate::pac::timer::TimAdv;
472
473 /// Set complementary output polarity.
474 fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
475 Self::regs_advanced()
476 .ccer()
477 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
478 }
479
480 /// Enable/disable a complementary channel.
481 fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
482 Self::regs_advanced()
483 .ccer()
484 .modify(|w| w.set_ccne(channel.index(), enable));
485 }
486 }
487}
488 11
489/// Timer channel. 12/// Timer channel.
490#[derive(Clone, Copy)] 13#[derive(Clone, Copy)]
@@ -511,454 +34,195 @@ impl Channel {
511 } 34 }
512} 35}
513 36
514/// Input capture mode. 37/// Amount of bits of a timer.
515#[derive(Clone, Copy)] 38#[derive(Clone, Copy, PartialEq, Eq, Debug)]
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} 60}
61/// Cut-down basic timer instance.
62pub trait BasicNoCr2Instance: CoreInstance {}
63/// Basic timer instance.
64pub trait BasicInstance: BasicNoCr2Instance {}
571 65
572impl CountingMode { 66/// General-purpose 16-bit timer with 1 channel instance.
573 /// Return whether this mode is edge-aligned (up or down). 67pub trait GeneralInstance1Channel: CoreInstance {}
574 pub fn is_edge_aligned(&self) -> bool {
575 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
576 }
577 68
578 /// Return whether this mode is center-aligned. 69/// General-purpose 16-bit timer with 2 channels instance.
579 pub fn is_center_aligned(&self) -> bool { 70pub trait GeneralInstance2Channel: GeneralInstance1Channel {}
580 matches!(
581 self,
582 CountingMode::CenterAlignedDownInterrupts
583 | CountingMode::CenterAlignedUpInterrupts
584 | CountingMode::CenterAlignedBothInterrupts
585 )
586 }
587}
588 71
589impl From<CountingMode> for (vals::Cms, vals::Dir) { 72/// General-purpose 16-bit timer with 4 channels instance.
590 fn from(value: CountingMode) -> Self { 73pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel {
591 match value { 74 // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel
592 CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), 75 // Advanced timers implement this trait, but the output needs to be
593 CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), 76 // enabled explicitly.
594 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), 77 // To support general-purpose and advanced timers, this function is added
595 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), 78 // here defaulting to noop and overwritten for advanced timers.
596 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), 79 /// Enable timer outputs.
597 } 80 fn enable_outputs(&self) {}
598 }
599} 81}
600 82
601impl From<(vals::Cms, vals::Dir)> for CountingMode { 83/// General-purpose 32-bit timer with 4 channels instance.
602 fn from(value: (vals::Cms, vals::Dir)) -> Self { 84pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {}
603 match value {
604 (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
605 (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
606 (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
607 (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
608 (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
609 }
610 }
611}
612
613/// Output compare mode.
614#[derive(Clone, Copy)]
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}
657 85
658/// Timer output pin polarity. 86/// Advanced 16-bit timer with 1 channel instance.
659#[derive(Clone, Copy)] 87pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel {
660pub enum OutputPolarity { 88 /// Capture compare interrupt for this timer.
661 /// Active high (higher duty value makes the pin spend more time high). 89 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
662 ActiveHigh,
663 /// Active low (higher duty value makes the pin spend more time low).
664 ActiveLow,
665} 90}
91/// Advanced 16-bit timer with 2 channels instance.
666 92
667impl From<OutputPolarity> for bool { 93pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {}
668 fn from(mode: OutputPolarity) -> Self {
669 match mode {
670 OutputPolarity::ActiveHigh => false,
671 OutputPolarity::ActiveLow => true,
672 }
673 }
674}
675 94
676/// Basic 16-bit timer instance. 95/// Advanced 16-bit timer with 4 channels instance.
677pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} 96pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
678
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}
689 97
690#[cfg(not(stm32l0))] 98pin_trait!(Channel1Pin, GeneralInstance4Channel);
691// It's just a General-purpose 32-bit timer instance. 99pin_trait!(Channel2Pin, GeneralInstance4Channel);
692/// Capture Compare 32-bit timer instance. 100pin_trait!(Channel3Pin, GeneralInstance4Channel);
693pub trait CaptureCompare32bitInstance: 101pin_trait!(Channel4Pin, GeneralInstance4Channel);
694 CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static 102pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
695{
696}
697 103
698#[cfg(not(stm32l0))] 104pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel);
699// It's just a Advanced Control timer instance. 105pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel);
700/// Complementary Capture Compare 32-bit timer instance. 106pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel);
701pub trait ComplementaryCaptureCompare16bitInstance: 107pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel);
702 CaptureCompare16bitInstance
703 + sealed::GeneralPurpose1ChannelComplementaryInstance
704 + sealed::GeneralPurpose2ChannelComplementaryInstance
705 + sealed::AdvancedControlInstance
706 + 'static
707{
708}
709 108
710pin_trait!(Channel1Pin, CaptureCompare16bitInstance); 109pin_trait!(BreakInputPin, AdvancedInstance4Channel);
711pin_trait!(Channel2Pin, CaptureCompare16bitInstance); 110pin_trait!(BreakInput2Pin, AdvancedInstance4Channel);
712pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
713pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
714pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
715 111
716cfg_if::cfg_if! { 112pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel);
717 if #[cfg(not(stm32l0))] { 113pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel);
718 pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
719 pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
720 pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
721 pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
722 114
723 pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); 115pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel);
724 pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); 116pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel);
725 117
726 pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); 118// Update Event trigger DMA for every timer
727 pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); 119dma_trait!(UpDma, BasicInstance);
728 120
729 pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); 121dma_trait!(Ch1Dma, GeneralInstance4Channel);
730 pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); 122dma_trait!(Ch2Dma, GeneralInstance4Channel);
731 } 123dma_trait!(Ch3Dma, GeneralInstance4Channel);
732} 124dma_trait!(Ch4Dma, GeneralInstance4Channel);
733 125
734#[allow(unused)] 126#[allow(unused)]
735macro_rules! impl_core_timer { 127macro_rules! impl_core_timer {
736 ($inst:ident, $irq:ident) => { 128 ($inst:ident, $bits:expr) => {
737 impl sealed::CoreInstance for crate::peripherals::$inst { 129 impl CoreInstance for crate::peripherals::$inst {
738 type Interrupt = crate::interrupt::typelevel::$irq; 130 type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP;
739
740 fn regs_core() -> crate::pac::timer::TimCore {
741 unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) }
742 }
743 }
744 };
745}
746
747#[allow(unused)]
748macro_rules! impl_basic_no_cr2_timer {
749 ($inst:ident) => {
750 impl sealed::BasicNoCr2Instance for crate::peripherals::$inst {
751 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 {
752 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) }
753 }
754 }
755 };
756}
757
758#[allow(unused)]
759macro_rules! impl_basic_timer {
760 ($inst:ident) => {
761 impl sealed::BasicInstance for crate::peripherals::$inst {
762 fn regs_basic() -> crate::pac::timer::TimBasic {
763 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
764 }
765 }
766 };
767}
768
769#[allow(unused)]
770macro_rules! impl_1ch_timer {
771 ($inst:ident) => {
772 impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst {
773 fn regs_1ch() -> crate::pac::timer::Tim1ch {
774 unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) }
775 }
776 }
777 };
778}
779
780#[allow(unused)]
781macro_rules! impl_2ch_timer {
782 ($inst:ident) => {
783 impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst {
784 fn regs_2ch() -> crate::pac::timer::Tim2ch {
785 unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) }
786 }
787 }
788 };
789}
790
791#[allow(unused)]
792macro_rules! impl_gp16_timer {
793 ($inst:ident) => {
794 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
795 fn regs_gp16() -> crate::pac::timer::TimGp16 {
796 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
797 }
798 }
799 };
800}
801
802#[allow(unused)]
803macro_rules! impl_gp32_timer {
804 ($inst:ident) => {
805 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
806 fn regs_gp32() -> crate::pac::timer::TimGp32 {
807 crate::pac::$inst
808 }
809 }
810 };
811}
812
813#[allow(unused)]
814macro_rules! impl_1ch_cmp_timer {
815 ($inst:ident) => {
816 impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {
817 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp {
818 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
819 }
820 }
821 };
822}
823 131
824#[allow(unused)] 132 const BITS: TimerBits = $bits;
825macro_rules! impl_2ch_cmp_timer {
826 ($inst:ident) => {
827 impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {
828 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp {
829 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
830 }
831 }
832 };
833}
834
835#[allow(unused)]
836macro_rules! impl_adv_timer {
837 ($inst:ident, $irq:ident) => {
838 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
839 type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq;
840 133
841 fn regs_advanced() -> crate::pac::timer::TimAdv { 134 fn regs() -> *mut () {
842 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } 135 crate::pac::$inst.as_ptr()
843 } 136 }
844 } 137 }
845 }; 138 };
846} 139}
847 140
848foreach_interrupt! { 141foreach_interrupt! {
849
850 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 142 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
851 impl_core_timer!($inst, $irq); 143 impl_core_timer!($inst, TimerBits::Bits16);
852 impl_basic_no_cr2_timer!($inst); 144 impl BasicNoCr2Instance for crate::peripherals::$inst {}
853 impl_basic_timer!($inst);
854 impl BasicInstance for crate::peripherals::$inst {} 145 impl BasicInstance for crate::peripherals::$inst {}
855 }; 146 };
856 147
857 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { 148 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
858 impl_core_timer!($inst, $irq); 149 impl_core_timer!($inst, TimerBits::Bits16);
859 impl_basic_no_cr2_timer!($inst); 150 impl BasicNoCr2Instance for crate::peripherals::$inst {}
860 impl_basic_timer!($inst);
861 impl_1ch_timer!($inst);
862 impl_2ch_timer!($inst);
863 impl_gp16_timer!($inst);
864 impl BasicInstance for crate::peripherals::$inst {} 151 impl BasicInstance for crate::peripherals::$inst {}
865 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 152 impl GeneralInstance1Channel for crate::peripherals::$inst {}
153 impl GeneralInstance2Channel for crate::peripherals::$inst {}
154 impl GeneralInstance4Channel for crate::peripherals::$inst {}
866 }; 155 };
867 156
868
869 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { 157 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
870 impl_core_timer!($inst, $irq); 158 impl_core_timer!($inst, TimerBits::Bits16);
871 impl_basic_no_cr2_timer!($inst); 159 impl BasicNoCr2Instance for crate::peripherals::$inst {}
872 impl_basic_timer!($inst);
873 impl_1ch_timer!($inst);
874 impl_2ch_timer!($inst);
875 impl_gp16_timer!($inst);
876 impl BasicInstance for crate::peripherals::$inst {} 160 impl BasicInstance for crate::peripherals::$inst {}
877 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 161 impl GeneralInstance1Channel for crate::peripherals::$inst {}
162 impl GeneralInstance2Channel for crate::peripherals::$inst {}
163 impl GeneralInstance4Channel for crate::peripherals::$inst {}
878 }; 164 };
879 165
880 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 166 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
881 impl_core_timer!($inst, $irq); 167 impl_core_timer!($inst, TimerBits::Bits16);
882 impl_basic_no_cr2_timer!($inst); 168 impl BasicNoCr2Instance for crate::peripherals::$inst {}
883 impl_basic_timer!($inst);
884 impl_1ch_timer!($inst);
885 impl_2ch_timer!($inst);
886 impl_gp16_timer!($inst);
887 impl BasicInstance for crate::peripherals::$inst {} 169 impl BasicInstance for crate::peripherals::$inst {}
888 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 170 impl GeneralInstance1Channel for crate::peripherals::$inst {}
171 impl GeneralInstance2Channel for crate::peripherals::$inst {}
172 impl GeneralInstance4Channel for crate::peripherals::$inst {}
889 }; 173 };
890 174
891 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 175 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
892 impl_core_timer!($inst, $irq); 176 impl_core_timer!($inst, TimerBits::Bits32);
893 impl_basic_no_cr2_timer!($inst); 177 impl BasicNoCr2Instance for crate::peripherals::$inst {}
894 impl_basic_timer!($inst);
895 impl_1ch_timer!($inst);
896 impl_2ch_timer!($inst);
897 impl_gp16_timer!($inst);
898 impl_gp32_timer!($inst);
899 impl BasicInstance for crate::peripherals::$inst {} 178 impl BasicInstance for crate::peripherals::$inst {}
900 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 179 impl GeneralInstance1Channel for crate::peripherals::$inst {}
901 impl CaptureCompare32bitInstance for crate::peripherals::$inst {} 180 impl GeneralInstance2Channel for crate::peripherals::$inst {}
181 impl GeneralInstance4Channel for crate::peripherals::$inst {}
182 impl GeneralInstance32bit4Channel for crate::peripherals::$inst {}
902 }; 183 };
903 184
904 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { 185 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
905 impl_core_timer!($inst, $irq); 186 impl_core_timer!($inst, TimerBits::Bits16);
906 impl_basic_no_cr2_timer!($inst); 187 impl BasicNoCr2Instance for crate::peripherals::$inst {}
907 impl_basic_timer!($inst);
908 impl_1ch_timer!($inst);
909 impl_2ch_timer!($inst);
910 impl_gp16_timer!($inst);
911 impl_1ch_cmp_timer!($inst);
912 impl_2ch_cmp_timer!($inst);
913 impl BasicInstance for crate::peripherals::$inst {} 188 impl BasicInstance for crate::peripherals::$inst {}
914 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 189 impl GeneralInstance1Channel for crate::peripherals::$inst {}
915 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 190 impl GeneralInstance2Channel for crate::peripherals::$inst {}
191 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
192 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
193 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
194 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
916 }; 195 };
917 ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => {
918 impl_adv_timer!($inst, $irq);
919 };
920
921 196
922 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { 197 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
923 impl_core_timer!($inst, $irq); 198 impl_core_timer!($inst, TimerBits::Bits16);
924 impl_basic_no_cr2_timer!($inst); 199 impl BasicNoCr2Instance for crate::peripherals::$inst {}
925 impl_basic_timer!($inst);
926 impl_1ch_timer!($inst);
927 impl_2ch_timer!($inst);
928 impl_gp16_timer!($inst);
929 impl_1ch_cmp_timer!($inst);
930 impl_2ch_cmp_timer!($inst);
931 impl BasicInstance for crate::peripherals::$inst {} 200 impl BasicInstance for crate::peripherals::$inst {}
932 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 201 impl GeneralInstance1Channel for crate::peripherals::$inst {}
933 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 202 impl GeneralInstance2Channel for crate::peripherals::$inst {}
203 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
204 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
205 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
206 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
934 }; 207 };
935 ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => {
936 impl_adv_timer!($inst, $irq);
937 };
938
939 208
940 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 209 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
941 impl_core_timer!($inst, $irq); 210 impl_core_timer!($inst, TimerBits::Bits16);
942 impl_basic_no_cr2_timer!($inst); 211 impl BasicNoCr2Instance for crate::peripherals::$inst {}
943 impl_basic_timer!($inst);
944 impl_1ch_timer!($inst);
945 impl_2ch_timer!($inst);
946 impl_gp16_timer!($inst);
947 impl_1ch_cmp_timer!($inst);
948 impl_2ch_cmp_timer!($inst);
949 impl BasicInstance for crate::peripherals::$inst {} 212 impl BasicInstance for crate::peripherals::$inst {}
950 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 213 impl GeneralInstance1Channel for crate::peripherals::$inst {}
951 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 214 impl GeneralInstance2Channel for crate::peripherals::$inst {}
952 }; 215 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
953 ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { 216 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
954 impl_adv_timer!($inst, $irq); 217 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
218 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
955 }; 219 };
956} 220}
957 221
958// Update Event trigger DMA for every timer 222#[cfg(not(stm32l0))]
959dma_trait!(UpDma, BasicInstance); 223#[allow(unused)]
960 224fn set_moe<T: GeneralInstance4Channel>() {
961dma_trait!(Ch1Dma, CaptureCompare16bitInstance); 225 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
962dma_trait!(Ch2Dma, CaptureCompare16bitInstance); 226 .bdtr()
963dma_trait!(Ch3Dma, CaptureCompare16bitInstance); 227 .modify(|w| w.set_moe(true));
964dma_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 1acba504e..b54e9a0d6 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,9 +4,8 @@ use core::marker::PhantomData;
4 4
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,14 +73,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
74 } 73 }
75 74
76 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 75 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
77 into_ref!(tim); 76 let mut this = Self { inner: Timer::new(tim) };
78
79 T::enable_and_reset();
80
81 let mut this = Self { inner: tim };
82 77
83 this.inner.set_counting_mode(counting_mode); 78 this.inner.set_counting_mode(counting_mode);
84 this.set_frequency(freq); 79 this.set_frequency(freq);
80 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
85 this.inner.start(); 81 this.inner.start();
86 82
87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 83 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -126,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
126 /// Get max duty value. 122 /// Get max duty value.
127 /// 123 ///
128 /// This value depends on the configured frequency and the timer's clock rate from RCC. 124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
129 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u32 {
130 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
131 } 127 }
132 128
133 /// Set the duty for a given channel. 129 /// Set the duty for a given channel.
134 /// 130 ///
135 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 131 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
136 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
137 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
138 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
139 } 135 }
@@ -141,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
141 /// Get the duty for a given channel. 137 /// Get the duty for a given channel.
142 /// 138 ///
143 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 139 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
144 pub fn get_duty(&self, channel: Channel) -> u16 { 140 pub fn get_duty(&self, channel: Channel) -> u32 {
145 self.inner.get_compare_value(channel) 141 self.inner.get_compare_value(channel)
146 } 142 }
147 143
@@ -165,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
165 channel: Channel, 161 channel: Channel,
166 duty: &[u16], 162 duty: &[u16],
167 ) { 163 ) {
168 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
169
170 into_ref!(dma); 164 into_ref!(dma);
171 165
172 #[allow(clippy::let_unit_value)] // eg. stm32f334 166 #[allow(clippy::let_unit_value)] // eg. stm32f334
@@ -201,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
201 &mut dma, 195 &mut dma,
202 req, 196 req,
203 duty, 197 duty,
204 T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, 198 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _,
205 dma_transfer_option, 199 dma_transfer_option,
206 ) 200 )
207 .await 201 .await
@@ -227,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
227 221
228macro_rules! impl_waveform_chx { 222macro_rules! impl_waveform_chx {
229 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { 223 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
230 impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 224 impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
231 /// Generate a sequence of PWM waveform 225 /// Generate a sequence of PWM waveform
232 /// 226 ///
233 /// Note: 227 /// Note:
234 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. 228 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
235 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { 229 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
236 use super::vals::Ccds; 230 use crate::pac::timer::vals::Ccds;
237
238 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
239 231
240 into_ref!(dma); 232 into_ref!(dma);
241 233
242 #[allow(clippy::let_unit_value)] // eg. stm32f334 234 #[allow(clippy::let_unit_value)] // eg. stm32f334
243 let req = dma.request(); 235 let req = dma.request();
244 236
245 let cc_channel = super::Channel::$cc_ch; 237 let cc_channel = Channel::$cc_ch;
246 238
247 let original_duty_state = self.get_duty(cc_channel); 239 let original_duty_state = self.get_duty(cc_channel);
248 let original_enable_state = self.is_enabled(cc_channel); 240 let original_enable_state = self.is_enabled(cc_channel);
@@ -279,7 +271,7 @@ macro_rules! impl_waveform_chx {
279 &mut dma, 271 &mut dma,
280 req, 272 req,
281 duty, 273 duty,
282 T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, 274 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
283 dma_transfer_option, 275 dma_transfer_option,
284 ) 276 )
285 .await 277 .await
@@ -314,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
314impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); 306impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
315impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); 307impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
316 308
317impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 309impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
318 type Channel = Channel; 310 type Channel = Channel;
319 type Time = Hertz; 311 type Time = Hertz;
320 type Duty = u16; 312 type Duty = u32;
321 313
322 fn disable(&mut self, channel: Self::Channel) { 314 fn disable(&mut self, channel: Self::Channel) {
323 self.inner.enable_channel(channel, false); 315 self.inner.enable_channel(channel, false);
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
new file mode 100644
index 000000000..fe614b811
--- /dev/null
+++ b/embassy-stm32/src/ucpd.rs
@@ -0,0 +1,607 @@
1//! USB Type-C/USB Power Delivery Interface (UCPD)
2
3// Implementation Notes
4//
5// As of Feb. 2024 the UCPD peripheral is availalbe on: G0, G4, H5, L5, U5
6//
7// Cube HAL LL Driver (g0):
8// https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Inc/stm32g0xx_ll_ucpd.h
9// https://github.com/STMicroelectronics/stm32g0xx_hal_driver/blob/v1.4.6/Src/stm32g0xx_ll_ucpd.c
10// Except for a the `LL_UCPD_RxAnalogFilterEnable/Disable()` functions the Cube HAL implementation of
11// all families is the same.
12//
13// Dead battery pull-down resistors functionality is enabled by default on startup and must
14// be disabled by setting a bit in PWR/SYSCFG registers. The exact name and location for that
15// bit is different for each familily.
16
17use core::future::poll_fn;
18use core::marker::PhantomData;
19use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll;
21
22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
24use embassy_sync::waitqueue::AtomicWaker;
25
26use crate::dma::{AnyChannel, Request, Transfer, TransferOptions};
27use crate::interrupt;
28use crate::interrupt::typelevel::Interrupt;
29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState};
31use crate::rcc::RccPeripheral;
32
33pub(crate) fn init(
34 _cs: critical_section::CriticalSection,
35 #[cfg(peri_ucpd1)] ucpd1_db_enable: bool,
36 #[cfg(peri_ucpd2)] ucpd2_db_enable: bool,
37) {
38 #[cfg(stm32g0x1)]
39 {
40 // according to RM0444 (STM32G0x1) section 8.1.1:
41 // when UCPD is disabled setting the strobe will disable dead battery
42 // (which is enabled after reset) but if UCPD is enabled, setting the
43 // strobe will apply the CC pin configuration from the control register
44 // (which is why we need to be careful about when we call this)
45 crate::pac::SYSCFG.cfgr1().modify(|w| {
46 w.set_ucpd1_strobe(!ucpd1_db_enable);
47 w.set_ucpd2_strobe(!ucpd2_db_enable);
48 });
49 }
50
51 #[cfg(any(stm32g4, stm32l5))]
52 {
53 crate::pac::PWR.cr3().modify(|w| {
54 #[cfg(stm32g4)]
55 w.set_ucpd1_dbdis(!ucpd1_db_enable);
56 #[cfg(stm32l5)]
57 w.set_ucpd_dbdis(!ucpd1_db_enable);
58 })
59 }
60
61 #[cfg(any(stm32h5, stm32u5))]
62 {
63 crate::pac::PWR.ucpdr().modify(|w| {
64 w.set_ucpd_dbdis(!ucpd1_db_enable);
65 })
66 }
67}
68
69/// Pull-up or Pull-down resistor state of both CC lines.
70#[derive(Debug, Clone, Copy, PartialEq)]
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
72pub enum CcPull {
73 /// Analog PHY for CC pin disabled.
74 Disabled,
75
76 /// Rd=5.1k pull-down resistor.
77 Sink,
78
79 /// Rp=56k pull-up resistor to indicate default USB power.
80 SourceDefaultUsb,
81
82 /// Rp=22k pull-up resistor to indicate support for up to 1.5A.
83 Source1_5A,
84
85 /// Rp=10k pull-up resistor to indicate support for up to 3.0A.
86 Source3_0A,
87}
88
89/// UCPD driver.
90pub struct Ucpd<'d, T: Instance> {
91 cc_phy: CcPhy<'d, T>,
92}
93
94impl<'d, T: Instance> Ucpd<'d, T> {
95 /// Creates a new UCPD driver instance.
96 pub fn new(
97 _peri: impl Peripheral<P = T> + 'd,
98 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
99 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd,
100 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd,
101 ) -> Self {
102 into_ref!(cc1, cc2);
103 cc1.set_as_analog();
104 cc2.set_as_analog();
105
106 T::enable_and_reset();
107 T::Interrupt::unpend();
108 unsafe { T::Interrupt::enable() };
109
110 let r = T::REGS;
111 r.cfgr1().write(|w| {
112 // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz.
113 // However, the optimum performance is ensured in the range from 6 to 12 MHz"
114 // UCPD is driven by HSI16 (16MHz internal oscillator), which we need to divide by 2.
115 w.set_psc_usbpdclk(PscUsbpdclk::DIV2);
116
117 // Prescaler to produce a target half-bit frequency of 600kHz which is required
118 // to produce transmit with a nominal nominal bit rate of 300Kbps+-10% using
119 // biphase mark coding (BMC, aka differential manchester coding).
120 // A divider of 13 gives the target frequency closest to spec (~615kHz, 1.625us).
121 w.set_hbitclkdiv(13 - 1);
122
123 // Time window for detecting non-idle (12-20us).
124 // 1.75us * 8 = 14us.
125 w.set_transwin(8 - 1);
126
127 // Time from the end of last bit of a Frame until the start of the first bit of the
128 // next Preamble (min 25us).
129 // 1.75us * 17 = ~30us
130 w.set_ifrgap(17 - 1);
131
132 // TODO: Currently only hard reset and SOP messages can be received.
133 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
134 w.set_rxordseten(0b1001);
135
136 // Enable DMA
137 w.set_txdmaen(true);
138 w.set_rxdmaen(true);
139
140 w.set_ucpden(true);
141 });
142
143 Self {
144 cc_phy: CcPhy { _lifetime: PhantomData },
145 }
146 }
147
148 /// Returns the TypeC CC PHY.
149 pub fn cc_phy(&mut self) -> &mut CcPhy<'d, T> {
150 &mut self.cc_phy
151 }
152
153 /// Splits the UCPD driver into a TypeC PHY to control and monitor CC voltage
154 /// and a Power Delivery (PD) PHY with receiver and transmitter.
155 pub fn split_pd_phy(
156 self,
157 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
158 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
159 cc_sel: CcSel,
160 ) -> (CcPhy<'d, T>, PdPhy<'d, T>) {
161 let r = T::REGS;
162
163 // TODO: Currently only SOP messages are supported.
164 r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000));
165
166 // Enable the receiver on one of the two CC lines.
167 r.cr().modify(|w| w.set_phyccsel(cc_sel));
168
169 // Enable hard reset receive interrupt.
170 r.imr().modify(|w| w.set_rxhrstdetie(true));
171
172 // Both parts must be dropped before the peripheral can be disabled.
173 T::state().drop_not_ready.store(true, Ordering::Relaxed);
174
175 into_ref!(rx_dma, tx_dma);
176 let rx_dma_req = rx_dma.request();
177 let tx_dma_req = tx_dma.request();
178 (
179 self.cc_phy,
180 PdPhy {
181 _lifetime: PhantomData,
182 rx_dma_ch: rx_dma.map_into(),
183 rx_dma_req,
184 tx_dma_ch: tx_dma.map_into(),
185 tx_dma_req,
186 },
187 )
188 }
189}
190
191/// Control and monitoring of TypeC CC pin functionailty.
192pub struct CcPhy<'d, T: Instance> {
193 _lifetime: PhantomData<&'d mut T>,
194}
195
196impl<'d, T: Instance> Drop for CcPhy<'d, T> {
197 fn drop(&mut self) {
198 let r = T::REGS;
199 r.cr().modify(|w| {
200 w.set_cc1tcdis(true);
201 w.set_cc2tcdis(true);
202 w.set_ccenable(Ccenable::DISABLED);
203 });
204
205 // Check if the PdPhy part was dropped already.
206 let drop_not_ready = &T::state().drop_not_ready;
207 if drop_not_ready.load(Ordering::Relaxed) {
208 drop_not_ready.store(true, Ordering::Relaxed);
209 } else {
210 r.cfgr1().write(|w| w.set_ucpden(false));
211 T::disable();
212 T::Interrupt::disable();
213 }
214 }
215}
216
217impl<'d, T: Instance> CcPhy<'d, T> {
218 /// Sets the pull-up/pull-down resistor values exposed on the CC pins.
219 pub fn set_pull(&mut self, cc_pull: CcPull) {
220 T::REGS.cr().modify(|w| {
221 w.set_anamode(if cc_pull == CcPull::Sink {
222 Anamode::SINK
223 } else {
224 Anamode::SOURCE
225 });
226 w.set_anasubmode(match cc_pull {
227 CcPull::SourceDefaultUsb => 1,
228 CcPull::Source1_5A => 2,
229 CcPull::Source3_0A => 3,
230 _ => 0,
231 });
232 w.set_ccenable(if cc_pull == CcPull::Disabled {
233 Ccenable::DISABLED
234 } else {
235 Ccenable::BOTH
236 });
237 });
238
239 // Disable dead-battery pull-down resistors which are enabled by default on boot.
240 critical_section::with(|cs| {
241 init(
242 cs,
243 false,
244 #[cfg(peri_ucpd2)]
245 false,
246 );
247 });
248 }
249
250 /// Returns the current voltage level of CC1 and CC2 pin as tuple.
251 ///
252 /// Interpretation of the voltage levels depends on the configured CC line
253 /// pull-up/pull-down resistance.
254 pub fn vstate(&self) -> (CcVState, CcVState) {
255 let sr = T::REGS.sr().read();
256 (sr.typec_vstate_cc1(), sr.typec_vstate_cc2())
257 }
258
259 /// Waits for a change in voltage state on either CC line.
260 pub async fn wait_for_vstate_change(&self) -> (CcVState, CcVState) {
261 let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false));
262 let prev_vstate = self.vstate();
263 poll_fn(|cx| {
264 let vstate = self.vstate();
265 if vstate != prev_vstate {
266 Poll::Ready(vstate)
267 } else {
268 T::state().waker.register(cx.waker());
269 self.enable_cc_interrupts(true);
270 Poll::Pending
271 }
272 })
273 .await
274 }
275
276 fn enable_cc_interrupts(&self, enable: bool) {
277 T::REGS.imr().modify(|w| {
278 w.set_typecevt1ie(enable);
279 w.set_typecevt2ie(enable);
280 });
281 }
282}
283
284/// Receive Error.
285#[derive(Debug, Clone, Copy)]
286#[cfg_attr(feature = "defmt", derive(defmt::Format))]
287pub enum RxError {
288 /// Incorrect CRC or truncated message (a line becoming static before EOP is met).
289 Crc,
290
291 /// Provided buffer was too small for the received message.
292 Overrun,
293
294 /// Hard Reset received before or during reception.
295 HardReset,
296}
297
298/// Transmit Error.
299#[derive(Debug, Clone, Copy)]
300#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301pub enum TxError {
302 /// Concurrent receive in progress or excessive noise on the line.
303 Discarded,
304
305 /// Hard Reset received before or during transmission.
306 HardReset,
307}
308
309/// Power Delivery (PD) PHY.
310pub struct PdPhy<'d, T: Instance> {
311 _lifetime: PhantomData<&'d mut T>,
312 rx_dma_ch: PeripheralRef<'d, AnyChannel>,
313 rx_dma_req: Request,
314 tx_dma_ch: PeripheralRef<'d, AnyChannel>,
315 tx_dma_req: Request,
316}
317
318impl<'d, T: Instance> Drop for PdPhy<'d, T> {
319 fn drop(&mut self) {
320 // Check if the Type-C part was dropped already.
321 let drop_not_ready = &T::state().drop_not_ready;
322 if drop_not_ready.load(Ordering::Relaxed) {
323 drop_not_ready.store(true, Ordering::Relaxed);
324 } else {
325 T::REGS.cfgr1().write(|w| w.set_ucpden(false));
326 T::disable();
327 T::Interrupt::disable();
328 }
329 }
330}
331
332impl<'d, T: Instance> PdPhy<'d, T> {
333 /// Receives a PD message into the provided buffer.
334 ///
335 /// Returns the number of received bytes or an error.
336 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
337 let r = T::REGS;
338
339 let dma = unsafe {
340 Transfer::new_read(
341 &self.rx_dma_ch,
342 self.rx_dma_req,
343 r.rxdr().as_ptr() as *mut u8,
344 buf,
345 TransferOptions::default(),
346 )
347 };
348
349 // Clear interrupt flags (possibly set from last receive).
350 r.icr().write(|w| {
351 w.set_rxorddetcf(true);
352 w.set_rxovrcf(true);
353 w.set_rxmsgendcf(true);
354 });
355
356 r.cr().modify(|w| w.set_phyrxen(true));
357 let _on_drop = OnDrop::new(|| {
358 r.cr().modify(|w| w.set_phyrxen(false));
359 self.enable_rx_interrupt(false);
360 });
361
362 poll_fn(|cx| {
363 let sr = r.sr().read();
364 if sr.rxhrstdet() {
365 // Clean and re-enable hard reset receive interrupt.
366 r.icr().write(|w| w.set_rxhrstdetcf(true));
367 r.imr().modify(|w| w.set_rxhrstdetie(true));
368 Poll::Ready(Err(RxError::HardReset))
369 } else if sr.rxmsgend() {
370 let ret = if sr.rxovr() {
371 Err(RxError::Overrun)
372 } else if sr.rxerr() {
373 Err(RxError::Crc)
374 } else {
375 Ok(())
376 };
377 Poll::Ready(ret)
378 } else {
379 T::state().waker.register(cx.waker());
380 self.enable_rx_interrupt(true);
381 Poll::Pending
382 }
383 })
384 .await?;
385
386 // Make sure that the last byte was fetched by DMA.
387 while r.sr().read().rxne() {
388 if dma.get_remaining_transfers() == 0 {
389 return Err(RxError::Overrun);
390 }
391 }
392
393 Ok(r.rx_payszr().read().rxpaysz().into())
394 }
395
396 fn enable_rx_interrupt(&self, enable: bool) {
397 T::REGS.imr().modify(|w| w.set_rxmsgendie(enable));
398 }
399
400 /// Transmits a PD message.
401 pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> {
402 let r = T::REGS;
403
404 // When a previous transmission was dropped before it had finished it
405 // might still be running because there is no way to abort an ongoing
406 // message transmission. Wait for it to finish but ignore errors.
407 if r.cr().read().txsend() {
408 if let Err(TxError::HardReset) = self.wait_tx_done().await {
409 return Err(TxError::HardReset);
410 }
411 }
412
413 // Clear the TX interrupt flags.
414 T::REGS.icr().write(|w| {
415 w.set_txmsgdisccf(true);
416 w.set_txmsgsentcf(true);
417 });
418
419 // Start the DMA and let it do its thing in the background.
420 let _dma = unsafe {
421 Transfer::new_write(
422 &self.tx_dma_ch,
423 self.tx_dma_req,
424 buf,
425 r.txdr().as_ptr() as *mut u8,
426 TransferOptions::default(),
427 )
428 };
429
430 // Configure and start the transmission.
431 r.tx_payszr().write(|w| w.set_txpaysz(buf.len() as _));
432 r.cr().modify(|w| {
433 w.set_txmode(Txmode::PACKET);
434 w.set_txsend(true);
435 });
436
437 self.wait_tx_done().await
438 }
439
440 async fn wait_tx_done(&self) -> Result<(), TxError> {
441 let _on_drop = OnDrop::new(|| self.enable_tx_interrupts(false));
442 poll_fn(|cx| {
443 let r = T::REGS;
444 let sr = r.sr().read();
445 if sr.rxhrstdet() {
446 // Clean and re-enable hard reset receive interrupt.
447 r.icr().write(|w| w.set_rxhrstdetcf(true));
448 r.imr().modify(|w| w.set_rxhrstdetie(true));
449 Poll::Ready(Err(TxError::HardReset))
450 } else if sr.txmsgdisc() {
451 Poll::Ready(Err(TxError::Discarded))
452 } else if sr.txmsgsent() {
453 Poll::Ready(Ok(()))
454 } else {
455 T::state().waker.register(cx.waker());
456 self.enable_tx_interrupts(true);
457 Poll::Pending
458 }
459 })
460 .await
461 }
462
463 fn enable_tx_interrupts(&self, enable: bool) {
464 T::REGS.imr().modify(|w| {
465 w.set_txmsgdiscie(enable);
466 w.set_txmsgsentie(enable);
467 });
468 }
469
470 /// Transmit a hard reset.
471 pub async fn transmit_hardreset(&mut self) -> Result<(), TxError> {
472 let r = T::REGS;
473
474 // Clear the hardreset interrupt flags.
475 T::REGS.icr().write(|w| {
476 w.set_hrstdisccf(true);
477 w.set_hrstsentcf(true);
478 });
479
480 // Trigger hard reset transmission.
481 r.cr().modify(|w| {
482 w.set_txhrst(true);
483 });
484
485 let _on_drop = OnDrop::new(|| self.enable_hardreset_interrupts(false));
486 poll_fn(|cx| {
487 let r = T::REGS;
488 let sr = r.sr().read();
489 if sr.rxhrstdet() {
490 // Clean and re-enable hard reset receive interrupt.
491 r.icr().write(|w| w.set_rxhrstdetcf(true));
492 r.imr().modify(|w| w.set_rxhrstdetie(true));
493 Poll::Ready(Err(TxError::HardReset))
494 } else if sr.hrstdisc() {
495 Poll::Ready(Err(TxError::Discarded))
496 } else if sr.hrstsent() {
497 Poll::Ready(Ok(()))
498 } else {
499 T::state().waker.register(cx.waker());
500 self.enable_hardreset_interrupts(true);
501 Poll::Pending
502 }
503 })
504 .await
505 }
506
507 fn enable_hardreset_interrupts(&self, enable: bool) {
508 T::REGS.imr().modify(|w| {
509 w.set_hrstdiscie(enable);
510 w.set_hrstsentie(enable);
511 });
512 }
513}
514
515/// Interrupt handler.
516pub struct InterruptHandler<T: Instance> {
517 _phantom: PhantomData<T>,
518}
519
520impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
521 unsafe fn on_interrupt() {
522 let r = T::REGS;
523 let sr = r.sr().read();
524
525 if sr.typecevt1() || sr.typecevt2() {
526 r.icr().write(|w| {
527 w.set_typecevt1cf(true);
528 w.set_typecevt2cf(true);
529 });
530 }
531
532 if sr.rxhrstdet() {
533 r.imr().modify(|w| w.set_rxhrstdetie(false));
534 }
535
536 if sr.rxmsgend() {
537 r.imr().modify(|w| w.set_rxmsgendie(false));
538 }
539
540 if sr.txmsgdisc() || sr.txmsgsent() {
541 r.imr().modify(|w| {
542 w.set_txmsgdiscie(false);
543 w.set_txmsgsentie(false);
544 });
545 }
546
547 if sr.hrstdisc() || sr.hrstsent() {
548 r.imr().modify(|w| {
549 w.set_hrstdiscie(false);
550 w.set_hrstsentie(false);
551 });
552 }
553
554 // Wake the task to clear and re-enabled interrupts.
555 T::state().waker.wake();
556 }
557}
558
559struct State {
560 waker: AtomicWaker,
561 // Inverted logic for a default state of 0 so that the data goes into the .bss section.
562 drop_not_ready: AtomicBool,
563}
564
565impl State {
566 pub const fn new() -> Self {
567 Self {
568 waker: AtomicWaker::new(),
569 drop_not_ready: AtomicBool::new(false),
570 }
571 }
572}
573
574trait SealedInstance {
575 const REGS: crate::pac::ucpd::Ucpd;
576 fn state() -> &'static State;
577}
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;
584}
585
586foreach_interrupt!(
587 ($inst:ident, ucpd, UCPD, GLOBAL, $irq:ident) => {
588 impl SealedInstance for crate::peripherals::$inst {
589 const REGS: crate::pac::ucpd::Ucpd = crate::pac::$inst;
590
591 fn state() -> &'static State {
592 static STATE: State = State::new();
593 &STATE
594 }
595 }
596
597 impl Instance for crate::peripherals::$inst {
598 type Interrupt = crate::interrupt::typelevel::$irq;
599 }
600 };
601);
602
603pin_trait!(Cc1Pin, Instance);
604pin_trait!(Cc2Pin, Instance);
605
606dma_trait!(TxDma, Instance);
607dma_trait!(RxDma, Instance);
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index aa13586f8..5e38532bd 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -27,5 +27,5 @@ pub fn uid_hex_bytes() -> &'static [u8; 24] {
27 LOADED = true; 27 LOADED = true;
28 } 28 }
29 }); 29 });
30 unsafe { &UID_HEX } 30 unsafe { &*core::ptr::addr_of!(UID_HEX) }
31} 31}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c11e3382f..51862e185 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,13 +1,10 @@
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 4debd4e54..1e3c44167 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,37 +1,69 @@
1//! Universal Serial Bus (USB) 1//! Universal Serial Bus (USB)
2 2
3use crate::interrupt; 3#[cfg_attr(usb, path = "usb.rs")]
4use crate::rcc::RccPeripheral; 4#[cfg_attr(otg, path = "otg.rs")]
5mod _version;
6pub use _version::*;
5 7
6mod usb; 8use crate::interrupt::typelevel::Interrupt;
7pub use usb::*; 9use crate::rcc::SealedRccPeripheral;
8 10
9pub(crate) mod sealed { 11/// clock, power initialization stuff that's common for USB and OTG.
10 pub trait Instance { 12fn common_init<T: Instance>() {
11 fn regs() -> crate::pac::usb::Usb; 13 // Check the USB clock is enabled and running at exactly 48 MHz.
14 // frequency() will panic if not enabled
15 let freq = T::frequency();
16 // Check frequency is within the 0.25% tolerance allowed by the spec.
17 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
18 // has tight clock restrictions due to something else (like audio).
19 if freq.0.abs_diff(48_000_000) > 120_000 {
20 panic!(
21 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
22 freq.0
23 )
12 } 24 }
13}
14 25
15/// USB instance trait. 26 #[cfg(any(stm32l4, stm32l5, stm32wb))]
16pub trait Instance: sealed::Instance + RccPeripheral + 'static { 27 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
17 /// Interrupt for this USB instance. 28
18 type Interrupt: interrupt::typelevel::Interrupt; 29 #[cfg(pwr_h5)]
19} 30 critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)));
31
32 #[cfg(stm32h7)]
33 {
34 // If true, VDD33USB is generated by internal regulator from VDD50USB
35 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
36 // TODO: unhardcode
37 let internal_regulator = false;
38
39 // Enable USB power
40 critical_section::with(|_| {
41 crate::pac::PWR.cr3().modify(|w| {
42 w.set_usb33den(true);
43 w.set_usbregen(internal_regulator);
44 })
45 });
46
47 // Wait for USB power to stabilize
48 while !crate::pac::PWR.cr3().read().usb33rdy() {}
49 }
50
51 #[cfg(stm32u5)]
52 {
53 // Enable USB power
54 critical_section::with(|_| {
55 crate::pac::PWR.svmcr().modify(|w| {
56 w.set_usv(true);
57 w.set_uvmen(true);
58 })
59 });
60
61 // Wait for USB power to stabilize
62 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
63 }
64
65 T::Interrupt::unpend();
66 unsafe { T::Interrupt::enable() };
20 67
21// Internal PHY pins 68 <T as SealedRccPeripheral>::enable_and_reset();
22pin_trait!(DpPin, Instance); 69}
23pin_trait!(DmPin, Instance);
24
25foreach_interrupt!(
26 ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
27 impl sealed::Instance for crate::peripherals::$inst {
28 fn regs() -> crate::pac::usb::Usb {
29 crate::pac::$inst
30 }
31 }
32
33 impl Instance for crate::peripherals::$inst {
34 type Interrupt = crate::interrupt::typelevel::$irq;
35 }
36 };
37);
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb/otg.rs
index 373697ec8..b0e7067bd 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -6,17 +6,16 @@ use core::task::Poll;
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 super::*; 14use crate::gpio::AFType;
15use crate::gpio::sealed::AFType;
16use crate::interrupt; 15use crate::interrupt;
17use crate::interrupt::typelevel::Interrupt; 16use crate::interrupt::typelevel::Interrupt;
18use crate::pac::otg::{regs, vals}; 17use crate::pac::otg::{regs, vals};
19use crate::rcc::sealed::RccPeripheral; 18use crate::rcc::{RccPeripheral, SealedRccPeripheral};
20use crate::time::Hertz; 19use crate::time::Hertz;
21 20
22/// Interrupt handler. 21/// Interrupt handler.
@@ -561,8 +560,7 @@ impl<'d, T: Instance> Bus<'d, T> {
561 560
562impl<'d, T: Instance> Bus<'d, T> { 561impl<'d, T: Instance> Bus<'d, T> {
563 fn init(&mut self) { 562 fn init(&mut self) {
564 #[cfg(stm32l4)] 563 super::common_init::<T>();
565 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
566 564
567 #[cfg(stm32f7)] 565 #[cfg(stm32f7)]
568 { 566 {
@@ -590,22 +588,6 @@ impl<'d, T: Instance> Bus<'d, T> {
590 588
591 #[cfg(stm32h7)] 589 #[cfg(stm32h7)]
592 { 590 {
593 // If true, VDD33USB is generated by internal regulator from VDD50USB
594 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
595 // TODO: unhardcode
596 let internal_regulator = false;
597
598 // Enable USB power
599 critical_section::with(|_| {
600 crate::pac::PWR.cr3().modify(|w| {
601 w.set_usb33den(true);
602 w.set_usbregen(internal_regulator);
603 })
604 });
605
606 // Wait for USB power to stabilize
607 while !crate::pac::PWR.cr3().read().usb33rdy() {}
608
609 // Enable ULPI clock if external PHY is used 591 // Enable ULPI clock if external PHY is used
610 let ulpien = !self.phy_type.internal(); 592 let ulpien = !self.phy_type.internal();
611 critical_section::with(|_| { 593 critical_section::with(|_| {
@@ -626,25 +608,6 @@ impl<'d, T: Instance> Bus<'d, T> {
626 }); 608 });
627 } 609 }
628 610
629 #[cfg(stm32u5)]
630 {
631 // Enable USB power
632 critical_section::with(|_| {
633 crate::pac::PWR.svmcr().modify(|w| {
634 w.set_usv(true);
635 w.set_uvmen(true);
636 })
637 });
638
639 // Wait for USB power to stabilize
640 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
641 }
642
643 <T as RccPeripheral>::enable_and_reset();
644
645 T::Interrupt::unpend();
646 unsafe { T::Interrupt::enable() };
647
648 let r = T::regs(); 611 let r = T::regs();
649 let core_id = r.cid().read().0; 612 let core_id = r.cid().read().0;
650 trace!("Core id {:08x}", core_id); 613 trace!("Core id {:08x}", core_id);
@@ -846,7 +809,7 @@ impl<'d, T: Instance> Bus<'d, T> {
846 fn disable(&mut self) { 809 fn disable(&mut self) {
847 T::Interrupt::disable(); 810 T::Interrupt::disable();
848 811
849 <T as RccPeripheral>::disable(); 812 <T as SealedRccPeripheral>::disable();
850 813
851 #[cfg(stm32l4)] 814 #[cfg(stm32l4)]
852 crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); 815 crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
@@ -1469,3 +1432,158 @@ fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 {
1469fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { 1432fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool {
1470 r.cid().read().0 & 0xf000 == 0x1000 1433 r.cid().read().0 & 0xf000 == 0x1000
1471} 1434}
1435
1436// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps
1437const MAX_EP_COUNT: usize = 9;
1438
1439trait SealedInstance {
1440 const HIGH_SPEED: bool;
1441 const FIFO_DEPTH_WORDS: u16;
1442 const ENDPOINT_COUNT: usize;
1443
1444 fn regs() -> crate::pac::otg::Otg;
1445 fn state() -> &'static super::State<{ MAX_EP_COUNT }>;
1446}
1447
1448/// USB instance trait.
1449#[allow(private_bounds)]
1450pub trait Instance: SealedInstance + RccPeripheral + 'static {
1451 /// Interrupt for this USB instance.
1452 type Interrupt: interrupt::typelevel::Interrupt;
1453}
1454
1455// Internal PHY pins
1456pin_trait!(DpPin, Instance);
1457pin_trait!(DmPin, Instance);
1458
1459// External PHY pins
1460pin_trait!(UlpiClkPin, Instance);
1461pin_trait!(UlpiDirPin, Instance);
1462pin_trait!(UlpiNxtPin, Instance);
1463pin_trait!(UlpiStpPin, Instance);
1464pin_trait!(UlpiD0Pin, Instance);
1465pin_trait!(UlpiD1Pin, Instance);
1466pin_trait!(UlpiD2Pin, Instance);
1467pin_trait!(UlpiD3Pin, Instance);
1468pin_trait!(UlpiD4Pin, Instance);
1469pin_trait!(UlpiD5Pin, Instance);
1470pin_trait!(UlpiD6Pin, Instance);
1471pin_trait!(UlpiD7Pin, Instance);
1472
1473foreach_interrupt!(
1474 (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
1475 impl SealedInstance for crate::peripherals::USB_OTG_FS {
1476 const HIGH_SPEED: bool = false;
1477
1478 cfg_if::cfg_if! {
1479 if #[cfg(stm32f1)] {
1480 const FIFO_DEPTH_WORDS: u16 = 128;
1481 const ENDPOINT_COUNT: usize = 8;
1482 } else if #[cfg(any(
1483 stm32f2,
1484 stm32f401,
1485 stm32f405,
1486 stm32f407,
1487 stm32f411,
1488 stm32f415,
1489 stm32f417,
1490 stm32f427,
1491 stm32f429,
1492 stm32f437,
1493 stm32f439,
1494 ))] {
1495 const FIFO_DEPTH_WORDS: u16 = 320;
1496 const ENDPOINT_COUNT: usize = 4;
1497 } else if #[cfg(any(
1498 stm32f412,
1499 stm32f413,
1500 stm32f423,
1501 stm32f446,
1502 stm32f469,
1503 stm32f479,
1504 stm32f7,
1505 stm32l4,
1506 stm32u5,
1507 ))] {
1508 const FIFO_DEPTH_WORDS: u16 = 320;
1509 const ENDPOINT_COUNT: usize = 6;
1510 } else if #[cfg(stm32g0x1)] {
1511 const FIFO_DEPTH_WORDS: u16 = 512;
1512 const ENDPOINT_COUNT: usize = 8;
1513 } else if #[cfg(stm32h7)] {
1514 const FIFO_DEPTH_WORDS: u16 = 1024;
1515 const ENDPOINT_COUNT: usize = 9;
1516 } else if #[cfg(stm32u5)] {
1517 const FIFO_DEPTH_WORDS: u16 = 320;
1518 const ENDPOINT_COUNT: usize = 6;
1519 } else {
1520 compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
1521 }
1522 }
1523
1524 fn regs() -> crate::pac::otg::Otg {
1525 crate::pac::USB_OTG_FS
1526 }
1527
1528 fn state() -> &'static State<MAX_EP_COUNT> {
1529 static STATE: State<MAX_EP_COUNT> = State::new();
1530 &STATE
1531 }
1532 }
1533
1534 impl Instance for crate::peripherals::USB_OTG_FS {
1535 type Interrupt = crate::interrupt::typelevel::$irq;
1536 }
1537 };
1538
1539 (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
1540 impl SealedInstance for crate::peripherals::USB_OTG_HS {
1541 const HIGH_SPEED: bool = true;
1542
1543 cfg_if::cfg_if! {
1544 if #[cfg(any(
1545 stm32f2,
1546 stm32f405,
1547 stm32f407,
1548 stm32f415,
1549 stm32f417,
1550 stm32f427,
1551 stm32f429,
1552 stm32f437,
1553 stm32f439,
1554 ))] {
1555 const FIFO_DEPTH_WORDS: u16 = 1024;
1556 const ENDPOINT_COUNT: usize = 6;
1557 } else if #[cfg(any(
1558 stm32f446,
1559 stm32f469,
1560 stm32f479,
1561 stm32f7,
1562 stm32h7,
1563 ))] {
1564 const FIFO_DEPTH_WORDS: u16 = 1024;
1565 const ENDPOINT_COUNT: usize = 9;
1566 } else if #[cfg(stm32u5)] {
1567 const FIFO_DEPTH_WORDS: u16 = 1024;
1568 const ENDPOINT_COUNT: usize = 9;
1569 } else {
1570 compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
1571 }
1572 }
1573
1574 fn regs() -> crate::pac::otg::Otg {
1575 // OTG HS registers are a superset of FS registers
1576 unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
1577 }
1578
1579 fn state() -> &'static State<MAX_EP_COUNT> {
1580 static STATE: State<MAX_EP_COUNT> = State::new();
1581 &STATE
1582 }
1583 }
1584
1585 impl Instance for crate::peripherals::USB_OTG_HS {
1586 type Interrupt = crate::interrupt::typelevel::$irq;
1587 }
1588 };
1589);
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index be321a19b..f48808cb3 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,12 +12,10 @@ use embassy_usb_driver::{
12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13}; 13};
14 14
15use super::{DmPin, DpPin, Instance};
16use crate::interrupt::typelevel::Interrupt;
17use crate::pac::usb::regs; 15use crate::pac::usb::regs;
18use crate::pac::usb::vals::{EpType, Stat}; 16use crate::pac::usb::vals::{EpType, Stat};
19use crate::pac::USBRAM; 17use crate::pac::USBRAM;
20use crate::rcc::sealed::RccPeripheral; 18use crate::rcc::RccPeripheral;
21use crate::{interrupt, Peripheral}; 19use crate::{interrupt, Peripheral};
22 20
23/// Interrupt handler. 21/// Interrupt handler.
@@ -259,18 +257,10 @@ impl<'d, T: Instance> Driver<'d, T> {
259 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 257 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
260 ) -> Self { 258 ) -> Self {
261 into_ref!(dp, dm); 259 into_ref!(dp, dm);
262 T::Interrupt::unpend();
263 unsafe { T::Interrupt::enable() };
264 260
265 let regs = T::regs(); 261 super::common_init::<T>();
266
267 #[cfg(any(stm32l4, stm32l5, stm32wb))]
268 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
269
270 #[cfg(pwr_h5)]
271 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
272 262
273 <T as RccPeripheral>::enable_and_reset(); 263 let regs = T::regs();
274 264
275 regs.cntr().write(|w| { 265 regs.cntr().write(|w| {
276 w.set_pdwn(false); 266 w.set_pdwn(false);
@@ -287,8 +277,8 @@ impl<'d, T: Instance> Driver<'d, T> {
287 277
288 #[cfg(not(stm32l1))] 278 #[cfg(not(stm32l1))]
289 { 279 {
290 dp.set_as_af(dp.af_num(), crate::gpio::sealed::AFType::OutputPushPull); 280 dp.set_as_af(dp.af_num(), crate::gpio::AFType::OutputPushPull);
291 dm.set_as_af(dm.af_num(), crate::gpio::sealed::AFType::OutputPushPull); 281 dm.set_as_af(dm.af_num(), crate::gpio::AFType::OutputPushPull);
292 } 282 }
293 #[cfg(stm32l1)] 283 #[cfg(stm32l1)]
294 let _ = (dp, dm); // suppress "unused" warnings. 284 let _ = (dp, dm); // suppress "unused" warnings.
@@ -647,7 +637,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
647 637
648trait Dir { 638trait Dir {
649 fn dir() -> Direction; 639 fn dir() -> Direction;
650 fn waker(i: usize) -> &'static AtomicWaker;
651} 640}
652 641
653/// Marker type for the "IN" direction. 642/// Marker type for the "IN" direction.
@@ -656,11 +645,6 @@ impl Dir for In {
656 fn dir() -> Direction { 645 fn dir() -> Direction {
657 Direction::In 646 Direction::In
658 } 647 }
659
660 #[inline]
661 fn waker(i: usize) -> &'static AtomicWaker {
662 &EP_IN_WAKERS[i]
663 }
664} 648}
665 649
666/// Marker type for the "OUT" direction. 650/// Marker type for the "OUT" direction.
@@ -669,11 +653,6 @@ impl Dir for Out {
669 fn dir() -> Direction { 653 fn dir() -> Direction {
670 Direction::Out 654 Direction::Out
671 } 655 }
672
673 #[inline]
674 fn waker(i: usize) -> &'static AtomicWaker {
675 &EP_OUT_WAKERS[i]
676 }
677} 656}
678 657
679/// USB endpoint. 658/// USB endpoint.
@@ -1057,3 +1036,32 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1057 }); 1036 });
1058 } 1037 }
1059} 1038}
1039
1040trait SealedInstance {
1041 fn regs() -> crate::pac::usb::Usb;
1042}
1043
1044/// USB instance trait.
1045#[allow(private_bounds)]
1046pub trait Instance: SealedInstance + RccPeripheral + 'static {
1047 /// Interrupt for this USB instance.
1048 type Interrupt: interrupt::typelevel::Interrupt;
1049}
1050
1051// Internal PHY pins
1052pin_trait!(DpPin, Instance);
1053pin_trait!(DmPin, Instance);
1054
1055foreach_interrupt!(
1056 ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
1057 impl SealedInstance for crate::peripherals::$inst {
1058 fn regs() -> crate::pac::usb::Usb {
1059 crate::pac::$inst
1060 }
1061 }
1062
1063 impl Instance for crate::peripherals::$inst {
1064 type Interrupt = crate::interrupt::typelevel::$irq;
1065 }
1066 };
1067);
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
deleted file mode 100644
index 0649e684b..000000000
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ /dev/null
@@ -1,163 +0,0 @@
1//! USB On The Go (OTG)
2
3use crate::rcc::RccPeripheral;
4use crate::{interrupt, peripherals};
5
6mod usb;
7pub use usb::*;
8
9// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps
10const MAX_EP_COUNT: usize = 9;
11
12pub(crate) mod sealed {
13 pub trait Instance {
14 const HIGH_SPEED: bool;
15 const FIFO_DEPTH_WORDS: u16;
16 const ENDPOINT_COUNT: usize;
17
18 fn regs() -> crate::pac::otg::Otg;
19 fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>;
20 }
21}
22
23/// USB OTG instance.
24pub trait Instance: sealed::Instance + RccPeripheral {
25 /// Interrupt for this USB OTG instance.
26 type Interrupt: interrupt::typelevel::Interrupt;
27}
28
29// Internal PHY pins
30pin_trait!(DpPin, Instance);
31pin_trait!(DmPin, Instance);
32
33// External PHY pins
34pin_trait!(UlpiClkPin, Instance);
35pin_trait!(UlpiDirPin, Instance);
36pin_trait!(UlpiNxtPin, Instance);
37pin_trait!(UlpiStpPin, Instance);
38pin_trait!(UlpiD0Pin, Instance);
39pin_trait!(UlpiD1Pin, Instance);
40pin_trait!(UlpiD2Pin, Instance);
41pin_trait!(UlpiD3Pin, Instance);
42pin_trait!(UlpiD4Pin, Instance);
43pin_trait!(UlpiD5Pin, Instance);
44pin_trait!(UlpiD6Pin, Instance);
45pin_trait!(UlpiD7Pin, Instance);
46
47foreach_interrupt!(
48 (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
49 impl sealed::Instance for peripherals::USB_OTG_FS {
50 const HIGH_SPEED: bool = false;
51
52 cfg_if::cfg_if! {
53 if #[cfg(stm32f1)] {
54 const FIFO_DEPTH_WORDS: u16 = 128;
55 const ENDPOINT_COUNT: usize = 8;
56 } else if #[cfg(any(
57 stm32f2,
58 stm32f401,
59 stm32f405,
60 stm32f407,
61 stm32f411,
62 stm32f415,
63 stm32f417,
64 stm32f427,
65 stm32f429,
66 stm32f437,
67 stm32f439,
68 ))] {
69 const FIFO_DEPTH_WORDS: u16 = 320;
70 const ENDPOINT_COUNT: usize = 4;
71 } else if #[cfg(any(
72 stm32f412,
73 stm32f413,
74 stm32f423,
75 stm32f446,
76 stm32f469,
77 stm32f479,
78 stm32f7,
79 stm32l4,
80 stm32u5,
81 ))] {
82 const FIFO_DEPTH_WORDS: u16 = 320;
83 const ENDPOINT_COUNT: usize = 6;
84 } else if #[cfg(stm32g0x1)] {
85 const FIFO_DEPTH_WORDS: u16 = 512;
86 const ENDPOINT_COUNT: usize = 8;
87 } else if #[cfg(stm32h7)] {
88 const FIFO_DEPTH_WORDS: u16 = 1024;
89 const ENDPOINT_COUNT: usize = 9;
90 } else if #[cfg(stm32u5)] {
91 const FIFO_DEPTH_WORDS: u16 = 320;
92 const ENDPOINT_COUNT: usize = 6;
93 } else {
94 compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
95 }
96 }
97
98 fn regs() -> crate::pac::otg::Otg {
99 crate::pac::USB_OTG_FS
100 }
101
102 fn state() -> &'static State<MAX_EP_COUNT> {
103 static STATE: State<MAX_EP_COUNT> = State::new();
104 &STATE
105 }
106 }
107
108 impl Instance for peripherals::USB_OTG_FS {
109 type Interrupt = crate::interrupt::typelevel::$irq;
110 }
111 };
112
113 (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
114 impl sealed::Instance for peripherals::USB_OTG_HS {
115 const HIGH_SPEED: bool = true;
116
117 cfg_if::cfg_if! {
118 if #[cfg(any(
119 stm32f2,
120 stm32f405,
121 stm32f407,
122 stm32f415,
123 stm32f417,
124 stm32f427,
125 stm32f429,
126 stm32f437,
127 stm32f439,
128 ))] {
129 const FIFO_DEPTH_WORDS: u16 = 1024;
130 const ENDPOINT_COUNT: usize = 6;
131 } else if #[cfg(any(
132 stm32f446,
133 stm32f469,
134 stm32f479,
135 stm32f7,
136 stm32h7,
137 ))] {
138 const FIFO_DEPTH_WORDS: u16 = 1024;
139 const ENDPOINT_COUNT: usize = 9;
140 } else if #[cfg(stm32u5)] {
141 const FIFO_DEPTH_WORDS: u16 = 1024;
142 const ENDPOINT_COUNT: usize = 9;
143 } else {
144 compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
145 }
146 }
147
148 fn regs() -> crate::pac::otg::Otg {
149 // OTG HS registers are a superset of FS registers
150 unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
151 }
152
153 fn state() -> &'static State<MAX_EP_COUNT> {
154 static STATE: State<MAX_EP_COUNT> = State::new();
155 &STATE
156 }
157 }
158
159 impl Instance for peripherals::USB_OTG_HS {
160 type Interrupt = crate::interrupt::typelevel::$irq;
161 }
162 };
163);
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 2ff0db09e..ab21c4b6b 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -80,18 +80,17 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
80 } 80 }
81} 81}
82 82
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/channel.rs b/embassy-sync/src/channel.rs
index 01db0d09a..48f4dafd6 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -263,6 +263,12 @@ impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> {
263 } 263 }
264} 264}
265 265
266impl<'ch, M: RawMutex, T, const N: usize> From<ReceiveFuture<'ch, M, T, N>> for DynamicReceiveFuture<'ch, T> {
267 fn from(value: ReceiveFuture<'ch, M, T, N>) -> Self {
268 Self { channel: value.channel }
269 }
270}
271
266/// Future returned by [`Channel::send`] and [`Sender::send`]. 272/// Future returned by [`Channel::send`] and [`Sender::send`].
267#[must_use = "futures do nothing unless you `.await` or poll them"] 273#[must_use = "futures do nothing unless you `.await` or poll them"]
268pub struct SendFuture<'ch, M, T, const N: usize> 274pub struct SendFuture<'ch, M, T, const N: usize>
@@ -321,6 +327,15 @@ impl<'ch, T> Future for DynamicSendFuture<'ch, T> {
321 327
322impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} 328impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {}
323 329
330impl<'ch, M: RawMutex, T, const N: usize> From<SendFuture<'ch, M, T, N>> for DynamicSendFuture<'ch, T> {
331 fn from(value: SendFuture<'ch, M, T, N>) -> Self {
332 Self {
333 channel: value.channel,
334 message: value.message,
335 }
336 }
337}
338
324pub(crate) trait DynamicChannel<T> { 339pub(crate) trait DynamicChannel<T> {
325 fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; 340 fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>;
326 341
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
index 78e583c1c..2ac42c557 100644
--- a/embassy-sync/src/fmt.rs
+++ b/embassy-sync/src/fmt.rs
@@ -1,5 +1,5 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused)]
3 3
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..52c468b4a
--- /dev/null
+++ b/embassy-sync/src/semaphore.rs
@@ -0,0 +1,704 @@
1//! A synchronization primitive for controlling access to a pool of resources.
2use core::cell::{Cell, RefCell};
3use core::convert::Infallible;
4use core::future::poll_fn;
5use core::mem::MaybeUninit;
6use core::task::{Poll, Waker};
7
8use heapless::Deque;
9
10use crate::blocking_mutex::raw::RawMutex;
11use crate::blocking_mutex::Mutex;
12use crate::waitqueue::WakerRegistration;
13
14/// An asynchronous semaphore.
15///
16/// A semaphore tracks a number of permits, typically representing a pool of shared resources.
17/// Users can acquire permits to synchronize access to those resources. The semaphore does not
18/// contain the resources themselves, only the count of available permits.
19pub trait Semaphore: Sized {
20 /// The error returned when the semaphore is unable to acquire the requested permits.
21 type Error;
22
23 /// Asynchronously acquire one or more permits from the semaphore.
24 async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>;
25
26 /// Try to immediately acquire one or more permits from the semaphore.
27 fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>>;
28
29 /// Asynchronously acquire all permits controlled by the semaphore.
30 ///
31 /// This method will wait until at least `min` permits are available, then acquire all available permits
32 /// from the semaphore. Note that other tasks may have already acquired some permits which could be released
33 /// back to the semaphore at any time. The number of permits actually acquired may be determined by calling
34 /// [`SemaphoreReleaser::permits`].
35 async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error>;
36
37 /// Try to immediately acquire all available permits from the semaphore, if at least `min` permits are available.
38 fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>>;
39
40 /// Release `permits` back to the semaphore, making them available to be acquired.
41 fn release(&self, permits: usize);
42
43 /// Reset the number of available permints in the semaphore to `permits`.
44 fn set(&self, permits: usize);
45}
46
47/// A representation of a number of acquired permits.
48///
49/// The acquired permits will be released back to the [`Semaphore`] when this is dropped.
50pub struct SemaphoreReleaser<'a, S: Semaphore> {
51 semaphore: &'a S,
52 permits: usize,
53}
54
55impl<'a, S: Semaphore> Drop for SemaphoreReleaser<'a, S> {
56 fn drop(&mut self) {
57 self.semaphore.release(self.permits);
58 }
59}
60
61impl<'a, S: Semaphore> SemaphoreReleaser<'a, S> {
62 /// The number of acquired permits.
63 pub fn permits(&self) -> usize {
64 self.permits
65 }
66
67 /// Prevent the acquired permits from being released on drop.
68 ///
69 /// Returns the number of acquired permits.
70 pub fn disarm(self) -> usize {
71 let permits = self.permits;
72 core::mem::forget(self);
73 permits
74 }
75}
76
77/// A greedy [`Semaphore`] implementation.
78///
79/// Tasks can acquire permits as soon as they become available, even if another task
80/// is waiting on a larger number of permits.
81pub struct GreedySemaphore<M: RawMutex> {
82 state: Mutex<M, Cell<SemaphoreState>>,
83}
84
85impl<M: RawMutex> Default for GreedySemaphore<M> {
86 fn default() -> Self {
87 Self::new(0)
88 }
89}
90
91impl<M: RawMutex> GreedySemaphore<M> {
92 /// Create a new `Semaphore`.
93 pub const fn new(permits: usize) -> Self {
94 Self {
95 state: Mutex::new(Cell::new(SemaphoreState {
96 permits,
97 waker: WakerRegistration::new(),
98 })),
99 }
100 }
101
102 #[cfg(test)]
103 fn permits(&self) -> usize {
104 self.state.lock(|cell| {
105 let state = cell.replace(SemaphoreState::EMPTY);
106 let permits = state.permits;
107 cell.replace(state);
108 permits
109 })
110 }
111
112 fn poll_acquire(
113 &self,
114 permits: usize,
115 acquire_all: bool,
116 waker: Option<&Waker>,
117 ) -> Poll<Result<SemaphoreReleaser<'_, Self>, Infallible>> {
118 self.state.lock(|cell| {
119 let mut state = cell.replace(SemaphoreState::EMPTY);
120 if let Some(permits) = state.take(permits, acquire_all) {
121 cell.set(state);
122 Poll::Ready(Ok(SemaphoreReleaser {
123 semaphore: self,
124 permits,
125 }))
126 } else {
127 if let Some(waker) = waker {
128 state.register(waker);
129 }
130 cell.set(state);
131 Poll::Pending
132 }
133 })
134 }
135}
136
137impl<M: RawMutex> Semaphore for GreedySemaphore<M> {
138 type Error = Infallible;
139
140 async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> {
141 poll_fn(|cx| self.poll_acquire(permits, false, Some(cx.waker()))).await
142 }
143
144 fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> {
145 match self.poll_acquire(permits, false, None) {
146 Poll::Ready(Ok(n)) => Some(n),
147 _ => None,
148 }
149 }
150
151 async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> {
152 poll_fn(|cx| self.poll_acquire(min, true, Some(cx.waker()))).await
153 }
154
155 fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> {
156 match self.poll_acquire(min, true, None) {
157 Poll::Ready(Ok(n)) => Some(n),
158 _ => None,
159 }
160 }
161
162 fn release(&self, permits: usize) {
163 if permits > 0 {
164 self.state.lock(|cell| {
165 let mut state = cell.replace(SemaphoreState::EMPTY);
166 state.permits += permits;
167 state.wake();
168 cell.set(state);
169 });
170 }
171 }
172
173 fn set(&self, permits: usize) {
174 self.state.lock(|cell| {
175 let mut state = cell.replace(SemaphoreState::EMPTY);
176 if permits > state.permits {
177 state.wake();
178 }
179 state.permits = permits;
180 cell.set(state);
181 });
182 }
183}
184
185struct SemaphoreState {
186 permits: usize,
187 waker: WakerRegistration,
188}
189
190impl SemaphoreState {
191 const EMPTY: SemaphoreState = SemaphoreState {
192 permits: 0,
193 waker: WakerRegistration::new(),
194 };
195
196 fn register(&mut self, w: &Waker) {
197 self.waker.register(w);
198 }
199
200 fn take(&mut self, mut permits: usize, acquire_all: bool) -> Option<usize> {
201 if self.permits < permits {
202 None
203 } else {
204 if acquire_all {
205 permits = self.permits;
206 }
207 self.permits -= permits;
208 Some(permits)
209 }
210 }
211
212 fn wake(&mut self) {
213 self.waker.wake();
214 }
215}
216
217/// A fair [`Semaphore`] implementation.
218///
219/// Tasks are allowed to acquire permits in FIFO order. A task waiting to acquire
220/// a large number of permits will prevent other tasks from acquiring any permits
221/// until its request is satisfied.
222///
223/// Up to `N` tasks may attempt to acquire permits concurrently. If additional
224/// tasks attempt to acquire a permit, a [`WaitQueueFull`] error will be returned.
225pub struct FairSemaphore<M, const N: usize>
226where
227 M: RawMutex,
228{
229 state: Mutex<M, RefCell<FairSemaphoreState<N>>>,
230}
231
232impl<M, const N: usize> Default for FairSemaphore<M, N>
233where
234 M: RawMutex,
235{
236 fn default() -> Self {
237 Self::new(0)
238 }
239}
240
241impl<M, const N: usize> FairSemaphore<M, N>
242where
243 M: RawMutex,
244{
245 /// Create a new `FairSemaphore`.
246 pub const fn new(permits: usize) -> Self {
247 Self {
248 state: Mutex::new(RefCell::new(FairSemaphoreState::new(permits))),
249 }
250 }
251
252 #[cfg(test)]
253 fn permits(&self) -> usize {
254 self.state.lock(|cell| cell.borrow().permits)
255 }
256
257 fn poll_acquire(
258 &self,
259 permits: usize,
260 acquire_all: bool,
261 cx: Option<(&Cell<Option<usize>>, &Waker)>,
262 ) -> Poll<Result<SemaphoreReleaser<'_, Self>, WaitQueueFull>> {
263 let ticket = cx.as_ref().map(|(cell, _)| cell.get()).unwrap_or(None);
264 self.state.lock(|cell| {
265 let mut state = cell.borrow_mut();
266 if let Some(permits) = state.take(ticket, permits, acquire_all) {
267 Poll::Ready(Ok(SemaphoreReleaser {
268 semaphore: self,
269 permits,
270 }))
271 } else if let Some((cell, waker)) = cx {
272 match state.register(ticket, waker) {
273 Ok(ticket) => {
274 cell.set(Some(ticket));
275 Poll::Pending
276 }
277 Err(err) => Poll::Ready(Err(err)),
278 }
279 } else {
280 Poll::Pending
281 }
282 })
283 }
284}
285
286/// An error indicating the [`FairSemaphore`]'s wait queue is full.
287#[derive(Debug, Clone, Copy, PartialEq, Eq)]
288#[cfg_attr(feature = "defmt", derive(defmt::Format))]
289pub struct WaitQueueFull;
290
291impl<M: RawMutex, const N: usize> Semaphore for FairSemaphore<M, N> {
292 type Error = WaitQueueFull;
293
294 async fn acquire(&self, permits: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> {
295 let ticket = Cell::new(None);
296 let _guard = OnDrop::new(|| self.state.lock(|cell| cell.borrow_mut().cancel(ticket.get())));
297 poll_fn(|cx| self.poll_acquire(permits, false, Some((&ticket, cx.waker())))).await
298 }
299
300 fn try_acquire(&self, permits: usize) -> Option<SemaphoreReleaser<'_, Self>> {
301 match self.poll_acquire(permits, false, None) {
302 Poll::Ready(Ok(x)) => Some(x),
303 _ => None,
304 }
305 }
306
307 async fn acquire_all(&self, min: usize) -> Result<SemaphoreReleaser<'_, Self>, Self::Error> {
308 let ticket = Cell::new(None);
309 let _guard = OnDrop::new(|| self.state.lock(|cell| cell.borrow_mut().cancel(ticket.get())));
310 poll_fn(|cx| self.poll_acquire(min, true, Some((&ticket, cx.waker())))).await
311 }
312
313 fn try_acquire_all(&self, min: usize) -> Option<SemaphoreReleaser<'_, Self>> {
314 match self.poll_acquire(min, true, None) {
315 Poll::Ready(Ok(x)) => Some(x),
316 _ => None,
317 }
318 }
319
320 fn release(&self, permits: usize) {
321 if permits > 0 {
322 self.state.lock(|cell| {
323 let mut state = cell.borrow_mut();
324 state.permits += permits;
325 state.wake();
326 });
327 }
328 }
329
330 fn set(&self, permits: usize) {
331 self.state.lock(|cell| {
332 let mut state = cell.borrow_mut();
333 if permits > state.permits {
334 state.wake();
335 }
336 state.permits = permits;
337 });
338 }
339}
340
341struct FairSemaphoreState<const N: usize> {
342 permits: usize,
343 next_ticket: usize,
344 wakers: Deque<Option<Waker>, N>,
345}
346
347impl<const N: usize> FairSemaphoreState<N> {
348 /// Create a new empty instance
349 const fn new(permits: usize) -> Self {
350 Self {
351 permits,
352 next_ticket: 0,
353 wakers: Deque::new(),
354 }
355 }
356
357 /// Register a waker. If the queue is full the function returns an error
358 fn register(&mut self, ticket: Option<usize>, w: &Waker) -> Result<usize, WaitQueueFull> {
359 self.pop_canceled();
360
361 match ticket {
362 None => {
363 let ticket = self.next_ticket.wrapping_add(self.wakers.len());
364 self.wakers.push_back(Some(w.clone())).or(Err(WaitQueueFull))?;
365 Ok(ticket)
366 }
367 Some(ticket) => {
368 self.set_waker(ticket, Some(w.clone()));
369 Ok(ticket)
370 }
371 }
372 }
373
374 fn cancel(&mut self, ticket: Option<usize>) {
375 if let Some(ticket) = ticket {
376 self.set_waker(ticket, None);
377 }
378 }
379
380 fn set_waker(&mut self, ticket: usize, waker: Option<Waker>) {
381 let i = ticket.wrapping_sub(self.next_ticket);
382 if i < self.wakers.len() {
383 let (a, b) = self.wakers.as_mut_slices();
384 let x = if i < a.len() { &mut a[i] } else { &mut b[i - a.len()] };
385 *x = waker;
386 }
387 }
388
389 fn take(&mut self, ticket: Option<usize>, mut permits: usize, acquire_all: bool) -> Option<usize> {
390 self.pop_canceled();
391
392 if permits > self.permits {
393 return None;
394 }
395
396 match ticket {
397 Some(n) if n != self.next_ticket => return None,
398 None if !self.wakers.is_empty() => return None,
399 _ => (),
400 }
401
402 if acquire_all {
403 permits = self.permits;
404 }
405 self.permits -= permits;
406
407 if ticket.is_some() {
408 self.pop();
409 }
410
411 Some(permits)
412 }
413
414 fn pop_canceled(&mut self) {
415 while let Some(None) = self.wakers.front() {
416 self.pop();
417 }
418 }
419
420 /// Panics if `self.wakers` is empty
421 fn pop(&mut self) {
422 self.wakers.pop_front().unwrap();
423 self.next_ticket = self.next_ticket.wrapping_add(1);
424 }
425
426 fn wake(&mut self) {
427 self.pop_canceled();
428
429 if let Some(Some(waker)) = self.wakers.front() {
430 waker.wake_by_ref();
431 }
432 }
433}
434
435/// A type to delay the drop handler invocation.
436#[must_use = "to delay the drop handler invocation to the end of the scope"]
437struct OnDrop<F: FnOnce()> {
438 f: MaybeUninit<F>,
439}
440
441impl<F: FnOnce()> OnDrop<F> {
442 /// Create a new instance.
443 pub fn new(f: F) -> Self {
444 Self { f: MaybeUninit::new(f) }
445 }
446}
447
448impl<F: FnOnce()> Drop for OnDrop<F> {
449 fn drop(&mut self) {
450 unsafe { self.f.as_ptr().read()() }
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 mod greedy {
457 use core::pin::pin;
458
459 use futures_util::poll;
460
461 use super::super::*;
462 use crate::blocking_mutex::raw::NoopRawMutex;
463
464 #[test]
465 fn try_acquire() {
466 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
467
468 let a = semaphore.try_acquire(1).unwrap();
469 assert_eq!(a.permits(), 1);
470 assert_eq!(semaphore.permits(), 2);
471
472 core::mem::drop(a);
473 assert_eq!(semaphore.permits(), 3);
474 }
475
476 #[test]
477 fn disarm() {
478 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
479
480 let a = semaphore.try_acquire(1).unwrap();
481 assert_eq!(a.disarm(), 1);
482 assert_eq!(semaphore.permits(), 2);
483 }
484
485 #[futures_test::test]
486 async fn acquire() {
487 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
488
489 let a = semaphore.acquire(1).await.unwrap();
490 assert_eq!(a.permits(), 1);
491 assert_eq!(semaphore.permits(), 2);
492
493 core::mem::drop(a);
494 assert_eq!(semaphore.permits(), 3);
495 }
496
497 #[test]
498 fn try_acquire_all() {
499 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
500
501 let a = semaphore.try_acquire_all(1).unwrap();
502 assert_eq!(a.permits(), 3);
503 assert_eq!(semaphore.permits(), 0);
504 }
505
506 #[futures_test::test]
507 async fn acquire_all() {
508 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
509
510 let a = semaphore.acquire_all(1).await.unwrap();
511 assert_eq!(a.permits(), 3);
512 assert_eq!(semaphore.permits(), 0);
513 }
514
515 #[test]
516 fn release() {
517 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
518 assert_eq!(semaphore.permits(), 3);
519 semaphore.release(2);
520 assert_eq!(semaphore.permits(), 5);
521 }
522
523 #[test]
524 fn set() {
525 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
526 assert_eq!(semaphore.permits(), 3);
527 semaphore.set(2);
528 assert_eq!(semaphore.permits(), 2);
529 }
530
531 #[test]
532 fn contested() {
533 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
534
535 let a = semaphore.try_acquire(1).unwrap();
536 let b = semaphore.try_acquire(3);
537 assert!(b.is_none());
538
539 core::mem::drop(a);
540
541 let b = semaphore.try_acquire(3);
542 assert!(b.is_some());
543 }
544
545 #[futures_test::test]
546 async fn greedy() {
547 let semaphore = GreedySemaphore::<NoopRawMutex>::new(3);
548
549 let a = semaphore.try_acquire(1).unwrap();
550
551 let b_fut = semaphore.acquire(3);
552 let mut b_fut = pin!(b_fut);
553 let b = poll!(b_fut.as_mut());
554 assert!(b.is_pending());
555
556 // Succeed even through `b` is waiting
557 let c = semaphore.try_acquire(1);
558 assert!(c.is_some());
559
560 let b = poll!(b_fut.as_mut());
561 assert!(b.is_pending());
562
563 core::mem::drop(a);
564
565 let b = poll!(b_fut.as_mut());
566 assert!(b.is_pending());
567
568 core::mem::drop(c);
569
570 let b = poll!(b_fut.as_mut());
571 assert!(b.is_ready());
572 }
573 }
574
575 mod fair {
576 use core::pin::pin;
577
578 use futures_util::poll;
579
580 use super::super::*;
581 use crate::blocking_mutex::raw::NoopRawMutex;
582
583 #[test]
584 fn try_acquire() {
585 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
586
587 let a = semaphore.try_acquire(1).unwrap();
588 assert_eq!(a.permits(), 1);
589 assert_eq!(semaphore.permits(), 2);
590
591 core::mem::drop(a);
592 assert_eq!(semaphore.permits(), 3);
593 }
594
595 #[test]
596 fn disarm() {
597 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
598
599 let a = semaphore.try_acquire(1).unwrap();
600 assert_eq!(a.disarm(), 1);
601 assert_eq!(semaphore.permits(), 2);
602 }
603
604 #[futures_test::test]
605 async fn acquire() {
606 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
607
608 let a = semaphore.acquire(1).await.unwrap();
609 assert_eq!(a.permits(), 1);
610 assert_eq!(semaphore.permits(), 2);
611
612 core::mem::drop(a);
613 assert_eq!(semaphore.permits(), 3);
614 }
615
616 #[test]
617 fn try_acquire_all() {
618 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
619
620 let a = semaphore.try_acquire_all(1).unwrap();
621 assert_eq!(a.permits(), 3);
622 assert_eq!(semaphore.permits(), 0);
623 }
624
625 #[futures_test::test]
626 async fn acquire_all() {
627 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
628
629 let a = semaphore.acquire_all(1).await.unwrap();
630 assert_eq!(a.permits(), 3);
631 assert_eq!(semaphore.permits(), 0);
632 }
633
634 #[test]
635 fn release() {
636 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
637 assert_eq!(semaphore.permits(), 3);
638 semaphore.release(2);
639 assert_eq!(semaphore.permits(), 5);
640 }
641
642 #[test]
643 fn set() {
644 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
645 assert_eq!(semaphore.permits(), 3);
646 semaphore.set(2);
647 assert_eq!(semaphore.permits(), 2);
648 }
649
650 #[test]
651 fn contested() {
652 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
653
654 let a = semaphore.try_acquire(1).unwrap();
655 let b = semaphore.try_acquire(3);
656 assert!(b.is_none());
657
658 core::mem::drop(a);
659
660 let b = semaphore.try_acquire(3);
661 assert!(b.is_some());
662 }
663
664 #[futures_test::test]
665 async fn fairness() {
666 let semaphore = FairSemaphore::<NoopRawMutex, 2>::new(3);
667
668 let a = semaphore.try_acquire(1);
669 assert!(a.is_some());
670
671 let b_fut = semaphore.acquire(3);
672 let mut b_fut = pin!(b_fut);
673 let b = poll!(b_fut.as_mut()); // Poll `b_fut` once so it is registered
674 assert!(b.is_pending());
675
676 let c = semaphore.try_acquire(1);
677 assert!(c.is_none());
678
679 let c_fut = semaphore.acquire(1);
680 let mut c_fut = pin!(c_fut);
681 let c = poll!(c_fut.as_mut()); // Poll `c_fut` once so it is registered
682 assert!(c.is_pending()); // `c` is blocked behind `b`
683
684 let d = semaphore.acquire(1).await;
685 assert!(matches!(d, Err(WaitQueueFull)));
686
687 core::mem::drop(a);
688
689 let c = poll!(c_fut.as_mut());
690 assert!(c.is_pending()); // `c` is still blocked behind `b`
691
692 let b = poll!(b_fut.as_mut());
693 assert!(b.is_ready());
694
695 let c = poll!(c_fut.as_mut());
696 assert!(c.is_pending()); // `c` is still blocked behind `b`
697
698 core::mem::drop(b);
699
700 let c = poll!(c_fut.as_mut());
701 assert!(c.is_ready());
702 }
703 }
704}
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index d75750ce7..520f1a896 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -125,7 +125,7 @@ where
125 }) 125 })
126 } 126 }
127 127
128 /// non-blocking method to check whether this signal has been signaled. 128 /// non-blocking method to check whether this signal has been signaled. This does not clear the signal.
129 pub fn signaled(&self) -> bool { 129 pub fn signaled(&self) -> bool {
130 self.state.lock(|cell| { 130 self.state.lock(|cell| {
131 let state = cell.replace(State::None); 131 let state = cell.replace(State::None);
diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs
index 78e583c1c..2ac42c557 100644
--- a/embassy-time/src/fmt.rs
+++ b/embassy-time/src/fmt.rs
@@ -1,5 +1,5 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused)]
3 3
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 c1c4f8359..1c13d623d 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -3,11 +3,14 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::can::bxcan::filter::Mask32; 6use embassy_stm32::can::frame::Envelope;
7use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; 7use embassy_stm32::can::{
8use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; 8 filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
9 TxInterruptHandler,
10};
9use embassy_stm32::peripherals::CAN; 11use embassy_stm32::peripherals::CAN;
10use embassy_stm32::{bind_interrupts, Config}; 12use embassy_stm32::{bind_interrupts, Config};
13use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
12 15
13bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
@@ -20,6 +23,27 @@ bind_interrupts!(struct Irqs {
20// This example is configured to work with real CAN transceivers on B8/B9. 23// This example is configured to work with real CAN transceivers on B8/B9.
21// See other examples for loopback. 24// See other examples for loopback.
22 25
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
23#[embassy_executor::main] 47#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 48async fn main(_spawner: Spawner) {
25 let p = embassy_stm32::init(Config::default()); 49 let p = embassy_stm32::init(Config::default());
@@ -27,36 +51,86 @@ async fn main(_spawner: Spawner) {
27 // Set alternate pin mapping to B8/B9 51 // Set alternate pin mapping to B8/B9
28 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); 52 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
29 53
54 static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new();
55 static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new();
56
30 let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); 57 let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
31 58
32 can.as_mut() 59 can.modify_filters()
33 .modify_filters() 60 .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all());
34 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
35 61
36 can.as_mut() 62 can.modify_config()
37 .modify_config()
38 .set_loopback(false) 63 .set_loopback(false)
39 .set_silent(false) 64 .set_silent(false)
40 .leave_disabled(); 65 .set_bitrate(250_000);
41
42 can.set_bitrate(250_000);
43 66
44 can.enable().await; 67 can.enable().await;
45
46 let mut i: u8 = 0; 68 let mut i: u8 = 0;
69
70 /*
71 // Example for using buffered Tx and Rx without needing to
72 // split first as is done below.
73 let mut can = can.buffered(
74 TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()),
75 RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
76 loop {
77 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
78 can.write(&tx_frame).await;
79
80 match can.read().await {
81 Ok((frame, ts)) => {
82 handle_frame(Envelope { ts, frame }, "Buf");
83 }
84 Err(err) => {
85 defmt::println!("Error {}", err);
86 }
87 }
88 i += 1;
89 }
90
91 */
92 let (mut tx, mut rx) = can.split();
93
94 // This example shows using the wait_not_empty API before try read
95 while i < 3 {
96 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
97 tx.write(&tx_frame).await;
98
99 rx.wait_not_empty().await;
100 let env = rx.try_read().unwrap();
101 handle_frame(env, "Wait");
102 i += 1;
103 }
104
105 // This example shows using the full async non-buffered API
106 while i < 6 {
107 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
108 tx.write(&tx_frame).await;
109
110 match rx.read().await {
111 Ok(env) => {
112 handle_frame(env, "NoBuf");
113 }
114 Err(err) => {
115 defmt::println!("Error {}", err);
116 }
117 }
118 i += 1;
119 }
120
121 // This example shows using buffered RX and TX. User passes in desired buffer (size)
122 // It's possible this way to have just RX or TX buffered.
123 let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
124 let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()));
125
47 loop { 126 loop {
48 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 127 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
49 can.write(&tx_frame).await; 128 tx.write(&tx_frame).await;
50 129
51 match can.read().await { 130 match rx.read().await {
52 Ok(env) => match env.frame.id() { 131 Ok(envelope) => {
53 Id::Extended(id) => { 132 handle_frame(envelope, "Buf");
54 defmt::println!("Extended Frame id={:x}", id.as_raw()); 133 }
55 }
56 Id::Standard(id) => {
57 defmt::println!("Standard Frame id={:x}", id.as_raw());
58 }
59 },
60 Err(err) => { 134 Err(err) => {
61 defmt::println!("Error {}", err); 135 defmt::println!("Error {}", err);
62 } 136 }
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index 1ae6c1dee..ee99acf41 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) {
60 60
61 // Create embassy-usb DeviceBuilder using the driver and config. 61 // Create embassy-usb DeviceBuilder using the driver and config.
62 // It needs some buffers for building the descriptors. 62 // It needs some buffers for building the descriptors.
63 let mut device_descriptor = [0; 256];
64 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
65 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
66 let mut control_buf = [0; 7]; 65 let mut control_buf = [0; 7];
@@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) {
70 let mut builder = Builder::new( 69 let mut builder = Builder::new(
71 driver, 70 driver,
72 config, 71 config,
73 &mut device_descriptor,
74 &mut config_descriptor, 72 &mut config_descriptor,
75 &mut bos_descriptor, 73 &mut bos_descriptor,
76 &mut [], // no msos descriptors 74 &mut [], // no msos descriptors
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs
index e32f283d1..e39e2daec 100644
--- a/examples/stm32f2/src/bin/pll.rs
+++ b/examples/stm32f2/src/bin/pll.rs
@@ -1,8 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
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 d074b4265..cedc057a7 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -4,9 +4,10 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::bind_interrupts; 6use embassy_stm32::bind_interrupts;
7use embassy_stm32::can::bxcan::filter::Mask32; 7use embassy_stm32::can::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 8use embassy_stm32::can::{
9use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; 9 Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler,
10};
10use embassy_stm32::gpio::{Input, Pull}; 11use embassy_stm32::gpio::{Input, Pull};
11use embassy_stm32::peripherals::CAN1; 12use embassy_stm32::peripherals::CAN1;
12use embassy_time::Instant; 13use embassy_time::Instant;
@@ -34,23 +35,18 @@ async fn main(_spawner: Spawner) {
34 35
35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); 36 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
36 37
37 can.as_mut() 38 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
38 .modify_filters()
39 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
40 39
41 can.as_mut() 40 can.modify_config()
42 .modify_config()
43 .set_loopback(true) // Receive own frames 41 .set_loopback(true) // Receive own frames
44 .set_silent(true) 42 .set_silent(true)
45 .leave_disabled(); 43 .set_bitrate(1_000_000);
46
47 can.set_bitrate(1_000_000);
48 44
49 can.enable().await; 45 can.enable().await;
50 46
51 let mut i: u8 = 0; 47 let mut i: u8 = 0;
52 loop { 48 loop {
53 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
54 let tx_ts = Instant::now(); 50 let tx_ts = Instant::now();
55 can.write(&tx_frame).await; 51 can.write(&tx_frame).await;
56 52
@@ -64,7 +60,7 @@ async fn main(_spawner: Spawner) {
64 60
65 info!( 61 info!(
66 "loopback frame {=u8}, latency: {} us", 62 "loopback frame {=u8}, latency: {} us",
67 unwrap!(envelope.frame.data())[0], 63 envelope.frame.data()[0],
68 latency.as_micros() 64 latency.as_micros()
69 ); 65 );
70 i += 1; 66 i += 1;
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index a196259a8..d2cbeea1b 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -7,8 +7,8 @@ use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::{Stack, StackResources};
8use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
9use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb_otg::Driver; 10use embassy_stm32::usb::Driver;
11use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 11use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
14use embassy_usb::{Builder, UsbDevice}; 14use embassy_usb::{Builder, UsbDevice};
@@ -36,7 +36,7 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
36} 36}
37 37
38bind_interrupts!(struct Irqs { 38bind_interrupts!(struct Irqs {
39 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 39 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
40 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 40 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
41}); 41});
42 42
@@ -63,13 +63,14 @@ async fn main(spawner: Spawner) {
63 config.rcc.apb1_pre = APBPrescaler::DIV4; 63 config.rcc.apb1_pre = APBPrescaler::DIV4;
64 config.rcc.apb2_pre = APBPrescaler::DIV2; 64 config.rcc.apb2_pre = APBPrescaler::DIV2;
65 config.rcc.sys = Sysclk::PLL1_P; 65 config.rcc.sys = Sysclk::PLL1_P;
66 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
66 } 67 }
67 let p = embassy_stm32::init(config); 68 let p = embassy_stm32::init(config);
68 69
69 // Create the driver, from the HAL. 70 // Create the driver, from the HAL.
70 static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); 71 static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new();
71 let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; 72 let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..];
72 let mut config = embassy_stm32::usb_otg::Config::default(); 73 let mut config = embassy_stm32::usb::Config::default();
73 config.vbus_detection = true; 74 config.vbus_detection = true;
74 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); 75 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
75 76
@@ -88,14 +89,12 @@ async fn main(spawner: Spawner) {
88 config.device_protocol = 0x01; 89 config.device_protocol = 0x01;
89 90
90 // Create embassy-usb DeviceBuilder using the driver and config. 91 // Create embassy-usb DeviceBuilder using the driver and config.
91 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
92 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 92 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
93 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 93 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
94 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); 94 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
95 let mut builder = Builder::new( 95 let mut builder = Builder::new(
96 driver, 96 driver,
97 config, 97 config,
98 &mut DEVICE_DESC.init([0; 256])[..],
99 &mut CONFIG_DESC.init([0; 256])[..], 98 &mut CONFIG_DESC.init([0; 256])[..],
100 &mut BOS_DESC.init([0; 256])[..], 99 &mut BOS_DESC.init([0; 256])[..],
101 &mut [], // no msos descriptors 100 &mut [], // no msos descriptors
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..a799b4e72
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,221 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::exti::ExtiInput;
9use embassy_stm32::gpio::Pull;
10use embassy_stm32::time::Hertz;
11use embassy_stm32::usb::Driver;
12use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
14use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Handler};
16use futures::future::join;
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let mut config = Config::default();
27 {
28 use embassy_stm32::rcc::*;
29 config.rcc.hse = Some(Hse {
30 freq: Hertz(8_000_000),
31 mode: HseMode::Bypass,
32 });
33 config.rcc.pll_src = PllSource::HSE;
34 config.rcc.pll = Some(Pll {
35 prediv: PllPreDiv::DIV4,
36 mul: PllMul::MUL168,
37 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
38 divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
39 divr: None,
40 });
41 config.rcc.ahb_pre = AHBPrescaler::DIV1;
42 config.rcc.apb1_pre = APBPrescaler::DIV4;
43 config.rcc.apb2_pre = APBPrescaler::DIV2;
44 config.rcc.sys = Sysclk::PLL1_P;
45 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
46 }
47 let p = embassy_stm32::init(config);
48
49 // Create the driver, from the HAL.
50 let mut ep_out_buffer = [0u8; 256];
51 let mut config = embassy_stm32::usb::Config::default();
52 config.vbus_detection = true;
53 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
54
55 // Create embassy-usb Config
56 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
57 config.manufacturer = Some("Embassy");
58 config.product = Some("HID keyboard example");
59 config.serial_number = Some("12345678");
60 config.max_power = 100;
61 config.max_packet_size_0 = 64;
62
63 // Required for windows compatibility.
64 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
65 config.device_class = 0xEF;
66 config.device_sub_class = 0x02;
67 config.device_protocol = 0x01;
68 config.composite_with_iads = true;
69
70 // Create embassy-usb DeviceBuilder using the driver and config.
71 // It needs some buffers for building the descriptors.
72 let mut config_descriptor = [0; 256];
73 let mut bos_descriptor = [0; 256];
74 // You can also add a Microsoft OS descriptor.
75 let mut msos_descriptor = [0; 256];
76 let mut control_buf = [0; 64];
77
78 let request_handler = MyRequestHandler {};
79 let mut device_handler = MyDeviceHandler::new();
80
81 let mut state = State::new();
82
83 let mut builder = Builder::new(
84 driver,
85 config,
86 &mut config_descriptor,
87 &mut bos_descriptor,
88 &mut msos_descriptor,
89 &mut control_buf,
90 );
91
92 builder.handler(&mut device_handler);
93
94 // Create classes on the builder.
95 let config = embassy_usb::class::hid::Config {
96 report_descriptor: KeyboardReport::desc(),
97 request_handler: Some(&request_handler),
98 poll_ms: 60,
99 max_packet_size: 8,
100 };
101
102 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
103
104 // Build the builder.
105 let mut usb = builder.build();
106
107 // Run the USB device.
108 let usb_fut = usb.run();
109
110 let (reader, mut writer) = hid.split();
111
112 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
113
114 // Do stuff with the class!
115 let in_fut = async {
116 loop {
117 button.wait_for_rising_edge().await;
118 // signal_pin.wait_for_high().await;
119 info!("Button pressed!");
120 // Create a report with the A key pressed. (no shift modifier)
121 let report = KeyboardReport {
122 keycodes: [4, 0, 0, 0, 0, 0],
123 leds: 0,
124 modifier: 0,
125 reserved: 0,
126 };
127 // Send the report.
128 match writer.write_serialize(&report).await {
129 Ok(()) => {}
130 Err(e) => warn!("Failed to send report: {:?}", e),
131 };
132
133 button.wait_for_falling_edge().await;
134 // signal_pin.wait_for_low().await;
135 info!("Button released!");
136 let report = KeyboardReport {
137 keycodes: [0, 0, 0, 0, 0, 0],
138 leds: 0,
139 modifier: 0,
140 reserved: 0,
141 };
142 match writer.write_serialize(&report).await {
143 Ok(()) => {}
144 Err(e) => warn!("Failed to send report: {:?}", e),
145 };
146 }
147 };
148
149 let out_fut = async {
150 reader.run(false, &request_handler).await;
151 };
152
153 // Run everything concurrently.
154 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
155 join(usb_fut, join(in_fut, out_fut)).await;
156}
157
158struct MyRequestHandler {}
159
160impl RequestHandler for MyRequestHandler {
161 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
162 info!("Get report for {:?}", id);
163 None
164 }
165
166 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
167 info!("Set report for {:?}: {=[u8]}", id, data);
168 OutResponse::Accepted
169 }
170
171 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
172 info!("Set idle rate for {:?} to {:?}", id, dur);
173 }
174
175 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
176 info!("Get idle rate for {:?}", id);
177 None
178 }
179}
180
181struct MyDeviceHandler {
182 configured: AtomicBool,
183}
184
185impl MyDeviceHandler {
186 fn new() -> Self {
187 MyDeviceHandler {
188 configured: AtomicBool::new(false),
189 }
190 }
191}
192
193impl Handler for MyDeviceHandler {
194 fn enabled(&mut self, enabled: bool) {
195 self.configured.store(false, Ordering::Relaxed);
196 if enabled {
197 info!("Device enabled");
198 } else {
199 info!("Device disabled");
200 }
201 }
202
203 fn reset(&mut self) {
204 self.configured.store(false, Ordering::Relaxed);
205 info!("Bus reset, the Vbus current limit is 100mA");
206 }
207
208 fn addressed(&mut self, addr: u8) {
209 self.configured.store(false, Ordering::Relaxed);
210 info!("USB address set to: {}", addr);
211 }
212
213 fn configured(&mut self, configured: bool) {
214 self.configured.store(configured, Ordering::Relaxed);
215 if configured {
216 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
217 } else {
218 info!("Device is no longer configured, the Vbus current limit is 100mA.");
219 }
220 }
221}
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index c98792880..0bc236119 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -4,8 +4,8 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::Driver; 7use embassy_stm32::usb::Driver;
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_time::Timer; 9use embassy_time::Timer;
10use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 10use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
11use embassy_usb::control::OutResponse; 11use embassy_usb::control::OutResponse;
@@ -15,7 +15,7 @@ use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
18 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 18 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
19}); 19});
20 20
21#[embassy_executor::main] 21#[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
39 config.rcc.apb1_pre = APBPrescaler::DIV4; 39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P; 41 config.rcc.sys = Sysclk::PLL1_P;
42 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
42 } 43 }
43 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
44 45
45 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256]; 47 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default(); 48 let mut config = embassy_stm32::usb::Config::default();
48 config.vbus_detection = true; 49 config.vbus_detection = true;
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 50 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50 51
@@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) {
63 64
64 // Create embassy-usb DeviceBuilder using the driver and config. 65 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors. 66 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256]; 67 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256]; 68 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64]; 69 let mut control_buf = [0; 64];
@@ -75,7 +75,6 @@ async fn main(_spawner: Spawner) {
75 let mut builder = Builder::new( 75 let mut builder = Builder::new(
76 driver, 76 driver,
77 config, 77 config,
78 &mut device_descriptor,
79 &mut config_descriptor, 78 &mut config_descriptor,
80 &mut bos_descriptor, 79 &mut bos_descriptor,
81 &mut [], // no msos descriptors 80 &mut [], // no msos descriptors
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index afff55187..4e583aeb8 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -52,8 +52,8 @@
52use defmt::*; 52use defmt::*;
53use embassy_executor::Spawner; 53use embassy_executor::Spawner;
54use embassy_stm32::time::Hertz; 54use embassy_stm32::time::Hertz;
55use embassy_stm32::usb_otg::Driver; 55use embassy_stm32::usb::Driver;
56use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 56use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; 57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
58use embassy_usb::msos::{self, windows_version}; 58use embassy_usb::msos::{self, windows_version};
59use embassy_usb::types::InterfaceNumber; 59use embassy_usb::types::InterfaceNumber;
@@ -66,7 +66,7 @@ use {defmt_rtt as _, panic_probe as _};
66const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; 66const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"];
67 67
68bind_interrupts!(struct Irqs { 68bind_interrupts!(struct Irqs {
69 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 69 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
70}); 70});
71 71
72#[embassy_executor::main] 72#[embassy_executor::main]
@@ -92,12 +92,13 @@ async fn main(_spawner: Spawner) {
92 config.rcc.apb1_pre = APBPrescaler::DIV4; 92 config.rcc.apb1_pre = APBPrescaler::DIV4;
93 config.rcc.apb2_pre = APBPrescaler::DIV2; 93 config.rcc.apb2_pre = APBPrescaler::DIV2;
94 config.rcc.sys = Sysclk::PLL1_P; 94 config.rcc.sys = Sysclk::PLL1_P;
95 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
95 } 96 }
96 let p = embassy_stm32::init(config); 97 let p = embassy_stm32::init(config);
97 98
98 // Create the driver, from the HAL. 99 // Create the driver, from the HAL.
99 let mut ep_out_buffer = [0u8; 256]; 100 let mut ep_out_buffer = [0u8; 256];
100 let mut config = embassy_stm32::usb_otg::Config::default(); 101 let mut config = embassy_stm32::usb::Config::default();
101 config.vbus_detection = true; 102 config.vbus_detection = true;
102 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 103 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
103 104
@@ -116,7 +117,6 @@ async fn main(_spawner: Spawner) {
116 117
117 // Create embassy-usb DeviceBuilder using the driver and config. 118 // Create embassy-usb DeviceBuilder using the driver and config.
118 // It needs some buffers for building the descriptors. 119 // It needs some buffers for building the descriptors.
119 let mut device_descriptor = [0; 256];
120 let mut config_descriptor = [0; 256]; 120 let mut config_descriptor = [0; 256];
121 let mut bos_descriptor = [0; 256]; 121 let mut bos_descriptor = [0; 256];
122 let mut msos_descriptor = [0; 256]; 122 let mut msos_descriptor = [0; 256];
@@ -129,7 +129,6 @@ async fn main(_spawner: Spawner) {
129 let mut builder = Builder::new( 129 let mut builder = Builder::new(
130 driver, 130 driver,
131 config, 131 config,
132 &mut device_descriptor,
133 &mut config_descriptor, 132 &mut config_descriptor,
134 &mut bos_descriptor, 133 &mut bos_descriptor,
135 &mut msos_descriptor, 134 &mut msos_descriptor,
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 58d994a61..f3a375d31 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -13,7 +13,7 @@ use futures::future::join;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
39 config.rcc.apb1_pre = APBPrescaler::DIV4; 39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P; 41 config.rcc.sys = Sysclk::PLL1_P;
42 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
42 } 43 }
43 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
44 45
45 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256]; 47 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default(); 48 let mut config = embassy_stm32::usb::Config::default();
48 config.vbus_detection = true; 49 config.vbus_detection = true;
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 50 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50 51
@@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) {
63 64
64 // Create embassy-usb DeviceBuilder using the driver and config. 65 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors. 66 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256]; 67 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256]; 68 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64]; 69 let mut control_buf = [0; 64];
@@ -73,7 +73,6 @@ async fn main(_spawner: Spawner) {
73 let mut builder = Builder::new( 73 let mut builder = Builder::new(
74 driver, 74 driver,
75 config, 75 config,
76 &mut device_descriptor,
77 &mut config_descriptor, 76 &mut config_descriptor,
78 &mut bos_descriptor, 77 &mut bos_descriptor,
79 &mut [], // no msos descriptors 78 &mut [], // no msos descriptors
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 6122cea2d..cbaff75fc 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -15,8 +15,9 @@
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 bcfdb67a8..e32b4d3df 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -1,16 +1,18 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::num::{NonZeroU16, NonZeroU8};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::bind_interrupts; 8use embassy_stm32::can::filter::Mask32;
7use embassy_stm32::can::bxcan::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
9use embassy_stm32::can::{ 9use embassy_stm32::can::{
10 Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, 10 Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
11 TxInterruptHandler,
11}; 12};
12use embassy_stm32::gpio::{Input, Pull}; 13use embassy_stm32::gpio::{Input, Pull};
13use embassy_stm32::peripherals::CAN3; 14use embassy_stm32::peripherals::CAN3;
15use embassy_stm32::{bind_interrupts, can};
14use static_cell::StaticCell; 16use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
16 18
@@ -22,9 +24,9 @@ bind_interrupts!(struct Irqs {
22}); 24});
23 25
24#[embassy_executor::task] 26#[embassy_executor::task]
25pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { 27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
26 loop { 28 loop {
27 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); 29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
28 tx.write(&frame).await; 30 tx.write(&frame).await;
29 embassy_time::Timer::after_secs(1).await; 31 embassy_time::Timer::after_secs(1).await;
30 } 32 }
@@ -45,19 +47,22 @@ async fn main(spawner: Spawner) {
45 47
46 static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); 48 static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new();
47 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); 49 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
48 can.as_mut() 50 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
49 .modify_filters() 51
50 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 52 can.modify_config()
53 .set_bit_timing(can::util::NominalBitTiming {
54 prescaler: NonZeroU16::new(2).unwrap(),
55 seg1: NonZeroU8::new(13).unwrap(),
56 seg2: NonZeroU8::new(2).unwrap(),
57 sync_jump_width: NonZeroU8::new(1).unwrap(),
58 }) // http://www.bittiming.can-wiki.info/
59 .set_loopback(true);
51 60
52 can.as_mut() 61 can.enable().await;
53 .modify_config()
54 .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
55 .set_loopback(true)
56 .enable();
57 62
58 let (tx, mut rx) = can.split(); 63 let (tx, mut rx) = can.split();
59 64
60 static CAN_TX: StaticCell<CanTx<'static, 'static, CAN3>> = StaticCell::new(); 65 static CAN_TX: StaticCell<CanTx<'static, CAN3>> = StaticCell::new();
61 let tx = CAN_TX.init(tx); 66 let tx = CAN_TX.init(tx);
62 spawner.spawn(send_can_message(tx)).unwrap(); 67 spawner.spawn(send_can_message(tx)).unwrap();
63 68
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
index 04927841a..235853cb9 100644
--- a/examples/stm32f7/src/bin/cryp.rs
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -6,11 +6,15 @@ use aes_gcm::aead::{AeadInPlace, KeyInit};
6use aes_gcm::Aes128Gcm; 6use aes_gcm::Aes128Gcm;
7use defmt::info; 7use defmt::info;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::cryp::*; 9use embassy_stm32::cryp::{self, *};
10use embassy_stm32::Config; 10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_time::Instant; 11use embassy_time::Instant;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs {
15 CRYP => cryp::InterruptHandler<peripherals::CRYP>;
16});
17
14#[embassy_executor::main] 18#[embassy_executor::main]
15async fn main(_spawner: Spawner) -> ! { 19async fn main(_spawner: Spawner) -> ! {
16 let config = Config::default(); 20 let config = Config::default();
@@ -19,7 +23,7 @@ async fn main(_spawner: Spawner) -> ! {
19 let payload: &[u8] = b"hello world"; 23 let payload: &[u8] = b"hello world";
20 let aad: &[u8] = b"additional data"; 24 let aad: &[u8] = b"additional data";
21 25
22 let hw_cryp = Cryp::new(p.CRYP); 26 let mut hw_cryp = Cryp::new(p.CRYP, p.DMA2_CH6, p.DMA2_CH5, Irqs);
23 let key: [u8; 16] = [0; 16]; 27 let key: [u8; 16] = [0; 16];
24 let mut ciphertext: [u8; 11] = [0; 11]; 28 let mut ciphertext: [u8; 11] = [0; 11];
25 let mut plaintext: [u8; 11] = [0; 11]; 29 let mut plaintext: [u8; 11] = [0; 11];
@@ -29,16 +33,18 @@ async fn main(_spawner: Spawner) -> ! {
29 33
30 // Encrypt in hardware using AES-GCM 128-bit 34 // Encrypt in hardware using AES-GCM 128-bit
31 let aes_gcm = AesGcm::new(&key, &iv); 35 let aes_gcm = AesGcm::new(&key, &iv);
32 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); 36 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt).await;
33 hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true); 37 hw_cryp.aad(&mut gcm_encrypt, aad, true).await;
34 hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true); 38 hw_cryp.payload(&mut gcm_encrypt, payload, &mut ciphertext, true).await;
35 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); 39 let encrypt_tag = hw_cryp.finish(gcm_encrypt).await;
36 40
37 // Decrypt in hardware using AES-GCM 128-bit 41 // Decrypt in hardware using AES-GCM 128-bit
38 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); 42 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await;
39 hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true); 43 hw_cryp.aad(&mut gcm_decrypt, aad, true).await;
40 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); 44 hw_cryp
41 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); 45 .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true)
46 .await;
47 let decrypt_tag = hw_cryp.finish(gcm_decrypt).await;
42 48
43 let hw_end_time = Instant::now(); 49 let hw_end_time = Instant::now();
44 let hw_execution_time = hw_end_time - hw_start_time; 50 let hw_execution_time = hw_end_time - hw_start_time;
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 97daf6bd1..39a5512f4 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -13,7 +13,7 @@ use futures::future::join;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
39 config.rcc.apb1_pre = APBPrescaler::DIV4; 39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P; 41 config.rcc.sys = Sysclk::PLL1_P;
42 config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
42 } 43 }
43 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
44 45
45 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256]; 47 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default(); 48 let mut config = embassy_stm32::usb::Config::default();
48 config.vbus_detection = true; 49 config.vbus_detection = true;
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 50 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50 51
@@ -63,7 +64,6 @@ async fn main(_spawner: Spawner) {
63 64
64 // Create embassy-usb DeviceBuilder using the driver and config. 65 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors. 66 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256]; 67 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256]; 68 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64]; 69 let mut control_buf = [0; 64];
@@ -73,7 +73,6 @@ async fn main(_spawner: Spawner) {
73 let mut builder = Builder::new( 73 let mut builder = Builder::new(
74 driver, 74 driver,
75 config, 75 config,
76 &mut device_descriptor,
77 &mut config_descriptor, 76 &mut config_descriptor,
78 &mut bos_descriptor, 77 &mut bos_descriptor,
79 &mut [], // no msos descriptors 78 &mut [], // no msos descriptors
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index 8b9915626..162dfd86b 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) {
36 36
37 // Create embassy-usb DeviceBuilder using the driver and config. 37 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 38 // It needs some buffers for building the descriptors.
39 let mut device_descriptor = [0; 256];
40 let mut config_descriptor = [0; 256]; 39 let mut config_descriptor = [0; 256];
41 let mut bos_descriptor = [0; 256]; 40 let mut bos_descriptor = [0; 256];
42 let mut control_buf = [0; 7]; 41 let mut control_buf = [0; 7];
@@ -46,7 +45,6 @@ async fn main(_spawner: Spawner) {
46 let mut builder = Builder::new( 45 let mut builder = Builder::new(
47 driver, 46 driver,
48 config, 47 config,
49 &mut device_descriptor,
50 &mut config_descriptor, 48 &mut config_descriptor,
51 &mut bos_descriptor, 49 &mut bos_descriptor,
52 &mut [], // no msos descriptors 50 &mut [], // no msos descriptors
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 4373a89a8..2ed632a93 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
36 } 36 }
37 let peripherals = embassy_stm32::init(config); 37 let peripherals = embassy_stm32::init(config);
38 38
39 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 39 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
40 40
41 can.set_extended_filter( 41 can.set_extended_filter(
42 can::filter::ExtendedFilterSlot::_0, 42 can::filter::ExtendedFilterSlot::_0,
@@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) {
56 info!("Configured"); 56 info!("Configured");
57 57
58 let mut can = can.start(match use_fd { 58 let mut can = can.start(match use_fd {
59 true => can::FdcanOperatingMode::InternalLoopbackMode, 59 true => can::OperatingMode::InternalLoopbackMode,
60 false => can::FdcanOperatingMode::NormalOperationMode, 60 false => can::OperatingMode::NormalOperationMode,
61 }); 61 });
62 62
63 let mut i = 0; 63 let mut i = 0;
64 let mut last_read_ts = embassy_time::Instant::now(); 64 let mut last_read_ts = embassy_time::Instant::now();
65 65
66 loop { 66 loop {
67 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 67 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
68 info!("Writing frame"); 68 info!("Writing frame");
69 69
70 _ = can.write(&frame).await; 70 _ = can.write(&frame).await;
71 71
72 match can.read().await { 72 match can.read().await {
73 Ok((rx_frame, ts)) => { 73 Ok(envelope) => {
74 let (ts, rx_frame) = (envelope.ts, envelope.frame);
74 let delta = (ts - last_read_ts).as_millis(); 75 let delta = (ts - last_read_ts).as_millis();
75 last_read_ts = ts; 76 last_read_ts = ts;
76 info!( 77 info!(
@@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) {
105 } 106 }
106 107
107 match can.read_fd().await { 108 match can.read_fd().await {
108 Ok((rx_frame, ts)) => { 109 Ok(envelope) => {
110 let (ts, rx_frame) = (envelope.ts, envelope.frame);
109 let delta = (ts - last_read_ts).as_millis(); 111 let delta = (ts - last_read_ts).as_millis();
110 last_read_ts = ts; 112 last_read_ts = ts;
111 info!( 113 info!(
@@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) {
129 let (mut tx, mut rx) = can.split(); 131 let (mut tx, mut rx) = can.split();
130 // With split 132 // With split
131 loop { 133 loop {
132 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 134 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
133 info!("Writing frame"); 135 info!("Writing frame");
134 _ = tx.write(&frame).await; 136 _ = tx.write(&frame).await;
135 137
136 match rx.read().await { 138 match rx.read().await {
137 Ok((rx_frame, ts)) => { 139 Ok(envelope) => {
140 let (ts, rx_frame) = (envelope.ts, envelope.frame);
138 let delta = (ts - last_read_ts).as_millis(); 141 let delta = (ts - last_read_ts).as_millis();
139 last_read_ts = ts; 142 last_read_ts = ts;
140 info!( 143 info!(
@@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) {
156 } 159 }
157 } 160 }
158 161
159 let can = can::Fdcan::join(tx, rx); 162 let can = can::Can::join(tx, rx);
160 163
161 info!("\n\n\nBuffered\n"); 164 info!("\n\n\nBuffered\n");
162 if use_fd { 165 if use_fd {
@@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) {
173 _ = can.write(frame).await; 176 _ = can.write(frame).await;
174 177
175 match can.read().await { 178 match can.read().await {
176 Ok((rx_frame, ts)) => { 179 Ok(envelope) => {
180 let (ts, rx_frame) = (envelope.ts, envelope.frame);
177 let delta = (ts - last_read_ts).as_millis(); 181 let delta = (ts - last_read_ts).as_millis();
178 last_read_ts = ts; 182 last_read_ts = ts;
179 info!( 183 info!(
@@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) {
198 RX_BUF.init(can::RxBuf::<10>::new()), 202 RX_BUF.init(can::RxBuf::<10>::new()),
199 ); 203 );
200 loop { 204 loop {
201 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 205 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
202 info!("Writing frame"); 206 info!("Writing frame");
203 207
204 // You can use any of these approaches to send. The writer makes it 208 // You can use any of these approaches to send. The writer makes it
@@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) {
208 can.writer().write(frame).await; 212 can.writer().write(frame).await;
209 213
210 match can.read().await { 214 match can.read().await {
211 Ok((rx_frame, ts)) => { 215 Ok(envelope) => {
216 let (ts, rx_frame) = (envelope.ts, envelope.frame);
212 let delta = (ts - last_read_ts).as_millis(); 217 let delta = (ts - last_read_ts).as_millis();
213 last_read_ts = ts; 218 last_read_ts = ts;
214 info!( 219 info!(
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
new file mode 100644
index 000000000..7caea634f
--- /dev/null
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -0,0 +1,86 @@
1#![no_std]
2#![no_main]
3
4use defmt::{error, info, Format};
5use embassy_executor::Spawner;
6use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd};
7use embassy_stm32::{bind_interrupts, peripherals, Config};
8use embassy_time::{with_timeout, Duration};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>;
13});
14
15#[derive(Debug, Format)]
16enum CableOrientation {
17 Normal,
18 Flipped,
19 DebugAccessoryMode,
20}
21
22// Returns true when the cable
23async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation {
24 loop {
25 let (cc1, cc2) = cc_phy.vstate();
26 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
27 // Detached, wait until attached by monitoring the CC lines.
28 cc_phy.wait_for_vstate_change().await;
29 continue;
30 }
31
32 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
33 if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change())
34 .await
35 .is_ok()
36 {
37 // State has changed, restart detection procedure.
38 continue;
39 };
40
41 // State was stable for the complete debounce period, check orientation.
42 return match (cc1, cc2) {
43 (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected
44 (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected
45 _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable)
46 };
47 }
48}
49
50#[embassy_executor::main]
51async fn main(_spawner: Spawner) {
52 let mut config = Config::default();
53 config.enable_ucpd1_dead_battery = true;
54 let p = embassy_stm32::init(config);
55
56 info!("Hello World!");
57
58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4);
59 ucpd.cc_phy().set_pull(CcPull::Sink);
60
61 info!("Waiting for USB connection...");
62 let cable_orientation = wait_attached(ucpd.cc_phy()).await;
63 info!("USB cable connected, orientation: {}", cable_orientation);
64
65 let cc_sel = match cable_orientation {
66 CableOrientation::Normal => {
67 info!("Starting PD communication on CC1 pin");
68 CcSel::CC1
69 }
70 CableOrientation::Flipped => {
71 info!("Starting PD communication on CC2 pin");
72 CcSel::CC2
73 }
74 CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"),
75 };
76 let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel);
77
78 loop {
79 // Enough space for the longest non-extended data message.
80 let mut buf = [0_u8; 30];
81 match pd_phy.receive(buf.as_mut()).await {
82 Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]),
83 Err(e) => error!("USB PD RX: {}", e),
84 }
85 }
86}
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index dc95aa6e5..dbe8f27c1 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -56,7 +56,6 @@ async fn main(_spawner: Spawner) {
56 config.device_protocol = 0x01; 56 config.device_protocol = 0x01;
57 config.composite_with_iads = true; 57 config.composite_with_iads = true;
58 58
59 let mut device_descriptor = [0; 256];
60 let mut config_descriptor = [0; 256]; 59 let mut config_descriptor = [0; 256];
61 let mut bos_descriptor = [0; 256]; 60 let mut bos_descriptor = [0; 256];
62 let mut control_buf = [0; 64]; 61 let mut control_buf = [0; 64];
@@ -66,7 +65,6 @@ async fn main(_spawner: Spawner) {
66 let mut builder = Builder::new( 65 let mut builder = Builder::new(
67 driver, 66 driver,
68 config, 67 config,
69 &mut device_descriptor,
70 &mut config_descriptor, 68 &mut config_descriptor,
71 &mut bos_descriptor, 69 &mut bos_descriptor,
72 &mut [], // no msos descriptors 70 &mut [], // no msos descriptors
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index 643df27f9..dd625c90a 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 24
25 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
26 26
27 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 27 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
28 28
29 // 250k bps 29 // 250k bps
30 can.set_bitrate(250_000); 30 can.set_bitrate(250_000);
@@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
38 let mut last_read_ts = embassy_time::Instant::now(); 38 let mut last_read_ts = embassy_time::Instant::now();
39 39
40 loop { 40 loop {
41 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 41 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame"); 42 info!("Writing frame");
43 _ = can.write(&frame).await; 43 _ = can.write(&frame).await;
44 44
45 match can.read().await { 45 match can.read().await {
46 Ok((rx_frame, ts)) => { 46 Ok(envelope) => {
47 let (rx_frame, ts) = envelope.parts();
47 let delta = (ts - last_read_ts).as_millis(); 48 let delta = (ts - last_read_ts).as_millis();
48 last_read_ts = ts; 49 last_read_ts = ts;
49 info!( 50 info!(
@@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
69 let (mut tx, mut rx) = can.split(); 70 let (mut tx, mut rx) = can.split();
70 // With split 71 // With split
71 loop { 72 loop {
72 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
73 info!("Writing frame"); 74 info!("Writing frame");
74 _ = tx.write(&frame).await; 75 _ = tx.write(&frame).await;
75 76
76 match rx.read().await { 77 match rx.read().await {
77 Ok((rx_frame, ts)) => { 78 Ok(envelope) => {
79 let (rx_frame, ts) = envelope.parts();
78 let delta = (ts - last_read_ts).as_millis(); 80 let delta = (ts - last_read_ts).as_millis();
79 last_read_ts = ts; 81 last_read_ts = ts;
80 info!( 82 info!(
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 83477c8fa..4f86bb342 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) {
65 65
66 // Create embassy-usb DeviceBuilder using the driver and config. 66 // Create embassy-usb DeviceBuilder using the driver and config.
67 // It needs some buffers for building the descriptors. 67 // It needs some buffers for building the descriptors.
68 let mut device_descriptor = [0; 256];
69 let mut config_descriptor = [0; 256]; 68 let mut config_descriptor = [0; 256];
70 let mut bos_descriptor = [0; 256]; 69 let mut bos_descriptor = [0; 256];
71 let mut control_buf = [0; 64]; 70 let mut control_buf = [0; 64];
@@ -75,7 +74,6 @@ async fn main(_spawner: Spawner) {
75 let mut builder = Builder::new( 74 let mut builder = Builder::new(
76 driver, 75 driver,
77 config, 76 config,
78 &mut device_descriptor,
79 &mut config_descriptor, 77 &mut config_descriptor,
80 &mut bos_descriptor, 78 &mut bos_descriptor,
81 &mut [], // no msos descriptors 79 &mut [], // no msos descriptors
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index e5a104baf..170a5aa28 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) {
78 ); 78 );
79 79
80 defmt::info!("attempting capture"); 80 defmt::info!("attempting capture");
81 defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); 81 defmt::unwrap!(dcmi.capture(unsafe { &mut *core::ptr::addr_of_mut!(FRAME) }).await);
82 82
83 defmt::info!("captured frame: {:x}", unsafe { &FRAME }); 83 defmt::info!("captured frame: {:x}", unsafe { &*core::ptr::addr_of!(FRAME) });
84 84
85 defmt::info!("main loop running"); 85 defmt::info!("main loop running");
86 loop { 86 loop {
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index 13a6a5051..22cb27481 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 24
25 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
26 26
27 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 27 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
28 28
29 // 250k bps 29 // 250k bps
30 can.set_bitrate(250_000); 30 can.set_bitrate(250_000);
@@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
38 let mut last_read_ts = embassy_time::Instant::now(); 38 let mut last_read_ts = embassy_time::Instant::now();
39 39
40 loop { 40 loop {
41 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 41 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame"); 42 info!("Writing frame");
43 _ = can.write(&frame).await; 43 _ = can.write(&frame).await;
44 44
45 match can.read().await { 45 match can.read().await {
46 Ok((rx_frame, ts)) => { 46 Ok(envelope) => {
47 let (rx_frame, ts) = envelope.parts();
47 let delta = (ts - last_read_ts).as_millis(); 48 let delta = (ts - last_read_ts).as_millis();
48 last_read_ts = ts; 49 last_read_ts = ts;
49 info!( 50 info!(
@@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
69 let (mut tx, mut rx) = can.split(); 70 let (mut tx, mut rx) = can.split();
70 // With split 71 // With split
71 loop { 72 loop {
72 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
73 info!("Writing frame"); 74 info!("Writing frame");
74 _ = tx.write(&frame).await; 75 _ = tx.write(&frame).await;
75 76
76 match rx.read().await { 77 match rx.read().await {
77 Ok((rx_frame, ts)) => { 78 Ok(envelope) => {
79 let (rx_frame, ts) = envelope.parts();
78 let delta = (ts - last_read_ts).as_millis(); 80 let delta = (ts - last_read_ts).as_millis();
79 last_read_ts = ts; 81 last_read_ts = ts;
80 info!( 82 info!(
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index feec28993..3a9887e3c 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -6,9 +6,9 @@ use embassy_executor::Spawner;
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/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index d81efb541..576506ad3 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::usb_otg::{Driver, Instance}; 6use embassy_stm32::usb::{Driver, Instance};
7use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 7use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
8use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 8use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
9use embassy_usb::driver::EndpointError; 9use embassy_usb::driver::EndpointError;
10use embassy_usb::Builder; 10use embassy_usb::Builder;
@@ -12,7 +12,7 @@ use futures::future::join;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
15 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 15 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
16}); 16});
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
@@ -40,12 +40,13 @@ async fn main(_spawner: Spawner) {
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1; 42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
43 } 44 }
44 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
45 46
46 // Create the driver, from the HAL. 47 // Create the driver, from the HAL.
47 let mut ep_out_buffer = [0u8; 256]; 48 let mut ep_out_buffer = [0u8; 256];
48 let mut config = embassy_stm32::usb_otg::Config::default(); 49 let mut config = embassy_stm32::usb::Config::default();
49 config.vbus_detection = true; 50 config.vbus_detection = true;
50 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 51 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
51 52
@@ -64,7 +65,6 @@ async fn main(_spawner: Spawner) {
64 65
65 // Create embassy-usb DeviceBuilder using the driver and config. 66 // Create embassy-usb DeviceBuilder using the driver and config.
66 // It needs some buffers for building the descriptors. 67 // It needs some buffers for building the descriptors.
67 let mut device_descriptor = [0; 256];
68 let mut config_descriptor = [0; 256]; 68 let mut config_descriptor = [0; 256];
69 let mut bos_descriptor = [0; 256]; 69 let mut bos_descriptor = [0; 256];
70 let mut control_buf = [0; 64]; 70 let mut control_buf = [0; 64];
@@ -74,7 +74,6 @@ async fn main(_spawner: Spawner) {
74 let mut builder = Builder::new( 74 let mut builder = Builder::new(
75 driver, 75 driver,
76 config, 76 config,
77 &mut device_descriptor,
78 &mut config_descriptor, 77 &mut config_descriptor,
79 &mut bos_descriptor, 78 &mut bos_descriptor,
80 &mut [], // no msos descriptors 79 &mut [], // no msos descriptors
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs
index f738ea358..653bbd6d2 100644
--- a/examples/stm32l1/src/bin/usb_serial.rs
+++ b/examples/stm32l1/src/bin/usb_serial.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 config.device_protocol = 0x01; 46 config.device_protocol = 0x01;
47 config.composite_with_iads = true; 47 config.composite_with_iads = true;
48 48
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 49 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 50 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
@@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) {
56 let mut builder = Builder::new( 55 let mut builder = Builder::new(
57 driver, 56 driver,
58 config, 57 config,
59 &mut device_descriptor,
60 &mut config_descriptor, 58 &mut config_descriptor,
61 &mut bos_descriptor, 59 &mut bos_descriptor,
62 &mut [], // no msos descriptors 60 &mut [], // no msos descriptors
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index f227812cd..d01b016c0 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -6,9 +6,9 @@ use embassy_executor::Spawner;
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 9247e56a1..198504b59 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -4,9 +4,8 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::*; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -14,7 +13,7 @@ use futures::future::join;
14use panic_probe as _; 13use panic_probe as _;
15 14
16bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
18}); 17});
19 18
20#[embassy_executor::main] 19#[embassy_executor::main]
@@ -22,23 +21,26 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 24 {
26 config.rcc.sys = Sysclk::PLL1_R; 25 use embassy_stm32::rcc::*;
27 config.rcc.hsi = true; 26 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
28 config.rcc.pll = Some(Pll { 27 config.rcc.sys = Sysclk::PLL1_R;
29 source: PllSource::HSI, 28 config.rcc.hsi = true;
30 prediv: PllPreDiv::DIV1, 29 config.rcc.pll = Some(Pll {
31 mul: PllMul::MUL10, 30 source: PllSource::HSI,
32 divp: None, 31 prediv: PllPreDiv::DIV1,
33 divq: None, 32 mul: PllMul::MUL10,
34 divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) 33 divp: None,
35 }); 34 divq: None,
36 35 divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2)
36 });
37 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
38 }
37 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
38 40
39 // Create the driver, from the HAL. 41 // Create the driver, from the HAL.
40 let mut ep_out_buffer = [0u8; 256]; 42 let mut ep_out_buffer = [0u8; 256];
41 let mut config = embassy_stm32::usb_otg::Config::default(); 43 let mut config = embassy_stm32::usb::Config::default();
42 config.vbus_detection = true; 44 config.vbus_detection = true;
43 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 45 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
44 46
@@ -58,7 +60,6 @@ async fn main(_spawner: Spawner) {
58 60
59 // Create embassy-usb DeviceBuilder using the driver and config. 61 // Create embassy-usb DeviceBuilder using the driver and config.
60 // It needs some buffers for building the descriptors. 62 // It needs some buffers for building the descriptors.
61 let mut device_descriptor = [0; 256];
62 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
63 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
64 let mut control_buf = [0; 64]; 65 let mut control_buf = [0; 64];
@@ -68,7 +69,6 @@ async fn main(_spawner: Spawner) {
68 let mut builder = Builder::new( 69 let mut builder = Builder::new(
69 driver, 70 driver,
70 config, 71 config,
71 &mut device_descriptor,
72 &mut config_descriptor, 72 &mut config_descriptor,
73 &mut bos_descriptor, 73 &mut bos_descriptor,
74 &mut [], // no msos descriptors 74 &mut [], // no msos descriptors
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index f6d8b16d0..7f73fd677 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -5,7 +5,6 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::{Stack, StackResources};
8use embassy_stm32::rcc::*;
9use embassy_stm32::rng::Rng; 8use embassy_stm32::rng::Rng;
10use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
11use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config};
@@ -44,17 +43,22 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
44#[embassy_executor::main] 43#[embassy_executor::main]
45async fn main(spawner: Spawner) { 44async fn main(spawner: Spawner) {
46 let mut config = Config::default(); 45 let mut config = Config::default();
47 config.rcc.hsi = true; 46 {
48 config.rcc.sys = Sysclk::PLL1_R; 47 use embassy_stm32::rcc::*;
49 config.rcc.pll = Some(Pll { 48 config.rcc.hsi = true;
50 // 80Mhz clock (16 / 1 * 10 / 2) 49 config.rcc.sys = Sysclk::PLL1_R;
51 source: PllSource::HSI, 50 config.rcc.pll = Some(Pll {
52 prediv: PllPreDiv::DIV1, 51 // 80Mhz clock (16 / 1 * 10 / 2)
53 mul: PllMul::MUL10, 52 source: PllSource::HSI,
54 divp: None, 53 prediv: PllPreDiv::DIV1,
55 divq: None, 54 mul: PllMul::MUL10,
56 divr: Some(PllRDiv::DIV2), 55 divp: None,
57 }); 56 divq: None,
57 divr: Some(PllRDiv::DIV2),
58 });
59 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
60 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
61 }
58 let p = embassy_stm32::init(config); 62 let p = embassy_stm32::init(config);
59 63
60 // Create the driver, from the HAL. 64 // Create the driver, from the HAL.
@@ -75,14 +79,12 @@ async fn main(spawner: Spawner) {
75 config.device_protocol = 0x01; 79 config.device_protocol = 0x01;
76 80
77 // Create embassy-usb DeviceBuilder using the driver and config. 81 // Create embassy-usb DeviceBuilder using the driver and config.
78 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
79 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 82 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
80 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 83 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
81 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); 84 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
82 let mut builder = Builder::new( 85 let mut builder = Builder::new(
83 driver, 86 driver,
84 config, 87 config,
85 &mut DEVICE_DESC.init([0; 256])[..],
86 &mut CONFIG_DESC.init([0; 256])[..], 88 &mut CONFIG_DESC.init([0; 256])[..],
87 &mut BOS_DESC.init([0; 256])[..], 89 &mut BOS_DESC.init([0; 256])[..],
88 &mut [], // no msos descriptors 90 &mut [], // no msos descriptors
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index c51ed96e0..9d30205bb 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb::Driver; 7use embassy_stm32::usb::Driver;
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 20#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 22 let mut config = Config::default();
24 config.rcc.hsi = true; 23 {
25 config.rcc.sys = Sysclk::PLL1_R; 24 use embassy_stm32::rcc::*;
26 config.rcc.pll = Some(Pll { 25 config.rcc.hsi = true;
27 // 80Mhz clock (16 / 1 * 10 / 2) 26 config.rcc.sys = Sysclk::PLL1_R;
28 source: PllSource::HSI, 27 config.rcc.pll = Some(Pll {
29 prediv: PllPreDiv::DIV1, 28 // 80Mhz clock (16 / 1 * 10 / 2)
30 mul: PllMul::MUL10, 29 source: PllSource::HSI,
31 divp: None, 30 prediv: PllPreDiv::DIV1,
32 divq: None, 31 mul: PllMul::MUL10,
33 divr: Some(PllRDiv::DIV2), 32 divp: None,
34 }); 33 divq: None,
34 divr: Some(PllRDiv::DIV2),
35 });
36 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
37 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
38 }
35 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
36 40
37 // Create the driver, from the HAL. 41 // Create the driver, from the HAL.
@@ -47,7 +51,6 @@ async fn main(_spawner: Spawner) {
47 51
48 // Create embassy-usb DeviceBuilder using the driver and config. 52 // Create embassy-usb DeviceBuilder using the driver and config.
49 // It needs some buffers for building the descriptors. 53 // It needs some buffers for building the descriptors.
50 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256]; 54 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256]; 55 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
@@ -58,7 +61,6 @@ async fn main(_spawner: Spawner) {
58 let mut builder = Builder::new( 61 let mut builder = Builder::new(
59 driver, 62 driver,
60 config, 63 config,
61 &mut device_descriptor,
62 &mut config_descriptor, 64 &mut config_descriptor,
63 &mut bos_descriptor, 65 &mut bos_descriptor,
64 &mut [], // no msos descriptors 66 &mut [], // no msos descriptors
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 87987f2ce..a64bda31b 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.hsi = true; 21 {
23 config.rcc.sys = Sysclk::PLL1_R; 22 use embassy_stm32::rcc::*;
24 config.rcc.pll = Some(Pll { 23 config.rcc.hsi = true;
25 // 80Mhz clock (16 / 1 * 10 / 2) 24 config.rcc.sys = Sysclk::PLL1_R;
26 source: PllSource::HSI, 25 config.rcc.pll = Some(Pll {
27 prediv: PllPreDiv::DIV1, 26 // 80Mhz clock (16 / 1 * 10 / 2)
28 mul: PllMul::MUL10, 27 source: PllSource::HSI,
29 divp: None, 28 prediv: PllPreDiv::DIV1,
30 divq: None, 29 mul: PllMul::MUL10,
31 divr: Some(PllRDiv::DIV2), 30 divp: None,
32 }); 31 divq: None,
32 divr: Some(PllRDiv::DIV2),
33 });
34 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
35 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
36 }
33 let p = embassy_stm32::init(config); 37 let p = embassy_stm32::init(config);
34 38
35 info!("Hello World!"); 39 info!("Hello World!");
@@ -43,7 +47,6 @@ async fn main(_spawner: Spawner) {
43 47
44 // Create embassy-usb DeviceBuilder using the driver and config. 48 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors. 49 // It needs some buffers for building the descriptors.
46 let mut device_descriptor = [0; 256];
47 let mut config_descriptor = [0; 256]; 50 let mut config_descriptor = [0; 256];
48 let mut bos_descriptor = [0; 256]; 51 let mut bos_descriptor = [0; 256];
49 let mut control_buf = [0; 7]; 52 let mut control_buf = [0; 7];
@@ -53,7 +56,6 @@ async fn main(_spawner: Spawner) {
53 let mut builder = Builder::new( 56 let mut builder = Builder::new(
54 driver, 57 driver,
55 config, 58 config,
56 &mut device_descriptor,
57 &mut config_descriptor, 59 &mut config_descriptor,
58 &mut bos_descriptor, 60 &mut bos_descriptor,
59 &mut [], // no msos descriptors 61 &mut [], // no msos descriptors
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 61851e5a2..6a313efb0 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -13,7 +13,7 @@ use futures::future::join;
13use panic_probe as _; 13use panic_probe as _;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -35,13 +35,14 @@ async fn main(_spawner: Spawner) {
35 config.rcc.sys = Sysclk::PLL1_R; 35 config.rcc.sys = Sysclk::PLL1_R;
36 config.rcc.voltage_range = VoltageScale::RANGE1; 36 config.rcc.voltage_range = VoltageScale::RANGE1;
37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
38 config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK
38 } 39 }
39 40
40 let p = embassy_stm32::init(config); 41 let p = embassy_stm32::init(config);
41 42
42 // Create the driver, from the HAL. 43 // Create the driver, from the HAL.
43 let mut ep_out_buffer = [0u8; 256]; 44 let mut ep_out_buffer = [0u8; 256];
44 let mut config = embassy_stm32::usb_otg::Config::default(); 45 let mut config = embassy_stm32::usb::Config::default();
45 config.vbus_detection = false; 46 config.vbus_detection = false;
46 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 47 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
47 48
@@ -60,7 +61,6 @@ async fn main(_spawner: Spawner) {
60 61
61 // Create embassy-usb DeviceBuilder using the driver and config. 62 // Create embassy-usb DeviceBuilder using the driver and config.
62 // It needs some buffers for building the descriptors. 63 // It needs some buffers for building the descriptors.
63 let mut device_descriptor = [0; 256];
64 let mut config_descriptor = [0; 256]; 64 let mut config_descriptor = [0; 256];
65 let mut bos_descriptor = [0; 256]; 65 let mut bos_descriptor = [0; 256];
66 let mut control_buf = [0; 64]; 66 let mut control_buf = [0; 64];
@@ -70,7 +70,6 @@ async fn main(_spawner: Spawner) {
70 let mut builder = Builder::new( 70 let mut builder = Builder::new(
71 driver, 71 driver,
72 config, 72 config,
73 &mut device_descriptor,
74 &mut config_descriptor, 73 &mut config_descriptor,
75 &mut bos_descriptor, 74 &mut bos_descriptor,
76 &mut [], // no msos descriptors 75 &mut [], // no msos descriptors
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index b8a7db353..98696fd2b 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
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/Cargo.toml b/tests/stm32/Cargo.toml
index bfe003a11..e42470004 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -13,7 +13,7 @@ stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
13stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] 13stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
@@ -47,6 +47,7 @@ mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
47embassy-stm32-wpan = [] 47embassy-stm32-wpan = []
48not-gpdma = [] 48not-gpdma = []
49dac = [] 49dac = []
50ucpd = []
50 51
51cm0 = ["portable-atomic/unsafe-assume-single-core"] 52cm0 = ["portable-atomic/unsafe-assume-single-core"]
52 53
@@ -161,6 +162,11 @@ path = "src/bin/timer.rs"
161required-features = [] 162required-features = []
162 163
163[[bin]] 164[[bin]]
165name = "ucpd"
166path = "src/bin/ucpd.rs"
167required-features = [ "ucpd",]
168
169[[bin]]
164name = "usart" 170name = "usart"
165path = "src/bin/usart.rs" 171path = "src/bin/usart.rs"
166required-features = [] 172required-features = []
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index f4effa244..551764458 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -6,17 +6,20 @@
6#[path = "../common.rs"] 6#[path = "../common.rs"]
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::bxcan::filter::Mask32; 11use embassy_stm32::can::filter::Mask32;
13use embassy_stm32::can::bxcan::{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]);
64 62
65 info!("Transmitting frame..."); 63 can.enable().await;
66 let tx_ts = Instant::now();
67 can.write(&tx_frame).await;
68 64
69 let envelope = can.read().await.unwrap(); 65 info!("Can configured");
70 info!("Frame received!");
71
72 info!("loopback time {}", envelope.ts);
73 info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]);
74
75 let latency = envelope.ts.saturating_duration_since(tx_ts);
76 info!("loopback latency {} us", latency.as_micros());
77 66
78 // Theoretical minimum latency is 55us, actual is usually ~80us 67 run_can_tests(&mut can, &options).await;
79 const MIN_LATENCY: Duration = Duration::from_micros(50);
80 const MAX_LATENCY: Duration = Duration::from_micros(150);
81 assert!(
82 MIN_LATENCY <= latency && latency <= MAX_LATENCY,
83 "{} <= {} <= {}",
84 MIN_LATENCY,
85 latency,
86 MAX_LATENCY
87 );
88 68
89 i += 1; 69 // Test again with a split
90 if i > 10 { 70 let (mut tx, mut rx) = can.split();
91 break; 71 run_split_can_tests(&mut tx, &mut rx, &options).await;
92 }
93 }
94 72
95 info!("Test OK"); 73 info!("Test OK");
74
96 cortex_m::asm::bkpt(); 75 cortex_m::asm::bkpt();
97} 76}
diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs
new file mode 100644
index 000000000..4b39269cc
--- /dev/null
+++ b/tests/stm32/src/bin/can_common.rs
@@ -0,0 +1,112 @@
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/cryp.rs b/tests/stm32/src/bin/cryp.rs
index f105abf26..60778bdaa 100644
--- a/tests/stm32/src/bin/cryp.rs
+++ b/tests/stm32/src/bin/cryp.rs
@@ -10,9 +10,14 @@ use aes_gcm::aead::{AeadInPlace, KeyInit};
10use aes_gcm::Aes128Gcm; 10use aes_gcm::Aes128Gcm;
11use common::*; 11use common::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_stm32::cryp::*; 13use embassy_stm32::cryp::{self, *};
14use embassy_stm32::{bind_interrupts, peripherals};
14use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
15 16
17bind_interrupts!(struct Irqs {
18 CRYP => cryp::InterruptHandler<peripherals::CRYP>;
19});
20
16#[embassy_executor::main] 21#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
18 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 23 let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
@@ -22,27 +27,32 @@ async fn main(_spawner: Spawner) {
22 const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; 27 const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1";
23 const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; 28 const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg";
24 29
25 let hw_cryp = Cryp::new(p.CRYP); 30 let in_dma = peri!(p, CRYP_IN_DMA);
31 let out_dma = peri!(p, CRYP_OUT_DMA);
32
33 let mut hw_cryp = Cryp::new(p.CRYP, in_dma, out_dma, Irqs);
26 let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 34 let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
27 let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; 35 let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
28 let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; 36 let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
29 let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 37 let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
30 38
31 // Encrypt in hardware using AES-GCM 128-bit 39 // Encrypt in hardware using AES-GCM 128-bit in blocking mode.
32 let aes_gcm = AesGcm::new(&key, &iv); 40 let aes_gcm = AesGcm::new(&key, &iv);
33 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); 41 let mut gcm_encrypt = hw_cryp.start_blocking(&aes_gcm, Direction::Encrypt);
34 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); 42 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false);
35 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); 43 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true);
36 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); 44 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false);
37 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); 45 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true);
38 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); 46 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
39 47
40 // Decrypt in hardware using AES-GCM 128-bit 48 // Decrypt in hardware using AES-GCM 128-bit in async (DMA) mode.
41 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); 49 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await;
42 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false); 50 hw_cryp.aad(&mut gcm_decrypt, AAD1, false).await;
43 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true); 51 hw_cryp.aad(&mut gcm_decrypt, AAD2, true).await;
44 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); 52 hw_cryp
45 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); 53 .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true)
54 .await;
55 let decrypt_tag = hw_cryp.finish(gcm_decrypt).await;
46 56
47 info!("AES-GCM Ciphertext: {:?}", ciphertext); 57 info!("AES-GCM Ciphertext: {:?}", ciphertext);
48 info!("AES-GCM Plaintext: {:?}", plaintext); 58 info!("AES-GCM Plaintext: {:?}", plaintext);
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index dd78d7fb3..27bdd038a 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -6,26 +6,26 @@
6#[path = "../common.rs"] 6#[path = "../common.rs"]
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
16bind_interrupts!(struct Irqs { 15mod can_common;
16use can_common::*;
17
18bind_interrupts!(struct Irqs2 {
19 FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
20 FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
21});
22bind_interrupts!(struct Irqs1 {
17 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; 23 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
18 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; 24 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
19}); 25});
20 26
21struct TestOptions {
22 config: Config,
23 max_latency: Duration,
24 second_fifo_working: bool,
25}
26
27#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] 27#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
28fn options() -> TestOptions { 28fn options() -> (Config, TestOptions) {
29 use embassy_stm32::rcc; 29 use embassy_stm32::rcc;
30 info!("H75 config"); 30 info!("H75 config");
31 let mut c = config(); 31 let mut c = config();
@@ -34,15 +34,17 @@ fn options() -> TestOptions {
34 mode: rcc::HseMode::Oscillator, 34 mode: rcc::HseMode::Oscillator,
35 }); 35 });
36 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; 36 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
37 TestOptions { 37 (
38 config: c, 38 c,
39 max_latency: Duration::from_micros(1200), 39 TestOptions {
40 second_fifo_working: false, 40 max_latency: Duration::from_micros(1200),
41 } 41 max_buffered: 3,
42 },
43 )
42} 44}
43 45
44#[cfg(any(feature = "stm32h7a3zi"))] 46#[cfg(any(feature = "stm32h7a3zi"))]
45fn options() -> TestOptions { 47fn options() -> (Config, TestOptions) {
46 use embassy_stm32::rcc; 48 use embassy_stm32::rcc;
47 info!("H7a config"); 49 info!("H7a config");
48 let mut c = config(); 50 let mut c = config();
@@ -51,139 +53,63 @@ fn options() -> TestOptions {
51 mode: rcc::HseMode::Oscillator, 53 mode: rcc::HseMode::Oscillator,
52 }); 54 });
53 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; 55 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
54 TestOptions { 56 (
55 config: c, 57 c,
56 max_latency: Duration::from_micros(1200), 58 TestOptions {
57 second_fifo_working: false, 59 max_latency: Duration::from_micros(1200),
58 } 60 max_buffered: 3,
61 },
62 )
59} 63}
60 64
61#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] 65#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
62fn options() -> TestOptions { 66fn options() -> (Config, TestOptions) {
63 info!("G4 config"); 67 info!("G4 config");
64 TestOptions { 68 (
65 config: config(), 69 config(),
66 max_latency: Duration::from_micros(500), 70 TestOptions {
67 second_fifo_working: true, 71 max_latency: Duration::from_micros(500),
68 } 72 max_buffered: 6,
73 },
74 )
69} 75}
70 76
71#[embassy_executor::main] 77#[embassy_executor::main]
72async fn main(_spawner: Spawner) { 78async fn main(_spawner: Spawner) {
73 //let peripherals = embassy_stm32::init(config()); 79 //let peripherals = embassy_stm32::init(config());
74 80
75 let options = options(); 81 let (config, options) = options();
76 let peripherals = embassy_stm32::init(options.config); 82 let peripherals = embassy_stm32::init(config);
77 83
78 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); 84 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
85 let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
79 86
80 // 250k bps 87 // 250k bps
81 can.set_bitrate(250_000); 88 can.set_bitrate(250_000);
89 can2.set_bitrate(250_000);
82 90
83 can.set_extended_filter( 91 can.set_extended_filter(
84 can::filter::ExtendedFilterSlot::_0, 92 can::filter::ExtendedFilterSlot::_0,
85 can::filter::ExtendedFilter::accept_all_into_fifo1(), 93 can::filter::ExtendedFilter::accept_all_into_fifo1(),
86 ); 94 );
95 can2.set_extended_filter(
96 can::filter::ExtendedFilterSlot::_0,
97 can::filter::ExtendedFilter::accept_all_into_fifo1(),
98 );
87 99
88 let mut can = can.into_internal_loopback_mode(); 100 let mut can = can.into_internal_loopback_mode();
101 let mut can2 = can2.into_internal_loopback_mode();
89 102
90 info!("CAN Configured"); 103 run_can_tests(&mut can, &options).await;
104 run_can_tests(&mut can2, &options).await;
91 105
92 let mut i: u8 = 0; 106 info!("CAN Configured");
93 loop {
94 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
95
96 info!("Transmitting frame...");
97 let tx_ts = Instant::now();
98 can.write(&tx_frame).await;
99
100 let (frame, timestamp) = can.read().await.unwrap();
101 info!("Frame received!");
102
103 // Check data.
104 assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
105
106 info!("loopback time {}", timestamp);
107 info!("loopback frame {=u8}", frame.data()[0]);
108 let latency = timestamp.saturating_duration_since(tx_ts);
109 info!("loopback latency {} us", latency.as_micros());
110
111 // Theoretical minimum latency is 55us, actual is usually ~80us
112 const MIN_LATENCY: Duration = Duration::from_micros(50);
113 // Was failing at 150 but we are not getting a real time stamp. I'm not
114 // sure if there are other delays
115 assert!(
116 MIN_LATENCY <= latency && latency <= options.max_latency,
117 "{} <= {} <= {}",
118 MIN_LATENCY,
119 latency,
120 options.max_latency
121 );
122
123 i += 1;
124 if i > 10 {
125 break;
126 }
127 }
128
129 let max_buffered = if options.second_fifo_working { 6 } else { 3 };
130
131 // Below here, check that we can receive from both FIFO0 and FIFO0
132 // Above we configured FIFO1 for extended ID packets. There are only 3 slots
133 // in each FIFO so make sure we write enough to fill them both up before reading.
134 for i in 0..3 {
135 // Try filling up the RX FIFO0 buffers with standard packets
136 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
137 info!("Transmitting frame {}", i);
138 can.write(&tx_frame).await;
139 }
140 for i in 3..max_buffered {
141 // Try filling up the RX FIFO0 buffers with extended packets
142 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
143 info!("Transmitting frame {}", i);
144 can.write(&tx_frame).await;
145 }
146
147 // Try and receive all 6 packets
148 for i in 0..max_buffered {
149 let (frame, _ts) = can.read().await.unwrap();
150 match frame.id() {
151 embedded_can::Id::Extended(id) => {
152 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
153 }
154 embedded_can::Id::Standard(id) => {
155 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
156 }
157 }
158 }
159 107
160 // Test again with a split 108 // Test again with a split
161 let (mut tx, mut rx) = can.split(); 109 let (mut tx, mut rx) = can.split();
162 for i in 0..3 { 110 let (mut tx2, mut rx2) = can2.split();
163 // Try filling up the RX FIFO0 buffers with standard packets 111 run_split_can_tests(&mut tx, &mut rx, &options).await;
164 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); 112 run_split_can_tests(&mut tx2, &mut rx2, &options).await;
165 info!("Transmitting frame {}", i);
166 tx.write(&tx_frame).await;
167 }
168 for i in 3..max_buffered {
169 // Try filling up the RX FIFO0 buffers with extended packets
170 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
171 info!("Transmitting frame {}", i);
172 tx.write(&tx_frame).await;
173 }
174
175 // Try and receive all 6 packets
176 for i in 0..max_buffered {
177 let (frame, _ts) = rx.read().await.unwrap();
178 match frame.id() {
179 embedded_can::Id::Extended(id) => {
180 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
181 }
182 embedded_can::Id::Standard(id) => {
183 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
184 }
185 }
186 }
187 113
188 info!("Test OK"); 114 info!("Test OK");
189 cortex_m::asm::bkpt(); 115 cortex_m::asm::bkpt();
diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs
new file mode 100644
index 000000000..c09334ec8
--- /dev/null
+++ b/tests/stm32/src/bin/ucpd.rs
@@ -0,0 +1,120 @@
1// required-features: ucpd
2#![no_std]
3#![no_main]
4#[path = "../common.rs"]
5mod common;
6
7use common::*;
8use defmt::{assert, assert_eq};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd};
12use embassy_stm32::{bind_interrupts, peripherals};
13use embassy_time::Timer;
14
15bind_interrupts!(struct Irqs {
16 UCPD1_2 => ucpd::InterruptHandler<peripherals::UCPD1>, ucpd::InterruptHandler<peripherals::UCPD2>;
17});
18
19static SRC_TO_SNK: [u8; 6] = [0, 1, 2, 3, 4, 5];
20static SNK_TO_SRC: [u8; 4] = [9, 8, 7, 6];
21
22async fn wait_for_vstate<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>, vstate: CcVState) {
23 let (mut cc1, mut _cc2) = cc_phy.vstate();
24 while cc1 != vstate {
25 (cc1, _cc2) = cc_phy.wait_for_vstate_change().await;
26 }
27}
28
29async fn source(
30 mut ucpd: Ucpd<'static, peripherals::UCPD1>,
31 rx_dma: peripherals::DMA1_CH1,
32 tx_dma: peripherals::DMA1_CH2,
33) {
34 debug!("source: setting default current pull-up");
35 ucpd.cc_phy().set_pull(CcPull::SourceDefaultUsb);
36
37 // Wait for default sink.
38 debug!("source: wait for sink");
39 wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await;
40
41 // Advertise a higher current by changing the pull-up resistor.
42 debug!("source: sink detected, setting 3.0A current pull-up");
43 ucpd.cc_phy().set_pull(CcPull::Source3_0A);
44
45 let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1);
46
47 // Listen for an incoming message
48 debug!("source: wait for message from sink");
49 let mut snk_to_src_buf = [0_u8; 30];
50 let n = unwrap!(pd_phy.receive(snk_to_src_buf.as_mut()).await);
51 assert_eq!(n, SNK_TO_SRC.len());
52 assert_eq!(&snk_to_src_buf[..n], SNK_TO_SRC.as_slice());
53
54 // Send message
55 debug!("source: message received, sending message");
56 unwrap!(pd_phy.transmit(SRC_TO_SNK.as_slice()).await);
57
58 // Wait for hard-reset
59 debug!("source: message sent, waiting for hard-reset");
60 assert!(matches!(
61 pd_phy.receive(snk_to_src_buf.as_mut()).await,
62 Err(RxError::HardReset)
63 ));
64}
65
66async fn sink(
67 mut ucpd: Ucpd<'static, peripherals::UCPD2>,
68 rx_dma: peripherals::DMA1_CH3,
69 tx_dma: peripherals::DMA1_CH4,
70) {
71 debug!("sink: setting pull down");
72 ucpd.cc_phy().set_pull(CcPull::Sink);
73
74 // Wait for default source.
75 debug!("sink: waiting for default vstate");
76 wait_for_vstate(ucpd.cc_phy(), CcVState::LOW).await;
77
78 // Wait higher current pull-up.
79 //debug!("sink: source default vstate detected, waiting for 3.0A vstate");
80 //wait_for_vstate(ucpd.cc_phy(), CcVState::HIGHEST).await;
81 //debug!("sink: source 3.0A vstate detected");
82 // TODO: not working yet, why? no idea, replace with timer for now
83 Timer::after_millis(100).await;
84
85 let (_, mut pd_phy) = ucpd.split_pd_phy(rx_dma, tx_dma, CcSel::CC1);
86
87 // Send message
88 debug!("sink: sending message");
89 unwrap!(pd_phy.transmit(SNK_TO_SRC.as_slice()).await);
90
91 // Listen for an incoming message
92 debug!("sink: message sent, waiting for message from source");
93 let mut src_to_snk_buf = [0_u8; 30];
94 let n = unwrap!(pd_phy.receive(src_to_snk_buf.as_mut()).await);
95 assert_eq!(n, SRC_TO_SNK.len());
96 assert_eq!(&src_to_snk_buf[..n], SRC_TO_SNK.as_slice());
97
98 // Send hard reset
99 debug!("sink: message received, sending hard-reset");
100 unwrap!(pd_phy.transmit_hardreset().await);
101}
102
103#[embassy_executor::main]
104async fn main(_spawner: Spawner) {
105 let p = embassy_stm32::init(config());
106 info!("Hello World!");
107
108 // Wire between PD0 and PA8
109 let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15);
110 let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2);
111
112 join(
113 source(ucpd1, p.DMA1_CH1, p.DMA1_CH2),
114 sink(ucpd2, p.DMA1_CH3, p.DMA1_CH4),
115 )
116 .await;
117
118 info!("Test OK");
119 cortex_m::asm::bkpt();
120}
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 3297ea7e2..0e555efc8 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -140,6 +140,7 @@ define_peris!(
140); 140);
141#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] 141#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
142define_peris!( 142define_peris!(
143 CRYP_IN_DMA = DMA1_CH0, CRYP_OUT_DMA = DMA1_CH1,
143 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, 144 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1,
144 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, 145 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1,
145 ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, 146 ADC = ADC1, DAC = DAC1, DAC_PIN = PA4,
@@ -250,13 +251,6 @@ define_peris!(
250); 251);
251 252
252pub fn config() -> Config { 253pub fn config() -> Config {
253 // Setting this bit is mandatory to use PG[15:2].
254 #[cfg(feature = "stm32u5a5zj")]
255 embassy_stm32::pac::PWR.svmcr().modify(|w| {
256 w.set_io2sv(true);
257 w.set_io2vmen(true);
258 });
259
260 #[allow(unused_mut)] 254 #[allow(unused_mut)]
261 let mut config = Config::default(); 255 let mut config = Config::default();
262 256