aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-06-19 15:52:33 -0500
committerxoviat <[email protected]>2023-06-19 15:52:33 -0500
commitaaad9068156305e5f6f41ee4013e025083bd0668 (patch)
tree67a08c8a512e8791433891a3b6deec813fc4c578
parent35083b262b364387713f4273649b62180123182c (diff)
parent3c70f799a28f5f28d84fa8ee8b4b232f5e9aad82 (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into can
-rwxr-xr-x.github/ci/doc.sh44
-rw-r--r--.github/workflows/doc.yml87
-rwxr-xr-xci.sh16
-rwxr-xr-xci_stable.sh4
-rw-r--r--cyw43-pio/Cargo.toml5
-rw-r--r--cyw43/Cargo.toml6
-rw-r--r--cyw43/src/control.rs5
-rw-r--r--cyw43/src/fmt.rs3
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs24
-rw-r--r--embassy-cortex-m/Cargo.toml47
-rw-r--r--embassy-cortex-m/src/lib.rs10
-rw-r--r--embassy-cortex-m/src/peripheral.rs144
-rw-r--r--embassy-executor/Cargo.toml2
-rw-r--r--embassy-executor/src/arch/cortex_m.rs15
-rw-r--r--embassy-futures/src/block_on.rs12
-rw-r--r--embassy-futures/src/fmt.rs3
-rw-r--r--embassy-hal-common/Cargo.toml16
-rw-r--r--embassy-hal-common/build.rs (renamed from embassy-cortex-m/build.rs)0
-rw-r--r--embassy-hal-common/src/interrupt.rs (renamed from embassy-cortex-m/src/interrupt.rs)336
-rw-r--r--embassy-hal-common/src/lib.rs3
-rw-r--r--embassy-lora/src/iv.rs28
-rw-r--r--embassy-macros/src/lib.rs24
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt.rs66
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_declare.rs34
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_take.rs57
-rw-r--r--embassy-macros/src/macros/mod.rs3
-rw-r--r--embassy-net-w5500/Cargo.toml5
-rw-r--r--embassy-net/Cargo.toml4
-rw-r--r--embassy-net/src/device.rs5
-rw-r--r--embassy-net/src/dns.rs1
-rw-r--r--embassy-net/src/lib.rs245
-rw-r--r--embassy-net/src/tcp.rs13
-rw-r--r--embassy-nrf/Cargo.toml9
-rw-r--r--embassy-nrf/src/buffered_uarte.rs17
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs56
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs62
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs62
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs60
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs82
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs90
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs94
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs92
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs50
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs72
-rw-r--r--embassy-nrf/src/gpiote.rs55
-rw-r--r--embassy-nrf/src/i2s.rs19
-rw-r--r--embassy-nrf/src/lib.rs33
-rw-r--r--embassy-nrf/src/pdm.rs17
-rw-r--r--embassy-nrf/src/pwm.rs7
-rw-r--r--embassy-nrf/src/qdec.rs17
-rw-r--r--embassy-nrf/src/qspi.rs16
-rw-r--r--embassy-nrf/src/rng.rs15
-rw-r--r--embassy-nrf/src/saadc.rs10
-rw-r--r--embassy-nrf/src/spim.rs20
-rw-r--r--embassy-nrf/src/spis.rs20
-rw-r--r--embassy-nrf/src/temp.rs9
-rw-r--r--embassy-nrf/src/time_driver.rs8
-rw-r--r--embassy-nrf/src/timer.rs5
-rw-r--r--embassy-nrf/src/twim.rs16
-rw-r--r--embassy-nrf/src/twis.rs16
-rw-r--r--embassy-nrf/src/uarte.rs129
-rw-r--r--embassy-nrf/src/usb/mod.rs16
-rw-r--r--embassy-nrf/src/usb/vbus_detect.rs16
-rw-r--r--embassy-rp/Cargo.toml20
-rw-r--r--embassy-rp/src/adc.rs136
-rw-r--r--embassy-rp/src/clocks.rs82
-rw-r--r--embassy-rp/src/critical_section_impl.rs19
-rw-r--r--embassy-rp/src/dma.rs63
-rw-r--r--embassy-rp/src/flash.rs84
-rw-r--r--embassy-rp/src/float/div.rs78
-rw-r--r--embassy-rp/src/gpio.rs186
-rw-r--r--embassy-rp/src/i2c.rs357
-rw-r--r--embassy-rp/src/interrupt.rs65
-rw-r--r--embassy-rp/src/lib.rs98
-rw-r--r--embassy-rp/src/multicore.rs63
-rw-r--r--embassy-rp/src/pio.rs468
-rw-r--r--embassy-rp/src/pwm.rs90
-rw-r--r--embassy-rp/src/reset.rs4
-rw-r--r--embassy-rp/src/rtc/mod.rs89
-rw-r--r--embassy-rp/src/spi.rs250
-rw-r--r--embassy-rp/src/timer.rs44
-rw-r--r--embassy-rp/src/uart/buffered.rs279
-rw-r--r--embassy-rp/src/uart/mod.rs325
-rw-r--r--embassy-rp/src/usb.rs312
-rw-r--r--embassy-rp/src/watchdog.rs60
-rw-r--r--embassy-stm32-wpan/Cargo.toml45
-rw-r--r--embassy-stm32-wpan/build.rs34
-rw-r--r--embassy-stm32-wpan/src/ble.rs63
-rw-r--r--embassy-stm32-wpan/src/channels.rs (renamed from embassy-stm32/src/tl_mbox/channels.rs)16
-rw-r--r--embassy-stm32-wpan/src/cmd.rs104
-rw-r--r--embassy-stm32-wpan/src/consts.rs (renamed from embassy-stm32/src/tl_mbox/consts.rs)4
-rw-r--r--embassy-stm32-wpan/src/evt.rs195
-rw-r--r--embassy-stm32-wpan/src/fmt.rs (renamed from embassy-cortex-m/src/fmt.rs)3
-rw-r--r--embassy-stm32-wpan/src/lib.rs255
-rw-r--r--embassy-stm32-wpan/src/mm.rs77
-rw-r--r--embassy-stm32-wpan/src/shci.rs (renamed from embassy-stm32/src/tl_mbox/shci.rs)54
-rw-r--r--embassy-stm32-wpan/src/sys.rs70
-rw-r--r--embassy-stm32-wpan/src/tables.rs175
-rw-r--r--embassy-stm32-wpan/src/unsafe_linked_list.rs257
-rw-r--r--embassy-stm32/Cargo.toml16
-rw-r--r--embassy-stm32/build.rs15
-rw-r--r--embassy-stm32/src/adc/f1.rs92
-rw-r--r--embassy-stm32/src/adc/v1.rs50
-rw-r--r--embassy-stm32/src/adc/v2.rs87
-rw-r--r--embassy-stm32/src/adc/v3.rs184
-rw-r--r--embassy-stm32/src/adc/v4.rs172
-rw-r--r--embassy-stm32/src/can/bxcan.rs13
-rw-r--r--embassy-stm32/src/crc/v1.rs10
-rw-r--r--embassy-stm32/src/crc/v2v3.rs98
-rw-r--r--embassy-stm32/src/dac.rs72
-rw-r--r--embassy-stm32/src/dcmi.rs130
-rw-r--r--embassy-stm32/src/dma/bdma.rs66
-rw-r--r--embassy-stm32/src/dma/dma.rs93
-rw-r--r--embassy-stm32/src/dma/dmamux.rs2
-rw-r--r--embassy-stm32/src/dma/gpdma.rs33
-rw-r--r--embassy-stm32/src/dma/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs403
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs13
-rw-r--r--embassy-stm32/src/eth/v1/tx_desc.rs11
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs29
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs441
-rw-r--r--embassy-stm32/src/exti.rs11
-rw-r--r--embassy-stm32/src/flash/asynch.rs11
-rw-r--r--embassy-stm32/src/flash/f4.rs30
-rw-r--r--embassy-stm32/src/fmc.rs8
-rw-r--r--embassy-stm32/src/gpio.rs42
-rw-r--r--embassy-stm32/src/i2c/mod.rs6
-rw-r--r--embassy-stm32/src/i2c/v1.rs168
-rw-r--r--embassy-stm32/src/i2c/v2.rs394
-rw-r--r--embassy-stm32/src/i2s.rs34
-rw-r--r--embassy-stm32/src/ipcc.rs337
-rw-r--r--embassy-stm32/src/lib.rs121
-rw-r--r--embassy-stm32/src/pwm/complementary_pwm.rs46
-rw-r--r--embassy-stm32/src/pwm/mod.rs58
-rw-r--r--embassy-stm32/src/pwm/simple_pwm.rs36
-rw-r--r--embassy-stm32/src/qspi/mod.rs238
-rw-r--r--embassy-stm32/src/rcc/f4.rs16
-rw-r--r--embassy-stm32/src/rcc/f7.rs4
-rw-r--r--embassy-stm32/src/rcc/g0.rs2
-rw-r--r--embassy-stm32/src/rcc/g4.rs334
-rw-r--r--embassy-stm32/src/rcc/h5.rs15
-rw-r--r--embassy-stm32/src/rcc/h7.rs22
-rw-r--r--embassy-stm32/src/rng.rs46
-rw-r--r--embassy-stm32/src/rtc/datetime.rs44
-rw-r--r--embassy-stm32/src/rtc/mod.rs38
-rw-r--r--embassy-stm32/src/rtc/v2.rs230
-rw-r--r--embassy-stm32/src/rtc/v3.rs234
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs671
-rw-r--r--embassy-stm32/src/spi/mod.rs280
-rw-r--r--embassy-stm32/src/time_driver.rs31
-rw-r--r--embassy-stm32/src/timer/mod.rs70
-rw-r--r--embassy-stm32/src/tl_mbox/ble.rs64
-rw-r--r--embassy-stm32/src/tl_mbox/cmd.rs49
-rw-r--r--embassy-stm32/src/tl_mbox/evt.rs136
-rw-r--r--embassy-stm32/src/tl_mbox/ipcc.rs174
-rw-r--r--embassy-stm32/src/tl_mbox/mm.rs67
-rw-r--r--embassy-stm32/src/tl_mbox/mod.rs417
-rw-r--r--embassy-stm32/src/tl_mbox/sys.rs83
-rw-r--r--embassy-stm32/src/tl_mbox/unsafe_linked_list.rs125
-rw-r--r--embassy-stm32/src/usart/buffered.rs174
-rw-r--r--embassy-stm32/src/usart/mod.rs433
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs81
-rw-r--r--embassy-stm32/src/usb/mod.rs6
-rw-r--r--embassy-stm32/src/usb/usb.rs424
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs12
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs540
-rw-r--r--embassy-stm32/src/wdg/mod.rs12
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/fmt.rs3
-rw-r--r--embassy-sync/src/pipe.rs10
-rw-r--r--embassy-usb-logger/src/lib.rs2
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml1
-rw-r--r--examples/nrf52840-rtic/.cargo/config.toml9
-rw-r--r--examples/nrf52840-rtic/Cargo.toml21
-rw-r--r--examples/nrf52840-rtic/build.rs35
-rw-r--r--examples/nrf52840-rtic/memory.x7
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs43
-rw-r--r--examples/nrf52840/Cargo.toml4
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs38
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs23
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml4
-rw-r--r--examples/rp/src/bin/button.rs5
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs23
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs23
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs24
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs24
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs2
-rw-r--r--examples/rp/src/bin/multicore.rs2
-rw-r--r--examples/rp/src/bin/multiprio.rs18
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs15
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs34
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs18
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs59
-rw-r--r--examples/rp/src/bin/wifi_scan.rs12
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs20
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/std/src/bin/net.rs22
-rw-r--r--examples/std/src/bin/net_dns.rs22
-rw-r--r--examples/std/src/bin/net_udp.rs22
-rw-r--r--examples/std/src/bin/tcp_accept.rs24
-rw-r--r--examples/stm32c0/Cargo.toml2
-rw-r--r--examples/stm32f0/Cargo.toml4
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f0/src/bin/wdg.rs4
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/Cargo.toml4
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f4/Cargo.toml4
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs36
-rw-r--r--examples/stm32f4/src/bin/wdt.rs8
-rw-r--r--examples/stm32f7/Cargo.toml4
-rw-r--r--examples/stm32f7/build.rs3
-rw-r--r--examples/stm32f7/src/bin/eth.rs25
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml3
-rw-r--r--examples/stm32g4/src/bin/pll.rs35
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs108
-rw-r--r--examples/stm32h5/Cargo.toml4
-rw-r--r--examples/stm32h5/src/bin/eth.rs25
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs8
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h7/src/bin/eth.rs25
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs25
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs54
-rw-r--r--examples/stm32h7/src/bin/wdg.rs4
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/Cargo.toml2
-rw-r--r--examples/stm32l4/src/bin/adc.rs10
-rw-r--r--examples/stm32l4/src/bin/dac.rs8
-rw-r--r--examples/stm32l5/Cargo.toml4
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs34
-rw-r--r--examples/stm32u5/Cargo.toml2
-rw-r--r--examples/stm32wb/Cargo.toml3
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs13
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_tx_rx.rs62
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/lora_lorawan.rs2
-rw-r--r--examples/stm32wl/src/bin/random.rs8
-rw-r--r--tests/perf-server/Cargo.toml8
-rwxr-xr-xtests/perf-server/deploy.sh11
-rw-r--r--tests/perf-server/perf-server.service16
-rw-r--r--tests/perf-server/src/main.rs90
-rw-r--r--tests/rp/Cargo.toml10
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs267
-rw-r--r--tests/rp/src/bin/float.rs10
-rw-r--r--tests/stm32/Cargo.toml7
-rw-r--r--tests/stm32/src/bin/rtc.rs6
-rw-r--r--tests/stm32/src/bin/tl_mbox.rs71
253 files changed, 8664 insertions, 8403 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
new file mode 100755
index 000000000..1402e742f
--- /dev/null
+++ b/.github/ci/doc.sh
@@ -0,0 +1,44 @@
1#!/bin/bash
2## on push branch=main
3
4set -euo pipefail
5
6export RUSTUP_HOME=/ci/cache/rustup
7export CARGO_HOME=/ci/cache/cargo
8export CARGO_TARGET_DIR=/ci/cache/target
9export BUILDER_THREADS=6
10export BUILDER_COMPRESS=true
11
12# force rustup to download the toolchain before starting building.
13# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently.
14# They all see the toolchain is not installed and try to install it in parallel
15# which makes rustup very sad
16rustc --version > /dev/null
17
18docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup
19docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup
20docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup
21docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup
22docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup
23docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup
24docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup
25docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup
26docserver-builder -i ./embassy-lora -o crates/embassy-lora/git.zup
27docserver-builder -i ./embassy-net -o crates/embassy-net/git.zup
28docserver-builder -i ./embassy-net-driver -o crates/embassy-net-driver/git.zup
29docserver-builder -i ./embassy-net-driver-channel -o crates/embassy-net-driver-channel/git.zup
30docserver-builder -i ./embassy-nrf -o crates/embassy-nrf/git.zup
31docserver-builder -i ./embassy-rp -o crates/embassy-rp/git.zup
32docserver-builder -i ./embassy-sync -o crates/embassy-sync/git.zup
33docserver-builder -i ./embassy-time -o crates/embassy-time/git.zup
34docserver-builder -i ./embassy-usb -o crates/embassy-usb/git.zup
35docserver-builder -i ./embassy-usb-driver -o crates/embassy-usb-driver/git.zup
36docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup
37docserver-builder -i ./cyw43 -o crates/cyw43/git.zup
38docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup
39docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup
40docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup
41
42export KUBECONFIG=/ci/secrets/kubeconfig.yml
43POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
44kubectl cp crates $POD:/data
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml
deleted file mode 100644
index a69a49718..000000000
--- a/.github/workflows/doc.yml
+++ /dev/null
@@ -1,87 +0,0 @@
1name: Docs
2
3on:
4 push:
5 branches: [main]
6
7env:
8 BUILDER_THREADS: '1'
9
10jobs:
11 doc:
12 runs-on: ubuntu-latest
13
14 # Since stm32 crates take SO LONG to build, we split them
15 # into a separate job. This way it doesn't slow down updating
16 # the rest.
17 strategy:
18 matrix:
19 crates:
20 #- stm32 # runs out of disk space...
21 - rest
22
23 # This will ensure at most one doc build job is running at a time
24 # (for stm32 and non-stm32 independently).
25 # If another job is already running, the new job will wait.
26 # If another job is already waiting, it'll be canceled.
27 # This means some commits will be skipped, but that's fine because
28 # we only care that the latest gets built.
29 concurrency: doc-${{ matrix.crates }}
30
31 steps:
32 - uses: actions/checkout@v3
33 with:
34 submodules: true
35 - name: Install Rust targets
36 run: |
37 rustup target add x86_64-unknown-linux-gnu
38 rustup target add wasm32-unknown-unknown
39 rustup target add thumbv6m-none-eabi
40 rustup target add thumbv7m-none-eabi
41 rustup target add thumbv7em-none-eabi
42 rustup target add thumbv7em-none-eabihf
43 rustup target add thumbv8m.base-none-eabi
44 rustup target add thumbv8m.main-none-eabi
45 rustup target add thumbv8m.main-none-eabihf
46
47 - name: Install docserver
48 run: |
49 wget -q -O /usr/local/bin/builder "https://github.com/embassy-rs/docserver/releases/download/v0.4/builder"
50 chmod +x /usr/local/bin/builder
51
52 - name: build-stm32
53 if: ${{ matrix.crates=='stm32' }}
54 run: |
55 mkdir crates
56 builder ./embassy-stm32 crates/embassy-stm32/git.zup
57
58 - name: build-rest
59 if: ${{ matrix.crates=='rest' }}
60 run: |
61 mkdir crates
62 builder ./embassy-boot/boot crates/embassy-boot/git.zup
63 builder ./embassy-boot/nrf crates/embassy-boot-nrf/git.zup
64 builder ./embassy-boot/rp crates/embassy-boot-rp/git.zup
65 builder ./embassy-boot/stm32 crates/embassy-boot-stm32/git.zup
66 builder ./embassy-cortex-m crates/embassy-cortex-m/git.zup
67 builder ./embassy-embedded-hal crates/embassy-embedded-hal/git.zup
68 builder ./embassy-executor crates/embassy-executor/git.zup
69 builder ./embassy-futures crates/embassy-futures/git.zup
70 builder ./embassy-lora crates/embassy-lora/git.zup
71 builder ./embassy-net crates/embassy-net/git.zup
72 builder ./embassy-net-driver crates/embassy-net-driver/git.zup
73 builder ./embassy-net-driver-channel crates/embassy-net-driver-channel/git.zup
74 builder ./embassy-nrf crates/embassy-nrf/git.zup
75 builder ./embassy-rp crates/embassy-rp/git.zup
76 builder ./embassy-sync crates/embassy-sync/git.zup
77 builder ./embassy-time crates/embassy-time/git.zup
78 builder ./embassy-usb crates/embassy-usb/git.zup
79 builder ./embassy-usb-driver crates/embassy-usb-driver/git.zup
80 builder ./embassy-usb-logger crates/embassy-usb-logger/git.zup
81
82 - name: upload
83 run: |
84 mkdir -p ~/.kube
85 echo "${{secrets.KUBECONFIG}}" > ~/.kube/config
86 POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
87 kubectl cp crates $POD:/data
diff --git a/ci.sh b/ci.sh
index 8a3669f07..760d6fbfb 100755
--- a/ci.sh
+++ b/ci.sh
@@ -3,7 +3,7 @@
3set -euo pipefail 3set -euo pipefail
4 4
5export RUSTFLAGS=-Dwarnings 5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace 6export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info
7 7
8# needed by wifi examples 8# needed by wifi examples
9export WIFI_NETWORK=x 9export WIFI_NETWORK=x
@@ -25,11 +25,19 @@ cargo batch \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
26 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 26 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
27 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ 27 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
28 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ 28 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
29 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 29 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
30 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ 30 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
31 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \ 31 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
32 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \ 32 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \
33 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
34 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
35 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
36 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits,nightly \
37 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
38 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits \
39 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
40 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits,nightly \
33 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \ 41 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
34 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \ 42 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
35 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \ 43 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
@@ -71,6 +79,7 @@ cargo batch \
71 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ 79 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
72 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ 80 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
73 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ 81 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
82 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
74 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \ 83 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
75 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ 84 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
76 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ 85 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
@@ -103,6 +112,7 @@ cargo batch \
103 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ 112 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
104 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ 113 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
105 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 114 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
115 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
106 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 116 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
107 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 117 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
108 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 118 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
@@ -158,4 +168,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
158 exit 168 exit
159fi 169fi
160 170
161teleprobe client run -r out/tests \ No newline at end of file 171teleprobe client run -r out/tests
diff --git a/ci_stable.sh b/ci_stable.sh
index a67087ffb..daae98961 100755
--- a/ci_stable.sh
+++ b/ci_stable.sh
@@ -14,9 +14,11 @@ cargo batch \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ 14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ 15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
17 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ 17 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
18 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 18 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
19 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ 19 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
20 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
21 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
20 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ 22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
21 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ 23 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ 24 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml
index 6e9e784a0..14c07178f 100644
--- a/cyw43-pio/Cargo.toml
+++ b/cyw43-pio/Cargo.toml
@@ -15,3 +15,8 @@ pio-proc = "0.2"
15pio = "0.2.1" 15pio = "0.2.1"
16fixed = "1.23.1" 16fixed = "1.23.1"
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
18
19[package.metadata.embassy_docs]
20src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/"
21src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/"
22target = "thumbv6m-none-eabi"
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index c7f8816f5..61caa0272 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -26,3 +26,9 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
26 26
27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" } 27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" }
28num_enum = { version = "0.5.7", default-features = false } 28num_enum = { version = "0.5.7", default-features = false }
29
30[package.metadata.embassy_docs]
31src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
32src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
33target = "thumbv6m-none-eabi"
34features = ["defmt", "firmware-logs"] \ No newline at end of file
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 6919d569e..c67614dd6 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -381,10 +381,7 @@ impl<'a> Control<'a> {
381 } 381 }
382 382
383 let ioctl = CancelOnDrop(self.ioctl_state); 383 let ioctl = CancelOnDrop(self.ioctl_state);
384 384 let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
385 ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
386 let resp_len = ioctl.0.wait_complete().await;
387
388 ioctl.defuse(); 385 ioctl.defuse();
389 386
390 resp_len 387 resp_len
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs
index 5730447b3..9534c101c 100644
--- a/cyw43/src/fmt.rs
+++ b/cyw43/src/fmt.rs
@@ -197,9 +197,6 @@ macro_rules! unwrap {
197 } 197 }
198} 198}
199 199
200#[cfg(feature = "defmt-timestamp-uptime")]
201defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)] 200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError; 201pub struct NoneError;
205 202
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
index 743d0c342..aecba0755 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
@@ -20,13 +20,13 @@ fn main() -> ! {
20 let led = Output::new(p.PB14, Level::Low, Speed::Low); 20 let led = Output::new(p.PB14, Level::Low, Speed::Low);
21 let mut button = Input::new(p.PC13, Pull::Up); 21 let mut button = Input::new(p.PC13, Pull::Up);
22 22
23 cortex_m::interrupt::free(|cs| unsafe { 23 cortex_m::interrupt::free(|cs| {
24 enable_interrupt(&mut button); 24 enable_interrupt(&mut button);
25 25
26 LED.borrow(cs).borrow_mut().replace(led); 26 LED.borrow(cs).borrow_mut().replace(led);
27 BUTTON.borrow(cs).borrow_mut().replace(button); 27 BUTTON.borrow(cs).borrow_mut().replace(button);
28 28
29 NVIC::unmask(pac::Interrupt::EXTI15_10); 29 unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) };
30 }); 30 });
31 31
32 loop { 32 loop {
@@ -64,25 +64,21 @@ const PORT: u8 = 2;
64const PIN: usize = 13; 64const PIN: usize = 13;
65fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { 65fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
66 let exti = pac::EXTI; 66 let exti = pac::EXTI;
67 unsafe { 67 let pin = PIN;
68 let pin = PIN; 68 let lines = exti.pr(0).read();
69 let lines = exti.pr(0).read(); 69 lines.line(pin)
70 lines.line(pin)
71 }
72} 70}
73 71
74fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 72fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
75 let exti = pac::EXTI; 73 let exti = pac::EXTI;
76 unsafe { 74 let pin = PIN;
77 let pin = PIN; 75 let mut lines = exti.pr(0).read();
78 let mut lines = exti.pr(0).read(); 76 lines.set_line(pin, true);
79 lines.set_line(pin, true); 77 exti.pr(0).write_value(lines);
80 exti.pr(0).write_value(lines);
81 }
82} 78}
83 79
84fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 80fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
85 cortex_m::interrupt::free(|_| unsafe { 81 cortex_m::interrupt::free(|_| {
86 let rcc = pac::RCC; 82 let rcc = pac::RCC;
87 rcc.apb2enr().modify(|w| w.set_syscfgen(true)); 83 rcc.apb2enr().modify(|w| w.set_syscfgen(true));
88 84
diff --git a/embassy-cortex-m/Cargo.toml b/embassy-cortex-m/Cargo.toml
deleted file mode 100644
index 2eb0cce2a..000000000
--- a/embassy-cortex-m/Cargo.toml
+++ /dev/null
@@ -1,47 +0,0 @@
1[package]
2name = "embassy-cortex-m"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[package.metadata.embassy_docs]
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-cortex-m/src/"
10features = ["prio-bits-3"]
11flavors = [
12 { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] },
13 { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] },
14 { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
15 { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
16 { name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] },
17 { name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] },
18 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
19]
20
21[features]
22default = []
23
24# Define the number of NVIC priority bits.
25prio-bits-0 = []
26prio-bits-1 = []
27prio-bits-2 = []
28prio-bits-3 = []
29prio-bits-4 = []
30prio-bits-5 = []
31prio-bits-6 = []
32prio-bits-7 = []
33prio-bits-8 = []
34
35[dependencies]
36defmt = { version = "0.3", optional = true }
37log = { version = "0.4.14", optional = true }
38
39embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
40embassy-executor = { version = "0.2.0", path = "../embassy-executor"}
41embassy-macros = { version = "0.2.0", path = "../embassy-macros"}
42embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
43atomic-polyfill = "1.0.1"
44critical-section = "1.1"
45cfg-if = "1.0.0"
46cortex-m = "0.7.6"
47
diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs
deleted file mode 100644
index e4b713a06..000000000
--- a/embassy-cortex-m/src/lib.rs
+++ /dev/null
@@ -1,10 +0,0 @@
1//! Embassy executor and interrupt handling specific to cortex-m devices.
2#![no_std]
3#![warn(missing_docs)]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8pub use embassy_executor as executor;
9pub mod interrupt;
10pub mod peripheral;
diff --git a/embassy-cortex-m/src/peripheral.rs b/embassy-cortex-m/src/peripheral.rs
deleted file mode 100644
index e2f295579..000000000
--- a/embassy-cortex-m/src/peripheral.rs
+++ /dev/null
@@ -1,144 +0,0 @@
1//! Peripheral interrupt handling specific to cortex-m devices.
2use core::mem::MaybeUninit;
3
4use cortex_m::peripheral::scb::VectActive;
5use cortex_m::peripheral::{NVIC, SCB};
6use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
7
8use crate::interrupt::{Interrupt, InterruptExt, Priority};
9
10/// A type which can be used as state with `PeripheralMutex`.
11///
12/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
13/// and `&mut T` is only `Send` where `T: Send`.
14pub trait PeripheralState: Send {
15 /// The interrupt that is used for this peripheral.
16 type Interrupt: Interrupt;
17
18 /// The interrupt handler that should be invoked for the peripheral. Implementations need to clear the appropriate interrupt flags to ensure the handle will not be called again.
19 fn on_interrupt(&mut self);
20}
21
22/// A type for storing the state of a peripheral that can be stored in a static.
23pub struct StateStorage<S>(MaybeUninit<S>);
24
25impl<S> StateStorage<S> {
26 /// Create a new instance for storing peripheral state.
27 pub const fn new() -> Self {
28 Self(MaybeUninit::uninit())
29 }
30}
31
32/// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in
33/// a safe way.
34pub struct PeripheralMutex<'a, S: PeripheralState> {
35 state: *mut S,
36 irq: PeripheralRef<'a, S::Interrupt>,
37}
38
39/// Whether `irq` can be preempted by the current interrupt.
40pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
41 match SCB::vect_active() {
42 // Thread mode can't preempt anything.
43 VectActive::ThreadMode => false,
44 // Exceptions don't always preempt interrupts,
45 // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
46 VectActive::Exception(_) => true,
47 VectActive::Interrupt { irqn } => {
48 #[derive(Clone, Copy)]
49 struct NrWrap(u16);
50 unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
51 fn number(self) -> u16 {
52 self.0
53 }
54 }
55 NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
56 }
57 }
58}
59
60impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
61 /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
62 ///
63 /// Registers `on_interrupt` as the `irq`'s handler, and enables it.
64 pub fn new(
65 irq: impl Peripheral<P = S::Interrupt> + 'a,
66 storage: &'a mut StateStorage<S>,
67 init: impl FnOnce() -> S,
68 ) -> Self {
69 into_ref!(irq);
70
71 if can_be_preempted(&*irq) {
72 panic!(
73 "`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"
74 );
75 }
76
77 let state_ptr = storage.0.as_mut_ptr();
78
79 // Safety: The pointer is valid and not used by anyone else
80 // because we have the `&mut StateStorage`.
81 unsafe { state_ptr.write(init()) };
82
83 irq.disable();
84 irq.set_handler(|p| unsafe {
85 // Safety: it's OK to get a &mut to the state, since
86 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
87 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
88 // which can't safely store a `PeripheralMutex` across invocations.
89 // - We can't have preempted a with() call because the irq is disabled during it.
90 let state = &mut *(p as *mut S);
91 state.on_interrupt();
92 });
93 irq.set_handler_context(state_ptr as *mut ());
94 irq.enable();
95
96 Self { irq, state: state_ptr }
97 }
98
99 /// Access the peripheral state ensuring interrupts are disabled so that the state can be
100 /// safely accessed.
101 pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
102 self.irq.disable();
103
104 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
105 let state = unsafe { &mut *self.state };
106 let r = f(state);
107
108 self.irq.enable();
109
110 r
111 }
112
113 /// Returns whether the wrapped interrupt is currently in a pending state.
114 pub fn is_pending(&self) -> bool {
115 self.irq.is_pending()
116 }
117
118 /// Forces the wrapped interrupt into a pending state.
119 pub fn pend(&self) {
120 self.irq.pend()
121 }
122
123 /// Forces the wrapped interrupt out of a pending state.
124 pub fn unpend(&self) {
125 self.irq.unpend()
126 }
127
128 /// Gets the priority of the wrapped interrupt.
129 pub fn priority(&self) -> Priority {
130 self.irq.get_priority()
131 }
132}
133
134impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
135 fn drop(&mut self) {
136 self.irq.disable();
137 self.irq.remove_handler();
138
139 // safety:
140 // - we initialized the state in `new`, so we know it's initialized.
141 // - the irq is disabled, so it won't preempt us while dropping.
142 unsafe { self.state.drop_in_place() }
143 }
144}
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index ce032479d..1e5494ef8 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -65,7 +65,7 @@ embassy-macros = { version = "0.2.0", path = "../embassy-macros" }
65embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true} 65embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
66atomic-polyfill = "1.0.1" 66atomic-polyfill = "1.0.1"
67critical-section = "1.1" 67critical-section = "1.1"
68static_cell = "1.0" 68static_cell = "1.1"
69 69
70# arch-cortex-m dependencies 70# arch-cortex-m dependencies
71cortex-m = { version = "0.7.6", optional = true } 71cortex-m = { version = "0.7.6", optional = true }
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index d6a55c4c7..94c8134d6 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -205,5 +205,20 @@ mod interrupt {
205 205
206 executor.spawner().make_send() 206 executor.spawner().make_send()
207 } 207 }
208
209 /// Get a SendSpawner for this executor
210 ///
211 /// This returns a [`SendSpawner`] you can use to spawn tasks on this
212 /// executor.
213 ///
214 /// This MUST only be called on an executor that has already been spawned.
215 /// The function will panic otherwise.
216 pub fn spawner(&'static self) -> crate::SendSpawner {
217 if !self.started.load(Ordering::Acquire) {
218 panic!("InterruptExecutor::spawner() called on uninitialized executor.");
219 }
220 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
221 executor.spawner().make_send()
222 }
208 } 223 }
209} 224}
diff --git a/embassy-futures/src/block_on.rs b/embassy-futures/src/block_on.rs
index da90351ec..77695216c 100644
--- a/embassy-futures/src/block_on.rs
+++ b/embassy-futures/src/block_on.rs
@@ -31,3 +31,15 @@ pub fn block_on<F: Future>(mut fut: F) -> F::Output {
31 } 31 }
32 } 32 }
33} 33}
34
35/// Poll a future once.
36pub fn poll_once<F: Future>(mut fut: F) -> Poll<F::Output> {
37 // safety: we don't move the future after this line.
38 let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
39
40 let raw_waker = RawWaker::new(ptr::null(), &VTABLE);
41 let waker = unsafe { Waker::from_raw(raw_waker) };
42 let mut cx = Context::from_waker(&waker);
43
44 fut.as_mut().poll(&mut cx)
45}
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-futures/src/fmt.rs
+++ b/embassy-futures/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml
index e8617c02f..18c758d7b 100644
--- a/embassy-hal-common/Cargo.toml
+++ b/embassy-hal-common/Cargo.toml
@@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8 8
9# Define the number of NVIC priority bits.
10prio-bits-0 = []
11prio-bits-1 = []
12prio-bits-2 = []
13prio-bits-3 = []
14prio-bits-4 = []
15prio-bits-5 = []
16prio-bits-6 = []
17prio-bits-7 = []
18prio-bits-8 = []
19
20cortex-m = ["dep:cortex-m", "dep:critical-section"]
21
9[dependencies] 22[dependencies]
10defmt = { version = "0.3", optional = true } 23defmt = { version = "0.3", optional = true }
11log = { version = "0.4.14", optional = true } 24log = { version = "0.4.14", optional = true }
12 25
13num-traits = { version = "0.2.14", default-features = false } 26num-traits = { version = "0.2.14", default-features = false }
27
28cortex-m = { version = "0.7.6", optional = true }
29critical-section = { version = "1", optional = true } \ No newline at end of file
diff --git a/embassy-cortex-m/build.rs b/embassy-hal-common/build.rs
index 6fe82b44f..6fe82b44f 100644
--- a/embassy-cortex-m/build.rs
+++ b/embassy-hal-common/build.rs
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-hal-common/src/interrupt.rs
index 3a82726df..b970aa2cd 100644
--- a/embassy-cortex-m/src/interrupt.rs
+++ b/embassy-hal-common/src/interrupt.rs
@@ -1,215 +1,209 @@
1//! Interrupt handling for cortex-m devices. 1//! Interrupt handling for cortex-m devices.
2use core::{mem, ptr}; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
3 4
4use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; 5use cortex_m::interrupt::InterruptNumber;
5use cortex_m::peripheral::NVIC; 6use cortex_m::peripheral::NVIC;
6use embassy_hal_common::Peripheral;
7pub use embassy_macros::cortex_m_interrupt_take as take;
8
9/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
10#[doc(hidden)]
11pub mod _export {
12 pub use atomic_polyfill as atomic;
13 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
14}
15
16/// Interrupt handler trait.
17///
18/// Drivers that need to handle interrupts implement this trait.
19/// The user must ensure `on_interrupt()` is called every time the interrupt fires.
20/// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
21pub trait Handler<I: Interrupt> {
22 /// Interrupt handler function.
23 ///
24 /// Must be called every time the `I` interrupt fires, synchronously from
25 /// the interrupt handler context.
26 ///
27 /// # Safety
28 ///
29 /// This function must ONLY be called from the interrupt handler for `I`.
30 unsafe fn on_interrupt();
31}
32
33/// Compile-time assertion that an interrupt has been bound to a handler.
34///
35/// For the vast majority of cases, you should use the `bind_interrupts!`
36/// macro instead of writing `unsafe impl`s of this trait.
37///
38/// # Safety
39///
40/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
41/// to be called every time the `I` interrupt fires.
42///
43/// This allows drivers to check bindings at compile-time.
44pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
45
46/// Implementation detail, do not use outside embassy crates.
47#[doc(hidden)]
48pub struct DynHandler {
49 pub func: AtomicPtr<()>,
50 pub ctx: AtomicPtr<()>,
51}
52 7
53impl DynHandler { 8/// Generate a standard `mod interrupt` for a HAL.
54 pub const fn new() -> Self { 9#[macro_export]
55 Self { 10macro_rules! interrupt_mod {
56 func: AtomicPtr::new(ptr::null_mut()), 11 ($($irqs:ident),* $(,)?) => {
57 ctx: AtomicPtr::new(ptr::null_mut()), 12 #[cfg(feature = "rt")]
13 pub use cortex_m_rt::interrupt;
14
15 /// Interrupt definitions.
16 pub mod interrupt {
17 pub use $crate::interrupt::{InterruptExt, Priority};
18 pub use crate::pac::Interrupt::*;
19 pub use crate::pac::Interrupt;
20
21 /// Type-level interrupt infrastructure.
22 ///
23 /// This module contains one *type* per interrupt. This is used for checking at compile time that
24 /// the interrupts are correctly bound to HAL drivers.
25 ///
26 /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro
27 /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate
28 /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...)
29 pub mod typelevel {
30 use super::InterruptExt;
31
32 mod sealed {
33 pub trait Interrupt {}
34 }
35
36 /// Type-level interrupt.
37 ///
38 /// This trait is implemented for all typelevel interrupt types in this module.
39 pub trait Interrupt: sealed::Interrupt {
40
41 /// Interrupt enum variant.
42 ///
43 /// This allows going from typelevel interrupts (one type per interrupt) to
44 /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt).
45 const IRQ: super::Interrupt;
46
47 /// Enable the interrupt.
48 #[inline]
49 unsafe fn enable() {
50 Self::IRQ.enable()
51 }
52
53 /// Disable the interrupt.
54 #[inline]
55 fn disable() {
56 Self::IRQ.disable()
57 }
58
59 /// Check if interrupt is enabled.
60 #[inline]
61 fn is_enabled() -> bool {
62 Self::IRQ.is_enabled()
63 }
64
65 /// Check if interrupt is pending.
66 #[inline]
67 fn is_pending() -> bool {
68 Self::IRQ.is_pending()
69 }
70
71 /// Set interrupt pending.
72 #[inline]
73 fn pend() {
74 Self::IRQ.pend()
75 }
76
77 /// Unset interrupt pending.
78 #[inline]
79 fn unpend() {
80 Self::IRQ.unpend()
81 }
82
83 /// Get the priority of the interrupt.
84 #[inline]
85 fn get_priority() -> crate::interrupt::Priority {
86 Self::IRQ.get_priority()
87 }
88
89 /// Set the interrupt priority.
90 #[inline]
91 fn set_priority(prio: crate::interrupt::Priority) {
92 Self::IRQ.set_priority(prio)
93 }
94 }
95
96 $(
97 #[allow(non_camel_case_types)]
98 #[doc=stringify!($irqs)]
99 #[doc=" typelevel interrupt."]
100 pub enum $irqs {}
101 impl sealed::Interrupt for $irqs{}
102 impl Interrupt for $irqs {
103 const IRQ: super::Interrupt = super::Interrupt::$irqs;
104 }
105 )*
106
107 /// Interrupt handler trait.
108 ///
109 /// Drivers that need to handle interrupts implement this trait.
110 /// The user must ensure `on_interrupt()` is called every time the interrupt fires.
111 /// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
112 pub trait Handler<I: Interrupt> {
113 /// Interrupt handler function.
114 ///
115 /// Must be called every time the `I` interrupt fires, synchronously from
116 /// the interrupt handler context.
117 ///
118 /// # Safety
119 ///
120 /// This function must ONLY be called from the interrupt handler for `I`.
121 unsafe fn on_interrupt();
122 }
123
124 /// Compile-time assertion that an interrupt has been bound to a handler.
125 ///
126 /// For the vast majority of cases, you should use the `bind_interrupts!`
127 /// macro instead of writing `unsafe impl`s of this trait.
128 ///
129 /// # Safety
130 ///
131 /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
132 /// to be called every time the `I` interrupt fires.
133 ///
134 /// This allows drivers to check bindings at compile-time.
135 pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
136 }
58 } 137 }
59 } 138 };
60}
61
62#[derive(Clone, Copy)]
63pub(crate) struct NrWrap(pub(crate) u16);
64unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
65 fn number(self) -> u16 {
66 self.0
67 }
68} 139}
69 140
70/// Represents an interrupt type that can be configured by embassy to handle 141/// Represents an interrupt type that can be configured by embassy to handle
71/// interrupts. 142/// interrupts.
72pub unsafe trait Interrupt: Peripheral<P = Self> { 143pub unsafe trait InterruptExt: InterruptNumber + Copy {
73 /// Return the NVIC interrupt number for this interrupt. 144 /// Enable the interrupt.
74 fn number(&self) -> u16;
75 /// Steal an instance of this interrupt
76 ///
77 /// # Safety
78 ///
79 /// This may panic if the interrupt has already been stolen and configured.
80 unsafe fn steal() -> Self;
81
82 /// Implementation detail, do not use outside embassy crates.
83 #[doc(hidden)]
84 unsafe fn __handler(&self) -> &'static DynHandler;
85}
86
87/// Represents additional behavior for all interrupts.
88pub trait InterruptExt: Interrupt {
89 /// Configure the interrupt handler for this interrupt.
90 ///
91 /// # Safety
92 ///
93 /// It is the responsibility of the caller to ensure the handler
94 /// points to a valid handler as long as interrupts are enabled.
95 fn set_handler(&self, func: unsafe fn(*mut ()));
96
97 /// Remove the interrupt handler for this interrupt.
98 fn remove_handler(&self);
99
100 /// Set point to a context that is passed to the interrupt handler when
101 /// an interrupt is pending.
102 ///
103 /// # Safety
104 ///
105 /// It is the responsibility of the caller to ensure the context
106 /// points to a valid handler as long as interrupts are enabled.
107 fn set_handler_context(&self, ctx: *mut ());
108
109 /// Enable the interrupt. Once enabled, the interrupt handler may
110 /// be called "any time".
111 fn enable(&self);
112
113 /// Disable the interrupt.
114 fn disable(&self);
115
116 /// Check if interrupt is being handled.
117 #[cfg(not(armv6m))]
118 fn is_active(&self) -> bool;
119
120 /// Check if interrupt is enabled.
121 fn is_enabled(&self) -> bool;
122
123 /// Check if interrupt is pending.
124 fn is_pending(&self) -> bool;
125
126 /// Set interrupt pending.
127 fn pend(&self);
128
129 /// Unset interrupt pending.
130 fn unpend(&self);
131
132 /// Get the priority of the interrupt.
133 fn get_priority(&self) -> Priority;
134
135 /// Set the interrupt priority.
136 fn set_priority(&self, prio: Priority);
137}
138
139impl<T: Interrupt + ?Sized> InterruptExt for T {
140 fn set_handler(&self, func: unsafe fn(*mut ())) {
141 compiler_fence(Ordering::SeqCst);
142 let handler = unsafe { self.__handler() };
143 handler.func.store(func as *mut (), Ordering::Relaxed);
144 compiler_fence(Ordering::SeqCst);
145 }
146
147 fn remove_handler(&self) {
148 compiler_fence(Ordering::SeqCst);
149 let handler = unsafe { self.__handler() };
150 handler.func.store(ptr::null_mut(), Ordering::Relaxed);
151 compiler_fence(Ordering::SeqCst);
152 }
153
154 fn set_handler_context(&self, ctx: *mut ()) {
155 let handler = unsafe { self.__handler() };
156 handler.ctx.store(ctx, Ordering::Relaxed);
157 }
158
159 #[inline] 145 #[inline]
160 fn enable(&self) { 146 unsafe fn enable(self) {
161 compiler_fence(Ordering::SeqCst); 147 compiler_fence(Ordering::SeqCst);
162 unsafe { 148 NVIC::unmask(self)
163 NVIC::unmask(NrWrap(self.number()));
164 }
165 } 149 }
166 150
151 /// Disable the interrupt.
167 #[inline] 152 #[inline]
168 fn disable(&self) { 153 fn disable(self) {
169 NVIC::mask(NrWrap(self.number())); 154 NVIC::mask(self);
170 compiler_fence(Ordering::SeqCst); 155 compiler_fence(Ordering::SeqCst);
171 } 156 }
172 157
158 /// Check if interrupt is being handled.
173 #[inline] 159 #[inline]
174 #[cfg(not(armv6m))] 160 #[cfg(not(armv6m))]
175 fn is_active(&self) -> bool { 161 fn is_active(self) -> bool {
176 NVIC::is_active(NrWrap(self.number())) 162 NVIC::is_active(self)
177 } 163 }
178 164
165 /// Check if interrupt is enabled.
179 #[inline] 166 #[inline]
180 fn is_enabled(&self) -> bool { 167 fn is_enabled(self) -> bool {
181 NVIC::is_enabled(NrWrap(self.number())) 168 NVIC::is_enabled(self)
182 } 169 }
183 170
171 /// Check if interrupt is pending.
184 #[inline] 172 #[inline]
185 fn is_pending(&self) -> bool { 173 fn is_pending(self) -> bool {
186 NVIC::is_pending(NrWrap(self.number())) 174 NVIC::is_pending(self)
187 } 175 }
188 176
177 /// Set interrupt pending.
189 #[inline] 178 #[inline]
190 fn pend(&self) { 179 fn pend(self) {
191 NVIC::pend(NrWrap(self.number())) 180 NVIC::pend(self)
192 } 181 }
193 182
183 /// Unset interrupt pending.
194 #[inline] 184 #[inline]
195 fn unpend(&self) { 185 fn unpend(self) {
196 NVIC::unpend(NrWrap(self.number())) 186 NVIC::unpend(self)
197 } 187 }
198 188
189 /// Get the priority of the interrupt.
199 #[inline] 190 #[inline]
200 fn get_priority(&self) -> Priority { 191 fn get_priority(self) -> Priority {
201 Priority::from(NVIC::get_priority(NrWrap(self.number()))) 192 Priority::from(NVIC::get_priority(self))
202 } 193 }
203 194
195 /// Set the interrupt priority.
204 #[inline] 196 #[inline]
205 fn set_priority(&self, prio: Priority) { 197 fn set_priority(self, prio: Priority) {
206 unsafe { 198 critical_section::with(|_| unsafe {
207 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); 199 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
208 nvic.set_priority(NrWrap(self.number()), prio.into()) 200 nvic.set_priority(self, prio.into())
209 } 201 })
210 } 202 }
211} 203}
212 204
205unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {}
206
213impl From<u8> for Priority { 207impl From<u8> for Priority {
214 fn from(priority: u8) -> Self { 208 fn from(priority: u8) -> Self {
215 unsafe { mem::transmute(priority & PRIO_MASK) } 209 unsafe { mem::transmute(priority & PRIO_MASK) }
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs
index b2a35cd35..235964aa4 100644
--- a/embassy-hal-common/src/lib.rs
+++ b/embassy-hal-common/src/lib.rs
@@ -11,3 +11,6 @@ mod peripheral;
11pub mod ratio; 11pub mod ratio;
12pub mod ring_buffer; 12pub mod ring_buffer;
13pub use peripheral::{Peripheral, PeripheralRef}; 13pub use peripheral::{Peripheral, PeripheralRef};
14
15#[cfg(feature = "cortex-m")]
16pub mod interrupt;
diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs
index d515bc365..136973fe3 100644
--- a/embassy-lora/src/iv.rs
+++ b/embassy-lora/src/iv.rs
@@ -1,7 +1,7 @@
1#[cfg(feature = "stm32wl")] 1#[cfg(feature = "stm32wl")]
2use embassy_stm32::interrupt; 2use embassy_stm32::interrupt;
3#[cfg(feature = "stm32wl")] 3#[cfg(feature = "stm32wl")]
4use embassy_stm32::interrupt::*; 4use embassy_stm32::interrupt::InterruptExt;
5#[cfg(feature = "stm32wl")] 5#[cfg(feature = "stm32wl")]
6use embassy_stm32::pac; 6use embassy_stm32::pac;
7#[cfg(feature = "stm32wl")] 7#[cfg(feature = "stm32wl")]
@@ -20,9 +20,9 @@ use lora_phy::mod_traits::InterfaceVariant;
20pub struct InterruptHandler {} 20pub struct InterruptHandler {}
21 21
22#[cfg(feature = "stm32wl")] 22#[cfg(feature = "stm32wl")]
23impl interrupt::Handler<interrupt::SUBGHZ_RADIO> for InterruptHandler { 23impl interrupt::typelevel::Handler<interrupt::typelevel::SUBGHZ_RADIO> for InterruptHandler {
24 unsafe fn on_interrupt() { 24 unsafe fn on_interrupt() {
25 unsafe { SUBGHZ_RADIO::steal() }.disable(); 25 interrupt::SUBGHZ_RADIO.disable();
26 IRQ_SIGNAL.signal(()); 26 IRQ_SIGNAL.signal(());
27 } 27 }
28} 28}
@@ -45,11 +45,11 @@ where
45{ 45{
46 /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination 46 /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination
47 pub fn new( 47 pub fn new(
48 _irq: impl interrupt::Binding<interrupt::SUBGHZ_RADIO, InterruptHandler>, 48 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SUBGHZ_RADIO, InterruptHandler>,
49 rf_switch_rx: Option<CTRL>, 49 rf_switch_rx: Option<CTRL>,
50 rf_switch_tx: Option<CTRL>, 50 rf_switch_tx: Option<CTRL>,
51 ) -> Result<Self, RadioError> { 51 ) -> Result<Self, RadioError> {
52 unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable(); 52 interrupt::SUBGHZ_RADIO.disable();
53 Ok(Self { 53 Ok(Self {
54 board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board 54 board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board
55 rf_switch_rx, 55 rf_switch_rx,
@@ -68,34 +68,28 @@ where
68 } 68 }
69 async fn set_nss_low(&mut self) -> Result<(), RadioError> { 69 async fn set_nss_low(&mut self) -> Result<(), RadioError> {
70 let pwr = pac::PWR; 70 let pwr = pac::PWR;
71 unsafe { 71 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
72 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
73 }
74 Ok(()) 72 Ok(())
75 } 73 }
76 async fn set_nss_high(&mut self) -> Result<(), RadioError> { 74 async fn set_nss_high(&mut self) -> Result<(), RadioError> {
77 let pwr = pac::PWR; 75 let pwr = pac::PWR;
78 unsafe { 76 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
79 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
80 }
81 Ok(()) 77 Ok(())
82 } 78 }
83 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { 79 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
84 let rcc = pac::RCC; 80 let rcc = pac::RCC;
85 unsafe { 81 rcc.csr().modify(|w| w.set_rfrst(true));
86 rcc.csr().modify(|w| w.set_rfrst(true)); 82 rcc.csr().modify(|w| w.set_rfrst(false));
87 rcc.csr().modify(|w| w.set_rfrst(false));
88 }
89 Ok(()) 83 Ok(())
90 } 84 }
91 async fn wait_on_busy(&mut self) -> Result<(), RadioError> { 85 async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
92 let pwr = pac::PWR; 86 let pwr = pac::PWR;
93 while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {} 87 while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
94 Ok(()) 88 Ok(())
95 } 89 }
96 90
97 async fn await_irq(&mut self) -> Result<(), RadioError> { 91 async fn await_irq(&mut self) -> Result<(), RadioError> {
98 unsafe { interrupt::SUBGHZ_RADIO::steal() }.enable(); 92 unsafe { interrupt::SUBGHZ_RADIO.enable() };
99 IRQ_SIGNAL.wait().await; 93 IRQ_SIGNAL.wait().await;
100 Ok(()) 94 Ok(())
101 } 95 }
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index dc5b519ff..ba4f13b77 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -156,27 +156,3 @@ pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
156 let f = syn::parse_macro_input!(item as syn::ItemFn); 156 let f = syn::parse_macro_input!(item as syn::ItemFn);
157 main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into() 157 main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
158} 158}
159
160#[proc_macro_attribute]
161pub fn cortex_m_interrupt(args: TokenStream, item: TokenStream) -> TokenStream {
162 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
163 let f = syn::parse_macro_input!(item as syn::ItemFn);
164 cortex_m_interrupt::run(args, f).unwrap_or_else(|x| x).into()
165}
166
167#[proc_macro]
168pub fn cortex_m_interrupt_declare(item: TokenStream) -> TokenStream {
169 let name = syn::parse_macro_input!(item as syn::Ident);
170 cortex_m_interrupt_declare::run(name).unwrap_or_else(|x| x).into()
171}
172
173/// # interrupt_take procedural macro
174///
175/// core::panic! is used as a default way to panic in this macro as there is no sensible way of enabling/disabling defmt for macro generation.
176/// We are aware that this brings bloat in the form of core::fmt, but the bloat is already included with e.g. array indexing panics.
177/// To get rid of this bloat, use the compiler flags `-Zbuild-std=core -Zbuild-std-features=panic_immediate_abort`.
178#[proc_macro]
179pub fn cortex_m_interrupt_take(item: TokenStream) -> TokenStream {
180 let name = syn::parse_macro_input!(item as syn::Ident);
181 cortex_m_interrupt_take::run(name).unwrap_or_else(|x| x).into()
182}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt.rs b/embassy-macros/src/macros/cortex_m_interrupt.rs
deleted file mode 100644
index 13af8ca07..000000000
--- a/embassy-macros/src/macros/cortex_m_interrupt.rs
+++ /dev/null
@@ -1,66 +0,0 @@
1use std::iter;
2
3use darling::FromMeta;
4use proc_macro2::TokenStream;
5use quote::quote;
6use syn::{ReturnType, Type, Visibility};
7
8use crate::util::ctxt::Ctxt;
9
10#[derive(Debug, FromMeta)]
11struct Args {}
12
13pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
14 let _args = Args::from_list(&args).map_err(|e| e.write_errors())?;
15
16 let ident = f.sig.ident.clone();
17 let ident_s = ident.to_string();
18
19 // XXX should we blacklist other attributes?
20
21 let valid_signature = f.sig.constness.is_none()
22 && f.vis == Visibility::Inherited
23 && f.sig.abi.is_none()
24 && f.sig.inputs.is_empty()
25 && f.sig.generics.params.is_empty()
26 && f.sig.generics.where_clause.is_none()
27 && f.sig.variadic.is_none()
28 && match f.sig.output {
29 ReturnType::Default => true,
30 ReturnType::Type(_, ref ty) => match **ty {
31 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
32 Type::Never(..) => true,
33 _ => false,
34 },
35 };
36
37 let ctxt = Ctxt::new();
38
39 if !valid_signature {
40 ctxt.error_spanned_by(
41 &f.sig,
42 "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
43 );
44 }
45
46 ctxt.check()?;
47
48 f.block.stmts = iter::once(
49 syn::parse2(quote! {{
50 // Check that this interrupt actually exists
51 let __irq_exists_check: interrupt::#ident;
52 }})
53 .unwrap(),
54 )
55 .chain(f.block.stmts)
56 .collect();
57
58 let result = quote!(
59 #[doc(hidden)]
60 #[export_name = #ident_s]
61 #[allow(non_snake_case)]
62 #f
63 );
64
65 Ok(result)
66}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
deleted file mode 100644
index 699883efa..000000000
--- a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
+++ /dev/null
@@ -1,34 +0,0 @@
1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
5 let name = format_ident!("{}", name);
6 let name_interrupt = format_ident!("{}", name);
7 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
8
9 let doc = format!("{} interrupt singleton.", name);
10
11 let result = quote! {
12 #[doc = #doc]
13 #[allow(non_camel_case_types)]
14 pub struct #name_interrupt(());
15 unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name_interrupt {
16 fn number(&self) -> u16 {
17 use cortex_m::interrupt::InterruptNumber;
18 let irq = InterruptEnum::#name;
19 irq.number() as u16
20 }
21 unsafe fn steal() -> Self {
22 Self(())
23 }
24 unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler {
25 #[export_name = #name_handler]
26 static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new();
27 &HANDLER
28 }
29 }
30
31 ::embassy_hal_common::impl_peripheral!(#name_interrupt);
32 };
33 Ok(result)
34}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
deleted file mode 100644
index 4806d1c12..000000000
--- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs
+++ /dev/null
@@ -1,57 +0,0 @@
1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
5 let name = format!("{}", name);
6 let name_interrupt = format_ident!("{}", name);
7 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
8
9 #[cfg(feature = "rtos-trace-interrupt")]
10 let (isr_enter, isr_exit) = (
11 quote! {
12 ::embassy_executor::rtos_trace_interrupt! {
13 ::embassy_executor::_export::trace::isr_enter();
14 }
15 },
16 quote! {
17 ::embassy_executor::rtos_trace_interrupt! {
18 ::embassy_executor::_export::trace::isr_exit();
19 }
20 },
21 );
22
23 #[cfg(not(feature = "rtos-trace-interrupt"))]
24 let (isr_enter, isr_exit) = (quote! {}, quote! {});
25
26 let result = quote! {
27 {
28 #[allow(non_snake_case)]
29 #[export_name = #name]
30 pub unsafe extern "C" fn trampoline() {
31 extern "C" {
32 #[link_name = #name_handler]
33 static HANDLER: interrupt::DynHandler;
34 }
35
36 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
37 let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed);
38 let func: fn(*mut ()) = ::core::mem::transmute(func);
39 #isr_enter
40
41 func(ctx);
42 #isr_exit
43
44 }
45
46 static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false);
47
48 if TAKEN.compare_exchange(false, true, interrupt::_export::atomic::Ordering::AcqRel, interrupt::_export::atomic::Ordering::Acquire).is_err() {
49 core::panic!("IRQ Already taken");
50 }
51
52 let irq: interrupt::#name_interrupt = unsafe { ::core::mem::transmute(()) };
53 irq
54 }
55 };
56 Ok(result)
57}
diff --git a/embassy-macros/src/macros/mod.rs b/embassy-macros/src/macros/mod.rs
index e547736fc..572094ca6 100644
--- a/embassy-macros/src/macros/mod.rs
+++ b/embassy-macros/src/macros/mod.rs
@@ -1,5 +1,2 @@
1pub mod cortex_m_interrupt;
2pub mod cortex_m_interrupt_declare;
3pub mod cortex_m_interrupt_take;
4pub mod main; 1pub mod main;
5pub mod task; 2pub mod task;
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-w5500/Cargo.toml
index 3f19e3d39..37d15c7ac 100644
--- a/embassy-net-w5500/Cargo.toml
+++ b/embassy-net-w5500/Cargo.toml
@@ -14,3 +14,8 @@ embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-
14embassy-time = { version = "0.1.0" } 14embassy-time = { version = "0.1.0" }
15embassy-futures = { version = "0.1.0" } 15embassy-futures = { version = "0.1.0" }
16defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
17
18[package.metadata.embassy_docs]
19src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/"
20src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/"
21target = "thumbv7em-none-eabi" \ No newline at end of file
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 0a47c5d94..4ac572577 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -26,7 +26,8 @@ unstable-traits = []
26udp = ["smoltcp/socket-udp"] 26udp = ["smoltcp/socket-udp"]
27tcp = ["smoltcp/socket-tcp"] 27tcp = ["smoltcp/socket-tcp"]
28dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] 28dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
29dhcpv4 = ["medium-ethernet", "smoltcp/socket-dhcpv4"] 29dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
30proto-ipv4 = ["smoltcp/proto-ipv4"]
30proto-ipv6 = ["smoltcp/proto-ipv6"] 31proto-ipv6 = ["smoltcp/proto-ipv6"]
31medium-ethernet = ["smoltcp/medium-ethernet"] 32medium-ethernet = ["smoltcp/medium-ethernet"]
32medium-ip = ["smoltcp/medium-ip"] 33medium-ip = ["smoltcp/medium-ip"]
@@ -38,7 +39,6 @@ defmt = { version = "0.3", optional = true }
38log = { version = "0.4.14", optional = true } 39log = { version = "0.4.14", optional = true }
39 40
40smoltcp = { version = "0.9.0", default-features = false, features = [ 41smoltcp = { version = "0.9.0", default-features = false, features = [
41 "proto-ipv4",
42 "socket", 42 "socket",
43 "async", 43 "async",
44]} 44]}
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index 5daa00544..583cdc87f 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -59,7 +59,10 @@ where
59 smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4); 59 smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
60 smolcaps.checksum.tcp = convert(caps.checksum.tcp); 60 smolcaps.checksum.tcp = convert(caps.checksum.tcp);
61 smolcaps.checksum.udp = convert(caps.checksum.udp); 61 smolcaps.checksum.udp = convert(caps.checksum.udp);
62 smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4); 62 #[cfg(feature = "proto-ipv4")]
63 {
64 smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4);
65 }
63 #[cfg(feature = "proto-ipv6")] 66 #[cfg(feature = "proto-ipv6")]
64 { 67 {
65 smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6); 68 smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6);
diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs
index 3fd235b2c..94f75f108 100644
--- a/embassy-net/src/dns.rs
+++ b/embassy-net/src/dns.rs
@@ -88,6 +88,7 @@ where
88 let addrs = self.query(host, qtype).await?; 88 let addrs = self.query(host, qtype).await?;
89 if let Some(first) = addrs.get(0) { 89 if let Some(first) = addrs.get(0) {
90 Ok(match first { 90 Ok(match first {
91 #[cfg(feature = "proto-ipv4")]
91 IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()), 92 IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()),
92 #[cfg(feature = "proto-ipv6")] 93 #[cfg(feature = "proto-ipv6")]
93 IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()), 94 IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()),
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index bccbad521..7e8f765f9 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -34,7 +34,9 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
34pub use smoltcp::wire::IpListenEndpoint; 34pub use smoltcp::wire::IpListenEndpoint;
35#[cfg(feature = "medium-ethernet")] 35#[cfg(feature = "medium-ethernet")]
36pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; 36pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
37pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; 37pub use smoltcp::wire::{IpAddress, IpCidr};
38#[cfg(feature = "proto-ipv4")]
39pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
38#[cfg(feature = "proto-ipv6")] 40#[cfg(feature = "proto-ipv6")]
39pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; 41pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
40 42
@@ -67,8 +69,9 @@ impl<const SOCK: usize> StackResources<SOCK> {
67} 69}
68 70
69/// Static IP address configuration. 71/// Static IP address configuration.
72#[cfg(feature = "proto-ipv4")]
70#[derive(Debug, Clone, PartialEq, Eq)] 73#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct StaticConfig { 74pub struct StaticConfigV4 {
72 /// IP address and subnet mask. 75 /// IP address and subnet mask.
73 pub address: Ipv4Cidr, 76 pub address: Ipv4Cidr,
74 /// Default gateway. 77 /// Default gateway.
@@ -77,6 +80,18 @@ pub struct StaticConfig {
77 pub dns_servers: Vec<Ipv4Address, 3>, 80 pub dns_servers: Vec<Ipv4Address, 3>,
78} 81}
79 82
83/// Static IPv6 address configuration
84#[cfg(feature = "proto-ipv6")]
85#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct StaticConfigV6 {
87 /// IP address and subnet mask.
88 pub address: Ipv6Cidr,
89 /// Default gateway.
90 pub gateway: Option<Ipv6Address>,
91 /// DNS servers.
92 pub dns_servers: Vec<Ipv6Address, 3>,
93}
94
80/// DHCP configuration. 95/// DHCP configuration.
81#[cfg(feature = "dhcpv4")] 96#[cfg(feature = "dhcpv4")]
82#[derive(Debug, Clone, PartialEq, Eq)] 97#[derive(Debug, Clone, PartialEq, Eq)]
@@ -112,12 +127,71 @@ impl Default for DhcpConfig {
112} 127}
113 128
114/// Network stack configuration. 129/// Network stack configuration.
115pub enum Config { 130pub struct Config {
116 /// Use a static IP address configuration. 131 /// IPv4 configuration
117 Static(StaticConfig), 132 #[cfg(feature = "proto-ipv4")]
133 pub ipv4: ConfigV4,
134 /// IPv6 configuration
135 #[cfg(feature = "proto-ipv6")]
136 pub ipv6: ConfigV6,
137}
138
139impl Config {
140 /// IPv4 configuration with static addressing.
141 #[cfg(feature = "proto-ipv4")]
142 pub fn ipv4_static(config: StaticConfigV4) -> Self {
143 Self {
144 ipv4: ConfigV4::Static(config),
145 #[cfg(feature = "proto-ipv6")]
146 ipv6: ConfigV6::None,
147 }
148 }
149
150 /// IPv6 configuration with static addressing.
151 #[cfg(feature = "proto-ipv6")]
152 pub fn ipv6_static(config: StaticConfigV6) -> Self {
153 Self {
154 #[cfg(feature = "proto-ipv4")]
155 ipv4: ConfigV4::None,
156 ipv6: ConfigV6::Static(config),
157 }
158 }
159
160 /// IPv6 configuration with dynamic addressing.
161 ///
162 /// # Example
163 /// ```rust
164 /// let _cfg = Config::dhcpv4(Default::default());
165 /// ```
166 #[cfg(feature = "dhcpv4")]
167 pub fn dhcpv4(config: DhcpConfig) -> Self {
168 Self {
169 ipv4: ConfigV4::Dhcp(config),
170 #[cfg(feature = "proto-ipv6")]
171 ipv6: ConfigV6::None,
172 }
173 }
174}
175
176/// Network stack IPv4 configuration.
177#[cfg(feature = "proto-ipv4")]
178pub enum ConfigV4 {
179 /// Use a static IPv4 address configuration.
180 Static(StaticConfigV4),
118 /// Use DHCP to obtain an IP address configuration. 181 /// Use DHCP to obtain an IP address configuration.
119 #[cfg(feature = "dhcpv4")] 182 #[cfg(feature = "dhcpv4")]
120 Dhcp(DhcpConfig), 183 Dhcp(DhcpConfig),
184 /// Do not configure IPv6.
185 None,
186}
187
188/// Network stack IPv6 configuration.
189#[cfg(feature = "proto-ipv6")]
190pub enum ConfigV6 {
191 /// Use a static IPv6 address configuration.
192 Static(StaticConfigV6),
193 /// Do not configure IPv6.
194 None,
121} 195}
122 196
123/// A network stack. 197/// A network stack.
@@ -131,7 +205,10 @@ pub struct Stack<D: Driver> {
131struct Inner<D: Driver> { 205struct Inner<D: Driver> {
132 device: D, 206 device: D,
133 link_up: bool, 207 link_up: bool,
134 config: Option<StaticConfig>, 208 #[cfg(feature = "proto-ipv4")]
209 static_v4: Option<StaticConfigV4>,
210 #[cfg(feature = "proto-ipv6")]
211 static_v6: Option<StaticConfigV6>,
135 #[cfg(feature = "dhcpv4")] 212 #[cfg(feature = "dhcpv4")]
136 dhcp_socket: Option<SocketHandle>, 213 dhcp_socket: Option<SocketHandle>,
137 #[cfg(feature = "dns")] 214 #[cfg(feature = "dns")]
@@ -187,7 +264,10 @@ impl<D: Driver + 'static> Stack<D> {
187 let mut inner = Inner { 264 let mut inner = Inner {
188 device, 265 device,
189 link_up: false, 266 link_up: false,
190 config: None, 267 #[cfg(feature = "proto-ipv4")]
268 static_v4: None,
269 #[cfg(feature = "proto-ipv6")]
270 static_v6: None,
191 #[cfg(feature = "dhcpv4")] 271 #[cfg(feature = "dhcpv4")]
192 dhcp_socket: None, 272 dhcp_socket: None,
193 #[cfg(feature = "dns")] 273 #[cfg(feature = "dns")]
@@ -199,17 +279,26 @@ impl<D: Driver + 'static> Stack<D> {
199 dns_waker: WakerRegistration::new(), 279 dns_waker: WakerRegistration::new(),
200 }; 280 };
201 281
202 match config { 282 #[cfg(feature = "proto-ipv4")]
203 Config::Static(config) => { 283 match config.ipv4 {
204 inner.apply_config(&mut socket, config); 284 ConfigV4::Static(config) => {
285 inner.apply_config_v4(&mut socket, config);
205 } 286 }
206 #[cfg(feature = "dhcpv4")] 287 #[cfg(feature = "dhcpv4")]
207 Config::Dhcp(config) => { 288 ConfigV4::Dhcp(config) => {
208 let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); 289 let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
209 inner.apply_dhcp_config(&mut dhcp_socket, config); 290 inner.apply_dhcp_config(&mut dhcp_socket, config);
210 let handle = socket.sockets.add(dhcp_socket); 291 let handle = socket.sockets.add(dhcp_socket);
211 inner.dhcp_socket = Some(handle); 292 inner.dhcp_socket = Some(handle);
212 } 293 }
294 ConfigV4::None => {}
295 }
296 #[cfg(feature = "proto-ipv6")]
297 match config.ipv6 {
298 ConfigV6::Static(config) => {
299 inner.apply_config_v6(&mut socket, config);
300 }
301 ConfigV6::None => {}
213 } 302 }
214 303
215 Self { 304 Self {
@@ -239,12 +328,40 @@ impl<D: Driver + 'static> Stack<D> {
239 /// Get whether the network stack has a valid IP configuration. 328 /// Get whether the network stack has a valid IP configuration.
240 /// This is true if the network stack has a static IP configuration or if DHCP has completed 329 /// This is true if the network stack has a static IP configuration or if DHCP has completed
241 pub fn is_config_up(&self) -> bool { 330 pub fn is_config_up(&self) -> bool {
242 self.with(|_s, i| i.config.is_some()) 331 let v4_up;
332 let v6_up;
333
334 #[cfg(feature = "proto-ipv4")]
335 {
336 v4_up = self.config_v4().is_some();
337 }
338 #[cfg(not(feature = "proto-ipv4"))]
339 {
340 v4_up = false;
341 }
342
343 #[cfg(feature = "proto-ipv6")]
344 {
345 v6_up = self.config_v6().is_some();
346 }
347 #[cfg(not(feature = "proto-ipv6"))]
348 {
349 v6_up = false;
350 }
351
352 v4_up || v6_up
243 } 353 }
244 354
245 /// Get the current IP configuration. 355 /// Get the current IPv4 configuration.
246 pub fn config(&self) -> Option<StaticConfig> { 356 #[cfg(feature = "proto-ipv4")]
247 self.with(|_s, i| i.config.clone()) 357 pub fn config_v4(&self) -> Option<StaticConfigV4> {
358 self.with(|_s, i| i.static_v4.clone())
359 }
360
361 /// Get the current IPv6 configuration.
362 #[cfg(feature = "proto-ipv6")]
363 pub fn config_v6(&self) -> Option<StaticConfigV6> {
364 self.with(|_s, i| i.static_v6.clone())
248 } 365 }
249 366
250 /// Run the network stack. 367 /// Run the network stack.
@@ -264,6 +381,7 @@ impl<D: Driver + 'static> Stack<D> {
264 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> { 381 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
265 // For A and AAAA queries we try detect whether `name` is just an IP address 382 // For A and AAAA queries we try detect whether `name` is just an IP address
266 match qtype { 383 match qtype {
384 #[cfg(feature = "proto-ipv4")]
267 dns::DnsQueryType::A => { 385 dns::DnsQueryType::A => {
268 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) { 386 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
269 return Ok([ip].into_iter().collect()); 387 return Ok([ip].into_iter().collect());
@@ -374,7 +492,8 @@ impl SocketStack {
374} 492}
375 493
376impl<D: Driver + 'static> Inner<D> { 494impl<D: Driver + 'static> Inner<D> {
377 fn apply_config(&mut self, s: &mut SocketStack, config: StaticConfig) { 495 #[cfg(feature = "proto-ipv4")]
496 fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) {
378 #[cfg(feature = "medium-ethernet")] 497 #[cfg(feature = "medium-ethernet")]
379 let medium = self.device.capabilities().medium; 498 let medium = self.device.capabilities().medium;
380 499
@@ -403,14 +522,86 @@ impl<D: Driver + 'static> Inner<D> {
403 debug!(" DNS server {}: {}", i, s); 522 debug!(" DNS server {}: {}", i, s);
404 } 523 }
405 524
525 self.static_v4 = Some(config);
526
406 #[cfg(feature = "dns")] 527 #[cfg(feature = "dns")]
407 { 528 {
408 let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket); 529 self.update_dns_servers(s)
409 let servers: Vec<IpAddress, 3> = config.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)).collect(); 530 }
410 socket.update_servers(&servers[..]); 531 }
532
533 /// Replaces the current IPv6 static configuration with a newly supplied config.
534 #[cfg(feature = "proto-ipv6")]
535 fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) {
536 #[cfg(feature = "medium-ethernet")]
537 let medium = self.device.capabilities().medium;
538
539 debug!("Acquired IPv6 configuration:");
540
541 debug!(" IP address: {}", config.address);
542 s.iface.update_ip_addrs(|addrs| {
543 if addrs.is_empty() {
544 addrs.push(IpCidr::Ipv6(config.address)).unwrap();
545 } else {
546 addrs[0] = IpCidr::Ipv6(config.address);
547 }
548 });
549
550 #[cfg(feature = "medium-ethernet")]
551 if Medium::Ethernet == medium {
552 if let Some(gateway) = config.gateway {
553 debug!(" Default gateway: {}", gateway);
554 s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap();
555 } else {
556 debug!(" Default gateway: None");
557 s.iface.routes_mut().remove_default_ipv6_route();
558 }
559 }
560 for (i, s) in config.dns_servers.iter().enumerate() {
561 debug!(" DNS server {}: {}", i, s);
411 } 562 }
412 563
413 self.config = Some(config) 564 self.static_v6 = Some(config);
565
566 #[cfg(feature = "dns")]
567 {
568 self.update_dns_servers(s)
569 }
570 }
571
572 #[cfg(feature = "dns")]
573 fn update_dns_servers(&mut self, s: &mut SocketStack) {
574 let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket);
575
576 let servers_v4;
577 #[cfg(feature = "proto-ipv4")]
578 {
579 servers_v4 = self
580 .static_v4
581 .iter()
582 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)));
583 };
584 #[cfg(not(feature = "proto-ipv4"))]
585 {
586 servers_v4 = core::iter::empty();
587 }
588
589 let servers_v6;
590 #[cfg(feature = "proto-ipv6")]
591 {
592 servers_v6 = self
593 .static_v6
594 .iter()
595 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c)));
596 }
597 #[cfg(not(feature = "proto-ipv6"))]
598 {
599 servers_v6 = core::iter::empty();
600 }
601
602 // Prefer the v6 DNS servers over the v4 servers
603 let servers: Vec<IpAddress, 6> = servers_v6.chain(servers_v4).collect();
604 socket.update_servers(&servers[..]);
414 } 605 }
415 606
416 #[cfg(feature = "dhcpv4")] 607 #[cfg(feature = "dhcpv4")]
@@ -430,9 +621,15 @@ impl<D: Driver + 'static> Inner<D> {
430 s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); 621 s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear());
431 #[cfg(feature = "medium-ethernet")] 622 #[cfg(feature = "medium-ethernet")]
432 if medium == Medium::Ethernet { 623 if medium == Medium::Ethernet {
433 s.iface.routes_mut().remove_default_ipv4_route(); 624 #[cfg(feature = "proto-ipv4")]
625 {
626 s.iface.routes_mut().remove_default_ipv4_route();
627 }
628 }
629 #[cfg(feature = "proto-ipv4")]
630 {
631 self.static_v4 = None
434 } 632 }
435 self.config = None
436 } 633 }
437 634
438 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { 635 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
@@ -470,12 +667,12 @@ impl<D: Driver + 'static> Inner<D> {
470 None => {} 667 None => {}
471 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), 668 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
472 Some(dhcpv4::Event::Configured(config)) => { 669 Some(dhcpv4::Event::Configured(config)) => {
473 let config = StaticConfig { 670 let config = StaticConfigV4 {
474 address: config.address, 671 address: config.address,
475 gateway: config.router, 672 gateway: config.router,
476 dns_servers: config.dns_servers, 673 dns_servers: config.dns_servers,
477 }; 674 };
478 self.apply_config(s, config) 675 self.apply_config_v4(s, config)
479 } 676 }
480 } 677 }
481 } else if old_link_up { 678 } else if old_link_up {
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 7babb5293..367675b13 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -278,10 +278,18 @@ impl<'a> TcpSocket<'a> {
278 self.io.with(|s, _| s.may_send()) 278 self.io.with(|s, _| s.may_send())
279 } 279 }
280 280
281 /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer. 281 /// return whether the recieve half of the full-duplex connection is open.
282 /// This function returns true if it’s possible to receive data from the remote endpoint.
283 /// It will return true while there is data in the receive buffer, and if there isn’t,
284 /// as long as the remote endpoint has not closed the connection.
282 pub fn may_recv(&self) -> bool { 285 pub fn may_recv(&self) -> bool {
283 self.io.with(|s, _| s.may_recv()) 286 self.io.with(|s, _| s.may_recv())
284 } 287 }
288
289 /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer.
290 pub fn can_recv(&self) -> bool {
291 self.io.with(|s, _| s.can_recv())
292 }
285} 293}
286 294
287impl<'a> Drop for TcpSocket<'a> { 295impl<'a> Drop for TcpSocket<'a> {
@@ -472,7 +480,10 @@ pub mod client {
472 Self: 'a, 480 Self: 'a,
473 { 481 {
474 let addr: crate::IpAddress = match remote.ip() { 482 let addr: crate::IpAddress = match remote.ip() {
483 #[cfg(feature = "proto-ipv4")]
475 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), 484 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
485 #[cfg(not(feature = "proto-ipv4"))]
486 IpAddr::V4(_) => panic!("ipv4 support not enabled"),
476 #[cfg(feature = "proto-ipv6")] 487 #[cfg(feature = "proto-ipv6")]
477 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), 488 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
478 #[cfg(not(feature = "proto-ipv6"))] 489 #[cfg(not(feature = "proto-ipv6"))]
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 83900d4d0..3e858f854 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -16,7 +16,8 @@ flavors = [
16] 16]
17 17
18[features] 18[features]
19default = [ 19default = ["rt"]
20rt = [
20 "nrf52805-pac?/rt", 21 "nrf52805-pac?/rt",
21 "nrf52810-pac?/rt", 22 "nrf52810-pac?/rt",
22 "nrf52811-pac?/rt", 23 "nrf52811-pac?/rt",
@@ -31,7 +32,7 @@ default = [
31 32
32time = ["dep:embassy-time"] 33time = ["dep:embassy-time"]
33 34
34defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] 35defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
35 36
36# Enable nightly-only features 37# Enable nightly-only features
37nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] 38nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
@@ -90,11 +91,9 @@ _dppi = []
90_gpio-p1 = [] 91_gpio-p1 = []
91 92
92[dependencies] 93[dependencies]
93embassy-executor = { version = "0.2.0", path = "../embassy-executor", optional = true }
94embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 94embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
95embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 95embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
96embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} 96embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] }
97embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
98embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
99embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } 98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
100 99
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 4d053c023..9bc1c1e7a 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -15,7 +15,6 @@ use core::slice;
15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; 15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
16use core::task::Poll; 16use core::task::Poll;
17 17
18use embassy_cortex_m::interrupt::Interrupt;
19use embassy_hal_common::atomic_ring_buffer::RingBuffer; 18use embassy_hal_common::atomic_ring_buffer::RingBuffer;
20use embassy_hal_common::{into_ref, PeripheralRef}; 19use embassy_hal_common::{into_ref, PeripheralRef};
21use embassy_sync::waitqueue::AtomicWaker; 20use embassy_sync::waitqueue::AtomicWaker;
@@ -24,13 +23,13 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
24 23
25use crate::gpio::sealed::Pin; 24use crate::gpio::sealed::Pin;
26use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 25use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
27use crate::interrupt::{self, InterruptExt}; 26use crate::interrupt::typelevel::Interrupt;
28use crate::ppi::{ 27use crate::ppi::{
29 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, 28 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
30}; 29};
31use crate::timer::{Instance as TimerInstance, Timer}; 30use crate::timer::{Instance as TimerInstance, Timer};
32use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; 31use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
33use crate::{pac, Peripheral}; 32use crate::{interrupt, pac, Peripheral};
34 33
35mod sealed { 34mod sealed {
36 use super::*; 35 use super::*;
@@ -77,7 +76,7 @@ pub struct InterruptHandler<U: UarteInstance> {
77 _phantom: PhantomData<U>, 76 _phantom: PhantomData<U>,
78} 77}
79 78
80impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> { 79impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for InterruptHandler<U> {
81 unsafe fn on_interrupt() { 80 unsafe fn on_interrupt() {
82 //trace!("irq: start"); 81 //trace!("irq: start");
83 let r = U::regs(); 82 let r = U::regs();
@@ -202,7 +201,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
202 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, 201 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
203 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, 202 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
204 ppi_group: impl Peripheral<P = impl Group> + 'd, 203 ppi_group: impl Peripheral<P = impl Group> + 'd,
205 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, 204 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
206 rxd: impl Peripheral<P = impl GpioPin> + 'd, 205 rxd: impl Peripheral<P = impl GpioPin> + 'd,
207 txd: impl Peripheral<P = impl GpioPin> + 'd, 206 txd: impl Peripheral<P = impl GpioPin> + 'd,
208 config: Config, 207 config: Config,
@@ -237,7 +236,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
237 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, 236 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
238 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, 237 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
239 ppi_group: impl Peripheral<P = impl Group> + 'd, 238 ppi_group: impl Peripheral<P = impl Group> + 'd,
240 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, 239 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
241 rxd: impl Peripheral<P = impl GpioPin> + 'd, 240 rxd: impl Peripheral<P = impl GpioPin> + 'd,
242 txd: impl Peripheral<P = impl GpioPin> + 'd, 241 txd: impl Peripheral<P = impl GpioPin> + 'd,
243 cts: impl Peripheral<P = impl GpioPin> + 'd, 242 cts: impl Peripheral<P = impl GpioPin> + 'd,
@@ -362,8 +361,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
362 ppi_ch2.disable(); 361 ppi_ch2.disable();
363 ppi_group.add_channel(&ppi_ch2); 362 ppi_group.add_channel(&ppi_ch2);
364 363
365 unsafe { U::Interrupt::steal() }.pend(); 364 U::Interrupt::pend();
366 unsafe { U::Interrupt::steal() }.enable(); 365 unsafe { U::Interrupt::enable() };
367 366
368 Self { 367 Self {
369 _peri: peri, 368 _peri: peri,
@@ -375,7 +374,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
375 } 374 }
376 375
377 fn pend_irq() { 376 fn pend_irq() {
378 unsafe { <U::Interrupt as Interrupt>::steal() }.pend() 377 U::Interrupt::pend()
379 } 378 }
380 379
381 /// Adjust the baud rate to the provided value. 380 /// Adjust the baud rate to the provided value.
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index e406c081b..8776000c8 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -208,33 +208,29 @@ impl_ppi_channel!(PPI_CH31, 31 => static);
208impl_saadc_input!(P0_04, ANALOG_INPUT2); 208impl_saadc_input!(P0_04, ANALOG_INPUT2);
209impl_saadc_input!(P0_05, ANALOG_INPUT3); 209impl_saadc_input!(P0_05, ANALOG_INPUT3);
210 210
211pub mod irqs { 211embassy_hal_common::interrupt_mod!(
212 use embassy_cortex_m::interrupt::_export::declare; 212 POWER_CLOCK,
213 213 RADIO,
214 use crate::pac::Interrupt as InterruptEnum; 214 UARTE0_UART0,
215 215 TWIM0_TWIS0_TWI0,
216 declare!(POWER_CLOCK); 216 SPIM0_SPIS0_SPI0,
217 declare!(RADIO); 217 GPIOTE,
218 declare!(UARTE0_UART0); 218 SAADC,
219 declare!(TWIM0_TWIS0_TWI0); 219 TIMER0,
220 declare!(SPIM0_SPIS0_SPI0); 220 TIMER1,
221 declare!(GPIOTE); 221 TIMER2,
222 declare!(SAADC); 222 RTC0,
223 declare!(TIMER0); 223 TEMP,
224 declare!(TIMER1); 224 RNG,
225 declare!(TIMER2); 225 ECB,
226 declare!(RTC0); 226 CCM_AAR,
227 declare!(TEMP); 227 WDT,
228 declare!(RNG); 228 RTC1,
229 declare!(ECB); 229 QDEC,
230 declare!(CCM_AAR); 230 SWI0_EGU0,
231 declare!(WDT); 231 SWI1_EGU1,
232 declare!(RTC1); 232 SWI2,
233 declare!(QDEC); 233 SWI3,
234 declare!(SWI0_EGU0); 234 SWI4,
235 declare!(SWI1_EGU1); 235 SWI5,
236 declare!(SWI2); 236);
237 declare!(SWI3);
238 declare!(SWI4);
239 declare!(SWI5);
240}
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index 153795e54..5519e8953 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -234,36 +234,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
234impl_saadc_input!(P0_30, ANALOG_INPUT6); 234impl_saadc_input!(P0_30, ANALOG_INPUT6);
235impl_saadc_input!(P0_31, ANALOG_INPUT7); 235impl_saadc_input!(P0_31, ANALOG_INPUT7);
236 236
237pub mod irqs { 237embassy_hal_common::interrupt_mod!(
238 use embassy_cortex_m::interrupt::_export::declare; 238 POWER_CLOCK,
239 239 RADIO,
240 use crate::pac::Interrupt as InterruptEnum; 240 UARTE0_UART0,
241 241 TWIM0_TWIS0_TWI0,
242 declare!(POWER_CLOCK); 242 SPIM0_SPIS0_SPI0,
243 declare!(RADIO); 243 GPIOTE,
244 declare!(UARTE0_UART0); 244 SAADC,
245 declare!(TWIM0_TWIS0_TWI0); 245 TIMER0,
246 declare!(SPIM0_SPIS0_SPI0); 246 TIMER1,
247 declare!(GPIOTE); 247 TIMER2,
248 declare!(SAADC); 248 RTC0,
249 declare!(TIMER0); 249 TEMP,
250 declare!(TIMER1); 250 RNG,
251 declare!(TIMER2); 251 ECB,
252 declare!(RTC0); 252 CCM_AAR,
253 declare!(TEMP); 253 WDT,
254 declare!(RNG); 254 RTC1,
255 declare!(ECB); 255 QDEC,
256 declare!(CCM_AAR); 256 COMP,
257 declare!(WDT); 257 SWI0_EGU0,
258 declare!(RTC1); 258 SWI1_EGU1,
259 declare!(QDEC); 259 SWI2,
260 declare!(COMP); 260 SWI3,
261 declare!(SWI0_EGU0); 261 SWI4,
262 declare!(SWI1_EGU1); 262 SWI5,
263 declare!(SWI2); 263 PWM0,
264 declare!(SWI3); 264 PDM,
265 declare!(SWI4); 265);
266 declare!(SWI5);
267 declare!(PWM0);
268 declare!(PDM);
269}
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index a7a7cf58c..d5367c59a 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -236,36 +236,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
236impl_saadc_input!(P0_30, ANALOG_INPUT6); 236impl_saadc_input!(P0_30, ANALOG_INPUT6);
237impl_saadc_input!(P0_31, ANALOG_INPUT7); 237impl_saadc_input!(P0_31, ANALOG_INPUT7);
238 238
239pub mod irqs { 239embassy_hal_common::interrupt_mod!(
240 use embassy_cortex_m::interrupt::_export::declare; 240 POWER_CLOCK,
241 241 RADIO,
242 use crate::pac::Interrupt as InterruptEnum; 242 UARTE0_UART0,
243 243 TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0,
244 declare!(POWER_CLOCK); 244 SPIM1_SPIS1_SPI1,
245 declare!(RADIO); 245 GPIOTE,
246 declare!(UARTE0_UART0); 246 SAADC,
247 declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 247 TIMER0,
248 declare!(SPIM1_SPIS1_SPI1); 248 TIMER1,
249 declare!(GPIOTE); 249 TIMER2,
250 declare!(SAADC); 250 RTC0,
251 declare!(TIMER0); 251 TEMP,
252 declare!(TIMER1); 252 RNG,
253 declare!(TIMER2); 253 ECB,
254 declare!(RTC0); 254 CCM_AAR,
255 declare!(TEMP); 255 WDT,
256 declare!(RNG); 256 RTC1,
257 declare!(ECB); 257 QDEC,
258 declare!(CCM_AAR); 258 COMP,
259 declare!(WDT); 259 SWI0_EGU0,
260 declare!(RTC1); 260 SWI1_EGU1,
261 declare!(QDEC); 261 SWI2,
262 declare!(COMP); 262 SWI3,
263 declare!(SWI0_EGU0); 263 SWI4,
264 declare!(SWI1_EGU1); 264 SWI5,
265 declare!(SWI2); 265 PWM0,
266 declare!(SWI3); 266 PDM,
267 declare!(SWI4); 267);
268 declare!(SWI5);
269 declare!(PWM0);
270 declare!(PDM);
271}
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index 14a1b8cc9..785170447 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -224,35 +224,31 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
224impl_ppi_channel!(PPI_CH30, 30 => static); 224impl_ppi_channel!(PPI_CH30, 30 => static);
225impl_ppi_channel!(PPI_CH31, 31 => static); 225impl_ppi_channel!(PPI_CH31, 31 => static);
226 226
227pub mod irqs { 227embassy_hal_common::interrupt_mod!(
228 use embassy_cortex_m::interrupt::_export::declare; 228 POWER_CLOCK,
229 229 RADIO,
230 use crate::pac::Interrupt as InterruptEnum; 230 UARTE0_UART0,
231 231 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
232 declare!(POWER_CLOCK); 232 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
233 declare!(RADIO); 233 GPIOTE,
234 declare!(UARTE0_UART0); 234 TIMER0,
235 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 235 TIMER1,
236 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 236 TIMER2,
237 declare!(GPIOTE); 237 RTC0,
238 declare!(TIMER0); 238 TEMP,
239 declare!(TIMER1); 239 RNG,
240 declare!(TIMER2); 240 ECB,
241 declare!(RTC0); 241 CCM_AAR,
242 declare!(TEMP); 242 WDT,
243 declare!(RNG); 243 RTC1,
244 declare!(ECB); 244 QDEC,
245 declare!(CCM_AAR); 245 COMP,
246 declare!(WDT); 246 SWI0_EGU0,
247 declare!(RTC1); 247 SWI1_EGU1,
248 declare!(QDEC); 248 SWI2_EGU2,
249 declare!(COMP); 249 SWI3_EGU3,
250 declare!(SWI0_EGU0); 250 SWI4_EGU4,
251 declare!(SWI1_EGU1); 251 SWI5_EGU5,
252 declare!(SWI2_EGU2); 252 TIMER3,
253 declare!(SWI3_EGU3); 253 USBD,
254 declare!(SWI4_EGU4); 254);
255 declare!(SWI5_EGU5);
256 declare!(TIMER3);
257 declare!(USBD);
258}
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 83ecd0deb..b77564a5c 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -263,46 +263,42 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
263 263
264impl_i2s!(I2S, I2S, I2S); 264impl_i2s!(I2S, I2S, I2S);
265 265
266pub mod irqs { 266embassy_hal_common::interrupt_mod!(
267 use embassy_cortex_m::interrupt::_export::declare; 267 POWER_CLOCK,
268 268 RADIO,
269 use crate::pac::Interrupt as InterruptEnum; 269 UARTE0_UART0,
270 270 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
271 declare!(POWER_CLOCK); 271 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
272 declare!(RADIO); 272 NFCT,
273 declare!(UARTE0_UART0); 273 GPIOTE,
274 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 274 SAADC,
275 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 275 TIMER0,
276 declare!(NFCT); 276 TIMER1,
277 declare!(GPIOTE); 277 TIMER2,
278 declare!(SAADC); 278 RTC0,
279 declare!(TIMER0); 279 TEMP,
280 declare!(TIMER1); 280 RNG,
281 declare!(TIMER2); 281 ECB,
282 declare!(RTC0); 282 CCM_AAR,
283 declare!(TEMP); 283 WDT,
284 declare!(RNG); 284 RTC1,
285 declare!(ECB); 285 QDEC,
286 declare!(CCM_AAR); 286 COMP_LPCOMP,
287 declare!(WDT); 287 SWI0_EGU0,
288 declare!(RTC1); 288 SWI1_EGU1,
289 declare!(QDEC); 289 SWI2_EGU2,
290 declare!(COMP_LPCOMP); 290 SWI3_EGU3,
291 declare!(SWI0_EGU0); 291 SWI4_EGU4,
292 declare!(SWI1_EGU1); 292 SWI5_EGU5,
293 declare!(SWI2_EGU2); 293 TIMER3,
294 declare!(SWI3_EGU3); 294 TIMER4,
295 declare!(SWI4_EGU4); 295 PWM0,
296 declare!(SWI5_EGU5); 296 PDM,
297 declare!(TIMER3); 297 MWU,
298 declare!(TIMER4); 298 PWM1,
299 declare!(PWM0); 299 PWM2,
300 declare!(PDM); 300 SPIM2_SPIS2_SPI2,
301 declare!(MWU); 301 RTC2,
302 declare!(PWM1); 302 FPU,
303 declare!(PWM2); 303 I2S,
304 declare!(SPIM2_SPIS2_SPI2); 304);
305 declare!(RTC2);
306 declare!(FPU);
307 declare!(I2S);
308}
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 5e5db04de..bff7f4ebb 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -306,50 +306,46 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
306 306
307impl_i2s!(I2S, I2S, I2S); 307impl_i2s!(I2S, I2S, I2S);
308 308
309pub mod irqs { 309embassy_hal_common::interrupt_mod!(
310 use embassy_cortex_m::interrupt::_export::declare; 310 POWER_CLOCK,
311 311 RADIO,
312 use crate::pac::Interrupt as InterruptEnum; 312 UARTE0_UART0,
313 313 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
314 declare!(POWER_CLOCK); 314 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
315 declare!(RADIO); 315 NFCT,
316 declare!(UARTE0_UART0); 316 GPIOTE,
317 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 317 SAADC,
318 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 318 TIMER0,
319 declare!(NFCT); 319 TIMER1,
320 declare!(GPIOTE); 320 TIMER2,
321 declare!(SAADC); 321 RTC0,
322 declare!(TIMER0); 322 TEMP,
323 declare!(TIMER1); 323 RNG,
324 declare!(TIMER2); 324 ECB,
325 declare!(RTC0); 325 CCM_AAR,
326 declare!(TEMP); 326 WDT,
327 declare!(RNG); 327 RTC1,
328 declare!(ECB); 328 QDEC,
329 declare!(CCM_AAR); 329 COMP_LPCOMP,
330 declare!(WDT); 330 SWI0_EGU0,
331 declare!(RTC1); 331 SWI1_EGU1,
332 declare!(QDEC); 332 SWI2_EGU2,
333 declare!(COMP_LPCOMP); 333 SWI3_EGU3,
334 declare!(SWI0_EGU0); 334 SWI4_EGU4,
335 declare!(SWI1_EGU1); 335 SWI5_EGU5,
336 declare!(SWI2_EGU2); 336 TIMER3,
337 declare!(SWI3_EGU3); 337 TIMER4,
338 declare!(SWI4_EGU4); 338 PWM0,
339 declare!(SWI5_EGU5); 339 PDM,
340 declare!(TIMER3); 340 MWU,
341 declare!(TIMER4); 341 PWM1,
342 declare!(PWM0); 342 PWM2,
343 declare!(PDM); 343 SPIM2_SPIS2_SPI2,
344 declare!(MWU); 344 RTC2,
345 declare!(PWM1); 345 FPU,
346 declare!(PWM2); 346 USBD,
347 declare!(SPIM2_SPIS2_SPI2); 347 UARTE1,
348 declare!(RTC2); 348 PWM3,
349 declare!(FPU); 349 SPIM3,
350 declare!(USBD); 350 I2S,
351 declare!(UARTE1); 351);
352 declare!(PWM3);
353 declare!(SPIM3);
354 declare!(I2S);
355}
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index f6d33f85c..9b0050823 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -311,52 +311,48 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
311 311
312impl_i2s!(I2S, I2S, I2S); 312impl_i2s!(I2S, I2S, I2S);
313 313
314pub mod irqs { 314embassy_hal_common::interrupt_mod!(
315 use embassy_cortex_m::interrupt::_export::declare; 315 POWER_CLOCK,
316 316 RADIO,
317 use crate::pac::Interrupt as InterruptEnum; 317 UARTE0_UART0,
318 318 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
319 declare!(POWER_CLOCK); 319 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
320 declare!(RADIO); 320 NFCT,
321 declare!(UARTE0_UART0); 321 GPIOTE,
322 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 322 SAADC,
323 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 323 TIMER0,
324 declare!(NFCT); 324 TIMER1,
325 declare!(GPIOTE); 325 TIMER2,
326 declare!(SAADC); 326 RTC0,
327 declare!(TIMER0); 327 TEMP,
328 declare!(TIMER1); 328 RNG,
329 declare!(TIMER2); 329 ECB,
330 declare!(RTC0); 330 CCM_AAR,
331 declare!(TEMP); 331 WDT,
332 declare!(RNG); 332 RTC1,
333 declare!(ECB); 333 QDEC,
334 declare!(CCM_AAR); 334 COMP_LPCOMP,
335 declare!(WDT); 335 SWI0_EGU0,
336 declare!(RTC1); 336 SWI1_EGU1,
337 declare!(QDEC); 337 SWI2_EGU2,
338 declare!(COMP_LPCOMP); 338 SWI3_EGU3,
339 declare!(SWI0_EGU0); 339 SWI4_EGU4,
340 declare!(SWI1_EGU1); 340 SWI5_EGU5,
341 declare!(SWI2_EGU2); 341 TIMER3,
342 declare!(SWI3_EGU3); 342 TIMER4,
343 declare!(SWI4_EGU4); 343 PWM0,
344 declare!(SWI5_EGU5); 344 PDM,
345 declare!(TIMER3); 345 MWU,
346 declare!(TIMER4); 346 PWM1,
347 declare!(PWM0); 347 PWM2,
348 declare!(PDM); 348 SPIM2_SPIS2_SPI2,
349 declare!(MWU); 349 RTC2,
350 declare!(PWM1); 350 FPU,
351 declare!(PWM2); 351 USBD,
352 declare!(SPIM2_SPIS2_SPI2); 352 UARTE1,
353 declare!(RTC2); 353 QSPI,
354 declare!(FPU); 354 CRYPTOCELL,
355 declare!(USBD); 355 PWM3,
356 declare!(UARTE1); 356 SPIM3,
357 declare!(QSPI); 357 I2S,
358 declare!(CRYPTOCELL); 358);
359 declare!(PWM3);
360 declare!(SPIM3);
361 declare!(I2S);
362}
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 34f96800f..410ae921c 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF5340 has a secure and non-secure (NS) mode. 5 // The nRF5340 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf5340_app_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf5340_app_pac::{ 11 pub use nrf5340_app_pac::{
10 interrupt, 12 interrupt,
@@ -504,50 +506,46 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
504impl_saadc_input!(P0_19, ANALOG_INPUT6); 506impl_saadc_input!(P0_19, ANALOG_INPUT6);
505impl_saadc_input!(P0_20, ANALOG_INPUT7); 507impl_saadc_input!(P0_20, ANALOG_INPUT7);
506 508
507pub mod irqs { 509embassy_hal_common::interrupt_mod!(
508 use embassy_cortex_m::interrupt::_export::declare; 510 FPU,
509 511 CACHE,
510 use crate::pac::Interrupt as InterruptEnum; 512 SPU,
511 513 CLOCK_POWER,
512 declare!(FPU); 514 SERIAL0,
513 declare!(CACHE); 515 SERIAL1,
514 declare!(SPU); 516 SPIM4,
515 declare!(CLOCK_POWER); 517 SERIAL2,
516 declare!(SERIAL0); 518 SERIAL3,
517 declare!(SERIAL1); 519 GPIOTE0,
518 declare!(SPIM4); 520 SAADC,
519 declare!(SERIAL2); 521 TIMER0,
520 declare!(SERIAL3); 522 TIMER1,
521 declare!(GPIOTE0); 523 TIMER2,
522 declare!(SAADC); 524 RTC0,
523 declare!(TIMER0); 525 RTC1,
524 declare!(TIMER1); 526 WDT0,
525 declare!(TIMER2); 527 WDT1,
526 declare!(RTC0); 528 COMP_LPCOMP,
527 declare!(RTC1); 529 EGU0,
528 declare!(WDT0); 530 EGU1,
529 declare!(WDT1); 531 EGU2,
530 declare!(COMP_LPCOMP); 532 EGU3,
531 declare!(EGU0); 533 EGU4,
532 declare!(EGU1); 534 EGU5,
533 declare!(EGU2); 535 PWM0,
534 declare!(EGU3); 536 PWM1,
535 declare!(EGU4); 537 PWM2,
536 declare!(EGU5); 538 PWM3,
537 declare!(PWM0); 539 PDM0,
538 declare!(PWM1); 540 I2S0,
539 declare!(PWM2); 541 IPC,
540 declare!(PWM3); 542 QSPI,
541 declare!(PDM0); 543 NFCT,
542 declare!(I2S0); 544 GPIOTE1,
543 declare!(IPC); 545 QDEC0,
544 declare!(QSPI); 546 QDEC1,
545 declare!(NFCT); 547 USBD,
546 declare!(GPIOTE1); 548 USBREGULATOR,
547 declare!(QDEC0); 549 KMU,
548 declare!(QDEC1); 550 CRYPTOCELL,
549 declare!(USBD); 551);
550 declare!(USBREGULATOR);
551 declare!(KMU);
552 declare!(CRYPTOCELL);
553}
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 1e59528cb..6ac783085 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF5340 has a secure and non-secure (NS) mode. 5 // The nRF5340 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf5340_net_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf5340_net_pac::{ 11 pub use nrf5340_net_pac::{
10 interrupt, 12 interrupt,
@@ -340,29 +342,25 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable);
340impl_ppi_channel!(PPI_CH30, 30 => configurable); 342impl_ppi_channel!(PPI_CH30, 30 => configurable);
341impl_ppi_channel!(PPI_CH31, 31 => configurable); 343impl_ppi_channel!(PPI_CH31, 31 => configurable);
342 344
343pub mod irqs { 345embassy_hal_common::interrupt_mod!(
344 use embassy_cortex_m::interrupt::_export::declare; 346 CLOCK_POWER,
345 347 RADIO,
346 use crate::pac::Interrupt as InterruptEnum; 348 RNG,
347 349 GPIOTE,
348 declare!(CLOCK_POWER); 350 WDT,
349 declare!(RADIO); 351 TIMER0,
350 declare!(RNG); 352 ECB,
351 declare!(GPIOTE); 353 AAR_CCM,
352 declare!(WDT); 354 TEMP,
353 declare!(TIMER0); 355 RTC0,
354 declare!(ECB); 356 IPC,
355 declare!(AAR_CCM); 357 SERIAL0,
356 declare!(TEMP); 358 EGU0,
357 declare!(RTC0); 359 RTC1,
358 declare!(IPC); 360 TIMER1,
359 declare!(SERIAL0); 361 TIMER2,
360 declare!(EGU0); 362 SWI0,
361 declare!(RTC1); 363 SWI1,
362 declare!(TIMER1); 364 SWI2,
363 declare!(TIMER2); 365 SWI3,
364 declare!(SWI0); 366);
365 declare!(SWI1);
366 declare!(SWI2);
367 declare!(SWI3);
368}
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index d2b45114f..67ea032ff 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF9160 has a secure and non-secure (NS) mode. 5 // The nRF9160 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf9160_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf9160_pac::{ 11 pub use nrf9160_pac::{
10 interrupt, 12 interrupt,
@@ -366,40 +368,36 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
366impl_saadc_input!(P0_19, ANALOG_INPUT6); 368impl_saadc_input!(P0_19, ANALOG_INPUT6);
367impl_saadc_input!(P0_20, ANALOG_INPUT7); 369impl_saadc_input!(P0_20, ANALOG_INPUT7);
368 370
369pub mod irqs { 371embassy_hal_common::interrupt_mod!(
370 use embassy_cortex_m::interrupt::_export::declare; 372 SPU,
371 373 CLOCK_POWER,
372 use crate::pac::Interrupt as InterruptEnum; 374 UARTE0_SPIM0_SPIS0_TWIM0_TWIS0,
373 375 UARTE1_SPIM1_SPIS1_TWIM1_TWIS1,
374 declare!(SPU); 376 UARTE2_SPIM2_SPIS2_TWIM2_TWIS2,
375 declare!(CLOCK_POWER); 377 UARTE3_SPIM3_SPIS3_TWIM3_TWIS3,
376 declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); 378 GPIOTE0,
377 declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); 379 SAADC,
378 declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 380 TIMER0,
379 declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 381 TIMER1,
380 declare!(GPIOTE0); 382 TIMER2,
381 declare!(SAADC); 383 RTC0,
382 declare!(TIMER0); 384 RTC1,
383 declare!(TIMER1); 385 WDT,
384 declare!(TIMER2); 386 EGU0,
385 declare!(RTC0); 387 EGU1,
386 declare!(RTC1); 388 EGU2,
387 declare!(WDT); 389 EGU3,
388 declare!(EGU0); 390 EGU4,
389 declare!(EGU1); 391 EGU5,
390 declare!(EGU2); 392 PWM0,
391 declare!(EGU3); 393 PWM1,
392 declare!(EGU4); 394 PWM2,
393 declare!(EGU5); 395 PDM,
394 declare!(PWM0); 396 PWM3,
395 declare!(PWM1); 397 I2S,
396 declare!(PWM2); 398 IPC,
397 declare!(PDM); 399 FPU,
398 declare!(PWM3); 400 GPIOTE1,
399 declare!(I2S); 401 KMU,
400 declare!(IPC); 402 CRYPTOCELL,
401 declare!(FPU); 403);
402 declare!(GPIOTE1);
403 declare!(KMU);
404 declare!(CRYPTOCELL);
405}
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 66c682b43..21d0d9564 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::gpio::sealed::Pin as _; 10use crate::gpio::sealed::Pin as _;
11use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; 11use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
12use crate::interrupt::{Interrupt, InterruptExt}; 12use crate::interrupt::InterruptExt;
13use crate::ppi::{Event, Task}; 13use crate::ppi::{Event, Task};
14use crate::{interrupt, pac, peripherals}; 14use crate::{interrupt, pac, peripherals};
15 15
@@ -74,42 +74,41 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
74 } 74 }
75 75
76 // Enable interrupts 76 // Enable interrupts
77 cfg_if::cfg_if! { 77 #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
78 if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { 78 let irq = interrupt::GPIOTE0;
79 let irq = unsafe { interrupt::GPIOTE0::steal() }; 79 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
80 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { 80 let irq = interrupt::GPIOTE1;
81 let irq = unsafe { interrupt::GPIOTE1::steal() }; 81 #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
82 } else { 82 let irq = interrupt::GPIOTE;
83 let irq = unsafe { interrupt::GPIOTE::steal() };
84 }
85 }
86 83
87 irq.unpend(); 84 irq.unpend();
88 irq.set_priority(irq_prio); 85 irq.set_priority(irq_prio);
89 irq.enable(); 86 unsafe { irq.enable() };
90 87
91 let g = regs(); 88 let g = regs();
92 g.events_port.write(|w| w); 89 g.events_port.write(|w| w);
93 g.intenset.write(|w| w.port().set()); 90 g.intenset.write(|w| w.port().set());
94} 91}
95 92
96cfg_if::cfg_if! { 93#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
97 if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { 94#[cfg(feature = "rt")]
98 #[interrupt] 95#[interrupt]
99 fn GPIOTE0() { 96fn GPIOTE0() {
100 unsafe { handle_gpiote_interrupt() }; 97 unsafe { handle_gpiote_interrupt() };
101 } 98}
102 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { 99
103 #[interrupt] 100#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
104 fn GPIOTE1() { 101#[cfg(feature = "rt")]
105 unsafe { handle_gpiote_interrupt() }; 102#[interrupt]
106 } 103fn GPIOTE1() {
107 } else { 104 unsafe { handle_gpiote_interrupt() };
108 #[interrupt] 105}
109 fn GPIOTE() { 106
110 unsafe { handle_gpiote_interrupt() }; 107#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
111 } 108#[cfg(feature = "rt")]
112 } 109#[interrupt]
110fn GPIOTE() {
111 unsafe { handle_gpiote_interrupt() };
113} 112}
114 113
115unsafe fn handle_gpiote_interrupt() { 114unsafe fn handle_gpiote_interrupt() {
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 8a1188ce4..fea38c4c0 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -9,15 +9,14 @@ use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{compiler_fence, Ordering}; 9use core::sync::atomic::{compiler_fence, Ordering};
10use core::task::Poll; 10use core::task::Poll;
11 11
12use embassy_cortex_m::interrupt::InterruptExt;
13use embassy_hal_common::drop::OnDrop; 12use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef}; 13use embassy_hal_common::{into_ref, PeripheralRef};
15 14
16use crate::gpio::{AnyPin, Pin as GpioPin}; 15use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::{self, Interrupt}; 16use crate::interrupt::typelevel::Interrupt;
18use crate::pac::i2s::RegisterBlock; 17use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts}; 18use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE}; 19use crate::{interrupt, Peripheral, EASY_DMA_SIZE};
21 20
22/// Type alias for `MultiBuffering` with 2 buffers. 21/// Type alias for `MultiBuffering` with 2 buffers.
23pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; 22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
@@ -368,7 +367,7 @@ pub struct InterruptHandler<T: Instance> {
368 _phantom: PhantomData<T>, 367 _phantom: PhantomData<T>,
369} 368}
370 369
371impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 370impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
372 unsafe fn on_interrupt() { 371 unsafe fn on_interrupt() {
373 let device = Device::<T>::new(); 372 let device = Device::<T>::new();
374 let s = T::state(); 373 let s = T::state();
@@ -409,7 +408,7 @@ impl<'d, T: Instance> I2S<'d, T> {
409 /// Create a new I2S in master mode 408 /// Create a new I2S in master mode
410 pub fn new_master( 409 pub fn new_master(
411 i2s: impl Peripheral<P = T> + 'd, 410 i2s: impl Peripheral<P = T> + 'd,
412 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 411 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
413 mck: impl Peripheral<P = impl GpioPin> + 'd, 412 mck: impl Peripheral<P = impl GpioPin> + 'd,
414 sck: impl Peripheral<P = impl GpioPin> + 'd, 413 sck: impl Peripheral<P = impl GpioPin> + 'd,
415 lrck: impl Peripheral<P = impl GpioPin> + 'd, 414 lrck: impl Peripheral<P = impl GpioPin> + 'd,
@@ -432,7 +431,7 @@ impl<'d, T: Instance> I2S<'d, T> {
432 /// Create a new I2S in slave mode 431 /// Create a new I2S in slave mode
433 pub fn new_slave( 432 pub fn new_slave(
434 i2s: impl Peripheral<P = T> + 'd, 433 i2s: impl Peripheral<P = T> + 'd,
435 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 434 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
436 sck: impl Peripheral<P = impl GpioPin> + 'd, 435 sck: impl Peripheral<P = impl GpioPin> + 'd,
437 lrck: impl Peripheral<P = impl GpioPin> + 'd, 436 lrck: impl Peripheral<P = impl GpioPin> + 'd,
438 config: Config, 437 config: Config,
@@ -564,8 +563,8 @@ impl<'d, T: Instance> I2S<'d, T> {
564 } 563 }
565 564
566 fn setup_interrupt(&self) { 565 fn setup_interrupt(&self) {
567 unsafe { T::Interrupt::steal() }.unpend(); 566 T::Interrupt::unpend();
568 unsafe { T::Interrupt::steal() }.enable(); 567 unsafe { T::Interrupt::enable() };
569 568
570 let device = Device::<T>::new(); 569 let device = Device::<T>::new();
571 device.disable_tx_ptr_interrupt(); 570 device.disable_tx_ptr_interrupt();
@@ -1174,7 +1173,7 @@ pub(crate) mod sealed {
1174/// I2S peripheral instance. 1173/// I2S peripheral instance.
1175pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 1174pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1176 /// Interrupt for this peripheral. 1175 /// Interrupt for this peripheral.
1177 type Interrupt: Interrupt; 1176 type Interrupt: interrupt::typelevel::Interrupt;
1178} 1177}
1179 1178
1180macro_rules! impl_i2s { 1179macro_rules! impl_i2s {
@@ -1189,7 +1188,7 @@ macro_rules! impl_i2s {
1189 } 1188 }
1190 } 1189 }
1191 impl crate::i2s::Instance for peripherals::$type { 1190 impl crate::i2s::Instance for peripherals::$type {
1192 type Interrupt = crate::interrupt::$irq; 1191 type Interrupt = crate::interrupt::typelevel::$irq;
1193 } 1192 }
1194 }; 1193 };
1195} 1194}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index d4d7a1cad..691545662 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -93,21 +93,14 @@ pub mod wdt;
93#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] 93#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
94mod chip; 94mod chip;
95 95
96pub mod interrupt { 96/// Macro to bind interrupts to handlers.
97 //! Interrupt definitions and macros to bind them. 97///
98 pub use cortex_m::interrupt::{CriticalSection, Mutex}; 98/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
99 pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; 99/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
100 100/// prove at compile-time that the right interrupts have been bound.
101 pub use crate::chip::irqs::*; 101// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
102 102#[macro_export]
103 /// Macro to bind interrupts to handlers. 103macro_rules! bind_interrupts {
104 ///
105 /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
106 /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
107 /// prove at compile-time that the right interrupts have been bound.
108 // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
109 #[macro_export]
110 macro_rules! bind_interrupts {
111 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 104 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
112 $vis struct $name; 105 $vis struct $name;
113 106
@@ -116,17 +109,16 @@ pub mod interrupt {
116 #[no_mangle] 109 #[no_mangle]
117 unsafe extern "C" fn $irq() { 110 unsafe extern "C" fn $irq() {
118 $( 111 $(
119 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); 112 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
120 )* 113 )*
121 } 114 }
122 115
123 $( 116 $(
124 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} 117 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
125 )* 118 )*
126 )* 119 )*
127 }; 120 };
128 } 121 }
129}
130 122
131// Reexports 123// Reexports
132 124
@@ -135,10 +127,11 @@ pub use chip::pac;
135#[cfg(not(feature = "unstable-pac"))] 127#[cfg(not(feature = "unstable-pac"))]
136pub(crate) use chip::pac; 128pub(crate) use chip::pac;
137pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; 129pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
138pub use embassy_cortex_m::executor;
139pub use embassy_cortex_m::interrupt::_export::interrupt;
140pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 130pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
141 131
132pub use crate::chip::interrupt;
133pub use crate::pac::NVIC_PRIO_BITS;
134
142pub mod config { 135pub mod config {
143 //! Configuration options used when initializing the HAL. 136 //! Configuration options used when initializing the HAL.
144 137
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 8815bb316..0e30f7002 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -6,7 +6,6 @@ use core::marker::PhantomData;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::Interrupt;
10use embassy_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
12use futures::future::poll_fn; 11use futures::future::poll_fn;
@@ -14,15 +13,15 @@ use futures::future::poll_fn;
14use crate::chip::EASY_DMA_SIZE; 13use crate::chip::EASY_DMA_SIZE;
15use crate::gpio::sealed::Pin; 14use crate::gpio::sealed::Pin;
16use crate::gpio::{AnyPin, Pin as GpioPin}; 15use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::{self, InterruptExt}; 16use crate::interrupt::typelevel::Interrupt;
18use crate::Peripheral; 17use crate::{interrupt, Peripheral};
19 18
20/// Interrupt handler. 19/// Interrupt handler.
21pub struct InterruptHandler<T: Instance> { 20pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>, 21 _phantom: PhantomData<T>,
23} 22}
24 23
25impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 24impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() { 25 unsafe fn on_interrupt() {
27 T::regs().intenclr.write(|w| w.end().clear()); 26 T::regs().intenclr.write(|w| w.end().clear());
28 T::state().waker.wake(); 27 T::state().waker.wake();
@@ -53,7 +52,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
53 /// Create PDM driver 52 /// Create PDM driver
54 pub fn new( 53 pub fn new(
55 pdm: impl Peripheral<P = T> + 'd, 54 pdm: impl Peripheral<P = T> + 'd,
56 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 55 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
57 clk: impl Peripheral<P = impl GpioPin> + 'd, 56 clk: impl Peripheral<P = impl GpioPin> + 'd,
58 din: impl Peripheral<P = impl GpioPin> + 'd, 57 din: impl Peripheral<P = impl GpioPin> + 'd,
59 config: Config, 58 config: Config,
@@ -94,8 +93,8 @@ impl<'d, T: Instance> Pdm<'d, T> {
94 r.gainr.write(|w| w.gainr().default_gain()); 93 r.gainr.write(|w| w.gainr().default_gain());
95 94
96 // IRQ 95 // IRQ
97 unsafe { T::Interrupt::steal() }.unpend(); 96 T::Interrupt::unpend();
98 unsafe { T::Interrupt::steal() }.enable(); 97 unsafe { T::Interrupt::enable() };
99 98
100 r.enable.write(|w| w.enable().set_bit()); 99 r.enable.write(|w| w.enable().set_bit());
101 100
@@ -274,7 +273,7 @@ pub(crate) mod sealed {
274/// PDM peripheral instance. 273/// PDM peripheral instance.
275pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 274pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
276 /// Interrupt for this peripheral. 275 /// Interrupt for this peripheral.
277 type Interrupt: Interrupt; 276 type Interrupt: interrupt::typelevel::Interrupt;
278} 277}
279 278
280macro_rules! impl_pdm { 279macro_rules! impl_pdm {
@@ -289,7 +288,7 @@ macro_rules! impl_pdm {
289 } 288 }
290 } 289 }
291 impl crate::pdm::Instance for peripherals::$type { 290 impl crate::pdm::Instance for peripherals::$type {
292 type Interrupt = crate::interrupt::$irq; 291 type Interrupt = crate::interrupt::typelevel::$irq;
293 } 292 }
294 }; 293 };
295} 294}
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 708f23104..363a255d5 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -8,10 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef};
8 8
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::sealed::Pin as _;
10use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; 10use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
11use crate::interrupt::Interrupt;
12use crate::ppi::{Event, Task}; 11use crate::ppi::{Event, Task};
13use crate::util::slice_in_ram_or; 12use crate::util::slice_in_ram_or;
14use crate::{pac, Peripheral}; 13use crate::{interrupt, pac, Peripheral};
15 14
16/// SimplePwm is the traditional pwm interface you're probably used to, allowing 15/// SimplePwm is the traditional pwm interface you're probably used to, allowing
17/// to simply set a duty cycle across up to four channels. 16/// to simply set a duty cycle across up to four channels.
@@ -843,7 +842,7 @@ pub(crate) mod sealed {
843/// PWM peripheral instance. 842/// PWM peripheral instance.
844pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 843pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
845 /// Interrupt for this peripheral. 844 /// Interrupt for this peripheral.
846 type Interrupt: Interrupt; 845 type Interrupt: interrupt::typelevel::Interrupt;
847} 846}
848 847
849macro_rules! impl_pwm { 848macro_rules! impl_pwm {
@@ -854,7 +853,7 @@ macro_rules! impl_pwm {
854 } 853 }
855 } 854 }
856 impl crate::pwm::Instance for peripherals::$type { 855 impl crate::pwm::Instance for peripherals::$type {
857 type Interrupt = crate::interrupt::$irq; 856 type Interrupt = crate::interrupt::typelevel::$irq;
858 } 857 }
859 }; 858 };
860} 859}
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index c845492fc..8bac87d37 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -6,12 +6,11 @@ use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::Interrupt;
10use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
11 10
12use crate::gpio::sealed::Pin as _; 11use crate::gpio::sealed::Pin as _;
13use crate::gpio::{AnyPin, Pin as GpioPin}; 12use crate::gpio::{AnyPin, Pin as GpioPin};
14use crate::interrupt::InterruptExt; 13use crate::interrupt::typelevel::Interrupt;
15use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peripheral};
16 15
17/// Quadrature decoder driver. 16/// Quadrature decoder driver.
@@ -51,7 +50,7 @@ pub struct InterruptHandler<T: Instance> {
51 _phantom: PhantomData<T>, 50 _phantom: PhantomData<T>,
52} 51}
53 52
54impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 53impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
55 unsafe fn on_interrupt() { 54 unsafe fn on_interrupt() {
56 T::regs().intenclr.write(|w| w.reportrdy().clear()); 55 T::regs().intenclr.write(|w| w.reportrdy().clear());
57 T::state().waker.wake(); 56 T::state().waker.wake();
@@ -62,7 +61,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
62 /// Create a new QDEC. 61 /// Create a new QDEC.
63 pub fn new( 62 pub fn new(
64 qdec: impl Peripheral<P = T> + 'd, 63 qdec: impl Peripheral<P = T> + 'd,
65 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 64 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
66 a: impl Peripheral<P = impl GpioPin> + 'd, 65 a: impl Peripheral<P = impl GpioPin> + 'd,
67 b: impl Peripheral<P = impl GpioPin> + 'd, 66 b: impl Peripheral<P = impl GpioPin> + 'd,
68 config: Config, 67 config: Config,
@@ -74,7 +73,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
74 /// Create a new QDEC, with a pin for LED output. 73 /// Create a new QDEC, with a pin for LED output.
75 pub fn new_with_led( 74 pub fn new_with_led(
76 qdec: impl Peripheral<P = T> + 'd, 75 qdec: impl Peripheral<P = T> + 'd,
77 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 76 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
78 a: impl Peripheral<P = impl GpioPin> + 'd, 77 a: impl Peripheral<P = impl GpioPin> + 'd,
79 b: impl Peripheral<P = impl GpioPin> + 'd, 78 b: impl Peripheral<P = impl GpioPin> + 'd,
80 led: impl Peripheral<P = impl GpioPin> + 'd, 79 led: impl Peripheral<P = impl GpioPin> + 'd,
@@ -134,8 +133,8 @@ impl<'d, T: Instance> Qdec<'d, T> {
134 SamplePeriod::_131ms => w.sampleper()._131ms(), 133 SamplePeriod::_131ms => w.sampleper()._131ms(),
135 }); 134 });
136 135
137 unsafe { T::Interrupt::steal() }.unpend(); 136 T::Interrupt::unpend();
138 unsafe { T::Interrupt::steal() }.enable(); 137 unsafe { T::Interrupt::enable() };
139 138
140 // Enable peripheral 139 // Enable peripheral
141 r.enable.write(|w| w.enable().set_bit()); 140 r.enable.write(|w| w.enable().set_bit());
@@ -272,7 +271,7 @@ pub(crate) mod sealed {
272/// qdec peripheral instance. 271/// qdec peripheral instance.
273pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 272pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
274 /// Interrupt for this peripheral. 273 /// Interrupt for this peripheral.
275 type Interrupt: Interrupt; 274 type Interrupt: interrupt::typelevel::Interrupt;
276} 275}
277 276
278macro_rules! impl_qdec { 277macro_rules! impl_qdec {
@@ -287,7 +286,7 @@ macro_rules! impl_qdec {
287 } 286 }
288 } 287 }
289 impl crate::qdec::Instance for peripherals::$type { 288 impl crate::qdec::Instance for peripherals::$type {
290 type Interrupt = crate::interrupt::$irq; 289 type Interrupt = crate::interrupt::typelevel::$irq;
291 } 290 }
292 }; 291 };
293} 292}
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 2e16c2ff5..baefc7967 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -12,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef};
12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
13 13
14use crate::gpio::{self, Pin as GpioPin}; 14use crate::gpio::{self, Pin as GpioPin};
15use crate::interrupt::{self, Interrupt, InterruptExt}; 15use crate::interrupt::typelevel::Interrupt;
16pub use crate::pac::qspi::ifconfig0::{ 16pub use crate::pac::qspi::ifconfig0::{
17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, 17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
18}; 18};
19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; 19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
20use crate::Peripheral; 20use crate::{interrupt, Peripheral};
21 21
22/// Deep power-down config. 22/// Deep power-down config.
23pub struct DeepPowerDownConfig { 23pub struct DeepPowerDownConfig {
@@ -120,7 +120,7 @@ pub struct InterruptHandler<T: Instance> {
120 _phantom: PhantomData<T>, 120 _phantom: PhantomData<T>,
121} 121}
122 122
123impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 123impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
124 unsafe fn on_interrupt() { 124 unsafe fn on_interrupt() {
125 let r = T::regs(); 125 let r = T::regs();
126 let s = T::state(); 126 let s = T::state();
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
143 /// Create a new QSPI driver. 143 /// Create a new QSPI driver.
144 pub fn new( 144 pub fn new(
145 qspi: impl Peripheral<P = T> + 'd, 145 qspi: impl Peripheral<P = T> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 146 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 sck: impl Peripheral<P = impl GpioPin> + 'd, 147 sck: impl Peripheral<P = impl GpioPin> + 'd,
148 csn: impl Peripheral<P = impl GpioPin> + 'd, 148 csn: impl Peripheral<P = impl GpioPin> + 'd,
149 io0: impl Peripheral<P = impl GpioPin> + 'd, 149 io0: impl Peripheral<P = impl GpioPin> + 'd,
@@ -207,8 +207,8 @@ impl<'d, T: Instance> Qspi<'d, T> {
207 w 207 w
208 }); 208 });
209 209
210 unsafe { T::Interrupt::steal() }.unpend(); 210 T::Interrupt::unpend();
211 unsafe { T::Interrupt::steal() }.enable(); 211 unsafe { T::Interrupt::enable() };
212 212
213 // Enable it 213 // Enable it
214 r.enable.write(|w| w.enable().enabled()); 214 r.enable.write(|w| w.enable().enabled());
@@ -644,7 +644,7 @@ pub(crate) mod sealed {
644/// QSPI peripheral instance. 644/// QSPI peripheral instance.
645pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 645pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
646 /// Interrupt for this peripheral. 646 /// Interrupt for this peripheral.
647 type Interrupt: Interrupt; 647 type Interrupt: interrupt::typelevel::Interrupt;
648} 648}
649 649
650macro_rules! impl_qspi { 650macro_rules! impl_qspi {
@@ -659,7 +659,7 @@ macro_rules! impl_qspi {
659 } 659 }
660 } 660 }
661 impl crate::qspi::Instance for peripherals::$type { 661 impl crate::qspi::Instance for peripherals::$type {
662 type Interrupt = crate::interrupt::$irq; 662 type Interrupt = crate::interrupt::typelevel::$irq;
663 } 663 }
664 }; 664 };
665} 665}
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index a5602248d..923b8b467 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -8,12 +8,11 @@ use core::ptr;
8use core::sync::atomic::{AtomicPtr, Ordering}; 8use core::sync::atomic::{AtomicPtr, Ordering};
9use core::task::Poll; 9use core::task::Poll;
10 10
11use embassy_cortex_m::interrupt::Interrupt;
12use embassy_hal_common::drop::OnDrop; 11use embassy_hal_common::drop::OnDrop;
13use embassy_hal_common::{into_ref, PeripheralRef}; 12use embassy_hal_common::{into_ref, PeripheralRef};
14use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
15 14
16use crate::interrupt::InterruptExt; 15use crate::interrupt::typelevel::Interrupt;
17use crate::{interrupt, Peripheral}; 16use crate::{interrupt, Peripheral};
18 17
19/// Interrupt handler. 18/// Interrupt handler.
@@ -21,7 +20,7 @@ pub struct InterruptHandler<T: Instance> {
21 _phantom: PhantomData<T>, 20 _phantom: PhantomData<T>,
22} 21}
23 22
24impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 23impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
25 unsafe fn on_interrupt() { 24 unsafe fn on_interrupt() {
26 let s = T::state(); 25 let s = T::state();
27 let r = T::regs(); 26 let r = T::regs();
@@ -90,7 +89,7 @@ impl<'d, T: Instance> Rng<'d, T> {
90 /// The synchronous API is safe. 89 /// The synchronous API is safe.
91 pub fn new( 90 pub fn new(
92 rng: impl Peripheral<P = T> + 'd, 91 rng: impl Peripheral<P = T> + 'd,
93 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 92 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
94 ) -> Self { 93 ) -> Self {
95 into_ref!(rng); 94 into_ref!(rng);
96 95
@@ -99,8 +98,8 @@ impl<'d, T: Instance> Rng<'d, T> {
99 this.stop(); 98 this.stop();
100 this.disable_irq(); 99 this.disable_irq();
101 100
102 unsafe { T::Interrupt::steal() }.unpend(); 101 T::Interrupt::unpend();
103 unsafe { T::Interrupt::steal() }.enable(); 102 unsafe { T::Interrupt::enable() };
104 103
105 this 104 this
106 } 105 }
@@ -256,7 +255,7 @@ pub(crate) mod sealed {
256/// RNG peripheral instance. 255/// RNG peripheral instance.
257pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 256pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
258 /// Interrupt for this peripheral. 257 /// Interrupt for this peripheral.
259 type Interrupt: Interrupt; 258 type Interrupt: interrupt::typelevel::Interrupt;
260} 259}
261 260
262macro_rules! impl_rng { 261macro_rules! impl_rng {
@@ -271,7 +270,7 @@ macro_rules! impl_rng {
271 } 270 }
272 } 271 }
273 impl crate::rng::Instance for peripherals::$type { 272 impl crate::rng::Instance for peripherals::$type {
274 type Interrupt = crate::interrupt::$irq; 273 type Interrupt = crate::interrupt::typelevel::$irq;
275 } 274 }
276 }; 275 };
277} 276}
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 8aff7df16..cf3fb9993 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -6,7 +6,6 @@ use core::future::poll_fn;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
10use embassy_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 10use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
@@ -18,6 +17,7 @@ use saadc::oversample::OVERSAMPLE_A;
18use saadc::resolution::VAL_A; 17use saadc::resolution::VAL_A;
19 18
20use self::sealed::Input as _; 19use self::sealed::Input as _;
20use crate::interrupt::InterruptExt;
21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; 21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
22use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 22use crate::timer::{Frequency, Instance as TimerInstance, Timer};
23use crate::{interrupt, pac, peripherals, Peripheral}; 23use crate::{interrupt, pac, peripherals, Peripheral};
@@ -33,7 +33,7 @@ pub struct InterruptHandler {
33 _private: (), 33 _private: (),
34} 34}
35 35
36impl interrupt::Handler<interrupt::SAADC> for InterruptHandler { 36impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler {
37 unsafe fn on_interrupt() { 37 unsafe fn on_interrupt() {
38 let r = unsafe { &*SAADC::ptr() }; 38 let r = unsafe { &*SAADC::ptr() };
39 39
@@ -144,7 +144,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
144 /// Create a new SAADC driver. 144 /// Create a new SAADC driver.
145 pub fn new( 145 pub fn new(
146 saadc: impl Peripheral<P = peripherals::SAADC> + 'd, 146 saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
147 _irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd, 147 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd,
148 config: Config, 148 config: Config,
149 channel_configs: [ChannelConfig; N], 149 channel_configs: [ChannelConfig; N],
150 ) -> Self { 150 ) -> Self {
@@ -189,8 +189,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
189 // Disable all events interrupts 189 // Disable all events interrupts
190 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); 190 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
191 191
192 unsafe { interrupt::SAADC::steal() }.unpend(); 192 interrupt::SAADC.unpend();
193 unsafe { interrupt::SAADC::steal() }.enable(); 193 unsafe { interrupt::SAADC.enable() };
194 194
195 Self { _p: saadc } 195 Self { _p: saadc }
196 } 196 }
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 89cbdfee9..66bbd1a8f 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -15,9 +15,9 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
15use crate::chip::FORCE_COPY_BUFFER_SIZE; 15use crate::chip::FORCE_COPY_BUFFER_SIZE;
16use crate::gpio::sealed::Pin as _; 16use crate::gpio::sealed::Pin as _;
17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
18use crate::interrupt::{self, Interrupt, InterruptExt}; 18use crate::interrupt::typelevel::Interrupt;
19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
20use crate::{pac, Peripheral}; 20use crate::{interrupt, pac, Peripheral};
21 21
22/// SPIM error 22/// SPIM error
23#[derive(Debug, Clone, Copy, PartialEq, Eq)] 23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -63,7 +63,7 @@ pub struct InterruptHandler<T: Instance> {
63 _phantom: PhantomData<T>, 63 _phantom: PhantomData<T>,
64} 64}
65 65
66impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 66impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
67 unsafe fn on_interrupt() { 67 unsafe fn on_interrupt() {
68 let r = T::regs(); 68 let r = T::regs();
69 let s = T::state(); 69 let s = T::state();
@@ -84,7 +84,7 @@ impl<'d, T: Instance> Spim<'d, T> {
84 /// Create a new SPIM driver. 84 /// Create a new SPIM driver.
85 pub fn new( 85 pub fn new(
86 spim: impl Peripheral<P = T> + 'd, 86 spim: impl Peripheral<P = T> + 'd,
87 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 87 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
88 sck: impl Peripheral<P = impl GpioPin> + 'd, 88 sck: impl Peripheral<P = impl GpioPin> + 'd,
89 miso: impl Peripheral<P = impl GpioPin> + 'd, 89 miso: impl Peripheral<P = impl GpioPin> + 'd,
90 mosi: impl Peripheral<P = impl GpioPin> + 'd, 90 mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -103,7 +103,7 @@ impl<'d, T: Instance> Spim<'d, T> {
103 /// Create a new SPIM driver, capable of TX only (MOSI only). 103 /// Create a new SPIM driver, capable of TX only (MOSI only).
104 pub fn new_txonly( 104 pub fn new_txonly(
105 spim: impl Peripheral<P = T> + 'd, 105 spim: impl Peripheral<P = T> + 'd,
106 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 106 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
107 sck: impl Peripheral<P = impl GpioPin> + 'd, 107 sck: impl Peripheral<P = impl GpioPin> + 'd,
108 mosi: impl Peripheral<P = impl GpioPin> + 'd, 108 mosi: impl Peripheral<P = impl GpioPin> + 'd,
109 config: Config, 109 config: Config,
@@ -115,7 +115,7 @@ impl<'d, T: Instance> Spim<'d, T> {
115 /// Create a new SPIM driver, capable of RX only (MISO only). 115 /// Create a new SPIM driver, capable of RX only (MISO only).
116 pub fn new_rxonly( 116 pub fn new_rxonly(
117 spim: impl Peripheral<P = T> + 'd, 117 spim: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 118 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 sck: impl Peripheral<P = impl GpioPin> + 'd, 119 sck: impl Peripheral<P = impl GpioPin> + 'd,
120 miso: impl Peripheral<P = impl GpioPin> + 'd, 120 miso: impl Peripheral<P = impl GpioPin> + 'd,
121 config: Config, 121 config: Config,
@@ -207,8 +207,8 @@ impl<'d, T: Instance> Spim<'d, T> {
207 // Disable all events interrupts 207 // Disable all events interrupts
208 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 208 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
209 209
210 unsafe { T::Interrupt::steal() }.unpend(); 210 T::Interrupt::unpend();
211 unsafe { T::Interrupt::steal() }.enable(); 211 unsafe { T::Interrupt::enable() };
212 212
213 Self { _p: spim } 213 Self { _p: spim }
214 } 214 }
@@ -408,7 +408,7 @@ pub(crate) mod sealed {
408/// SPIM peripheral instance 408/// SPIM peripheral instance
409pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 409pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
410 /// Interrupt for this peripheral. 410 /// Interrupt for this peripheral.
411 type Interrupt: Interrupt; 411 type Interrupt: interrupt::typelevel::Interrupt;
412} 412}
413 413
414macro_rules! impl_spim { 414macro_rules! impl_spim {
@@ -423,7 +423,7 @@ macro_rules! impl_spim {
423 } 423 }
424 } 424 }
425 impl crate::spim::Instance for peripherals::$type { 425 impl crate::spim::Instance for peripherals::$type {
426 type Interrupt = crate::interrupt::$irq; 426 type Interrupt = crate::interrupt::typelevel::$irq;
427 } 427 }
428 }; 428 };
429} 429}
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 55b5e060e..aa438415a 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -13,9 +13,9 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
13use crate::chip::FORCE_COPY_BUFFER_SIZE; 13use crate::chip::FORCE_COPY_BUFFER_SIZE;
14use crate::gpio::sealed::Pin as _; 14use crate::gpio::sealed::Pin as _;
15use crate::gpio::{self, AnyPin, Pin as GpioPin}; 15use crate::gpio::{self, AnyPin, Pin as GpioPin};
16use crate::interrupt::{self, Interrupt, InterruptExt}; 16use crate::interrupt::typelevel::Interrupt;
17use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 17use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
18use crate::{pac, Peripheral}; 18use crate::{interrupt, pac, Peripheral};
19 19
20/// SPIS error 20/// SPIS error
21#[derive(Debug, Clone, Copy, PartialEq, Eq)] 21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>, 68 _phantom: PhantomData<T>,
69} 69}
70 70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 71impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() { 72 unsafe fn on_interrupt() {
73 let r = T::regs(); 73 let r = T::regs();
74 let s = T::state(); 74 let s = T::state();
@@ -94,7 +94,7 @@ impl<'d, T: Instance> Spis<'d, T> {
94 /// Create a new SPIS driver. 94 /// Create a new SPIS driver.
95 pub fn new( 95 pub fn new(
96 spis: impl Peripheral<P = T> + 'd, 96 spis: impl Peripheral<P = T> + 'd,
97 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 97 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
98 cs: impl Peripheral<P = impl GpioPin> + 'd, 98 cs: impl Peripheral<P = impl GpioPin> + 'd,
99 sck: impl Peripheral<P = impl GpioPin> + 'd, 99 sck: impl Peripheral<P = impl GpioPin> + 'd,
100 miso: impl Peripheral<P = impl GpioPin> + 'd, 100 miso: impl Peripheral<P = impl GpioPin> + 'd,
@@ -115,7 +115,7 @@ impl<'d, T: Instance> Spis<'d, T> {
115 /// Create a new SPIS driver, capable of TX only (MISO only). 115 /// Create a new SPIS driver, capable of TX only (MISO only).
116 pub fn new_txonly( 116 pub fn new_txonly(
117 spis: impl Peripheral<P = T> + 'd, 117 spis: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 118 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 cs: impl Peripheral<P = impl GpioPin> + 'd, 119 cs: impl Peripheral<P = impl GpioPin> + 'd,
120 sck: impl Peripheral<P = impl GpioPin> + 'd, 120 sck: impl Peripheral<P = impl GpioPin> + 'd,
121 miso: impl Peripheral<P = impl GpioPin> + 'd, 121 miso: impl Peripheral<P = impl GpioPin> + 'd,
@@ -128,7 +128,7 @@ impl<'d, T: Instance> Spis<'d, T> {
128 /// Create a new SPIS driver, capable of RX only (MOSI only). 128 /// Create a new SPIS driver, capable of RX only (MOSI only).
129 pub fn new_rxonly( 129 pub fn new_rxonly(
130 spis: impl Peripheral<P = T> + 'd, 130 spis: impl Peripheral<P = T> + 'd,
131 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 131 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
132 cs: impl Peripheral<P = impl GpioPin> + 'd, 132 cs: impl Peripheral<P = impl GpioPin> + 'd,
133 sck: impl Peripheral<P = impl GpioPin> + 'd, 133 sck: impl Peripheral<P = impl GpioPin> + 'd,
134 mosi: impl Peripheral<P = impl GpioPin> + 'd, 134 mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -214,8 +214,8 @@ impl<'d, T: Instance> Spis<'d, T> {
214 // Disable all events interrupts. 214 // Disable all events interrupts.
215 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 215 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
216 216
217 unsafe { T::Interrupt::steal() }.unpend(); 217 T::Interrupt::unpend();
218 unsafe { T::Interrupt::steal() }.enable(); 218 unsafe { T::Interrupt::enable() };
219 219
220 Self { _p: spis } 220 Self { _p: spis }
221 } 221 }
@@ -480,7 +480,7 @@ pub(crate) mod sealed {
480/// SPIS peripheral instance 480/// SPIS peripheral instance
481pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 481pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
482 /// Interrupt for this peripheral. 482 /// Interrupt for this peripheral.
483 type Interrupt: Interrupt; 483 type Interrupt: interrupt::typelevel::Interrupt;
484} 484}
485 485
486macro_rules! impl_spis { 486macro_rules! impl_spis {
@@ -495,7 +495,7 @@ macro_rules! impl_spis {
495 } 495 }
496 } 496 }
497 impl crate::spis::Instance for peripherals::$type { 497 impl crate::spis::Instance for peripherals::$type {
498 type Interrupt = crate::interrupt::$irq; 498 type Interrupt = crate::interrupt::typelevel::$irq;
499 } 499 }
500 }; 500 };
501} 501}
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 0653710af..491e92c04 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -3,7 +3,6 @@
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::Interrupt;
7use embassy_hal_common::drop::OnDrop; 6use embassy_hal_common::drop::OnDrop;
8use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
@@ -18,7 +17,7 @@ pub struct InterruptHandler {
18 _private: (), 17 _private: (),
19} 18}
20 19
21impl interrupt::Handler<interrupt::TEMP> for InterruptHandler { 20impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler {
22 unsafe fn on_interrupt() { 21 unsafe fn on_interrupt() {
23 let r = unsafe { &*pac::TEMP::PTR }; 22 let r = unsafe { &*pac::TEMP::PTR };
24 r.intenclr.write(|w| w.datardy().clear()); 23 r.intenclr.write(|w| w.datardy().clear());
@@ -37,13 +36,13 @@ impl<'d> Temp<'d> {
37 /// Create a new temperature sensor driver. 36 /// Create a new temperature sensor driver.
38 pub fn new( 37 pub fn new(
39 _peri: impl Peripheral<P = TEMP> + 'd, 38 _peri: impl Peripheral<P = TEMP> + 'd,
40 _irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd, 39 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd,
41 ) -> Self { 40 ) -> Self {
42 into_ref!(_peri); 41 into_ref!(_peri);
43 42
44 // Enable interrupt that signals temperature values 43 // Enable interrupt that signals temperature values
45 unsafe { interrupt::TEMP::steal() }.unpend(); 44 interrupt::TEMP.unpend();
46 unsafe { interrupt::TEMP::steal() }.enable(); 45 unsafe { interrupt::TEMP.enable() };
47 46
48 Self { _peri } 47 Self { _peri }
49 } 48 }
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index c82c238cc..f1ab4f8fd 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -7,7 +7,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
8use embassy_time::driver::{AlarmHandle, Driver}; 8use embassy_time::driver::{AlarmHandle, Driver};
9 9
10use crate::interrupt::{Interrupt, InterruptExt}; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
12 12
13fn rtc() -> &'static pac::rtc0::RegisterBlock { 13fn rtc() -> &'static pac::rtc0::RegisterBlock {
@@ -142,9 +142,8 @@ impl RtcDriver {
142 // Wait for clear 142 // Wait for clear
143 while r.counter.read().bits() != 0 {} 143 while r.counter.read().bits() != 0 {}
144 144
145 let irq = unsafe { interrupt::RTC1::steal() }; 145 interrupt::RTC1.set_priority(irq_prio);
146 irq.set_priority(irq_prio); 146 unsafe { interrupt::RTC1.enable() };
147 irq.enable();
148 } 147 }
149 148
150 fn on_interrupt(&self) { 149 fn on_interrupt(&self) {
@@ -296,6 +295,7 @@ impl Driver for RtcDriver {
296 } 295 }
297} 296}
298 297
298#[cfg(feature = "rt")]
299#[interrupt] 299#[interrupt]
300fn RTC1() { 300fn RTC1() {
301 DRIVER.on_interrupt() 301 DRIVER.on_interrupt()
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 2a0e16a50..dc3757856 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -8,7 +8,6 @@
8 8
9use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
10 10
11use crate::interrupt::Interrupt;
12use crate::ppi::{Event, Task}; 11use crate::ppi::{Event, Task};
13use crate::{pac, Peripheral}; 12use crate::{pac, Peripheral};
14 13
@@ -29,7 +28,7 @@ pub(crate) mod sealed {
29/// Basic Timer instance. 28/// Basic Timer instance.
30pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 29pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
31 /// Interrupt for this peripheral. 30 /// Interrupt for this peripheral.
32 type Interrupt: Interrupt; 31 type Interrupt: crate::interrupt::typelevel::Interrupt;
33} 32}
34 33
35/// Extended timer instance. 34/// Extended timer instance.
@@ -44,7 +43,7 @@ macro_rules! impl_timer {
44 } 43 }
45 } 44 }
46 impl crate::timer::Instance for peripherals::$type { 45 impl crate::timer::Instance for peripherals::$type {
47 type Interrupt = crate::interrupt::$irq; 46 type Interrupt = crate::interrupt::typelevel::$irq;
48 } 47 }
49 }; 48 };
50 ($type:ident, $pac_type:ident, $irq:ident) => { 49 ($type:ident, $pac_type:ident, $irq:ident) => {
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index cab36884f..2ad0d19b1 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -16,9 +16,9 @@ use embassy_time::{Duration, Instant};
16 16
17use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 17use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
18use crate::gpio::Pin as GpioPin; 18use crate::gpio::Pin as GpioPin;
19use crate::interrupt::{self, Interrupt, InterruptExt}; 19use crate::interrupt::typelevel::Interrupt;
20use crate::util::{slice_in_ram, slice_in_ram_or}; 20use crate::util::{slice_in_ram, slice_in_ram_or};
21use crate::{gpio, pac, Peripheral}; 21use crate::{gpio, interrupt, pac, Peripheral};
22 22
23/// TWI frequency 23/// TWI frequency
24#[derive(Clone, Copy)] 24#[derive(Clone, Copy)]
@@ -98,7 +98,7 @@ pub struct InterruptHandler<T: Instance> {
98 _phantom: PhantomData<T>, 98 _phantom: PhantomData<T>,
99} 99}
100 100
101impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 101impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
102 unsafe fn on_interrupt() { 102 unsafe fn on_interrupt() {
103 let r = T::regs(); 103 let r = T::regs();
104 let s = T::state(); 104 let s = T::state();
@@ -123,7 +123,7 @@ impl<'d, T: Instance> Twim<'d, T> {
123 /// Create a new TWI driver. 123 /// Create a new TWI driver.
124 pub fn new( 124 pub fn new(
125 twim: impl Peripheral<P = T> + 'd, 125 twim: impl Peripheral<P = T> + 'd,
126 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 126 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
127 sda: impl Peripheral<P = impl GpioPin> + 'd, 127 sda: impl Peripheral<P = impl GpioPin> + 'd,
128 scl: impl Peripheral<P = impl GpioPin> + 'd, 128 scl: impl Peripheral<P = impl GpioPin> + 'd,
129 config: Config, 129 config: Config,
@@ -174,8 +174,8 @@ impl<'d, T: Instance> Twim<'d, T> {
174 // Disable all events interrupts 174 // Disable all events interrupts
175 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 175 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
176 176
177 unsafe { T::Interrupt::steal() }.unpend(); 177 T::Interrupt::unpend();
178 unsafe { T::Interrupt::steal() }.enable(); 178 unsafe { T::Interrupt::enable() };
179 179
180 Self { _p: twim } 180 Self { _p: twim }
181 } 181 }
@@ -750,7 +750,7 @@ pub(crate) mod sealed {
750/// TWIM peripheral instance. 750/// TWIM peripheral instance.
751pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 751pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
752 /// Interrupt for this peripheral. 752 /// Interrupt for this peripheral.
753 type Interrupt: Interrupt; 753 type Interrupt: interrupt::typelevel::Interrupt;
754} 754}
755 755
756macro_rules! impl_twim { 756macro_rules! impl_twim {
@@ -765,7 +765,7 @@ macro_rules! impl_twim {
765 } 765 }
766 } 766 }
767 impl crate::twim::Instance for peripherals::$type { 767 impl crate::twim::Instance for peripherals::$type {
768 type Interrupt = crate::interrupt::$irq; 768 type Interrupt = crate::interrupt::typelevel::$irq;
769 } 769 }
770 }; 770 };
771} 771}
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index f68a9940a..a115d5616 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -15,9 +15,9 @@ use embassy_time::{Duration, Instant};
15 15
16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
17use crate::gpio::Pin as GpioPin; 17use crate::gpio::Pin as GpioPin;
18use crate::interrupt::{self, Interrupt, InterruptExt}; 18use crate::interrupt::typelevel::Interrupt;
19use crate::util::slice_in_ram_or; 19use crate::util::slice_in_ram_or;
20use crate::{gpio, pac, Peripheral}; 20use crate::{gpio, interrupt, pac, Peripheral};
21 21
22/// TWIS config. 22/// TWIS config.
23#[non_exhaustive] 23#[non_exhaustive]
@@ -114,7 +114,7 @@ pub struct InterruptHandler<T: Instance> {
114 _phantom: PhantomData<T>, 114 _phantom: PhantomData<T>,
115} 115}
116 116
117impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 117impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
118 unsafe fn on_interrupt() { 118 unsafe fn on_interrupt() {
119 let r = T::regs(); 119 let r = T::regs();
120 let s = T::state(); 120 let s = T::state();
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Twis<'d, T> {
143 /// Create a new TWIS driver. 143 /// Create a new TWIS driver.
144 pub fn new( 144 pub fn new(
145 twis: impl Peripheral<P = T> + 'd, 145 twis: impl Peripheral<P = T> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 146 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 sda: impl Peripheral<P = impl GpioPin> + 'd, 147 sda: impl Peripheral<P = impl GpioPin> + 'd,
148 scl: impl Peripheral<P = impl GpioPin> + 'd, 148 scl: impl Peripheral<P = impl GpioPin> + 'd,
149 config: Config, 149 config: Config,
@@ -204,8 +204,8 @@ impl<'d, T: Instance> Twis<'d, T> {
204 // Generate suspend on read event 204 // Generate suspend on read event
205 r.shorts.write(|w| w.read_suspend().enabled()); 205 r.shorts.write(|w| w.read_suspend().enabled());
206 206
207 unsafe { T::Interrupt::steal() }.unpend(); 207 T::Interrupt::unpend();
208 unsafe { T::Interrupt::steal() }.enable(); 208 unsafe { T::Interrupt::enable() };
209 209
210 Self { _p: twis } 210 Self { _p: twis }
211 } 211 }
@@ -778,7 +778,7 @@ pub(crate) mod sealed {
778/// TWIS peripheral instance. 778/// TWIS peripheral instance.
779pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 779pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
780 /// Interrupt for this peripheral. 780 /// Interrupt for this peripheral.
781 type Interrupt: Interrupt; 781 type Interrupt: interrupt::typelevel::Interrupt;
782} 782}
783 783
784macro_rules! impl_twis { 784macro_rules! impl_twis {
@@ -793,7 +793,7 @@ macro_rules! impl_twis {
793 } 793 }
794 } 794 }
795 impl crate::twis::Instance for peripherals::$type { 795 impl crate::twis::Instance for peripherals::$type {
796 type Interrupt = crate::interrupt::$irq; 796 type Interrupt = crate::interrupt::typelevel::$irq;
797 } 797 }
798 }; 798 };
799} 799}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 032089635..48d57fea4 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -27,11 +27,11 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
28use crate::gpio::sealed::Pin as _; 28use crate::gpio::sealed::Pin as _;
29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
30use crate::interrupt::{self, Interrupt, InterruptExt}; 30use crate::interrupt::typelevel::Interrupt;
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
33use crate::util::slice_in_ram_or; 33use crate::util::slice_in_ram_or;
34use crate::{pac, Peripheral}; 34use crate::{interrupt, pac, Peripheral};
35 35
36/// UARTE config. 36/// UARTE config.
37#[derive(Clone)] 37#[derive(Clone)]
@@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>, 68 _phantom: PhantomData<T>,
69} 69}
70 70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 71impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() { 72 unsafe fn on_interrupt() {
73 let r = T::regs(); 73 let r = T::regs();
74 let s = T::state(); 74 let s = T::state();
@@ -108,7 +108,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
108 /// Create a new UARTE without hardware flow control 108 /// Create a new UARTE without hardware flow control
109 pub fn new( 109 pub fn new(
110 uarte: impl Peripheral<P = T> + 'd, 110 uarte: impl Peripheral<P = T> + 'd,
111 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 111 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
112 rxd: impl Peripheral<P = impl GpioPin> + 'd, 112 rxd: impl Peripheral<P = impl GpioPin> + 'd,
113 txd: impl Peripheral<P = impl GpioPin> + 'd, 113 txd: impl Peripheral<P = impl GpioPin> + 'd,
114 config: Config, 114 config: Config,
@@ -120,7 +120,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
120 /// Create a new UARTE with hardware flow control (RTS/CTS) 120 /// Create a new UARTE with hardware flow control (RTS/CTS)
121 pub fn new_with_rtscts( 121 pub fn new_with_rtscts(
122 uarte: impl Peripheral<P = T> + 'd, 122 uarte: impl Peripheral<P = T> + 'd,
123 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 123 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
124 rxd: impl Peripheral<P = impl GpioPin> + 'd, 124 rxd: impl Peripheral<P = impl GpioPin> + 'd,
125 txd: impl Peripheral<P = impl GpioPin> + 'd, 125 txd: impl Peripheral<P = impl GpioPin> + 'd,
126 cts: impl Peripheral<P = impl GpioPin> + 'd, 126 cts: impl Peripheral<P = impl GpioPin> + 'd,
@@ -168,8 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
168 } 168 }
169 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); 169 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
170 170
171 unsafe { T::Interrupt::steal() }.unpend(); 171 T::Interrupt::unpend();
172 unsafe { T::Interrupt::steal() }.enable(); 172 unsafe { T::Interrupt::enable() };
173 173
174 let hardware_flow_control = match (rts.is_some(), cts.is_some()) { 174 let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
175 (false, false) => false, 175 (false, false) => false,
@@ -205,50 +205,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
205 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 205 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
206 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 206 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
207 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { 207 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) {
208 let timer = Timer::new(timer); 208 (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2))
209
210 into_ref!(ppi_ch1, ppi_ch2);
211
212 let r = T::regs();
213
214 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
215 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
216 //
217 // We want to stop RX if line is idle for 2 bytes worth of time
218 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
219 // This gives us the amount of 16M ticks for 20 bits.
220 let baudrate = r.baudrate.read().baudrate().variant().unwrap();
221 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
222
223 timer.set_frequency(Frequency::F16MHz);
224 timer.cc(0).write(timeout);
225 timer.cc(0).short_compare_clear();
226 timer.cc(0).short_compare_stop();
227
228 let mut ppi_ch1 = Ppi::new_one_to_two(
229 ppi_ch1.map_into(),
230 Event::from_reg(&r.events_rxdrdy),
231 timer.task_clear(),
232 timer.task_start(),
233 );
234 ppi_ch1.enable();
235
236 let mut ppi_ch2 = Ppi::new_one_to_one(
237 ppi_ch2.map_into(),
238 timer.cc(0).event_compare(),
239 Task::from_reg(&r.tasks_stoprx),
240 );
241 ppi_ch2.enable();
242
243 (
244 self.tx,
245 UarteRxWithIdle {
246 rx: self.rx,
247 timer,
248 ppi_ch1: ppi_ch1,
249 _ppi_ch2: ppi_ch2,
250 },
251 )
252 } 209 }
253 210
254 /// Return the endtx event for use with PPI 211 /// Return the endtx event for use with PPI
@@ -313,7 +270,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
313 /// Create a new tx-only UARTE without hardware flow control 270 /// Create a new tx-only UARTE without hardware flow control
314 pub fn new( 271 pub fn new(
315 uarte: impl Peripheral<P = T> + 'd, 272 uarte: impl Peripheral<P = T> + 'd,
316 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 273 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
317 txd: impl Peripheral<P = impl GpioPin> + 'd, 274 txd: impl Peripheral<P = impl GpioPin> + 'd,
318 config: Config, 275 config: Config,
319 ) -> Self { 276 ) -> Self {
@@ -324,7 +281,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
324 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) 281 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
325 pub fn new_with_rtscts( 282 pub fn new_with_rtscts(
326 uarte: impl Peripheral<P = T> + 'd, 283 uarte: impl Peripheral<P = T> + 'd,
327 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 284 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
328 txd: impl Peripheral<P = impl GpioPin> + 'd, 285 txd: impl Peripheral<P = impl GpioPin> + 'd,
329 cts: impl Peripheral<P = impl GpioPin> + 'd, 286 cts: impl Peripheral<P = impl GpioPin> + 'd,
330 config: Config, 287 config: Config,
@@ -358,8 +315,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
358 let hardware_flow_control = cts.is_some(); 315 let hardware_flow_control = cts.is_some();
359 configure(r, config, hardware_flow_control); 316 configure(r, config, hardware_flow_control);
360 317
361 unsafe { T::Interrupt::steal() }.unpend(); 318 T::Interrupt::unpend();
362 unsafe { T::Interrupt::steal() }.enable(); 319 unsafe { T::Interrupt::enable() };
363 320
364 let s = T::state(); 321 let s = T::state();
365 s.tx_rx_refcount.store(1, Ordering::Relaxed); 322 s.tx_rx_refcount.store(1, Ordering::Relaxed);
@@ -509,7 +466,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
509 /// Create a new rx-only UARTE without hardware flow control 466 /// Create a new rx-only UARTE without hardware flow control
510 pub fn new( 467 pub fn new(
511 uarte: impl Peripheral<P = T> + 'd, 468 uarte: impl Peripheral<P = T> + 'd,
512 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 469 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
513 rxd: impl Peripheral<P = impl GpioPin> + 'd, 470 rxd: impl Peripheral<P = impl GpioPin> + 'd,
514 config: Config, 471 config: Config,
515 ) -> Self { 472 ) -> Self {
@@ -520,7 +477,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
520 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) 477 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
521 pub fn new_with_rtscts( 478 pub fn new_with_rtscts(
522 uarte: impl Peripheral<P = T> + 'd, 479 uarte: impl Peripheral<P = T> + 'd,
523 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 480 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
524 rxd: impl Peripheral<P = impl GpioPin> + 'd, 481 rxd: impl Peripheral<P = impl GpioPin> + 'd,
525 rts: impl Peripheral<P = impl GpioPin> + 'd, 482 rts: impl Peripheral<P = impl GpioPin> + 'd,
526 config: Config, 483 config: Config,
@@ -551,8 +508,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
551 r.psel.txd.write(|w| w.connect().disconnected()); 508 r.psel.txd.write(|w| w.connect().disconnected());
552 r.psel.cts.write(|w| w.connect().disconnected()); 509 r.psel.cts.write(|w| w.connect().disconnected());
553 510
554 unsafe { T::Interrupt::steal() }.unpend(); 511 T::Interrupt::unpend();
555 unsafe { T::Interrupt::steal() }.enable(); 512 unsafe { T::Interrupt::enable() };
556 513
557 let hardware_flow_control = rts.is_some(); 514 let hardware_flow_control = rts.is_some();
558 configure(r, config, hardware_flow_control); 515 configure(r, config, hardware_flow_control);
@@ -563,6 +520,56 @@ impl<'d, T: Instance> UarteRx<'d, T> {
563 Self { _p: uarte } 520 Self { _p: uarte }
564 } 521 }
565 522
523 /// Upgrade to an instance that supports idle line detection.
524 pub fn with_idle<U: TimerInstance>(
525 self,
526 timer: impl Peripheral<P = U> + 'd,
527 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
528 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
529 ) -> UarteRxWithIdle<'d, T, U> {
530 let timer = Timer::new(timer);
531
532 into_ref!(ppi_ch1, ppi_ch2);
533
534 let r = T::regs();
535
536 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
537 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
538 //
539 // We want to stop RX if line is idle for 2 bytes worth of time
540 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
541 // This gives us the amount of 16M ticks for 20 bits.
542 let baudrate = r.baudrate.read().baudrate().variant().unwrap();
543 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
544
545 timer.set_frequency(Frequency::F16MHz);
546 timer.cc(0).write(timeout);
547 timer.cc(0).short_compare_clear();
548 timer.cc(0).short_compare_stop();
549
550 let mut ppi_ch1 = Ppi::new_one_to_two(
551 ppi_ch1.map_into(),
552 Event::from_reg(&r.events_rxdrdy),
553 timer.task_clear(),
554 timer.task_start(),
555 );
556 ppi_ch1.enable();
557
558 let mut ppi_ch2 = Ppi::new_one_to_one(
559 ppi_ch2.map_into(),
560 timer.cc(0).event_compare(),
561 Task::from_reg(&r.tasks_stoprx),
562 );
563 ppi_ch2.enable();
564
565 UarteRxWithIdle {
566 rx: self,
567 timer,
568 ppi_ch1: ppi_ch1,
569 _ppi_ch2: ppi_ch2,
570 }
571 }
572
566 /// Read bytes until the buffer is filled. 573 /// Read bytes until the buffer is filled.
567 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 574 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
568 if buffer.len() == 0 { 575 if buffer.len() == 0 {
@@ -889,7 +896,7 @@ pub(crate) mod sealed {
889/// UARTE peripheral instance. 896/// UARTE peripheral instance.
890pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 897pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
891 /// Interrupt for this peripheral. 898 /// Interrupt for this peripheral.
892 type Interrupt: Interrupt; 899 type Interrupt: interrupt::typelevel::Interrupt;
893} 900}
894 901
895macro_rules! impl_uarte { 902macro_rules! impl_uarte {
@@ -908,7 +915,7 @@ macro_rules! impl_uarte {
908 } 915 }
909 } 916 }
910 impl crate::uarte::Instance for peripherals::$type { 917 impl crate::uarte::Instance for peripherals::$type {
911 type Interrupt = crate::interrupt::$irq; 918 type Interrupt = crate::interrupt::typelevel::$irq;
912 } 919 }
913 }; 920 };
914} 921}
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs
index c1f3f48cb..76cf40ac7 100644
--- a/embassy-nrf/src/usb/mod.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -18,9 +18,9 @@ use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo
18use pac::usbd::RegisterBlock; 18use pac::usbd::RegisterBlock;
19 19
20use self::vbus_detect::VbusDetect; 20use self::vbus_detect::VbusDetect;
21use crate::interrupt::{self, Interrupt, InterruptExt}; 21use crate::interrupt::typelevel::Interrupt;
22use crate::util::slice_in_ram; 22use crate::util::slice_in_ram;
23use crate::{pac, Peripheral}; 23use crate::{interrupt, pac, Peripheral};
24 24
25const NEW_AW: AtomicWaker = AtomicWaker::new(); 25const NEW_AW: AtomicWaker = AtomicWaker::new();
26static BUS_WAKER: AtomicWaker = NEW_AW; 26static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -34,7 +34,7 @@ pub struct InterruptHandler<T: Instance> {
34 _phantom: PhantomData<T>, 34 _phantom: PhantomData<T>,
35} 35}
36 36
37impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 37impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
38 unsafe fn on_interrupt() { 38 unsafe fn on_interrupt() {
39 let regs = T::regs(); 39 let regs = T::regs();
40 40
@@ -98,13 +98,13 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
98 /// Create a new USB driver. 98 /// Create a new USB driver.
99 pub fn new( 99 pub fn new(
100 usb: impl Peripheral<P = T> + 'd, 100 usb: impl Peripheral<P = T> + 'd,
101 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 101 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 vbus_detect: V, 102 vbus_detect: V,
103 ) -> Self { 103 ) -> Self {
104 into_ref!(usb); 104 into_ref!(usb);
105 105
106 unsafe { T::Interrupt::steal() }.unpend(); 106 T::Interrupt::unpend();
107 unsafe { T::Interrupt::steal() }.enable(); 107 unsafe { T::Interrupt::enable() };
108 108
109 Self { 109 Self {
110 _p: usb, 110 _p: usb,
@@ -804,7 +804,7 @@ pub(crate) mod sealed {
804/// USB peripheral instance. 804/// USB peripheral instance.
805pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 805pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
806 /// Interrupt for this peripheral. 806 /// Interrupt for this peripheral.
807 type Interrupt: Interrupt; 807 type Interrupt: interrupt::typelevel::Interrupt;
808} 808}
809 809
810macro_rules! impl_usb { 810macro_rules! impl_usb {
@@ -815,7 +815,7 @@ macro_rules! impl_usb {
815 } 815 }
816 } 816 }
817 impl crate::usb::Instance for peripherals::$type { 817 impl crate::usb::Instance for peripherals::$type {
818 type Interrupt = crate::interrupt::$irq; 818 type Interrupt = crate::interrupt::typelevel::$irq;
819 } 819 }
820 }; 820 };
821} 821}
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs
index cecd4c595..a05e5aa52 100644
--- a/embassy-nrf/src/usb/vbus_detect.rs
+++ b/embassy-nrf/src/usb/vbus_detect.rs
@@ -7,8 +7,8 @@ use core::task::Poll;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::BUS_WAKER; 9use super::BUS_WAKER;
10use crate::interrupt::{self, Interrupt, InterruptExt}; 10use crate::interrupt::typelevel::Interrupt;
11use crate::pac; 11use crate::{interrupt, pac};
12 12
13/// Trait for detecting USB VBUS power. 13/// Trait for detecting USB VBUS power.
14/// 14///
@@ -29,9 +29,9 @@ pub trait VbusDetect {
29} 29}
30 30
31#[cfg(not(feature = "_nrf5340"))] 31#[cfg(not(feature = "_nrf5340"))]
32type UsbRegIrq = interrupt::POWER_CLOCK; 32type UsbRegIrq = interrupt::typelevel::POWER_CLOCK;
33#[cfg(feature = "_nrf5340")] 33#[cfg(feature = "_nrf5340")]
34type UsbRegIrq = interrupt::USBREGULATOR; 34type UsbRegIrq = interrupt::typelevel::USBREGULATOR;
35 35
36#[cfg(not(feature = "_nrf5340"))] 36#[cfg(not(feature = "_nrf5340"))]
37type UsbRegPeri = pac::POWER; 37type UsbRegPeri = pac::POWER;
@@ -43,7 +43,7 @@ pub struct InterruptHandler {
43 _private: (), 43 _private: (),
44} 44}
45 45
46impl interrupt::Handler<UsbRegIrq> for InterruptHandler { 46impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
47 unsafe fn on_interrupt() { 47 unsafe fn on_interrupt() {
48 let regs = unsafe { &*UsbRegPeri::ptr() }; 48 let regs = unsafe { &*UsbRegPeri::ptr() };
49 49
@@ -77,11 +77,11 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new();
77 77
78impl HardwareVbusDetect { 78impl HardwareVbusDetect {
79 /// Create a new `VbusDetectNative`. 79 /// Create a new `VbusDetectNative`.
80 pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { 80 pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
81 let regs = unsafe { &*UsbRegPeri::ptr() }; 81 let regs = unsafe { &*UsbRegPeri::ptr() };
82 82
83 unsafe { UsbRegIrq::steal() }.unpend(); 83 UsbRegIrq::unpend();
84 unsafe { UsbRegIrq::steal() }.enable(); 84 unsafe { UsbRegIrq::enable() };
85 85
86 regs.intenset 86 regs.intenset
87 .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); 87 .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index e032dfdae..49aa6a4d5 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -13,7 +13,8 @@ flavors = [
13] 13]
14 14
15[features] 15[features]
16default = [ "rp-pac/rt" ] 16default = [ "rt" ]
17rt = [ "rp-pac/rt" ]
17 18
18defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"] 19defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
19 20
@@ -41,8 +42,13 @@ boot2-ram-memcpy = []
41boot2-w25q080 = [] 42boot2-w25q080 = []
42boot2-w25x10cl = [] 43boot2-w25x10cl = []
43 44
45# Indicate code is running from RAM.
46# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
47# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
48run-from-ram = []
49
44# Enable nightly-only features 50# Enable nightly-only features
45nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] 51nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
46 52
47# Implement embedded-hal 1.0 alpha traits. 53# Implement embedded-hal 1.0 alpha traits.
48# Implement embedded-hal-async traits if `nightly` is set as well. 54# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -50,11 +56,9 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
50 56
51[dependencies] 57[dependencies]
52embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 58embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
53embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
54embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 59embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
55embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 60embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
56embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} 61embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] }
57embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
58embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 62embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
59embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 63embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
60atomic-polyfill = "1.0.1" 64atomic-polyfill = "1.0.1"
@@ -72,7 +76,7 @@ embedded-storage = { version = "0.3" }
72rand_core = "0.6.4" 76rand_core = "0.6.4"
73fixed = "1.23.1" 77fixed = "1.23.1"
74 78
75rp-pac = { version = "4" } 79rp-pac = { version = "5" }
76 80
77embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
78embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
@@ -85,5 +89,5 @@ pio = {version= "0.2.1" }
85rp2040-boot2 = "0.3" 89rp2040-boot2 = "0.3"
86 90
87[dev-dependencies] 91[dev-dependencies]
88embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } 92embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
89static_cell = "1.0" 93static_cell = "1.1"
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 59c7a47ce..b96d5a4a8 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -3,14 +3,14 @@ use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::{Binding, Interrupt};
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot}; 7use embedded_hal_02::adc::{Channel, OneShot};
9 8
10use crate::gpio::Pin; 9use crate::gpio::Pin;
11use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO}; 10use crate::interrupt::typelevel::Binding;
11use crate::interrupt::InterruptExt;
12use crate::peripherals::ADC; 12use crate::peripherals::ADC;
13use crate::{pac, peripherals, Peripheral}; 13use crate::{interrupt, pac, peripherals, Peripheral};
14static WAKER: AtomicWaker = AtomicWaker::new(); 14static WAKER: AtomicWaker = AtomicWaker::new();
15 15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)] 16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -47,105 +47,91 @@ impl<'d> Adc<'d> {
47 47
48 pub fn new( 48 pub fn new(
49 _inner: impl Peripheral<P = ADC> + 'd, 49 _inner: impl Peripheral<P = ADC> + 'd,
50 _irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>, 50 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
51 _config: Config, 51 _config: Config,
52 ) -> Self { 52 ) -> Self {
53 unsafe { 53 let reset = Self::reset();
54 let reset = Self::reset(); 54 crate::reset::reset(reset);
55 crate::reset::reset(reset); 55 crate::reset::unreset_wait(reset);
56 crate::reset::unreset_wait(reset); 56 let r = Self::regs();
57 let r = Self::regs(); 57 // Enable ADC
58 // Enable ADC 58 r.cs().write(|w| w.set_en(true));
59 r.cs().write(|w| w.set_en(true)); 59 // Wait for ADC ready
60 // Wait for ADC ready 60 while !r.cs().read().ready() {}
61 while !r.cs().read().ready() {}
62 }
63 61
64 // Setup IRQ 62 // Setup IRQ
65 unsafe { 63 interrupt::ADC_IRQ_FIFO.unpend();
66 ADC_IRQ_FIFO::steal().unpend(); 64 unsafe { interrupt::ADC_IRQ_FIFO.enable() };
67 ADC_IRQ_FIFO::steal().enable();
68 };
69 65
70 Self { phantom: PhantomData } 66 Self { phantom: PhantomData }
71 } 67 }
72 68
73 async fn wait_for_ready() { 69 async fn wait_for_ready() {
74 let r = Self::regs(); 70 let r = Self::regs();
75 unsafe { 71 r.inte().write(|w| w.set_fifo(true));
76 r.inte().write(|w| w.set_fifo(true)); 72 compiler_fence(Ordering::SeqCst);
77 compiler_fence(Ordering::SeqCst); 73 poll_fn(|cx| {
78 poll_fn(|cx| { 74 WAKER.register(cx.waker());
79 WAKER.register(cx.waker()); 75 if r.cs().read().ready() {
80 if r.cs().read().ready() { 76 return Poll::Ready(());
81 return Poll::Ready(()); 77 }
82 } 78 Poll::Pending
83 Poll::Pending 79 })
84 }) 80 .await;
85 .await;
86 }
87 } 81 }
88 82
89 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 83 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
90 let r = Self::regs(); 84 let r = Self::regs();
91 unsafe { 85 // disable pull-down and pull-up resistors
92 // disable pull-down and pull-up resistors 86 // pull-down resistors are enabled by default
93 // pull-down resistors are enabled by default 87 pin.pad_ctrl().modify(|w| {
94 pin.pad_ctrl().modify(|w| { 88 w.set_ie(true);
95 w.set_ie(true); 89 let (pu, pd) = (false, false);
96 let (pu, pd) = (false, false); 90 w.set_pue(pu);
97 w.set_pue(pu); 91 w.set_pde(pd);
98 w.set_pde(pd); 92 });
99 }); 93 r.cs().modify(|w| {
100 r.cs().modify(|w| { 94 w.set_ainsel(PIN::channel());
101 w.set_ainsel(PIN::channel()); 95 w.set_start_once(true)
102 w.set_start_once(true) 96 });
103 }); 97 Self::wait_for_ready().await;
104 Self::wait_for_ready().await; 98 r.result().read().result().into()
105 r.result().read().result().into()
106 }
107 } 99 }
108 100
109 pub async fn read_temperature(&mut self) -> u16 { 101 pub async fn read_temperature(&mut self) -> u16 {
110 let r = Self::regs(); 102 let r = Self::regs();
111 unsafe { 103 r.cs().modify(|w| w.set_ts_en(true));
112 r.cs().modify(|w| w.set_ts_en(true)); 104 if !r.cs().read().ready() {
113 if !r.cs().read().ready() {
114 Self::wait_for_ready().await;
115 }
116 r.cs().modify(|w| {
117 w.set_ainsel(4);
118 w.set_start_once(true)
119 });
120 Self::wait_for_ready().await; 105 Self::wait_for_ready().await;
121 r.result().read().result().into()
122 } 106 }
107 r.cs().modify(|w| {
108 w.set_ainsel(4);
109 w.set_start_once(true)
110 });
111 Self::wait_for_ready().await;
112 r.result().read().result().into()
123 } 113 }
124 114
125 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { 115 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
126 let r = Self::regs(); 116 let r = Self::regs();
127 unsafe { 117 r.cs().modify(|w| {
128 r.cs().modify(|w| { 118 w.set_ainsel(PIN::channel());
129 w.set_ainsel(PIN::channel()); 119 w.set_start_once(true)
130 w.set_start_once(true) 120 });
131 }); 121 while !r.cs().read().ready() {}
132 while !r.cs().read().ready() {} 122 r.result().read().result().into()
133 r.result().read().result().into()
134 }
135 } 123 }
136 124
137 pub fn blocking_read_temperature(&mut self) -> u16 { 125 pub fn blocking_read_temperature(&mut self) -> u16 {
138 let r = Self::regs(); 126 let r = Self::regs();
139 unsafe { 127 r.cs().modify(|w| w.set_ts_en(true));
140 r.cs().modify(|w| w.set_ts_en(true)); 128 while !r.cs().read().ready() {}
141 while !r.cs().read().ready() {} 129 r.cs().modify(|w| {
142 r.cs().modify(|w| { 130 w.set_ainsel(4);
143 w.set_ainsel(4); 131 w.set_start_once(true)
144 w.set_start_once(true) 132 });
145 }); 133 while !r.cs().read().ready() {}
146 while !r.cs().read().ready() {} 134 r.result().read().result().into()
147 r.result().read().result().into()
148 }
149 } 135 }
150} 136}
151 137
@@ -164,7 +150,7 @@ pub struct InterruptHandler {
164 _empty: (), 150 _empty: (),
165} 151}
166 152
167impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler { 153impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
168 unsafe fn on_interrupt() { 154 unsafe fn on_interrupt() {
169 let r = Adc::regs(); 155 let r = Adc::regs();
170 r.inte().write(|w| w.set_fifo(false)); 156 r.inte().write(|w| w.set_fifo(false));
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 67439fda3..4c6223107 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
542 reset::unreset_wait(peris); 542 reset::unreset_wait(peris);
543} 543}
544 544
545unsafe fn configure_rosc(config: RoscConfig) -> u32 { 545fn configure_rosc(config: RoscConfig) -> u32 {
546 let p = pac::ROSC; 546 let p = pac::ROSC;
547 547
548 p.freqa().write(|w| { 548 p.freqa().write(|w| {
@@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 {
620 CLOCKS.rtc.load(Ordering::Relaxed) 620 CLOCKS.rtc.load(Ordering::Relaxed)
621} 621}
622 622
623unsafe fn start_xosc(crystal_hz: u32) { 623fn start_xosc(crystal_hz: u32) {
624 pac::XOSC 624 pac::XOSC
625 .ctrl() 625 .ctrl()
626 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); 626 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
@@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) {
635} 635}
636 636
637#[inline(always)] 637#[inline(always)]
638unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { 638fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
639 let ref_freq = input_freq / config.refdiv as u32; 639 let ref_freq = input_freq / config.refdiv as u32;
640 assert!(config.fbdiv >= 16 && config.fbdiv <= 320); 640 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
641 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 641 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
@@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> {
700 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { 700 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
701 into_ref!(gpin); 701 into_ref!(gpin);
702 702
703 unsafe { 703 gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
704 gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
705 }
706 704
707 Gpin { 705 Gpin {
708 gpin: gpin.map_into(), 706 gpin: gpin.map_into(),
@@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> {
717 715
718impl<'d, T: Pin> Drop for Gpin<'d, T> { 716impl<'d, T: Pin> Drop for Gpin<'d, T> {
719 fn drop(&mut self) { 717 fn drop(&mut self) {
720 unsafe { 718 self.gpin
721 self.gpin 719 .io()
722 .io() 720 .ctrl()
723 .ctrl() 721 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
724 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
725 }
726 } 722 }
727} 723}
728 724
@@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
768 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { 764 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
769 into_ref!(gpout); 765 into_ref!(gpout);
770 766
771 unsafe { 767 gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
772 gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
773 }
774 768
775 Self { gpout } 769 Self { gpout }
776 } 770 }
777 771
778 pub fn set_div(&self, int: u32, frac: u8) { 772 pub fn set_div(&self, int: u32, frac: u8) {
779 unsafe { 773 let c = pac::CLOCKS;
780 let c = pac::CLOCKS; 774 c.clk_gpout_div(self.gpout.number()).write(|w| {
781 c.clk_gpout_div(self.gpout.number()).write(|w| { 775 w.set_int(int);
782 w.set_int(int); 776 w.set_frac(frac);
783 w.set_frac(frac); 777 });
784 });
785 }
786 } 778 }
787 779
788 pub fn set_src(&self, src: GpoutSrc) { 780 pub fn set_src(&self, src: GpoutSrc) {
789 unsafe { 781 let c = pac::CLOCKS;
790 let c = pac::CLOCKS; 782 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
791 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 783 w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
792 w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); 784 });
793 });
794 }
795 } 785 }
796 786
797 pub fn enable(&self) { 787 pub fn enable(&self) {
798 unsafe { 788 let c = pac::CLOCKS;
799 let c = pac::CLOCKS; 789 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
800 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 790 w.set_enable(true);
801 w.set_enable(true); 791 });
802 });
803 }
804 } 792 }
805 793
806 pub fn disable(&self) { 794 pub fn disable(&self) {
807 unsafe { 795 let c = pac::CLOCKS;
808 let c = pac::CLOCKS; 796 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
809 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 797 w.set_enable(false);
810 w.set_enable(false); 798 });
811 });
812 }
813 } 799 }
814 800
815 pub fn get_freq(&self) -> u32 { 801 pub fn get_freq(&self) -> u32 {
816 let c = pac::CLOCKS; 802 let c = pac::CLOCKS;
817 let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; 803 let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc();
818 804
819 let base = match src { 805 let base = match src {
820 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), 806 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
@@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
831 _ => unreachable!(), 817 _ => unreachable!(),
832 }; 818 };
833 819
834 let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; 820 let div = c.clk_gpout_div(self.gpout.number()).read();
835 let int = if div.int() == 0 { 65536 } else { div.int() } as u64; 821 let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
836 let frac = div.frac() as u64; 822 let frac = div.frac() as u64;
837 823
@@ -842,12 +828,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
842impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { 828impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
843 fn drop(&mut self) { 829 fn drop(&mut self) {
844 self.disable(); 830 self.disable();
845 unsafe { 831 self.gpout
846 self.gpout 832 .io()
847 .io() 833 .ctrl()
848 .ctrl() 834 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
849 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
850 }
851 } 835 }
852} 836}
853 837
@@ -864,7 +848,7 @@ impl RoscRng {
864 let mut acc = 0; 848 let mut acc = 0;
865 for _ in 0..u8::BITS { 849 for _ in 0..u8::BITS {
866 acc <<= 1; 850 acc <<= 1;
867 acc |= unsafe { random_reg.read().randombit() as u8 }; 851 acc |= random_reg.read().randombit() as u8;
868 } 852 }
869 acc 853 acc
870 } 854 }
diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs
index ce284c856..d233e6fab 100644
--- a/embassy-rp/src/critical_section_impl.rs
+++ b/embassy-rp/src/critical_section_impl.rs
@@ -103,14 +103,11 @@ where
103 /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is 103 /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is
104 /// already in use somewhere else. 104 /// already in use somewhere else.
105 pub fn try_claim() -> Option<Self> { 105 pub fn try_claim() -> Option<Self> {
106 // Safety: We're only reading from this register 106 let lock = pac::SIO.spinlock(N).read();
107 unsafe { 107 if lock > 0 {
108 let lock = pac::SIO.spinlock(N).read(); 108 Some(Self(core::marker::PhantomData))
109 if lock > 0 { 109 } else {
110 Some(Self(core::marker::PhantomData)) 110 None
111 } else {
112 None
113 }
114 } 111 }
115 } 112 }
116 113
@@ -120,10 +117,8 @@ where
120 /// 117 ///
121 /// Only call this function if you hold the spin-lock. 118 /// Only call this function if you hold the spin-lock.
122 pub unsafe fn release() { 119 pub unsafe fn release() {
123 unsafe { 120 // Write (any value): release the lock
124 // Write (any value): release the lock 121 pac::SIO.spinlock(N).write_value(1);
125 pac::SIO.spinlock(N).write_value(1);
126 }
127 } 122 }
128} 123}
129 124
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index ba07a88df..1a458778c 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -4,16 +4,17 @@ use core::pin::Pin;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
8use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; 7use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma::vals::DataSize; 9use pac::dma::vals::DataSize;
11 10
11use crate::interrupt::InterruptExt;
12use crate::pac::dma::vals; 12use crate::pac::dma::vals;
13use crate::{interrupt, pac, peripherals}; 13use crate::{interrupt, pac, peripherals};
14 14
15#[cfg(feature = "rt")]
15#[interrupt] 16#[interrupt]
16unsafe fn DMA_IRQ_0() { 17fn DMA_IRQ_0() {
17 let ints0 = pac::DMA.ints0().read().ints0(); 18 let ints0 = pac::DMA.ints0().read().ints0();
18 for channel in 0..CHANNEL_COUNT { 19 for channel in 0..CHANNEL_COUNT {
19 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); 20 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
@@ -29,13 +30,12 @@ unsafe fn DMA_IRQ_0() {
29} 30}
30 31
31pub(crate) unsafe fn init() { 32pub(crate) unsafe fn init() {
32 let irq = interrupt::DMA_IRQ_0::steal(); 33 interrupt::DMA_IRQ_0.disable();
33 irq.disable(); 34 interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3);
34 irq.set_priority(interrupt::Priority::P3);
35 35
36 pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); 36 pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF));
37 37
38 irq.enable(); 38 interrupt::DMA_IRQ_0.enable();
39} 39}
40 40
41pub unsafe fn read<'a, C: Channel, W: Word>( 41pub unsafe fn read<'a, C: Channel, W: Word>(
@@ -76,16 +76,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
76 ) 76 )
77} 77}
78 78
79static DUMMY: u32 = 0;
80
79pub unsafe fn write_repeated<'a, C: Channel, W: Word>( 81pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
80 ch: impl Peripheral<P = C> + 'a, 82 ch: impl Peripheral<P = C> + 'a,
81 to: *mut W, 83 to: *mut W,
82 len: usize, 84 len: usize,
83 dreq: u8, 85 dreq: u8,
84) -> Transfer<'a, C> { 86) -> Transfer<'a, C> {
85 let dummy: u32 = 0;
86 copy_inner( 87 copy_inner(
87 ch, 88 ch,
88 &dummy as *const u32, 89 &DUMMY as *const u32,
89 to as *mut u32, 90 to as *mut u32,
90 len, 91 len,
91 W::size(), 92 W::size(),
@@ -127,28 +128,26 @@ fn copy_inner<'a, C: Channel>(
127) -> Transfer<'a, C> { 128) -> Transfer<'a, C> {
128 into_ref!(ch); 129 into_ref!(ch);
129 130
130 unsafe { 131 let p = ch.regs();
131 let p = ch.regs();
132 132
133 p.read_addr().write_value(from as u32); 133 p.read_addr().write_value(from as u32);
134 p.write_addr().write_value(to as u32); 134 p.write_addr().write_value(to as u32);
135 p.trans_count().write_value(len as u32); 135 p.trans_count().write_value(len as u32);
136 136
137 compiler_fence(Ordering::SeqCst); 137 compiler_fence(Ordering::SeqCst);
138 138
139 p.ctrl_trig().write(|w| { 139 p.ctrl_trig().write(|w| {
140 // TODO: Add all DREQ options to pac vals::TreqSel, and use 140 // TODO: Add all DREQ options to pac vals::TreqSel, and use
141 // `set_treq:sel` 141 // `set_treq:sel`
142 w.0 = ((dreq as u32) & 0x3f) << 15usize; 142 w.0 = ((dreq as u32) & 0x3f) << 15usize;
143 w.set_data_size(data_size); 143 w.set_data_size(data_size);
144 w.set_incr_read(incr_read); 144 w.set_incr_read(incr_read);
145 w.set_incr_write(incr_write); 145 w.set_incr_write(incr_write);
146 w.set_chain_to(ch.number()); 146 w.set_chain_to(ch.number());
147 w.set_en(true); 147 w.set_en(true);
148 }); 148 });
149 149
150 compiler_fence(Ordering::SeqCst); 150 compiler_fence(Ordering::SeqCst);
151 }
152 Transfer::new(ch) 151 Transfer::new(ch)
153} 152}
154 153
@@ -168,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
168impl<'a, C: Channel> Drop for Transfer<'a, C> { 167impl<'a, C: Channel> Drop for Transfer<'a, C> {
169 fn drop(&mut self) { 168 fn drop(&mut self) {
170 let p = self.channel.regs(); 169 let p = self.channel.regs();
171 unsafe { 170 pac::DMA
172 pac::DMA 171 .chan_abort()
173 .chan_abort() 172 .modify(|m| m.set_chan_abort(1 << self.channel.number()));
174 .modify(|m| m.set_chan_abort(1 << self.channel.number())); 173 while p.ctrl_trig().read().busy() {}
175 while p.ctrl_trig().read().busy() {}
176 }
177 } 174 }
178} 175}
179 176
@@ -185,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
185 // calls to wake will deregister the waker. 182 // calls to wake will deregister the waker.
186 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); 183 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
187 184
188 if unsafe { self.channel.regs().ctrl_trig().read().busy() } { 185 if self.channel.regs().ctrl_trig().read().busy() {
189 Poll::Pending 186 Poll::Pending
190 } else { 187 } else {
191 Poll::Ready(()) 188 Poll::Ready(())
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 0410429e0..96d2d4541 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{
9use crate::pac; 9use crate::pac;
10use crate::peripherals::FLASH; 10use crate::peripherals::FLASH;
11 11
12pub const FLASH_BASE: usize = 0x10000000; 12pub const FLASH_BASE: *const u32 = 0x10000000 as _;
13
14// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
15// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
16pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
13 17
14// **NOTE**: 18// **NOTE**:
15// 19//
@@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
63 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 67 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
64 trace!( 68 trace!(
65 "Reading from 0x{:x} to 0x{:x}", 69 "Reading from 0x{:x} to 0x{:x}",
66 FLASH_BASE + offset as usize, 70 FLASH_BASE as u32 + offset,
67 FLASH_BASE + offset as usize + bytes.len() 71 FLASH_BASE as u32 + offset + bytes.len() as u32
68 ); 72 );
69 check_read(self, offset, bytes.len())?; 73 check_read(self, offset, bytes.len())?;
70 74
@@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
89 93
90 let len = to - from; 94 let len = to - from;
91 95
92 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? }; 96 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
93 97
94 Ok(()) 98 Ok(())
95 } 99 }
@@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
114 118
115 let unaligned_offset = offset as usize - start; 119 let unaligned_offset = offset as usize - start;
116 120
117 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 121 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
118 } 122 }
119 123
120 let remaining_len = bytes.len() - start_padding; 124 let remaining_len = bytes.len() - start_padding;
@@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
132 if bytes.as_ptr() as usize >= 0x2000_0000 { 136 if bytes.as_ptr() as usize >= 0x2000_0000 {
133 let aligned_data = &bytes[start_padding..end_padding]; 137 let aligned_data = &bytes[start_padding..end_padding];
134 138
135 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? } 139 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
136 } else { 140 } else {
137 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { 141 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
138 let mut ram_buf = [0xFF_u8; PAGE_SIZE]; 142 let mut ram_buf = [0xFF_u8; PAGE_SIZE];
139 ram_buf.copy_from_slice(chunk); 143 ram_buf.copy_from_slice(chunk);
140 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? } 144 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
141 aligned_offset += PAGE_SIZE; 145 aligned_offset += PAGE_SIZE;
142 } 146 }
143 } 147 }
@@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
152 156
153 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); 157 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
154 158
155 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 159 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
156 } 160 }
157 161
158 Ok(()) 162 Ok(())
@@ -163,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
163 /// - DMA must not access flash memory 167 /// - DMA must not access flash memory
164 unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { 168 unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
165 // Make sure we're running on CORE0 169 // Make sure we're running on CORE0
166 let core_id: u32 = unsafe { pac::SIO.cpuid().read() }; 170 let core_id: u32 = pac::SIO.cpuid().read();
167 if core_id != 0 { 171 if core_id != 0 {
168 return Err(Error::InvalidCore); 172 return Err(Error::InvalidCore);
169 } 173 }
@@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
190 194
191 /// Read SPI flash unique ID 195 /// Read SPI flash unique ID
192 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 196 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
193 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? }; 197 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
194 Ok(()) 198 Ok(())
195 } 199 }
196 200
@@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
199 let mut jedec = None; 203 let mut jedec = None;
200 unsafe { 204 unsafe {
201 self.in_ram(|| { 205 self.in_ram(|| {
202 jedec.replace(ram_helpers::flash_jedec_id(true)); 206 jedec.replace(ram_helpers::flash_jedec_id());
203 })?; 207 })?;
204 }; 208 };
205 Ok(jedec.unwrap()) 209 Ok(jedec.unwrap())
@@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
242mod ram_helpers { 246mod ram_helpers {
243 use core::marker::PhantomData; 247 use core::marker::PhantomData;
244 248
249 use super::*;
245 use crate::rom_data; 250 use crate::rom_data;
246 251
247 #[repr(C)] 252 #[repr(C)]
@@ -306,7 +311,7 @@ mod ram_helpers {
306 /// 311 ///
307 /// `addr` and `len` must be multiples of 4096 312 /// `addr` and `len` must be multiples of 4096
308 /// 313 ///
309 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 314 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
310 /// is used to re-initialize the XIP engine after flashing. 315 /// is used to re-initialize the XIP engine after flashing.
311 /// 316 ///
312 /// # Safety 317 /// # Safety
@@ -318,10 +323,10 @@ mod ram_helpers {
318 /// - DMA must not access flash memory 323 /// - DMA must not access flash memory
319 /// 324 ///
320 /// `addr` and `len` parameters must be valid and are not checked. 325 /// `addr` and `len` parameters must be valid and are not checked.
321 pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) { 326 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
322 let mut boot2 = [0u32; 256 / 4]; 327 let mut boot2 = [0u32; 256 / 4];
323 let ptrs = if use_boot2 { 328 let ptrs = if USE_BOOT2 {
324 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 329 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
325 flash_function_pointers_with_boot2(true, false, &boot2) 330 flash_function_pointers_with_boot2(true, false, &boot2)
326 } else { 331 } else {
327 flash_function_pointers(true, false) 332 flash_function_pointers(true, false)
@@ -336,7 +341,7 @@ mod ram_helpers {
336 /// 341 ///
337 /// `addr` and `data.len()` must be multiples of 4096 342 /// `addr` and `data.len()` must be multiples of 4096
338 /// 343 ///
339 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 344 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
340 /// is used to re-initialize the XIP engine after flashing. 345 /// is used to re-initialize the XIP engine after flashing.
341 /// 346 ///
342 /// # Safety 347 /// # Safety
@@ -348,10 +353,10 @@ mod ram_helpers {
348 /// - DMA must not access flash memory 353 /// - DMA must not access flash memory
349 /// 354 ///
350 /// `addr` and `len` parameters must be valid and are not checked. 355 /// `addr` and `len` parameters must be valid and are not checked.
351 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) { 356 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
352 let mut boot2 = [0u32; 256 / 4]; 357 let mut boot2 = [0u32; 256 / 4];
353 let ptrs = if use_boot2 { 358 let ptrs = if USE_BOOT2 {
354 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 359 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
355 flash_function_pointers_with_boot2(true, true, &boot2) 360 flash_function_pointers_with_boot2(true, true, &boot2)
356 } else { 361 } else {
357 flash_function_pointers(true, true) 362 flash_function_pointers(true, true)
@@ -371,7 +376,7 @@ mod ram_helpers {
371 /// 376 ///
372 /// `addr` and `data.len()` must be multiples of 256 377 /// `addr` and `data.len()` must be multiples of 256
373 /// 378 ///
374 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 379 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
375 /// is used to re-initialize the XIP engine after flashing. 380 /// is used to re-initialize the XIP engine after flashing.
376 /// 381 ///
377 /// # Safety 382 /// # Safety
@@ -383,10 +388,10 @@ mod ram_helpers {
383 /// - DMA must not access flash memory 388 /// - DMA must not access flash memory
384 /// 389 ///
385 /// `addr` and `len` parameters must be valid and are not checked. 390 /// `addr` and `len` parameters must be valid and are not checked.
386 pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) { 391 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
387 let mut boot2 = [0u32; 256 / 4]; 392 let mut boot2 = [0u32; 256 / 4];
388 let ptrs = if use_boot2 { 393 let ptrs = if USE_BOOT2 {
389 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 394 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
390 flash_function_pointers_with_boot2(false, true, &boot2) 395 flash_function_pointers_with_boot2(false, true, &boot2)
391 } else { 396 } else {
392 flash_function_pointers(false, true) 397 flash_function_pointers(false, true)
@@ -508,10 +513,10 @@ mod ram_helpers {
508 /// - DMA must not access flash memory 513 /// - DMA must not access flash memory
509 /// 514 ///
510 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 515 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
511 pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) { 516 pub unsafe fn flash_unique_id(out: &mut [u8]) {
512 let mut boot2 = [0u32; 256 / 4]; 517 let mut boot2 = [0u32; 256 / 4];
513 let ptrs = if use_boot2 { 518 let ptrs = if USE_BOOT2 {
514 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 519 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
515 flash_function_pointers_with_boot2(false, false, &boot2) 520 flash_function_pointers_with_boot2(false, false, &boot2)
516 } else { 521 } else {
517 flash_function_pointers(false, false) 522 flash_function_pointers(false, false)
@@ -536,10 +541,10 @@ mod ram_helpers {
536 /// - DMA must not access flash memory 541 /// - DMA must not access flash memory
537 /// 542 ///
538 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 543 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
539 pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 { 544 pub unsafe fn flash_jedec_id() -> u32 {
540 let mut boot2 = [0u32; 256 / 4]; 545 let mut boot2 = [0u32; 256 / 4];
541 let ptrs = if use_boot2 { 546 let ptrs = if USE_BOOT2 {
542 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 547 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
543 flash_function_pointers_with_boot2(false, false, &boot2) 548 flash_function_pointers_with_boot2(false, false, &boot2)
544 } else { 549 } else {
545 flash_function_pointers(false, false) 550 flash_function_pointers(false, false)
@@ -586,7 +591,6 @@ mod ram_helpers {
586 "ldr r4, [r5, #4]", 591 "ldr r4, [r5, #4]",
587 "blx r4", // flash_exit_xip() 592 "blx r4", // flash_exit_xip()
588 593
589 "mov r7, r10", // cmd
590 594
591 "movs r4, #0x18", 595 "movs r4, #0x18",
592 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13 596 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
@@ -603,8 +607,9 @@ mod ram_helpers {
603 "str r1, [r4, #0]", 607 "str r1, [r4, #0]",
604 608
605 // Write ctrlr1 with len-1 609 // Write ctrlr1 with len-1
606 "ldr r0, [r7, #8]", // dummy_len 610 "mov r3, r10", // cmd
607 "ldr r1, [r7, #16]", // data_len 611 "ldr r0, [r3, #8]", // dummy_len
612 "ldr r1, [r3, #16]", // data_len
608 "add r0, r1", 613 "add r0, r1",
609 "subs r0, #1", 614 "subs r0, #1",
610 "str r0, [r4, #0x04]", // CTRLR1 615 "str r0, [r4, #0x04]", // CTRLR1
@@ -616,8 +621,8 @@ mod ram_helpers {
616 // Write cmd/addr phase to DR 621 // Write cmd/addr phase to DR
617 "mov r2, r4", 622 "mov r2, r4",
618 "adds r2, 0x60", // &DR 623 "adds r2, 0x60", // &DR
619 "ldr r0, [r7, #0]", // cmd_addr 624 "ldr r0, [r3, #0]", // cmd_addr
620 "ldr r1, [r7, #4]", // cmd_addr_len 625 "ldr r1, [r3, #4]", // cmd_addr_len
621 "10:", 626 "10:",
622 "ldrb r3, [r0]", 627 "ldrb r3, [r0]",
623 "strb r3, [r2]", // DR 628 "strb r3, [r2]", // DR
@@ -626,7 +631,8 @@ mod ram_helpers {
626 "bne 10b", 631 "bne 10b",
627 632
628 // Skip any dummy cycles 633 // Skip any dummy cycles
629 "ldr r1, [r7, #8]", // dummy_len 634 "mov r3, r10", // cmd
635 "ldr r1, [r3, #8]", // dummy_len
630 "cmp r1, #0", 636 "cmp r1, #0",
631 "beq 9f", 637 "beq 9f",
632 "4:", 638 "4:",
@@ -643,8 +649,9 @@ mod ram_helpers {
643 649
644 // Read RX fifo 650 // Read RX fifo
645 "9:", 651 "9:",
646 "ldr r0, [r7, #12]", // data 652 "mov r2, r10", // cmd
647 "ldr r1, [r7, #16]", // data_len 653 "ldr r0, [r2, #12]", // data
654 "ldr r1, [r2, #16]", // data_len
648 655
649 "2:", 656 "2:",
650 "ldr r3, [r4, #0x28]", // SR 657 "ldr r3, [r4, #0x28]", // SR
@@ -678,13 +685,12 @@ mod ram_helpers {
678 out("r2") _, 685 out("r2") _,
679 out("r3") _, 686 out("r3") _,
680 out("r4") _, 687 out("r4") _,
688 out("r5") _,
681 // Registers r8-r10 are used to store values 689 // Registers r8-r10 are used to store values
682 // from r0-r2 in registers not clobbered by 690 // from r0-r2 in registers not clobbered by
683 // function calls. 691 // function calls.
684 // The values can't be passed in using r8-r10 directly 692 // The values can't be passed in using r8-r10 directly
685 // due to https://github.com/rust-lang/rust/issues/99071 693 // due to https://github.com/rust-lang/rust/issues/99071
686 out("r8") _,
687 out("r9") _,
688 out("r10") _, 694 out("r10") _,
689 clobber_abi("C"), 695 clobber_abi("C"),
690 ); 696 );
diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs
index 094dec446..aff0dcb07 100644
--- a/embassy-rp/src/float/div.rs
+++ b/embassy-rp/src/float/div.rs
@@ -17,45 +17,43 @@ where
17{ 17{
18 let sio = rp_pac::SIO; 18 let sio = rp_pac::SIO;
19 19
20 unsafe { 20 // Since we can't save the signed-ness of the calculation, we have to make
21 // Since we can't save the signed-ness of the calculation, we have to make 21 // sure that there's at least an 8 cycle delay before we read the result.
22 // sure that there's at least an 8 cycle delay before we read the result. 22 // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
23 // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. 23 // Since we can't be sure the Rust implementation will optimize to the same,
24 // Since we can't be sure the Rust implementation will optimize to the same, 24 // just use an explicit wait.
25 // just use an explicit wait. 25 while !sio.div().csr().read().ready() {}
26 while !sio.div().csr().read().ready() {} 26
27 27 // Read the quotient last, since that's what clears the dirty flag
28 // Read the quotient last, since that's what clears the dirty flag 28 let dividend = sio.div().udividend().read();
29 let dividend = sio.div().udividend().read(); 29 let divisor = sio.div().udivisor().read();
30 let divisor = sio.div().udivisor().read(); 30 let remainder = sio.div().remainder().read();
31 let remainder = sio.div().remainder().read(); 31 let quotient = sio.div().quotient().read();
32 let quotient = sio.div().quotient().read(); 32
33 33 // If we get interrupted here (before a write sets the DIRTY flag) its fine, since
34 // If we get interrupted here (before a write sets the DIRTY flag) its fine, since 34 // we have the full state, so the interruptor doesn't have to restore it. Once the
35 // we have the full state, so the interruptor doesn't have to restore it. Once the 35 // write happens and the DIRTY flag is set, the interruptor becomes responsible for
36 // write happens and the DIRTY flag is set, the interruptor becomes responsible for 36 // restoring our state.
37 // restoring our state. 37 let result = f();
38 let result = f(); 38
39 39 // If we are interrupted here, then the interruptor will start an incorrect calculation
40 // If we are interrupted here, then the interruptor will start an incorrect calculation 40 // using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
41 // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. 41 // This sets DIRTY, so any interruptor will save the state.
42 // This sets DIRTY, so any interruptor will save the state. 42 sio.div().udividend().write_value(dividend);
43 sio.div().udividend().write_value(dividend); 43 // If we are interrupted here, the the interruptor may start the calculation using
44 // If we are interrupted here, the the interruptor may start the calculation using 44 // incorrectly signed inputs, but we'll restore the result ourselves.
45 // incorrectly signed inputs, but we'll restore the result ourselves. 45 // This sets DIRTY, so any interruptor will save the state.
46 // This sets DIRTY, so any interruptor will save the state. 46 sio.div().udivisor().write_value(divisor);
47 sio.div().udivisor().write_value(divisor); 47 // If we are interrupted here, the interruptor will have restored everything but the
48 // If we are interrupted here, the interruptor will have restored everything but the 48 // quotient may be wrongly signed. If the calculation started by the above writes is
49 // quotient may be wrongly signed. If the calculation started by the above writes is 49 // still ongoing it is stopped, so it won't replace the result we're restoring.
50 // still ongoing it is stopped, so it won't replace the result we're restoring. 50 // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
51 // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. 51 sio.div().remainder().write_value(remainder);
52 sio.div().remainder().write_value(remainder); 52 // State fully restored after the quotient write. This sets both DIRTY and READY, so
53 // State fully restored after the quotient write. This sets both DIRTY and READY, so 53 // whatever we may have interrupted can read the result.
54 // whatever we may have interrupted can read the result. 54 sio.div().quotient().write_value(quotient);
55 sio.div().quotient().write_value(quotient); 55
56 56 result
57 result
58 }
59} 57}
60 58
61fn save_divider<F, R>(f: F) -> R 59fn save_divider<F, R>(f: F) -> R
@@ -63,7 +61,7 @@ where
63 F: FnOnce() -> R, 61 F: FnOnce() -> R,
64{ 62{
65 let sio = rp_pac::SIO; 63 let sio = rp_pac::SIO;
66 if unsafe { !sio.div().csr().read().dirty() } { 64 if !sio.div().csr().read().dirty() {
67 // Not dirty, so nothing is waiting for the calculation. So we can just 65 // Not dirty, so nothing is waiting for the calculation. So we can just
68 // issue it directly without a save/restore. 66 // issue it directly without a save/restore.
69 f() 67 f()
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index da8efba91..ce0d02557 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -3,10 +3,10 @@ use core::future::Future;
3use core::pin::Pin as FuturePin; 3use core::pin::Pin as FuturePin;
4use core::task::{Context, Poll}; 4use core::task::{Context, Poll};
5 5
6use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
7use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 6use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9 8
9use crate::interrupt::InterruptExt;
10use crate::pac::common::{Reg, RW}; 10use crate::pac::common::{Reg, RW};
11use crate::pac::SIO; 11use crate::pac::SIO;
12use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; 12use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
@@ -31,9 +31,9 @@ impl From<bool> for Level {
31 } 31 }
32} 32}
33 33
34impl Into<bool> for Level { 34impl From<Level> for bool {
35 fn into(self) -> bool { 35 fn from(level: Level) -> bool {
36 match self { 36 match level {
37 Level::Low => false, 37 Level::Low => false,
38 Level::High => true, 38 Level::High => true,
39 } 39 }
@@ -137,14 +137,14 @@ pub enum InterruptTrigger {
137} 137}
138 138
139pub(crate) unsafe fn init() { 139pub(crate) unsafe fn init() {
140 let irq = interrupt::IO_IRQ_BANK0::steal(); 140 interrupt::IO_IRQ_BANK0.disable();
141 irq.disable(); 141 interrupt::IO_IRQ_BANK0.set_priority(interrupt::Priority::P3);
142 irq.set_priority(interrupt::Priority::P3); 142 interrupt::IO_IRQ_BANK0.enable();
143 irq.enable();
144} 143}
145 144
145#[cfg(feature = "rt")]
146#[interrupt] 146#[interrupt]
147unsafe fn IO_IRQ_BANK0() { 147fn IO_IRQ_BANK0() {
148 let cpu = SIO.cpuid().read() as usize; 148 let cpu = SIO.cpuid().read() as usize;
149 // There are two sets of interrupt registers, one for cpu0 and one for cpu1 149 // There are two sets of interrupt registers, one for cpu0 and one for cpu1
150 // and here we are selecting the set that belongs to the currently executing 150 // and here we are selecting the set that belongs to the currently executing
@@ -185,47 +185,45 @@ struct InputFuture<'a, T: Pin> {
185impl<'d, T: Pin> InputFuture<'d, T> { 185impl<'d, T: Pin> InputFuture<'d, T> {
186 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { 186 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
187 into_ref!(pin); 187 into_ref!(pin);
188 unsafe { 188 let pin_group = (pin.pin() % 8) as usize;
189 let pin_group = (pin.pin() % 8) as usize; 189 // first, clear the INTR register bits. without this INTR will still
190 // first, clear the INTR register bits. without this INTR will still 190 // contain reports of previous edges, causing the IRQ to fire early
191 // contain reports of previous edges, causing the IRQ to fire early 191 // on stale state. clearing these means that we can only detect edges
192 // on stale state. clearing these means that we can only detect edges 192 // that occur *after* the clear happened, but since both this and the
193 // that occur *after* the clear happened, but since both this and the 193 // alternative are fundamentally racy it's probably fine.
194 // alternative are fundamentally racy it's probably fine. 194 // (the alternative being checking the current level and waiting for
195 // (the alternative being checking the current level and waiting for 195 // its inverse, but that requires reading the current level and thus
196 // its inverse, but that requires reading the current level and thus 196 // missing anything that happened before the level was read.)
197 // missing anything that happened before the level was read.) 197 pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
198 pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { 198 w.set_edge_high(pin_group, true);
199 w.set_edge_high(pin_group, true); 199 w.set_edge_low(pin_group, true);
200 w.set_edge_low(pin_group, true); 200 });
201
202 // Each INTR register is divided into 8 groups, one group for each
203 // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
204 // and EGDE_HIGH.
205 pin.int_proc()
206 .inte((pin.pin() / 8) as usize)
207 .write_set(|w| match level {
208 InterruptTrigger::LevelHigh => {
209 trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
210 w.set_level_high(pin_group, true);
211 }
212 InterruptTrigger::LevelLow => {
213 w.set_level_low(pin_group, true);
214 }
215 InterruptTrigger::EdgeHigh => {
216 w.set_edge_high(pin_group, true);
217 }
218 InterruptTrigger::EdgeLow => {
219 w.set_edge_low(pin_group, true);
220 }
221 InterruptTrigger::AnyEdge => {
222 w.set_edge_high(pin_group, true);
223 w.set_edge_low(pin_group, true);
224 }
201 }); 225 });
202 226
203 // Each INTR register is divided into 8 groups, one group for each
204 // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
205 // and EGDE_HIGH.
206 pin.int_proc()
207 .inte((pin.pin() / 8) as usize)
208 .write_set(|w| match level {
209 InterruptTrigger::LevelHigh => {
210 trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
211 w.set_level_high(pin_group, true);
212 }
213 InterruptTrigger::LevelLow => {
214 w.set_level_low(pin_group, true);
215 }
216 InterruptTrigger::EdgeHigh => {
217 w.set_edge_high(pin_group, true);
218 }
219 InterruptTrigger::EdgeLow => {
220 w.set_edge_low(pin_group, true);
221 }
222 InterruptTrigger::AnyEdge => {
223 w.set_edge_high(pin_group, true);
224 w.set_edge_low(pin_group, true);
225 }
226 });
227 }
228
229 Self { pin, level } 227 Self { pin, level }
230 } 228 }
231} 229}
@@ -242,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
242 // then we want to access the interrupt enable register for our 240 // then we want to access the interrupt enable register for our
243 // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and 241 // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
244 // PROC0_INTE3 per cpu). 242 // PROC0_INTE3 per cpu).
245 let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() }; 243 let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read();
246 // The register is divided into groups of four, one group for 244 // The register is divided into groups of four, one group for
247 // each pin. Each group consists of four trigger levels LEVEL_LOW, 245 // each pin. Each group consists of four trigger levels LEVEL_LOW,
248 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. 246 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
@@ -449,15 +447,13 @@ impl<'d, T: Pin> Flex<'d, T> {
449 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 447 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
450 into_ref!(pin); 448 into_ref!(pin);
451 449
452 unsafe { 450 pin.pad_ctrl().write(|w| {
453 pin.pad_ctrl().write(|w| { 451 w.set_ie(true);
454 w.set_ie(true); 452 });
455 });
456 453
457 pin.io().ctrl().write(|w| { 454 pin.io().ctrl().write(|w| {
458 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); 455 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
459 }); 456 });
460 }
461 457
462 Self { pin } 458 Self { pin }
463 } 459 }
@@ -470,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> {
470 /// Set the pin's pull. 466 /// Set the pin's pull.
471 #[inline] 467 #[inline]
472 pub fn set_pull(&mut self, pull: Pull) { 468 pub fn set_pull(&mut self, pull: Pull) {
473 unsafe { 469 self.pin.pad_ctrl().modify(|w| {
474 self.pin.pad_ctrl().modify(|w| { 470 w.set_ie(true);
475 w.set_ie(true); 471 let (pu, pd) = match pull {
476 let (pu, pd) = match pull { 472 Pull::Up => (true, false),
477 Pull::Up => (true, false), 473 Pull::Down => (false, true),
478 Pull::Down => (false, true), 474 Pull::None => (false, false),
479 Pull::None => (false, false), 475 };
480 }; 476 w.set_pue(pu);
481 w.set_pue(pu); 477 w.set_pde(pd);
482 w.set_pde(pd); 478 });
483 });
484 }
485 } 479 }
486 480
487 /// Set the pin's drive strength. 481 /// Set the pin's drive strength.
488 #[inline] 482 #[inline]
489 pub fn set_drive_strength(&mut self, strength: Drive) { 483 pub fn set_drive_strength(&mut self, strength: Drive) {
490 unsafe { 484 self.pin.pad_ctrl().modify(|w| {
491 self.pin.pad_ctrl().modify(|w| { 485 w.set_drive(match strength {
492 w.set_drive(match strength { 486 Drive::_2mA => pac::pads::vals::Drive::_2MA,
493 Drive::_2mA => pac::pads::vals::Drive::_2MA, 487 Drive::_4mA => pac::pads::vals::Drive::_4MA,
494 Drive::_4mA => pac::pads::vals::Drive::_4MA, 488 Drive::_8mA => pac::pads::vals::Drive::_8MA,
495 Drive::_8mA => pac::pads::vals::Drive::_8MA, 489 Drive::_12mA => pac::pads::vals::Drive::_12MA,
496 Drive::_12mA => pac::pads::vals::Drive::_12MA,
497 });
498 }); 490 });
499 } 491 });
500 } 492 }
501 493
502 // Set the pin's slew rate. 494 // Set the pin's slew rate.
503 #[inline] 495 #[inline]
504 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 496 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
505 unsafe { 497 self.pin.pad_ctrl().modify(|w| {
506 self.pin.pad_ctrl().modify(|w| { 498 w.set_slewfast(slew_rate == SlewRate::Fast);
507 w.set_slewfast(slew_rate == SlewRate::Fast); 499 });
508 });
509 }
510 } 500 }
511 501
512 /// Put the pin into input mode. 502 /// Put the pin into input mode.
@@ -514,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> {
514 /// The pull setting is left unchanged. 504 /// The pull setting is left unchanged.
515 #[inline] 505 #[inline]
516 pub fn set_as_input(&mut self) { 506 pub fn set_as_input(&mut self) {
517 unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) } 507 self.pin.sio_oe().value_clr().write_value(self.bit())
518 } 508 }
519 509
520 /// Put the pin into output mode. 510 /// Put the pin into output mode.
@@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> {
523 /// at a specific level, call `set_high`/`set_low` on the pin first. 513 /// at a specific level, call `set_high`/`set_low` on the pin first.
524 #[inline] 514 #[inline]
525 pub fn set_as_output(&mut self) { 515 pub fn set_as_output(&mut self) {
526 unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) } 516 self.pin.sio_oe().value_set().write_value(self.bit())
527 } 517 }
528 518
529 #[inline] 519 #[inline]
530 fn is_set_as_output(&self) -> bool { 520 fn is_set_as_output(&self) -> bool {
531 unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 } 521 (self.pin.sio_oe().value().read() & self.bit()) != 0
532 } 522 }
533 523
534 #[inline] 524 #[inline]
535 pub fn toggle_set_as_output(&mut self) { 525 pub fn toggle_set_as_output(&mut self) {
536 unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) } 526 self.pin.sio_oe().value_xor().write_value(self.bit())
537 } 527 }
538 528
539 #[inline] 529 #[inline]
@@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> {
543 533
544 #[inline] 534 #[inline]
545 pub fn is_low(&self) -> bool { 535 pub fn is_low(&self) -> bool {
546 unsafe { self.pin.sio_in().read() & self.bit() == 0 } 536 self.pin.sio_in().read() & self.bit() == 0
547 } 537 }
548 538
549 /// Returns current pin level 539 /// Returns current pin level
@@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> {
555 /// Set the output as high. 545 /// Set the output as high.
556 #[inline] 546 #[inline]
557 pub fn set_high(&mut self) { 547 pub fn set_high(&mut self) {
558 unsafe { self.pin.sio_out().value_set().write_value(self.bit()) } 548 self.pin.sio_out().value_set().write_value(self.bit())
559 } 549 }
560 550
561 /// Set the output as low. 551 /// Set the output as low.
562 #[inline] 552 #[inline]
563 pub fn set_low(&mut self) { 553 pub fn set_low(&mut self) {
564 unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) } 554 self.pin.sio_out().value_clr().write_value(self.bit())
565 } 555 }
566 556
567 /// Set the output level. 557 /// Set the output level.
@@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> {
576 /// Is the output level high? 566 /// Is the output level high?
577 #[inline] 567 #[inline]
578 pub fn is_set_high(&self) -> bool { 568 pub fn is_set_high(&self) -> bool {
579 unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 } 569 (self.pin.sio_out().value().read() & self.bit()) == 0
580 } 570 }
581 571
582 /// Is the output level low? 572 /// Is the output level low?
@@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> {
594 /// Toggle pin output 584 /// Toggle pin output
595 #[inline] 585 #[inline]
596 pub fn toggle(&mut self) { 586 pub fn toggle(&mut self) {
597 unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } 587 self.pin.sio_out().value_xor().write_value(self.bit())
598 } 588 }
599 589
600 #[inline] 590 #[inline]
@@ -626,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> {
626impl<'d, T: Pin> Drop for Flex<'d, T> { 616impl<'d, T: Pin> Drop for Flex<'d, T> {
627 #[inline] 617 #[inline]
628 fn drop(&mut self) { 618 fn drop(&mut self) {
629 unsafe { 619 self.pin.pad_ctrl().write(|_| {});
630 self.pin.pad_ctrl().write(|_| {}); 620 self.pin.io().ctrl().write(|w| {
631 self.pin.io().ctrl().write(|w| { 621 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
632 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); 622 });
633 });
634 }
635 } 623 }
636} 624}
637 625
@@ -688,7 +676,7 @@ pub(crate) mod sealed {
688 Bank::Bank0 => crate::pac::IO_BANK0, 676 Bank::Bank0 => crate::pac::IO_BANK0,
689 Bank::Qspi => crate::pac::IO_QSPI, 677 Bank::Qspi => crate::pac::IO_QSPI,
690 }; 678 };
691 let proc = unsafe { SIO.cpuid().read() }; 679 let proc = SIO.cpuid().read();
692 io_block.int_proc(proc as _) 680 io_block.int_proc(proc as _)
693 } 681 }
694 } 682 }
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 6ce77f073..791c64554 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -2,14 +2,14 @@ use core::future;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
6use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8use pac::i2c; 7use pac::i2c;
9 8
10use crate::gpio::sealed::Pin; 9use crate::gpio::sealed::Pin;
11use crate::gpio::AnyPin; 10use crate::gpio::AnyPin;
12use crate::{pac, peripherals, Peripheral}; 11use crate::interrupt::typelevel::{Binding, Interrupt};
12use crate::{interrupt, pac, peripherals, Peripheral};
13 13
14/// I2C error abort reason 14/// I2C error abort reason
15#[derive(Debug)] 15#[derive(Debug)]
@@ -82,14 +82,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
82 82
83 let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); 83 let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
84 84
85 unsafe { 85 let r = T::regs();
86 let i2c = T::regs();
87 86
88 // mask everything initially 87 // mask everything initially
89 i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); 88 r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
90 T::Interrupt::steal().unpend(); 89 T::Interrupt::unpend();
91 T::Interrupt::steal().enable(); 90 unsafe { T::Interrupt::enable() };
92 }
93 91
94 i2c 92 i2c
95 } 93 }
@@ -137,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
137 let last = remaining_queue == 0; 135 let last = remaining_queue == 0;
138 batch += 1; 136 batch += 1;
139 137
140 unsafe { 138 p.ic_data_cmd().write(|w| {
141 p.ic_data_cmd().write(|w| { 139 w.set_restart(restart && remaining_queue == buffer.len() - 1);
142 w.set_restart(restart && remaining_queue == buffer.len() - 1); 140 w.set_stop(last && send_stop);
143 w.set_stop(last && send_stop); 141 w.set_cmd(true);
144 w.set_cmd(true); 142 });
145 });
146 }
147 } 143 }
148 144
149 // We've either run out of txfifo or just plain finished setting up 145 // We've either run out of txfifo or just plain finished setting up
@@ -163,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
163 Poll::Pending 159 Poll::Pending
164 } 160 }
165 }, 161 },
166 |_me| unsafe { 162 |_me| {
167 // Set the read threshold to the number of bytes we're 163 // Set the read threshold to the number of bytes we're
168 // expecting so we don't get spurious interrupts. 164 // expecting so we don't get spurious interrupts.
169 p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); 165 p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
@@ -187,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
187 let rxbytes = (rxfifo as usize).min(remaining); 183 let rxbytes = (rxfifo as usize).min(remaining);
188 let received = buffer.len() - remaining; 184 let received = buffer.len() - remaining;
189 for b in &mut buffer[received..received + rxbytes] { 185 for b in &mut buffer[received..received + rxbytes] {
190 *b = unsafe { p.ic_data_cmd().read().dat() }; 186 *b = p.ic_data_cmd().read().dat();
191 } 187 }
192 remaining -= rxbytes; 188 remaining -= rxbytes;
193 } 189 }
@@ -213,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
213 if let Some(byte) = bytes.next() { 209 if let Some(byte) = bytes.next() {
214 let last = bytes.peek().is_none(); 210 let last = bytes.peek().is_none();
215 211
216 unsafe { 212 p.ic_data_cmd().write(|w| {
217 p.ic_data_cmd().write(|w| { 213 w.set_stop(last && send_stop);
218 w.set_stop(last && send_stop); 214 w.set_cmd(false);
219 w.set_cmd(false); 215 w.set_dat(byte);
220 w.set_dat(byte); 216 });
221 });
222 }
223 } else { 217 } else {
224 break 'xmit Ok(()); 218 break 'xmit Ok(());
225 } 219 }
@@ -237,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
237 Poll::Pending 231 Poll::Pending
238 } 232 }
239 }, 233 },
240 |_me| unsafe { 234 |_me| {
241 // Set tx "free" threshold a little high so that we get 235 // Set tx "free" threshold a little high so that we get
242 // woken before the fifo completely drains to minimize 236 // woken before the fifo completely drains to minimize
243 // transfer stalls. 237 // transfer stalls.
@@ -269,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
269 263
270 let had_abort2 = self 264 let had_abort2 = self
271 .wait_on( 265 .wait_on(
272 |me| unsafe { 266 |me| {
273 // We could see an abort while processing fifo backlog, 267 // We could see an abort while processing fifo backlog,
274 // so handle it here. 268 // so handle it here.
275 let abort = me.read_and_clear_abort_reason(); 269 let abort = me.read_and_clear_abort_reason();
@@ -281,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
281 Poll::Pending 275 Poll::Pending
282 } 276 }
283 }, 277 },
284 |_me| unsafe { 278 |_me| {
285 p.ic_intr_mask().modify(|w| { 279 p.ic_intr_mask().modify(|w| {
286 w.set_m_stop_det(true); 280 w.set_m_stop_det(true);
287 w.set_m_tx_abrt(true); 281 w.set_m_tx_abrt(true);
@@ -289,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
289 }, 283 },
290 ) 284 )
291 .await; 285 .await;
292 unsafe { 286 p.ic_clr_stop_det().read();
293 p.ic_clr_stop_det().read();
294 }
295 287
296 had_abort.and(had_abort2) 288 had_abort.and(had_abort2)
297 } else { 289 } else {
@@ -314,7 +306,7 @@ pub struct InterruptHandler<T: Instance> {
314 _uart: PhantomData<T>, 306 _uart: PhantomData<T>,
315} 307}
316 308
317impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 309impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
318 // Mask interrupts and wake any task waiting for this interrupt 310 // Mask interrupts and wake any task waiting for this interrupt
319 unsafe fn on_interrupt() { 311 unsafe fn on_interrupt() {
320 let i2c = T::regs(); 312 let i2c = T::regs();
@@ -338,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
338 330
339 let p = T::regs(); 331 let p = T::regs();
340 332
341 unsafe { 333 let reset = T::reset();
342 let reset = T::reset(); 334 crate::reset::reset(reset);
343 crate::reset::reset(reset); 335 crate::reset::unreset_wait(reset);
344 crate::reset::unreset_wait(reset); 336
345 337 p.ic_enable().write(|w| w.set_enable(false));
346 p.ic_enable().write(|w| w.set_enable(false)); 338
347 339 // Select controller mode & speed
348 // Select controller mode & speed 340 p.ic_con().modify(|w| {
349 p.ic_con().modify(|w| { 341 // Always use "fast" mode (<= 400 kHz, works fine for standard
350 // Always use "fast" mode (<= 400 kHz, works fine for standard 342 // mode too)
351 // mode too) 343 w.set_speed(i2c::vals::Speed::FAST);
352 w.set_speed(i2c::vals::Speed::FAST); 344 w.set_master_mode(true);
353 w.set_master_mode(true); 345 w.set_ic_slave_disable(true);
354 w.set_ic_slave_disable(true); 346 w.set_ic_restart_en(true);
355 w.set_ic_restart_en(true); 347 w.set_tx_empty_ctrl(true);
356 w.set_tx_empty_ctrl(true); 348 });
357 }); 349
358 350 // Set FIFO watermarks to 1 to make things simpler. This is encoded
359 // Set FIFO watermarks to 1 to make things simpler. This is encoded 351 // by a register value of 0.
360 // by a register value of 0. 352 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
361 p.ic_tx_tl().write(|w| w.set_tx_tl(0)); 353 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
362 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 354
363 355 // Configure SCL & SDA pins
364 // Configure SCL & SDA pins 356 scl.io().ctrl().write(|w| w.set_funcsel(3));
365 scl.io().ctrl().write(|w| w.set_funcsel(3)); 357 sda.io().ctrl().write(|w| w.set_funcsel(3));
366 sda.io().ctrl().write(|w| w.set_funcsel(3)); 358
367 359 scl.pad_ctrl().write(|w| {
368 scl.pad_ctrl().write(|w| { 360 w.set_schmitt(true);
369 w.set_schmitt(true); 361 w.set_ie(true);
370 w.set_ie(true); 362 w.set_od(false);
371 w.set_od(false); 363 w.set_pue(true);
372 w.set_pue(true); 364 w.set_pde(false);
373 w.set_pde(false); 365 });
374 }); 366 sda.pad_ctrl().write(|w| {
375 sda.pad_ctrl().write(|w| { 367 w.set_schmitt(true);
376 w.set_schmitt(true); 368 w.set_ie(true);
377 w.set_ie(true); 369 w.set_od(false);
378 w.set_od(false); 370 w.set_pue(true);
379 w.set_pue(true); 371 w.set_pde(false);
380 w.set_pde(false); 372 });
381 }); 373
374 // Configure baudrate
375
376 // There are some subtleties to I2C timing which we are completely
377 // ignoring here See:
378 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
379 let clk_base = crate::clocks::clk_peri_freq();
380
381 let period = (clk_base + config.frequency / 2) / config.frequency;
382 let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low
383 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
384
385 // Check for out-of-range divisors:
386 assert!(hcnt <= 0xffff);
387 assert!(lcnt <= 0xffff);
388 assert!(hcnt >= 8);
389 assert!(lcnt >= 8);
390
391 // Per I2C-bus specification a device in standard or fast mode must
392 // internally provide a hold time of at least 300ns for the SDA
393 // signal to bridge the undefined region of the falling edge of SCL.
394 // A smaller hold time of 120ns is used for fast mode plus.
395 let sda_tx_hold_count = if config.frequency < 1_000_000 {
396 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
397 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
398 // fit in uint. Add 1 to avoid division truncation.
399 ((clk_base * 3) / 10_000_000) + 1
400 } else {
401 // fast mode plus requires a clk_base > 32MHz
402 assert!(clk_base >= 32_000_000);
382 403
383 // Configure baudrate 404 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
384 405 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
385 // There are some subtleties to I2C timing which we are completely 406 // fit in uint. Add 1 to avoid division truncation.
386 // ignoring here See: 407 ((clk_base * 3) / 25_000_000) + 1
387 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 408 };
388 let clk_base = crate::clocks::clk_peri_freq(); 409 assert!(sda_tx_hold_count <= lcnt - 2);
389
390 let period = (clk_base + config.frequency / 2) / config.frequency;
391 let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low
392 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
393
394 // Check for out-of-range divisors:
395 assert!(hcnt <= 0xffff);
396 assert!(lcnt <= 0xffff);
397 assert!(hcnt >= 8);
398 assert!(lcnt >= 8);
399
400 // Per I2C-bus specification a device in standard or fast mode must
401 // internally provide a hold time of at least 300ns for the SDA
402 // signal to bridge the undefined region of the falling edge of SCL.
403 // A smaller hold time of 120ns is used for fast mode plus.
404 let sda_tx_hold_count = if config.frequency < 1_000_000 {
405 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
406 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
407 // fit in uint. Add 1 to avoid division truncation.
408 ((clk_base * 3) / 10_000_000) + 1
409 } else {
410 // fast mode plus requires a clk_base > 32MHz
411 assert!(clk_base >= 32_000_000);
412 410
413 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / 411 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
414 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't 412 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
415 // fit in uint. Add 1 to avoid division truncation. 413 p.ic_fs_spklen()
416 ((clk_base * 3) / 25_000_000) + 1 414 .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
417 }; 415 p.ic_sda_hold()
418 assert!(sda_tx_hold_count <= lcnt - 2); 416 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
419 417
420 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); 418 // Enable I2C block
421 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); 419 p.ic_enable().write(|w| w.set_enable(true));
422 p.ic_fs_spklen()
423 .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
424 p.ic_sda_hold()
425 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
426
427 // Enable I2C block
428 p.ic_enable().write(|w| w.set_enable(true));
429 }
430 420
431 Self { phantom: PhantomData } 421 Self { phantom: PhantomData }
432 } 422 }
@@ -441,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
441 } 431 }
442 432
443 let p = T::regs(); 433 let p = T::regs();
444 unsafe { 434 p.ic_enable().write(|w| w.set_enable(false));
445 p.ic_enable().write(|w| w.set_enable(false)); 435 p.ic_tar().write(|w| w.set_ic_tar(addr));
446 p.ic_tar().write(|w| w.set_ic_tar(addr)); 436 p.ic_enable().write(|w| w.set_enable(true));
447 p.ic_enable().write(|w| w.set_enable(true));
448 }
449 Ok(()) 437 Ok(())
450 } 438 }
451 439
@@ -457,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
457 #[inline] 445 #[inline]
458 fn tx_fifo_capacity() -> u8 { 446 fn tx_fifo_capacity() -> u8 {
459 let p = T::regs(); 447 let p = T::regs();
460 unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } 448 FIFO_SIZE - p.ic_txflr().read().txflr()
461 } 449 }
462 450
463 #[inline] 451 #[inline]
464 fn rx_fifo_len() -> u8 { 452 fn rx_fifo_len() -> u8 {
465 let p = T::regs(); 453 let p = T::regs();
466 unsafe { p.ic_rxflr().read().rxflr() } 454 p.ic_rxflr().read().rxflr()
467 } 455 }
468 456
469 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { 457 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
470 let p = T::regs(); 458 let p = T::regs();
471 unsafe { 459 let abort_reason = p.ic_tx_abrt_source().read();
472 let abort_reason = p.ic_tx_abrt_source().read(); 460 if abort_reason.0 != 0 {
473 if abort_reason.0 != 0 { 461 // Note clearing the abort flag also clears the reason, and this
474 // Note clearing the abort flag also clears the reason, and this 462 // instance of flag is clear-on-read! Note also the
475 // instance of flag is clear-on-read! Note also the 463 // IC_CLR_TX_ABRT register always reads as 0.
476 // IC_CLR_TX_ABRT register always reads as 0. 464 p.ic_clr_tx_abrt().read();
477 p.ic_clr_tx_abrt().read(); 465
478 466 let reason = if abort_reason.abrt_7b_addr_noack()
479 let reason = if abort_reason.abrt_7b_addr_noack() 467 | abort_reason.abrt_10addr1_noack()
480 | abort_reason.abrt_10addr1_noack() 468 | abort_reason.abrt_10addr2_noack()
481 | abort_reason.abrt_10addr2_noack() 469 {
482 { 470 AbortReason::NoAcknowledge
483 AbortReason::NoAcknowledge 471 } else if abort_reason.arb_lost() {
484 } else if abort_reason.arb_lost() { 472 AbortReason::ArbitrationLoss
485 AbortReason::ArbitrationLoss
486 } else {
487 AbortReason::Other(abort_reason.0)
488 };
489
490 Err(Error::Abort(reason))
491 } else { 473 } else {
492 Ok(()) 474 AbortReason::Other(abort_reason.0)
493 } 475 };
476
477 Err(Error::Abort(reason))
478 } else {
479 Ok(())
494 } 480 }
495 } 481 }
496 482
@@ -505,24 +491,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
505 let first = i == 0; 491 let first = i == 0;
506 let last = i == lastindex; 492 let last = i == lastindex;
507 493
508 // NOTE(unsafe) We have &mut self 494 // wait until there is space in the FIFO to write the next byte
509 unsafe { 495 while Self::tx_fifo_full() {}
510 // wait until there is space in the FIFO to write the next byte
511 while Self::tx_fifo_full() {}
512 496
513 p.ic_data_cmd().write(|w| { 497 p.ic_data_cmd().write(|w| {
514 w.set_restart(restart && first); 498 w.set_restart(restart && first);
515 w.set_stop(send_stop && last); 499 w.set_stop(send_stop && last);
516 500
517 w.set_cmd(true); 501 w.set_cmd(true);
518 }); 502 });
519
520 while Self::rx_fifo_len() == 0 {
521 self.read_and_clear_abort_reason()?;
522 }
523 503
524 *byte = p.ic_data_cmd().read().dat(); 504 while Self::rx_fifo_len() == 0 {
505 self.read_and_clear_abort_reason()?;
525 } 506 }
507
508 *byte = p.ic_data_cmd().read().dat();
526 } 509 }
527 510
528 Ok(()) 511 Ok(())
@@ -538,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
538 for (i, byte) in write.iter().enumerate() { 521 for (i, byte) in write.iter().enumerate() {
539 let last = i == write.len() - 1; 522 let last = i == write.len() - 1;
540 523
541 // NOTE(unsafe) We have &mut self 524 p.ic_data_cmd().write(|w| {
542 unsafe { 525 w.set_stop(send_stop && last);
543 p.ic_data_cmd().write(|w| { 526 w.set_dat(*byte);
544 w.set_stop(send_stop && last); 527 });
545 w.set_dat(*byte);
546 });
547
548 // Wait until the transmission of the address/data from the
549 // internal shift register has completed. For this to function
550 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
551 // TX_EMPTY_CTRL flag was set in i2c_init.
552 while !p.ic_raw_intr_stat().read().tx_empty() {}
553 528
554 let abort_reason = self.read_and_clear_abort_reason(); 529 // Wait until the transmission of the address/data from the
530 // internal shift register has completed. For this to function
531 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
532 // TX_EMPTY_CTRL flag was set in i2c_init.
533 while !p.ic_raw_intr_stat().read().tx_empty() {}
555 534
556 if abort_reason.is_err() || (send_stop && last) { 535 let abort_reason = self.read_and_clear_abort_reason();
557 // If the transaction was aborted or if it completed
558 // successfully wait until the STOP condition has occurred.
559 536
560 while !p.ic_raw_intr_stat().read().stop_det() {} 537 if abort_reason.is_err() || (send_stop && last) {
538 // If the transaction was aborted or if it completed
539 // successfully wait until the STOP condition has occurred.
561 540
562 p.ic_clr_stop_det().read().clr_stop_det(); 541 while !p.ic_raw_intr_stat().read().stop_det() {}
563 }
564 542
565 // Note the hardware issues a STOP automatically on an abort 543 p.ic_clr_stop_det().read().clr_stop_det();
566 // condition. Note also the hardware clears RX FIFO as well as
567 // TX on abort, ecause we set hwparam
568 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
569 abort_reason?;
570 } 544 }
545
546 // Note the hardware issues a STOP automatically on an abort
547 // condition. Note also the hardware clears RX FIFO as well as
548 // TX on abort, ecause we set hwparam
549 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
550 abort_reason?;
571 } 551 }
572 Ok(()) 552 Ok(())
573 } 553 }
@@ -762,14 +742,15 @@ fn i2c_reserved_addr(addr: u16) -> bool {
762} 742}
763 743
764mod sealed { 744mod sealed {
765 use embassy_cortex_m::interrupt::Interrupt;
766 use embassy_sync::waitqueue::AtomicWaker; 745 use embassy_sync::waitqueue::AtomicWaker;
767 746
747 use crate::interrupt;
748
768 pub trait Instance { 749 pub trait Instance {
769 const TX_DREQ: u8; 750 const TX_DREQ: u8;
770 const RX_DREQ: u8; 751 const RX_DREQ: u8;
771 752
772 type Interrupt: Interrupt; 753 type Interrupt: interrupt::typelevel::Interrupt;
773 754
774 fn regs() -> crate::pac::i2c::I2c; 755 fn regs() -> crate::pac::i2c::I2c;
775 fn reset() -> crate::pac::resets::regs::Peripherals; 756 fn reset() -> crate::pac::resets::regs::Peripherals;
@@ -805,7 +786,7 @@ macro_rules! impl_instance {
805 const TX_DREQ: u8 = $tx_dreq; 786 const TX_DREQ: u8 = $tx_dreq;
806 const RX_DREQ: u8 = $rx_dreq; 787 const RX_DREQ: u8 = $rx_dreq;
807 788
808 type Interrupt = crate::interrupt::$irq; 789 type Interrupt = crate::interrupt::typelevel::$irq;
809 790
810 #[inline] 791 #[inline]
811 fn regs() -> pac::i2c::I2c { 792 fn regs() -> pac::i2c::I2c {
diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs
deleted file mode 100644
index 1db13deef..000000000
--- a/embassy-rp/src/interrupt.rs
+++ /dev/null
@@ -1,65 +0,0 @@
1//! Interrupt definitions and macros to bind them.
2pub use cortex_m::interrupt::{CriticalSection, Mutex};
3use embassy_cortex_m::interrupt::_export::declare;
4pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
5
6use crate::pac::Interrupt as InterruptEnum;
7declare!(TIMER_IRQ_0);
8declare!(TIMER_IRQ_1);
9declare!(TIMER_IRQ_2);
10declare!(TIMER_IRQ_3);
11declare!(PWM_IRQ_WRAP);
12declare!(USBCTRL_IRQ);
13declare!(XIP_IRQ);
14declare!(PIO0_IRQ_0);
15declare!(PIO0_IRQ_1);
16declare!(PIO1_IRQ_0);
17declare!(PIO1_IRQ_1);
18declare!(DMA_IRQ_0);
19declare!(DMA_IRQ_1);
20declare!(IO_IRQ_BANK0);
21declare!(IO_IRQ_QSPI);
22declare!(SIO_IRQ_PROC0);
23declare!(SIO_IRQ_PROC1);
24declare!(CLOCKS_IRQ);
25declare!(SPI0_IRQ);
26declare!(SPI1_IRQ);
27declare!(UART0_IRQ);
28declare!(UART1_IRQ);
29declare!(ADC_IRQ_FIFO);
30declare!(I2C0_IRQ);
31declare!(I2C1_IRQ);
32declare!(RTC_IRQ);
33declare!(SWI_IRQ_0);
34declare!(SWI_IRQ_1);
35declare!(SWI_IRQ_2);
36declare!(SWI_IRQ_3);
37declare!(SWI_IRQ_4);
38declare!(SWI_IRQ_5);
39
40/// Macro to bind interrupts to handlers.
41///
42/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
43/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
44/// prove at compile-time that the right interrupts have been bound.
45// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
46#[macro_export]
47macro_rules! bind_interrupts {
48 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
49 $vis struct $name;
50
51 $(
52 #[allow(non_snake_case)]
53 #[no_mangle]
54 unsafe extern "C" fn $irq() {
55 $(
56 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
57 )*
58 }
59
60 $(
61 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
62 )*
63 )*
64 };
65}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 4e4542d70..4fd3cb46a 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -16,7 +16,6 @@ pub mod flash;
16mod float; 16mod float;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c; 18pub mod i2c;
19pub mod interrupt;
20pub mod multicore; 19pub mod multicore;
21pub mod pwm; 20pub mod pwm;
22mod reset; 21mod reset;
@@ -37,14 +36,77 @@ pub mod pio_instr_util;
37pub mod relocate; 36pub mod relocate;
38 37
39// Reexports 38// Reexports
40pub use embassy_cortex_m::executor;
41pub use embassy_cortex_m::interrupt::_export::interrupt;
42pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 39pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
43#[cfg(feature = "unstable-pac")] 40#[cfg(feature = "unstable-pac")]
44pub use rp_pac as pac; 41pub use rp_pac as pac;
45#[cfg(not(feature = "unstable-pac"))] 42#[cfg(not(feature = "unstable-pac"))]
46pub(crate) use rp_pac as pac; 43pub(crate) use rp_pac as pac;
47 44
45#[cfg(feature = "rt")]
46pub use crate::pac::NVIC_PRIO_BITS;
47
48embassy_hal_common::interrupt_mod!(
49 TIMER_IRQ_0,
50 TIMER_IRQ_1,
51 TIMER_IRQ_2,
52 TIMER_IRQ_3,
53 PWM_IRQ_WRAP,
54 USBCTRL_IRQ,
55 XIP_IRQ,
56 PIO0_IRQ_0,
57 PIO0_IRQ_1,
58 PIO1_IRQ_0,
59 PIO1_IRQ_1,
60 DMA_IRQ_0,
61 DMA_IRQ_1,
62 IO_IRQ_BANK0,
63 IO_IRQ_QSPI,
64 SIO_IRQ_PROC0,
65 SIO_IRQ_PROC1,
66 CLOCKS_IRQ,
67 SPI0_IRQ,
68 SPI1_IRQ,
69 UART0_IRQ,
70 UART1_IRQ,
71 ADC_IRQ_FIFO,
72 I2C0_IRQ,
73 I2C1_IRQ,
74 RTC_IRQ,
75 SWI_IRQ_0,
76 SWI_IRQ_1,
77 SWI_IRQ_2,
78 SWI_IRQ_3,
79 SWI_IRQ_4,
80 SWI_IRQ_5,
81);
82
83/// Macro to bind interrupts to handlers.
84///
85/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
86/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
87/// prove at compile-time that the right interrupts have been bound.
88// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
89#[macro_export]
90macro_rules! bind_interrupts {
91 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
92 $vis struct $name;
93
94 $(
95 #[allow(non_snake_case)]
96 #[no_mangle]
97 unsafe extern "C" fn $irq() {
98 $(
99 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
100 )*
101 }
102
103 $(
104 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
105 )*
106 )*
107 };
108}
109
48embassy_hal_common::peripherals! { 110embassy_hal_common::peripherals! {
49 PIN_0, 111 PIN_0,
50 PIN_1, 112 PIN_1,
@@ -199,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals {
199 261
200/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. 262/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
201trait RegExt<T: Copy> { 263trait RegExt<T: Copy> {
202 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 264 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
203 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 265 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
204 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 266 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
205} 267}
206 268
207impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { 269impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
208 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 270 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
209 let mut val = Default::default(); 271 let mut val = Default::default();
210 let res = f(&mut val); 272 let res = f(&mut val);
211 let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T; 273 unsafe {
212 ptr.write_volatile(val); 274 let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
275 ptr.write_volatile(val);
276 }
213 res 277 res
214 } 278 }
215 279
216 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 280 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
217 let mut val = Default::default(); 281 let mut val = Default::default();
218 let res = f(&mut val); 282 let res = f(&mut val);
219 let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T; 283 unsafe {
220 ptr.write_volatile(val); 284 let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
285 ptr.write_volatile(val);
286 }
221 res 287 res
222 } 288 }
223 289
224 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 290 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
225 let mut val = Default::default(); 291 let mut val = Default::default();
226 let res = f(&mut val); 292 let res = f(&mut val);
227 let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T; 293 unsafe {
228 ptr.write_volatile(val); 294 let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
295 ptr.write_volatile(val);
296 }
229 res 297 res
230 } 298 }
231} 299}
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index a13209f74..468e8470a 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -50,7 +50,7 @@
50use core::mem::ManuallyDrop; 50use core::mem::ManuallyDrop;
51use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; 51use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
52 52
53use crate::interrupt::{Interrupt, InterruptExt}; 53use crate::interrupt::InterruptExt;
54use crate::peripherals::CORE1; 54use crate::peripherals::CORE1;
55use crate::{gpio, interrupt, pac}; 55use crate::{gpio, interrupt, pac};
56 56
@@ -106,6 +106,7 @@ impl<const SIZE: usize> Stack<SIZE> {
106 } 106 }
107} 107}
108 108
109#[cfg(feature = "rt")]
109#[interrupt] 110#[interrupt]
110#[link_section = ".data.ram_func"] 111#[link_section = ".data.ram_func"]
111unsafe fn SIO_IRQ_PROC1() { 112unsafe fn SIO_IRQ_PROC1() {
@@ -156,21 +157,18 @@ where
156 157
157 IS_CORE1_INIT.store(true, Ordering::Release); 158 IS_CORE1_INIT.store(true, Ordering::Release);
158 // Enable fifo interrupt on CORE1 for `pause` functionality. 159 // Enable fifo interrupt on CORE1 for `pause` functionality.
159 let irq = unsafe { interrupt::SIO_IRQ_PROC1::steal() }; 160 unsafe { interrupt::SIO_IRQ_PROC1.enable() };
160 irq.enable();
161 161
162 entry() 162 entry()
163 } 163 }
164 164
165 // Reset the core 165 // Reset the core
166 unsafe { 166 let psm = pac::PSM;
167 let psm = pac::PSM; 167 psm.frce_off().modify(|w| w.set_proc1(true));
168 psm.frce_off().modify(|w| w.set_proc1(true)); 168 while !psm.frce_off().read().proc1() {
169 while !psm.frce_off().read().proc1() { 169 cortex_m::asm::nop();
170 cortex_m::asm::nop();
171 }
172 psm.frce_off().modify(|w| w.set_proc1(false));
173 } 170 }
171 psm.frce_off().modify(|w| w.set_proc1(false));
174 172
175 // The ARM AAPCS ABI requires 8-byte stack alignment. 173 // The ARM AAPCS ABI requires 8-byte stack alignment.
176 // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be 174 // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be
@@ -270,14 +268,12 @@ pub fn resume_core1() {
270// Push a value to the inter-core FIFO, block until space is available 268// Push a value to the inter-core FIFO, block until space is available
271#[inline(always)] 269#[inline(always)]
272fn fifo_write(value: u32) { 270fn fifo_write(value: u32) {
273 unsafe { 271 let sio = pac::SIO;
274 let sio = pac::SIO; 272 // Wait for the FIFO to have enough space
275 // Wait for the FIFO to have enough space 273 while !sio.fifo().st().read().rdy() {
276 while !sio.fifo().st().read().rdy() { 274 cortex_m::asm::nop();
277 cortex_m::asm::nop();
278 }
279 sio.fifo().wr().write_value(value);
280 } 275 }
276 sio.fifo().wr().write_value(value);
281 // Fire off an event to the other core. 277 // Fire off an event to the other core.
282 // This is required as the other core may be `wfe` (waiting for event) 278 // This is required as the other core may be `wfe` (waiting for event)
283 cortex_m::asm::sev(); 279 cortex_m::asm::sev();
@@ -286,37 +282,32 @@ fn fifo_write(value: u32) {
286// Pop a value from inter-core FIFO, block until available 282// Pop a value from inter-core FIFO, block until available
287#[inline(always)] 283#[inline(always)]
288fn fifo_read() -> u32 { 284fn fifo_read() -> u32 {
289 unsafe { 285 let sio = pac::SIO;
290 let sio = pac::SIO; 286 // Wait until FIFO has data
291 // Wait until FIFO has data 287 while !sio.fifo().st().read().vld() {
292 while !sio.fifo().st().read().vld() { 288 cortex_m::asm::nop();
293 cortex_m::asm::nop();
294 }
295 sio.fifo().rd().read()
296 } 289 }
290 sio.fifo().rd().read()
297} 291}
298 292
299// Pop a value from inter-core FIFO, `wfe` until available 293// Pop a value from inter-core FIFO, `wfe` until available
300#[inline(always)] 294#[inline(always)]
295#[allow(unused)]
301fn fifo_read_wfe() -> u32 { 296fn fifo_read_wfe() -> u32 {
302 unsafe { 297 let sio = pac::SIO;
303 let sio = pac::SIO; 298 // Wait until FIFO has data
304 // Wait until FIFO has data 299 while !sio.fifo().st().read().vld() {
305 while !sio.fifo().st().read().vld() { 300 cortex_m::asm::wfe();
306 cortex_m::asm::wfe();
307 }
308 sio.fifo().rd().read()
309 } 301 }
302 sio.fifo().rd().read()
310} 303}
311 304
312// Drain inter-core FIFO 305// Drain inter-core FIFO
313#[inline(always)] 306#[inline(always)]
314fn fifo_drain() { 307fn fifo_drain() {
315 unsafe { 308 let sio = pac::SIO;
316 let sio = pac::SIO; 309 while sio.fifo().st().read().vld() {
317 while sio.fifo().st().read().vld() { 310 let _ = sio.fifo().rd().read();
318 let _ = sio.fifo().rd().read();
319 }
320 } 311 }
321} 312}
322 313
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index cbe45334a..1b36e0a54 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use atomic_polyfill::{AtomicU32, AtomicU8}; 7use atomic_polyfill::{AtomicU32, AtomicU8};
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11use fixed::types::extra::U8; 10use fixed::types::extra::U8;
@@ -17,6 +16,7 @@ use pio::{SideSet, Wrap};
17use crate::dma::{Channel, Transfer, Word}; 16use crate::dma::{Channel, Transfer, Word};
18use crate::gpio::sealed::Pin as SealedPin; 17use crate::gpio::sealed::Pin as SealedPin;
19use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; 18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
19use crate::interrupt::InterruptExt;
20use crate::pac::dma::vals::TreqSel; 20use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 21use crate::relocate::RelocatedProgram;
22use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt}; 22use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
@@ -85,8 +85,9 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
85const TXNFULL_MASK: u32 = 1 << 4; 85const TXNFULL_MASK: u32 = 1 << 4;
86const SMIRQ_MASK: u32 = 1 << 8; 86const SMIRQ_MASK: u32 = 1 << 8;
87 87
88#[cfg(feature = "rt")]
88#[interrupt] 89#[interrupt]
89unsafe fn PIO0_IRQ_0() { 90fn PIO0_IRQ_0() {
90 use crate::pac; 91 use crate::pac;
91 let ints = pac::PIO0.irqs(0).ints().read().0; 92 let ints = pac::PIO0.irqs(0).ints().read().0;
92 for bit in 0..12 { 93 for bit in 0..12 {
@@ -97,8 +98,9 @@ unsafe fn PIO0_IRQ_0() {
97 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints); 98 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
98} 99}
99 100
101#[cfg(feature = "rt")]
100#[interrupt] 102#[interrupt]
101unsafe fn PIO1_IRQ_0() { 103fn PIO1_IRQ_0() {
102 use crate::pac; 104 use crate::pac;
103 let ints = pac::PIO1.irqs(0).ints().read().0; 105 let ints = pac::PIO1.irqs(0).ints().read().0;
104 for bit in 0..12 { 106 for bit in 0..12 {
@@ -110,17 +112,15 @@ unsafe fn PIO1_IRQ_0() {
110} 112}
111 113
112pub(crate) unsafe fn init() { 114pub(crate) unsafe fn init() {
113 let irq = interrupt::PIO0_IRQ_0::steal(); 115 interrupt::PIO0_IRQ_0.disable();
114 irq.disable(); 116 interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
115 irq.set_priority(interrupt::Priority::P3);
116 pac::PIO0.irqs(0).inte().write(|m| m.0 = 0); 117 pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
117 irq.enable(); 118 interrupt::PIO0_IRQ_0.enable();
118 119
119 let irq = interrupt::PIO1_IRQ_0::steal(); 120 interrupt::PIO1_IRQ_0.disable();
120 irq.disable(); 121 interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
121 irq.set_priority(interrupt::Priority::P3);
122 pac::PIO1.irqs(0).inte().write(|m| m.0 = 0); 122 pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
123 irq.enable(); 123 interrupt::PIO1_IRQ_0.enable();
124} 124}
125 125
126/// Future that waits for TX-FIFO to become writable 126/// Future that waits for TX-FIFO to become writable
@@ -145,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
145 Poll::Ready(()) 145 Poll::Ready(())
146 } else { 146 } else {
147 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); 147 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
148 unsafe { 148 PIO::PIO.irqs(0).inte().write_set(|m| {
149 PIO::PIO.irqs(0).inte().write_set(|m| { 149 m.0 = TXNFULL_MASK << SM;
150 m.0 = TXNFULL_MASK << SM; 150 });
151 });
152 }
153 // debug!("Pending"); 151 // debug!("Pending");
154 Poll::Pending 152 Poll::Pending
155 } 153 }
@@ -158,11 +156,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
158 156
159impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { 157impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
160 fn drop(&mut self) { 158 fn drop(&mut self) {
161 unsafe { 159 PIO::PIO.irqs(0).inte().write_clear(|m| {
162 PIO::PIO.irqs(0).inte().write_clear(|m| { 160 m.0 = TXNFULL_MASK << SM;
163 m.0 = TXNFULL_MASK << SM; 161 });
164 });
165 }
166 } 162 }
167} 163}
168 164
@@ -186,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
186 Poll::Ready(v) 182 Poll::Ready(v)
187 } else { 183 } else {
188 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); 184 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
189 unsafe { 185 PIO::PIO.irqs(0).inte().write_set(|m| {
190 PIO::PIO.irqs(0).inte().write_set(|m| { 186 m.0 = RXNEMPTY_MASK << SM;
191 m.0 = RXNEMPTY_MASK << SM; 187 });
192 });
193 }
194 //debug!("Pending"); 188 //debug!("Pending");
195 Poll::Pending 189 Poll::Pending
196 } 190 }
@@ -199,11 +193,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
199 193
200impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { 194impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
201 fn drop(&mut self) { 195 fn drop(&mut self) {
202 unsafe { 196 PIO::PIO.irqs(0).inte().write_clear(|m| {
203 PIO::PIO.irqs(0).inte().write_clear(|m| { 197 m.0 = RXNEMPTY_MASK << SM;
204 m.0 = RXNEMPTY_MASK << SM; 198 });
205 });
206 }
207 } 199 }
208} 200}
209 201
@@ -220,30 +212,24 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
220 //debug!("Poll {},{}", PIO::PIO_NO, SM); 212 //debug!("Poll {},{}", PIO::PIO_NO, SM);
221 213
222 // Check if IRQ flag is already set 214 // Check if IRQ flag is already set
223 if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } { 215 if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 {
224 unsafe { 216 PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
225 PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
226 }
227 return Poll::Ready(()); 217 return Poll::Ready(());
228 } 218 }
229 219
230 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); 220 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
231 unsafe { 221 PIO::PIO.irqs(0).inte().write_set(|m| {
232 PIO::PIO.irqs(0).inte().write_set(|m| { 222 m.0 = SMIRQ_MASK << self.irq_no;
233 m.0 = SMIRQ_MASK << self.irq_no; 223 });
234 });
235 }
236 Poll::Pending 224 Poll::Pending
237 } 225 }
238} 226}
239 227
240impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { 228impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
241 fn drop(&mut self) { 229 fn drop(&mut self) {
242 unsafe { 230 PIO::PIO.irqs(0).inte().write_clear(|m| {
243 PIO::PIO.irqs(0).inte().write_clear(|m| { 231 m.0 = SMIRQ_MASK << self.irq_no;
244 m.0 = SMIRQ_MASK << self.irq_no; 232 });
245 });
246 }
247 } 233 }
248} 234}
249 235
@@ -256,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
256 /// Set the pin's drive strength. 242 /// Set the pin's drive strength.
257 #[inline] 243 #[inline]
258 pub fn set_drive_strength(&mut self, strength: Drive) { 244 pub fn set_drive_strength(&mut self, strength: Drive) {
259 unsafe { 245 self.pin.pad_ctrl().modify(|w| {
260 self.pin.pad_ctrl().modify(|w| { 246 w.set_drive(match strength {
261 w.set_drive(match strength { 247 Drive::_2mA => pac::pads::vals::Drive::_2MA,
262 Drive::_2mA => pac::pads::vals::Drive::_2MA, 248 Drive::_4mA => pac::pads::vals::Drive::_4MA,
263 Drive::_4mA => pac::pads::vals::Drive::_4MA, 249 Drive::_8mA => pac::pads::vals::Drive::_8MA,
264 Drive::_8mA => pac::pads::vals::Drive::_8MA, 250 Drive::_12mA => pac::pads::vals::Drive::_12MA,
265 Drive::_12mA => pac::pads::vals::Drive::_12MA,
266 });
267 }); 251 });
268 } 252 });
269 } 253 }
270 254
271 // Set the pin's slew rate. 255 // Set the pin's slew rate.
272 #[inline] 256 #[inline]
273 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 257 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
274 unsafe { 258 self.pin.pad_ctrl().modify(|w| {
275 self.pin.pad_ctrl().modify(|w| { 259 w.set_slewfast(slew_rate == SlewRate::Fast);
276 w.set_slewfast(slew_rate == SlewRate::Fast); 260 });
277 });
278 }
279 } 261 }
280 262
281 /// Set the pin's pull. 263 /// Set the pin's pull.
282 #[inline] 264 #[inline]
283 pub fn set_pull(&mut self, pull: Pull) { 265 pub fn set_pull(&mut self, pull: Pull) {
284 unsafe { 266 self.pin.pad_ctrl().modify(|w| {
285 self.pin.pad_ctrl().modify(|w| { 267 w.set_pue(pull == Pull::Up);
286 w.set_pue(pull == Pull::Up); 268 w.set_pde(pull == Pull::Down);
287 w.set_pde(pull == Pull::Down); 269 });
288 });
289 }
290 } 270 }
291 271
292 /// Set the pin's schmitt trigger. 272 /// Set the pin's schmitt trigger.
293 #[inline] 273 #[inline]
294 pub fn set_schmitt(&mut self, enable: bool) { 274 pub fn set_schmitt(&mut self, enable: bool) {
295 unsafe { 275 self.pin.pad_ctrl().modify(|w| {
296 self.pin.pad_ctrl().modify(|w| { 276 w.set_schmitt(enable);
297 w.set_schmitt(enable); 277 });
298 });
299 }
300 } 278 }
301 279
302 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { 280 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
303 let mask = 1 << self.pin(); 281 let mask = 1 << self.pin();
304 unsafe { 282 if bypass {
305 if bypass { 283 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
306 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); 284 } else {
307 } else { 285 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
308 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
309 }
310 } 286 }
311 } 287 }
312 288
@@ -321,41 +297,37 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
321 297
322impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { 298impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
323 pub fn empty(&self) -> bool { 299 pub fn empty(&self) -> bool {
324 unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } 300 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
325 } 301 }
326 302
327 pub fn full(&self) -> bool { 303 pub fn full(&self) -> bool {
328 unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } 304 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
329 } 305 }
330 306
331 pub fn level(&self) -> u8 { 307 pub fn level(&self) -> u8 {
332 unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } 308 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
333 } 309 }
334 310
335 pub fn stalled(&self) -> bool { 311 pub fn stalled(&self) -> bool {
336 unsafe { 312 let fdebug = PIO::PIO.fdebug();
337 let fdebug = PIO::PIO.fdebug(); 313 let ret = fdebug.read().rxstall() & (1 << SM) != 0;
338 let ret = fdebug.read().rxstall() & (1 << SM) != 0; 314 if ret {
339 if ret { 315 fdebug.write(|w| w.set_rxstall(1 << SM));
340 fdebug.write(|w| w.set_rxstall(1 << SM));
341 }
342 ret
343 } 316 }
317 ret
344 } 318 }
345 319
346 pub fn underflowed(&self) -> bool { 320 pub fn underflowed(&self) -> bool {
347 unsafe { 321 let fdebug = PIO::PIO.fdebug();
348 let fdebug = PIO::PIO.fdebug(); 322 let ret = fdebug.read().rxunder() & (1 << SM) != 0;
349 let ret = fdebug.read().rxunder() & (1 << SM) != 0; 323 if ret {
350 if ret { 324 fdebug.write(|w| w.set_rxunder(1 << SM));
351 fdebug.write(|w| w.set_rxunder(1 << SM));
352 }
353 ret
354 } 325 }
326 ret
355 } 327 }
356 328
357 pub fn pull(&mut self) -> u32 { 329 pub fn pull(&mut self) -> u32 {
358 unsafe { PIO::PIO.rxf(SM).read() } 330 PIO::PIO.rxf(SM).read()
359 } 331 }
360 332
361 pub fn try_pull(&mut self) -> Option<u32> { 333 pub fn try_pull(&mut self) -> Option<u32> {
@@ -374,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
374 ch: PeripheralRef<'a, C>, 346 ch: PeripheralRef<'a, C>,
375 data: &'a mut [W], 347 data: &'a mut [W],
376 ) -> Transfer<'a, C> { 348 ) -> Transfer<'a, C> {
377 unsafe { 349 let pio_no = PIO::PIO_NO;
378 let pio_no = PIO::PIO_NO; 350 let p = ch.regs();
379 let p = ch.regs(); 351 p.write_addr().write_value(data.as_ptr() as u32);
380 p.write_addr().write_value(data.as_ptr() as u32); 352 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
381 p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); 353 p.trans_count().write_value(data.len() as u32);
382 p.trans_count().write_value(data.len() as u32); 354 compiler_fence(Ordering::SeqCst);
383 compiler_fence(Ordering::SeqCst); 355 p.ctrl_trig().write(|w| {
384 p.ctrl_trig().write(|w| { 356 // Set RX DREQ for this statemachine
385 // Set RX DREQ for this statemachine 357 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
386 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); 358 w.set_data_size(W::size());
387 w.set_data_size(W::size()); 359 w.set_chain_to(ch.number());
388 w.set_chain_to(ch.number()); 360 w.set_incr_read(false);
389 w.set_incr_read(false); 361 w.set_incr_write(true);
390 w.set_incr_write(true); 362 w.set_en(true);
391 w.set_en(true); 363 });
392 }); 364 compiler_fence(Ordering::SeqCst);
393 compiler_fence(Ordering::SeqCst);
394 }
395 Transfer::new(ch) 365 Transfer::new(ch)
396 } 366 }
397} 367}
@@ -402,42 +372,36 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
402 372
403impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { 373impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
404 pub fn empty(&self) -> bool { 374 pub fn empty(&self) -> bool {
405 unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } 375 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
406 } 376 }
407 pub fn full(&self) -> bool { 377 pub fn full(&self) -> bool {
408 unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } 378 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
409 } 379 }
410 380
411 pub fn level(&self) -> u8 { 381 pub fn level(&self) -> u8 {
412 unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } 382 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
413 } 383 }
414 384
415 pub fn stalled(&self) -> bool { 385 pub fn stalled(&self) -> bool {
416 unsafe { 386 let fdebug = PIO::PIO.fdebug();
417 let fdebug = PIO::PIO.fdebug(); 387 let ret = fdebug.read().txstall() & (1 << SM) != 0;
418 let ret = fdebug.read().txstall() & (1 << SM) != 0; 388 if ret {
419 if ret { 389 fdebug.write(|w| w.set_txstall(1 << SM));
420 fdebug.write(|w| w.set_txstall(1 << SM));
421 }
422 ret
423 } 390 }
391 ret
424 } 392 }
425 393
426 pub fn overflowed(&self) -> bool { 394 pub fn overflowed(&self) -> bool {
427 unsafe { 395 let fdebug = PIO::PIO.fdebug();
428 let fdebug = PIO::PIO.fdebug(); 396 let ret = fdebug.read().txover() & (1 << SM) != 0;
429 let ret = fdebug.read().txover() & (1 << SM) != 0; 397 if ret {
430 if ret { 398 fdebug.write(|w| w.set_txover(1 << SM));
431 fdebug.write(|w| w.set_txover(1 << SM));
432 }
433 ret
434 } 399 }
400 ret
435 } 401 }
436 402
437 pub fn push(&mut self, v: u32) { 403 pub fn push(&mut self, v: u32) {
438 unsafe { 404 PIO::PIO.txf(SM).write_value(v);
439 PIO::PIO.txf(SM).write_value(v);
440 }
441 } 405 }
442 406
443 pub fn try_push(&mut self, v: u32) -> bool { 407 pub fn try_push(&mut self, v: u32) -> bool {
@@ -453,24 +417,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
453 } 417 }
454 418
455 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { 419 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
456 unsafe { 420 let pio_no = PIO::PIO_NO;
457 let pio_no = PIO::PIO_NO; 421 let p = ch.regs();
458 let p = ch.regs(); 422 p.read_addr().write_value(data.as_ptr() as u32);
459 p.read_addr().write_value(data.as_ptr() as u32); 423 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
460 p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); 424 p.trans_count().write_value(data.len() as u32);
461 p.trans_count().write_value(data.len() as u32); 425 compiler_fence(Ordering::SeqCst);
462 compiler_fence(Ordering::SeqCst); 426 p.ctrl_trig().write(|w| {
463 p.ctrl_trig().write(|w| { 427 // Set TX DREQ for this statemachine
464 // Set TX DREQ for this statemachine 428 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
465 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); 429 w.set_data_size(W::size());
466 w.set_data_size(W::size()); 430 w.set_chain_to(ch.number());
467 w.set_chain_to(ch.number()); 431 w.set_incr_read(true);
468 w.set_incr_read(true); 432 w.set_incr_write(false);
469 w.set_incr_write(false); 433 w.set_en(true);
470 w.set_en(true); 434 });
471 }); 435 compiler_fence(Ordering::SeqCst);
472 compiler_fence(Ordering::SeqCst);
473 }
474 Transfer::new(ch) 436 Transfer::new(ch)
475 } 437 }
476} 438}
@@ -482,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
482 444
483impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { 445impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
484 fn drop(&mut self) { 446 fn drop(&mut self) {
485 unsafe { 447 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
486 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
487 }
488 on_pio_drop::<PIO>(); 448 on_pio_drop::<PIO>();
489 } 449 }
490} 450}
@@ -647,45 +607,43 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
647 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); 607 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
648 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); 608 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
649 let sm = Self::this_sm(); 609 let sm = Self::this_sm();
650 unsafe { 610 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
651 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); 611 sm.execctrl().write(|w| {
652 sm.execctrl().write(|w| { 612 w.set_side_en(config.exec.side_en);
653 w.set_side_en(config.exec.side_en); 613 w.set_side_pindir(config.exec.side_pindir);
654 w.set_side_pindir(config.exec.side_pindir); 614 w.set_jmp_pin(config.exec.jmp_pin);
655 w.set_jmp_pin(config.exec.jmp_pin); 615 w.set_out_en_sel(config.out_en_sel);
656 w.set_out_en_sel(config.out_en_sel); 616 w.set_inline_out_en(config.inline_out_en);
657 w.set_inline_out_en(config.inline_out_en); 617 w.set_out_sticky(config.out_sticky);
658 w.set_out_sticky(config.out_sticky); 618 w.set_wrap_top(config.exec.wrap_top);
659 w.set_wrap_top(config.exec.wrap_top); 619 w.set_wrap_bottom(config.exec.wrap_bottom);
660 w.set_wrap_bottom(config.exec.wrap_bottom); 620 w.set_status_sel(match config.status_sel {
661 w.set_status_sel(match config.status_sel { 621 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
662 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, 622 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
663 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
664 });
665 w.set_status_n(config.status_n);
666 });
667 sm.shiftctrl().write(|w| {
668 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
669 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
670 w.set_pull_thresh(config.shift_out.threshold);
671 w.set_push_thresh(config.shift_in.threshold);
672 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
673 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
674 w.set_autopull(config.shift_out.auto_fill);
675 w.set_autopush(config.shift_in.auto_fill);
676 });
677 sm.pinctrl().write(|w| {
678 w.set_sideset_count(config.pins.sideset_count);
679 w.set_set_count(config.pins.set_count);
680 w.set_out_count(config.pins.out_count);
681 w.set_in_base(config.pins.in_base);
682 w.set_sideset_base(config.pins.sideset_base);
683 w.set_set_base(config.pins.set_base);
684 w.set_out_base(config.pins.out_base);
685 }); 623 });
686 if let Some(origin) = config.origin { 624 w.set_status_n(config.status_n);
687 pio_instr_util::exec_jmp(self, origin); 625 });
688 } 626 sm.shiftctrl().write(|w| {
627 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
628 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
629 w.set_pull_thresh(config.shift_out.threshold);
630 w.set_push_thresh(config.shift_in.threshold);
631 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
632 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
633 w.set_autopull(config.shift_out.auto_fill);
634 w.set_autopush(config.shift_in.auto_fill);
635 });
636 sm.pinctrl().write(|w| {
637 w.set_sideset_count(config.pins.sideset_count);
638 w.set_set_count(config.pins.set_count);
639 w.set_out_count(config.pins.out_count);
640 w.set_in_base(config.pins.in_base);
641 w.set_sideset_base(config.pins.sideset_base);
642 w.set_set_base(config.pins.set_base);
643 w.set_out_base(config.pins.out_base);
644 });
645 if let Some(origin) = config.origin {
646 unsafe { pio_instr_util::exec_jmp(self, origin) }
689 } 647 }
690 } 648 }
691 649
@@ -696,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
696 654
697 pub fn restart(&mut self) { 655 pub fn restart(&mut self) {
698 let mask = 1u8 << SM; 656 let mask = 1u8 << SM;
699 unsafe { 657 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
700 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
701 }
702 } 658 }
703 pub fn set_enable(&mut self, enable: bool) { 659 pub fn set_enable(&mut self, enable: bool) {
704 let mask = 1u8 << SM; 660 let mask = 1u8 << SM;
705 unsafe { 661 if enable {
706 if enable { 662 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
707 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); 663 } else {
708 } else { 664 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
709 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
710 }
711 } 665 }
712 } 666 }
713 667
714 pub fn is_enabled(&self) -> bool { 668 pub fn is_enabled(&self) -> bool {
715 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } 669 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
716 } 670 }
717 671
718 pub fn clkdiv_restart(&mut self) { 672 pub fn clkdiv_restart(&mut self) {
719 let mask = 1u8 << SM; 673 let mask = 1u8 << SM;
720 unsafe { 674 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
721 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
722 }
723 } 675 }
724 676
725 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { 677 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
726 let enabled = self.is_enabled(); 678 let enabled = self.is_enabled();
727 self.set_enable(false); 679 self.set_enable(false);
728 let pincfg = unsafe { Self::this_sm().pinctrl().read() }; 680 let pincfg = Self::this_sm().pinctrl().read();
729 let execcfg = unsafe { Self::this_sm().execctrl().read() }; 681 let execcfg = Self::this_sm().execctrl().read();
730 unsafe { 682 Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
731 Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
732 }
733 f(self); 683 f(self);
734 unsafe { 684 Self::this_sm().pinctrl().write_value(pincfg);
735 Self::this_sm().pinctrl().write_value(pincfg); 685 Self::this_sm().execctrl().write_value(execcfg);
736 Self::this_sm().execctrl().write_value(execcfg);
737 }
738 self.set_enable(enabled); 686 self.set_enable(enabled);
739 } 687 }
740 688
@@ -743,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
743 pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { 691 pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
744 self.with_paused(|sm| { 692 self.with_paused(|sm| {
745 for pin in pins { 693 for pin in pins {
746 unsafe { 694 Self::this_sm().pinctrl().write(|w| {
747 Self::this_sm().pinctrl().write(|w| { 695 w.set_set_base(pin.pin());
748 w.set_set_base(pin.pin()); 696 w.set_set_count(1);
749 w.set_set_count(1); 697 });
750 }); 698 // SET PINDIRS, (dir)
751 // SET PINDIRS, (dir) 699 unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) };
752 sm.exec_instr(0b111_00000_100_00000 | dir as u16);
753 }
754 } 700 }
755 }); 701 });
756 } 702 }
@@ -760,29 +706,25 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
760 pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { 706 pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
761 self.with_paused(|sm| { 707 self.with_paused(|sm| {
762 for pin in pins { 708 for pin in pins {
763 unsafe { 709 Self::this_sm().pinctrl().write(|w| {
764 Self::this_sm().pinctrl().write(|w| { 710 w.set_set_base(pin.pin());
765 w.set_set_base(pin.pin()); 711 w.set_set_count(1);
766 w.set_set_count(1); 712 });
767 }); 713 // SET PINS, (dir)
768 // SET PINS, (dir) 714 unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) };
769 sm.exec_instr(0b111_00000_000_00000 | level as u16);
770 }
771 } 715 }
772 }); 716 });
773 } 717 }
774 718
775 pub fn clear_fifos(&mut self) { 719 pub fn clear_fifos(&mut self) {
776 // Toggle FJOIN_RX to flush FIFOs 720 // Toggle FJOIN_RX to flush FIFOs
777 unsafe { 721 let shiftctrl = Self::this_sm().shiftctrl();
778 let shiftctrl = Self::this_sm().shiftctrl(); 722 shiftctrl.modify(|w| {
779 shiftctrl.modify(|w| { 723 w.set_fjoin_rx(!w.fjoin_rx());
780 w.set_fjoin_rx(!w.fjoin_rx()); 724 });
781 }); 725 shiftctrl.modify(|w| {
782 shiftctrl.modify(|w| { 726 w.set_fjoin_rx(!w.fjoin_rx());
783 w.set_fjoin_rx(!w.fjoin_rx()); 727 });
784 });
785 }
786 } 728 }
787 729
788 pub unsafe fn exec_instr(&mut self, instr: u16) { 730 pub unsafe fn exec_instr(&mut self, instr: u16) {
@@ -856,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
856 if (self.instructions_used | used_mask) & mask != 0 { 798 if (self.instructions_used | used_mask) & mask != 0 {
857 return Err(addr); 799 return Err(addr);
858 } 800 }
859 unsafe { 801 PIO::PIO.instr_mem(addr).write(|w| {
860 PIO::PIO.instr_mem(addr).write(|w| { 802 w.set_instr_mem(instr);
861 w.set_instr_mem(instr); 803 });
862 });
863 }
864 used_mask |= mask; 804 used_mask |= mask;
865 } 805 }
866 self.instructions_used |= used_mask; 806 self.instructions_used |= used_mask;
@@ -877,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
877 } 817 }
878 818
879 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { 819 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
880 unsafe { 820 // this can interfere with per-pin bypass functions. splitting the
881 // this can interfere with per-pin bypass functions. splitting the 821 // modification is going to be fine since nothing that relies on
882 // modification is going to be fine since nothing that relies on 822 // it can reasonably run before we finish.
883 // it can reasonably run before we finish. 823 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
884 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); 824 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
885 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
886 }
887 } 825 }
888 826
889 pub fn get_input_sync_bypass(&self) -> u32 { 827 pub fn get_input_sync_bypass(&self) -> u32 {
890 unsafe { PIO::PIO.input_sync_bypass().read() } 828 PIO::PIO.input_sync_bypass().read()
891 } 829 }
892 830
893 /// Register a pin for PIO usage. Pins will be released from the PIO block 831 /// Register a pin for PIO usage. Pins will be released from the PIO block
@@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
896 /// of [`Pio`] do not keep pin registrations alive.** 834 /// of [`Pio`] do not keep pin registrations alive.**
897 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { 835 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
898 into_ref!(pin); 836 into_ref!(pin);
899 unsafe { 837 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
900 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
901 }
902 // we can be relaxed about this because we're &mut here and nothing is cached 838 // we can be relaxed about this because we're &mut here and nothing is cached
903 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); 839 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
904 Pin { 840 Pin {
@@ -916,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
916 _pio: PhantomData, 852 _pio: PhantomData,
917 }; 853 };
918 f(&mut batch); 854 f(&mut batch);
919 unsafe { 855 PIO::PIO.ctrl().modify(|w| {
920 PIO::PIO.ctrl().modify(|w| { 856 w.set_clkdiv_restart(batch.clkdiv_restart);
921 w.set_clkdiv_restart(batch.clkdiv_restart); 857 w.set_sm_restart(batch.sm_restart);
922 w.set_sm_restart(batch.sm_restart); 858 w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
923 w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); 859 });
924 });
925 }
926 } 860 }
927} 861}
928 862
@@ -974,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
974 } 908 }
975 909
976 pub fn check_any(&self, irqs: u8) -> bool { 910 pub fn check_any(&self, irqs: u8) -> bool {
977 unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } 911 PIO::PIO.irq().read().irq() & irqs != 0
978 } 912 }
979 913
980 pub fn check_all(&self, irqs: u8) -> bool { 914 pub fn check_all(&self, irqs: u8) -> bool {
981 unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } 915 PIO::PIO.irq().read().irq() & irqs == irqs
982 } 916 }
983 917
984 pub fn clear(&self, irq_no: usize) { 918 pub fn clear(&self, irq_no: usize) {
@@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
987 } 921 }
988 922
989 pub fn clear_all(&self, irqs: u8) { 923 pub fn clear_all(&self, irqs: u8) {
990 unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } 924 PIO::PIO.irq().write(|w| w.set_irq(irqs))
991 } 925 }
992 926
993 pub fn set(&self, irq_no: usize) { 927 pub fn set(&self, irq_no: usize) {
@@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
996 } 930 }
997 931
998 pub fn set_all(&self, irqs: u8) { 932 pub fn set_all(&self, irqs: u8) {
999 unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } 933 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
1000 } 934 }
1001} 935}
1002 936
@@ -1068,9 +1002,7 @@ fn on_pio_drop<PIO: Instance>() {
1068 // we only have 30 pins. don't test the other two since gpio() asserts. 1002 // we only have 30 pins. don't test the other two since gpio() asserts.
1069 for i in 0..30 { 1003 for i in 0..30 {
1070 if used_pins & (1 << i) != 0 { 1004 if used_pins & (1 << i) != 0 {
1071 unsafe { 1005 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
1072 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
1073 }
1074 } 1006 }
1075 } 1007 }
1076 } 1008 }
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 0f9dcf479..20bb88446 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> {
71 into_ref!(inner); 71 into_ref!(inner);
72 72
73 let p = inner.regs(); 73 let p = inner.regs();
74 unsafe { 74 p.csr().modify(|w| {
75 p.csr().modify(|w| { 75 w.set_divmode(divmode);
76 w.set_divmode(divmode); 76 w.set_en(false);
77 w.set_en(false); 77 });
78 }); 78 p.ctr().write(|w| w.0 = 0);
79 p.ctr().write(|w| w.0 = 0); 79 Self::configure(p, &config);
80 Self::configure(p, &config); 80
81 81 if let Some(pin) = &a {
82 if let Some(pin) = &a { 82 pin.io().ctrl().write(|w| w.set_funcsel(4));
83 pin.io().ctrl().write(|w| w.set_funcsel(4)); 83 }
84 } 84 if let Some(pin) = &b {
85 if let Some(pin) = &b { 85 pin.io().ctrl().write(|w| w.set_funcsel(4));
86 pin.io().ctrl().write(|w| w.set_funcsel(4));
87 }
88 } 86 }
89 Self { 87 Self {
90 inner, 88 inner,
@@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> {
161 panic!("Requested divider is too large"); 159 panic!("Requested divider is too large");
162 } 160 }
163 161
164 unsafe { 162 p.div().write_value(ChDiv(config.divider.to_bits() as u32));
165 p.div().write_value(ChDiv(config.divider.to_bits() as u32)); 163 p.cc().write(|w| {
166 p.cc().write(|w| { 164 w.set_a(config.compare_a);
167 w.set_a(config.compare_a); 165 w.set_b(config.compare_b);
168 w.set_b(config.compare_b); 166 });
169 }); 167 p.top().write(|w| w.set_top(config.top));
170 p.top().write(|w| w.set_top(config.top)); 168 p.csr().modify(|w| {
171 p.csr().modify(|w| { 169 w.set_a_inv(config.invert_a);
172 w.set_a_inv(config.invert_a); 170 w.set_b_inv(config.invert_b);
173 w.set_b_inv(config.invert_b); 171 w.set_ph_correct(config.phase_correct);
174 w.set_ph_correct(config.phase_correct); 172 w.set_en(config.enable);
175 w.set_en(config.enable); 173 });
176 });
177 }
178 } 174 }
179 175
180 #[inline] 176 #[inline]
181 pub unsafe fn phase_advance(&mut self) { 177 pub fn phase_advance(&mut self) {
182 let p = self.inner.regs(); 178 let p = self.inner.regs();
183 p.csr().write_set(|w| w.set_ph_adv(true)); 179 p.csr().write_set(|w| w.set_ph_adv(true));
184 while p.csr().read().ph_adv() {} 180 while p.csr().read().ph_adv() {}
185 } 181 }
186 182
187 #[inline] 183 #[inline]
188 pub unsafe fn phase_retard(&mut self) { 184 pub fn phase_retard(&mut self) {
189 let p = self.inner.regs(); 185 let p = self.inner.regs();
190 p.csr().write_set(|w| w.set_ph_ret(true)); 186 p.csr().write_set(|w| w.set_ph_ret(true));
191 while p.csr().read().ph_ret() {} 187 while p.csr().read().ph_ret() {}
@@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
193 189
194 #[inline] 190 #[inline]
195 pub fn counter(&self) -> u16 { 191 pub fn counter(&self) -> u16 {
196 unsafe { self.inner.regs().ctr().read().ctr() } 192 self.inner.regs().ctr().read().ctr()
197 } 193 }
198 194
199 #[inline] 195 #[inline]
200 pub fn set_counter(&self, ctr: u16) { 196 pub fn set_counter(&self, ctr: u16) {
201 unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } 197 self.inner.regs().ctr().write(|w| w.set_ctr(ctr))
202 } 198 }
203 199
204 #[inline] 200 #[inline]
@@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
209 205
210 #[inline] 206 #[inline]
211 pub fn wrapped(&mut self) -> bool { 207 pub fn wrapped(&mut self) -> bool {
212 unsafe { pac::PWM.intr().read().0 & self.bit() != 0 } 208 pac::PWM.intr().read().0 & self.bit() != 0
213 } 209 }
214 210
215 #[inline] 211 #[inline]
216 pub fn clear_wrapped(&mut self) { 212 pub fn clear_wrapped(&mut self) {
217 unsafe { 213 pac::PWM.intr().write_value(Intr(self.bit() as _));
218 pac::PWM.intr().write_value(Intr(self.bit() as _));
219 }
220 } 214 }
221 215
222 #[inline] 216 #[inline]
@@ -237,26 +231,22 @@ impl PwmBatch {
237 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { 231 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
238 let mut en = PwmBatch(0); 232 let mut en = PwmBatch(0);
239 batch(&mut en); 233 batch(&mut en);
240 unsafe { 234 if enabled {
241 if enabled { 235 pac::PWM.en().write_set(|w| w.0 = en.0);
242 pac::PWM.en().write_set(|w| w.0 = en.0); 236 } else {
243 } else { 237 pac::PWM.en().write_clear(|w| w.0 = en.0);
244 pac::PWM.en().write_clear(|w| w.0 = en.0);
245 }
246 } 238 }
247 } 239 }
248} 240}
249 241
250impl<'d, T: Channel> Drop for Pwm<'d, T> { 242impl<'d, T: Channel> Drop for Pwm<'d, T> {
251 fn drop(&mut self) { 243 fn drop(&mut self) {
252 unsafe { 244 self.inner.regs().csr().write_clear(|w| w.set_en(false));
253 self.inner.regs().csr().write_clear(|w| w.set_en(false)); 245 if let Some(pin) = &self.pin_a {
254 if let Some(pin) = &self.pin_a { 246 pin.io().ctrl().write(|w| w.set_funcsel(31));
255 pin.io().ctrl().write(|w| w.set_funcsel(31)); 247 }
256 } 248 if let Some(pin) = &self.pin_b {
257 if let Some(pin) = &self.pin_b { 249 pin.io().ctrl().write(|w| w.set_funcsel(31));
258 pin.io().ctrl().write(|w| w.set_funcsel(31));
259 }
260 } 250 }
261 } 251 }
262} 252}
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs
index edd47c223..70512fa14 100644
--- a/embassy-rp/src/reset.rs
+++ b/embassy-rp/src/reset.rs
@@ -4,11 +4,11 @@ use crate::pac;
4 4
5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); 5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
6 6
7pub unsafe fn reset(peris: Peripherals) { 7pub(crate) fn reset(peris: Peripherals) {
8 pac::RESETS.reset().write_value(peris); 8 pac::RESETS.reset().write_value(peris);
9} 9}
10 10
11pub unsafe fn unreset_wait(peris: Peripherals) { 11pub(crate) fn unreset_wait(peris: Peripherals) {
12 // TODO use the "atomic clear" register version 12 // TODO use the "atomic clear" register version
13 pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); 13 pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
14 while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} 14 while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index e1d886d4a..b18f12fc4 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
26 into_ref!(inner); 26 into_ref!(inner);
27 27
28 // Set the RTC divider 28 // Set the RTC divider
29 unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; 29 inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
30 30
31 let mut result = Self { inner }; 31 let mut result = Self { inner };
32 result.set_leap_year_check(true); // should be on by default, make sure this is the case. 32 result.set_leap_year_check(true); // should be on by default, make sure this is the case.
@@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
38 /// 38 ///
39 /// Leap year checking is enabled by default. 39 /// Leap year checking is enabled by default.
40 pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { 40 pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
41 unsafe { 41 self.inner.regs().ctrl().modify(|w| {
42 self.inner 42 w.set_force_notleapyear(!leap_year_check_enabled);
43 .regs() 43 });
44 .ctrl()
45 .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
46 };
47 } 44 }
48 45
49 /// Checks to see if this RealTimeClock is running 46 /// Checks to see if this RealTimeClock is running
50 pub fn is_running(&self) -> bool { 47 pub fn is_running(&self) -> bool {
51 unsafe { self.inner.regs().ctrl().read().rtc_active() } 48 self.inner.regs().ctrl().read().rtc_active()
52 } 49 }
53 50
54 /// Set the datetime to a new value. 51 /// Set the datetime to a new value.
@@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
60 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; 57 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
61 58
62 // disable RTC while we configure it 59 // disable RTC while we configure it
63 unsafe { 60 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
64 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); 61 while self.inner.regs().ctrl().read().rtc_active() {
65 while self.inner.regs().ctrl().read().rtc_active() { 62 core::hint::spin_loop();
66 core::hint::spin_loop(); 63 }
67 } 64
68 65 self.inner.regs().setup_0().write(|w| {
69 self.inner.regs().setup_0().write(|w| { 66 self::datetime::write_setup_0(&t, w);
70 self::datetime::write_setup_0(&t, w); 67 });
71 }); 68 self.inner.regs().setup_1().write(|w| {
72 self.inner.regs().setup_1().write(|w| { 69 self::datetime::write_setup_1(&t, w);
73 self::datetime::write_setup_1(&t, w); 70 });
74 }); 71
75 72 // Load the new datetime and re-enable RTC
76 // Load the new datetime and re-enable RTC 73 self.inner.regs().ctrl().write(|w| w.set_load(true));
77 self.inner.regs().ctrl().write(|w| w.set_load(true)); 74 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
78 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); 75 while !self.inner.regs().ctrl().read().rtc_active() {
79 while !self.inner.regs().ctrl().read().rtc_active() { 76 core::hint::spin_loop();
80 core::hint::spin_loop();
81 }
82 } 77 }
83 Ok(()) 78 Ok(())
84 } 79 }
@@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
93 return Err(RtcError::NotRunning); 88 return Err(RtcError::NotRunning);
94 } 89 }
95 90
96 let rtc_0 = unsafe { self.inner.regs().rtc_0().read() }; 91 let rtc_0 = self.inner.regs().rtc_0().read();
97 let rtc_1 = unsafe { self.inner.regs().rtc_1().read() }; 92 let rtc_1 = self.inner.regs().rtc_1().read();
98 93
99 self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) 94 self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
100 } 95 }
@@ -103,12 +98,10 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
103 /// 98 ///
104 /// [`schedule_alarm`]: #method.schedule_alarm 99 /// [`schedule_alarm`]: #method.schedule_alarm
105 pub fn disable_alarm(&mut self) { 100 pub fn disable_alarm(&mut self) {
106 unsafe { 101 self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
107 self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
108 102
109 while self.inner.regs().irq_setup_0().read().match_active() { 103 while self.inner.regs().irq_setup_0().read().match_active() {
110 core::hint::spin_loop(); 104 core::hint::spin_loop();
111 }
112 } 105 }
113 } 106 }
114 107
@@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
132 pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { 125 pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
133 self.disable_alarm(); 126 self.disable_alarm();
134 127
135 unsafe { 128 self.inner.regs().irq_setup_0().write(|w| {
136 self.inner.regs().irq_setup_0().write(|w| { 129 filter.write_setup_0(w);
137 filter.write_setup_0(w); 130 });
138 }); 131 self.inner.regs().irq_setup_1().write(|w| {
139 self.inner.regs().irq_setup_1().write(|w| { 132 filter.write_setup_1(w);
140 filter.write_setup_1(w); 133 });
141 }); 134
142 135 self.inner.regs().inte().modify(|w| w.set_rtc(true));
143 self.inner.regs().inte().modify(|w| w.set_rtc(true)); 136
144 137 // Set the enable bit and check if it is set
145 // Set the enable bit and check if it is set 138 self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
146 self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); 139 while !self.inner.regs().irq_setup_0().read().match_active() {
147 while !self.inner.regs().irq_setup_0().read().match_active() { 140 core::hint::spin_loop();
148 core::hint::spin_loop();
149 }
150 } 141 }
151 } 142 }
152 143
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 742a35d49..e817d074e 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -79,33 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
79 ) -> Self { 79 ) -> Self {
80 into_ref!(inner); 80 into_ref!(inner);
81 81
82 unsafe { 82 let p = inner.regs();
83 let p = inner.regs(); 83 let (presc, postdiv) = calc_prescs(config.frequency);
84 let (presc, postdiv) = calc_prescs(config.frequency); 84
85 85 p.cpsr().write(|w| w.set_cpsdvsr(presc));
86 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 86 p.cr0().write(|w| {
87 p.cr0().write(|w| { 87 w.set_dss(0b0111); // 8bit
88 w.set_dss(0b0111); // 8bit 88 w.set_spo(config.polarity == Polarity::IdleHigh);
89 w.set_spo(config.polarity == Polarity::IdleHigh); 89 w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
90 w.set_sph(config.phase == Phase::CaptureOnSecondTransition); 90 w.set_scr(postdiv);
91 w.set_scr(postdiv); 91 });
92 }); 92
93 p.cr1().write(|w| { 93 // Always enable DREQ signals -- harmless if DMA is not listening
94 w.set_sse(true); // enable 94 p.dmacr().write(|reg| {
95 }); 95 reg.set_rxdmae(true);
96 96 reg.set_txdmae(true);
97 if let Some(pin) = &clk { 97 });
98 pin.io().ctrl().write(|w| w.set_funcsel(1)); 98
99 } 99 // finally, enable.
100 if let Some(pin) = &mosi { 100 p.cr1().write(|w| w.set_sse(true));
101 pin.io().ctrl().write(|w| w.set_funcsel(1)); 101
102 } 102 if let Some(pin) = &clk {
103 if let Some(pin) = &miso { 103 pin.io().ctrl().write(|w| w.set_funcsel(1));
104 pin.io().ctrl().write(|w| w.set_funcsel(1)); 104 }
105 } 105 if let Some(pin) = &mosi {
106 if let Some(pin) = &cs { 106 pin.io().ctrl().write(|w| w.set_funcsel(1));
107 pin.io().ctrl().write(|w| w.set_funcsel(1)); 107 }
108 } 108 if let Some(pin) = &miso {
109 pin.io().ctrl().write(|w| w.set_funcsel(1));
110 }
111 if let Some(pin) = &cs {
112 pin.io().ctrl().write(|w| w.set_funcsel(1));
109 } 113 }
110 Self { 114 Self {
111 inner, 115 inner,
@@ -116,60 +120,52 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
116 } 120 }
117 121
118 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { 122 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
119 unsafe { 123 let p = self.inner.regs();
120 let p = self.inner.regs(); 124 for &b in data {
121 for &b in data { 125 while !p.sr().read().tnf() {}
122 while !p.sr().read().tnf() {} 126 p.dr().write(|w| w.set_data(b as _));
123 p.dr().write(|w| w.set_data(b as _)); 127 while !p.sr().read().rne() {}
124 while !p.sr().read().rne() {} 128 let _ = p.dr().read();
125 let _ = p.dr().read();
126 }
127 } 129 }
128 self.flush()?; 130 self.flush()?;
129 Ok(()) 131 Ok(())
130 } 132 }
131 133
132 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { 134 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
133 unsafe { 135 let p = self.inner.regs();
134 let p = self.inner.regs(); 136 for b in data {
135 for b in data { 137 while !p.sr().read().tnf() {}
136 while !p.sr().read().tnf() {} 138 p.dr().write(|w| w.set_data(*b as _));
137 p.dr().write(|w| w.set_data(*b as _)); 139 while !p.sr().read().rne() {}
138 while !p.sr().read().rne() {} 140 *b = p.dr().read().data() as u8;
139 *b = p.dr().read().data() as u8;
140 }
141 } 141 }
142 self.flush()?; 142 self.flush()?;
143 Ok(()) 143 Ok(())
144 } 144 }
145 145
146 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { 146 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
147 unsafe { 147 let p = self.inner.regs();
148 let p = self.inner.regs(); 148 for b in data {
149 for b in data { 149 while !p.sr().read().tnf() {}
150 while !p.sr().read().tnf() {} 150 p.dr().write(|w| w.set_data(0));
151 p.dr().write(|w| w.set_data(0)); 151 while !p.sr().read().rne() {}
152 while !p.sr().read().rne() {} 152 *b = p.dr().read().data() as u8;
153 *b = p.dr().read().data() as u8;
154 }
155 } 153 }
156 self.flush()?; 154 self.flush()?;
157 Ok(()) 155 Ok(())
158 } 156 }
159 157
160 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { 158 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
161 unsafe { 159 let p = self.inner.regs();
162 let p = self.inner.regs(); 160 let len = read.len().max(write.len());
163 let len = read.len().max(write.len()); 161 for i in 0..len {
164 for i in 0..len { 162 let wb = write.get(i).copied().unwrap_or(0);
165 let wb = write.get(i).copied().unwrap_or(0); 163 while !p.sr().read().tnf() {}
166 while !p.sr().read().tnf() {} 164 p.dr().write(|w| w.set_data(wb as _));
167 p.dr().write(|w| w.set_data(wb as _)); 165 while !p.sr().read().rne() {}
168 while !p.sr().read().rne() {} 166 let rb = p.dr().read().data() as u8;
169 let rb = p.dr().read().data() as u8; 167 if let Some(r) = read.get_mut(i) {
170 if let Some(r) = read.get_mut(i) { 168 *r = rb;
171 *r = rb;
172 }
173 } 169 }
174 } 170 }
175 self.flush()?; 171 self.flush()?;
@@ -177,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
177 } 173 }
178 174
179 pub fn flush(&mut self) -> Result<(), Error> { 175 pub fn flush(&mut self) -> Result<(), Error> {
180 unsafe { 176 let p = self.inner.regs();
181 let p = self.inner.regs(); 177 while p.sr().read().bsy() {}
182 while p.sr().read().bsy() {}
183 }
184 Ok(()) 178 Ok(())
185 } 179 }
186 180
187 pub fn set_frequency(&mut self, freq: u32) { 181 pub fn set_frequency(&mut self, freq: u32) {
188 let (presc, postdiv) = calc_prescs(freq); 182 let (presc, postdiv) = calc_prescs(freq);
189 let p = self.inner.regs(); 183 let p = self.inner.regs();
190 unsafe { 184 // disable
191 // disable 185 p.cr1().write(|w| w.set_sse(false));
192 p.cr1().write(|w| w.set_sse(false)); 186
193 187 // change stuff
194 // change stuff 188 p.cpsr().write(|w| w.set_cpsdvsr(presc));
195 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 189 p.cr0().modify(|w| {
196 p.cr0().modify(|w| { 190 w.set_scr(postdiv);
197 w.set_scr(postdiv); 191 });
198 }); 192
199 193 // enable
200 // enable 194 p.cr1().write(|w| w.set_sse(true));
201 p.cr1().write(|w| w.set_sse(true));
202 }
203 } 195 }
204} 196}
205 197
@@ -329,48 +321,45 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
329 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 321 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
330 let tx_ch = self.tx_dma.as_mut().unwrap(); 322 let tx_ch = self.tx_dma.as_mut().unwrap();
331 let tx_transfer = unsafe { 323 let tx_transfer = unsafe {
332 self.inner.regs().dmacr().modify(|reg| {
333 reg.set_txdmae(true);
334 });
335 // If we don't assign future to a variable, the data register pointer 324 // If we don't assign future to a variable, the data register pointer
336 // is held across an await and makes the future non-Send. 325 // is held across an await and makes the future non-Send.
337 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 326 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
338 }; 327 };
339 tx_transfer.await; 328 tx_transfer.await;
340 329
341 let p = self.inner.regs(); 330 let p = self.inner.regs();
342 unsafe { 331 while p.sr().read().bsy() {}
343 while p.sr().read().bsy() {}
344 332
345 // clear RX FIFO contents to prevent stale reads 333 // clear RX FIFO contents to prevent stale reads
346 while p.sr().read().rne() { 334 while p.sr().read().rne() {
347 let _: u16 = p.dr().read().data(); 335 let _: u16 = p.dr().read().data();
348 }
349 // clear RX overrun interrupt
350 p.icr().write(|w| w.set_roric(true));
351 } 336 }
337 // clear RX overrun interrupt
338 p.icr().write(|w| w.set_roric(true));
352 339
353 Ok(()) 340 Ok(())
354 } 341 }
355 342
356 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 343 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
357 unsafe { 344 // Start RX first. Transfer starts when TX starts, if RX
358 self.inner.regs().dmacr().write(|reg| { 345 // is not started yet we might lose bytes.
359 reg.set_rxdmae(true); 346 let rx_ch = self.rx_dma.as_mut().unwrap();
360 reg.set_txdmae(true); 347 let rx_transfer = unsafe {
361 })
362 };
363 let tx_ch = self.tx_dma.as_mut().unwrap();
364 let tx_transfer = unsafe {
365 // If we don't assign future to a variable, the data register pointer 348 // If we don't assign future to a variable, the data register pointer
366 // is held across an await and makes the future non-Send. 349 // is held across an await and makes the future non-Send.
367 crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) 350 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
368 }; 351 };
369 let rx_ch = self.rx_dma.as_mut().unwrap(); 352
370 let rx_transfer = unsafe { 353 let tx_ch = self.tx_dma.as_mut().unwrap();
354 let tx_transfer = unsafe {
371 // If we don't assign future to a variable, the data register pointer 355 // If we don't assign future to a variable, the data register pointer
372 // is held across an await and makes the future non-Send. 356 // is held across an await and makes the future non-Send.
373 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) 357 crate::dma::write_repeated(
358 tx_ch,
359 self.inner.regs().dr().as_ptr() as *mut u8,
360 buffer.len(),
361 T::TX_DREQ,
362 )
374 }; 363 };
375 join(tx_transfer, rx_transfer).await; 364 join(tx_transfer, rx_transfer).await;
376 Ok(()) 365 Ok(())
@@ -388,11 +377,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
388 let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr); 377 let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr);
389 let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); 378 let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
390 379
391 unsafe { 380 // Start RX first. Transfer starts when TX starts, if RX
392 self.inner.regs().dmacr().write(|reg| { 381 // is not started yet we might lose bytes.
393 reg.set_rxdmae(true); 382 let rx_ch = self.rx_dma.as_mut().unwrap();
394 reg.set_txdmae(true); 383 let rx_transfer = unsafe {
395 }) 384 // If we don't assign future to a variable, the data register pointer
385 // is held across an await and makes the future non-Send.
386 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ)
396 }; 387 };
397 388
398 let mut tx_ch = self.tx_dma.as_mut().unwrap(); 389 let mut tx_ch = self.tx_dma.as_mut().unwrap();
@@ -401,38 +392,29 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
401 let tx_transfer = async { 392 let tx_transfer = async {
402 let p = self.inner.regs(); 393 let p = self.inner.regs();
403 unsafe { 394 unsafe {
404 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await; 395 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
405 396
406 if rx_len > tx_len { 397 if rx_len > tx_len {
407 let write_bytes_len = rx_len - tx_len; 398 let write_bytes_len = rx_len - tx_len;
408 // write dummy data 399 // write dummy data
409 // this will disable incrementation of the buffers 400 // this will disable incrementation of the buffers
410 crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await 401 crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
411 } 402 }
412 } 403 }
413 }; 404 };
414
415 let rx_ch = self.rx_dma.as_mut().unwrap();
416 let rx_transfer = unsafe {
417 // If we don't assign future to a variable, the data register pointer
418 // is held across an await and makes the future non-Send.
419 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)
420 };
421 join(tx_transfer, rx_transfer).await; 405 join(tx_transfer, rx_transfer).await;
422 406
423 // if tx > rx we should clear any overflow of the FIFO SPI buffer 407 // if tx > rx we should clear any overflow of the FIFO SPI buffer
424 if tx_len > rx_len { 408 if tx_len > rx_len {
425 let p = self.inner.regs(); 409 let p = self.inner.regs();
426 unsafe { 410 while p.sr().read().bsy() {}
427 while p.sr().read().bsy() {}
428 411
429 // clear RX FIFO contents to prevent stale reads 412 // clear RX FIFO contents to prevent stale reads
430 while p.sr().read().rne() { 413 while p.sr().read().rne() {
431 let _: u16 = p.dr().read().data(); 414 let _: u16 = p.dr().read().data();
432 }
433 // clear RX overrun interrupt
434 p.icr().write(|w| w.set_roric(true));
435 } 415 }
416 // clear RX overrun interrupt
417 p.icr().write(|w| w.set_roric(true));
436 } 418 }
437 419
438 Ok(()) 420 Ok(())
@@ -630,14 +612,12 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
630 fn set_config(&mut self, config: &Self::Config) { 612 fn set_config(&mut self, config: &Self::Config) {
631 let p = self.inner.regs(); 613 let p = self.inner.regs();
632 let (presc, postdiv) = calc_prescs(config.frequency); 614 let (presc, postdiv) = calc_prescs(config.frequency);
633 unsafe { 615 p.cpsr().write(|w| w.set_cpsdvsr(presc));
634 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 616 p.cr0().write(|w| {
635 p.cr0().write(|w| { 617 w.set_dss(0b0111); // 8bit
636 w.set_dss(0b0111); // 8bit 618 w.set_spo(config.polarity == Polarity::IdleHigh);
637 w.set_spo(config.polarity == Polarity::IdleHigh); 619 w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
638 w.set_sph(config.phase == Phase::CaptureOnSecondTransition); 620 w.set_scr(postdiv);
639 w.set_scr(postdiv); 621 });
640 });
641 }
642 } 622 }
643} 623}
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index 80efd779f..faa8df037 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::blocking_mutex::Mutex; 6use embassy_sync::blocking_mutex::Mutex;
7use embassy_time::driver::{AlarmHandle, Driver}; 7use embassy_time::driver::{AlarmHandle, Driver};
8 8
9use crate::interrupt::{Interrupt, InterruptExt}; 9use crate::interrupt::InterruptExt;
10use crate::{interrupt, pac}; 10use crate::{interrupt, pac};
11 11
12struct AlarmState { 12struct AlarmState {
@@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
34impl Driver for TimerDriver { 34impl Driver for TimerDriver {
35 fn now(&self) -> u64 { 35 fn now(&self) -> u64 {
36 loop { 36 loop {
37 unsafe { 37 let hi = pac::TIMER.timerawh().read();
38 let hi = pac::TIMER.timerawh().read(); 38 let lo = pac::TIMER.timerawl().read();
39 let lo = pac::TIMER.timerawl().read(); 39 let hi2 = pac::TIMER.timerawh().read();
40 let hi2 = pac::TIMER.timerawh().read(); 40 if hi == hi2 {
41 if hi == hi2 { 41 return (hi as u64) << 32 | (lo as u64);
42 return (hi as u64) << 32 | (lo as u64);
43 }
44 } 42 }
45 } 43 }
46 } 44 }
@@ -78,13 +76,13 @@ impl Driver for TimerDriver {
78 // Note that we're not checking the high bits at all. This means the irq may fire early 76 // Note that we're not checking the high bits at all. This means the irq may fire early
79 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire 77 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
80 // it is checked if the alarm time has passed. 78 // it is checked if the alarm time has passed.
81 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 79 pac::TIMER.alarm(n).write_value(timestamp as u32);
82 80
83 let now = self.now(); 81 let now = self.now();
84 if timestamp <= now { 82 if timestamp <= now {
85 // If alarm timestamp has passed the alarm will not fire. 83 // If alarm timestamp has passed the alarm will not fire.
86 // Disarm the alarm and return `false` to indicate that. 84 // Disarm the alarm and return `false` to indicate that.
87 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } 85 pac::TIMER.armed().write(|w| w.set_armed(1 << n));
88 86
89 alarm.timestamp.set(u64::MAX); 87 alarm.timestamp.set(u64::MAX);
90 88
@@ -106,17 +104,17 @@ impl TimerDriver {
106 } else { 104 } else {
107 // Not elapsed, arm it again. 105 // Not elapsed, arm it again.
108 // This can happen if it was set more than 2^32 us in the future. 106 // This can happen if it was set more than 2^32 us in the future.
109 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 107 pac::TIMER.alarm(n).write_value(timestamp as u32);
110 } 108 }
111 }); 109 });
112 110
113 // clear the irq 111 // clear the irq
114 unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } 112 pac::TIMER.intr().write(|w| w.set_alarm(n, true));
115 } 113 }
116 114
117 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 115 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
118 // disarm 116 // disarm
119 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } 117 pac::TIMER.armed().write(|w| w.set_armed(1 << n));
120 118
121 let alarm = &self.alarms.borrow(cs)[n]; 119 let alarm = &self.alarms.borrow(cs)[n];
122 alarm.timestamp.set(u64::MAX); 120 alarm.timestamp.set(u64::MAX);
@@ -145,28 +143,32 @@ pub unsafe fn init() {
145 w.set_alarm(2, true); 143 w.set_alarm(2, true);
146 w.set_alarm(3, true); 144 w.set_alarm(3, true);
147 }); 145 });
148 interrupt::TIMER_IRQ_0::steal().enable(); 146 interrupt::TIMER_IRQ_0.enable();
149 interrupt::TIMER_IRQ_1::steal().enable(); 147 interrupt::TIMER_IRQ_1.enable();
150 interrupt::TIMER_IRQ_2::steal().enable(); 148 interrupt::TIMER_IRQ_2.enable();
151 interrupt::TIMER_IRQ_3::steal().enable(); 149 interrupt::TIMER_IRQ_3.enable();
152} 150}
153 151
152#[cfg(feature = "rt")]
154#[interrupt] 153#[interrupt]
155unsafe fn TIMER_IRQ_0() { 154fn TIMER_IRQ_0() {
156 DRIVER.check_alarm(0) 155 DRIVER.check_alarm(0)
157} 156}
158 157
158#[cfg(feature = "rt")]
159#[interrupt] 159#[interrupt]
160unsafe fn TIMER_IRQ_1() { 160fn TIMER_IRQ_1() {
161 DRIVER.check_alarm(1) 161 DRIVER.check_alarm(1)
162} 162}
163 163
164#[cfg(feature = "rt")]
164#[interrupt] 165#[interrupt]
165unsafe fn TIMER_IRQ_2() { 166fn TIMER_IRQ_2() {
166 DRIVER.check_alarm(2) 167 DRIVER.check_alarm(2)
167} 168}
168 169
170#[cfg(feature = "rt")]
169#[interrupt] 171#[interrupt]
170unsafe fn TIMER_IRQ_3() { 172fn TIMER_IRQ_3() {
171 DRIVER.check_alarm(3) 173 DRIVER.check_alarm(3)
172} 174}
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 12d6b8d91..30eeb5476 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -3,14 +3,14 @@ use core::slice;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU8, Ordering}; 5use atomic_polyfill::{AtomicU8, Ordering};
6use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
7use embassy_hal_common::atomic_ring_buffer::RingBuffer; 6use embassy_hal_common::atomic_ring_buffer::RingBuffer;
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
10 9
11use super::*; 10use super::*;
12use crate::clocks::clk_peri_freq; 11use crate::clocks::clk_peri_freq;
13use crate::RegExt; 12use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::{interrupt, RegExt};
14 14
15pub struct State { 15pub struct State {
16 tx_waker: AtomicWaker, 16 tx_waker: AtomicWaker,
@@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
73 // we clear it after it happens. The downside is that the we manually have 73 // we clear it after it happens. The downside is that the we manually have
74 // to pend the ISR when we want data transmission to start. 74 // to pend the ISR when we want data transmission to start.
75 let regs = T::regs(); 75 let regs = T::regs();
76 unsafe { 76 regs.uartimsc().write(|w| {
77 regs.uartimsc().write(|w| { 77 w.set_rxim(true);
78 w.set_rxim(true); 78 w.set_rtim(true);
79 w.set_rtim(true); 79 w.set_txim(true);
80 w.set_txim(true); 80 });
81 }); 81
82 82 T::Interrupt::unpend();
83 T::Interrupt::steal().unpend(); 83 unsafe { T::Interrupt::enable() };
84 T::Interrupt::steal().enable();
85 };
86} 84}
87 85
88impl<'d, T: Instance> BufferedUart<'d, T> { 86impl<'d, T: Instance> BufferedUart<'d, T> {
@@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
247 // (Re-)Enable the interrupt to receive more data in case it was 245 // (Re-)Enable the interrupt to receive more data in case it was
248 // disabled because the buffer was full or errors were detected. 246 // disabled because the buffer was full or errors were detected.
249 let regs = T::regs(); 247 let regs = T::regs();
250 unsafe { 248 regs.uartimsc().write_set(|w| {
251 regs.uartimsc().write_set(|w| { 249 w.set_rxim(true);
252 w.set_rxim(true); 250 w.set_rtim(true);
253 w.set_rtim(true); 251 });
254 });
255 }
256 252
257 Poll::Ready(result) 253 Poll::Ready(result)
258 } 254 }
@@ -299,12 +295,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
299 // (Re-)Enable the interrupt to receive more data in case it was 295 // (Re-)Enable the interrupt to receive more data in case it was
300 // disabled because the buffer was full or errors were detected. 296 // disabled because the buffer was full or errors were detected.
301 let regs = T::regs(); 297 let regs = T::regs();
302 unsafe { 298 regs.uartimsc().write_set(|w| {
303 regs.uartimsc().write_set(|w| { 299 w.set_rxim(true);
304 w.set_rxim(true); 300 w.set_rtim(true);
305 w.set_rtim(true); 301 });
306 });
307 }
308 } 302 }
309} 303}
310 304
@@ -362,7 +356,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
362 // FIFO and the number of bytes drops below a threshold. When the 356 // FIFO and the number of bytes drops below a threshold. When the
363 // FIFO was empty we have to manually pend the interrupt to shovel 357 // FIFO was empty we have to manually pend the interrupt to shovel
364 // TX data from the buffer into the FIFO. 358 // TX data from the buffer into the FIFO.
365 unsafe { T::Interrupt::steal() }.pend(); 359 T::Interrupt::pend();
366 Poll::Ready(Ok(n)) 360 Poll::Ready(Ok(n))
367 }) 361 })
368 } 362 }
@@ -398,7 +392,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
398 // FIFO and the number of bytes drops below a threshold. When the 392 // FIFO and the number of bytes drops below a threshold. When the
399 // FIFO was empty we have to manually pend the interrupt to shovel 393 // FIFO was empty we have to manually pend the interrupt to shovel
400 // TX data from the buffer into the FIFO. 394 // TX data from the buffer into the FIFO.
401 unsafe { T::Interrupt::steal() }.pend(); 395 T::Interrupt::pend();
402 return Ok(n); 396 return Ok(n);
403 } 397 }
404 } 398 }
@@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
414 } 408 }
415 409
416 pub fn busy(&self) -> bool { 410 pub fn busy(&self) -> bool {
417 unsafe { T::regs().uartfr().read().busy() } 411 T::regs().uartfr().read().busy()
418 } 412 }
419 413
420 /// Assert a break condition after waiting for the transmit buffers to empty, 414 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
426 /// for the transmit fifo to empty, which may take a while on slow links. 420 /// for the transmit fifo to empty, which may take a while on slow links.
427 pub async fn send_break(&mut self, bits: u32) { 421 pub async fn send_break(&mut self, bits: u32) {
428 let regs = T::regs(); 422 let regs = T::regs();
429 let bits = bits.max(unsafe { 423 let bits = bits.max({
430 let lcr = regs.uartlcr_h().read(); 424 let lcr = regs.uartlcr_h().read();
431 let width = lcr.wlen() as u32 + 5; 425 let width = lcr.wlen() as u32 + 5;
432 let parity = lcr.pen() as u32; 426 let parity = lcr.pen() as u32;
433 let stops = 1 + lcr.stp2() as u32; 427 let stops = 1 + lcr.stp2() as u32;
434 2 * (1 + width + parity + stops) 428 2 * (1 + width + parity + stops)
435 }); 429 });
436 let divx64 = unsafe { 430 let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
437 ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 431 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
438 } as u64;
439 let div_clk = clk_peri_freq() as u64 * 64; 432 let div_clk = clk_peri_freq() as u64 * 64;
440 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 433 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
441 434
442 Self::flush().await.unwrap(); 435 Self::flush().await.unwrap();
443 while self.busy() {} 436 while self.busy() {}
444 unsafe { 437 regs.uartlcr_h().write_set(|w| w.set_brk(true));
445 regs.uartlcr_h().write_set(|w| w.set_brk(true));
446 }
447 Timer::after(Duration::from_micros(wait_usecs)).await; 438 Timer::after(Duration::from_micros(wait_usecs)).await;
448 unsafe { 439 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
449 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
450 }
451 } 440 }
452} 441}
453 442
454impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 443impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
455 fn drop(&mut self) { 444 fn drop(&mut self) {
456 let state = T::buffered_state(); 445 let state = T::buffered_state();
457 unsafe { 446 unsafe { state.rx_buf.deinit() }
458 state.rx_buf.deinit();
459 447
460 // TX is inactive if the the buffer is not available. 448 // TX is inactive if the the buffer is not available.
461 // We can now unregister the interrupt handler 449 // We can now unregister the interrupt handler
462 if state.tx_buf.len() == 0 { 450 if state.tx_buf.len() == 0 {
463 T::Interrupt::steal().disable(); 451 T::Interrupt::disable();
464 }
465 } 452 }
466 } 453 }
467} 454}
@@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
469impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { 456impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
470 fn drop(&mut self) { 457 fn drop(&mut self) {
471 let state = T::buffered_state(); 458 let state = T::buffered_state();
472 unsafe { 459 unsafe { state.tx_buf.deinit() }
473 state.tx_buf.deinit();
474 460
475 // RX is inactive if the the buffer is not available. 461 // RX is inactive if the the buffer is not available.
476 // We can now unregister the interrupt handler 462 // We can now unregister the interrupt handler
477 if state.rx_buf.len() == 0 { 463 if state.rx_buf.len() == 0 {
478 T::Interrupt::steal().disable(); 464 T::Interrupt::disable();
479 }
480 } 465 }
481 } 466 }
482} 467}
@@ -485,7 +470,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
485 _uart: PhantomData<T>, 470 _uart: PhantomData<T>,
486} 471}
487 472
488impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> { 473impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
489 unsafe fn on_interrupt() { 474 unsafe fn on_interrupt() {
490 let r = T::regs(); 475 let r = T::regs();
491 if r.uartdmacr().read().rxdmae() { 476 if r.uartdmacr().read().rxdmae() {
@@ -494,94 +479,92 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
494 479
495 let s = T::buffered_state(); 480 let s = T::buffered_state();
496 481
497 unsafe { 482 // Clear TX and error interrupt flags
498 // Clear TX and error interrupt flags 483 // RX interrupt flags are cleared by reading from the FIFO.
499 // RX interrupt flags are cleared by reading from the FIFO. 484 let ris = r.uartris().read();
500 let ris = r.uartris().read(); 485 r.uarticr().write(|w| {
501 r.uarticr().write(|w| { 486 w.set_txic(ris.txris());
502 w.set_txic(ris.txris()); 487 w.set_feic(ris.feris());
503 w.set_feic(ris.feris()); 488 w.set_peic(ris.peris());
504 w.set_peic(ris.peris()); 489 w.set_beic(ris.beris());
505 w.set_beic(ris.beris()); 490 w.set_oeic(ris.oeris());
506 w.set_oeic(ris.oeris()); 491 });
507 });
508 492
509 trace!("on_interrupt ris={:#X}", ris.0); 493 trace!("on_interrupt ris={:#X}", ris.0);
510 494
511 // Errors 495 // Errors
512 if ris.feris() { 496 if ris.feris() {
513 warn!("Framing error"); 497 warn!("Framing error");
514 } 498 }
515 if ris.peris() { 499 if ris.peris() {
516 warn!("Parity error"); 500 warn!("Parity error");
517 } 501 }
518 if ris.beris() { 502 if ris.beris() {
519 warn!("Break error"); 503 warn!("Break error");
520 } 504 }
521 if ris.oeris() { 505 if ris.oeris() {
522 warn!("Overrun error"); 506 warn!("Overrun error");
523 } 507 }
524 508
525 // RX 509 // RX
526 let mut rx_writer = s.rx_buf.writer(); 510 let mut rx_writer = unsafe { s.rx_buf.writer() };
527 let rx_buf = rx_writer.push_slice(); 511 let rx_buf = rx_writer.push_slice();
528 let mut n_read = 0; 512 let mut n_read = 0;
529 let mut error = false; 513 let mut error = false;
530 for rx_byte in rx_buf { 514 for rx_byte in rx_buf {
531 if r.uartfr().read().rxfe() { 515 if r.uartfr().read().rxfe() {
532 break; 516 break;
533 }
534 let dr = r.uartdr().read();
535 if (dr.0 >> 8) != 0 {
536 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
537 error = true;
538 // only fill the buffer with valid characters. the current character is fine
539 // if the error is an overrun, but if we add it to the buffer we'll report
540 // the overrun one character too late. drop it instead and pretend we were
541 // a bit slower at draining the rx fifo than we actually were.
542 // this is consistent with blocking uart error reporting.
543 break;
544 }
545 *rx_byte = dr.data();
546 n_read += 1;
547 }
548 if n_read > 0 {
549 rx_writer.push_done(n_read);
550 s.rx_waker.wake();
551 } else if error {
552 s.rx_waker.wake();
553 } 517 }
554 // Disable any further RX interrupts when the buffer becomes full or 518 let dr = r.uartdr().read();
555 // errors have occurred. This lets us buffer additional errors in the 519 if (dr.0 >> 8) != 0 {
556 // fifo without needing more error storage locations, and most applications 520 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
557 // will want to do a full reset of their uart state anyway once an error 521 error = true;
558 // has happened. 522 // only fill the buffer with valid characters. the current character is fine
559 if s.rx_buf.is_full() || error { 523 // if the error is an overrun, but if we add it to the buffer we'll report
560 r.uartimsc().write_clear(|w| { 524 // the overrun one character too late. drop it instead and pretend we were
561 w.set_rxim(true); 525 // a bit slower at draining the rx fifo than we actually were.
562 w.set_rtim(true); 526 // this is consistent with blocking uart error reporting.
563 }); 527 break;
564 } 528 }
529 *rx_byte = dr.data();
530 n_read += 1;
531 }
532 if n_read > 0 {
533 rx_writer.push_done(n_read);
534 s.rx_waker.wake();
535 } else if error {
536 s.rx_waker.wake();
537 }
538 // Disable any further RX interrupts when the buffer becomes full or
539 // errors have occurred. This lets us buffer additional errors in the
540 // fifo without needing more error storage locations, and most applications
541 // will want to do a full reset of their uart state anyway once an error
542 // has happened.
543 if s.rx_buf.is_full() || error {
544 r.uartimsc().write_clear(|w| {
545 w.set_rxim(true);
546 w.set_rtim(true);
547 });
548 }
565 549
566 // TX 550 // TX
567 let mut tx_reader = s.tx_buf.reader(); 551 let mut tx_reader = unsafe { s.tx_buf.reader() };
568 let tx_buf = tx_reader.pop_slice(); 552 let tx_buf = tx_reader.pop_slice();
569 let mut n_written = 0; 553 let mut n_written = 0;
570 for tx_byte in tx_buf.iter_mut() { 554 for tx_byte in tx_buf.iter_mut() {
571 if r.uartfr().read().txff() { 555 if r.uartfr().read().txff() {
572 break; 556 break;
573 }
574 r.uartdr().write(|w| w.set_data(*tx_byte));
575 n_written += 1;
576 }
577 if n_written > 0 {
578 tx_reader.pop_done(n_written);
579 s.tx_waker.wake();
580 } 557 }
581 // The TX interrupt only triggers once when the FIFO threshold is 558 r.uartdr().write(|w| w.set_data(*tx_byte));
582 // crossed. No need to disable it when the buffer becomes empty 559 n_written += 1;
583 // as it does re-trigger anymore once we have cleared it. 560 }
561 if n_written > 0 {
562 tx_reader.pop_done(n_written);
563 s.tx_waker.wake();
584 } 564 }
565 // The TX interrupt only triggers once when the FIFO threshold is
566 // crossed. No need to disable it when the buffer becomes empty
567 // as it does re-trigger anymore once we have cleared it.
585 } 568 }
586} 569}
587 570
@@ -695,24 +678,22 @@ mod eh02 {
695 678
696 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 679 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
697 let r = T::regs(); 680 let r = T::regs();
698 unsafe { 681 if r.uartfr().read().rxfe() {
699 if r.uartfr().read().rxfe() { 682 return Err(nb::Error::WouldBlock);
700 return Err(nb::Error::WouldBlock); 683 }
701 }
702 684
703 let dr = r.uartdr().read(); 685 let dr = r.uartdr().read();
704 686
705 if dr.oe() { 687 if dr.oe() {
706 Err(nb::Error::Other(Error::Overrun)) 688 Err(nb::Error::Other(Error::Overrun))
707 } else if dr.be() { 689 } else if dr.be() {
708 Err(nb::Error::Other(Error::Break)) 690 Err(nb::Error::Other(Error::Break))
709 } else if dr.pe() { 691 } else if dr.pe() {
710 Err(nb::Error::Other(Error::Parity)) 692 Err(nb::Error::Other(Error::Parity))
711 } else if dr.fe() { 693 } else if dr.fe() {
712 Err(nb::Error::Other(Error::Framing)) 694 Err(nb::Error::Other(Error::Framing))
713 } else { 695 } else {
714 Ok(dr.data()) 696 Ok(dr.data())
715 }
716 } 697 }
717 } 698 }
718 } 699 }
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 44e0ca0f6..7b94bce5e 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -3,7 +3,6 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU16, Ordering}; 5use atomic_polyfill::{AtomicU16, Ordering};
6use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
7use embassy_futures::select::{select, Either}; 6use embassy_futures::select::{select, Either};
8use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
@@ -14,8 +13,9 @@ use crate::clocks::clk_peri_freq;
14use crate::dma::{AnyChannel, Channel}; 13use crate::dma::{AnyChannel, Channel};
15use crate::gpio::sealed::Pin; 14use crate::gpio::sealed::Pin;
16use crate::gpio::AnyPin; 15use crate::gpio::AnyPin;
16use crate::interrupt::typelevel::{Binding, Interrupt};
17use crate::pac::io::vals::{Inover, Outover}; 17use crate::pac::io::vals::{Inover, Outover};
18use crate::{pac, peripherals, Peripheral, RegExt}; 18use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
19 19
20#[cfg(feature = "nightly")] 20#[cfg(feature = "nightly")]
21mod buffered; 21mod buffered;
@@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
146 146
147 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 147 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
148 let r = T::regs(); 148 let r = T::regs();
149 unsafe { 149 for &b in buffer {
150 for &b in buffer { 150 while r.uartfr().read().txff() {}
151 while r.uartfr().read().txff() {} 151 r.uartdr().write(|w| w.set_data(b));
152 r.uartdr().write(|w| w.set_data(b));
153 }
154 } 152 }
155 Ok(()) 153 Ok(())
156 } 154 }
157 155
158 pub fn blocking_flush(&mut self) -> Result<(), Error> { 156 pub fn blocking_flush(&mut self) -> Result<(), Error> {
159 let r = T::regs(); 157 let r = T::regs();
160 unsafe { while !r.uartfr().read().txfe() {} } 158 while !r.uartfr().read().txfe() {}
161 Ok(()) 159 Ok(())
162 } 160 }
163 161
164 pub fn busy(&self) -> bool { 162 pub fn busy(&self) -> bool {
165 unsafe { T::regs().uartfr().read().busy() } 163 T::regs().uartfr().read().busy()
166 } 164 }
167 165
168 /// Assert a break condition after waiting for the transmit buffers to empty, 166 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -174,28 +172,23 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
174 /// for the transmit fifo to empty, which may take a while on slow links. 172 /// for the transmit fifo to empty, which may take a while on slow links.
175 pub async fn send_break(&mut self, bits: u32) { 173 pub async fn send_break(&mut self, bits: u32) {
176 let regs = T::regs(); 174 let regs = T::regs();
177 let bits = bits.max(unsafe { 175 let bits = bits.max({
178 let lcr = regs.uartlcr_h().read(); 176 let lcr = regs.uartlcr_h().read();
179 let width = lcr.wlen() as u32 + 5; 177 let width = lcr.wlen() as u32 + 5;
180 let parity = lcr.pen() as u32; 178 let parity = lcr.pen() as u32;
181 let stops = 1 + lcr.stp2() as u32; 179 let stops = 1 + lcr.stp2() as u32;
182 2 * (1 + width + parity + stops) 180 2 * (1 + width + parity + stops)
183 }); 181 });
184 let divx64 = unsafe { 182 let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
185 ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 183 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
186 } as u64;
187 let div_clk = clk_peri_freq() as u64 * 64; 184 let div_clk = clk_peri_freq() as u64 * 64;
188 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 185 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
189 186
190 self.blocking_flush().unwrap(); 187 self.blocking_flush().unwrap();
191 while self.busy() {} 188 while self.busy() {}
192 unsafe { 189 regs.uartlcr_h().write_set(|w| w.set_brk(true));
193 regs.uartlcr_h().write_set(|w| w.set_brk(true));
194 }
195 Timer::after(Duration::from_micros(wait_usecs)).await; 190 Timer::after(Duration::from_micros(wait_usecs)).await;
196 unsafe { 191 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
197 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
198 }
199 } 192 }
200} 193}
201 194
@@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
221 }); 214 });
222 // If we don't assign future to a variable, the data register pointer 215 // If we don't assign future to a variable, the data register pointer
223 // is held across an await and makes the future non-Send. 216 // is held across an await and makes the future non-Send.
224 crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) 217 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ)
225 }; 218 };
226 transfer.await; 219 transfer.await;
227 Ok(()) 220 Ok(())
@@ -245,12 +238,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
245 fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self { 238 fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
246 debug_assert_eq!(has_irq, rx_dma.is_some()); 239 debug_assert_eq!(has_irq, rx_dma.is_some());
247 if has_irq { 240 if has_irq {
248 unsafe { 241 // disable all error interrupts initially
249 // disable all error interrupts initially 242 T::regs().uartimsc().write(|w| w.0 = 0);
250 T::regs().uartimsc().write(|w| w.0 = 0); 243 T::Interrupt::unpend();
251 T::Interrupt::steal().unpend(); 244 unsafe { T::Interrupt::enable() };
252 T::Interrupt::steal().enable();
253 }
254 } 245 }
255 Self { 246 Self {
256 rx_dma, 247 rx_dma,
@@ -269,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
269 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 260 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
270 let r = T::regs(); 261 let r = T::regs();
271 for (i, b) in buffer.iter_mut().enumerate() { 262 for (i, b) in buffer.iter_mut().enumerate() {
272 if unsafe { r.uartfr().read().rxfe() } { 263 if r.uartfr().read().rxfe() {
273 return Ok(i); 264 return Ok(i);
274 } 265 }
275 266
276 let dr = unsafe { r.uartdr().read() }; 267 let dr = r.uartdr().read();
277 268
278 if dr.oe() { 269 if dr.oe() {
279 return Err(Error::Overrun); 270 return Err(Error::Overrun);
@@ -294,15 +285,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
294impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { 285impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
295 fn drop(&mut self) { 286 fn drop(&mut self) {
296 if let Some(_) = self.rx_dma { 287 if let Some(_) = self.rx_dma {
297 unsafe { 288 T::Interrupt::disable();
298 T::Interrupt::steal().disable(); 289 // clear dma flags. irq handlers use these to disambiguate among themselves.
299 // clear dma flags. irq handlers use these to disambiguate among themselves. 290 T::regs().uartdmacr().write_clear(|reg| {
300 T::regs().uartdmacr().write_clear(|reg| { 291 reg.set_rxdmae(true);
301 reg.set_rxdmae(true); 292 reg.set_txdmae(true);
302 reg.set_txdmae(true); 293 reg.set_dmaonerr(true);
303 reg.set_dmaonerr(true); 294 });
304 });
305 }
306 } 295 }
307 } 296 }
308} 297}
@@ -334,7 +323,7 @@ pub struct InterruptHandler<T: Instance> {
334 _uart: PhantomData<T>, 323 _uart: PhantomData<T>,
335} 324}
336 325
337impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 326impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
338 unsafe fn on_interrupt() { 327 unsafe fn on_interrupt() {
339 let uart = T::regs(); 328 let uart = T::regs();
340 if !uart.uartdmacr().read().rxdmae() { 329 if !uart.uartdmacr().read().rxdmae() {
@@ -357,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
357 // clear error flags before we drain the fifo. errors that have accumulated 346 // clear error flags before we drain the fifo. errors that have accumulated
358 // in the flags will also be present in the fifo. 347 // in the flags will also be present in the fifo.
359 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 348 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
360 unsafe { 349 T::regs().uarticr().write(|w| {
361 T::regs().uarticr().write(|w| { 350 w.set_oeic(true);
362 w.set_oeic(true); 351 w.set_beic(true);
363 w.set_beic(true); 352 w.set_peic(true);
364 w.set_peic(true); 353 w.set_feic(true);
365 w.set_feic(true); 354 });
366 });
367 }
368 355
369 // then drain the fifo. we need to read at most 32 bytes. errors that apply 356 // then drain the fifo. we need to read at most 32 bytes. errors that apply
370 // to fifo bytes will be reported directly. 357 // to fifo bytes will be reported directly.
@@ -381,20 +368,20 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
381 // interrupt flags will have been raised, and those will be picked up immediately 368 // interrupt flags will have been raised, and those will be picked up immediately
382 // by the interrupt handler. 369 // by the interrupt handler.
383 let ch = self.rx_dma.as_mut().unwrap(); 370 let ch = self.rx_dma.as_mut().unwrap();
371 T::regs().uartimsc().write_set(|w| {
372 w.set_oeim(true);
373 w.set_beim(true);
374 w.set_peim(true);
375 w.set_feim(true);
376 });
377 T::regs().uartdmacr().write_set(|reg| {
378 reg.set_rxdmae(true);
379 reg.set_dmaonerr(true);
380 });
384 let transfer = unsafe { 381 let transfer = unsafe {
385 T::regs().uartimsc().write_set(|w| {
386 w.set_oeim(true);
387 w.set_beim(true);
388 w.set_peim(true);
389 w.set_feim(true);
390 });
391 T::regs().uartdmacr().write_set(|reg| {
392 reg.set_rxdmae(true);
393 reg.set_dmaonerr(true);
394 });
395 // If we don't assign future to a variable, the data register pointer 382 // If we don't assign future to a variable, the data register pointer
396 // is held across an await and makes the future non-Send. 383 // is held across an await and makes the future non-Send.
397 crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) 384 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ)
398 }; 385 };
399 386
400 // wait for either the transfer to complete or an error to happen. 387 // wait for either the transfer to complete or an error to happen.
@@ -577,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
577 config: Config, 564 config: Config,
578 ) { 565 ) {
579 let r = T::regs(); 566 let r = T::regs();
580 unsafe { 567 if let Some(pin) = &tx {
581 if let Some(pin) = &tx { 568 pin.io().ctrl().write(|w| {
582 pin.io().ctrl().write(|w| { 569 w.set_funcsel(2);
583 w.set_funcsel(2); 570 w.set_outover(if config.invert_tx {
584 w.set_outover(if config.invert_tx { 571 Outover::INVERT
585 Outover::INVERT 572 } else {
586 } else { 573 Outover::NORMAL
587 Outover::NORMAL
588 });
589 }); 574 });
590 pin.pad_ctrl().write(|w| w.set_ie(true)); 575 });
591 } 576 pin.pad_ctrl().write(|w| w.set_ie(true));
592 if let Some(pin) = &rx { 577 }
593 pin.io().ctrl().write(|w| { 578 if let Some(pin) = &rx {
594 w.set_funcsel(2); 579 pin.io().ctrl().write(|w| {
595 w.set_inover(if config.invert_rx { 580 w.set_funcsel(2);
596 Inover::INVERT 581 w.set_inover(if config.invert_rx {
597 } else { 582 Inover::INVERT
598 Inover::NORMAL 583 } else {
599 }); 584 Inover::NORMAL
600 }); 585 });
601 pin.pad_ctrl().write(|w| w.set_ie(true)); 586 });
602 } 587 pin.pad_ctrl().write(|w| w.set_ie(true));
603 if let Some(pin) = &cts { 588 }
604 pin.io().ctrl().write(|w| { 589 if let Some(pin) = &cts {
605 w.set_funcsel(2); 590 pin.io().ctrl().write(|w| {
606 w.set_inover(if config.invert_cts { 591 w.set_funcsel(2);
607 Inover::INVERT 592 w.set_inover(if config.invert_cts {
608 } else { 593 Inover::INVERT
609 Inover::NORMAL 594 } else {
610 }); 595 Inover::NORMAL
611 }); 596 });
612 pin.pad_ctrl().write(|w| w.set_ie(true)); 597 });
613 } 598 pin.pad_ctrl().write(|w| w.set_ie(true));
614 if let Some(pin) = &rts { 599 }
615 pin.io().ctrl().write(|w| { 600 if let Some(pin) = &rts {
616 w.set_funcsel(2); 601 pin.io().ctrl().write(|w| {
617 w.set_outover(if config.invert_rts { 602 w.set_funcsel(2);
618 Outover::INVERT 603 w.set_outover(if config.invert_rts {
619 } else { 604 Outover::INVERT
620 Outover::NORMAL 605 } else {
621 }); 606 Outover::NORMAL
622 }); 607 });
623 pin.pad_ctrl().write(|w| w.set_ie(true)); 608 });
624 } 609 pin.pad_ctrl().write(|w| w.set_ie(true));
610 }
625 611
626 Self::set_baudrate_inner(config.baudrate); 612 Self::set_baudrate_inner(config.baudrate);
627 613
628 let (pen, eps) = match config.parity { 614 let (pen, eps) = match config.parity {
629 Parity::ParityNone => (false, false), 615 Parity::ParityNone => (false, false),
630 Parity::ParityOdd => (true, false), 616 Parity::ParityOdd => (true, false),
631 Parity::ParityEven => (true, true), 617 Parity::ParityEven => (true, true),
632 }; 618 };
633 619
634 r.uartlcr_h().write(|w| { 620 r.uartlcr_h().write(|w| {
635 w.set_wlen(config.data_bits.bits()); 621 w.set_wlen(config.data_bits.bits());
636 w.set_stp2(config.stop_bits == StopBits::STOP2); 622 w.set_stp2(config.stop_bits == StopBits::STOP2);
637 w.set_pen(pen); 623 w.set_pen(pen);
638 w.set_eps(eps); 624 w.set_eps(eps);
639 w.set_fen(true); 625 w.set_fen(true);
640 }); 626 });
641 627
642 r.uartifls().write(|w| { 628 r.uartifls().write(|w| {
643 w.set_rxiflsel(0b000); 629 w.set_rxiflsel(0b000);
644 w.set_txiflsel(0b000); 630 w.set_txiflsel(0b000);
645 }); 631 });
646 632
647 r.uartcr().write(|w| { 633 r.uartcr().write(|w| {
648 w.set_uarten(true); 634 w.set_uarten(true);
649 w.set_rxe(true); 635 w.set_rxe(true);
650 w.set_txe(true); 636 w.set_txe(true);
651 w.set_ctsen(cts.is_some()); 637 w.set_ctsen(cts.is_some());
652 w.set_rtsen(rts.is_some()); 638 w.set_rtsen(rts.is_some());
653 }); 639 });
654 }
655 } 640 }
656 641
657 /// sets baudrate on runtime 642 /// sets baudrate on runtime
@@ -676,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
676 baud_fbrd = 0; 661 baud_fbrd = 0;
677 } 662 }
678 663
679 unsafe { 664 // Load PL011's baud divisor registers
680 // Load PL011's baud divisor registers 665 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
681 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 666 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
682 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
683 667
684 // PL011 needs a (dummy) line control register write to latch in the 668 // PL011 needs a (dummy) line control register write to latch in the
685 // divisors. We don't want to actually change LCR contents here. 669 // divisors. We don't want to actually change LCR contents here.
686 r.uartlcr_h().modify(|_| {}); 670 r.uartlcr_h().modify(|_| {});
687 }
688 } 671 }
689} 672}
690 673
@@ -733,24 +716,22 @@ mod eh02 {
733 type Error = Error; 716 type Error = Error;
734 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 717 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
735 let r = T::regs(); 718 let r = T::regs();
736 unsafe { 719 if r.uartfr().read().rxfe() {
737 if r.uartfr().read().rxfe() { 720 return Err(nb::Error::WouldBlock);
738 return Err(nb::Error::WouldBlock); 721 }
739 }
740 722
741 let dr = r.uartdr().read(); 723 let dr = r.uartdr().read();
742 724
743 if dr.oe() { 725 if dr.oe() {
744 Err(nb::Error::Other(Error::Overrun)) 726 Err(nb::Error::Other(Error::Overrun))
745 } else if dr.be() { 727 } else if dr.be() {
746 Err(nb::Error::Other(Error::Break)) 728 Err(nb::Error::Other(Error::Break))
747 } else if dr.pe() { 729 } else if dr.pe() {
748 Err(nb::Error::Other(Error::Parity)) 730 Err(nb::Error::Other(Error::Parity))
749 } else if dr.fe() { 731 } else if dr.fe() {
750 Err(nb::Error::Other(Error::Framing)) 732 Err(nb::Error::Other(Error::Framing))
751 } else { 733 } else {
752 Ok(dr.data()) 734 Ok(dr.data())
753 }
754 } 735 }
755 } 736 }
756 } 737 }
@@ -760,22 +741,18 @@ mod eh02 {
760 741
761 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 742 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
762 let r = T::regs(); 743 let r = T::regs();
763 unsafe { 744 if r.uartfr().read().txff() {
764 if r.uartfr().read().txff() { 745 return Err(nb::Error::WouldBlock);
765 return Err(nb::Error::WouldBlock);
766 }
767
768 r.uartdr().write(|w| w.set_data(word));
769 } 746 }
747
748 r.uartdr().write(|w| w.set_data(word));
770 Ok(()) 749 Ok(())
771 } 750 }
772 751
773 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { 752 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
774 let r = T::regs(); 753 let r = T::regs();
775 unsafe { 754 if !r.uartfr().read().txfe() {
776 if !r.uartfr().read().txfe() { 755 return Err(nb::Error::WouldBlock);
777 return Err(nb::Error::WouldBlock);
778 }
779 } 756 }
780 Ok(()) 757 Ok(())
781 } 758 }
@@ -856,22 +833,20 @@ mod eh1 {
856 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { 833 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
857 fn read(&mut self) -> nb::Result<u8, Self::Error> { 834 fn read(&mut self) -> nb::Result<u8, Self::Error> {
858 let r = T::regs(); 835 let r = T::regs();
859 unsafe { 836 let dr = r.uartdr().read();
860 let dr = r.uartdr().read(); 837
861 838 if dr.oe() {
862 if dr.oe() { 839 Err(nb::Error::Other(Error::Overrun))
863 Err(nb::Error::Other(Error::Overrun)) 840 } else if dr.be() {
864 } else if dr.be() { 841 Err(nb::Error::Other(Error::Break))
865 Err(nb::Error::Other(Error::Break)) 842 } else if dr.pe() {
866 } else if dr.pe() { 843 Err(nb::Error::Other(Error::Parity))
867 Err(nb::Error::Other(Error::Parity)) 844 } else if dr.fe() {
868 } else if dr.fe() { 845 Err(nb::Error::Other(Error::Framing))
869 Err(nb::Error::Other(Error::Framing)) 846 } else if dr.fe() {
870 } else if dr.fe() { 847 Ok(dr.data())
871 Ok(dr.data()) 848 } else {
872 } else { 849 Err(nb::Error::WouldBlock)
873 Err(nb::Error::WouldBlock)
874 }
875 } 850 }
876 } 851 }
877 } 852 }
@@ -932,7 +907,7 @@ mod sealed {
932 const TX_DREQ: u8; 907 const TX_DREQ: u8;
933 const RX_DREQ: u8; 908 const RX_DREQ: u8;
934 909
935 type Interrupt: crate::interrupt::Interrupt; 910 type Interrupt: interrupt::typelevel::Interrupt;
936 911
937 fn regs() -> pac::uart::Uart; 912 fn regs() -> pac::uart::Uart;
938 913
@@ -970,7 +945,7 @@ macro_rules! impl_instance {
970 const TX_DREQ: u8 = $tx_dreq; 945 const TX_DREQ: u8 = $tx_dreq;
971 const RX_DREQ: u8 = $rx_dreq; 946 const RX_DREQ: u8 = $rx_dreq;
972 947
973 type Interrupt = crate::interrupt::$irq; 948 type Interrupt = crate::interrupt::typelevel::$irq;
974 949
975 fn regs() -> pac::uart::Uart { 950 fn regs() -> pac::uart::Uart {
976 pac::$inst 951 pac::$inst
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index fada2790f..1900ab416 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -4,15 +4,14 @@ use core::slice;
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 embassy_cortex_m::interrupt::{self, Binding};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb_driver as driver; 8use embassy_usb_driver as driver;
10use embassy_usb_driver::{ 9use embassy_usb_driver::{
11 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 10 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
12}; 11};
13 12
14use crate::interrupt::{Interrupt, InterruptExt}; 13use crate::interrupt::typelevel::{Binding, Interrupt};
15use crate::{pac, peripherals, Peripheral, RegExt}; 14use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
16 15
17pub(crate) mod sealed { 16pub(crate) mod sealed {
18 pub trait Instance { 17 pub trait Instance {
@@ -22,7 +21,7 @@ pub(crate) mod sealed {
22} 21}
23 22
24pub trait Instance: sealed::Instance + 'static { 23pub trait Instance: sealed::Instance + 'static {
25 type Interrupt: Interrupt; 24 type Interrupt: interrupt::typelevel::Interrupt;
26} 25}
27 26
28impl crate::usb::sealed::Instance for peripherals::USB { 27impl crate::usb::sealed::Instance for peripherals::USB {
@@ -35,12 +34,12 @@ impl crate::usb::sealed::Instance for peripherals::USB {
35} 34}
36 35
37impl crate::usb::Instance for peripherals::USB { 36impl crate::usb::Instance for peripherals::USB {
38 type Interrupt = crate::interrupt::USBCTRL_IRQ; 37 type Interrupt = crate::interrupt::typelevel::USBCTRL_IRQ;
39} 38}
40 39
41const EP_COUNT: usize = 16; 40const EP_COUNT: usize = 16;
42const EP_MEMORY_SIZE: usize = 4096; 41const EP_MEMORY_SIZE: usize = 4096;
43const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0; 42const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8;
44 43
45const NEW_AW: AtomicWaker = AtomicWaker::new(); 44const NEW_AW: AtomicWaker = AtomicWaker::new();
46static BUS_WAKER: AtomicWaker = NEW_AW; 45static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -106,15 +105,13 @@ pub struct Driver<'d, T: Instance> {
106 105
107impl<'d, T: Instance> Driver<'d, T> { 106impl<'d, T: Instance> Driver<'d, T> {
108 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self { 107 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
109 unsafe { 108 T::Interrupt::unpend();
110 T::Interrupt::steal().unpend(); 109 unsafe { T::Interrupt::enable() };
111 T::Interrupt::steal().enable();
112 }
113 110
114 let regs = T::regs(); 111 let regs = T::regs();
115 unsafe { 112 unsafe {
116 // zero fill regs 113 // zero fill regs
117 let p = regs.0 as *mut u32; 114 let p = regs.as_ptr() as *mut u32;
118 for i in 0..0x9c / 4 { 115 for i in 0..0x9c / 4 {
119 p.add(i).write_volatile(0) 116 p.add(i).write_volatile(0)
120 } 117 }
@@ -124,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> {
124 for i in 0..0x100 / 4 { 121 for i in 0..0x100 / 4 {
125 p.add(i).write_volatile(0) 122 p.add(i).write_volatile(0)
126 } 123 }
127
128 regs.usb_muxing().write(|w| {
129 w.set_to_phy(true);
130 w.set_softcon(true);
131 });
132 regs.usb_pwr().write(|w| {
133 w.set_vbus_detect(true);
134 w.set_vbus_detect_override_en(true);
135 });
136 regs.main_ctrl().write(|w| {
137 w.set_controller_en(true);
138 });
139 } 124 }
140 125
126 regs.usb_muxing().write(|w| {
127 w.set_to_phy(true);
128 w.set_softcon(true);
129 });
130 regs.usb_pwr().write(|w| {
131 w.set_vbus_detect(true);
132 w.set_vbus_detect_override_en(true);
133 });
134 regs.main_ctrl().write(|w| {
135 w.set_controller_en(true);
136 });
137
141 // Initialize the bus so that it signals that power is available 138 // Initialize the bus so that it signals that power is available
142 BUS_WAKER.wake(); 139 BUS_WAKER.wake();
143 140
@@ -216,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> {
216 }; 213 };
217 214
218 match D::dir() { 215 match D::dir() {
219 Direction::Out => unsafe { 216 Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| {
220 T::dpram().ep_out_control(index - 1).write(|w| { 217 w.set_enable(false);
221 w.set_enable(false); 218 w.set_buffer_address(addr);
222 w.set_buffer_address(addr); 219 w.set_interrupt_per_buff(true);
223 w.set_interrupt_per_buff(true); 220 w.set_endpoint_type(ep_type_reg);
224 w.set_endpoint_type(ep_type_reg); 221 }),
225 }) 222 Direction::In => T::dpram().ep_in_control(index - 1).write(|w| {
226 }, 223 w.set_enable(false);
227 Direction::In => unsafe { 224 w.set_buffer_address(addr);
228 T::dpram().ep_in_control(index - 1).write(|w| { 225 w.set_interrupt_per_buff(true);
229 w.set_enable(false); 226 w.set_endpoint_type(ep_type_reg);
230 w.set_buffer_address(addr); 227 }),
231 w.set_interrupt_per_buff(true);
232 w.set_endpoint_type(ep_type_reg);
233 })
234 },
235 } 228 }
236 229
237 Ok(Endpoint { 230 Ok(Endpoint {
@@ -251,7 +244,7 @@ pub struct InterruptHandler<T: Instance> {
251 _uart: PhantomData<T>, 244 _uart: PhantomData<T>,
252} 245}
253 246
254impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 247impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
255 unsafe fn on_interrupt() { 248 unsafe fn on_interrupt() {
256 let regs = T::regs(); 249 let regs = T::regs();
257 //let x = regs.istr().read().0; 250 //let x = regs.istr().read().0;
@@ -318,22 +311,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
318 311
319 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 312 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
320 let regs = T::regs(); 313 let regs = T::regs();
321 unsafe { 314 regs.inte().write(|w| {
322 regs.inte().write(|w| { 315 w.set_bus_reset(true);
323 w.set_bus_reset(true); 316 w.set_buff_status(true);
324 w.set_buff_status(true); 317 w.set_dev_resume_from_host(true);
325 w.set_dev_resume_from_host(true); 318 w.set_dev_suspend(true);
326 w.set_dev_suspend(true); 319 w.set_setup_req(true);
327 w.set_setup_req(true); 320 });
328 }); 321 regs.int_ep_ctrl().write(|w| {
329 regs.int_ep_ctrl().write(|w| { 322 w.set_int_ep_active(0xFFFE); // all EPs
330 w.set_int_ep_active(0xFFFE); // all EPs 323 });
331 }); 324 regs.sie_ctrl().write(|w| {
332 regs.sie_ctrl().write(|w| { 325 w.set_ep0_int_1buf(true);
333 w.set_ep0_int_1buf(true); 326 w.set_pullup_en(true);
334 w.set_pullup_en(true); 327 });
335 }) 328
336 }
337 trace!("enabled"); 329 trace!("enabled");
338 330
339 ( 331 (
@@ -358,7 +350,7 @@ pub struct Bus<'d, T: Instance> {
358 350
359impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 351impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
360 async fn poll(&mut self) -> Event { 352 async fn poll(&mut self) -> Event {
361 poll_fn(move |cx| unsafe { 353 poll_fn(move |cx| {
362 BUS_WAKER.register(cx.waker()); 354 BUS_WAKER.register(cx.waker());
363 355
364 if !self.inited { 356 if !self.inited {
@@ -428,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
428 420
429 let n = ep_addr.index(); 421 let n = ep_addr.index();
430 match ep_addr.direction() { 422 match ep_addr.direction() {
431 Direction::In => unsafe { 423 Direction::In => {
432 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); 424 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
433 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { 425 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
434 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before 426 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
435 }); 427 });
436 EP_IN_WAKERS[n].wake(); 428 EP_IN_WAKERS[n].wake();
437 }, 429 }
438 Direction::Out => unsafe { 430 Direction::Out => {
439 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); 431 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
440 432
441 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { 433 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@@ -449,7 +441,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
449 w.set_available(0, true); 441 w.set_available(0, true);
450 }); 442 });
451 EP_OUT_WAKERS[n].wake(); 443 EP_OUT_WAKERS[n].wake();
452 }, 444 }
453 } 445 }
454 } 446 }
455 447
@@ -507,7 +499,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
507 let index = self.info.addr.index(); 499 let index = self.info.addr.index();
508 poll_fn(|cx| { 500 poll_fn(|cx| {
509 EP_IN_WAKERS[index].register(cx.waker()); 501 EP_IN_WAKERS[index].register(cx.waker());
510 let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; 502 let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read();
511 if val.enable() { 503 if val.enable() {
512 Poll::Ready(()) 504 Poll::Ready(())
513 } else { 505 } else {
@@ -529,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
529 let index = self.info.addr.index(); 521 let index = self.info.addr.index();
530 poll_fn(|cx| { 522 poll_fn(|cx| {
531 EP_OUT_WAKERS[index].register(cx.waker()); 523 EP_OUT_WAKERS[index].register(cx.waker());
532 let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; 524 let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read();
533 if val.enable() { 525 if val.enable() {
534 Poll::Ready(()) 526 Poll::Ready(())
535 } else { 527 } else {
@@ -545,7 +537,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
545 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 537 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
546 trace!("READ WAITING, buf.len() = {}", buf.len()); 538 trace!("READ WAITING, buf.len() = {}", buf.len());
547 let index = self.info.addr.index(); 539 let index = self.info.addr.index();
548 let val = poll_fn(|cx| unsafe { 540 let val = poll_fn(|cx| {
549 EP_OUT_WAKERS[index].register(cx.waker()); 541 EP_OUT_WAKERS[index].register(cx.waker());
550 let val = T::dpram().ep_out_buffer_control(index).read(); 542 let val = T::dpram().ep_out_buffer_control(index).read();
551 if val.available(0) { 543 if val.available(0) {
@@ -564,19 +556,17 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
564 556
565 trace!("READ OK, rx_len = {}", rx_len); 557 trace!("READ OK, rx_len = {}", rx_len);
566 558
567 unsafe { 559 let pid = !val.pid(0);
568 let pid = !val.pid(0); 560 T::dpram().ep_out_buffer_control(index).write(|w| {
569 T::dpram().ep_out_buffer_control(index).write(|w| { 561 w.set_pid(0, pid);
570 w.set_pid(0, pid); 562 w.set_length(0, self.info.max_packet_size);
571 w.set_length(0, self.info.max_packet_size); 563 });
572 }); 564 cortex_m::asm::delay(12);
573 cortex_m::asm::delay(12); 565 T::dpram().ep_out_buffer_control(index).write(|w| {
574 T::dpram().ep_out_buffer_control(index).write(|w| { 566 w.set_pid(0, pid);
575 w.set_pid(0, pid); 567 w.set_length(0, self.info.max_packet_size);
576 w.set_length(0, self.info.max_packet_size); 568 w.set_available(0, true);
577 w.set_available(0, true); 569 });
578 });
579 }
580 570
581 Ok(rx_len) 571 Ok(rx_len)
582 } 572 }
@@ -591,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
591 trace!("WRITE WAITING"); 581 trace!("WRITE WAITING");
592 582
593 let index = self.info.addr.index(); 583 let index = self.info.addr.index();
594 let val = poll_fn(|cx| unsafe { 584 let val = poll_fn(|cx| {
595 EP_IN_WAKERS[index].register(cx.waker()); 585 EP_IN_WAKERS[index].register(cx.waker());
596 let val = T::dpram().ep_in_buffer_control(index).read(); 586 let val = T::dpram().ep_in_buffer_control(index).read();
597 if val.available(0) { 587 if val.available(0) {
@@ -604,21 +594,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
604 594
605 self.buf.write(buf); 595 self.buf.write(buf);
606 596
607 unsafe { 597 let pid = !val.pid(0);
608 let pid = !val.pid(0); 598 T::dpram().ep_in_buffer_control(index).write(|w| {
609 T::dpram().ep_in_buffer_control(index).write(|w| { 599 w.set_pid(0, pid);
610 w.set_pid(0, pid); 600 w.set_length(0, buf.len() as _);
611 w.set_length(0, buf.len() as _); 601 w.set_full(0, true);
612 w.set_full(0, true); 602 });
613 }); 603 cortex_m::asm::delay(12);
614 cortex_m::asm::delay(12); 604 T::dpram().ep_in_buffer_control(index).write(|w| {
615 T::dpram().ep_in_buffer_control(index).write(|w| { 605 w.set_pid(0, pid);
616 w.set_pid(0, pid); 606 w.set_length(0, buf.len() as _);
617 w.set_length(0, buf.len() as _); 607 w.set_full(0, true);
618 w.set_full(0, true); 608 w.set_available(0, true);
619 w.set_available(0, true); 609 });
620 });
621 }
622 610
623 trace!("WRITE OK"); 611 trace!("WRITE OK");
624 612
@@ -640,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
640 loop { 628 loop {
641 trace!("SETUP read waiting"); 629 trace!("SETUP read waiting");
642 let regs = T::regs(); 630 let regs = T::regs();
643 unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) }; 631 regs.inte().write_set(|w| w.set_setup_req(true));
644 632
645 poll_fn(|cx| unsafe { 633 poll_fn(|cx| {
646 EP_OUT_WAKERS[0].register(cx.waker()); 634 EP_OUT_WAKERS[0].register(cx.waker());
647 let regs = T::regs(); 635 let regs = T::regs();
648 if regs.sie_status().read().setup_rec() { 636 if regs.sie_status().read().setup_rec() {
@@ -657,13 +645,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
657 EndpointBuffer::<T>::new(0, 8).read(&mut buf); 645 EndpointBuffer::<T>::new(0, 8).read(&mut buf);
658 646
659 let regs = T::regs(); 647 let regs = T::regs();
660 unsafe { 648 regs.sie_status().write(|w| w.set_setup_rec(true));
661 regs.sie_status().write(|w| w.set_setup_rec(true));
662 649
663 // set PID to 0, so (after toggling) first DATA is PID 1 650 // set PID to 0, so (after toggling) first DATA is PID 1
664 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); 651 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
665 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); 652 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
666 }
667 653
668 trace!("SETUP read ok"); 654 trace!("SETUP read ok");
669 return buf; 655 return buf;
@@ -671,23 +657,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
671 } 657 }
672 658
673 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { 659 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
674 unsafe { 660 let bufcontrol = T::dpram().ep_out_buffer_control(0);
675 let bufcontrol = T::dpram().ep_out_buffer_control(0); 661 let pid = !bufcontrol.read().pid(0);
676 let pid = !bufcontrol.read().pid(0); 662 bufcontrol.write(|w| {
677 bufcontrol.write(|w| { 663 w.set_length(0, self.max_packet_size);
678 w.set_length(0, self.max_packet_size); 664 w.set_pid(0, pid);
679 w.set_pid(0, pid); 665 });
680 }); 666 cortex_m::asm::delay(12);
681 cortex_m::asm::delay(12); 667 bufcontrol.write(|w| {
682 bufcontrol.write(|w| { 668 w.set_length(0, self.max_packet_size);
683 w.set_length(0, self.max_packet_size); 669 w.set_pid(0, pid);
684 w.set_pid(0, pid); 670 w.set_available(0, true);
685 w.set_available(0, true); 671 });
686 });
687 }
688 672
689 trace!("control: data_out len={} first={} last={}", buf.len(), first, last); 673 trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
690 let val = poll_fn(|cx| unsafe { 674 let val = poll_fn(|cx| {
691 EP_OUT_WAKERS[0].register(cx.waker()); 675 EP_OUT_WAKERS[0].register(cx.waker());
692 let val = T::dpram().ep_out_buffer_control(0).read(); 676 let val = T::dpram().ep_out_buffer_control(0).read();
693 if val.available(0) { 677 if val.available(0) {
@@ -717,24 +701,22 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
717 } 701 }
718 EndpointBuffer::<T>::new(0x100, 64).write(data); 702 EndpointBuffer::<T>::new(0x100, 64).write(data);
719 703
720 unsafe { 704 let bufcontrol = T::dpram().ep_in_buffer_control(0);
721 let bufcontrol = T::dpram().ep_in_buffer_control(0); 705 let pid = !bufcontrol.read().pid(0);
722 let pid = !bufcontrol.read().pid(0); 706 bufcontrol.write(|w| {
723 bufcontrol.write(|w| { 707 w.set_length(0, data.len() as _);
724 w.set_length(0, data.len() as _); 708 w.set_pid(0, pid);
725 w.set_pid(0, pid); 709 w.set_full(0, true);
726 w.set_full(0, true); 710 });
727 }); 711 cortex_m::asm::delay(12);
728 cortex_m::asm::delay(12); 712 bufcontrol.write(|w| {
729 bufcontrol.write(|w| { 713 w.set_length(0, data.len() as _);
730 w.set_length(0, data.len() as _); 714 w.set_pid(0, pid);
731 w.set_pid(0, pid); 715 w.set_full(0, true);
732 w.set_full(0, true); 716 w.set_available(0, true);
733 w.set_available(0, true); 717 });
734 });
735 }
736 718
737 poll_fn(|cx| unsafe { 719 poll_fn(|cx| {
738 EP_IN_WAKERS[0].register(cx.waker()); 720 EP_IN_WAKERS[0].register(cx.waker());
739 let bufcontrol = T::dpram().ep_in_buffer_control(0); 721 let bufcontrol = T::dpram().ep_in_buffer_control(0);
740 if bufcontrol.read().available(0) { 722 if bufcontrol.read().available(0) {
@@ -748,48 +730,44 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
748 730
749 if last { 731 if last {
750 // prepare status phase right away. 732 // prepare status phase right away.
751 unsafe { 733 let bufcontrol = T::dpram().ep_out_buffer_control(0);
752 let bufcontrol = T::dpram().ep_out_buffer_control(0);
753 bufcontrol.write(|w| {
754 w.set_length(0, 0);
755 w.set_pid(0, true);
756 });
757 cortex_m::asm::delay(12);
758 bufcontrol.write(|w| {
759 w.set_length(0, 0);
760 w.set_pid(0, true);
761 w.set_available(0, true);
762 });
763 }
764 }
765
766 Ok(())
767 }
768
769 async fn accept(&mut self) {
770 trace!("control: accept");
771
772 let bufcontrol = T::dpram().ep_in_buffer_control(0);
773 unsafe {
774 bufcontrol.write(|w| { 734 bufcontrol.write(|w| {
775 w.set_length(0, 0); 735 w.set_length(0, 0);
776 w.set_pid(0, true); 736 w.set_pid(0, true);
777 w.set_full(0, true);
778 }); 737 });
779 cortex_m::asm::delay(12); 738 cortex_m::asm::delay(12);
780 bufcontrol.write(|w| { 739 bufcontrol.write(|w| {
781 w.set_length(0, 0); 740 w.set_length(0, 0);
782 w.set_pid(0, true); 741 w.set_pid(0, true);
783 w.set_full(0, true);
784 w.set_available(0, true); 742 w.set_available(0, true);
785 }); 743 });
786 } 744 }
787 745
746 Ok(())
747 }
748
749 async fn accept(&mut self) {
750 trace!("control: accept");
751
752 let bufcontrol = T::dpram().ep_in_buffer_control(0);
753 bufcontrol.write(|w| {
754 w.set_length(0, 0);
755 w.set_pid(0, true);
756 w.set_full(0, true);
757 });
758 cortex_m::asm::delay(12);
759 bufcontrol.write(|w| {
760 w.set_length(0, 0);
761 w.set_pid(0, true);
762 w.set_full(0, true);
763 w.set_available(0, true);
764 });
765
788 // wait for completion before returning, needed so 766 // wait for completion before returning, needed so
789 // set_address() doesn't happen early. 767 // set_address() doesn't happen early.
790 poll_fn(|cx| { 768 poll_fn(|cx| {
791 EP_IN_WAKERS[0].register(cx.waker()); 769 EP_IN_WAKERS[0].register(cx.waker());
792 if unsafe { bufcontrol.read().available(0) } { 770 if bufcontrol.read().available(0) {
793 Poll::Pending 771 Poll::Pending
794 } else { 772 } else {
795 Poll::Ready(()) 773 Poll::Ready(())
@@ -802,14 +780,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
802 trace!("control: reject"); 780 trace!("control: reject");
803 781
804 let regs = T::regs(); 782 let regs = T::regs();
805 unsafe { 783 regs.ep_stall_arm().write_set(|w| {
806 regs.ep_stall_arm().write_set(|w| { 784 w.set_ep0_in(true);
807 w.set_ep0_in(true); 785 w.set_ep0_out(true);
808 w.set_ep0_out(true); 786 });
809 }); 787 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
810 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); 788 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
811 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
812 }
813 } 789 }
814 790
815 async fn accept_set_address(&mut self, addr: u8) { 791 async fn accept_set_address(&mut self, addr: u8) {
@@ -817,6 +793,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
817 793
818 let regs = T::regs(); 794 let regs = T::regs();
819 trace!("setting addr: {}", addr); 795 trace!("setting addr: {}", addr);
820 unsafe { regs.addr_endp().write(|w| w.set_address(addr)) } 796 regs.addr_endp().write(|w| w.set_address(addr))
821 } 797 }
822} 798}
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index 78a295ae7..d37795cc9 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -35,45 +35,37 @@ impl Watchdog {
35 /// * `cycles` - Total number of tick cycles before the next tick is generated. 35 /// * `cycles` - Total number of tick cycles before the next tick is generated.
36 /// It is expected to be the frequency in MHz of clk_ref. 36 /// It is expected to be the frequency in MHz of clk_ref.
37 pub fn enable_tick_generation(&mut self, cycles: u8) { 37 pub fn enable_tick_generation(&mut self, cycles: u8) {
38 unsafe { 38 let watchdog = pac::WATCHDOG;
39 let watchdog = pac::WATCHDOG; 39 watchdog.tick().write(|w| {
40 watchdog.tick().write(|w| { 40 w.set_enable(true);
41 w.set_enable(true); 41 w.set_cycles(cycles.into())
42 w.set_cycles(cycles.into()) 42 });
43 });
44 }
45 } 43 }
46 44
47 /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode 45 /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
48 /// or when JTAG is accessing bus fabric 46 /// or when JTAG is accessing bus fabric
49 pub fn pause_on_debug(&mut self, pause: bool) { 47 pub fn pause_on_debug(&mut self, pause: bool) {
50 unsafe { 48 let watchdog = pac::WATCHDOG;
51 let watchdog = pac::WATCHDOG; 49 watchdog.ctrl().write(|w| {
52 watchdog.ctrl().write(|w| { 50 w.set_pause_dbg0(pause);
53 w.set_pause_dbg0(pause); 51 w.set_pause_dbg1(pause);
54 w.set_pause_dbg1(pause); 52 w.set_pause_jtag(pause);
55 w.set_pause_jtag(pause); 53 })
56 })
57 }
58 } 54 }
59 55
60 fn load_counter(&self, counter: u32) { 56 fn load_counter(&self, counter: u32) {
61 unsafe { 57 let watchdog = pac::WATCHDOG;
62 let watchdog = pac::WATCHDOG; 58 watchdog.load().write_value(pac::watchdog::regs::Load(counter));
63 watchdog.load().write_value(pac::watchdog::regs::Load(counter));
64 }
65 } 59 }
66 60
67 fn enable(&self, bit: bool) { 61 fn enable(&self, bit: bool) {
68 unsafe { 62 let watchdog = pac::WATCHDOG;
69 let watchdog = pac::WATCHDOG; 63 watchdog.ctrl().write(|w| w.set_enable(bit))
70 watchdog.ctrl().write(|w| w.set_enable(bit))
71 }
72 } 64 }
73 65
74 // Configure which hardware will be reset by the watchdog 66 // Configure which hardware will be reset by the watchdog
75 // (everything except ROSC, XOSC) 67 // (everything except ROSC, XOSC)
76 unsafe fn configure_wdog_reset_triggers(&self) { 68 fn configure_wdog_reset_triggers(&self) {
77 let psm = pac::PSM; 69 let psm = pac::PSM;
78 psm.wdsel().write_value(pac::psm::regs::Wdsel( 70 psm.wdsel().write_value(pac::psm::regs::Wdsel(
79 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), 71 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
@@ -100,23 +92,19 @@ impl Watchdog {
100 self.load_value = delay_us * 2; 92 self.load_value = delay_us * 2;
101 93
102 self.enable(false); 94 self.enable(false);
103 unsafe { 95 self.configure_wdog_reset_triggers();
104 self.configure_wdog_reset_triggers();
105 }
106 self.load_counter(self.load_value); 96 self.load_counter(self.load_value);
107 self.enable(true); 97 self.enable(true);
108 } 98 }
109 99
110 /// Trigger a system reset 100 /// Trigger a system reset
111 pub fn trigger_reset(&mut self) { 101 pub fn trigger_reset(&mut self) {
112 unsafe { 102 self.configure_wdog_reset_triggers();
113 self.configure_wdog_reset_triggers(); 103 self.pause_on_debug(false);
114 self.pause_on_debug(false); 104 self.enable(true);
115 self.enable(true); 105 let watchdog = pac::WATCHDOG;
116 let watchdog = pac::WATCHDOG; 106 watchdog.ctrl().write(|w| {
117 watchdog.ctrl().write(|w| { 107 w.set_trigger(true);
118 w.set_trigger(true); 108 })
119 })
120 }
121 } 109 }
122} 110}
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
new file mode 100644
index 000000000..1c1b57b36
--- /dev/null
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -0,0 +1,45 @@
1[package]
2name = "embassy-stm32-wpan"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[package.metadata.embassy_docs]
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src"
10target = "thumbv7em-none-eabihf"
11features = ["stm32wb55rg"]
12
13[dependencies]
14embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
15embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
16embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
17embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
18embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
20
21defmt = { version = "0.3", optional = true }
22cortex-m = "0.7.6"
23heapless = "0.7.16"
24
25bit_field = "0.10.2"
26
27[features]
28defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
29
30stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
31stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
32stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
33stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ]
34stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ]
35stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ]
36stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ]
37stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ]
38stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ]
39stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ]
40stm32wb55re = [ "embassy-stm32/stm32wb55re" ]
41stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
42stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
43stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
44stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
45stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
new file mode 100644
index 000000000..4edf73d59
--- /dev/null
+++ b/embassy-stm32-wpan/build.rs
@@ -0,0 +1,34 @@
1use std::env;
2
3fn main() {
4 match env::vars()
5 .map(|(a, _)| a)
6 .filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
7 .get_one()
8 {
9 Ok(_) => {}
10 Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
11 Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
12 }
13}
14
15enum GetOneError {
16 None,
17 Multiple,
18}
19
20trait IteratorExt: Iterator {
21 fn get_one(self) -> Result<Self::Item, GetOneError>;
22}
23
24impl<T: Iterator> IteratorExt for T {
25 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
26 match self.next() {
27 None => Err(GetOneError::None),
28 Some(res) => match self.next() {
29 Some(_) => Err(GetOneError::Multiple),
30 None => Ok(res),
31 },
32 }
33 }
34}
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs
new file mode 100644
index 000000000..f0bd6f48c
--- /dev/null
+++ b/embassy-stm32-wpan/src/ble.rs
@@ -0,0 +1,63 @@
1use core::marker::PhantomData;
2
3use embassy_stm32::ipcc::Ipcc;
4
5use crate::cmd::CmdPacket;
6use crate::consts::TlPacketType;
7use crate::evt::EvtBox;
8use crate::tables::BleTable;
9use crate::unsafe_linked_list::LinkedListNode;
10use crate::{channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
11
12pub struct Ble {
13 phantom: PhantomData<Ble>,
14}
15
16impl Ble {
17 pub(crate) fn new() -> Self {
18 unsafe {
19 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
20
21 TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
22 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
23 pcs_buffer: CS_BUFFER.as_ptr().cast(),
24 pevt_queue: EVT_QUEUE.as_ptr().cast(),
25 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
26 });
27 }
28
29 Self { phantom: PhantomData }
30 }
31 /// `HW_IPCC_BLE_EvtNot`
32 pub async fn read(&self) -> EvtBox {
33 Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
34 if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
35 Some(EvtBox::new(node_ptr.cast()))
36 } else {
37 None
38 }
39 })
40 .await
41 }
42
43 /// `TL_BLE_SendCmd`
44 pub async fn write(&self, opcode: u16, payload: &[u8]) {
45 Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe {
46 CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload);
47 })
48 .await;
49 }
50
51 /// `TL_BLE_SendAclData`
52 pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
53 Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
54 CmdPacket::write_into(
55 HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
56 TlPacketType::AclData,
57 handle,
58 payload,
59 );
60 })
61 .await;
62 }
63}
diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32-wpan/src/channels.rs
index 25a065ba4..9a2be1cfa 100644
--- a/embassy-stm32/src/tl_mbox/channels.rs
+++ b/embassy-stm32-wpan/src/channels.rs
@@ -50,36 +50,30 @@
50//! 50//!
51 51
52pub mod cpu1 { 52pub mod cpu1 {
53 use crate::tl_mbox::ipcc::IpccChannel; 53 use embassy_stm32::ipcc::IpccChannel;
54 54
55 // Not used currently but reserved
56 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; 55 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
57 // Not used currently but reserved
58 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; 56 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
59 #[allow(dead_code)] // Not used currently but reserved
60 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 57 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
61 #[allow(dead_code)] // Not used currently but reserved 58 #[allow(dead_code)] // Not used currently but reserved
62 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; 59 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
63 #[allow(dead_code)] // Not used currently but reserved 60 #[allow(dead_code)] // Not used currently but reserved
64 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 61 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
65 // Not used currently but reserved
66 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
67 #[allow(dead_code)] // Not used currently but reserved 62 #[allow(dead_code)] // Not used currently but reserved
63 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
68 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 64 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
69 #[allow(dead_code)] // Not used currently but reserved 65 #[allow(dead_code)] // Not used currently but reserved
70 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 66 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
71 #[allow(dead_code)] // Not used currently but reserved 67 #[allow(dead_code)] // Not used currently but reserved
72 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 68 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
73 #[allow(dead_code)] // Not used currently but reserved
74 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; 69 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
75} 70}
76 71
77pub mod cpu2 { 72pub mod cpu2 {
78 use crate::tl_mbox::ipcc::IpccChannel; 73 use embassy_stm32::ipcc::IpccChannel;
79 74
80 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; 75 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
81 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; 76 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
82 #[allow(dead_code)] // Not used currently but reserved
83 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 77 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
84 #[allow(dead_code)] // Not used currently but reserved 78 #[allow(dead_code)] // Not used currently but reserved
85 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 79 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
@@ -88,10 +82,8 @@ pub mod cpu2 {
88 #[allow(dead_code)] // Not used currently but reserved 82 #[allow(dead_code)] // Not used currently but reserved
89 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 83 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
90 #[allow(dead_code)] // Not used currently but reserved 84 #[allow(dead_code)] // Not used currently but reserved
91 pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 85 pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
92 #[allow(dead_code)] // Not used currently but reserved
93 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; 86 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
94 #[allow(dead_code)] // Not used currently but reserved
95 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; 87 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
96 #[allow(dead_code)] // Not used currently but reserved 88 #[allow(dead_code)] // Not used currently but reserved
97 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; 89 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs
new file mode 100644
index 000000000..edca82390
--- /dev/null
+++ b/embassy-stm32-wpan/src/cmd.rs
@@ -0,0 +1,104 @@
1use core::ptr;
2
3use crate::consts::TlPacketType;
4use crate::PacketHeader;
5
6#[derive(Copy, Clone)]
7#[repr(C, packed)]
8pub struct Cmd {
9 pub cmd_code: u16,
10 pub payload_len: u8,
11 pub payload: [u8; 255],
12}
13
14impl Default for Cmd {
15 fn default() -> Self {
16 Self {
17 cmd_code: 0,
18 payload_len: 0,
19 payload: [0u8; 255],
20 }
21 }
22}
23
24#[derive(Copy, Clone, Default)]
25#[repr(C, packed)]
26pub struct CmdSerial {
27 pub ty: u8,
28 pub cmd: Cmd,
29}
30
31#[derive(Copy, Clone, Default)]
32#[repr(C, packed)]
33pub struct CmdSerialStub {
34 pub ty: u8,
35 pub cmd_code: u16,
36 pub payload_len: u8,
37}
38
39#[derive(Copy, Clone, Default)]
40#[repr(C, packed)]
41pub struct CmdPacket {
42 pub header: PacketHeader,
43 pub cmdserial: CmdSerial,
44}
45
46impl CmdPacket {
47 pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) {
48 let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub;
49 let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _;
50
51 ptr::write_volatile(
52 p_cmd_serial,
53 CmdSerialStub {
54 ty: packet_type as u8,
55 cmd_code: cmd_code,
56 payload_len: payload.len() as u8,
57 },
58 );
59
60 ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
61 }
62}
63
64#[derive(Copy, Clone)]
65#[repr(C, packed)]
66pub struct AclDataSerial {
67 pub ty: u8,
68 pub handle: u16,
69 pub length: u16,
70 pub acl_data: [u8; 1],
71}
72
73#[derive(Copy, Clone)]
74#[repr(C, packed)]
75pub struct AclDataSerialStub {
76 pub ty: u8,
77 pub handle: u16,
78 pub length: u16,
79}
80
81#[derive(Copy, Clone)]
82#[repr(C, packed)]
83pub struct AclDataPacket {
84 pub header: PacketHeader,
85 pub acl_data_serial: AclDataSerial,
86}
87
88impl AclDataPacket {
89 pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) {
90 let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub;
91 let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _;
92
93 ptr::write_volatile(
94 p_cmd_serial,
95 AclDataSerialStub {
96 ty: packet_type as u8,
97 handle: handle,
98 length: payload.len() as u16,
99 },
100 );
101
102 ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
103 }
104}
diff --git a/embassy-stm32/src/tl_mbox/consts.rs b/embassy-stm32-wpan/src/consts.rs
index e16a26cd0..caf26c06b 100644
--- a/embassy-stm32/src/tl_mbox/consts.rs
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -1,4 +1,6 @@
1#[derive(PartialEq)] 1use core::convert::TryFrom;
2
3#[derive(Debug)]
2#[repr(C)] 4#[repr(C)]
3pub enum TlPacketType { 5pub enum TlPacketType {
4 BleCmd = 0x01, 6 BleCmd = 0x01,
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
new file mode 100644
index 000000000..3a9d03576
--- /dev/null
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -0,0 +1,195 @@
1use core::{ptr, slice};
2
3use super::PacketHeader;
4use crate::mm;
5
6/**
7 * The payload of `Evt` for a command status event
8 */
9#[derive(Copy, Clone)]
10#[repr(C, packed)]
11pub struct CsEvt {
12 pub status: u8,
13 pub num_cmd: u8,
14 pub cmd_code: u16,
15}
16
17/**
18 * The payload of `Evt` for a command complete event
19 */
20#[derive(Copy, Clone, Default)]
21#[repr(C, packed)]
22pub struct CcEvt {
23 pub num_cmd: u8,
24 pub cmd_code: u16,
25 pub payload: [u8; 1],
26}
27
28impl CcEvt {
29 pub fn write(&self, buf: &mut [u8]) {
30 unsafe {
31 let len = core::mem::size_of::<CcEvt>();
32 assert!(buf.len() >= len);
33
34 let self_ptr: *const CcEvt = self;
35 let self_buf_ptr: *const u8 = self_ptr.cast();
36
37 core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len);
38 }
39 }
40}
41
42#[derive(Copy, Clone, Default)]
43#[repr(C, packed)]
44pub struct AsynchEvt {
45 sub_evt_code: u16,
46 payload: [u8; 1],
47}
48
49#[derive(Copy, Clone, Default)]
50#[repr(C, packed)]
51pub struct Evt {
52 pub evt_code: u8,
53 pub payload_len: u8,
54 pub payload: [u8; 1],
55}
56
57#[derive(Copy, Clone, Default)]
58#[repr(C, packed)]
59pub struct EvtSerial {
60 pub kind: u8,
61 pub evt: Evt,
62}
63
64#[derive(Copy, Clone, Default)]
65pub struct EvtStub {
66 pub kind: u8,
67 pub evt_code: u8,
68}
69
70/// This format shall be used for all events (asynchronous and command response) reported
71/// by the CPU2 except for the command response of a system command where the header is not there
72/// and the format to be used shall be `EvtSerial`.
73///
74/// ### Note:
75/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
76/// include the header and shall use `EvtPacket` format. Only the command response format on the
77/// system channel is different.
78#[derive(Copy, Clone, Default)]
79#[repr(C, packed)]
80pub struct EvtPacket {
81 pub header: PacketHeader,
82 pub evt_serial: EvtSerial,
83}
84
85impl EvtPacket {
86 pub fn kind(&self) -> u8 {
87 self.evt_serial.kind
88 }
89
90 pub fn evt(&self) -> &Evt {
91 &self.evt_serial.evt
92 }
93}
94
95/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
96/// on [`Drop`]
97#[derive(Debug)]
98pub struct EvtBox {
99 ptr: *mut EvtPacket,
100}
101
102unsafe impl Send for EvtBox {}
103impl EvtBox {
104 pub(super) fn new(ptr: *mut EvtPacket) -> Self {
105 Self { ptr }
106 }
107
108 /// Returns information about the event
109 pub fn stub(&self) -> EvtStub {
110 unsafe {
111 let p_evt_stub = &(*self.ptr).evt_serial as *const _ as *const EvtStub;
112
113 ptr::read_volatile(p_evt_stub)
114 }
115 }
116
117 pub fn payload<'a>(&self) -> &'a [u8] {
118 unsafe {
119 let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8;
120 let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8;
121
122 let payload_len = ptr::read_volatile(p_payload_len);
123
124 slice::from_raw_parts(p_payload, payload_len as usize)
125 }
126 }
127
128 // TODO: bring back acl
129
130 // /// writes an underlying [`EvtPacket`] into the provided buffer.
131 // /// Returns the number of bytes that were written.
132 // /// Returns an error if event kind is unknown or if provided buffer size is not enough.
133 // #[allow(clippy::result_unit_err)]
134 // pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
135 // unsafe {
136 // let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
137 //
138 // let evt_data: *const EvtPacket = self.ptr.cast();
139 // let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
140 // let evt_serial_buf: *const u8 = evt_serial.cast();
141 //
142 // let acl_data: *const AclDataPacket = self.ptr.cast();
143 // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
144 // let acl_serial_buf: *const u8 = acl_serial.cast();
145 //
146 // if let TlPacketType::AclData = evt_kind {
147 // let len = (*acl_serial).length as usize + 5;
148 // if len > buf.len() {
149 // return Err(());
150 // }
151 //
152 // core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
153 //
154 // Ok(len)
155 // } else {
156 // let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
157 // if len > buf.len() {
158 // return Err(());
159 // }
160 //
161 // core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
162 //
163 // Ok(len)
164 // }
165 // }
166 // }
167 //
168 // /// returns the size of a buffer required to hold this event
169 // #[allow(clippy::result_unit_err)]
170 // pub fn size(&self) -> Result<usize, ()> {
171 // unsafe {
172 // let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
173 //
174 // let evt_data: *const EvtPacket = self.ptr.cast();
175 // let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
176 //
177 // let acl_data: *const AclDataPacket = self.ptr.cast();
178 // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
179 //
180 // if let TlPacketType::AclData = evt_kind {
181 // Ok((*acl_serial).length as usize + 5)
182 // } else {
183 // Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
184 // }
185 // }
186 // }
187}
188
189impl Drop for EvtBox {
190 fn drop(&mut self) {
191 trace!("evt box drop packet");
192
193 unsafe { mm::MemoryManager::drop_event_packet(self.ptr) };
194 }
195}
diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-cortex-m/src/fmt.rs
+++ b/embassy-stm32-wpan/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
new file mode 100644
index 000000000..833db0df3
--- /dev/null
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -0,0 +1,255 @@
1#![no_std]
2
3// This must go FIRST so that all the other modules see its macros.
4pub mod fmt;
5
6use core::mem::MaybeUninit;
7use core::sync::atomic::{compiler_fence, Ordering};
8
9use ble::Ble;
10use cmd::CmdPacket;
11use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
12use embassy_stm32::interrupt;
13use embassy_stm32::interrupt::typelevel::Interrupt;
14use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler};
15use embassy_stm32::peripherals::IPCC;
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::channel::Channel;
18use embassy_sync::signal::Signal;
19use evt::{CcEvt, EvtBox};
20use mm::MemoryManager;
21use sys::Sys;
22use tables::{
23 BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
24};
25use unsafe_linked_list::LinkedListNode;
26
27pub mod ble;
28pub mod channels;
29pub mod cmd;
30pub mod consts;
31pub mod evt;
32pub mod mm;
33pub mod shci;
34pub mod sys;
35pub mod tables;
36pub mod unsafe_linked_list;
37
38#[link_section = "TL_REF_TABLE"]
39pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
40
41#[link_section = "MB_MEM1"]
42static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
43
44#[link_section = "MB_MEM1"]
45static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
46
47#[link_section = "MB_MEM1"]
48static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
49
50#[link_section = "MB_MEM1"]
51static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
52
53#[link_section = "MB_MEM1"]
54static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
55
56#[link_section = "MB_MEM1"]
57static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
58
59#[link_section = "MB_MEM1"]
60static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
61
62#[link_section = "MB_MEM2"]
63static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
64
65// Not in shared RAM
66static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
67
68#[allow(dead_code)] // Not used currently but reserved
69#[link_section = "MB_MEM2"]
70static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
71
72type PacketHeader = LinkedListNode;
73
74const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
75const TL_EVT_HEADER_SIZE: usize = 3;
76const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>();
77
78#[link_section = "MB_MEM2"]
79static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
80 MaybeUninit::uninit();
81
82#[link_section = "MB_MEM2"]
83static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
84
85#[link_section = "MB_MEM2"]
86static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
87
88#[link_section = "MB_MEM2"]
89pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
90
91/**
92 * Queue length of BLE Event
93 * This parameter defines the number of asynchronous events that can be stored in the HCI layer before
94 * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer
95 * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large
96 * enough to store all asynchronous events received in between.
97 * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events
98 * between the HCI command and its event.
99 * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small,
100 * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting
101 * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate
102 * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout).
103 */
104const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5;
105const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
106const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE;
107
108const fn divc(x: usize, y: usize) -> usize {
109 ((x) + (y) - 1) / (y)
110}
111
112const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
113
114#[link_section = "MB_MEM2"]
115static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
116
117#[link_section = "MB_MEM2"]
118static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
119 MaybeUninit::uninit();
120
121#[link_section = "MB_MEM2"]
122static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
123 MaybeUninit::uninit();
124
125#[link_section = "MB_MEM2"]
126static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
127
128#[link_section = "MB_MEM2"]
129// fuck these "magic" numbers from ST ---v---v
130static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
131
132// TODO: remove these items
133
134#[allow(dead_code)]
135/// current event that is produced during IPCC IRQ handler execution
136/// on SYS channel
137static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
138
139#[allow(dead_code)]
140/// last received Command Complete event
141static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
142
143static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
144
145pub struct TlMbox<'d> {
146 _ipcc: PeripheralRef<'d, IPCC>,
147
148 pub sys_subsystem: Sys,
149 pub mm_subsystem: MemoryManager,
150 pub ble_subsystem: Ble,
151}
152
153impl<'d> TlMbox<'d> {
154 pub fn init(
155 ipcc: impl Peripheral<P = IPCC> + 'd,
156 _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
157 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
158 config: Config,
159 ) -> Self {
160 into_ref!(ipcc);
161
162 unsafe {
163 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
164 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
165 ble_table: TL_BLE_TABLE.as_ptr(),
166 thread_table: TL_THREAD_TABLE.as_ptr(),
167 sys_table: TL_SYS_TABLE.as_ptr(),
168 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
169 traces_table: TL_TRACES_TABLE.as_ptr(),
170 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
171 // zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
172 // lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
173 // ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
174 });
175
176 TL_SYS_TABLE
177 .as_mut_ptr()
178 .write_volatile(MaybeUninit::zeroed().assume_init());
179 TL_DEVICE_INFO_TABLE
180 .as_mut_ptr()
181 .write_volatile(MaybeUninit::zeroed().assume_init());
182 TL_BLE_TABLE
183 .as_mut_ptr()
184 .write_volatile(MaybeUninit::zeroed().assume_init());
185 TL_THREAD_TABLE
186 .as_mut_ptr()
187 .write_volatile(MaybeUninit::zeroed().assume_init());
188 TL_MEM_MANAGER_TABLE
189 .as_mut_ptr()
190 .write_volatile(MaybeUninit::zeroed().assume_init());
191
192 TL_TRACES_TABLE
193 .as_mut_ptr()
194 .write_volatile(MaybeUninit::zeroed().assume_init());
195 TL_MAC_802_15_4_TABLE
196 .as_mut_ptr()
197 .write_volatile(MaybeUninit::zeroed().assume_init());
198 // TL_ZIGBEE_TABLE
199 // .as_mut_ptr()
200 // .write_volatile(MaybeUninit::zeroed().assume_init());
201 // TL_LLD_TESTS_TABLE
202 // .as_mut_ptr()
203 // .write_volatile(MaybeUninit::zeroed().assume_init());
204 // TL_BLE_LLD_TABLE
205 // .as_mut_ptr()
206 // .write_volatile(MaybeUninit::zeroed().assume_init());
207
208 EVT_POOL
209 .as_mut_ptr()
210 .write_volatile(MaybeUninit::zeroed().assume_init());
211 SYS_SPARE_EVT_BUF
212 .as_mut_ptr()
213 .write_volatile(MaybeUninit::zeroed().assume_init());
214 BLE_SPARE_EVT_BUF
215 .as_mut_ptr()
216 .write_volatile(MaybeUninit::zeroed().assume_init());
217
218 {
219 BLE_CMD_BUFFER
220 .as_mut_ptr()
221 .write_volatile(MaybeUninit::zeroed().assume_init());
222 HCI_ACL_DATA_BUFFER
223 .as_mut_ptr()
224 .write_volatile(MaybeUninit::zeroed().assume_init());
225 CS_BUFFER
226 .as_mut_ptr()
227 .write_volatile(MaybeUninit::zeroed().assume_init());
228 }
229 }
230
231 compiler_fence(Ordering::SeqCst);
232
233 Ipcc::enable(config);
234
235 let sys = sys::Sys::new();
236 let ble = ble::Ble::new();
237 let mm = mm::MemoryManager::new();
238
239 // enable interrupts
240 interrupt::typelevel::IPCC_C1_RX::unpend();
241 interrupt::typelevel::IPCC_C1_TX::unpend();
242
243 unsafe { interrupt::typelevel::IPCC_C1_RX::enable() };
244 unsafe { interrupt::typelevel::IPCC_C1_TX::enable() };
245
246 STATE.reset();
247
248 Self {
249 _ipcc: ipcc,
250 sys_subsystem: sys,
251 ble_subsystem: ble,
252 mm_subsystem: mm,
253 }
254 }
255}
diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/mm.rs
new file mode 100644
index 000000000..21f42409a
--- /dev/null
+++ b/embassy-stm32-wpan/src/mm.rs
@@ -0,0 +1,77 @@
1//! Memory manager routines
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use cortex_m::interrupt;
8use embassy_stm32::ipcc::Ipcc;
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::evt::EvtPacket;
12use crate::tables::MemManagerTable;
13use crate::unsafe_linked_list::LinkedListNode;
14use crate::{
15 channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
16 TL_MEM_MANAGER_TABLE,
17};
18
19static MM_WAKER: AtomicWaker = AtomicWaker::new();
20
21pub struct MemoryManager {
22 phantom: PhantomData<MemoryManager>,
23}
24
25impl MemoryManager {
26 pub(crate) fn new() -> Self {
27 unsafe {
28 LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
29 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
30
31 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
32 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
33 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
34 blepool: EVT_POOL.as_ptr().cast(),
35 blepoolsize: POOL_SIZE as u32,
36 pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
37 traces_evt_pool: core::ptr::null(),
38 tracespoolsize: 0,
39 });
40 }
41
42 Self { phantom: PhantomData }
43 }
44
45 /// SAFETY: passing a pointer to something other than an event packet is UB
46 pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) {
47 interrupt::free(|_| unsafe {
48 LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
49 });
50
51 MM_WAKER.wake();
52 }
53
54 pub async fn run_queue(&self) {
55 loop {
56 poll_fn(|cx| unsafe {
57 MM_WAKER.register(cx.waker());
58 if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
59 Poll::Pending
60 } else {
61 Poll::Ready(())
62 }
63 })
64 .await;
65
66 Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
67 interrupt::free(|_| unsafe {
68 // CS required while moving nodes
69 while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
70 LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
71 }
72 })
73 })
74 .await;
75 }
76 }
77}
diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32-wpan/src/shci.rs
index 6b5b2dd19..cdf027d5e 100644
--- a/embassy-stm32/src/tl_mbox/shci.rs
+++ b/embassy-stm32-wpan/src/shci.rs
@@ -1,16 +1,10 @@
1//! HCI commands for system channel 1use core::{mem, slice};
2 2
3use super::cmd::CmdPacket; 3use super::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
4use super::consts::TlPacketType;
5use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
6use crate::tl_mbox::ipcc::Ipcc;
7 4
8const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; 5pub const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
9pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
10#[allow(dead_code)]
11const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
12 6
13#[derive(Clone, Copy)] 7#[derive(Debug, Clone, Copy)]
14#[repr(C, packed)] 8#[repr(C, packed)]
15pub struct ShciBleInitCmdParam { 9pub struct ShciBleInitCmdParam {
16 /// NOT USED CURRENTLY 10 /// NOT USED CURRENTLY
@@ -38,6 +32,12 @@ pub struct ShciBleInitCmdParam {
38 pub hw_version: u8, 32 pub hw_version: u8,
39} 33}
40 34
35impl ShciBleInitCmdParam {
36 pub fn payload<'a>(&self) -> &'a [u8] {
37 unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
38 }
39}
40
41impl Default for ShciBleInitCmdParam { 41impl Default for ShciBleInitCmdParam {
42 fn default() -> Self { 42 fn default() -> Self {
43 Self { 43 Self {
@@ -63,39 +63,19 @@ impl Default for ShciBleInitCmdParam {
63 } 63 }
64} 64}
65 65
66#[derive(Clone, Copy, Default)] 66#[derive(Debug, Clone, Copy, Default)]
67#[repr(C, packed)] 67#[repr(C, packed)]
68pub struct ShciHeader { 68pub struct ShciHeader {
69 metadata: [u32; 3], 69 metadata: [u32; 3],
70} 70}
71 71
72#[derive(Clone, Copy)] 72#[derive(Debug, Clone, Copy)]
73#[repr(C, packed)] 73#[repr(C, packed)]
74pub struct ShciBleInitCmdPacket { 74pub struct ShciBleInitCmdPacket {
75 header: ShciHeader, 75 pub header: ShciHeader,
76 param: ShciBleInitCmdParam, 76 pub param: ShciBleInitCmdParam,
77} 77}
78 78
79pub fn shci_ble_init(param: ShciBleInitCmdParam) { 79pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
80 let mut packet = ShciBleInitCmdPacket { 80#[allow(dead_code)] // Not used currently but reserved
81 header: ShciHeader::default(), 81const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
82 param,
83 };
84
85 let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
86
87 unsafe {
88 let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
89
90 (*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
91 (*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
92
93 let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
94 core::ptr::write(cmd_buf, *cmd_ptr);
95
96 cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
97
98 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
99 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
100 }
101}
diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sys.rs
new file mode 100644
index 000000000..a185cd4f1
--- /dev/null
+++ b/embassy-stm32-wpan/src/sys.rs
@@ -0,0 +1,70 @@
1use core::marker::PhantomData;
2
3use crate::cmd::CmdPacket;
4use crate::consts::TlPacketType;
5use crate::evt::EvtBox;
6use crate::shci::{ShciBleInitCmdParam, SCHI_OPCODE_BLE_INIT};
7use crate::tables::{SysTable, WirelessFwInfoTable};
8use crate::unsafe_linked_list::LinkedListNode;
9use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
10
11pub struct Sys {
12 phantom: PhantomData<Sys>,
13}
14
15impl Sys {
16 /// TL_Sys_Init
17 pub(crate) fn new() -> Self {
18 unsafe {
19 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
20
21 TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
22 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
23 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
24 });
25 }
26
27 Self { phantom: PhantomData }
28 }
29
30 /// Returns CPU2 wireless firmware information (if present).
31 pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
32 let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
33
34 // Zero version indicates that CPU2 wasn't active and didn't fill the information table
35 if info.version != 0 {
36 Some(info)
37 } else {
38 None
39 }
40 }
41
42 pub fn write(&self, opcode: u16, payload: &[u8]) {
43 unsafe {
44 CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode, payload);
45 }
46 }
47
48 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) {
49 debug!("sending SHCI");
50
51 Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || {
52 self.write(SCHI_OPCODE_BLE_INIT, param.payload());
53 })
54 .await;
55
56 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
57 }
58
59 /// `HW_IPCC_SYS_EvtNot`
60 pub async fn read(&self) -> EvtBox {
61 Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
62 if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
63 Some(EvtBox::new(node_ptr.cast()))
64 } else {
65 None
66 }
67 })
68 .await
69 }
70}
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs
new file mode 100644
index 000000000..151216958
--- /dev/null
+++ b/embassy-stm32-wpan/src/tables.rs
@@ -0,0 +1,175 @@
1use bit_field::BitField;
2
3use crate::cmd::{AclDataPacket, CmdPacket};
4use crate::unsafe_linked_list::LinkedListNode;
5
6#[derive(Debug, Copy, Clone)]
7#[repr(C, packed)]
8pub struct SafeBootInfoTable {
9 version: u32,
10}
11
12#[derive(Debug, Copy, Clone)]
13#[repr(C, packed)]
14pub struct RssInfoTable {
15 pub version: u32,
16 pub memory_size: u32,
17 pub rss_info: u32,
18}
19
20/**
21 * Version
22 * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version
23 * [4:7] = branch - 0: Mass Market - x: ...
24 * [8:15] = Subversion
25 * [16:23] = Version minor
26 * [24:31] = Version major
27 *
28 * Memory Size
29 * [0:7] = Flash ( Number of 4k sector)
30 * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension )
31 * [16:23] = SRAM2b ( Number of 1k sector)
32 * [24:31] = SRAM2a ( Number of 1k sector)
33 */
34#[derive(Debug, Copy, Clone)]
35#[repr(C, packed)]
36pub struct WirelessFwInfoTable {
37 pub version: u32,
38 pub memory_size: u32,
39 pub thread_info: u32,
40 pub ble_info: u32,
41}
42
43impl WirelessFwInfoTable {
44 pub fn version_major(&self) -> u8 {
45 let version = self.version;
46 (version.get_bits(24..31) & 0xff) as u8
47 }
48
49 pub fn version_minor(&self) -> u8 {
50 let version = self.version;
51 (version.clone().get_bits(16..23) & 0xff) as u8
52 }
53
54 pub fn subversion(&self) -> u8 {
55 let version = self.version;
56 (version.clone().get_bits(8..15) & 0xff) as u8
57 }
58
59 /// Size of FLASH, expressed in number of 4K sectors.
60 pub fn flash_size(&self) -> u8 {
61 let memory_size = self.memory_size;
62 (memory_size.clone().get_bits(0..7) & 0xff) as u8
63 }
64
65 /// Size of SRAM2a, expressed in number of 1K sectors.
66 pub fn sram2a_size(&self) -> u8 {
67 let memory_size = self.memory_size;
68 (memory_size.clone().get_bits(24..31) & 0xff) as u8
69 }
70
71 /// Size of SRAM2b, expressed in number of 1K sectors.
72 pub fn sram2b_size(&self) -> u8 {
73 let memory_size = self.memory_size;
74 (memory_size.clone().get_bits(16..23) & 0xff) as u8
75 }
76}
77
78#[derive(Debug, Clone)]
79#[repr(C, align(4))]
80pub struct DeviceInfoTable {
81 pub safe_boot_info_table: SafeBootInfoTable,
82 pub rss_info_table: RssInfoTable,
83 pub wireless_fw_info_table: WirelessFwInfoTable,
84}
85
86#[derive(Debug)]
87#[repr(C, align(4))]
88pub struct BleTable {
89 pub pcmd_buffer: *mut CmdPacket,
90 pub pcs_buffer: *const u8,
91 pub pevt_queue: *const u8,
92 pub phci_acl_data_buffer: *mut AclDataPacket,
93}
94
95#[derive(Debug)]
96#[repr(C, align(4))]
97pub struct ThreadTable {
98 pub nostack_buffer: *const u8,
99 pub clicmdrsp_buffer: *const u8,
100 pub otcmdrsp_buffer: *const u8,
101}
102
103// TODO: use later
104#[derive(Debug)]
105#[repr(C, align(4))]
106pub struct LldTestsTable {
107 pub clicmdrsp_buffer: *const u8,
108 pub m0cmd_buffer: *const u8,
109}
110
111// TODO: use later
112#[derive(Debug)]
113#[repr(C, align(4))]
114pub struct BleLldTable {
115 pub cmdrsp_buffer: *const u8,
116 pub m0cmd_buffer: *const u8,
117}
118
119// TODO: use later
120#[derive(Debug)]
121#[repr(C, align(4))]
122pub struct ZigbeeTable {
123 pub notif_m0_to_m4_buffer: *const u8,
124 pub appli_cmd_m4_to_m0_bufer: *const u8,
125 pub request_m0_to_m4_buffer: *const u8,
126}
127
128#[derive(Debug)]
129#[repr(C, align(4))]
130pub struct SysTable {
131 pub pcmd_buffer: *mut CmdPacket,
132 pub sys_queue: *const LinkedListNode,
133}
134
135#[derive(Debug)]
136#[repr(C, align(4))]
137pub struct MemManagerTable {
138 pub spare_ble_buffer: *const u8,
139 pub spare_sys_buffer: *const u8,
140
141 pub blepool: *const u8,
142 pub blepoolsize: u32,
143
144 pub pevt_free_buffer_queue: *mut LinkedListNode,
145
146 pub traces_evt_pool: *const u8,
147 pub tracespoolsize: u32,
148}
149
150#[derive(Debug)]
151#[repr(C, align(4))]
152pub struct TracesTable {
153 pub traces_queue: *const u8,
154}
155
156#[derive(Debug)]
157#[repr(C, align(4))]
158pub struct Mac802_15_4Table {
159 pub p_cmdrsp_buffer: *const u8,
160 pub p_notack_buffer: *const u8,
161 pub evt_queue: *const u8,
162}
163
164/// Reference table. Contains pointers to all other tables.
165#[derive(Debug, Copy, Clone)]
166#[repr(C)]
167pub struct RefTable {
168 pub device_info_table: *const DeviceInfoTable,
169 pub ble_table: *const BleTable,
170 pub thread_table: *const ThreadTable,
171 pub sys_table: *const SysTable,
172 pub mem_manager_table: *const MemManagerTable,
173 pub traces_table: *const TracesTable,
174 pub mac_802_15_4_table: *const Mac802_15_4Table,
175}
diff --git a/embassy-stm32-wpan/src/unsafe_linked_list.rs b/embassy-stm32-wpan/src/unsafe_linked_list.rs
new file mode 100644
index 000000000..d8bc29763
--- /dev/null
+++ b/embassy-stm32-wpan/src/unsafe_linked_list.rs
@@ -0,0 +1,257 @@
1//! Unsafe linked list.
2//! Translated from ST's C by `c2rust` tool.
3
4#![allow(
5 dead_code,
6 mutable_transmutes,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals,
10 unused_assignments,
11 unused_mut
12)]
13
14use core::ptr;
15
16use cortex_m::interrupt;
17
18#[derive(Copy, Clone)]
19#[repr(C, packed(4))]
20pub struct LinkedListNode {
21 pub next: *mut LinkedListNode,
22 pub prev: *mut LinkedListNode,
23}
24
25impl Default for LinkedListNode {
26 fn default() -> Self {
27 LinkedListNode {
28 next: core::ptr::null_mut(),
29 prev: core::ptr::null_mut(),
30 }
31 }
32}
33
34impl LinkedListNode {
35 pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) {
36 ptr::write_volatile(
37 p_list_head,
38 LinkedListNode {
39 next: p_list_head,
40 prev: p_list_head,
41 },
42 );
43 }
44
45 pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
46 interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
47 }
48
49 /// Insert `node` after `list_head` and before the next node
50 pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
51 interrupt::free(|_| {
52 let mut list_head = ptr::read_volatile(p_list_head);
53 if p_list_head != list_head.next {
54 let mut node_next = ptr::read_volatile(list_head.next);
55 let node = LinkedListNode {
56 next: list_head.next,
57 prev: p_list_head,
58 };
59
60 list_head.next = p_node;
61 node_next.prev = p_node;
62
63 // All nodes must be written because they will all be seen by another core
64 ptr::write_volatile(p_node, node);
65 ptr::write_volatile(node.next, node_next);
66 ptr::write_volatile(p_list_head, list_head);
67 } else {
68 let node = LinkedListNode {
69 next: list_head.next,
70 prev: p_list_head,
71 };
72
73 list_head.next = p_node;
74 list_head.prev = p_node;
75
76 // All nodes must be written because they will all be seen by another core
77 ptr::write_volatile(p_node, node);
78 ptr::write_volatile(p_list_head, list_head);
79 }
80 });
81 }
82
83 /// Insert `node` before `list_tail` and after the second-to-last node
84 pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
85 interrupt::free(|_| {
86 let mut list_tail = ptr::read_volatile(p_list_tail);
87 if p_list_tail != list_tail.prev {
88 let mut node_prev = ptr::read_volatile(list_tail.prev);
89 let node = LinkedListNode {
90 next: p_list_tail,
91 prev: list_tail.prev,
92 };
93
94 list_tail.prev = p_node;
95 node_prev.next = p_node;
96
97 // All nodes must be written because they will all be seen by another core
98 ptr::write_volatile(p_node, node);
99 ptr::write_volatile(node.prev, node_prev);
100 ptr::write_volatile(p_list_tail, list_tail);
101 } else {
102 let node = LinkedListNode {
103 next: p_list_tail,
104 prev: list_tail.prev,
105 };
106
107 list_tail.prev = p_node;
108 list_tail.next = p_node;
109
110 // All nodes must be written because they will all be seen by another core
111 ptr::write_volatile(p_node, node);
112 ptr::write_volatile(p_list_tail, list_tail);
113 }
114 });
115 }
116
117 /// Remove `node` from the linked list
118 pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
119 interrupt::free(|_| {
120 // trace!("remove node: {:x}", p_node);
121 // apparently linked list nodes are not always aligned.
122 // if more hardfaults occur, more of these may need to be converted to unaligned.
123 let node = ptr::read_unaligned(p_node);
124 // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
125
126 if node.next != node.prev {
127 let mut node_next = ptr::read_volatile(node.next);
128 let mut node_prev = ptr::read_volatile(node.prev);
129
130 node_prev.next = node.next;
131 node_next.prev = node.prev;
132
133 ptr::write_volatile(node.next, node_next);
134 ptr::write_volatile(node.prev, node_prev);
135 } else {
136 let mut node_next = ptr::read_volatile(node.next);
137
138 node_next.next = node.next;
139 node_next.prev = node.prev;
140
141 ptr::write_volatile(node.next, node_next);
142 }
143 });
144 }
145
146 /// Remove `list_head` and return a pointer to the `node`.
147 pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
148 interrupt::free(|_| {
149 let list_head = ptr::read_volatile(p_list_head);
150
151 if list_head.next == p_list_head {
152 None
153 } else {
154 // Allowed because a removed node is not seen by another core
155 let p_node = list_head.next;
156 Self::remove_node(p_node);
157
158 Some(p_node)
159 }
160 })
161 }
162
163 /// Remove `list_tail` and return a pointer to the `node`.
164 pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
165 interrupt::free(|_| {
166 let list_tail = ptr::read_volatile(p_list_tail);
167
168 if list_tail.prev == p_list_tail {
169 None
170 } else {
171 // Allowed because a removed node is not seen by another core
172 let p_node = list_tail.prev;
173 Self::remove_node(p_node);
174
175 Some(p_node)
176 }
177 })
178 }
179
180 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
181 interrupt::free(|_| {
182 (*node).next = (*ref_node).next;
183 (*node).prev = ref_node;
184 (*ref_node).next = node;
185 (*(*node).next).prev = node;
186 });
187
188 todo!("this function has not been converted to volatile semantics");
189 }
190
191 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
192 interrupt::free(|_| {
193 (*node).next = ref_node;
194 (*node).prev = (*ref_node).prev;
195 (*ref_node).prev = node;
196 (*(*node).prev).next = node;
197 });
198
199 todo!("this function has not been converted to volatile semantics");
200 }
201
202 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
203 interrupt::free(|_| {
204 let mut size = 0;
205 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
206
207 temp = (*list_head).next;
208 while temp != list_head {
209 size += 1;
210 temp = (*temp).next
211 }
212
213 size
214 });
215
216 todo!("this function has not been converted to volatile semantics");
217 }
218
219 pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
220 interrupt::free(|_| {
221 let ref_node = ptr::read_volatile(p_ref_node);
222
223 // Allowed because a removed node is not seen by another core
224 ref_node.next
225 })
226 }
227
228 pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
229 interrupt::free(|_| {
230 let ref_node = ptr::read_volatile(p_ref_node);
231
232 // Allowed because a removed node is not seen by another core
233 ref_node.prev
234 })
235 }
236}
237
238#[allow(dead_code)]
239unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) {
240 info!("iterating list from node: {:x}", p_node);
241 let mut p_current_node = p_node;
242 let mut i = 0;
243 loop {
244 let current_node = ptr::read_volatile(p_current_node);
245 info!(
246 "node (prev, current, next): {:x}, {:x}, {:x}",
247 current_node.prev, p_current_node, current_node.next
248 );
249
250 i += 1;
251 if i > 10 || current_node.next == p_node {
252 break;
253 }
254
255 p_current_node = current_node.next;
256 }
257}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 4e29bb32f..3d9ee8261 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -32,11 +32,9 @@ flavors = [
32 32
33[dependencies] 33[dependencies]
34embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 34embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
35embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
36embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 35embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
37embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 36embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
38embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]} 37embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
39embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
40embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 38embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
41embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 39embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
42embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 40embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
@@ -59,7 +57,7 @@ sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 58critical-section = "1.1"
61atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
62stm32-metapac = "9" 60stm32-metapac = "10"
63vcell = "0.1.3" 61vcell = "0.1.3"
64bxcan = "0.7.0" 62bxcan = "0.7.0"
65nb = "1.0.0" 63nb = "1.0.0"
@@ -76,11 +74,13 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 74[build-dependencies]
77proc-macro2 = "1.0.36" 75proc-macro2 = "1.0.36"
78quote = "1.0.15" 76quote = "1.0.15"
79stm32-metapac = { version = "9", default-features = false, features = ["metadata"]} 77stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
80 78
81[features] 79[features]
82default = ["stm32-metapac/rt"] 80default = ["rt"]
83defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] 81rt = ["stm32-metapac/rt"]
82
83defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
84memory-x = ["stm32-metapac/memory-x"] 84memory-x = ["stm32-metapac/memory-x"]
85exti = [] 85exti = []
86 86
@@ -99,7 +99,7 @@ time-driver-tim12 = ["_time-driver"]
99time-driver-tim15 = ["_time-driver"] 99time-driver-tim15 = ["_time-driver"]
100 100
101# Enable nightly-only features 101# Enable nightly-only features
102nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] 102nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
103 103
104# Reexport stm32-metapac at `embassy_stm32::pac`. 104# Reexport stm32-metapac at `embassy_stm32::pac`.
105# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. 105# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 730c78f5e..f71074bcf 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -160,13 +160,11 @@ fn main() {
160 } 160 }
161 161
162 g.extend(quote! { 162 g.extend(quote! {
163 pub mod interrupt { 163 embassy_hal_common::interrupt_mod!(
164 use crate::pac::Interrupt as InterruptEnum;
165 use embassy_cortex_m::interrupt::_export::declare;
166 #( 164 #(
167 declare!(#irqs); 165 #irqs,
168 )* 166 )*
169 } 167 );
170 }); 168 });
171 169
172 // ======== 170 // ========
@@ -297,6 +295,7 @@ fn main() {
297 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); 295 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
298 296
299 g.extend(quote! { 297 g.extend(quote! {
298 #[cfg(feature = "rt")]
300 #[crate::interrupt] 299 #[crate::interrupt]
301 unsafe fn #irq () { 300 unsafe fn #irq () {
302 #( 301 #(
@@ -323,7 +322,7 @@ fn main() {
323 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); 322 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
324 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); 323 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
325 quote! { 324 quote! {
326 critical_section::with(|_| unsafe { 325 critical_section::with(|_| {
327 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); 326 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
328 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); 327 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
329 }); 328 });
@@ -354,13 +353,13 @@ fn main() {
354 }) 353 })
355 } 354 }
356 fn enable() { 355 fn enable() {
357 critical_section::with(|_| unsafe { 356 critical_section::with(|_| {
358 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); 357 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
359 #after_enable 358 #after_enable
360 }) 359 })
361 } 360 }
362 fn disable() { 361 fn disable() {
363 critical_section::with(|_| unsafe { 362 critical_section::with(|_| {
364 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); 363 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
365 }) 364 })
366 } 365 }
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index d30ec001d..2322204d5 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -32,26 +32,22 @@ impl<'d, T: Instance> Adc<'d, T> {
32 into_ref!(adc); 32 into_ref!(adc);
33 T::enable(); 33 T::enable();
34 T::reset(); 34 T::reset();
35 unsafe { 35 T::regs().cr2().modify(|reg| reg.set_adon(true));
36 T::regs().cr2().modify(|reg| reg.set_adon(true));
37 }
38 36
39 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 37 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
40 // for at least two ADC clock cycles 38 // for at least two ADC clock cycles
41 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); 39 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
42 40
43 unsafe { 41 // Reset calibration
44 // Reset calibration 42 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
45 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 43 while T::regs().cr2().read().rstcal() {
46 while T::regs().cr2().read().rstcal() { 44 // spin
47 // spin 45 }
48 } 46
49 47 // Calibrate
50 // Calibrate 48 T::regs().cr2().modify(|reg| reg.set_cal(true));
51 T::regs().cr2().modify(|reg| reg.set_cal(true)); 49 while T::regs().cr2().read().cal() {
52 while T::regs().cr2().read().cal() { 50 // spin
53 // spin
54 }
55 } 51 }
56 52
57 // One cycle after calibration 53 // One cycle after calibration
@@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> {
81 } 77 }
82 78
83 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { 79 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
84 unsafe { 80 T::regs().cr2().modify(|reg| {
85 T::regs().cr2().modify(|reg| { 81 reg.set_tsvrefe(true);
86 reg.set_tsvrefe(true); 82 });
87 })
88 }
89 Vref {} 83 Vref {}
90 } 84 }
91 85
92 pub fn enable_temperature(&self) -> Temperature { 86 pub fn enable_temperature(&self) -> Temperature {
93 unsafe { 87 T::regs().cr2().modify(|reg| {
94 T::regs().cr2().modify(|reg| { 88 reg.set_tsvrefe(true);
95 reg.set_tsvrefe(true); 89 });
96 })
97 }
98 Temperature {} 90 Temperature {}
99 } 91 }
100 92
@@ -104,41 +96,37 @@ impl<'d, T: Instance> Adc<'d, T> {
104 96
105 /// Perform a single conversion. 97 /// Perform a single conversion.
106 fn convert(&mut self) -> u16 { 98 fn convert(&mut self) -> u16 {
107 unsafe { 99 T::regs().cr2().modify(|reg| {
108 T::regs().cr2().modify(|reg| { 100 reg.set_adon(true);
109 reg.set_adon(true); 101 reg.set_swstart(true);
110 reg.set_swstart(true); 102 });
111 }); 103 while T::regs().cr2().read().swstart() {}
112 while T::regs().cr2().read().swstart() {} 104 while !T::regs().sr().read().eoc() {}
113 while !T::regs().sr().read().eoc() {} 105
114 106 T::regs().dr().read().0 as u16
115 T::regs().dr().read().0 as u16
116 }
117 } 107 }
118 108
119 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 109 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
120 unsafe { 110 Self::set_channel_sample_time(pin.channel(), self.sample_time);
121 Self::set_channel_sample_time(pin.channel(), self.sample_time); 111 T::regs().cr1().modify(|reg| {
122 T::regs().cr1().modify(|reg| { 112 reg.set_scan(false);
123 reg.set_scan(false); 113 reg.set_discen(false);
124 reg.set_discen(false); 114 });
125 }); 115 T::regs().sqr1().modify(|reg| reg.set_l(0));
126 T::regs().sqr1().modify(|reg| reg.set_l(0)); 116
127 117 T::regs().cr2().modify(|reg| {
128 T::regs().cr2().modify(|reg| { 118 reg.set_cont(false);
129 reg.set_cont(false); 119 reg.set_exttrig(true);
130 reg.set_exttrig(true); 120 reg.set_swstart(false);
131 reg.set_swstart(false); 121 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
132 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); 122 });
133 });
134 }
135 123
136 // Configure the channel to sample 124 // Configure the channel to sample
137 unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) } 125 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
138 self.convert() 126 self.convert()
139 } 127 }
140 128
141 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 129 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
142 let sample_time = sample_time.into(); 130 let sample_time = sample_time.into();
143 if ch <= 9 { 131 if ch <= 9 {
144 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); 132 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 82a8c3efb..d9af0c55e 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> {
57 // 57 //
58 // 6.3.20 Vbat monitoring characteristics 58 // 6.3.20 Vbat monitoring characteristics
59 // ts_vbat ≥ 4μs 59 // ts_vbat ≥ 4μs
60 unsafe { 60 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
61 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
62 }
63 Vbat 61 Vbat
64 } 62 }
65 63
66 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { 64 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
67 // Table 28. Embedded internal reference voltage 65 // Table 28. Embedded internal reference voltage
68 // tstart = 10μs 66 // tstart = 10μs
69 unsafe { 67 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
70 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
71 }
72 delay.delay_us(10); 68 delay.delay_us(10);
73 Vref 69 Vref
74 } 70 }
@@ -79,27 +75,23 @@ impl<'d, T: Instance> Adc<'d, T> {
79 // 6.3.19 Temperature sensor characteristics 75 // 6.3.19 Temperature sensor characteristics
80 // tstart ≤ 10μs 76 // tstart ≤ 10μs
81 // ts_temp ≥ 4μs 77 // ts_temp ≥ 4μs
82 unsafe { 78 T::regs().ccr().modify(|reg| reg.set_tsen(true));
83 T::regs().ccr().modify(|reg| reg.set_tsen(true));
84 }
85 delay.delay_us(10); 79 delay.delay_us(10);
86 Temperature 80 Temperature
87 } 81 }
88 82
89 fn calibrate(&self) { 83 fn calibrate(&self) {
90 unsafe { 84 // A.7.1 ADC calibration code example
91 // A.7.1 ADC calibration code example 85 if T::regs().cr().read().aden() {
92 if T::regs().cr().read().aden() { 86 T::regs().cr().modify(|reg| reg.set_addis(true));
93 T::regs().cr().modify(|reg| reg.set_addis(true)); 87 }
94 } 88 while T::regs().cr().read().aden() {
95 while T::regs().cr().read().aden() { 89 // spin
96 // spin 90 }
97 } 91 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
98 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); 92 T::regs().cr().modify(|reg| reg.set_adcal(true));
99 T::regs().cr().modify(|reg| reg.set_adcal(true)); 93 while T::regs().cr().read().adcal() {
100 while T::regs().cr().read().adcal() { 94 // spin
101 // spin
102 }
103 } 95 }
104 } 96 }
105 97
@@ -108,9 +100,7 @@ impl<'d, T: Instance> Adc<'d, T> {
108 } 100 }
109 101
110 pub fn set_resolution(&mut self, resolution: Resolution) { 102 pub fn set_resolution(&mut self, resolution: Resolution) {
111 unsafe { 103 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
112 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
113 }
114 } 104 }
115 105
116 pub fn read<P>(&mut self, pin: &mut P) -> u16 106 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -118,18 +108,16 @@ impl<'d, T: Instance> Adc<'d, T> {
118 P: AdcPin<T> + crate::gpio::sealed::Pin, 108 P: AdcPin<T> + crate::gpio::sealed::Pin,
119 { 109 {
120 let channel = pin.channel(); 110 let channel = pin.channel();
121 unsafe { 111 pin.set_as_analog();
122 pin.set_as_analog(); 112 self.read_channel(channel)
123 self.read_channel(channel)
124 }
125 } 113 }
126 114
127 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 115 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
128 let channel = channel.channel(); 116 let channel = channel.channel();
129 unsafe { self.read_channel(channel) } 117 self.read_channel(channel)
130 } 118 }
131 119
132 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 120 fn read_channel(&mut self, channel: u8) -> u16 {
133 // A.7.2 ADC enable sequence code example 121 // A.7.2 ADC enable sequence code example
134 if T::regs().isr().read().adrdy() { 122 if T::regs().isr().read().adrdy() {
135 T::regs().isr().modify(|reg| reg.set_adrdy(true)); 123 T::regs().isr().modify(|reg| reg.set_adrdy(true));
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 11a51f993..091c1d447 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -100,13 +100,10 @@ where
100 T::reset(); 100 T::reset();
101 101
102 let presc = Prescaler::from_pclk2(T::frequency()); 102 let presc = Prescaler::from_pclk2(T::frequency());
103 unsafe { 103 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
104 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 104 T::regs().cr2().modify(|reg| {
105 105 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
106 T::regs().cr2().modify(|reg| { 106 });
107 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
108 });
109 }
110 107
111 delay.delay_us(ADC_POWERUP_TIME_US); 108 delay.delay_us(ADC_POWERUP_TIME_US);
112 109
@@ -121,19 +118,15 @@ where
121 } 118 }
122 119
123 pub fn set_resolution(&mut self, resolution: Resolution) { 120 pub fn set_resolution(&mut self, resolution: Resolution) {
124 unsafe { 121 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
125 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
126 }
127 } 122 }
128 123
129 /// Enables internal voltage reference and returns [VrefInt], which can be used in 124 /// Enables internal voltage reference and returns [VrefInt], which can be used in
130 /// [Adc::read_internal()] to perform conversion. 125 /// [Adc::read_internal()] to perform conversion.
131 pub fn enable_vrefint(&self) -> VrefInt { 126 pub fn enable_vrefint(&self) -> VrefInt {
132 unsafe { 127 T::common_regs().ccr().modify(|reg| {
133 T::common_regs().ccr().modify(|reg| { 128 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
134 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 129 });
135 });
136 }
137 130
138 VrefInt {} 131 VrefInt {}
139 } 132 }
@@ -144,11 +137,9 @@ where
144 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, 137 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
145 /// temperature sensor will return vbat value. 138 /// temperature sensor will return vbat value.
146 pub fn enable_temperature(&self) -> Temperature { 139 pub fn enable_temperature(&self) -> Temperature {
147 unsafe { 140 T::common_regs().ccr().modify(|reg| {
148 T::common_regs().ccr().modify(|reg| { 141 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
149 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 142 });
150 });
151 }
152 143
153 Temperature {} 144 Temperature {}
154 } 145 }
@@ -156,37 +147,33 @@ where
156 /// Enables vbat input and returns [Vbat], which can be used in 147 /// Enables vbat input and returns [Vbat], which can be used in
157 /// [Adc::read_internal()] to perform conversion. 148 /// [Adc::read_internal()] to perform conversion.
158 pub fn enable_vbat(&self) -> Vbat { 149 pub fn enable_vbat(&self) -> Vbat {
159 unsafe { 150 T::common_regs().ccr().modify(|reg| {
160 T::common_regs().ccr().modify(|reg| { 151 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
161 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); 152 });
162 });
163 }
164 153
165 Vbat {} 154 Vbat {}
166 } 155 }
167 156
168 /// Perform a single conversion. 157 /// Perform a single conversion.
169 fn convert(&mut self) -> u16 { 158 fn convert(&mut self) -> u16 {
170 unsafe { 159 // clear end of conversion flag
171 // clear end of conversion flag 160 T::regs().sr().modify(|reg| {
172 T::regs().sr().modify(|reg| { 161 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
173 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); 162 });
174 }); 163
175 164 // Start conversion
176 // Start conversion 165 T::regs().cr2().modify(|reg| {
177 T::regs().cr2().modify(|reg| { 166 reg.set_swstart(true);
178 reg.set_swstart(true); 167 });
179 }); 168
180 169 while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED {
181 while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { 170 // spin //wait for actual start
182 // spin //wait for actual start
183 }
184 while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
185 // spin //wait for finish
186 }
187
188 T::regs().dr().read().0 as u16
189 } 171 }
172 while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
173 // spin //wait for finish
174 }
175
176 T::regs().dr().read().0 as u16
190 } 177 }
191 178
192 pub fn read<P>(&mut self, pin: &mut P) -> u16 179 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -194,18 +181,16 @@ where
194 P: AdcPin<T>, 181 P: AdcPin<T>,
195 P: crate::gpio::sealed::Pin, 182 P: crate::gpio::sealed::Pin,
196 { 183 {
197 unsafe { 184 pin.set_as_analog();
198 pin.set_as_analog();
199 185
200 self.read_channel(pin.channel()) 186 self.read_channel(pin.channel())
201 }
202 } 187 }
203 188
204 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 189 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
205 unsafe { self.read_channel(channel.channel()) } 190 self.read_channel(channel.channel())
206 } 191 }
207 192
208 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 193 fn read_channel(&mut self, channel: u8) -> u16 {
209 // Configure ADC 194 // Configure ADC
210 195
211 // Select channel 196 // Select channel
@@ -219,7 +204,7 @@ where
219 val 204 val
220 } 205 }
221 206
222 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 207 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
223 let sample_time = sample_time.into(); 208 let sample_time = sample_time.into();
224 if ch <= 9 { 209 if ch <= 9 {
225 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); 210 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 90aa7d3b9..94cdc86cd 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/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock 12/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
13/// configuration. 13/// configuration.
14fn enable() { 14fn enable() {
15 critical_section::with(|_| unsafe { 15 critical_section::with(|_| {
16 #[cfg(stm32h7)] 16 #[cfg(stm32h7)]
17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); 17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
18 #[cfg(stm32g0)] 18 #[cfg(stm32g0)]
@@ -62,29 +62,25 @@ impl<'d, T: Instance> Adc<'d, T> {
62 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 62 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
63 into_ref!(adc); 63 into_ref!(adc);
64 enable(); 64 enable();
65 unsafe { 65 T::regs().cr().modify(|reg| {
66 T::regs().cr().modify(|reg| { 66 #[cfg(not(adc_g0))]
67 #[cfg(not(adc_g0))] 67 reg.set_deeppwd(false);
68 reg.set_deeppwd(false); 68 reg.set_advregen(true);
69 reg.set_advregen(true); 69 });
70 }); 70
71 71 #[cfg(adc_g0)]
72 #[cfg(adc_g0)] 72 T::regs().cfgr1().modify(|reg| {
73 T::regs().cfgr1().modify(|reg| { 73 reg.set_chselrmod(false);
74 reg.set_chselrmod(false); 74 });
75 });
76 }
77 75
78 delay.delay_us(20); 76 delay.delay_us(20);
79 77
80 unsafe { 78 T::regs().cr().modify(|reg| {
81 T::regs().cr().modify(|reg| { 79 reg.set_adcal(true);
82 reg.set_adcal(true); 80 });
83 });
84 81
85 while T::regs().cr().read().adcal() { 82 while T::regs().cr().read().adcal() {
86 // spin 83 // spin
87 }
88 } 84 }
89 85
90 delay.delay_us(1); 86 delay.delay_us(1);
@@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> {
96 } 92 }
97 93
98 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { 94 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
99 unsafe { 95 T::common_regs().ccr().modify(|reg| {
100 T::common_regs().ccr().modify(|reg| { 96 reg.set_vrefen(true);
101 reg.set_vrefen(true); 97 });
102 });
103 }
104 98
105 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us 99 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
106 // to stabilize the internal voltage reference, we wait a little more. 100 // to stabilize the internal voltage reference, we wait a little more.
@@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> {
112 } 106 }
113 107
114 pub fn enable_temperature(&self) -> Temperature { 108 pub fn enable_temperature(&self) -> Temperature {
115 unsafe { 109 T::common_regs().ccr().modify(|reg| {
116 T::common_regs().ccr().modify(|reg| { 110 reg.set_ch17sel(true);
117 reg.set_ch17sel(true); 111 });
118 });
119 }
120 112
121 Temperature {} 113 Temperature {}
122 } 114 }
123 115
124 pub fn enable_vbat(&self) -> Vbat { 116 pub fn enable_vbat(&self) -> Vbat {
125 unsafe { 117 T::common_regs().ccr().modify(|reg| {
126 T::common_regs().ccr().modify(|reg| { 118 reg.set_ch18sel(true);
127 reg.set_ch18sel(true); 119 });
128 });
129 }
130 120
131 Vbat {} 121 Vbat {}
132 } 122 }
@@ -136,12 +126,10 @@ impl<'d, T: Instance> Adc<'d, T> {
136 } 126 }
137 127
138 pub fn set_resolution(&mut self, resolution: Resolution) { 128 pub fn set_resolution(&mut self, resolution: Resolution) {
139 unsafe { 129 #[cfg(not(stm32g0))]
140 #[cfg(not(stm32g0))] 130 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
141 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 131 #[cfg(stm32g0)]
142 #[cfg(stm32g0)] 132 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
143 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
144 }
145 } 133 }
146 134
147 /* 135 /*
@@ -155,77 +143,73 @@ impl<'d, T: Instance> Adc<'d, T> {
155 143
156 /// Perform a single conversion. 144 /// Perform a single conversion.
157 fn convert(&mut self) -> u16 { 145 fn convert(&mut self) -> u16 {
158 unsafe { 146 T::regs().isr().modify(|reg| {
159 T::regs().isr().modify(|reg| { 147 reg.set_eos(true);
160 reg.set_eos(true); 148 reg.set_eoc(true);
161 reg.set_eoc(true); 149 });
162 }); 150
163 151 // Start conversion
164 // Start conversion 152 T::regs().cr().modify(|reg| {
165 T::regs().cr().modify(|reg| { 153 reg.set_adstart(true);
166 reg.set_adstart(true); 154 });
167 }); 155
168 156 while !T::regs().isr().read().eos() {
169 while !T::regs().isr().read().eos() { 157 // spin
170 // spin
171 }
172
173 T::regs().dr().read().0 as u16
174 } 158 }
159
160 T::regs().dr().read().0 as u16
175 } 161 }
176 162
177 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 163 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
178 unsafe { 164 // Make sure bits are off
179 // Make sure bits are off 165 while T::regs().cr().read().addis() {
180 while T::regs().cr().read().addis() { 166 // spin
181 // spin
182 }
183
184 // Enable ADC
185 T::regs().isr().modify(|reg| {
186 reg.set_adrdy(true);
187 });
188 T::regs().cr().modify(|reg| {
189 reg.set_aden(true);
190 });
191
192 while !T::regs().isr().read().adrdy() {
193 // spin
194 }
195
196 // Configure channel
197 Self::set_channel_sample_time(pin.channel(), self.sample_time);
198
199 // Select channel
200 #[cfg(not(stm32g0))]
201 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
202 #[cfg(stm32g0)]
203 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
204
205 // Some models are affected by an erratum:
206 // If we perform conversions slower than 1 kHz, the first read ADC value can be
207 // corrupted, so we discard it and measure again.
208 //
209 // STM32L471xx: Section 2.7.3
210 // STM32G4: Section 2.7.3
211 #[cfg(any(rcc_l4, rcc_g4))]
212 let _ = self.convert();
213
214 let val = self.convert();
215
216 T::regs().cr().modify(|reg| reg.set_addis(true));
217
218 val
219 } 167 }
168
169 // Enable ADC
170 T::regs().isr().modify(|reg| {
171 reg.set_adrdy(true);
172 });
173 T::regs().cr().modify(|reg| {
174 reg.set_aden(true);
175 });
176
177 while !T::regs().isr().read().adrdy() {
178 // spin
179 }
180
181 // Configure channel
182 Self::set_channel_sample_time(pin.channel(), self.sample_time);
183
184 // Select channel
185 #[cfg(not(stm32g0))]
186 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
187 #[cfg(stm32g0)]
188 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
189
190 // Some models are affected by an erratum:
191 // If we perform conversions slower than 1 kHz, the first read ADC value can be
192 // corrupted, so we discard it and measure again.
193 //
194 // STM32L471xx: Section 2.7.3
195 // STM32G4: Section 2.7.3
196 #[cfg(any(rcc_l4, rcc_g4))]
197 let _ = self.convert();
198
199 let val = self.convert();
200
201 T::regs().cr().modify(|reg| reg.set_addis(true));
202
203 val
220 } 204 }
221 205
222 #[cfg(stm32g0)] 206 #[cfg(stm32g0)]
223 unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 207 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
224 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 208 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
225 } 209 }
226 210
227 #[cfg(not(stm32g0))] 211 #[cfg(not(stm32g0))]
228 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 212 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
229 let sample_time = sample_time.into(); 213 let sample_time = sample_time.into();
230 if ch <= 9 { 214 if ch <= 9 {
231 T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); 215 T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 4707b7c95..c51c6840f 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -46,8 +46,8 @@ foreach_peripheral!(
46 (adc, ADC1) => { 46 (adc, ADC1) => {
47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { 47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
48 fn frequency() -> crate::time::Hertz { 48 fn frequency() -> crate::time::Hertz {
49 critical_section::with(|_| unsafe { 49 critical_section::with(|_| {
50 match crate::rcc::get_freqs().adc { 50 match unsafe { crate::rcc::get_freqs() }.adc {
51 Some(ck) => ck, 51 Some(ck) => ck,
52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
53 } 53 }
@@ -55,7 +55,7 @@ foreach_peripheral!(
55 } 55 }
56 56
57 fn enable() { 57 fn enable() {
58 critical_section::with(|_| unsafe { 58 critical_section::with(|_| {
59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) 59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
60 }); 60 });
61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); 61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@@ -63,7 +63,7 @@ foreach_peripheral!(
63 63
64 fn disable() { 64 fn disable() {
65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
66 critical_section::with(|_| unsafe { 66 critical_section::with(|_| {
67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); 67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
68 }) 68 })
69 } 69 }
@@ -72,7 +72,7 @@ foreach_peripheral!(
72 72
73 fn reset() { 73 fn reset() {
74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
75 critical_section::with(|_| unsafe { 75 critical_section::with(|_| {
76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); 76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); 77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
78 }); 78 });
@@ -85,8 +85,8 @@ foreach_peripheral!(
85 (adc, ADC2) => { 85 (adc, ADC2) => {
86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { 86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
87 fn frequency() -> crate::time::Hertz { 87 fn frequency() -> crate::time::Hertz {
88 critical_section::with(|_| unsafe { 88 critical_section::with(|_| {
89 match crate::rcc::get_freqs().adc { 89 match unsafe { crate::rcc::get_freqs() }.adc {
90 Some(ck) => ck, 90 Some(ck) => ck,
91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
92 } 92 }
@@ -94,7 +94,7 @@ foreach_peripheral!(
94 } 94 }
95 95
96 fn enable() { 96 fn enable() {
97 critical_section::with(|_| unsafe { 97 critical_section::with(|_| {
98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) 98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
99 }); 99 });
100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); 100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@@ -102,7 +102,7 @@ foreach_peripheral!(
102 102
103 fn disable() { 103 fn disable() {
104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
105 critical_section::with(|_| unsafe { 105 critical_section::with(|_| {
106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); 106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
107 }) 107 })
108 } 108 }
@@ -111,7 +111,7 @@ foreach_peripheral!(
111 111
112 fn reset() { 112 fn reset() {
113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
114 critical_section::with(|_| unsafe { 114 critical_section::with(|_| {
115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); 115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); 116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
117 }); 117 });
@@ -124,8 +124,8 @@ foreach_peripheral!(
124 (adc, ADC3) => { 124 (adc, ADC3) => {
125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { 125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
126 fn frequency() -> crate::time::Hertz { 126 fn frequency() -> crate::time::Hertz {
127 critical_section::with(|_| unsafe { 127 critical_section::with(|_| {
128 match crate::rcc::get_freqs().adc { 128 match unsafe { crate::rcc::get_freqs() }.adc {
129 Some(ck) => ck, 129 Some(ck) => ck,
130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
131 } 131 }
@@ -133,22 +133,22 @@ foreach_peripheral!(
133 } 133 }
134 134
135 fn enable() { 135 fn enable() {
136 critical_section::with(|_| unsafe { 136 critical_section::with(|_| {
137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) 137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
138 }); 138 });
139 } 139 }
140 140
141 fn disable() { 141 fn disable() {
142 critical_section::with(|_| unsafe { 142 critical_section::with(|_| {
143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); 143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
144 }) 144 })
145 } 145 }
146 146
147 fn reset() { 147 fn reset() {
148 critical_section::with(|_| unsafe { 148 critical_section::with(|_| {
149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); 149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); 150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
151 }); 151 });
152 } 152 }
153 } 153 }
154 154
@@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> {
232 232
233 let prescaler = Prescaler::from_ker_ck(T::frequency()); 233 let prescaler = Prescaler::from_ker_ck(T::frequency());
234 234
235 unsafe { 235 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
236 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
237 }
238 236
239 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 237 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
240 info!("ADC frequency set to {} Hz", frequency.0); 238 info!("ADC frequency set to {} Hz", frequency.0);
@@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> {
251 } else { 249 } else {
252 Boost::LT50 250 Boost::LT50
253 }; 251 };
254 unsafe { 252 T::regs().cr().modify(|w| w.set_boost(boost));
255 T::regs().cr().modify(|w| w.set_boost(boost));
256 }
257 253
258 let mut s = Self { 254 let mut s = Self {
259 adc, 255 adc,
@@ -272,84 +268,68 @@ impl<'d, T: Instance> Adc<'d, T> {
272 } 268 }
273 269
274 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { 270 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
275 unsafe { 271 T::regs().cr().modify(|reg| {
276 T::regs().cr().modify(|reg| { 272 reg.set_deeppwd(false);
277 reg.set_deeppwd(false); 273 reg.set_advregen(true);
278 reg.set_advregen(true); 274 });
279 });
280 }
281 275
282 delay.delay_us(10); 276 delay.delay_us(10);
283 } 277 }
284 278
285 fn configure_differential_inputs(&mut self) { 279 fn configure_differential_inputs(&mut self) {
286 unsafe { 280 T::regs().difsel().modify(|w| {
287 T::regs().difsel().modify(|w| { 281 for n in 0..20 {
288 for n in 0..20 { 282 w.set_difsel(n, Difsel::SINGLEENDED);
289 w.set_difsel(n, Difsel::SINGLEENDED); 283 }
290 } 284 });
291 })
292 };
293 } 285 }
294 286
295 fn calibrate(&mut self) { 287 fn calibrate(&mut self) {
296 unsafe { 288 T::regs().cr().modify(|w| {
297 T::regs().cr().modify(|w| { 289 w.set_adcaldif(Adcaldif::SINGLEENDED);
298 w.set_adcaldif(Adcaldif::SINGLEENDED); 290 w.set_adcallin(true);
299 w.set_adcallin(true); 291 });
300 });
301 292
302 T::regs().cr().modify(|w| w.set_adcal(true)); 293 T::regs().cr().modify(|w| w.set_adcal(true));
303 294
304 while T::regs().cr().read().adcal() {} 295 while T::regs().cr().read().adcal() {}
305 }
306 } 296 }
307 297
308 fn enable(&mut self) { 298 fn enable(&mut self) {
309 unsafe { 299 T::regs().isr().write(|w| w.set_adrdy(true));
310 T::regs().isr().write(|w| w.set_adrdy(true)); 300 T::regs().cr().modify(|w| w.set_aden(true));
311 T::regs().cr().modify(|w| w.set_aden(true)); 301 while !T::regs().isr().read().adrdy() {}
312 while !T::regs().isr().read().adrdy() {} 302 T::regs().isr().write(|w| w.set_adrdy(true));
313 T::regs().isr().write(|w| w.set_adrdy(true));
314 }
315 } 303 }
316 304
317 fn configure(&mut self) { 305 fn configure(&mut self) {
318 // single conversion mode, software trigger 306 // single conversion mode, software trigger
319 unsafe { 307 T::regs().cfgr().modify(|w| {
320 T::regs().cfgr().modify(|w| { 308 w.set_cont(false);
321 w.set_cont(false); 309 w.set_exten(Exten::DISABLED);
322 w.set_exten(Exten::DISABLED); 310 });
323 })
324 }
325 } 311 }
326 312
327 pub fn enable_vrefint(&self) -> VrefInt { 313 pub fn enable_vrefint(&self) -> VrefInt {
328 unsafe { 314 T::common_regs().ccr().modify(|reg| {
329 T::common_regs().ccr().modify(|reg| { 315 reg.set_vrefen(true);
330 reg.set_vrefen(true); 316 });
331 });
332 }
333 317
334 VrefInt {} 318 VrefInt {}
335 } 319 }
336 320
337 pub fn enable_temperature(&self) -> Temperature { 321 pub fn enable_temperature(&self) -> Temperature {
338 unsafe { 322 T::common_regs().ccr().modify(|reg| {
339 T::common_regs().ccr().modify(|reg| { 323 reg.set_vsenseen(true);
340 reg.set_vsenseen(true); 324 });
341 });
342 }
343 325
344 Temperature {} 326 Temperature {}
345 } 327 }
346 328
347 pub fn enable_vbat(&self) -> Vbat { 329 pub fn enable_vbat(&self) -> Vbat {
348 unsafe { 330 T::common_regs().ccr().modify(|reg| {
349 T::common_regs().ccr().modify(|reg| { 331 reg.set_vbaten(true);
350 reg.set_vbaten(true); 332 });
351 });
352 }
353 333
354 Vbat {} 334 Vbat {}
355 } 335 }
@@ -359,30 +339,26 @@ impl<'d, T: Instance> Adc<'d, T> {
359 } 339 }
360 340
361 pub fn set_resolution(&mut self, resolution: Resolution) { 341 pub fn set_resolution(&mut self, resolution: Resolution) {
362 unsafe { 342 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
363 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
364 }
365 } 343 }
366 344
367 /// Perform a single conversion. 345 /// Perform a single conversion.
368 fn convert(&mut self) -> u16 { 346 fn convert(&mut self) -> u16 {
369 unsafe { 347 T::regs().isr().modify(|reg| {
370 T::regs().isr().modify(|reg| { 348 reg.set_eos(true);
371 reg.set_eos(true); 349 reg.set_eoc(true);
372 reg.set_eoc(true); 350 });
373 });
374
375 // Start conversion
376 T::regs().cr().modify(|reg| {
377 reg.set_adstart(true);
378 });
379
380 while !T::regs().isr().read().eos() {
381 // spin
382 }
383 351
384 T::regs().dr().read().0 as u16 352 // Start conversion
353 T::regs().cr().modify(|reg| {
354 reg.set_adstart(true);
355 });
356
357 while !T::regs().isr().read().eos() {
358 // spin
385 } 359 }
360
361 T::regs().dr().read().0 as u16
386 } 362 }
387 363
388 pub fn read<P>(&mut self, pin: &mut P) -> u16 364 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -390,18 +366,16 @@ impl<'d, T: Instance> Adc<'d, T> {
390 P: AdcPin<T>, 366 P: AdcPin<T>,
391 P: crate::gpio::sealed::Pin, 367 P: crate::gpio::sealed::Pin,
392 { 368 {
393 unsafe { 369 pin.set_as_analog();
394 pin.set_as_analog();
395 370
396 self.read_channel(pin.channel()) 371 self.read_channel(pin.channel())
397 }
398 } 372 }
399 373
400 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 374 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
401 unsafe { self.read_channel(channel.channel()) } 375 self.read_channel(channel.channel())
402 } 376 }
403 377
404 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 378 fn read_channel(&mut self, channel: u8) -> u16 {
405 // Configure channel 379 // Configure channel
406 Self::set_channel_sample_time(channel, self.sample_time); 380 Self::set_channel_sample_time(channel, self.sample_time);
407 381
@@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> {
417 self.convert() 391 self.convert()
418 } 392 }
419 393
420 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 394 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
421 let sample_time = sample_time.into(); 395 let sample_time = sample_time.into();
422 if ch <= 9 { 396 if ch <= 9 {
423 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); 397 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 08ba783ff..9cd40fd8b 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -105,10 +105,8 @@ impl<'d, T: Instance> Can<'d, T> {
105 ) -> Self { 105 ) -> Self {
106 into_ref!(peri, rx, tx); 106 into_ref!(peri, rx, tx);
107 107
108 unsafe { 108 rx.set_as_af(rx.af_num(), AFType::Input);
109 rx.set_as_af(rx.af_num(), AFType::Input); 109 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
110 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
111 }
112 110
113 T::enable(); 111 T::enable();
114 T::reset(); 112 T::reset();
@@ -146,6 +144,9 @@ impl<'d, T: Instance> Can<'d, T> {
146 T::SCEInterrupt::steal().enable(); 144 T::SCEInterrupt::steal().enable();
147 } 145 }
148 146
147 rx.set_as_af(rx.af_num(), AFType::Input);
148 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
149
149 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); 150 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
150 Self { can } 151 Self { can }
151 } 152 }
@@ -346,7 +347,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
346 fn drop(&mut self) { 347 fn drop(&mut self) {
347 // Cannot call `free()` because it moves the instance. 348 // Cannot call `free()` because it moves the instance.
348 // Manually reset the peripheral. 349 // Manually reset the peripheral.
349 unsafe { T::regs().mcr().write(|w| w.set_reset(true)) } 350 T::regs().mcr().write(|w| w.set_reset(true));
350 T::disable(); 351 T::disable();
351 } 352 }
352} 353}
@@ -422,7 +423,7 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
422foreach_peripheral!( 423foreach_peripheral!(
423 (can, $inst:ident) => { 424 (can, $inst:ident) => {
424 impl sealed::Instance for peripherals::$inst { 425 impl sealed::Instance for peripherals::$inst {
425 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _; 426 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
426 427
427 fn regs() -> &'static crate::pac::can::Can { 428 fn regs() -> &'static crate::pac::can::Can {
428 &crate::pac::$inst 429 &crate::pac::$inst
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index 393089eed..3946a2d47 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -27,26 +27,24 @@ impl<'d> Crc<'d> {
27 27
28 /// Resets the CRC unit to default value (0xFFFF_FFFF) 28 /// Resets the CRC unit to default value (0xFFFF_FFFF)
29 pub fn reset(&mut self) { 29 pub fn reset(&mut self) {
30 unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) }; 30 PAC_CRC.cr().write(|w| w.set_reset(true));
31 } 31 }
32 32
33 /// Feeds a word to the peripheral and returns the current CRC value 33 /// Feeds a word to the peripheral and returns the current CRC value
34 pub fn feed_word(&mut self, word: u32) -> u32 { 34 pub fn feed_word(&mut self, word: u32) -> u32 {
35 // write a single byte to the device, and return the result 35 // write a single byte to the device, and return the result
36 unsafe { 36 PAC_CRC.dr().write_value(word);
37 PAC_CRC.dr().write_value(word);
38 }
39 self.read() 37 self.read()
40 } 38 }
41 /// Feed a slice of words to the peripheral and return the result. 39 /// Feed a slice of words to the peripheral and return the result.
42 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 40 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
43 for word in words { 41 for word in words {
44 unsafe { PAC_CRC.dr().write_value(*word) } 42 PAC_CRC.dr().write_value(*word);
45 } 43 }
46 44
47 self.read() 45 self.read()
48 } 46 }
49 pub fn read(&self) -> u32 { 47 pub fn read(&self) -> u32 {
50 unsafe { PAC_CRC.dr().read() } 48 PAC_CRC.dr().read()
51 } 49 }
52} 50}
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 8acb3a770..f337055a7 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -85,95 +85,79 @@ impl<'d> Crc<'d> {
85 } 85 }
86 86
87 pub fn reset(&mut self) { 87 pub fn reset(&mut self) {
88 unsafe { 88 PAC_CRC.cr().modify(|w| w.set_reset(true));
89 PAC_CRC.cr().modify(|w| w.set_reset(true));
90 }
91 } 89 }
92 90
93 /// Reconfigures the CRC peripheral. Doesn't reset. 91 /// Reconfigures the CRC peripheral. Doesn't reset.
94 fn reconfigure(&mut self) { 92 fn reconfigure(&mut self) {
95 unsafe { 93 // Init CRC value
96 // Init CRC value 94 PAC_CRC.init().write_value(self._config.crc_init_value);
97 PAC_CRC.init().write_value(self._config.crc_init_value); 95 #[cfg(crc_v3)]
98 #[cfg(crc_v3)] 96 PAC_CRC.pol().write_value(self._config.crc_poly);
99 PAC_CRC.pol().write_value(self._config.crc_poly);
100 97
101 // configure CR components 98 // configure CR components
102 // (reverse I/O, polysize, poly) 99 // (reverse I/O, polysize, poly)
103 PAC_CRC.cr().write(|w| { 100 PAC_CRC.cr().write(|w| {
104 // configure reverse output 101 // configure reverse output
105 w.set_rev_out(match self._config.reverse_out { 102 w.set_rev_out(match self._config.reverse_out {
106 true => vals::RevOut::REVERSED, 103 true => vals::RevOut::REVERSED,
107 false => vals::RevOut::NORMAL, 104 false => vals::RevOut::NORMAL,
108 }); 105 });
109 // configure reverse input 106 // configure reverse input
110 w.set_rev_in(match self._config.reverse_in { 107 w.set_rev_in(match self._config.reverse_in {
111 InputReverseConfig::None => vals::RevIn::NORMAL, 108 InputReverseConfig::None => vals::RevIn::NORMAL,
112 InputReverseConfig::Byte => vals::RevIn::BYTE, 109 InputReverseConfig::Byte => vals::RevIn::BYTE,
113 InputReverseConfig::Halfword => vals::RevIn::HALFWORD, 110 InputReverseConfig::Halfword => vals::RevIn::HALFWORD,
114 InputReverseConfig::Word => vals::RevIn::WORD, 111 InputReverseConfig::Word => vals::RevIn::WORD,
115 }); 112 });
116 // configure the polynomial. 113 // configure the polynomial.
117 #[cfg(crc_v3)] 114 #[cfg(crc_v3)]
118 w.set_polysize(match self._config.poly_size { 115 w.set_polysize(match self._config.poly_size {
119 PolySize::Width7 => vals::Polysize::POLYSIZE7, 116 PolySize::Width7 => vals::Polysize::POLYSIZE7,
120 PolySize::Width8 => vals::Polysize::POLYSIZE8, 117 PolySize::Width8 => vals::Polysize::POLYSIZE8,
121 PolySize::Width16 => vals::Polysize::POLYSIZE16, 118 PolySize::Width16 => vals::Polysize::POLYSIZE16,
122 PolySize::Width32 => vals::Polysize::POLYSIZE32, 119 PolySize::Width32 => vals::Polysize::POLYSIZE32,
123 }); 120 });
124 }) 121 });
125 }
126 122
127 self.reset(); 123 self.reset();
128 } 124 }
129 125
130 /// Feeds a byte into the CRC peripheral. Returns the computed checksum. 126 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
131 pub fn feed_byte(&mut self, byte: u8) -> u32 { 127 pub fn feed_byte(&mut self, byte: u8) -> u32 {
132 unsafe { 128 PAC_CRC.dr8().write_value(byte);
133 PAC_CRC.dr8().write_value(byte); 129 PAC_CRC.dr().read()
134 PAC_CRC.dr().read()
135 }
136 } 130 }
137 131
138 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. 132 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
139 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { 133 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
140 for byte in bytes { 134 for byte in bytes {
141 unsafe { 135 PAC_CRC.dr8().write_value(*byte);
142 PAC_CRC.dr8().write_value(*byte);
143 }
144 } 136 }
145 unsafe { PAC_CRC.dr().read() } 137 PAC_CRC.dr().read()
146 } 138 }
147 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. 139 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
148 pub fn feed_halfword(&mut self, halfword: u16) -> u32 { 140 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
149 unsafe { 141 PAC_CRC.dr16().write_value(halfword);
150 PAC_CRC.dr16().write_value(halfword); 142 PAC_CRC.dr().read()
151 PAC_CRC.dr().read()
152 }
153 } 143 }
154 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. 144 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
155 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { 145 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
156 for halfword in halfwords { 146 for halfword in halfwords {
157 unsafe { 147 PAC_CRC.dr16().write_value(*halfword);
158 PAC_CRC.dr16().write_value(*halfword);
159 }
160 } 148 }
161 unsafe { PAC_CRC.dr().read() } 149 PAC_CRC.dr().read()
162 } 150 }
163 /// Feeds a words into the CRC peripheral. Returns the computed checksum. 151 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
164 pub fn feed_word(&mut self, word: u32) -> u32 { 152 pub fn feed_word(&mut self, word: u32) -> u32 {
165 unsafe { 153 PAC_CRC.dr().write_value(word as u32);
166 PAC_CRC.dr().write_value(word as u32); 154 PAC_CRC.dr().read()
167 PAC_CRC.dr().read()
168 }
169 } 155 }
170 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. 156 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
171 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 157 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
172 for word in words { 158 for word in words {
173 unsafe { 159 PAC_CRC.dr().write_value(*word as u32);
174 PAC_CRC.dr().write_value(*word as u32);
175 }
176 } 160 }
177 unsafe { PAC_CRC.dr().read() } 161 PAC_CRC.dr().read()
178 } 162 }
179} 163}
diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac.rs
index 60e856c78..631118877 100644
--- a/embassy-stm32/src/dac.rs
+++ b/embassy-stm32/src/dac.rs
@@ -121,13 +121,11 @@ impl<'d, T: Instance> Dac<'d, T> {
121 T::enable(); 121 T::enable();
122 T::reset(); 122 T::reset();
123 123
124 unsafe { 124 T::regs().cr().modify(|reg| {
125 T::regs().cr().modify(|reg| { 125 for ch in 0..channels {
126 for ch in 0..channels { 126 reg.set_en(ch as usize, true);
127 reg.set_en(ch as usize, true); 127 }
128 } 128 });
129 });
130 }
131 129
132 Self { channels, _peri: peri } 130 Self { channels, _peri: peri }
133 } 131 }
@@ -143,11 +141,9 @@ impl<'d, T: Instance> Dac<'d, T> {
143 141
144 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { 142 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
145 self.check_channel_exists(ch)?; 143 self.check_channel_exists(ch)?;
146 unsafe { 144 T::regs().cr().modify(|reg| {
147 T::regs().cr().modify(|reg| { 145 reg.set_en(ch.index(), on);
148 reg.set_en(ch.index(), on); 146 });
149 })
150 }
151 Ok(()) 147 Ok(())
152 } 148 }
153 149
@@ -162,56 +158,42 @@ impl<'d, T: Instance> Dac<'d, T> {
162 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { 158 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
163 self.check_channel_exists(Channel::Ch1)?; 159 self.check_channel_exists(Channel::Ch1)?;
164 unwrap!(self.disable_channel(Channel::Ch1)); 160 unwrap!(self.disable_channel(Channel::Ch1));
165 unsafe { 161 T::regs().cr().modify(|reg| {
166 T::regs().cr().modify(|reg| { 162 reg.set_tsel1(trigger.tsel());
167 reg.set_tsel1(trigger.tsel()); 163 });
168 })
169 }
170 Ok(()) 164 Ok(())
171 } 165 }
172 166
173 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { 167 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
174 self.check_channel_exists(Channel::Ch2)?; 168 self.check_channel_exists(Channel::Ch2)?;
175 unwrap!(self.disable_channel(Channel::Ch2)); 169 unwrap!(self.disable_channel(Channel::Ch2));
176 unsafe { 170 T::regs().cr().modify(|reg| {
177 T::regs().cr().modify(|reg| { 171 reg.set_tsel2(trigger.tsel());
178 reg.set_tsel2(trigger.tsel()); 172 });
179 })
180 }
181 Ok(()) 173 Ok(())
182 } 174 }
183 175
184 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { 176 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
185 self.check_channel_exists(ch)?; 177 self.check_channel_exists(ch)?;
186 unsafe { 178 T::regs().swtrigr().write(|reg| {
187 T::regs().swtrigr().write(|reg| { 179 reg.set_swtrig(ch.index(), true);
188 reg.set_swtrig(ch.index(), true); 180 });
189 });
190 }
191 Ok(()) 181 Ok(())
192 } 182 }
193 183
194 pub fn trigger_all(&mut self) { 184 pub fn trigger_all(&mut self) {
195 unsafe { 185 T::regs().swtrigr().write(|reg| {
196 T::regs().swtrigr().write(|reg| { 186 reg.set_swtrig(Channel::Ch1.index(), true);
197 reg.set_swtrig(Channel::Ch1.index(), true); 187 reg.set_swtrig(Channel::Ch2.index(), true);
198 reg.set_swtrig(Channel::Ch2.index(), true); 188 });
199 })
200 }
201 } 189 }
202 190
203 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { 191 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
204 self.check_channel_exists(ch)?; 192 self.check_channel_exists(ch)?;
205 match value { 193 match value {
206 Value::Bit8(v) => unsafe { 194 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
207 T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); 195 Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
208 }, 196 Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
209 Value::Bit12(v, Alignment::Left) => unsafe {
210 T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v));
211 },
212 Value::Bit12(v, Alignment::Right) => unsafe {
213 T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v));
214 },
215 } 197 }
216 Ok(()) 198 Ok(())
217 } 199 }
@@ -239,20 +221,20 @@ foreach_peripheral!(
239 } 221 }
240 222
241 fn reset() { 223 fn reset() {
242 critical_section::with(|_| unsafe { 224 critical_section::with(|_| {
243 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); 225 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
244 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); 226 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
245 }) 227 })
246 } 228 }
247 229
248 fn enable() { 230 fn enable() {
249 critical_section::with(|_| unsafe { 231 critical_section::with(|_| {
250 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); 232 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
251 }) 233 })
252 } 234 }
253 235
254 fn disable() { 236 fn disable() {
255 critical_section::with(|_| unsafe { 237 critical_section::with(|_| {
256 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); 238 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
257 }) 239 })
258 } 240 }
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 5f3fc6a93..78b026cb6 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9use crate::gpio::sealed::AFType; 9use crate::gpio::sealed::AFType;
10use crate::gpio::Speed; 10use crate::gpio::Speed;
11use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, Peripheral}; 12use crate::{interrupt, Peripheral};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
@@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
16 _phantom: PhantomData<T>, 16 _phantom: PhantomData<T>,
17} 17}
18 18
19impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
20 unsafe fn on_interrupt() { 20 unsafe fn on_interrupt() {
21 let ris = crate::pac::DCMI.ris().read(); 21 let ris = crate::pac::DCMI.ris().read();
22 if ris.err_ris() { 22 if ris.err_ris() {
@@ -96,8 +96,7 @@ impl Default for Config {
96macro_rules! config_pins { 96macro_rules! config_pins {
97 ($($pin:ident),*) => { 97 ($($pin:ident),*) => {
98 into_ref!($($pin),*); 98 into_ref!($($pin),*);
99 // NOTE(unsafe) Exclusive access to the registers 99 critical_section::with(|_| {
100 critical_section::with(|_| unsafe {
101 $( 100 $(
102 $pin.set_as_af($pin.af_num(), AFType::Input); 101 $pin.set_as_af($pin.af_num(), AFType::Input);
103 $pin.set_speed(Speed::VeryHigh); 102 $pin.set_speed(Speed::VeryHigh);
@@ -119,7 +118,7 @@ where
119 pub fn new_8bit( 118 pub fn new_8bit(
120 peri: impl Peripheral<P = T> + 'd, 119 peri: impl Peripheral<P = T> + 'd,
121 dma: impl Peripheral<P = Dma> + 'd, 120 dma: impl Peripheral<P = Dma> + 'd,
122 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 121 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
123 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 122 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
124 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 123 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
125 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 124 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -143,7 +142,7 @@ where
143 pub fn new_10bit( 142 pub fn new_10bit(
144 peri: impl Peripheral<P = T> + 'd, 143 peri: impl Peripheral<P = T> + 'd,
145 dma: impl Peripheral<P = Dma> + 'd, 144 dma: impl Peripheral<P = Dma> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 145 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 146 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
148 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 147 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
149 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 148 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -169,7 +168,7 @@ where
169 pub fn new_12bit( 168 pub fn new_12bit(
170 peri: impl Peripheral<P = T> + 'd, 169 peri: impl Peripheral<P = T> + 'd,
171 dma: impl Peripheral<P = Dma> + 'd, 170 dma: impl Peripheral<P = Dma> + 'd,
172 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 171 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
173 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 172 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
174 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 173 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
175 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 174 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -197,7 +196,7 @@ where
197 pub fn new_14bit( 196 pub fn new_14bit(
198 peri: impl Peripheral<P = T> + 'd, 197 peri: impl Peripheral<P = T> + 'd,
199 dma: impl Peripheral<P = Dma> + 'd, 198 dma: impl Peripheral<P = Dma> + 'd,
200 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 199 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
201 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 200 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
202 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 201 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
203 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 202 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -227,7 +226,7 @@ where
227 pub fn new_es_8bit( 226 pub fn new_es_8bit(
228 peri: impl Peripheral<P = T> + 'd, 227 peri: impl Peripheral<P = T> + 'd,
229 dma: impl Peripheral<P = Dma> + 'd, 228 dma: impl Peripheral<P = Dma> + 'd,
230 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 229 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
231 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 230 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
232 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 231 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
233 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 232 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -249,7 +248,7 @@ where
249 pub fn new_es_10bit( 248 pub fn new_es_10bit(
250 peri: impl Peripheral<P = T> + 'd, 249 peri: impl Peripheral<P = T> + 'd,
251 dma: impl Peripheral<P = Dma> + 'd, 250 dma: impl Peripheral<P = Dma> + 'd,
252 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 251 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
253 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 252 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
254 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 253 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
255 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 254 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -273,7 +272,7 @@ where
273 pub fn new_es_12bit( 272 pub fn new_es_12bit(
274 peri: impl Peripheral<P = T> + 'd, 273 peri: impl Peripheral<P = T> + 'd,
275 dma: impl Peripheral<P = Dma> + 'd, 274 dma: impl Peripheral<P = Dma> + 'd,
276 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 275 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
277 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 276 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
278 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 277 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
279 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 278 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -299,7 +298,7 @@ where
299 pub fn new_es_14bit( 298 pub fn new_es_14bit(
300 peri: impl Peripheral<P = T> + 'd, 299 peri: impl Peripheral<P = T> + 'd,
301 dma: impl Peripheral<P = Dma> + 'd, 300 dma: impl Peripheral<P = Dma> + 'd,
302 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 301 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
303 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 302 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
304 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 303 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
305 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 304 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -334,25 +333,23 @@ where
334 T::reset(); 333 T::reset();
335 T::enable(); 334 T::enable();
336 335
337 unsafe { 336 peri.regs().cr().modify(|r| {
338 peri.regs().cr().modify(|r| { 337 r.set_cm(true); // disable continuous mode (snapshot mode)
339 r.set_cm(true); // disable continuous mode (snapshot mode) 338 r.set_ess(use_embedded_synchronization);
340 r.set_ess(use_embedded_synchronization); 339 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
341 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); 340 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
342 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); 341 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
343 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); 342 r.set_fcrc(0x00); // capture every frame
344 r.set_fcrc(0x00); // capture every frame 343 r.set_edm(edm); // extended data mode
345 r.set_edm(edm); // extended data mode 344 });
346 });
347 }
348 345
349 unsafe { T::Interrupt::steal() }.unpend(); 346 T::Interrupt::unpend();
350 unsafe { T::Interrupt::steal() }.enable(); 347 unsafe { T::Interrupt::enable() };
351 348
352 Self { inner: peri, dma } 349 Self { inner: peri, dma }
353 } 350 }
354 351
355 unsafe fn toggle(enable: bool) { 352 fn toggle(enable: bool) {
356 crate::pac::DCMI.cr().modify(|r| { 353 crate::pac::DCMI.cr().modify(|r| {
357 r.set_enable(enable); 354 r.set_enable(enable);
358 r.set_capture(enable); 355 r.set_capture(enable);
@@ -360,23 +357,19 @@ where
360 } 357 }
361 358
362 fn enable_irqs() { 359 fn enable_irqs() {
363 unsafe { 360 crate::pac::DCMI.ier().modify(|r| {
364 crate::pac::DCMI.ier().modify(|r| { 361 r.set_err_ie(true);
365 r.set_err_ie(true); 362 r.set_ovr_ie(true);
366 r.set_ovr_ie(true); 363 r.set_frame_ie(true);
367 r.set_frame_ie(true); 364 });
368 });
369 }
370 } 365 }
371 366
372 fn clear_interrupt_flags() { 367 fn clear_interrupt_flags() {
373 unsafe { 368 crate::pac::DCMI.icr().write(|r| {
374 crate::pac::DCMI.icr().write(|r| { 369 r.set_ovr_isc(true);
375 r.set_ovr_isc(true); 370 r.set_err_isc(true);
376 r.set_err_isc(true); 371 r.set_frame_isc(true);
377 r.set_frame_isc(true); 372 })
378 })
379 }
380 } 373 }
381 374
382 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. 375 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
@@ -392,41 +385,30 @@ where
392 return self.capture_giant(buffer).await; 385 return self.capture_giant(buffer).await;
393 } 386 }
394 } 387 }
388
395 async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { 389 async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
396 let r = self.inner.regs(); 390 let r = self.inner.regs();
397 let src = r.dr().ptr() as *mut u32; 391 let src = r.dr().as_ptr() as *mut u32;
398 let request = self.dma.request(); 392 let request = self.dma.request();
399 let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; 393 let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) };
400 394
401 Self::clear_interrupt_flags(); 395 Self::clear_interrupt_flags();
402 Self::enable_irqs(); 396 Self::enable_irqs();
403 397
404 unsafe { Self::toggle(true) }; 398 Self::toggle(true);
405 399
406 let result = poll_fn(|cx| { 400 let result = poll_fn(|cx| {
407 STATE.waker.register(cx.waker()); 401 STATE.waker.register(cx.waker());
408 402
409 let ris = unsafe { crate::pac::DCMI.ris().read() }; 403 let ris = crate::pac::DCMI.ris().read();
410 if ris.err_ris() { 404 if ris.err_ris() {
411 unsafe { 405 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
412 crate::pac::DCMI.icr().write(|r| {
413 r.set_err_isc(true);
414 })
415 };
416 Poll::Ready(Err(Error::PeripheralError)) 406 Poll::Ready(Err(Error::PeripheralError))
417 } else if ris.ovr_ris() { 407 } else if ris.ovr_ris() {
418 unsafe { 408 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
419 crate::pac::DCMI.icr().write(|r| {
420 r.set_ovr_isc(true);
421 })
422 };
423 Poll::Ready(Err(Error::Overrun)) 409 Poll::Ready(Err(Error::Overrun))
424 } else if ris.frame_ris() { 410 } else if ris.frame_ris() {
425 unsafe { 411 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
426 crate::pac::DCMI.icr().write(|r| {
427 r.set_frame_isc(true);
428 })
429 };
430 Poll::Ready(Ok(())) 412 Poll::Ready(Ok(()))
431 } else { 413 } else {
432 Poll::Pending 414 Poll::Pending
@@ -435,7 +417,7 @@ where
435 417
436 let (_, result) = embassy_futures::join::join(dma_read, result).await; 418 let (_, result) = embassy_futures::join::join(dma_read, result).await;
437 419
438 unsafe { Self::toggle(false) }; 420 Self::toggle(false);
439 421
440 result 422 result
441 } 423 }
@@ -468,7 +450,7 @@ where
468 let request = channel.request(); 450 let request = channel.request();
469 451
470 let r = self.inner.regs(); 452 let r = self.inner.regs();
471 let src = r.dr().ptr() as *mut u32; 453 let src = r.dr().as_ptr() as *mut u32;
472 454
473 let mut transfer = unsafe { 455 let mut transfer = unsafe {
474 crate::dma::DoubleBuffered::new_read( 456 crate::dma::DoubleBuffered::new_read(
@@ -526,38 +508,26 @@ where
526 let result = poll_fn(|cx| { 508 let result = poll_fn(|cx| {
527 STATE.waker.register(cx.waker()); 509 STATE.waker.register(cx.waker());
528 510
529 let ris = unsafe { crate::pac::DCMI.ris().read() }; 511 let ris = crate::pac::DCMI.ris().read();
530 if ris.err_ris() { 512 if ris.err_ris() {
531 unsafe { 513 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
532 crate::pac::DCMI.icr().write(|r| {
533 r.set_err_isc(true);
534 })
535 };
536 Poll::Ready(Err(Error::PeripheralError)) 514 Poll::Ready(Err(Error::PeripheralError))
537 } else if ris.ovr_ris() { 515 } else if ris.ovr_ris() {
538 unsafe { 516 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
539 crate::pac::DCMI.icr().write(|r| {
540 r.set_ovr_isc(true);
541 })
542 };
543 Poll::Ready(Err(Error::Overrun)) 517 Poll::Ready(Err(Error::Overrun))
544 } else if ris.frame_ris() { 518 } else if ris.frame_ris() {
545 unsafe { 519 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
546 crate::pac::DCMI.icr().write(|r| {
547 r.set_frame_isc(true);
548 })
549 };
550 Poll::Ready(Ok(())) 520 Poll::Ready(Ok(()))
551 } else { 521 } else {
552 Poll::Pending 522 Poll::Pending
553 } 523 }
554 }); 524 });
555 525
556 unsafe { Self::toggle(true) }; 526 Self::toggle(true);
557 527
558 let (_, result) = embassy_futures::join::join(dma_result, result).await; 528 let (_, result) = embassy_futures::join::join(dma_result, result).await;
559 529
560 unsafe { Self::toggle(false) }; 530 Self::toggle(false);
561 531
562 result 532 result
563 } 533 }
@@ -570,7 +540,7 @@ mod sealed {
570} 540}
571 541
572pub trait Instance: sealed::Instance + 'static { 542pub trait Instance: sealed::Instance + 'static {
573 type Interrupt: Interrupt; 543 type Interrupt: interrupt::typelevel::Interrupt;
574} 544}
575 545
576pin_trait!(D0Pin, Instance); 546pin_trait!(D0Pin, Instance);
@@ -602,7 +572,7 @@ macro_rules! impl_peripheral {
602 } 572 }
603 573
604 impl Instance for crate::peripherals::$inst { 574 impl Instance for crate::peripherals::$inst {
605 type Interrupt = crate::interrupt::$irq; 575 type Interrupt = crate::interrupt::typelevel::$irq;
606 } 576 }
607 }; 577 };
608} 578}
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 9dafa26d0..a307c803c 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -6,7 +6,6 @@ use core::sync::atomic::{fence, Ordering};
6use core::task::{Context, Poll, Waker}; 6use core::task::{Context, Poll, Waker};
7 7
8use atomic_polyfill::AtomicUsize; 8use atomic_polyfill::AtomicUsize;
9use embassy_cortex_m::interrupt::Priority;
10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
11use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
12 11
@@ -14,7 +13,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
14use super::word::{Word, WordSize}; 13use super::word::{Word, WordSize};
15use super::Dir; 14use super::Dir;
16use crate::_generated::BDMA_CHANNEL_COUNT; 15use crate::_generated::BDMA_CHANNEL_COUNT;
17use crate::interrupt::{Interrupt, InterruptExt}; 16use crate::interrupt::typelevel::Interrupt;
17use crate::interrupt::Priority;
18use crate::pac; 18use crate::pac;
19use crate::pac::bdma::{regs, vals}; 19use crate::pac::bdma::{regs, vals};
20 20
@@ -70,9 +70,8 @@ static STATE: State = State::new();
70pub(crate) unsafe fn init(irq_priority: Priority) { 70pub(crate) unsafe fn init(irq_priority: Priority) {
71 foreach_interrupt! { 71 foreach_interrupt! {
72 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 72 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
73 let irq = crate::interrupt::$irq::steal(); 73 crate::interrupt::typelevel::$irq::set_priority(irq_priority);
74 irq.set_priority(irq_priority); 74 crate::interrupt::typelevel::$irq::enable();
75 irq.enable();
76 }; 75 };
77 } 76 }
78 crate::_generated::init_bdma(); 77 crate::_generated::init_bdma();
@@ -108,7 +107,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
108 let cr = dma.ch(channel_num).cr(); 107 let cr = dma.ch(channel_num).cr();
109 108
110 if isr.teif(channel_num) { 109 if isr.teif(channel_num) {
111 panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); 110 panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
112 } 111 }
113 112
114 if isr.htif(channel_num) && cr.read().htie() { 113 if isr.htif(channel_num) && cr.read().htie() {
@@ -292,29 +291,25 @@ impl<'a, C: Channel> Transfer<'a, C> {
292 } 291 }
293 292
294 fn clear_irqs(&mut self) { 293 fn clear_irqs(&mut self) {
295 unsafe { 294 self.channel.regs().ifcr().write(|w| {
296 self.channel.regs().ifcr().write(|w| { 295 w.set_tcif(self.channel.num(), true);
297 w.set_tcif(self.channel.num(), true); 296 w.set_teif(self.channel.num(), true);
298 w.set_teif(self.channel.num(), true); 297 });
299 })
300 }
301 } 298 }
302 299
303 pub fn request_stop(&mut self) { 300 pub fn request_stop(&mut self) {
304 let ch = self.channel.regs().ch(self.channel.num()); 301 let ch = self.channel.regs().ch(self.channel.num());
305 302
306 // Disable the channel. Keep the IEs enabled so the irqs still fire. 303 // Disable the channel. Keep the IEs enabled so the irqs still fire.
307 unsafe { 304 ch.cr().write(|w| {
308 ch.cr().write(|w| { 305 w.set_teie(true);
309 w.set_teie(true); 306 w.set_tcie(true);
310 w.set_tcie(true); 307 });
311 })
312 }
313 } 308 }
314 309
315 pub fn is_running(&mut self) -> bool { 310 pub fn is_running(&mut self) -> bool {
316 let ch = self.channel.regs().ch(self.channel.num()); 311 let ch = self.channel.regs().ch(self.channel.num());
317 let en = unsafe { ch.cr().read() }.en(); 312 let en = ch.cr().read().en();
318 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; 313 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
319 en && !tcif 314 en && !tcif
320 } 315 }
@@ -323,11 +318,12 @@ impl<'a, C: Channel> Transfer<'a, C> {
323 /// Note: this will be zero for transfers that completed without cancellation. 318 /// Note: this will be zero for transfers that completed without cancellation.
324 pub fn get_remaining_transfers(&self) -> u16 { 319 pub fn get_remaining_transfers(&self) -> u16 {
325 let ch = self.channel.regs().ch(self.channel.num()); 320 let ch = self.channel.regs().ch(self.channel.num());
326 unsafe { ch.ndtr().read() }.ndt() 321 ch.ndtr().read().ndt()
327 } 322 }
328 323
329 pub fn blocking_wait(mut self) { 324 pub fn blocking_wait(mut self) {
330 while self.is_running() {} 325 while self.is_running() {}
326 self.request_stop();
331 327
332 // "Subsequent reads and writes cannot be moved ahead of preceding reads." 328 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
333 fence(Ordering::SeqCst); 329 fence(Ordering::SeqCst);
@@ -367,7 +363,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
367impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 363impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
368 fn get_remaining_transfers(&self) -> usize { 364 fn get_remaining_transfers(&self) -> usize {
369 let ch = self.0.regs().ch(self.0.num()); 365 let ch = self.0.regs().ch(self.0.num());
370 unsafe { ch.ndtr().read() }.ndt() as usize 366 ch.ndtr().read().ndt() as usize
371 } 367 }
372 368
373 fn get_complete_count(&self) -> usize { 369 fn get_complete_count(&self) -> usize {
@@ -443,7 +439,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
443 439
444 pub fn start(&mut self) { 440 pub fn start(&mut self) {
445 let ch = self.channel.regs().ch(self.channel.num()); 441 let ch = self.channel.regs().ch(self.channel.num());
446 unsafe { ch.cr().write_value(self.cr) } 442 ch.cr().write_value(self.cr)
447 } 443 }
448 444
449 pub fn clear(&mut self) { 445 pub fn clear(&mut self) {
@@ -470,31 +466,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
470 466
471 fn clear_irqs(&mut self) { 467 fn clear_irqs(&mut self) {
472 let dma = self.channel.regs(); 468 let dma = self.channel.regs();
473 unsafe { 469 dma.ifcr().write(|w| {
474 dma.ifcr().write(|w| { 470 w.set_htif(self.channel.num(), true);
475 w.set_htif(self.channel.num(), true); 471 w.set_tcif(self.channel.num(), true);
476 w.set_tcif(self.channel.num(), true); 472 w.set_teif(self.channel.num(), true);
477 w.set_teif(self.channel.num(), true); 473 });
478 })
479 }
480 } 474 }
481 475
482 pub fn request_stop(&mut self) { 476 pub fn request_stop(&mut self) {
483 let ch = self.channel.regs().ch(self.channel.num()); 477 let ch = self.channel.regs().ch(self.channel.num());
484 478
485 // Disable the channel. Keep the IEs enabled so the irqs still fire. 479 // Disable the channel. Keep the IEs enabled so the irqs still fire.
486 unsafe { 480 ch.cr().write(|w| {
487 ch.cr().write(|w| { 481 w.set_teie(true);
488 w.set_teie(true); 482 w.set_htie(true);
489 w.set_htie(true); 483 w.set_tcie(true);
490 w.set_tcie(true); 484 });
491 })
492 }
493 } 485 }
494 486
495 pub fn is_running(&mut self) -> bool { 487 pub fn is_running(&mut self) -> bool {
496 let ch = self.channel.regs().ch(self.channel.num()); 488 let ch = self.channel.regs().ch(self.channel.num());
497 unsafe { ch.cr().read() }.en() 489 ch.cr().read().en()
498 } 490 }
499} 491}
500 492
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 47b749ece..8abe541d3 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -5,7 +5,6 @@ use core::sync::atomic::{fence, Ordering};
5use core::task::{Context, Poll, Waker}; 5use core::task::{Context, Poll, Waker};
6 6
7use atomic_polyfill::AtomicUsize; 7use atomic_polyfill::AtomicUsize;
8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11 10
@@ -13,7 +12,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
13use super::word::{Word, WordSize}; 12use super::word::{Word, WordSize};
14use super::Dir; 13use super::Dir;
15use crate::_generated::DMA_CHANNEL_COUNT; 14use crate::_generated::DMA_CHANNEL_COUNT;
16use crate::interrupt::{Interrupt, InterruptExt}; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::Priority;
17use crate::pac::dma::{regs, vals}; 17use crate::pac::dma::{regs, vals};
18use crate::{interrupt, pac}; 18use crate::{interrupt, pac};
19 19
@@ -149,9 +149,8 @@ static STATE: State = State::new();
149pub(crate) unsafe fn init(irq_priority: Priority) { 149pub(crate) unsafe fn init(irq_priority: Priority) {
150 foreach_interrupt! { 150 foreach_interrupt! {
151 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 151 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
152 let irq = interrupt::$irq::steal(); 152 interrupt::typelevel::$irq::set_priority(irq_priority);
153 irq.set_priority(irq_priority); 153 interrupt::typelevel::$irq::enable();
154 irq.enable();
155 }; 154 };
156 } 155 }
157 crate::_generated::init_dma(); 156 crate::_generated::init_dma();
@@ -184,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
184 let isr = dma.isr(channel_num / 4).read(); 183 let isr = dma.isr(channel_num / 4).read();
185 184
186 if isr.teif(channel_num % 4) { 185 if isr.teif(channel_num % 4) {
187 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); 186 panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
188 } 187 }
189 188
190 if isr.htif(channel_num % 4) && cr.read().htie() { 189 if isr.htif(channel_num % 4) && cr.read().htie() {
@@ -388,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> {
388 let isrn = self.channel.num() / 4; 387 let isrn = self.channel.num() / 4;
389 let isrbit = self.channel.num() % 4; 388 let isrbit = self.channel.num() % 4;
390 389
391 unsafe { 390 self.channel.regs().ifcr(isrn).write(|w| {
392 self.channel.regs().ifcr(isrn).write(|w| { 391 w.set_tcif(isrbit, true);
393 w.set_tcif(isrbit, true); 392 w.set_teif(isrbit, true);
394 w.set_teif(isrbit, true); 393 });
395 })
396 }
397 } 394 }
398 395
399 pub fn request_stop(&mut self) { 396 pub fn request_stop(&mut self) {
400 let ch = self.channel.regs().st(self.channel.num()); 397 let ch = self.channel.regs().st(self.channel.num());
401 398
402 // Disable the channel. Keep the IEs enabled so the irqs still fire. 399 // Disable the channel. Keep the IEs enabled so the irqs still fire.
403 unsafe { 400 ch.cr().write(|w| {
404 ch.cr().write(|w| { 401 w.set_teie(true);
405 w.set_teie(true); 402 w.set_tcie(true);
406 w.set_tcie(true); 403 });
407 })
408 }
409 } 404 }
410 405
411 pub fn is_running(&mut self) -> bool { 406 pub fn is_running(&mut self) -> bool {
412 let ch = self.channel.regs().st(self.channel.num()); 407 let ch = self.channel.regs().st(self.channel.num());
413 unsafe { ch.cr().read() }.en() 408 ch.cr().read().en()
414 } 409 }
415 410
416 /// Gets the total remaining transfers for the channel 411 /// Gets the total remaining transfers for the channel
417 /// Note: this will be zero for transfers that completed without cancellation. 412 /// Note: this will be zero for transfers that completed without cancellation.
418 pub fn get_remaining_transfers(&self) -> u16 { 413 pub fn get_remaining_transfers(&self) -> u16 {
419 let ch = self.channel.regs().st(self.channel.num()); 414 let ch = self.channel.regs().st(self.channel.num());
420 unsafe { ch.ndtr().read() }.ndt() 415 ch.ndtr().read().ndt()
421 } 416 }
422 417
423 pub fn blocking_wait(mut self) { 418 pub fn blocking_wait(mut self) {
@@ -538,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
538 let isrn = channel_number / 4; 533 let isrn = channel_number / 4;
539 let isrbit = channel_number % 4; 534 let isrbit = channel_number % 4;
540 535
541 unsafe { 536 dma.ifcr(isrn).write(|w| {
542 dma.ifcr(isrn).write(|w| { 537 w.set_htif(isrbit, true);
543 w.set_htif(isrbit, true); 538 w.set_tcif(isrbit, true);
544 w.set_tcif(isrbit, true); 539 w.set_teif(isrbit, true);
545 w.set_teif(isrbit, true); 540 });
546 })
547 }
548 } 541 }
549 542
550 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { 543 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
@@ -559,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
559 552
560 pub fn is_buffer0_accessible(&mut self) -> bool { 553 pub fn is_buffer0_accessible(&mut self) -> bool {
561 let ch = self.channel.regs().st(self.channel.num()); 554 let ch = self.channel.regs().st(self.channel.num());
562 unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1 555 ch.cr().read().ct() == vals::Ct::MEMORY1
563 } 556 }
564 557
565 pub fn set_waker(&mut self, waker: &Waker) { 558 pub fn set_waker(&mut self, waker: &Waker) {
@@ -570,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
570 let ch = self.channel.regs().st(self.channel.num()); 563 let ch = self.channel.regs().st(self.channel.num());
571 564
572 // Disable the channel. Keep the IEs enabled so the irqs still fire. 565 // Disable the channel. Keep the IEs enabled so the irqs still fire.
573 unsafe { 566 ch.cr().write(|w| {
574 ch.cr().write(|w| { 567 w.set_teie(true);
575 w.set_teie(true); 568 w.set_tcie(true);
576 w.set_tcie(true); 569 });
577 })
578 }
579 } 570 }
580 571
581 pub fn is_running(&mut self) -> bool { 572 pub fn is_running(&mut self) -> bool {
582 let ch = self.channel.regs().st(self.channel.num()); 573 let ch = self.channel.regs().st(self.channel.num());
583 unsafe { ch.cr().read() }.en() 574 ch.cr().read().en()
584 } 575 }
585 576
586 /// Gets the total remaining transfers for the channel 577 /// Gets the total remaining transfers for the channel
587 /// Note: this will be zero for transfers that completed without cancellation. 578 /// Note: this will be zero for transfers that completed without cancellation.
588 pub fn get_remaining_transfers(&self) -> u16 { 579 pub fn get_remaining_transfers(&self) -> u16 {
589 let ch = self.channel.regs().st(self.channel.num()); 580 let ch = self.channel.regs().st(self.channel.num());
590 unsafe { ch.ndtr().read() }.ndt() 581 ch.ndtr().read().ndt()
591 } 582 }
592} 583}
593 584
@@ -608,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
608impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 599impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
609 fn get_remaining_transfers(&self) -> usize { 600 fn get_remaining_transfers(&self) -> usize {
610 let ch = self.0.regs().st(self.0.num()); 601 let ch = self.0.regs().st(self.0.num());
611 unsafe { ch.ndtr().read() }.ndt() as usize 602 ch.ndtr().read().ndt() as usize
612 } 603 }
613 604
614 fn get_complete_count(&self) -> usize { 605 fn get_complete_count(&self) -> usize {
@@ -699,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
699 690
700 pub fn start(&mut self) { 691 pub fn start(&mut self) {
701 let ch = self.channel.regs().st(self.channel.num()); 692 let ch = self.channel.regs().st(self.channel.num());
702 unsafe { ch.cr().write_value(self.cr) } 693 ch.cr().write_value(self.cr);
703 } 694 }
704 695
705 pub fn clear(&mut self) { 696 pub fn clear(&mut self) {
@@ -730,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
730 let isrn = channel_number / 4; 721 let isrn = channel_number / 4;
731 let isrbit = channel_number % 4; 722 let isrbit = channel_number % 4;
732 723
733 unsafe { 724 dma.ifcr(isrn).write(|w| {
734 dma.ifcr(isrn).write(|w| { 725 w.set_htif(isrbit, true);
735 w.set_htif(isrbit, true); 726 w.set_tcif(isrbit, true);
736 w.set_tcif(isrbit, true); 727 w.set_teif(isrbit, true);
737 w.set_teif(isrbit, true); 728 });
738 })
739 }
740 } 729 }
741 730
742 pub fn request_stop(&mut self) { 731 pub fn request_stop(&mut self) {
743 let ch = self.channel.regs().st(self.channel.num()); 732 let ch = self.channel.regs().st(self.channel.num());
744 733
745 // Disable the channel. Keep the IEs enabled so the irqs still fire. 734 // Disable the channel. Keep the IEs enabled so the irqs still fire.
746 unsafe { 735 ch.cr().write(|w| {
747 ch.cr().write(|w| { 736 w.set_teie(true);
748 w.set_teie(true); 737 w.set_htie(true);
749 w.set_htie(true); 738 w.set_tcie(true);
750 w.set_tcie(true); 739 });
751 })
752 }
753 } 740 }
754 741
755 pub fn is_running(&mut self) -> bool { 742 pub fn is_running(&mut self) -> bool {
756 let ch = self.channel.regs().st(self.channel.num()); 743 let ch = self.channel.regs().st(self.channel.num());
757 unsafe { ch.cr().read() }.en() 744 ch.cr().read().en()
758 } 745 }
759} 746}
760 747
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index a8c4c5827..36fc03403 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -2,7 +2,7 @@
2 2
3use crate::{pac, peripherals}; 3use crate::{pac, peripherals};
4 4
5pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { 5pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
6 let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); 6 let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num());
7 ch_mux_regs.write(|reg| { 7 ch_mux_regs.write(|reg| {
8 reg.set_nbreq(0); 8 reg.set_nbreq(0);
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 5a516ccda..c600df92d 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -5,14 +5,14 @@ use core::pin::Pin;
5use core::sync::atomic::{fence, Ordering}; 5use core::sync::atomic::{fence, Ordering};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11 10
12use super::word::{Word, WordSize}; 11use super::word::{Word, WordSize};
13use super::Dir; 12use super::Dir;
14use crate::_generated::GPDMA_CHANNEL_COUNT; 13use crate::_generated::GPDMA_CHANNEL_COUNT;
15use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::typelevel::Interrupt;
15use crate::interrupt::Priority;
16use crate::pac; 16use crate::pac;
17use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
18 18
@@ -56,9 +56,8 @@ static STATE: State = State::new();
56pub(crate) unsafe fn init(irq_priority: Priority) { 56pub(crate) unsafe fn init(irq_priority: Priority) {
57 foreach_interrupt! { 57 foreach_interrupt! {
58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { 58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
59 let irq = crate::interrupt::$irq::steal(); 59 crate::interrupt::typelevel::$irq::set_priority(irq_priority);
60 irq.set_priority(irq_priority); 60 crate::interrupt::typelevel::$irq::enable();
61 irq.enable();
62 }; 61 };
63 } 62 }
64 crate::_generated::init_gpdma(); 63 crate::_generated::init_gpdma();
@@ -93,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
93 if sr.dtef() { 92 if sr.dtef() {
94 panic!( 93 panic!(
95 "DMA: data transfer error on DMA@{:08x} channel {}", 94 "DMA: data transfer error on DMA@{:08x} channel {}",
96 dma.0 as u32, channel_num 95 dma.as_ptr() as u32,
96 channel_num
97 ); 97 );
98 } 98 }
99 if sr.usef() { 99 if sr.usef() {
100 panic!( 100 panic!(
101 "DMA: user settings error on DMA@{:08x} channel {}", 101 "DMA: user settings error on DMA@{:08x} channel {}",
102 dma.0 as u32, channel_num 102 dma.as_ptr() as u32,
103 channel_num
103 ); 104 );
104 } 105 }
105 106
@@ -299,26 +300,24 @@ impl<'a, C: Channel> Transfer<'a, C> {
299 let ch = self.channel.regs().ch(self.channel.num()); 300 let ch = self.channel.regs().ch(self.channel.num());
300 301
301 // Disable the channel. Keep the IEs enabled so the irqs still fire. 302 // Disable the channel. Keep the IEs enabled so the irqs still fire.
302 unsafe { 303 ch.cr().write(|w| {
303 ch.cr().write(|w| { 304 w.set_tcie(true);
304 w.set_tcie(true); 305 w.set_useie(true);
305 w.set_useie(true); 306 w.set_dteie(true);
306 w.set_dteie(true); 307 w.set_suspie(true);
307 w.set_suspie(true); 308 })
308 })
309 }
310 } 309 }
311 310
312 pub fn is_running(&mut self) -> bool { 311 pub fn is_running(&mut self) -> bool {
313 let ch = self.channel.regs().ch(self.channel.num()); 312 let ch = self.channel.regs().ch(self.channel.num());
314 !unsafe { ch.sr().read() }.tcf() 313 !ch.sr().read().tcf()
315 } 314 }
316 315
317 /// Gets the total remaining transfers for the channel 316 /// Gets the total remaining transfers for the channel
318 /// Note: this will be zero for transfers that completed without cancellation. 317 /// Note: this will be zero for transfers that completed without cancellation.
319 pub fn get_remaining_transfers(&self) -> u16 { 318 pub fn get_remaining_transfers(&self) -> u16 {
320 let ch = self.channel.regs().ch(self.channel.num()); 319 let ch = self.channel.regs().ch(self.channel.num());
321 unsafe { ch.br1().read() }.bndt() 320 ch.br1().read().bndt()
322 } 321 }
323 322
324 pub fn blocking_wait(mut self) { 323 pub fn blocking_wait(mut self) {
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 3ac0d1b3d..0858587bd 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -26,11 +26,11 @@ pub mod word;
26 26
27use core::mem; 27use core::mem;
28 28
29use embassy_cortex_m::interrupt::Priority;
30use embassy_hal_common::impl_peripheral; 29use embassy_hal_common::impl_peripheral;
31 30
32#[cfg(dmamux)] 31#[cfg(dmamux)]
33pub use self::dmamux::*; 32pub use self::dmamux::*;
33use crate::interrupt::Priority;
34 34
35#[derive(Debug, Copy, Clone, PartialEq, Eq)] 35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))] 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 8ef2c3584..b53c2d0fa 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -5,7 +5,6 @@ mod tx_desc;
5 5
6use core::sync::atomic::{fence, Ordering}; 6use core::sync::atomic::{fence, Ordering};
7 7
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 9use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
11 10
@@ -14,6 +13,7 @@ pub(crate) use self::tx_desc::{TDes, TDesRing};
14use super::*; 13use super::*;
15use crate::gpio::sealed::{AFType, Pin as __GpioPin}; 14use crate::gpio::sealed::{AFType, Pin as __GpioPin};
16use crate::gpio::AnyPin; 15use crate::gpio::AnyPin;
16use crate::interrupt::InterruptExt;
17#[cfg(eth_v1a)] 17#[cfg(eth_v1a)]
18use crate::pac::AFIO; 18use crate::pac::AFIO;
19#[cfg(any(eth_v1b, eth_v1c))] 19#[cfg(any(eth_v1b, eth_v1c))]
@@ -24,23 +24,21 @@ use crate::{interrupt, Peripheral};
24/// Interrupt handler. 24/// Interrupt handler.
25pub struct InterruptHandler {} 25pub struct InterruptHandler {}
26 26
27impl interrupt::Handler<interrupt::ETH> for InterruptHandler { 27impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
28 unsafe fn on_interrupt() { 28 unsafe fn on_interrupt() {
29 WAKER.wake(); 29 WAKER.wake();
30 30
31 // TODO: Check and clear more flags 31 // TODO: Check and clear more flags
32 unsafe { 32 let dma = ETH.ethernet_dma();
33 let dma = ETH.ethernet_dma(); 33
34 34 dma.dmasr().modify(|w| {
35 dma.dmasr().modify(|w| { 35 w.set_ts(true);
36 w.set_ts(true); 36 w.set_rs(true);
37 w.set_rs(true); 37 w.set_nis(true);
38 w.set_nis(true); 38 });
39 }); 39 // Delay two peripheral's clock
40 // Delay two peripheral's clock 40 dma.dmasr().read();
41 dma.dmasr().read(); 41 dma.dmasr().read();
42 dma.dmasr().read();
43 }
44 } 42 }
45} 43}
46 44
@@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
59#[cfg(eth_v1a)] 57#[cfg(eth_v1a)]
60macro_rules! config_in_pins { 58macro_rules! config_in_pins {
61 ($($pin:ident),*) => { 59 ($($pin:ident),*) => {
62 // NOTE(unsafe) Exclusive access to the registers
63 critical_section::with(|_| { 60 critical_section::with(|_| {
64 $( 61 $(
65 // TODO properly create a set_as_input function 62 // TODO properly create a set_as_input function
@@ -72,7 +69,6 @@ macro_rules! config_in_pins {
72#[cfg(eth_v1a)] 69#[cfg(eth_v1a)]
73macro_rules! config_af_pins { 70macro_rules! config_af_pins {
74 ($($pin:ident),*) => { 71 ($($pin:ident),*) => {
75 // NOTE(unsafe) Exclusive access to the registers
76 critical_section::with(|_| { 72 critical_section::with(|_| {
77 $( 73 $(
78 // We are lucky here, this configures to max speed (50MHz) 74 // We are lucky here, this configures to max speed (50MHz)
@@ -85,7 +81,6 @@ macro_rules! config_af_pins {
85#[cfg(any(eth_v1b, eth_v1c))] 81#[cfg(any(eth_v1b, eth_v1c))]
86macro_rules! config_pins { 82macro_rules! config_pins {
87 ($($pin:ident),*) => { 83 ($($pin:ident),*) => {
88 // NOTE(unsafe) Exclusive access to the registers
89 critical_section::with(|_| { 84 critical_section::with(|_| {
90 $( 85 $(
91 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 86 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@@ -100,7 +95,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
100 pub fn new<const TX: usize, const RX: usize>( 95 pub fn new<const TX: usize, const RX: usize>(
101 queue: &'d mut PacketQueue<TX, RX>, 96 queue: &'d mut PacketQueue<TX, RX>,
102 peri: impl Peripheral<P = T> + 'd, 97 peri: impl Peripheral<P = T> + 'd,
103 _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, 98 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
104 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 99 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
105 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 100 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
106 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 101 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -116,222 +111,208 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
116 ) -> Self { 111 ) -> Self {
117 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 112 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
118 113
119 unsafe { 114 // Enable the necessary Clocks
120 // Enable the necessary Clocks 115 #[cfg(eth_v1a)]
121 // NOTE(unsafe) We have exclusive access to the registers 116 critical_section::with(|_| {
122 #[cfg(eth_v1a)] 117 RCC.apb2enr().modify(|w| w.set_afioen(true));
123 critical_section::with(|_| {
124 RCC.apb2enr().modify(|w| w.set_afioen(true));
125
126 // Select RMII (Reduced Media Independent Interface)
127 // Must be done prior to enabling peripheral clock
128 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
129
130 RCC.ahbenr().modify(|w| {
131 w.set_ethen(true);
132 w.set_ethtxen(true);
133 w.set_ethrxen(true);
134 });
135 });
136
137 #[cfg(any(eth_v1b, eth_v1c))]
138 critical_section::with(|_| {
139 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
140 RCC.ahb1enr().modify(|w| {
141 w.set_ethen(true);
142 w.set_ethtxen(true);
143 w.set_ethrxen(true);
144 });
145
146 // RMII (Reduced Media Independent Interface)
147 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
148 });
149
150 #[cfg(eth_v1a)]
151 {
152 config_in_pins!(ref_clk, rx_d0, rx_d1);
153 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
154 }
155
156 #[cfg(any(eth_v1b, eth_v1c))]
157 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
158
159 // NOTE(unsafe) We have exclusive access to the registers
160 let dma = ETH.ethernet_dma();
161 let mac = ETH.ethernet_mac();
162
163 // Reset and wait
164 dma.dmabmr().modify(|w| w.set_sr(true));
165 while dma.dmabmr().read().sr() {}
166
167 mac.maccr().modify(|w| {
168 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
169 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
170 w.set_fes(Fes::FES100); // fast ethernet speed
171 w.set_dm(Dm::FULLDUPLEX); // full duplex
172 // TODO: Carrier sense ? ECRSFD
173 });
174
175 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
176 // so the LR write must happen after the HR write.
177 mac.maca0hr()
178 .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
179 mac.maca0lr().write(|w| {
180 w.set_maca0l(
181 u32::from(mac_addr[0])
182 | (u32::from(mac_addr[1]) << 8)
183 | (u32::from(mac_addr[2]) << 16)
184 | (u32::from(mac_addr[3]) << 24),
185 )
186 });
187
188 // pause time
189 mac.macfcr().modify(|w| w.set_pt(0x100));
190
191 // Transfer and Forward, Receive and Forward
192 dma.dmaomr().modify(|w| {
193 w.set_tsf(Tsf::STOREFORWARD);
194 w.set_rsf(Rsf::STOREFORWARD);
195 });
196 118
197 dma.dmabmr().modify(|w| { 119 // Select RMII (Reduced Media Independent Interface)
198 w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? 120 // Must be done prior to enabling peripheral clock
199 }); 121 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
200 122
201 // TODO MTU size setting not found for v1 ethernet, check if correct 123 RCC.ahbenr().modify(|w| {
202 124 w.set_ethen(true);
203 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 125 w.set_ethtxen(true);
204 let hclk = crate::rcc::get_freqs().ahb1; 126 w.set_ethrxen(true);
205 let hclk_mhz = hclk.0 / 1_000_000;
206
207 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
208 let clock_range = match hclk_mhz {
209 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
210 25..=34 => Cr::CR_20_35, // Divide by 16
211 35..=59 => Cr::CR_35_60, // Divide by 26
212 60..=99 => Cr::CR_60_100, // Divide by 42
213 100..=149 => Cr::CR_100_150, // Divide by 62
214 150..=216 => Cr::CR_150_168, // Divide by 102
215 _ => {
216 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
217 }
218 };
219
220 let pins = [
221 ref_clk.map_into(),
222 mdio.map_into(),
223 mdc.map_into(),
224 crs.map_into(),
225 rx_d0.map_into(),
226 rx_d1.map_into(),
227 tx_d0.map_into(),
228 tx_d1.map_into(),
229 tx_en.map_into(),
230 ];
231
232 let mut this = Self {
233 _peri: peri,
234 pins,
235 _phy: phy,
236 clock_range,
237 phy_addr,
238 mac_addr,
239 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
240 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
241 };
242
243 fence(Ordering::SeqCst);
244
245 let mac = ETH.ethernet_mac();
246 let dma = ETH.ethernet_dma();
247
248 mac.maccr().modify(|w| {
249 w.set_re(true);
250 w.set_te(true);
251 });
252 dma.dmaomr().modify(|w| {
253 w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
254 w.set_st(St::STARTED); // start transmitting channel
255 w.set_sr(DmaomrSr::STARTED); // start receiving channel
256 }); 127 });
128 });
257 129
258 this.rx.demand_poll(); 130 #[cfg(any(eth_v1b, eth_v1c))]
259 131 critical_section::with(|_| {
260 // Enable interrupts 132 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
261 dma.dmaier().modify(|w| { 133 RCC.ahb1enr().modify(|w| {
262 w.set_nise(true); 134 w.set_ethen(true);
263 w.set_rie(true); 135 w.set_ethtxen(true);
264 w.set_tie(true); 136 w.set_ethrxen(true);
265 }); 137 });
266 138
267 P::phy_reset(&mut this); 139 // RMII (Reduced Media Independent Interface)
268 P::phy_init(&mut this); 140 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
141 });
269 142
270 interrupt::ETH::steal().unpend(); 143 #[cfg(eth_v1a)]
271 interrupt::ETH::steal().enable(); 144 {
272 145 config_in_pins!(ref_clk, rx_d0, rx_d1);
273 this 146 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
274 } 147 }
148
149 #[cfg(any(eth_v1b, eth_v1c))]
150 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
151
152 let dma = ETH.ethernet_dma();
153 let mac = ETH.ethernet_mac();
154
155 // Reset and wait
156 dma.dmabmr().modify(|w| w.set_sr(true));
157 while dma.dmabmr().read().sr() {}
158
159 mac.maccr().modify(|w| {
160 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
161 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
162 w.set_fes(Fes::FES100); // fast ethernet speed
163 w.set_dm(Dm::FULLDUPLEX); // full duplex
164 // TODO: Carrier sense ? ECRSFD
165 });
166
167 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
168 // so the LR write must happen after the HR write.
169 mac.maca0hr()
170 .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
171 mac.maca0lr().write(|w| {
172 w.set_maca0l(
173 u32::from(mac_addr[0])
174 | (u32::from(mac_addr[1]) << 8)
175 | (u32::from(mac_addr[2]) << 16)
176 | (u32::from(mac_addr[3]) << 24),
177 )
178 });
179
180 // pause time
181 mac.macfcr().modify(|w| w.set_pt(0x100));
182
183 // Transfer and Forward, Receive and Forward
184 dma.dmaomr().modify(|w| {
185 w.set_tsf(Tsf::STOREFORWARD);
186 w.set_rsf(Rsf::STOREFORWARD);
187 });
188
189 dma.dmabmr().modify(|w| {
190 w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ?
191 });
192
193 // TODO MTU size setting not found for v1 ethernet, check if correct
194
195 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
196 let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
197 let hclk_mhz = hclk.0 / 1_000_000;
198
199 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
200 let clock_range = match hclk_mhz {
201 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
202 25..=34 => Cr::CR_20_35, // Divide by 16
203 35..=59 => Cr::CR_35_60, // Divide by 26
204 60..=99 => Cr::CR_60_100, // Divide by 42
205 100..=149 => Cr::CR_100_150, // Divide by 62
206 150..=216 => Cr::CR_150_168, // Divide by 102
207 _ => {
208 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
209 }
210 };
211
212 let pins = [
213 ref_clk.map_into(),
214 mdio.map_into(),
215 mdc.map_into(),
216 crs.map_into(),
217 rx_d0.map_into(),
218 rx_d1.map_into(),
219 tx_d0.map_into(),
220 tx_d1.map_into(),
221 tx_en.map_into(),
222 ];
223
224 let mut this = Self {
225 _peri: peri,
226 pins,
227 _phy: phy,
228 clock_range,
229 phy_addr,
230 mac_addr,
231 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
232 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
233 };
234
235 fence(Ordering::SeqCst);
236
237 let mac = ETH.ethernet_mac();
238 let dma = ETH.ethernet_dma();
239
240 mac.maccr().modify(|w| {
241 w.set_re(true);
242 w.set_te(true);
243 });
244 dma.dmaomr().modify(|w| {
245 w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
246 w.set_st(St::STARTED); // start transmitting channel
247 w.set_sr(DmaomrSr::STARTED); // start receiving channel
248 });
249
250 this.rx.demand_poll();
251
252 // Enable interrupts
253 dma.dmaier().modify(|w| {
254 w.set_nise(true);
255 w.set_rie(true);
256 w.set_tie(true);
257 });
258
259 P::phy_reset(&mut this);
260 P::phy_init(&mut this);
261
262 interrupt::ETH.unpend();
263 unsafe { interrupt::ETH.enable() };
264
265 this
275 } 266 }
276} 267}
277 268
278unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 269unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
279 fn smi_read(&mut self, reg: u8) -> u16 { 270 fn smi_read(&mut self, reg: u8) -> u16 {
280 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 271 let mac = ETH.ethernet_mac();
281 unsafe { 272
282 let mac = ETH.ethernet_mac(); 273 mac.macmiiar().modify(|w| {
283 274 w.set_pa(self.phy_addr);
284 mac.macmiiar().modify(|w| { 275 w.set_mr(reg);
285 w.set_pa(self.phy_addr); 276 w.set_mw(Mw::READ); // read operation
286 w.set_mr(reg); 277 w.set_cr(self.clock_range);
287 w.set_mw(Mw::READ); // read operation 278 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
288 w.set_cr(self.clock_range); 279 });
289 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress 280 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
290 }); 281 mac.macmiidr().read().md()
291 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
292 mac.macmiidr().read().md()
293 }
294 } 282 }
295 283
296 fn smi_write(&mut self, reg: u8, val: u16) { 284 fn smi_write(&mut self, reg: u8, val: u16) {
297 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 285 let mac = ETH.ethernet_mac();
298 unsafe { 286
299 let mac = ETH.ethernet_mac(); 287 mac.macmiidr().write(|w| w.set_md(val));
300 288 mac.macmiiar().modify(|w| {
301 mac.macmiidr().write(|w| w.set_md(val)); 289 w.set_pa(self.phy_addr);
302 mac.macmiiar().modify(|w| { 290 w.set_mr(reg);
303 w.set_pa(self.phy_addr); 291 w.set_mw(Mw::WRITE); // write
304 w.set_mr(reg); 292 w.set_cr(self.clock_range);
305 w.set_mw(Mw::WRITE); // write 293 w.set_mb(MbProgress::BUSY);
306 w.set_cr(self.clock_range); 294 });
307 w.set_mb(MbProgress::BUSY); 295 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
308 });
309 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
310 }
311 } 296 }
312} 297}
313 298
314impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 299impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
315 fn drop(&mut self) { 300 fn drop(&mut self) {
316 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers 301 let dma = ETH.ethernet_dma();
317 unsafe { 302 let mac = ETH.ethernet_mac();
318 let dma = ETH.ethernet_dma();
319 let mac = ETH.ethernet_mac();
320
321 // Disable the TX DMA and wait for any previous transmissions to be completed
322 dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
323
324 // Disable MAC transmitter and receiver
325 mac.maccr().modify(|w| {
326 w.set_re(false);
327 w.set_te(false);
328 });
329 303
330 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); 304 // Disable the TX DMA and wait for any previous transmissions to be completed
331 } 305 dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
306
307 // Disable MAC transmitter and receiver
308 mac.maccr().modify(|w| {
309 w.set_re(false);
310 w.set_te(false);
311 });
332 312
333 // NOTE(unsafe) Exclusive access to the regs 313 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
334 critical_section::with(|_| unsafe { 314
315 critical_section::with(|_| {
335 for pin in self.pins.iter_mut() { 316 for pin in self.pins.iter_mut() {
336 pin.set_as_disconnected(); 317 pin.set_as_disconnected();
337 } 318 }
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 8b8566d92..01a073bb9 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> {
146 } 146 }
147 147
148 // Register rx descriptor start 148 // Register rx descriptor start
149 // NOTE (unsafe) Used for atomic writes 149 ETH.ethernet_dma()
150 unsafe { 150 .dmardlar()
151 ETH.ethernet_dma() 151 .write(|w| w.0 = descriptors.as_ptr() as u32);
152 .dmardlar()
153 .write(|w| w.0 = descriptors.as_ptr() as u32);
154 };
155 // We already have fences in `set_owned`, which is called in `setup` 152 // We already have fences in `set_owned`, which is called in `setup`
156 153
157 Self { 154 Self {
@@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> {
162 } 159 }
163 160
164 pub(crate) fn demand_poll(&self) { 161 pub(crate) fn demand_poll(&self) {
165 unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; 162 ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL));
166 } 163 }
167 164
168 /// Get current `RunningState` 165 /// Get current `RunningState`
169 fn running_state(&self) -> RunningState { 166 fn running_state(&self) -> RunningState {
170 match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { 167 match ETH.ethernet_dma().dmasr().read().rps() {
171 // Reset or Stop Receive Command issued 168 // Reset or Stop Receive Command issued
172 Rps::STOPPED => RunningState::Stopped, 169 Rps::STOPPED => RunningState::Stopped,
173 // Fetching receive transfer descriptor 170 // Fetching receive transfer descriptor
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs
index 0e63c5443..1317d20f4 100644
--- a/embassy-stm32/src/eth/v1/tx_desc.rs
+++ b/embassy-stm32/src/eth/v1/tx_desc.rs
@@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> {
120 } 120 }
121 121
122 // Register txdescriptor start 122 // Register txdescriptor start
123 // NOTE (unsafe) Used for atomic writes 123 ETH.ethernet_dma()
124 unsafe { 124 .dmatdlar()
125 ETH.ethernet_dma() 125 .write(|w| w.0 = descriptors.as_ptr() as u32);
126 .dmatdlar()
127 .write(|w| w.0 = descriptors.as_ptr() as u32);
128 }
129 126
130 Self { 127 Self {
131 descriptors, 128 descriptors,
@@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> {
169 self.index = 0 166 self.index = 0
170 } 167 }
171 // Request the DMA engine to poll the latest tx descriptor 168 // Request the DMA engine to poll the latest tx descriptor
172 unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } 169 ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1)
173 } 170 }
174} 171}
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 2426596fb..e9799adf1 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> {
73 73
74 // Initialize the pointers in the DMA engine. (There will be a memory barrier later 74 // Initialize the pointers in the DMA engine. (There will be a memory barrier later
75 // before the DMA engine is enabled.) 75 // before the DMA engine is enabled.)
76 // NOTE (unsafe) Used for atomic writes 76 let dma = ETH.ethernet_dma();
77 unsafe { 77 dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
78 let dma = ETH.ethernet_dma(); 78 dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
79 79 dma.dmactx_dtpr().write(|w| w.0 = 0);
80 dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
81 dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
82 dma.dmactx_dtpr().write(|w| w.0 = 0);
83 }
84 80
85 Self { 81 Self {
86 descriptors, 82 descriptors,
@@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> {
129 } 125 }
130 126
131 // signal DMA it can try again. 127 // signal DMA it can try again.
132 // NOTE(unsafe) Atomic write 128 ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0)
133 unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
134 } 129 }
135} 130}
136 131
@@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> {
199 desc.set_ready(buffers[i].0.as_mut_ptr()); 194 desc.set_ready(buffers[i].0.as_mut_ptr());
200 } 195 }
201 196
202 unsafe { 197 let dma = ETH.ethernet_dma();
203 let dma = ETH.ethernet_dma(); 198 dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
204 199 dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
205 dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); 200 dma.dmacrx_dtpr().write(|w| w.0 = 0);
206 dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
207 dma.dmacrx_dtpr().write(|w| w.0 = 0);
208 }
209 201
210 Self { 202 Self {
211 descriptors, 203 descriptors,
@@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> {
254 fence(Ordering::Release); 246 fence(Ordering::Release);
255 247
256 // signal DMA it can try again. 248 // signal DMA it can try again.
257 // NOTE(unsafe) Atomic write 249 ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0);
258 unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
259 250
260 // Increment index. 251 // Increment index.
261 self.index += 1; 252 self.index += 1;
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index b56c3e8ab..600e1d3bc 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -2,36 +2,34 @@ mod descriptors;
2 2
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
6use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
7 6
8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; 7pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::*; 8use super::*;
10use crate::gpio::sealed::{AFType, Pin as _}; 9use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 10use crate::gpio::{AnyPin, Speed};
11use crate::interrupt::InterruptExt;
12use crate::pac::ETH; 12use crate::pac::ETH;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, Peripheral};
14 14
15/// Interrupt handler. 15/// Interrupt handler.
16pub struct InterruptHandler {} 16pub struct InterruptHandler {}
17 17
18impl interrupt::Handler<interrupt::ETH> for InterruptHandler { 18impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
19 unsafe fn on_interrupt() { 19 unsafe fn on_interrupt() {
20 WAKER.wake(); 20 WAKER.wake();
21 21
22 // TODO: Check and clear more flags 22 // TODO: Check and clear more flags
23 unsafe { 23 let dma = ETH.ethernet_dma();
24 let dma = ETH.ethernet_dma(); 24
25 25 dma.dmacsr().modify(|w| {
26 dma.dmacsr().modify(|w| { 26 w.set_ti(true);
27 w.set_ti(true); 27 w.set_ri(true);
28 w.set_ri(true); 28 w.set_nis(true);
29 w.set_nis(true); 29 });
30 }); 30 // Delay two peripheral's clock
31 // Delay two peripheral's clock 31 dma.dmacsr().read();
32 dma.dmacsr().read(); 32 dma.dmacsr().read();
33 dma.dmacsr().read();
34 }
35 } 33 }
36} 34}
37 35
@@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
50 48
51macro_rules! config_pins { 49macro_rules! config_pins {
52 ($($pin:ident),*) => { 50 ($($pin:ident),*) => {
53 // NOTE(unsafe) Exclusive access to the registers
54 critical_section::with(|_| { 51 critical_section::with(|_| {
55 $( 52 $(
56 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 53 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@@ -64,7 +61,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
64 pub fn new<const TX: usize, const RX: usize>( 61 pub fn new<const TX: usize, const RX: usize>(
65 queue: &'d mut PacketQueue<TX, RX>, 62 queue: &'d mut PacketQueue<TX, RX>,
66 peri: impl Peripheral<P = T> + 'd, 63 peri: impl Peripheral<P = T> + 'd,
67 _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, 64 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
68 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 65 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
69 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 66 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
70 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 67 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -80,239 +77,225 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
80 ) -> Self { 77 ) -> Self {
81 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 78 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
82 79
83 unsafe { 80 // Enable the necessary Clocks
84 // Enable the necessary Clocks 81 #[cfg(not(rcc_h5))]
85 // NOTE(unsafe) We have exclusive access to the registers 82 critical_section::with(|_| {
86 #[cfg(not(rcc_h5))] 83 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
87 critical_section::with(|_| { 84 crate::pac::RCC.ahb1enr().modify(|w| {
88 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); 85 w.set_eth1macen(true);
89 crate::pac::RCC.ahb1enr().modify(|w| { 86 w.set_eth1txen(true);
90 w.set_eth1macen(true); 87 w.set_eth1rxen(true);
91 w.set_eth1txen(true);
92 w.set_eth1rxen(true);
93 });
94
95 // RMII
96 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
97 });
98
99 #[cfg(rcc_h5)]
100 critical_section::with(|_| {
101 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
102
103 crate::pac::RCC.ahb1enr().modify(|w| {
104 w.set_ethen(true);
105 w.set_ethtxen(true);
106 w.set_ethrxen(true);
107 });
108
109 // RMII
110 crate::pac::SBS
111 .pmcr()
112 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
113 });
114
115 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
116
117 // NOTE(unsafe) We have exclusive access to the registers
118 let dma = ETH.ethernet_dma();
119 let mac = ETH.ethernet_mac();
120 let mtl = ETH.ethernet_mtl();
121
122 // Reset and wait
123 dma.dmamr().modify(|w| w.set_swr(true));
124 while dma.dmamr().read().swr() {}
125
126 mac.maccr().modify(|w| {
127 w.set_ipg(0b000); // 96 bit times
128 w.set_acs(true);
129 w.set_fes(true);
130 w.set_dm(true);
131 // TODO: Carrier sense ? ECRSFD
132 });
133
134 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
135 // so the LR write must happen after the HR write.
136 mac.maca0hr()
137 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
138 mac.maca0lr().write(|w| {
139 w.set_addrlo(
140 u32::from(mac_addr[0])
141 | (u32::from(mac_addr[1]) << 8)
142 | (u32::from(mac_addr[2]) << 16)
143 | (u32::from(mac_addr[3]) << 24),
144 )
145 });
146
147 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
148
149 // disable all MMC RX interrupts
150 mac.mmc_rx_interrupt_mask().write(|w| {
151 w.set_rxcrcerpim(true);
152 w.set_rxalgnerpim(true);
153 w.set_rxucgpim(true);
154 w.set_rxlpiuscim(true);
155 w.set_rxlpitrcim(true)
156 });
157
158 // disable all MMC TX interrupts
159 mac.mmc_tx_interrupt_mask().write(|w| {
160 w.set_txscolgpim(true);
161 w.set_txmcolgpim(true);
162 w.set_txgpktim(true);
163 w.set_txlpiuscim(true);
164 w.set_txlpitrcim(true);
165 });
166
167 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
168 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
169
170 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
171 dma.dmacrx_cr().modify(|w| {
172 w.set_rxpbl(1); // 32 ?
173 w.set_rbsz(MTU as u16);
174 }); 88 });
175 89
176 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 90 // RMII
177 let hclk = crate::rcc::get_freqs().ahb1; 91 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
178 let hclk_mhz = hclk.0 / 1_000_000; 92 });
179
180 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
181 let clock_range = match hclk_mhz {
182 0..=34 => 2, // Divide by 16
183 35..=59 => 3, // Divide by 26
184 60..=99 => 0, // Divide by 42
185 100..=149 => 1, // Divide by 62
186 150..=249 => 4, // Divide by 102
187 250..=310 => 5, // Divide by 124
188 _ => {
189 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
190 }
191 };
192
193 let pins = [
194 ref_clk.map_into(),
195 mdio.map_into(),
196 mdc.map_into(),
197 crs.map_into(),
198 rx_d0.map_into(),
199 rx_d1.map_into(),
200 tx_d0.map_into(),
201 tx_d1.map_into(),
202 tx_en.map_into(),
203 ];
204
205 let mut this = Self {
206 _peri: peri,
207 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
208 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
209 pins,
210 _phy: phy,
211 clock_range,
212 phy_addr,
213 mac_addr,
214 };
215
216 fence(Ordering::SeqCst);
217
218 let mac = ETH.ethernet_mac();
219 let mtl = ETH.ethernet_mtl();
220 let dma = ETH.ethernet_dma();
221
222 mac.maccr().modify(|w| {
223 w.set_re(true);
224 w.set_te(true);
225 });
226 mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
227 93
228 dma.dmactx_cr().modify(|w| w.set_st(true)); 94 #[cfg(rcc_h5)]
229 dma.dmacrx_cr().modify(|w| w.set_sr(true)); 95 critical_section::with(|_| {
96 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
230 97
231 // Enable interrupts 98 crate::pac::RCC.ahb1enr().modify(|w| {
232 dma.dmacier().modify(|w| { 99 w.set_ethen(true);
233 w.set_nie(true); 100 w.set_ethtxen(true);
234 w.set_rie(true); 101 w.set_ethrxen(true);
235 w.set_tie(true);
236 }); 102 });
237 103
238 P::phy_reset(&mut this); 104 // RMII
239 P::phy_init(&mut this); 105 crate::pac::SBS
240 106 .pmcr()
241 interrupt::ETH::steal().unpend(); 107 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
242 interrupt::ETH::steal().enable(); 108 });
243 109
244 this 110 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
245 } 111
112 let dma = ETH.ethernet_dma();
113 let mac = ETH.ethernet_mac();
114 let mtl = ETH.ethernet_mtl();
115
116 // Reset and wait
117 dma.dmamr().modify(|w| w.set_swr(true));
118 while dma.dmamr().read().swr() {}
119
120 mac.maccr().modify(|w| {
121 w.set_ipg(0b000); // 96 bit times
122 w.set_acs(true);
123 w.set_fes(true);
124 w.set_dm(true);
125 // TODO: Carrier sense ? ECRSFD
126 });
127
128 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
129 // so the LR write must happen after the HR write.
130 mac.maca0hr()
131 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
132 mac.maca0lr().write(|w| {
133 w.set_addrlo(
134 u32::from(mac_addr[0])
135 | (u32::from(mac_addr[1]) << 8)
136 | (u32::from(mac_addr[2]) << 16)
137 | (u32::from(mac_addr[3]) << 24),
138 )
139 });
140
141 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
142
143 // disable all MMC RX interrupts
144 mac.mmc_rx_interrupt_mask().write(|w| {
145 w.set_rxcrcerpim(true);
146 w.set_rxalgnerpim(true);
147 w.set_rxucgpim(true);
148 w.set_rxlpiuscim(true);
149 w.set_rxlpitrcim(true)
150 });
151
152 // disable all MMC TX interrupts
153 mac.mmc_tx_interrupt_mask().write(|w| {
154 w.set_txscolgpim(true);
155 w.set_txmcolgpim(true);
156 w.set_txgpktim(true);
157 w.set_txlpiuscim(true);
158 w.set_txlpitrcim(true);
159 });
160
161 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
162 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
163
164 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
165 dma.dmacrx_cr().modify(|w| {
166 w.set_rxpbl(1); // 32 ?
167 w.set_rbsz(MTU as u16);
168 });
169
170 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
171 let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
172 let hclk_mhz = hclk.0 / 1_000_000;
173
174 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
175 let clock_range = match hclk_mhz {
176 0..=34 => 2, // Divide by 16
177 35..=59 => 3, // Divide by 26
178 60..=99 => 0, // Divide by 42
179 100..=149 => 1, // Divide by 62
180 150..=249 => 4, // Divide by 102
181 250..=310 => 5, // Divide by 124
182 _ => {
183 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
184 }
185 };
186
187 let pins = [
188 ref_clk.map_into(),
189 mdio.map_into(),
190 mdc.map_into(),
191 crs.map_into(),
192 rx_d0.map_into(),
193 rx_d1.map_into(),
194 tx_d0.map_into(),
195 tx_d1.map_into(),
196 tx_en.map_into(),
197 ];
198
199 let mut this = Self {
200 _peri: peri,
201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
203 pins,
204 _phy: phy,
205 clock_range,
206 phy_addr,
207 mac_addr,
208 };
209
210 fence(Ordering::SeqCst);
211
212 let mac = ETH.ethernet_mac();
213 let mtl = ETH.ethernet_mtl();
214 let dma = ETH.ethernet_dma();
215
216 mac.maccr().modify(|w| {
217 w.set_re(true);
218 w.set_te(true);
219 });
220 mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
221
222 dma.dmactx_cr().modify(|w| w.set_st(true));
223 dma.dmacrx_cr().modify(|w| w.set_sr(true));
224
225 // Enable interrupts
226 dma.dmacier().modify(|w| {
227 w.set_nie(true);
228 w.set_rie(true);
229 w.set_tie(true);
230 });
231
232 P::phy_reset(&mut this);
233 P::phy_init(&mut this);
234
235 interrupt::ETH.unpend();
236 unsafe { interrupt::ETH.enable() };
237
238 this
246 } 239 }
247} 240}
248 241
249unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 242unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
250 fn smi_read(&mut self, reg: u8) -> u16 { 243 fn smi_read(&mut self, reg: u8) -> u16 {
251 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 244 let mac = ETH.ethernet_mac();
252 unsafe { 245
253 let mac = ETH.ethernet_mac(); 246 mac.macmdioar().modify(|w| {
254 247 w.set_pa(self.phy_addr);
255 mac.macmdioar().modify(|w| { 248 w.set_rda(reg);
256 w.set_pa(self.phy_addr); 249 w.set_goc(0b11); // read
257 w.set_rda(reg); 250 w.set_cr(self.clock_range);
258 w.set_goc(0b11); // read 251 w.set_mb(true);
259 w.set_cr(self.clock_range); 252 });
260 w.set_mb(true); 253 while mac.macmdioar().read().mb() {}
261 }); 254 mac.macmdiodr().read().md()
262 while mac.macmdioar().read().mb() {}
263 mac.macmdiodr().read().md()
264 }
265 } 255 }
266 256
267 fn smi_write(&mut self, reg: u8, val: u16) { 257 fn smi_write(&mut self, reg: u8, val: u16) {
268 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 258 let mac = ETH.ethernet_mac();
269 unsafe { 259
270 let mac = ETH.ethernet_mac(); 260 mac.macmdiodr().write(|w| w.set_md(val));
271 261 mac.macmdioar().modify(|w| {
272 mac.macmdiodr().write(|w| w.set_md(val)); 262 w.set_pa(self.phy_addr);
273 mac.macmdioar().modify(|w| { 263 w.set_rda(reg);
274 w.set_pa(self.phy_addr); 264 w.set_goc(0b01); // write
275 w.set_rda(reg); 265 w.set_cr(self.clock_range);
276 w.set_goc(0b01); // write 266 w.set_mb(true);
277 w.set_cr(self.clock_range); 267 });
278 w.set_mb(true); 268 while mac.macmdioar().read().mb() {}
279 });
280 while mac.macmdioar().read().mb() {}
281 }
282 } 269 }
283} 270}
284 271
285impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 272impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
286 fn drop(&mut self) { 273 fn drop(&mut self) {
287 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers 274 let dma = ETH.ethernet_dma();
288 unsafe { 275 let mac = ETH.ethernet_mac();
289 let dma = ETH.ethernet_dma(); 276 let mtl = ETH.ethernet_mtl();
290 let mac = ETH.ethernet_mac(); 277
291 let mtl = ETH.ethernet_mtl(); 278 // Disable the TX DMA and wait for any previous transmissions to be completed
292 279 dma.dmactx_cr().modify(|w| w.set_st(false));
293 // Disable the TX DMA and wait for any previous transmissions to be completed 280 while {
294 dma.dmactx_cr().modify(|w| w.set_st(false)); 281 let txqueue = mtl.mtltx_qdr().read();
295 while { 282 txqueue.trcsts() == 0b01 || txqueue.txqsts()
296 let txqueue = mtl.mtltx_qdr().read(); 283 } {}
297 txqueue.trcsts() == 0b01 || txqueue.txqsts() 284
298 } {} 285 // Disable MAC transmitter and receiver
299 286 mac.maccr().modify(|w| {
300 // Disable MAC transmitter and receiver 287 w.set_re(false);
301 mac.maccr().modify(|w| { 288 w.set_te(false);
302 w.set_re(false); 289 });
303 w.set_te(false); 290
304 }); 291 // Wait for previous receiver transfers to be completed and then disable the RX DMA
292 while {
293 let rxqueue = mtl.mtlrx_qdr().read();
294 rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
295 } {}
296 dma.dmacrx_cr().modify(|w| w.set_sr(false));
305 297
306 // Wait for previous receiver transfers to be completed and then disable the RX DMA 298 critical_section::with(|_| {
307 while {
308 let rxqueue = mtl.mtlrx_qdr().read();
309 rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
310 } {}
311 dma.dmacrx_cr().modify(|w| w.set_sr(false));
312 }
313
314 // NOTE(unsafe) Exclusive access to the regs
315 critical_section::with(|_| unsafe {
316 for pin in self.pins.iter_mut() { 299 for pin in self.pins.iter_mut() {
317 pin.set_as_disconnected(); 300 pin.set_as_disconnected();
318 } 301 }
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 10109e56a..3ff92c9e6 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> {
206 206
207impl<'a> ExtiInputFuture<'a> { 207impl<'a> ExtiInputFuture<'a> {
208 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { 208 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
209 critical_section::with(|_| unsafe { 209 critical_section::with(|_| {
210 let pin = pin as usize; 210 let pin = pin as usize;
211 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); 211 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
212 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); 212 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
@@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> {
233 233
234impl<'a> Drop for ExtiInputFuture<'a> { 234impl<'a> Drop for ExtiInputFuture<'a> {
235 fn drop(&mut self) { 235 fn drop(&mut self) {
236 critical_section::with(|_| unsafe { 236 critical_section::with(|_| {
237 let pin = self.pin as _; 237 let pin = self.pin as _;
238 cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); 238 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
239 }); 239 });
@@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> {
246 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 246 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
247 EXTI_WAKERS[self.pin as usize].register(cx.waker()); 247 EXTI_WAKERS[self.pin as usize].register(cx.waker());
248 248
249 let imr = unsafe { cpu_regs().imr(0).read() }; 249 let imr = cpu_regs().imr(0).read();
250 if !imr.line(self.pin as _) { 250 if !imr.line(self.pin as _) {
251 Poll::Ready(()) 251 Poll::Ready(())
252 } else { 252 } else {
@@ -291,6 +291,7 @@ macro_rules! foreach_exti_irq {
291 291
292macro_rules! impl_irq { 292macro_rules! impl_irq {
293 ($e:ident) => { 293 ($e:ident) => {
294 #[cfg(feature = "rt")]
294 #[interrupt] 295 #[interrupt]
295 unsafe fn $e() { 296 unsafe fn $e() {
296 on_irq() 297 on_irq()
@@ -354,13 +355,13 @@ impl_exti!(EXTI15, 15);
354 355
355macro_rules! enable_irq { 356macro_rules! enable_irq {
356 ($e:ident) => { 357 ($e:ident) => {
357 crate::interrupt::$e::steal().enable(); 358 crate::interrupt::typelevel::$e::enable();
358 }; 359 };
359} 360}
360 361
361/// safety: must be called only once 362/// safety: must be called only once
362pub(crate) unsafe fn init() { 363pub(crate) unsafe fn init() {
363 use crate::interrupt::{Interrupt, InterruptExt}; 364 use crate::interrupt::typelevel::Interrupt;
364 365
365 foreach_exti_irq!(enable_irq); 366 foreach_exti_irq!(enable_irq);
366 367
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 3c3ece99a..70a5ded62 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,7 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use atomic_polyfill::{fence, Ordering}; 3use atomic_polyfill::{fence, Ordering};
4use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
5use embassy_hal_common::drop::OnDrop; 4use embassy_hal_common::drop::OnDrop;
6use embassy_hal_common::into_ref; 5use embassy_hal_common::into_ref;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@@ -11,6 +10,7 @@ use super::{
11 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, 10 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE,
12 WRITE_SIZE, 11 WRITE_SIZE,
13}; 12};
13use crate::interrupt::InterruptExt;
14use crate::peripherals::FLASH; 14use crate::peripherals::FLASH;
15use crate::{interrupt, Peripheral}; 15use crate::{interrupt, Peripheral};
16 16
@@ -19,13 +19,12 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new
19impl<'d> Flash<'d, Async> { 19impl<'d> Flash<'d, Async> {
20 pub fn new( 20 pub fn new(
21 p: impl Peripheral<P = FLASH> + 'd, 21 p: impl Peripheral<P = FLASH> + 'd,
22 _irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd, 22 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
23 ) -> Self { 23 ) -> Self {
24 into_ref!(p); 24 into_ref!(p);
25 25
26 let flash_irq = unsafe { crate::interrupt::FLASH::steal() }; 26 crate::interrupt::FLASH.unpend();
27 flash_irq.unpend(); 27 unsafe { crate::interrupt::FLASH.enable() };
28 flash_irq.enable();
29 28
30 Self { 29 Self {
31 inner: p, 30 inner: p,
@@ -50,7 +49,7 @@ impl<'d> Flash<'d, Async> {
50/// Interrupt handler 49/// Interrupt handler
51pub struct InterruptHandler; 50pub struct InterruptHandler;
52 51
53impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler { 52impl interrupt::typelevel::Handler<crate::interrupt::typelevel::FLASH> for InterruptHandler {
54 unsafe fn on_interrupt() { 53 unsafe fn on_interrupt() {
55 family::on_interrupt(); 54 family::on_interrupt();
56 } 55 }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 5e1fc696f..242d99278 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -192,7 +192,7 @@ impl FlashSector {
192 192
193#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] 193#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
194pub(crate) fn is_default_layout() -> bool { 194pub(crate) fn is_default_layout() -> bool {
195 unsafe { !pac::FLASH.optcr().read().db1m() } 195 !pac::FLASH.optcr().read().db1m()
196} 196}
197 197
198#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] 198#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
@@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
336 ret 336 ret
337} 337}
338 338
339pub(crate) unsafe fn clear_all_err() { 339pub(crate) fn clear_all_err() {
340 pac::FLASH.sr().write(|w| { 340 pac::FLASH.sr().write(|w| {
341 w.set_pgserr(true); 341 w.set_pgserr(true);
342 w.set_pgperr(true); 342 w.set_pgperr(true);
@@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() {
345 }); 345 });
346} 346}
347 347
348pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { 348pub(crate) async fn wait_ready() -> Result<(), Error> {
349 use core::task::Poll; 349 use core::task::Poll;
350 350
351 use futures::future::poll_fn; 351 use futures::future::poll_fn;
@@ -391,10 +391,10 @@ fn save_data_cache_state() {
391 let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; 391 let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2;
392 if dual_bank { 392 if dual_bank {
393 // Disable data cache during write/erase if there are two banks, see errata 2.2.12 393 // Disable data cache during write/erase if there are two banks, see errata 2.2.12
394 let dcen = unsafe { pac::FLASH.acr().read().dcen() }; 394 let dcen = pac::FLASH.acr().read().dcen();
395 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); 395 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
396 if dcen { 396 if dcen {
397 unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; 397 pac::FLASH.acr().modify(|w| w.set_dcen(false));
398 } 398 }
399 } 399 }
400} 400}
@@ -405,12 +405,10 @@ fn restore_data_cache_state() {
405 // Restore data cache if it was enabled 405 // Restore data cache if it was enabled
406 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); 406 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
407 if dcen { 407 if dcen {
408 unsafe { 408 // Reset data cache before we enable it again
409 // Reset data cache before we enable it again 409 pac::FLASH.acr().modify(|w| w.set_dcrst(true));
410 pac::FLASH.acr().modify(|w| w.set_dcrst(true)); 410 pac::FLASH.acr().modify(|w| w.set_dcrst(false));
411 pac::FLASH.acr().modify(|w| w.set_dcrst(false)); 411 pac::FLASH.acr().modify(|w| w.set_dcen(true))
412 pac::FLASH.acr().modify(|w| w.set_dcen(true))
413 };
414 } 412 }
415 } 413 }
416} 414}
@@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
445 feature = "stm32f439vi", 443 feature = "stm32f439vi",
446 feature = "stm32f439zi", 444 feature = "stm32f439zi",
447 ))] 445 ))]
448 if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { 446 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
449 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); 447 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11");
450 } 448 }
451 449
@@ -479,11 +477,9 @@ fn pa12_is_output_pull_low() -> bool {
479 use pac::gpio::vals; 477 use pac::gpio::vals;
480 use pac::GPIOA; 478 use pac::GPIOA;
481 const PIN: usize = 12; 479 const PIN: usize = 12;
482 unsafe { 480 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
483 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 481 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
484 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN 482 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
485 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
486 }
487} 483}
488 484
489#[cfg(test)] 485#[cfg(test)]
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index b9129cb51..a4f3b9686 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
16where 16where
17 T: Instance, 17 T: Instance,
18{ 18{
19 const REGISTERS: *const () = T::REGS.0 as *const _; 19 const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
20 20
21 fn enable(&mut self) { 21 fn enable(&mut self) {
22 <T as crate::rcc::sealed::RccPeripheral>::enable(); 22 <T as crate::rcc::sealed::RccPeripheral>::enable();
@@ -28,9 +28,7 @@ where
28 // fsmc v1, v2 and v3 does not have the fmcen bit 28 // fsmc v1, v2 and v3 does not have the fmcen bit
29 // This is a "not" because it is expected that all future versions have this bit 29 // This is a "not" because it is expected that all future versions have this bit
30 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] 30 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
31 unsafe { 31 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
32 T::REGS.bcr1().modify(|r| r.set_fmcen(true))
33 };
34 } 32 }
35 33
36 fn source_clock_hz(&self) -> u32 { 34 fn source_clock_hz(&self) -> u32 {
@@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor {
67 chip: CHIP 65 chip: CHIP
68 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { 66 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
69 67
70 critical_section::with(|_| unsafe { 68 critical_section::with(|_| {
71 config_pins!( 69 config_pins!(
72 $($addr_pin_name),*, 70 $($addr_pin_name),*,
73 $($ba_pin_name),*, 71 $($ba_pin_name),*,
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 4895684e0..af3a8eaca 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> {
46 /// Put the pin into input mode. 46 /// Put the pin into input mode.
47 #[inline] 47 #[inline]
48 pub fn set_as_input(&mut self, pull: Pull) { 48 pub fn set_as_input(&mut self, pull: Pull) {
49 critical_section::with(|_| unsafe { 49 critical_section::with(|_| {
50 let r = self.pin.block(); 50 let r = self.pin.block();
51 let n = self.pin.pin() as usize; 51 let n = self.pin.pin() as usize;
52 #[cfg(gpio_v1)] 52 #[cfg(gpio_v1)]
@@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> {
84 /// at a specific level, call `set_high`/`set_low` on the pin first. 84 /// at a specific level, call `set_high`/`set_low` on the pin first.
85 #[inline] 85 #[inline]
86 pub fn set_as_output(&mut self, speed: Speed) { 86 pub fn set_as_output(&mut self, speed: Speed) {
87 critical_section::with(|_| unsafe { 87 critical_section::with(|_| {
88 let r = self.pin.block(); 88 let r = self.pin.block();
89 let n = self.pin.pin() as usize; 89 let n = self.pin.pin() as usize;
90 #[cfg(gpio_v1)] 90 #[cfg(gpio_v1)]
@@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> {
116 /// at a specific level, call `set_high`/`set_low` on the pin first. 116 /// at a specific level, call `set_high`/`set_low` on the pin first.
117 #[inline] 117 #[inline]
118 pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) { 118 pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
119 critical_section::with(|_| unsafe { 119 critical_section::with(|_| {
120 let r = self.pin.block(); 120 let r = self.pin.block();
121 let n = self.pin.pin() as usize; 121 let n = self.pin.pin() as usize;
122 #[cfg(gpio_v1)] 122 #[cfg(gpio_v1)]
@@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> {
147 147
148 #[inline] 148 #[inline]
149 pub fn is_low(&self) -> bool { 149 pub fn is_low(&self) -> bool {
150 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; 150 let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
151 state == vals::Idr::LOW 151 state == vals::Idr::LOW
152 } 152 }
153 153
@@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> {
164 /// Is the output pin set as low? 164 /// Is the output pin set as low?
165 #[inline] 165 #[inline]
166 pub fn is_set_low(&self) -> bool { 166 pub fn is_set_low(&self) -> bool {
167 let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; 167 let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
168 state == vals::Odr::LOW 168 state == vals::Odr::LOW
169 } 169 }
170 170
@@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> {
207impl<'d, T: Pin> Drop for Flex<'d, T> { 207impl<'d, T: Pin> Drop for Flex<'d, T> {
208 #[inline] 208 #[inline]
209 fn drop(&mut self) { 209 fn drop(&mut self) {
210 critical_section::with(|_| unsafe { 210 critical_section::with(|_| {
211 let r = self.pin.block(); 211 let r = self.pin.block();
212 let n = self.pin.pin() as usize; 212 let n = self.pin.pin() as usize;
213 #[cfg(gpio_v1)] 213 #[cfg(gpio_v1)]
@@ -341,9 +341,9 @@ impl From<bool> for Level {
341 } 341 }
342} 342}
343 343
344impl Into<bool> for Level { 344impl From<Level> for bool {
345 fn into(self) -> bool { 345 fn from(level: Level) -> bool {
346 match self { 346 match level {
347 Level::Low => false, 347 Level::Low => false,
348 Level::High => true, 348 Level::High => true,
349 } 349 }
@@ -534,29 +534,25 @@ pub(crate) mod sealed {
534 /// Set the output as high. 534 /// Set the output as high.
535 #[inline] 535 #[inline]
536 fn set_high(&self) { 536 fn set_high(&self) {
537 unsafe { 537 let n = self._pin() as _;
538 let n = self._pin() as _; 538 self.block().bsrr().write(|w| w.set_bs(n, true));
539 self.block().bsrr().write(|w| w.set_bs(n, true));
540 }
541 } 539 }
542 540
543 /// Set the output as low. 541 /// Set the output as low.
544 #[inline] 542 #[inline]
545 fn set_low(&self) { 543 fn set_low(&self) {
546 unsafe { 544 let n = self._pin() as _;
547 let n = self._pin() as _; 545 self.block().bsrr().write(|w| w.set_br(n, true));
548 self.block().bsrr().write(|w| w.set_br(n, true));
549 }
550 } 546 }
551 547
552 #[inline] 548 #[inline]
553 unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) { 549 fn set_as_af(&self, af_num: u8, af_type: AFType) {
554 self.set_as_af_pull(af_num, af_type, Pull::None); 550 self.set_as_af_pull(af_num, af_type, Pull::None);
555 } 551 }
556 552
557 #[cfg(gpio_v1)] 553 #[cfg(gpio_v1)]
558 #[inline] 554 #[inline]
559 unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { 555 fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
560 // F1 uses the AFIO register for remapping. 556 // F1 uses the AFIO register for remapping.
561 // For now, this is not implemented, so af_num is ignored 557 // For now, this is not implemented, so af_num is ignored
562 // _af_num should be zero here, since it is not set by stm32-data 558 // _af_num should be zero here, since it is not set by stm32-data
@@ -599,7 +595,7 @@ pub(crate) mod sealed {
599 595
600 #[cfg(gpio_v2)] 596 #[cfg(gpio_v2)]
601 #[inline] 597 #[inline]
602 unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { 598 fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
603 let pin = self._pin() as usize; 599 let pin = self._pin() as usize;
604 let block = self.block(); 600 let block = self.block();
605 block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); 601 block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num));
@@ -614,7 +610,7 @@ pub(crate) mod sealed {
614 } 610 }
615 611
616 #[inline] 612 #[inline]
617 unsafe fn set_as_analog(&self) { 613 fn set_as_analog(&self) {
618 let pin = self._pin() as usize; 614 let pin = self._pin() as usize;
619 let block = self.block(); 615 let block = self.block();
620 #[cfg(gpio_v1)] 616 #[cfg(gpio_v1)]
@@ -635,12 +631,12 @@ pub(crate) mod sealed {
635 /// This is currently the same as set_as_analog but is semantically different really. 631 /// This is currently the same as set_as_analog but is semantically different really.
636 /// Drivers should set_as_disconnected pins when dropped. 632 /// Drivers should set_as_disconnected pins when dropped.
637 #[inline] 633 #[inline]
638 unsafe fn set_as_disconnected(&self) { 634 fn set_as_disconnected(&self) {
639 self.set_as_analog(); 635 self.set_as_analog();
640 } 636 }
641 637
642 #[inline] 638 #[inline]
643 unsafe fn set_speed(&self, speed: Speed) { 639 fn set_speed(&self, speed: Speed) {
644 let pin = self._pin() as usize; 640 let pin = self._pin() as usize;
645 641
646 #[cfg(gpio_v1)] 642 #[cfg(gpio_v1)]
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index f898fcc8b..b35678ed9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use crate::interrupt::Interrupt; 3use crate::interrupt;
4 4
5#[cfg_attr(i2c_v1, path = "v1.rs")] 5#[cfg_attr(i2c_v1, path = "v1.rs")]
6#[cfg_attr(i2c_v2, path = "v2.rs")] 6#[cfg_attr(i2c_v2, path = "v2.rs")]
@@ -35,7 +35,7 @@ pub(crate) mod sealed {
35} 35}
36 36
37pub trait Instance: sealed::Instance + 'static { 37pub trait Instance: sealed::Instance + 'static {
38 type Interrupt: Interrupt; 38 type Interrupt: interrupt::typelevel::Interrupt;
39} 39}
40 40
41pin_trait!(SclPin, Instance); 41pin_trait!(SclPin, Instance);
@@ -57,7 +57,7 @@ foreach_interrupt!(
57 } 57 }
58 58
59 impl Instance for peripherals::$inst { 59 impl Instance for peripherals::$inst {
60 type Interrupt = crate::interrupt::$irq; 60 type Interrupt = crate::interrupt::typelevel::$irq;
61 } 61 }
62 }; 62 };
63); 63);
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index b9be2e587..aa485cd86 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
16 _phantom: PhantomData<T>, 16 _phantom: PhantomData<T>,
17} 17}
18 18
19impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
20 unsafe fn on_interrupt() {} 20 unsafe fn on_interrupt() {}
21} 21}
22 22
@@ -57,7 +57,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
57 _peri: impl Peripheral<P = T> + 'd, 57 _peri: impl Peripheral<P = T> + 'd,
58 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 58 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
59 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 59 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
60 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 tx_dma: impl Peripheral<P = TXDMA> + 'd, 61 tx_dma: impl Peripheral<P = TXDMA> + 'd,
62 rx_dma: impl Peripheral<P = RXDMA> + 'd, 62 rx_dma: impl Peripheral<P = RXDMA> + 'd,
63 freq: Hertz, 63 freq: Hertz,
@@ -68,53 +68,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
68 T::enable(); 68 T::enable();
69 T::reset(); 69 T::reset();
70 70
71 unsafe { 71 scl.set_as_af_pull(
72 scl.set_as_af_pull( 72 scl.af_num(),
73 scl.af_num(), 73 AFType::OutputOpenDrain,
74 AFType::OutputOpenDrain, 74 match config.scl_pullup {
75 match config.scl_pullup { 75 true => Pull::Up,
76 true => Pull::Up, 76 false => Pull::None,
77 false => Pull::None, 77 },
78 }, 78 );
79 ); 79 sda.set_as_af_pull(
80 sda.set_as_af_pull( 80 sda.af_num(),
81 sda.af_num(), 81 AFType::OutputOpenDrain,
82 AFType::OutputOpenDrain, 82 match config.sda_pullup {
83 match config.sda_pullup { 83 true => Pull::Up,
84 true => Pull::Up, 84 false => Pull::None,
85 false => Pull::None, 85 },
86 }, 86 );
87 );
88 }
89 87
90 unsafe { 88 T::regs().cr1().modify(|reg| {
91 T::regs().cr1().modify(|reg| { 89 reg.set_pe(false);
92 reg.set_pe(false); 90 //reg.set_anfoff(false);
93 //reg.set_anfoff(false); 91 });
94 });
95 }
96 92
97 let timings = Timings::new(T::frequency(), freq.into()); 93 let timings = Timings::new(T::frequency(), freq.into());
98 94
99 unsafe { 95 T::regs().cr2().modify(|reg| {
100 T::regs().cr2().modify(|reg| { 96 reg.set_freq(timings.freq);
101 reg.set_freq(timings.freq); 97 });
102 }); 98 T::regs().ccr().modify(|reg| {
103 T::regs().ccr().modify(|reg| { 99 reg.set_f_s(timings.mode.f_s());
104 reg.set_f_s(timings.mode.f_s()); 100 reg.set_duty(timings.duty.duty());
105 reg.set_duty(timings.duty.duty()); 101 reg.set_ccr(timings.ccr);
106 reg.set_ccr(timings.ccr); 102 });
107 }); 103 T::regs().trise().modify(|reg| {
108 T::regs().trise().modify(|reg| { 104 reg.set_trise(timings.trise);
109 reg.set_trise(timings.trise); 105 });
110 });
111 }
112 106
113 unsafe { 107 T::regs().cr1().modify(|reg| {
114 T::regs().cr1().modify(|reg| { 108 reg.set_pe(true);
115 reg.set_pe(true); 109 });
116 });
117 }
118 110
119 Self { 111 Self {
120 phantom: PhantomData, 112 phantom: PhantomData,
@@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
123 } 115 }
124 } 116 }
125 117
126 unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { 118 fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
127 // Note that flags should only be cleared once they have been registered. If flags are 119 // Note that flags should only be cleared once they have been registered. If flags are
128 // cleared otherwise, there may be an inherent race condition and flags may be missed. 120 // cleared otherwise, there may be an inherent race condition and flags may be missed.
129 let sr1 = T::regs().sr1().read(); 121 let sr1 = T::regs().sr1().read();
@@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
162 Ok(sr1) 154 Ok(sr1)
163 } 155 }
164 156
165 unsafe fn write_bytes( 157 fn write_bytes(
166 &mut self, 158 &mut self,
167 addr: u8, 159 addr: u8,
168 bytes: &[u8], 160 bytes: &[u8],
@@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
211 Ok(()) 203 Ok(())
212 } 204 }
213 205
214 unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 206 fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
215 // Wait until we're ready for sending 207 // Wait until we're ready for sending
216 while { 208 while {
217 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 209 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
@@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
234 Ok(()) 226 Ok(())
235 } 227 }
236 228
237 unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { 229 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
238 while { 230 while {
239 // Check for any potential error conditions. 231 // Check for any potential error conditions.
240 self.check_and_clear_error_flags()?; 232 self.check_and_clear_error_flags()?;
@@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
256 ) -> Result<(), Error> { 248 ) -> Result<(), Error> {
257 if let Some((last, buffer)) = buffer.split_last_mut() { 249 if let Some((last, buffer)) = buffer.split_last_mut() {
258 // Send a START condition and set ACK bit 250 // Send a START condition and set ACK bit
259 unsafe { 251 T::regs().cr1().modify(|reg| {
260 T::regs().cr1().modify(|reg| { 252 reg.set_start(true);
261 reg.set_start(true); 253 reg.set_ack(true);
262 reg.set_ack(true); 254 });
263 });
264 }
265 255
266 // Wait until START condition was generated 256 // Wait until START condition was generated
267 while unsafe { !self.check_and_clear_error_flags()?.start() } { 257 while !self.check_and_clear_error_flags()?.start() {
268 check_timeout()?; 258 check_timeout()?;
269 } 259 }
270 260
271 // Also wait until signalled we're master and everything is waiting for us 261 // Also wait until signalled we're master and everything is waiting for us
272 while { 262 while {
273 let sr2 = unsafe { T::regs().sr2().read() }; 263 let sr2 = T::regs().sr2().read();
274 !sr2.msl() && !sr2.busy() 264 !sr2.msl() && !sr2.busy()
275 } { 265 } {
276 check_timeout()?; 266 check_timeout()?;
277 } 267 }
278 268
279 // Set up current address, we're trying to talk to 269 // Set up current address, we're trying to talk to
280 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } 270 T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1));
281 271
282 // Wait until address was sent 272 // Wait until address was sent
283 // Wait for the address to be acknowledged 273 // Wait for the address to be acknowledged
284 while unsafe { !self.check_and_clear_error_flags()?.addr() } { 274 while !self.check_and_clear_error_flags()?.addr() {
285 check_timeout()?; 275 check_timeout()?;
286 } 276 }
287 277
288 // Clear condition by reading SR2 278 // Clear condition by reading SR2
289 let _ = unsafe { T::regs().sr2().read() }; 279 let _ = T::regs().sr2().read();
290 280
291 // Receive bytes into buffer 281 // Receive bytes into buffer
292 for c in buffer { 282 for c in buffer {
293 *c = unsafe { self.recv_byte(&check_timeout)? }; 283 *c = self.recv_byte(&check_timeout)?;
294 } 284 }
295 285
296 // Prepare to send NACK then STOP after next byte 286 // Prepare to send NACK then STOP after next byte
297 unsafe { 287 T::regs().cr1().modify(|reg| {
298 T::regs().cr1().modify(|reg| { 288 reg.set_ack(false);
299 reg.set_ack(false); 289 reg.set_stop(true);
300 reg.set_stop(true); 290 });
301 })
302 }
303 291
304 // Receive last byte 292 // Receive last byte
305 *last = unsafe { self.recv_byte(&check_timeout)? }; 293 *last = self.recv_byte(&check_timeout)?;
306 294
307 // Wait for the STOP to be sent. 295 // Wait for the STOP to be sent.
308 while unsafe { T::regs().cr1().read().stop() } { 296 while T::regs().cr1().read().stop() {
309 check_timeout()?; 297 check_timeout()?;
310 } 298 }
311 299
@@ -326,15 +314,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
326 write: &[u8], 314 write: &[u8],
327 check_timeout: impl Fn() -> Result<(), Error>, 315 check_timeout: impl Fn() -> Result<(), Error>,
328 ) -> Result<(), Error> { 316 ) -> Result<(), Error> {
329 unsafe { 317 self.write_bytes(addr, write, &check_timeout)?;
330 self.write_bytes(addr, write, &check_timeout)?; 318 // Send a STOP condition
331 // Send a STOP condition 319 T::regs().cr1().modify(|reg| reg.set_stop(true));
332 T::regs().cr1().modify(|reg| reg.set_stop(true)); 320 // Wait for STOP condition to transmit.
333 // Wait for STOP condition to transmit. 321 while T::regs().cr1().read().stop() {
334 while T::regs().cr1().read().stop() { 322 check_timeout()?;
335 check_timeout()?; 323 }
336 }
337 };
338 324
339 // Fallthrough is success 325 // Fallthrough is success
340 Ok(()) 326 Ok(())
@@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
351 read: &mut [u8], 337 read: &mut [u8],
352 check_timeout: impl Fn() -> Result<(), Error>, 338 check_timeout: impl Fn() -> Result<(), Error>,
353 ) -> Result<(), Error> { 339 ) -> Result<(), Error> {
354 unsafe { self.write_bytes(addr, write, &check_timeout)? }; 340 self.write_bytes(addr, write, &check_timeout)?;
355 self.blocking_read_timeout(addr, read, &check_timeout)?; 341 self.blocking_read_timeout(addr, read, &check_timeout)?;
356 342
357 Ok(()) 343 Ok(())
@@ -478,8 +464,6 @@ impl Timings {
478 assert!(freq >= 2 && freq <= 50); 464 assert!(freq >= 2 && freq <= 50);
479 465
480 // Configure bus frequency into I2C peripheral 466 // Configure bus frequency into I2C peripheral
481 //self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
482
483 let trise = if speed <= 100_000 { 467 let trise = if speed <= 100_000 {
484 freq + 1 468 freq + 1
485 } else { 469 } else {
@@ -539,18 +523,16 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
539 type Config = Hertz; 523 type Config = Hertz;
540 fn set_config(&mut self, config: &Self::Config) { 524 fn set_config(&mut self, config: &Self::Config) {
541 let timings = Timings::new(T::frequency(), *config); 525 let timings = Timings::new(T::frequency(), *config);
542 unsafe { 526 T::regs().cr2().modify(|reg| {
543 T::regs().cr2().modify(|reg| { 527 reg.set_freq(timings.freq);
544 reg.set_freq(timings.freq); 528 });
545 }); 529 T::regs().ccr().modify(|reg| {
546 T::regs().ccr().modify(|reg| { 530 reg.set_f_s(timings.mode.f_s());
547 reg.set_f_s(timings.mode.f_s()); 531 reg.set_duty(timings.duty.duty());
548 reg.set_duty(timings.duty.duty()); 532 reg.set_ccr(timings.ccr);
549 reg.set_ccr(timings.ccr); 533 });
550 }); 534 T::regs().trise().modify(|reg| {
551 T::regs().trise().modify(|reg| { 535 reg.set_trise(timings.trise);
552 reg.set_trise(timings.trise); 536 });
553 });
554 }
555 } 537 }
556} 538}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 642ddc18c..1f036d55c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -3,7 +3,6 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
7use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
8use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
9use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
@@ -13,6 +12,7 @@ use crate::dma::{NoDma, Transfer};
13use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
14use crate::gpio::Pull; 13use crate::gpio::Pull;
15use crate::i2c::{Error, Instance, SclPin, SdaPin}; 14use crate::i2c::{Error, Instance, SclPin, SdaPin};
15use crate::interrupt::typelevel::Interrupt;
16use crate::pac::i2c; 16use crate::pac::i2c;
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{interrupt, Peripheral}; 18use crate::{interrupt, Peripheral};
@@ -22,7 +22,7 @@ pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>, 22 _phantom: PhantomData<T>,
23} 23}
24 24
25impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() { 26 unsafe fn on_interrupt() {
27 let regs = T::regs(); 27 let regs = T::regs();
28 let isr = regs.isr().read(); 28 let isr = regs.isr().read();
@@ -78,7 +78,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
78 peri: impl Peripheral<P = T> + 'd, 78 peri: impl Peripheral<P = T> + 'd,
79 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 79 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
80 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 80 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
81 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 81 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
82 tx_dma: impl Peripheral<P = TXDMA> + 'd, 82 tx_dma: impl Peripheral<P = TXDMA> + 'd,
83 rx_dma: impl Peripheral<P = RXDMA> + 'd, 83 rx_dma: impl Peripheral<P = RXDMA> + 'd,
84 freq: Hertz, 84 freq: Hertz,
@@ -89,52 +89,44 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
89 T::enable(); 89 T::enable();
90 T::reset(); 90 T::reset();
91 91
92 unsafe { 92 scl.set_as_af_pull(
93 scl.set_as_af_pull( 93 scl.af_num(),
94 scl.af_num(), 94 AFType::OutputOpenDrain,
95 AFType::OutputOpenDrain, 95 match config.scl_pullup {
96 match config.scl_pullup { 96 true => Pull::Up,
97 true => Pull::Up, 97 false => Pull::None,
98 false => Pull::None, 98 },
99 }, 99 );
100 ); 100 sda.set_as_af_pull(
101 sda.set_as_af_pull( 101 sda.af_num(),
102 sda.af_num(), 102 AFType::OutputOpenDrain,
103 AFType::OutputOpenDrain, 103 match config.sda_pullup {
104 match config.sda_pullup { 104 true => Pull::Up,
105 true => Pull::Up, 105 false => Pull::None,
106 false => Pull::None, 106 },
107 }, 107 );
108 ); 108
109 } 109 T::regs().cr1().modify(|reg| {
110 110 reg.set_pe(false);
111 unsafe { 111 reg.set_anfoff(false);
112 T::regs().cr1().modify(|reg| { 112 });
113 reg.set_pe(false);
114 reg.set_anfoff(false);
115 });
116 }
117 113
118 let timings = Timings::new(T::frequency(), freq.into()); 114 let timings = Timings::new(T::frequency(), freq.into());
119 115
120 unsafe { 116 T::regs().timingr().write(|reg| {
121 T::regs().timingr().write(|reg| { 117 reg.set_presc(timings.prescale);
122 reg.set_presc(timings.prescale); 118 reg.set_scll(timings.scll);
123 reg.set_scll(timings.scll); 119 reg.set_sclh(timings.sclh);
124 reg.set_sclh(timings.sclh); 120 reg.set_sdadel(timings.sdadel);
125 reg.set_sdadel(timings.sdadel); 121 reg.set_scldel(timings.scldel);
126 reg.set_scldel(timings.scldel); 122 });
127 });
128 }
129 123
130 unsafe { 124 T::regs().cr1().modify(|reg| {
131 T::regs().cr1().modify(|reg| { 125 reg.set_pe(true);
132 reg.set_pe(true); 126 });
133 });
134 }
135 127
136 unsafe { T::Interrupt::steal() }.unpend(); 128 T::Interrupt::unpend();
137 unsafe { T::Interrupt::steal() }.enable(); 129 unsafe { T::Interrupt::enable() };
138 130
139 Self { 131 Self {
140 _peri: peri, 132 _peri: peri,
@@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
144 } 136 }
145 137
146 fn master_stop(&mut self) { 138 fn master_stop(&mut self) {
147 unsafe { 139 T::regs().cr2().write(|w| w.set_stop(true));
148 T::regs().cr2().write(|w| w.set_stop(true));
149 }
150 } 140 }
151 141
152 unsafe fn master_read( 142 fn master_read(
153 address: u8, 143 address: u8,
154 length: usize, 144 length: usize,
155 stop: Stop, 145 stop: Stop,
@@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
191 Ok(()) 181 Ok(())
192 } 182 }
193 183
194 unsafe fn master_write( 184 fn master_write(
195 address: u8, 185 address: u8,
196 length: usize, 186 length: usize,
197 stop: Stop, 187 stop: Stop,
@@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
229 Ok(()) 219 Ok(())
230 } 220 }
231 221
232 unsafe fn master_continue( 222 fn master_continue(
233 length: usize, 223 length: usize,
234 reload: bool, 224 reload: bool,
235 check_timeout: impl Fn() -> Result<(), Error>, 225 check_timeout: impl Fn() -> Result<(), Error>,
@@ -259,13 +249,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
259 //$i2c.txdr.write(|w| w.txdata().bits(0)); 249 //$i2c.txdr.write(|w| w.txdata().bits(0));
260 //} 250 //}
261 251
262 unsafe { 252 if T::regs().isr().read().txis() {
263 if T::regs().isr().read().txis() { 253 T::regs().txdr().write(|w| w.set_txdata(0));
264 T::regs().txdr().write(|w| w.set_txdata(0)); 254 }
265 } 255 if !T::regs().isr().read().txe() {
266 if !T::regs().isr().read().txe() { 256 T::regs().isr().modify(|w| w.set_txe(true))
267 T::regs().isr().modify(|w| w.set_txe(true))
268 }
269 } 257 }
270 258
271 // If TXDR is not flagged as empty, write 1 to flush it 259 // If TXDR is not flagged as empty, write 1 to flush it
@@ -276,21 +264,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
276 264
277 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 265 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
278 loop { 266 loop {
279 unsafe { 267 let isr = T::regs().isr().read();
280 let isr = T::regs().isr().read(); 268 if isr.txe() {
281 if isr.txe() { 269 return Ok(());
282 return Ok(()); 270 } else if isr.berr() {
283 } else if isr.berr() { 271 T::regs().icr().write(|reg| reg.set_berrcf(true));
284 T::regs().icr().write(|reg| reg.set_berrcf(true)); 272 return Err(Error::Bus);
285 return Err(Error::Bus); 273 } else if isr.arlo() {
286 } else if isr.arlo() { 274 T::regs().icr().write(|reg| reg.set_arlocf(true));
287 T::regs().icr().write(|reg| reg.set_arlocf(true)); 275 return Err(Error::Arbitration);
288 return Err(Error::Arbitration); 276 } else if isr.nackf() {
289 } else if isr.nackf() { 277 T::regs().icr().write(|reg| reg.set_nackcf(true));
290 T::regs().icr().write(|reg| reg.set_nackcf(true)); 278 self.flush_txdr();
291 self.flush_txdr(); 279 return Err(Error::Nack);
292 return Err(Error::Nack);
293 }
294 } 280 }
295 281
296 check_timeout()?; 282 check_timeout()?;
@@ -299,21 +285,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
299 285
300 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 286 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
301 loop { 287 loop {
302 unsafe { 288 let isr = T::regs().isr().read();
303 let isr = T::regs().isr().read(); 289 if isr.rxne() {
304 if isr.rxne() { 290 return Ok(());
305 return Ok(()); 291 } else if isr.berr() {
306 } else if isr.berr() { 292 T::regs().icr().write(|reg| reg.set_berrcf(true));
307 T::regs().icr().write(|reg| reg.set_berrcf(true)); 293 return Err(Error::Bus);
308 return Err(Error::Bus); 294 } else if isr.arlo() {
309 } else if isr.arlo() { 295 T::regs().icr().write(|reg| reg.set_arlocf(true));
310 T::regs().icr().write(|reg| reg.set_arlocf(true)); 296 return Err(Error::Arbitration);
311 return Err(Error::Arbitration); 297 } else if isr.nackf() {
312 } else if isr.nackf() { 298 T::regs().icr().write(|reg| reg.set_nackcf(true));
313 T::regs().icr().write(|reg| reg.set_nackcf(true)); 299 self.flush_txdr();
314 self.flush_txdr(); 300 return Err(Error::Nack);
315 return Err(Error::Nack);
316 }
317 } 301 }
318 302
319 check_timeout()?; 303 check_timeout()?;
@@ -322,21 +306,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
322 306
323 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 307 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
324 loop { 308 loop {
325 unsafe { 309 let isr = T::regs().isr().read();
326 let isr = T::regs().isr().read(); 310 if isr.tc() {
327 if isr.tc() { 311 return Ok(());
328 return Ok(()); 312 } else if isr.berr() {
329 } else if isr.berr() { 313 T::regs().icr().write(|reg| reg.set_berrcf(true));
330 T::regs().icr().write(|reg| reg.set_berrcf(true)); 314 return Err(Error::Bus);
331 return Err(Error::Bus); 315 } else if isr.arlo() {
332 } else if isr.arlo() { 316 T::regs().icr().write(|reg| reg.set_arlocf(true));
333 T::regs().icr().write(|reg| reg.set_arlocf(true)); 317 return Err(Error::Arbitration);
334 return Err(Error::Arbitration); 318 } else if isr.nackf() {
335 } else if isr.nackf() { 319 T::regs().icr().write(|reg| reg.set_nackcf(true));
336 T::regs().icr().write(|reg| reg.set_nackcf(true)); 320 self.flush_txdr();
337 self.flush_txdr(); 321 return Err(Error::Nack);
338 return Err(Error::Nack);
339 }
340 } 322 }
341 323
342 check_timeout()?; 324 check_timeout()?;
@@ -358,32 +340,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
358 }; 340 };
359 let last_chunk_idx = total_chunks.saturating_sub(1); 341 let last_chunk_idx = total_chunks.saturating_sub(1);
360 342
361 unsafe { 343 Self::master_read(
362 Self::master_read( 344 address,
363 address, 345 read.len().min(255),
364 read.len().min(255), 346 Stop::Automatic,
365 Stop::Automatic, 347 last_chunk_idx != 0,
366 last_chunk_idx != 0, 348 restart,
367 restart, 349 &check_timeout,
368 &check_timeout, 350 )?;
369 )?;
370 }
371 351
372 for (number, chunk) in read.chunks_mut(255).enumerate() { 352 for (number, chunk) in read.chunks_mut(255).enumerate() {
373 if number != 0 { 353 if number != 0 {
374 // NOTE(unsafe) We have &mut self 354 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
375 unsafe {
376 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
377 }
378 } 355 }
379 356
380 for byte in chunk { 357 for byte in chunk {
381 // Wait until we have received something 358 // Wait until we have received something
382 self.wait_rxne(&check_timeout)?; 359 self.wait_rxne(&check_timeout)?;
383 360
384 unsafe { 361 *byte = T::regs().rxdr().read().rxdata();
385 *byte = T::regs().rxdr().read().rxdata();
386 }
387 } 362 }
388 } 363 }
389 Ok(()) 364 Ok(())
@@ -407,23 +382,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
407 // I2C start 382 // I2C start
408 // 383 //
409 // ST SAD+W 384 // ST SAD+W
410 // NOTE(unsafe) We have &mut self 385 Self::master_write(
411 unsafe { 386 address,
412 Self::master_write( 387 write.len().min(255),
413 address, 388 Stop::Software,
414 write.len().min(255), 389 last_chunk_idx != 0,
415 Stop::Software, 390 &check_timeout,
416 last_chunk_idx != 0, 391 )?;
417 &check_timeout,
418 )?;
419 }
420 392
421 for (number, chunk) in write.chunks(255).enumerate() { 393 for (number, chunk) in write.chunks(255).enumerate() {
422 if number != 0 { 394 if number != 0 {
423 // NOTE(unsafe) We have &mut self 395 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
424 unsafe {
425 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
426 }
427 } 396 }
428 397
429 for byte in chunk { 398 for byte in chunk {
@@ -432,9 +401,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
432 // through) 401 // through)
433 self.wait_txe(&check_timeout)?; 402 self.wait_txe(&check_timeout)?;
434 403
435 unsafe { 404 T::regs().txdr().write(|w| w.set_txdata(*byte));
436 T::regs().txdr().write(|w| w.set_txdata(*byte));
437 }
438 } 405 }
439 } 406 }
440 // Wait until the write finishes 407 // Wait until the write finishes
@@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
467 w.set_tcie(true); 434 w.set_tcie(true);
468 } 435 }
469 }); 436 });
470 let dst = regs.txdr().ptr() as *mut u8; 437 let dst = regs.txdr().as_ptr() as *mut u8;
471 438
472 let ch = &mut self.tx_dma; 439 let ch = &mut self.tx_dma;
473 let request = ch.request(); 440 let request = ch.request();
@@ -479,37 +446,30 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
479 446
480 let on_drop = OnDrop::new(|| { 447 let on_drop = OnDrop::new(|| {
481 let regs = T::regs(); 448 let regs = T::regs();
482 unsafe { 449 regs.cr1().modify(|w| {
483 regs.cr1().modify(|w| { 450 if last_slice {
484 if last_slice { 451 w.set_txdmaen(false);
485 w.set_txdmaen(false); 452 }
486 } 453 w.set_tcie(false);
487 w.set_tcie(false); 454 })
488 })
489 }
490 }); 455 });
491 456
492 poll_fn(|cx| { 457 poll_fn(|cx| {
493 state.waker.register(cx.waker()); 458 state.waker.register(cx.waker());
494 459
495 let isr = unsafe { T::regs().isr().read() }; 460 let isr = T::regs().isr().read();
496 if remaining_len == total_len { 461 if remaining_len == total_len {
497 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
498 if first_slice { 462 if first_slice {
499 unsafe { 463 Self::master_write(
500 Self::master_write( 464 address,
501 address, 465 total_len.min(255),
502 total_len.min(255), 466 Stop::Software,
503 Stop::Software, 467 (total_len > 255) || !last_slice,
504 (total_len > 255) || !last_slice, 468 &check_timeout,
505 &check_timeout, 469 )?;
506 )?;
507 }
508 } else { 470 } else {
509 unsafe { 471 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
510 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; 472 T::regs().cr1().modify(|w| w.set_tcie(true));
511 T::regs().cr1().modify(|w| w.set_tcie(true));
512 }
513 } 473 }
514 } else if !(isr.tcr() || isr.tc()) { 474 } else if !(isr.tcr() || isr.tc()) {
515 // poll_fn was woken without an interrupt present 475 // poll_fn was woken without an interrupt present
@@ -519,13 +479,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
519 } else { 479 } else {
520 let last_piece = (remaining_len <= 255) && last_slice; 480 let last_piece = (remaining_len <= 255) && last_slice;
521 481
522 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers 482 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
523 unsafe { 483 return Poll::Ready(Err(e));
524 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
525 return Poll::Ready(Err(e));
526 }
527 T::regs().cr1().modify(|w| w.set_tcie(true));
528 } 484 }
485 T::regs().cr1().modify(|w| w.set_tcie(true));
529 } 486 }
530 487
531 remaining_len = remaining_len.saturating_sub(255); 488 remaining_len = remaining_len.saturating_sub(255);
@@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
564 w.set_rxdmaen(true); 521 w.set_rxdmaen(true);
565 w.set_tcie(true); 522 w.set_tcie(true);
566 }); 523 });
567 let src = regs.rxdr().ptr() as *mut u8; 524 let src = regs.rxdr().as_ptr() as *mut u8;
568 525
569 let ch = &mut self.rx_dma; 526 let ch = &mut self.rx_dma;
570 let request = ch.request(); 527 let request = ch.request();
@@ -576,30 +533,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
576 533
577 let on_drop = OnDrop::new(|| { 534 let on_drop = OnDrop::new(|| {
578 let regs = T::regs(); 535 let regs = T::regs();
579 unsafe { 536 regs.cr1().modify(|w| {
580 regs.cr1().modify(|w| { 537 w.set_rxdmaen(false);
581 w.set_rxdmaen(false); 538 w.set_tcie(false);
582 w.set_tcie(false); 539 })
583 })
584 }
585 }); 540 });
586 541
587 poll_fn(|cx| { 542 poll_fn(|cx| {
588 state.waker.register(cx.waker()); 543 state.waker.register(cx.waker());
589 544
590 let isr = unsafe { T::regs().isr().read() }; 545 let isr = T::regs().isr().read();
591 if remaining_len == total_len { 546 if remaining_len == total_len {
592 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 547 Self::master_read(
593 unsafe { 548 address,
594 Self::master_read( 549 total_len.min(255),
595 address, 550 Stop::Software,
596 total_len.min(255), 551 total_len > 255,
597 Stop::Software, 552 restart,
598 total_len > 255, 553 &check_timeout,
599 restart, 554 )?;
600 &check_timeout,
601 )?;
602 }
603 } else if !(isr.tcr() || isr.tc()) { 555 } else if !(isr.tcr() || isr.tc()) {
604 // poll_fn was woken without an interrupt present 556 // poll_fn was woken without an interrupt present
605 return Poll::Pending; 557 return Poll::Pending;
@@ -608,13 +560,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
608 } else { 560 } else {
609 let last_piece = remaining_len <= 255; 561 let last_piece = remaining_len <= 255;
610 562
611 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 563 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
612 unsafe { 564 return Poll::Ready(Err(e));
613 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
614 return Poll::Ready(Err(e));
615 }
616 T::regs().cr1().modify(|w| w.set_tcie(true));
617 } 565 }
566 T::regs().cr1().modify(|w| w.set_tcie(true));
618 } 567 }
619 568
620 remaining_len = remaining_len.saturating_sub(255); 569 remaining_len = remaining_len.saturating_sub(255);
@@ -758,16 +707,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
758 let first_length = write[0].len(); 707 let first_length = write[0].len();
759 let last_slice_index = write.len() - 1; 708 let last_slice_index = write.len() - 1;
760 709
761 // NOTE(unsafe) We have &mut self 710 Self::master_write(
762 unsafe { 711 address,
763 Self::master_write( 712 first_length.min(255),
764 address, 713 Stop::Software,
765 first_length.min(255), 714 (first_length > 255) || (last_slice_index != 0),
766 Stop::Software, 715 &check_timeout,
767 (first_length > 255) || (last_slice_index != 0), 716 )?;
768 &check_timeout,
769 )?;
770 }
771 717
772 for (idx, slice) in write.iter().enumerate() { 718 for (idx, slice) in write.iter().enumerate() {
773 let slice_len = slice.len(); 719 let slice_len = slice.len();
@@ -780,26 +726,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
780 let last_chunk_idx = total_chunks.saturating_sub(1); 726 let last_chunk_idx = total_chunks.saturating_sub(1);
781 727
782 if idx != 0 { 728 if idx != 0 {
783 // NOTE(unsafe) We have &mut self 729 Self::master_continue(
784 unsafe { 730 slice_len.min(255),
785 Self::master_continue( 731 (idx != last_slice_index) || (slice_len > 255),
786 slice_len.min(255), 732 &check_timeout,
787 (idx != last_slice_index) || (slice_len > 255), 733 )?;
788 &check_timeout,
789 )?;
790 }
791 } 734 }
792 735
793 for (number, chunk) in slice.chunks(255).enumerate() { 736 for (number, chunk) in slice.chunks(255).enumerate() {
794 if number != 0 { 737 if number != 0 {
795 // NOTE(unsafe) We have &mut self 738 Self::master_continue(
796 unsafe { 739 chunk.len(),
797 Self::master_continue( 740 (number != last_chunk_idx) || (idx != last_slice_index),
798 chunk.len(), 741 &check_timeout,
799 (number != last_chunk_idx) || (idx != last_slice_index), 742 )?;
800 &check_timeout,
801 )?;
802 }
803 } 743 }
804 744
805 for byte in chunk { 745 for byte in chunk {
@@ -810,9 +750,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
810 750
811 // Put byte on the wire 751 // Put byte on the wire
812 //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); 752 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
813 unsafe { 753 T::regs().txdr().write(|w| w.set_txdata(*byte));
814 T::regs().txdr().write(|w| w.set_txdata(*byte));
815 }
816 } 754 }
817 } 755 }
818 } 756 }
@@ -1061,14 +999,12 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
1061 type Config = Hertz; 999 type Config = Hertz;
1062 fn set_config(&mut self, config: &Self::Config) { 1000 fn set_config(&mut self, config: &Self::Config) {
1063 let timings = Timings::new(T::frequency(), *config); 1001 let timings = Timings::new(T::frequency(), *config);
1064 unsafe { 1002 T::regs().timingr().write(|reg| {
1065 T::regs().timingr().write(|reg| { 1003 reg.set_presc(timings.prescale);
1066 reg.set_presc(timings.prescale); 1004 reg.set_scll(timings.scll);
1067 reg.set_scll(timings.scll); 1005 reg.set_sclh(timings.sclh);
1068 reg.set_sclh(timings.sclh); 1006 reg.set_sdadel(timings.sdadel);
1069 reg.set_sdadel(timings.sdadel); 1007 reg.set_scldel(timings.scldel);
1070 reg.set_scldel(timings.scldel); 1008 });
1071 });
1072 }
1073 } 1009 }
1074} 1010}
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 2bb199f68..62dda69b4 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -153,19 +153,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
153 ) -> Self { 153 ) -> Self {
154 into_ref!(sd, ws, ck, mck); 154 into_ref!(sd, ws, ck, mck);
155 155
156 unsafe { 156 sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
157 sd.set_as_af(sd.af_num(), AFType::OutputPushPull); 157 sd.set_speed(crate::gpio::Speed::VeryHigh);
158 sd.set_speed(crate::gpio::Speed::VeryHigh);
159 158
160 ws.set_as_af(ws.af_num(), AFType::OutputPushPull); 159 ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
161 ws.set_speed(crate::gpio::Speed::VeryHigh); 160 ws.set_speed(crate::gpio::Speed::VeryHigh);
162 161
163 ck.set_as_af(ck.af_num(), AFType::OutputPushPull); 162 ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
164 ck.set_speed(crate::gpio::Speed::VeryHigh); 163 ck.set_speed(crate::gpio::Speed::VeryHigh);
165 164
166 mck.set_as_af(mck.af_num(), AFType::OutputPushPull); 165 mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
167 mck.set_speed(crate::gpio::Speed::VeryHigh); 166 mck.set_speed(crate::gpio::Speed::VeryHigh);
168 }
169 167
170 let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default()); 168 let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
171 169
@@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
178 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 176 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
179 177
180 #[cfg(any(spi_v1, spi_f1))] 178 #[cfg(any(spi_v1, spi_f1))]
181 unsafe { 179 {
182 use stm32_metapac::spi::vals::{I2scfg, Odd}; 180 use stm32_metapac::spi::vals::{I2scfg, Odd};
183 181
184 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud 182 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
@@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
232 w.set_i2se(true) 230 w.set_i2se(true)
233 }); 231 });
234 } 232 }
235 #[cfg(spi_v2)]
236 unsafe {}
237 #[cfg(any(spi_v3, spi_v4))]
238 unsafe {}
239 233
240 Self { 234 Self {
241 _peri: spi, 235 _peri: spi,
@@ -264,12 +258,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
264 258
265impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { 259impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
266 fn drop(&mut self) { 260 fn drop(&mut self) {
267 unsafe { 261 self.sd.as_ref().map(|x| x.set_as_disconnected());
268 self.sd.as_ref().map(|x| x.set_as_disconnected()); 262 self.ws.as_ref().map(|x| x.set_as_disconnected());
269 self.ws.as_ref().map(|x| x.set_as_disconnected()); 263 self.ck.as_ref().map(|x| x.set_as_disconnected());
270 self.ck.as_ref().map(|x| x.set_as_disconnected()); 264 self.mck.as_ref().map(|x| x.set_as_disconnected());
271 self.mck.as_ref().map(|x| x.set_as_disconnected());
272 }
273 } 265 }
274} 266}
275 267
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
new file mode 100644
index 000000000..3062226c7
--- /dev/null
+++ b/embassy-stm32/src/ipcc.rs
@@ -0,0 +1,337 @@
1use core::future::poll_fn;
2use core::task::Poll;
3
4use atomic_polyfill::{compiler_fence, Ordering};
5
6use self::sealed::Instance;
7use crate::interrupt;
8use crate::interrupt::typelevel::Interrupt;
9use crate::peripherals::IPCC;
10use crate::rcc::sealed::RccPeripheral;
11
12/// Interrupt handler.
13pub struct ReceiveInterruptHandler {}
14
15impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
16 unsafe fn on_interrupt() {
17 let regs = IPCC::regs();
18
19 let channels = [
20 IpccChannel::Channel1,
21 IpccChannel::Channel2,
22 IpccChannel::Channel3,
23 IpccChannel::Channel4,
24 IpccChannel::Channel5,
25 IpccChannel::Channel6,
26 ];
27
28 // Status register gives channel occupied status. For rx, use cpu1.
29 let sr = regs.cpu(1).sr().read();
30 regs.cpu(0).mr().modify(|w| {
31 for channel in channels {
32 if sr.chf(channel as usize) {
33 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
34 w.set_chom(channel as usize, true);
35
36 // There shouldn't be a race because the channel is masked only if the interrupt has fired
37 IPCC::state().rx_waker_for(channel).wake();
38 }
39 }
40 })
41 }
42}
43
44pub struct TransmitInterruptHandler {}
45
46impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
47 unsafe fn on_interrupt() {
48 let regs = IPCC::regs();
49
50 let channels = [
51 IpccChannel::Channel1,
52 IpccChannel::Channel2,
53 IpccChannel::Channel3,
54 IpccChannel::Channel4,
55 IpccChannel::Channel5,
56 IpccChannel::Channel6,
57 ];
58
59 // Status register gives channel occupied status. For tx, use cpu0.
60 let sr = regs.cpu(0).sr().read();
61 regs.cpu(0).mr().modify(|w| {
62 for channel in channels {
63 if !sr.chf(channel as usize) {
64 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
65 w.set_chfm(channel as usize, true);
66
67 // There shouldn't be a race because the channel is masked only if the interrupt has fired
68 IPCC::state().tx_waker_for(channel).wake();
69 }
70 }
71 });
72 }
73}
74
75#[non_exhaustive]
76#[derive(Clone, Copy, Default)]
77pub struct Config {
78 // TODO: add IPCC peripheral configuration, if any, here
79 // reserved for future use
80}
81
82#[derive(Debug, Clone, Copy)]
83#[repr(C)]
84pub enum IpccChannel {
85 Channel1 = 0,
86 Channel2 = 1,
87 Channel3 = 2,
88 Channel4 = 3,
89 Channel5 = 4,
90 Channel6 = 5,
91}
92
93pub struct Ipcc;
94
95impl Ipcc {
96 pub fn enable(_config: Config) {
97 IPCC::enable();
98 IPCC::reset();
99 IPCC::set_cpu2(true);
100
101 _configure_pwr();
102
103 let regs = IPCC::regs();
104
105 regs.cpu(0).cr().modify(|w| {
106 w.set_rxoie(true);
107 w.set_txfie(true);
108 });
109
110 // enable interrupts
111 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
112 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
113
114 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
115 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
116 }
117
118 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
119 pub async fn send(channel: IpccChannel, f: impl FnOnce()) {
120 let regs = IPCC::regs();
121
122 Self::flush(channel).await;
123 compiler_fence(Ordering::SeqCst);
124
125 f();
126
127 compiler_fence(Ordering::SeqCst);
128
129 trace!("ipcc: ch {}: send data", channel as u8);
130 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true));
131 }
132
133 /// Wait for the tx channel to become clear
134 pub async fn flush(channel: IpccChannel) {
135 let regs = IPCC::regs();
136
137 // This is a race, but is nice for debugging
138 if regs.cpu(0).sr().read().chf(channel as usize) {
139 trace!("ipcc: ch {}: wait for tx free", channel as u8);
140 }
141
142 poll_fn(|cx| {
143 IPCC::state().tx_waker_for(channel).register(cx.waker());
144 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
145 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false));
146
147 compiler_fence(Ordering::SeqCst);
148
149 if !regs.cpu(0).sr().read().chf(channel as usize) {
150 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
151 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
152
153 Poll::Ready(())
154 } else {
155 Poll::Pending
156 }
157 })
158 .await;
159 }
160
161 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
162 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R {
163 let regs = IPCC::regs();
164
165 loop {
166 // This is a race, but is nice for debugging
167 if !regs.cpu(1).sr().read().chf(channel as usize) {
168 trace!("ipcc: ch {}: wait for rx occupied", channel as u8);
169 }
170
171 poll_fn(|cx| {
172 IPCC::state().rx_waker_for(channel).register(cx.waker());
173 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
174 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false));
175
176 compiler_fence(Ordering::SeqCst);
177
178 if regs.cpu(1).sr().read().chf(channel as usize) {
179 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
180 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
181
182 Poll::Ready(())
183 } else {
184 Poll::Pending
185 }
186 })
187 .await;
188
189 trace!("ipcc: ch {}: read data", channel as u8);
190 compiler_fence(Ordering::SeqCst);
191
192 match f() {
193 Some(ret) => return ret,
194 None => {}
195 }
196
197 trace!("ipcc: ch {}: clear rx", channel as u8);
198 compiler_fence(Ordering::SeqCst);
199 // If the channel is clear and the read function returns none, fetch more data
200 regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true));
201 }
202 }
203}
204
205impl sealed::Instance for crate::peripherals::IPCC {
206 fn regs() -> crate::pac::ipcc::Ipcc {
207 crate::pac::IPCC
208 }
209
210 fn set_cpu2(enabled: bool) {
211 crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled));
212 }
213
214 fn state() -> &'static self::sealed::State {
215 static STATE: self::sealed::State = self::sealed::State::new();
216 &STATE
217 }
218}
219
220pub(crate) mod sealed {
221 use embassy_sync::waitqueue::AtomicWaker;
222
223 use super::*;
224
225 pub struct State {
226 rx_wakers: [AtomicWaker; 6],
227 tx_wakers: [AtomicWaker; 6],
228 }
229
230 impl State {
231 pub const fn new() -> Self {
232 const WAKER: AtomicWaker = AtomicWaker::new();
233
234 Self {
235 rx_wakers: [WAKER; 6],
236 tx_wakers: [WAKER; 6],
237 }
238 }
239
240 pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
241 match channel {
242 IpccChannel::Channel1 => &self.rx_wakers[0],
243 IpccChannel::Channel2 => &self.rx_wakers[1],
244 IpccChannel::Channel3 => &self.rx_wakers[2],
245 IpccChannel::Channel4 => &self.rx_wakers[3],
246 IpccChannel::Channel5 => &self.rx_wakers[4],
247 IpccChannel::Channel6 => &self.rx_wakers[5],
248 }
249 }
250
251 pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
252 match channel {
253 IpccChannel::Channel1 => &self.tx_wakers[0],
254 IpccChannel::Channel2 => &self.tx_wakers[1],
255 IpccChannel::Channel3 => &self.tx_wakers[2],
256 IpccChannel::Channel4 => &self.tx_wakers[3],
257 IpccChannel::Channel5 => &self.tx_wakers[4],
258 IpccChannel::Channel6 => &self.tx_wakers[5],
259 }
260 }
261 }
262
263 pub trait Instance: crate::rcc::RccPeripheral {
264 fn regs() -> crate::pac::ipcc::Ipcc;
265 fn set_cpu2(enabled: bool);
266 fn state() -> &'static State;
267 }
268}
269
270fn _configure_pwr() {
271 // TODO: move this to RCC
272
273 let pwr = crate::pac::PWR;
274 let rcc = crate::pac::RCC;
275
276 rcc.cfgr().modify(|w| w.set_stopwuck(true));
277
278 pwr.cr1().modify(|w| w.set_dbp(true));
279 pwr.cr1().modify(|w| w.set_dbp(true));
280
281 // configure LSE
282 rcc.bdcr().modify(|w| w.set_lseon(true));
283
284 // select system clock source = PLL
285 // set PLL coefficients
286 // m: 2,
287 // n: 12,
288 // r: 3,
289 // q: 4,
290 // p: 3,
291 let src_bits = 0b11;
292 let pllp = (3 - 1) & 0b11111;
293 let pllq = (4 - 1) & 0b111;
294 let pllr = (3 - 1) & 0b111;
295 let plln = 12 & 0b1111111;
296 let pllm = (2 - 1) & 0b111;
297 rcc.pllcfgr().modify(|w| {
298 w.set_pllsrc(src_bits);
299 w.set_pllm(pllm);
300 w.set_plln(plln);
301 w.set_pllr(pllr);
302 w.set_pllp(pllp);
303 w.set_pllpen(true);
304 w.set_pllq(pllq);
305 w.set_pllqen(true);
306 });
307 // enable PLL
308 rcc.cr().modify(|w| w.set_pllon(true));
309 rcc.cr().write(|w| w.set_hsion(false));
310 // while !rcc.cr().read().pllrdy() {}
311
312 // configure SYSCLK mux to use PLL clocl
313 rcc.cfgr().modify(|w| w.set_sw(0b11));
314
315 // configure CPU1 & CPU2 dividers
316 rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
317 rcc.extcfgr().modify(|w| {
318 w.set_c2hpre(0b1000); // div2
319 w.set_shdhpre(0); // not divided
320 });
321
322 // apply APB1 / APB2 values
323 rcc.cfgr().modify(|w| {
324 w.set_ppre1(0b000); // not divided
325 w.set_ppre2(0b000); // not divided
326 });
327
328 // TODO: required
329 // set RF wake-up clock = LSE
330 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
331
332 // set LPTIM1 & LPTIM2 clock source
333 rcc.ccipr().modify(|w| {
334 w.set_lptim1sel(0b00); // PCLK
335 w.set_lptim2sel(0b00); // PCLK
336 });
337}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 6533509eb..45a7b5476 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -41,6 +41,8 @@ pub mod crc;
41pub mod flash; 41pub mod flash;
42#[cfg(all(spi_v1, rcc_f4))] 42#[cfg(all(spi_v1, rcc_f4))]
43pub mod i2s; 43pub mod i2s;
44#[cfg(stm32wb)]
45pub mod ipcc;
44pub mod pwm; 46pub mod pwm;
45#[cfg(quadspi)] 47#[cfg(quadspi)]
46pub mod qspi; 48pub mod qspi;
@@ -52,8 +54,6 @@ pub mod rtc;
52pub mod sdmmc; 54pub mod sdmmc;
53#[cfg(spi)] 55#[cfg(spi)]
54pub mod spi; 56pub mod spi;
55#[cfg(stm32wb)]
56pub mod tl_mbox;
57#[cfg(usart)] 57#[cfg(usart)]
58pub mod usart; 58pub mod usart;
59#[cfg(usb)] 59#[cfg(usb)]
@@ -72,52 +72,47 @@ pub(crate) mod _generated {
72 include!(concat!(env!("OUT_DIR"), "/_generated.rs")); 72 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
73} 73}
74 74
75pub mod interrupt { 75pub use crate::_generated::interrupt;
76 //! Interrupt definitions and macros to bind them. 76
77 pub use cortex_m::interrupt::{CriticalSection, Mutex}; 77/// Macro to bind interrupts to handlers.
78 pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; 78///
79 79/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
80 pub use crate::_generated::interrupt::*; 80/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
81 81/// prove at compile-time that the right interrupts have been bound.
82 /// Macro to bind interrupts to handlers. 82// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
83 /// 83#[macro_export]
84 /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 84macro_rules! bind_interrupts {
85 /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to 85 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
86 /// prove at compile-time that the right interrupts have been bound. 86 $vis struct $name;
87 // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. 87
88 #[macro_export] 88 $(
89 macro_rules! bind_interrupts { 89 #[allow(non_snake_case)]
90 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 90 #[no_mangle]
91 $vis struct $name; 91 unsafe extern "C" fn $irq() {
92
93 $(
94 #[allow(non_snake_case)]
95 #[no_mangle]
96 unsafe extern "C" fn $irq() {
97 $(
98 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
99 )*
100 }
101
102 $( 92 $(
103 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} 93 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
104 )* 94 )*
95 }
96
97 $(
98 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
105 )* 99 )*
106 }; 100 )*
107 } 101 };
108} 102}
109 103
110// Reexports 104// Reexports
111pub use _generated::{peripherals, Peripherals}; 105pub use _generated::{peripherals, Peripherals};
112pub use embassy_cortex_m::executor;
113use embassy_cortex_m::interrupt::Priority;
114pub use embassy_cortex_m::interrupt::_export::interrupt;
115pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 106pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
116#[cfg(feature = "unstable-pac")] 107#[cfg(feature = "unstable-pac")]
117pub use stm32_metapac as pac; 108pub use stm32_metapac as pac;
118#[cfg(not(feature = "unstable-pac"))] 109#[cfg(not(feature = "unstable-pac"))]
119pub(crate) use stm32_metapac as pac; 110pub(crate) use stm32_metapac as pac;
120 111
112use crate::interrupt::Priority;
113#[cfg(feature = "rt")]
114pub use crate::pac::NVIC_PRIO_BITS;
115
121#[non_exhaustive] 116#[non_exhaustive]
122pub struct Config { 117pub struct Config {
123 pub rcc: rcc::Config, 118 pub rcc: rcc::Config,
@@ -151,35 +146,35 @@ impl Default for Config {
151pub fn init(config: Config) -> Peripherals { 146pub fn init(config: Config) -> Peripherals {
152 let p = Peripherals::take(); 147 let p = Peripherals::take();
153 148
154 unsafe { 149 #[cfg(dbgmcu)]
155 #[cfg(dbgmcu)] 150 if config.enable_debug_during_sleep {
156 if config.enable_debug_during_sleep { 151 crate::pac::DBGMCU.cr().modify(|cr| {
157 crate::pac::DBGMCU.cr().modify(|cr| { 152 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
158 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] 153 {
159 { 154 cr.set_dbg_stop(true);
160 cr.set_dbg_stop(true); 155 cr.set_dbg_standby(true);
161 cr.set_dbg_standby(true); 156 }
162 } 157 #[cfg(any(
163 #[cfg(any( 158 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
164 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 159 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
165 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 160 ))]
166 ))] 161 {
167 { 162 cr.set_dbg_sleep(true);
168 cr.set_dbg_sleep(true); 163 cr.set_dbg_stop(true);
169 cr.set_dbg_stop(true); 164 cr.set_dbg_standby(true);
170 cr.set_dbg_standby(true); 165 }
171 } 166 #[cfg(dbgmcu_h7)]
172 #[cfg(dbgmcu_h7)] 167 {
173 { 168 cr.set_d1dbgcken(true);
174 cr.set_d1dbgcken(true); 169 cr.set_d3dbgcken(true);
175 cr.set_d3dbgcken(true); 170 cr.set_dbgsleep_d1(true);
176 cr.set_dbgsleep_d1(true); 171 cr.set_dbgstby_d1(true);
177 cr.set_dbgstby_d1(true); 172 cr.set_dbgstop_d1(true);
178 cr.set_dbgstop_d1(true); 173 }
179 } 174 });
180 }); 175 }
181 }
182 176
177 unsafe {
183 gpio::init(); 178 gpio::init();
184 dma::init( 179 dma::init(
185 #[cfg(bdma)] 180 #[cfg(bdma)]
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
index cfb79947c..0e153202e 100644
--- a/embassy-stm32/src/pwm/complementary_pwm.rs
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
23 into_ref!(pin); 23 into_ref!(pin);
24 critical_section::with(|_| unsafe { 24 critical_section::with(|_| {
25 pin.set_low(); 25 pin.set_low();
26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull); 26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
27 #[cfg(gpio_v2)] 27 #[cfg(gpio_v2)]
@@ -72,33 +72,27 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
72 this.inner.set_frequency(freq); 72 this.inner.set_frequency(freq);
73 this.inner.start(); 73 this.inner.start();
74 74
75 unsafe { 75 this.inner.enable_outputs(true);
76 this.inner.enable_outputs(true); 76
77 77 this.inner
78 this.inner 78 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
79 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 79 this.inner
80 this.inner 80 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
81 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 81 this.inner
82 this.inner 82 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
83 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 83 this.inner
84 this.inner 84 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
85 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
86 }
87 this 85 this
88 } 86 }
89 87
90 pub fn enable(&mut self, channel: Channel) { 88 pub fn enable(&mut self, channel: Channel) {
91 unsafe { 89 self.inner.enable_channel(channel, true);
92 self.inner.enable_channel(channel, true); 90 self.inner.enable_complementary_channel(channel, true);
93 self.inner.enable_complementary_channel(channel, true);
94 }
95 } 91 }
96 92
97 pub fn disable(&mut self, channel: Channel) { 93 pub fn disable(&mut self, channel: Channel) {
98 unsafe { 94 self.inner.enable_complementary_channel(channel, false);
99 self.inner.enable_complementary_channel(channel, false); 95 self.inner.enable_channel(channel, false);
100 self.inner.enable_channel(channel, false);
101 }
102 } 96 }
103 97
104 pub fn set_freq(&mut self, freq: Hertz) { 98 pub fn set_freq(&mut self, freq: Hertz) {
@@ -106,22 +100,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
106 } 100 }
107 101
108 pub fn get_max_duty(&self) -> u16 { 102 pub fn get_max_duty(&self) -> u16 {
109 unsafe { self.inner.get_max_compare_value() } 103 self.inner.get_max_compare_value()
110 } 104 }
111 105
112 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 106 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
113 assert!(duty < self.get_max_duty()); 107 assert!(duty < self.get_max_duty());
114 unsafe { self.inner.set_compare_value(channel, duty) } 108 self.inner.set_compare_value(channel, duty)
115 } 109 }
116 110
117 /// Set the dead time as a proportion of max_duty 111 /// Set the dead time as a proportion of max_duty
118 pub fn set_dead_time(&mut self, value: u16) { 112 pub fn set_dead_time(&mut self, value: u16) {
119 let (ckd, value) = compute_dead_time_value(value); 113 let (ckd, value) = compute_dead_time_value(value);
120 114
121 unsafe { 115 self.inner.set_dead_time_clock_division(ckd);
122 self.inner.set_dead_time_clock_division(ckd); 116 self.inner.set_dead_time_value(value);
123 self.inner.set_dead_time_value(value);
124 }
125 } 117 }
126} 118}
127 119
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index 0bef07089..5aba2663e 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -59,33 +59,33 @@ pub(crate) mod sealed {
59 59
60 pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { 60 pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
61 /// Global output enable. Does not do anything on non-advanced timers. 61 /// Global output enable. Does not do anything on non-advanced timers.
62 unsafe fn enable_outputs(&mut self, enable: bool); 62 fn enable_outputs(&mut self, enable: bool);
63 63
64 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 64 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
65 65
66 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); 66 fn enable_channel(&mut self, channel: Channel, enable: bool);
67 67
68 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16); 68 fn set_compare_value(&mut self, channel: Channel, value: u16);
69 69
70 unsafe fn get_max_compare_value(&self) -> u16; 70 fn get_max_compare_value(&self) -> u16;
71 } 71 }
72 72
73 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { 73 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
74 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); 74 fn set_dead_time_clock_division(&mut self, value: Ckd);
75 75
76 unsafe fn set_dead_time_value(&mut self, value: u8); 76 fn set_dead_time_value(&mut self, value: u8);
77 77
78 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); 78 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
79 } 79 }
80 80
81 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { 81 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
82 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 82 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
83 83
84 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); 84 fn enable_channel(&mut self, channel: Channel, enable: bool);
85 85
86 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32); 86 fn set_compare_value(&mut self, channel: Channel, value: u32);
87 87
88 unsafe fn get_max_compare_value(&self) -> u32; 88 fn get_max_compare_value(&self) -> u32;
89 } 89 }
90} 90}
91 91
@@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance:
108macro_rules! impl_compare_capable_16bit { 108macro_rules! impl_compare_capable_16bit {
109 ($inst:ident) => { 109 ($inst:ident) => {
110 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 110 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
111 unsafe fn enable_outputs(&mut self, _enable: bool) {} 111 fn enable_outputs(&mut self, _enable: bool) {}
112 112
113 unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { 113 fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
114 use crate::timer::sealed::GeneralPurpose16bitInstance; 114 use crate::timer::sealed::GeneralPurpose16bitInstance;
115 let r = Self::regs_gp16(); 115 let r = Self::regs_gp16();
116 let raw_channel: usize = channel.raw(); 116 let raw_channel: usize = channel.raw();
@@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit {
118 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 118 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
119 } 119 }
120 120
121 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 121 fn enable_channel(&mut self, channel: Channel, enable: bool) {
122 use crate::timer::sealed::GeneralPurpose16bitInstance; 122 use crate::timer::sealed::GeneralPurpose16bitInstance;
123 Self::regs_gp16() 123 Self::regs_gp16()
124 .ccer() 124 .ccer()
125 .modify(|w| w.set_cce(channel.raw(), enable)); 125 .modify(|w| w.set_cce(channel.raw(), enable));
126 } 126 }
127 127
128 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { 128 fn set_compare_value(&mut self, channel: Channel, value: u16) {
129 use crate::timer::sealed::GeneralPurpose16bitInstance; 129 use crate::timer::sealed::GeneralPurpose16bitInstance;
130 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 130 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
131 } 131 }
132 132
133 unsafe fn get_max_compare_value(&self) -> u16 { 133 fn get_max_compare_value(&self) -> u16 {
134 use crate::timer::sealed::GeneralPurpose16bitInstance; 134 use crate::timer::sealed::GeneralPurpose16bitInstance;
135 Self::regs_gp16().arr().read().arr() 135 Self::regs_gp16().arr().read().arr()
136 } 136 }
@@ -150,7 +150,7 @@ foreach_interrupt! {
150 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 150 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
151 impl_compare_capable_16bit!($inst); 151 impl_compare_capable_16bit!($inst);
152 impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { 152 impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
153 unsafe fn set_output_compare_mode( 153 fn set_output_compare_mode(
154 &mut self, 154 &mut self,
155 channel: crate::pwm::Channel, 155 channel: crate::pwm::Channel,
156 mode: OutputCompareMode, 156 mode: OutputCompareMode,
@@ -160,17 +160,17 @@ foreach_interrupt! {
160 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 160 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
161 } 161 }
162 162
163 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 163 fn enable_channel(&mut self, channel: Channel, enable: bool) {
164 use crate::timer::sealed::GeneralPurpose32bitInstance; 164 use crate::timer::sealed::GeneralPurpose32bitInstance;
165 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); 165 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
166 } 166 }
167 167
168 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) { 168 fn set_compare_value(&mut self, channel: Channel, value: u32) {
169 use crate::timer::sealed::GeneralPurpose32bitInstance; 169 use crate::timer::sealed::GeneralPurpose32bitInstance;
170 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 170 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
171 } 171 }
172 172
173 unsafe fn get_max_compare_value(&self) -> u32 { 173 fn get_max_compare_value(&self) -> u32 {
174 use crate::timer::sealed::GeneralPurpose32bitInstance; 174 use crate::timer::sealed::GeneralPurpose32bitInstance;
175 Self::regs_gp32().arr().read().arr() as u32 175 Self::regs_gp32().arr().read().arr() as u32
176 } 176 }
@@ -185,13 +185,13 @@ foreach_interrupt! {
185 185
186 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 186 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
187 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 187 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
188 unsafe fn enable_outputs(&mut self, enable: bool) { 188 fn enable_outputs(&mut self, enable: bool) {
189 use crate::timer::sealed::AdvancedControlInstance; 189 use crate::timer::sealed::AdvancedControlInstance;
190 let r = Self::regs_advanced(); 190 let r = Self::regs_advanced();
191 r.bdtr().modify(|w| w.set_moe(enable)); 191 r.bdtr().modify(|w| w.set_moe(enable));
192 } 192 }
193 193
194 unsafe fn set_output_compare_mode( 194 fn set_output_compare_mode(
195 &mut self, 195 &mut self,
196 channel: crate::pwm::Channel, 196 channel: crate::pwm::Channel,
197 mode: OutputCompareMode, 197 mode: OutputCompareMode,
@@ -203,21 +203,21 @@ foreach_interrupt! {
203 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 203 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
204 } 204 }
205 205
206 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 206 fn enable_channel(&mut self, channel: Channel, enable: bool) {
207 use crate::timer::sealed::AdvancedControlInstance; 207 use crate::timer::sealed::AdvancedControlInstance;
208 Self::regs_advanced() 208 Self::regs_advanced()
209 .ccer() 209 .ccer()
210 .modify(|w| w.set_cce(channel.raw(), enable)); 210 .modify(|w| w.set_cce(channel.raw(), enable));
211 } 211 }
212 212
213 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { 213 fn set_compare_value(&mut self, channel: Channel, value: u16) {
214 use crate::timer::sealed::AdvancedControlInstance; 214 use crate::timer::sealed::AdvancedControlInstance;
215 Self::regs_advanced() 215 Self::regs_advanced()
216 .ccr(channel.raw()) 216 .ccr(channel.raw())
217 .modify(|w| w.set_ccr(value)); 217 .modify(|w| w.set_ccr(value));
218 } 218 }
219 219
220 unsafe fn get_max_compare_value(&self) -> u16 { 220 fn get_max_compare_value(&self) -> u16 {
221 use crate::timer::sealed::AdvancedControlInstance; 221 use crate::timer::sealed::AdvancedControlInstance;
222 Self::regs_advanced().arr().read().arr() 222 Self::regs_advanced().arr().read().arr()
223 } 223 }
@@ -228,17 +228,17 @@ foreach_interrupt! {
228 } 228 }
229 229
230 impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { 230 impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
231 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) { 231 fn set_dead_time_clock_division(&mut self, value: Ckd) {
232 use crate::timer::sealed::AdvancedControlInstance; 232 use crate::timer::sealed::AdvancedControlInstance;
233 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 233 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
234 } 234 }
235 235
236 unsafe fn set_dead_time_value(&mut self, value: u8) { 236 fn set_dead_time_value(&mut self, value: u8) {
237 use crate::timer::sealed::AdvancedControlInstance; 237 use crate::timer::sealed::AdvancedControlInstance;
238 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 238 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
239 } 239 }
240 240
241 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 241 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
242 use crate::timer::sealed::AdvancedControlInstance; 242 use crate::timer::sealed::AdvancedControlInstance;
243 Self::regs_advanced() 243 Self::regs_advanced()
244 .ccer() 244 .ccer()
diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs
index b045a2d78..995f59c23 100644
--- a/embassy-stm32/src/pwm/simple_pwm.rs
+++ b/embassy-stm32/src/pwm/simple_pwm.rs
@@ -24,7 +24,7 @@ macro_rules! channel_impl {
24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
26 into_ref!(pin); 26 into_ref!(pin);
27 critical_section::with(|_| unsafe { 27 critical_section::with(|_| {
28 pin.set_low(); 28 pin.set_low();
29 pin.set_as_af(pin.af_num(), AFType::OutputPushPull); 29 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
30 #[cfg(gpio_v2)] 30 #[cfg(gpio_v2)]
@@ -71,31 +71,25 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
71 this.inner.set_frequency(freq); 71 this.inner.set_frequency(freq);
72 this.inner.start(); 72 this.inner.start();
73 73
74 unsafe { 74 this.inner.enable_outputs(true);
75 this.inner.enable_outputs(true); 75
76 76 this.inner
77 this.inner 77 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
78 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 78 this.inner
79 this.inner 79 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
80 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 80 this.inner
81 this.inner 81 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
82 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 82 this.inner
83 this.inner 83 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
84 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
85 }
86 this 84 this
87 } 85 }
88 86
89 pub fn enable(&mut self, channel: Channel) { 87 pub fn enable(&mut self, channel: Channel) {
90 unsafe { 88 self.inner.enable_channel(channel, true);
91 self.inner.enable_channel(channel, true);
92 }
93 } 89 }
94 90
95 pub fn disable(&mut self, channel: Channel) { 91 pub fn disable(&mut self, channel: Channel) {
96 unsafe { 92 self.inner.enable_channel(channel, false);
97 self.inner.enable_channel(channel, false);
98 }
99 } 93 }
100 94
101 pub fn set_freq(&mut self, freq: Hertz) { 95 pub fn set_freq(&mut self, freq: Hertz) {
@@ -103,11 +97,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
103 } 97 }
104 98
105 pub fn get_max_duty(&self) -> u16 { 99 pub fn get_max_duty(&self) -> u16 {
106 unsafe { self.inner.get_max_compare_value() } 100 self.inner.get_max_compare_value()
107 } 101 }
108 102
109 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 103 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
110 assert!(duty < self.get_max_duty()); 104 assert!(duty < self.get_max_duty());
111 unsafe { self.inner.set_compare_value(channel, duty) } 105 self.inner.set_compare_value(channel, duty)
112 } 106 }
113} 107}
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index c3126b37f..e9db934bf 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -96,20 +96,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
96 ) -> Self { 96 ) -> Self {
97 into_ref!(peri, d0, d1, d2, d3, sck, nss); 97 into_ref!(peri, d0, d1, d2, d3, sck, nss);
98 98
99 unsafe { 99 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
100 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 100 sck.set_speed(crate::gpio::Speed::VeryHigh);
101 sck.set_speed(crate::gpio::Speed::VeryHigh); 101 nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
102 nss.set_as_af(nss.af_num(), AFType::OutputPushPull); 102 nss.set_speed(crate::gpio::Speed::VeryHigh);
103 nss.set_speed(crate::gpio::Speed::VeryHigh); 103 d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
104 d0.set_as_af(d0.af_num(), AFType::OutputPushPull); 104 d0.set_speed(crate::gpio::Speed::VeryHigh);
105 d0.set_speed(crate::gpio::Speed::VeryHigh); 105 d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
106 d1.set_as_af(d1.af_num(), AFType::OutputPushPull); 106 d1.set_speed(crate::gpio::Speed::VeryHigh);
107 d1.set_speed(crate::gpio::Speed::VeryHigh); 107 d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
108 d2.set_as_af(d2.af_num(), AFType::OutputPushPull); 108 d2.set_speed(crate::gpio::Speed::VeryHigh);
109 d2.set_speed(crate::gpio::Speed::VeryHigh); 109 d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
110 d3.set_as_af(d3.af_num(), AFType::OutputPushPull); 110 d3.set_speed(crate::gpio::Speed::VeryHigh);
111 d3.set_speed(crate::gpio::Speed::VeryHigh);
112 }
113 111
114 Self::new_inner( 112 Self::new_inner(
115 peri, 113 peri,
@@ -138,21 +136,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
138 into_ref!(peri, dma); 136 into_ref!(peri, dma);
139 137
140 T::enable(); 138 T::enable();
141 unsafe { 139 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
142 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
143 140
144 while T::REGS.sr().read().busy() {} 141 while T::REGS.sr().read().busy() {}
145 142
146 T::REGS.cr().write(|w| { 143 T::REGS.cr().write(|w| {
147 w.set_prescaler(config.prescaler); 144 w.set_prescaler(config.prescaler);
148 w.set_en(true); 145 w.set_en(true);
149 }); 146 });
150 T::REGS.dcr().write(|w| { 147 T::REGS.dcr().write(|w| {
151 w.set_fsize(config.memory_size.into()); 148 w.set_fsize(config.memory_size.into());
152 w.set_csht(config.cs_high_time.into()); 149 w.set_csht(config.cs_high_time.into());
153 w.set_ckmode(false); 150 w.set_ckmode(false);
154 }); 151 });
155 }
156 152
157 Self { 153 Self {
158 _peri: peri, 154 _peri: peri,
@@ -168,148 +164,140 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
168 } 164 }
169 165
170 pub fn command(&mut self, transaction: TransferConfig) { 166 pub fn command(&mut self, transaction: TransferConfig) {
171 unsafe { 167 T::REGS.cr().modify(|v| v.set_dmaen(false));
172 T::REGS.cr().modify(|v| v.set_dmaen(false)); 168 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
173 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
174 169
175 while !T::REGS.sr().read().tcf() {} 170 while !T::REGS.sr().read().tcf() {}
176 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 171 T::REGS.fcr().modify(|v| v.set_ctcf(true));
177 }
178 } 172 }
179 173
180 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 174 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
181 unsafe { 175 T::REGS.cr().modify(|v| v.set_dmaen(false));
182 T::REGS.cr().modify(|v| v.set_dmaen(false)); 176 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
183 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 177
184 178 if let Some(len) = transaction.data_len {
185 if let Some(len) = transaction.data_len { 179 let current_ar = T::REGS.ar().read().address();
186 let current_ar = T::REGS.ar().read().address(); 180 T::REGS.ccr().modify(|v| {
187 T::REGS.ccr().modify(|v| { 181 v.set_fmode(QspiMode::IndirectRead.into());
188 v.set_fmode(QspiMode::IndirectRead.into()); 182 });
189 }); 183 T::REGS.ar().write(|v| {
190 T::REGS.ar().write(|v| { 184 v.set_address(current_ar);
191 v.set_address(current_ar); 185 });
192 });
193
194 for idx in 0..len {
195 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
196 buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
197 }
198 }
199 186
200 while !T::REGS.sr().read().tcf() {} 187 for idx in 0..len {
201 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 188 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
189 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
190 }
202 } 191 }
192
193 while !T::REGS.sr().read().tcf() {}
194 T::REGS.fcr().modify(|v| v.set_ctcf(true));
203 } 195 }
204 196
205 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 197 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
206 unsafe { 198 T::REGS.cr().modify(|v| v.set_dmaen(false));
207 T::REGS.cr().modify(|v| v.set_dmaen(false)); 199 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
208 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
209
210 if let Some(len) = transaction.data_len {
211 T::REGS.ccr().modify(|v| {
212 v.set_fmode(QspiMode::IndirectWrite.into());
213 });
214
215 for idx in 0..len {
216 while !T::REGS.sr().read().ftf() {}
217 *(T::REGS.dr().ptr() as *mut u8) = buf[idx];
218 }
219 }
220 200
221 while !T::REGS.sr().read().tcf() {} 201 if let Some(len) = transaction.data_len {
222 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 202 T::REGS.ccr().modify(|v| {
203 v.set_fmode(QspiMode::IndirectWrite.into());
204 });
205
206 for idx in 0..len {
207 while !T::REGS.sr().read().ftf() {}
208 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
209 }
223 } 210 }
211
212 while !T::REGS.sr().read().tcf() {}
213 T::REGS.fcr().modify(|v| v.set_ctcf(true));
224 } 214 }
225 215
226 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 216 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
227 where 217 where
228 Dma: QuadDma<T>, 218 Dma: QuadDma<T>,
229 { 219 {
230 unsafe { 220 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
231 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 221
232 222 T::REGS.ccr().modify(|v| {
233 T::REGS.ccr().modify(|v| { 223 v.set_fmode(QspiMode::IndirectRead.into());
234 v.set_fmode(QspiMode::IndirectRead.into()); 224 });
235 }); 225 let current_ar = T::REGS.ar().read().address();
236 let current_ar = T::REGS.ar().read().address(); 226 T::REGS.ar().write(|v| {
237 T::REGS.ar().write(|v| { 227 v.set_address(current_ar);
238 v.set_address(current_ar); 228 });
239 }); 229
240 230 let request = self.dma.request();
241 let request = self.dma.request(); 231 let transfer = unsafe {
242 let transfer = Transfer::new_read( 232 Transfer::new_read(
243 &mut self.dma, 233 &mut self.dma,
244 request, 234 request,
245 T::REGS.dr().ptr() as *mut u8, 235 T::REGS.dr().as_ptr() as *mut u8,
246 buf, 236 buf,
247 Default::default(), 237 Default::default(),
248 ); 238 )
239 };
249 240
250 T::REGS.cr().modify(|v| v.set_dmaen(true)); 241 T::REGS.cr().modify(|v| v.set_dmaen(true));
251 242
252 transfer.blocking_wait(); 243 transfer.blocking_wait();
253 }
254 } 244 }
255 245
256 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 246 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
257 where 247 where
258 Dma: QuadDma<T>, 248 Dma: QuadDma<T>,
259 { 249 {
260 unsafe { 250 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
261 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
262 251
263 T::REGS.ccr().modify(|v| { 252 T::REGS.ccr().modify(|v| {
264 v.set_fmode(QspiMode::IndirectWrite.into()); 253 v.set_fmode(QspiMode::IndirectWrite.into());
265 }); 254 });
266 255
267 let request = self.dma.request(); 256 let request = self.dma.request();
268 let transfer = Transfer::new_write( 257 let transfer = unsafe {
258 Transfer::new_write(
269 &mut self.dma, 259 &mut self.dma,
270 request, 260 request,
271 buf, 261 buf,
272 T::REGS.dr().ptr() as *mut u8, 262 T::REGS.dr().as_ptr() as *mut u8,
273 Default::default(), 263 Default::default(),
274 ); 264 )
265 };
275 266
276 T::REGS.cr().modify(|v| v.set_dmaen(true)); 267 T::REGS.cr().modify(|v| v.set_dmaen(true));
277 268
278 transfer.blocking_wait(); 269 transfer.blocking_wait();
279 }
280 } 270 }
281 271
282 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { 272 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
283 unsafe { 273 T::REGS.fcr().modify(|v| {
284 T::REGS.fcr().modify(|v| { 274 v.set_csmf(true);
285 v.set_csmf(true); 275 v.set_ctcf(true);
286 v.set_ctcf(true); 276 v.set_ctef(true);
287 v.set_ctef(true); 277 v.set_ctof(true);
288 v.set_ctof(true); 278 });
289 });
290 279
291 while T::REGS.sr().read().busy() {} 280 while T::REGS.sr().read().busy() {}
292 281
293 if let Some(len) = transaction.data_len { 282 if let Some(len) = transaction.data_len {
294 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); 283 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
295 } 284 }
296 285
297 T::REGS.ccr().write(|v| { 286 T::REGS.ccr().write(|v| {
298 v.set_fmode(fmode.into()); 287 v.set_fmode(fmode.into());
299 v.set_imode(transaction.iwidth.into()); 288 v.set_imode(transaction.iwidth.into());
300 v.set_instruction(transaction.instruction); 289 v.set_instruction(transaction.instruction);
301 v.set_admode(transaction.awidth.into()); 290 v.set_admode(transaction.awidth.into());
302 v.set_adsize(self.config.address_size.into()); 291 v.set_adsize(self.config.address_size.into());
303 v.set_dmode(transaction.dwidth.into()); 292 v.set_dmode(transaction.dwidth.into());
304 v.set_abmode(QspiWidth::NONE.into()); 293 v.set_abmode(QspiWidth::NONE.into());
305 v.set_dcyc(transaction.dummy.into()); 294 v.set_dcyc(transaction.dummy.into());
295 });
296
297 if let Some(addr) = transaction.address {
298 T::REGS.ar().write(|v| {
299 v.set_address(addr);
306 }); 300 });
307
308 if let Some(addr) = transaction.address {
309 T::REGS.ar().write(|v| {
310 v.set_address(addr);
311 });
312 }
313 } 301 }
314 } 302 }
315} 303}
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index e0929ca49..bc430afb2 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -36,18 +36,18 @@ pub struct Config {
36} 36}
37 37
38#[cfg(stm32f410)] 38#[cfg(stm32f410)]
39unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { 39fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
40 None 40 None
41} 41}
42 42
43// Not currently implemented, but will be in the future 43// Not currently implemented, but will be in the future
44#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] 44#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
45unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { 45fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
46 None 46 None
47} 47}
48 48
49#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] 49#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
50unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { 50fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
51 let min_div = 2; 51 let min_div = 2;
52 let max_div = 7; 52 let max_div = 7;
53 let target = match plli2s { 53 let target = match plli2s {
@@ -82,13 +82,7 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
82 Some(output) 82 Some(output)
83} 83}
84 84
85unsafe fn setup_pll( 85fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
86 pllsrcclk: u32,
87 use_hse: bool,
88 pllsysclk: Option<u32>,
89 plli2s: Option<u32>,
90 pll48clk: bool,
91) -> PllResults {
92 use crate::pac::rcc::vals::{Pllp, Pllsrc}; 86 use crate::pac::rcc::vals::{Pllp, Pllsrc};
93 87
94 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 88 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
@@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
320 } 314 }
321} 315}
322 316
323unsafe fn flash_setup(sysclk: u32) { 317fn flash_setup(sysclk: u32) {
324 use crate::pac::flash::vals::Latency; 318 use crate::pac::flash::vals::Latency;
325 319
326 // Be conservative with voltage ranges 320 // Be conservative with voltage ranges
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 2d21326a3..71215cac5 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -25,7 +25,7 @@ pub struct Config {
25 pub pll48: bool, 25 pub pll48: bool,
26} 26}
27 27
28unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { 28fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
29 use crate::pac::rcc::vals::{Pllp, Pllsrc}; 29 use crate::pac::rcc::vals::{Pllp, Pllsrc};
30 30
31 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 31 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
@@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
97 } 97 }
98} 98}
99 99
100unsafe fn flash_setup(sysclk: u32) { 100fn flash_setup(sysclk: u32) {
101 use crate::pac::flash::vals::Latency; 101 use crate::pac::flash::vals::Latency;
102 102
103 // Be conservative with voltage ranges 103 // Be conservative with voltage ranges
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 3e138c7ab..17c73c36b 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -245,7 +245,7 @@ impl Default for Config {
245} 245}
246 246
247impl PllConfig { 247impl PllConfig {
248 pub(crate) unsafe fn init(self) -> u32 { 248 pub(crate) fn init(self) -> u32 {
249 assert!(self.n >= 8 && self.n <= 86); 249 assert!(self.n >= 8 && self.n <= 86);
250 let (src, input_freq) = match self.source { 250 let (src, input_freq) = match self.source {
251 PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), 251 PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 7e748c7b5..9401af4c3 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,4 +1,6 @@
1use stm32_metapac::rcc::vals::{Hpre, Ppre, Sw}; 1use stm32_metapac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
3use stm32_metapac::FLASH;
2 4
3use crate::pac::{PWR, RCC}; 5use crate::pac::{PWR, RCC};
4use crate::rcc::{set_freqs, Clocks}; 6use crate::rcc::{set_freqs, Clocks};
@@ -15,6 +17,7 @@ pub const LSI_FREQ: Hertz = Hertz(32_000);
15pub enum ClockSrc { 17pub enum ClockSrc {
16 HSE(Hertz), 18 HSE(Hertz),
17 HSI16, 19 HSI16,
20 PLL,
18} 21}
19 22
20/// AHB prescaler 23/// AHB prescaler
@@ -41,6 +44,222 @@ pub enum APBPrescaler {
41 Div16, 44 Div16,
42} 45}
43 46
47/// PLL clock input source
48#[derive(Clone, Copy, Debug)]
49pub enum PllSrc {
50 HSI16,
51 HSE(Hertz),
52}
53
54impl Into<Pllsrc> for PllSrc {
55 fn into(self) -> Pllsrc {
56 match self {
57 PllSrc::HSE(..) => Pllsrc::HSE,
58 PllSrc::HSI16 => Pllsrc::HSI16,
59 }
60 }
61}
62
63seq_macro::seq!(P in 2..=31 {
64 /// Output divider for the PLL P output.
65 #[derive(Clone, Copy)]
66 pub enum PllP {
67 // Note: If PLL P is set to 0 the PLLP bit controls the output division. There does not seem to
68 // a good reason to do this so the API does not support it.
69 // Div1 is invalid
70 #(
71 Div~P,
72 )*
73 }
74
75 impl From<PllP> for u8 {
76 /// Returns the register value for the P output divider.
77 fn from(val: PllP) -> u8 {
78 match val {
79 #(
80 PllP::Div~P => P,
81 )*
82 }
83 }
84 }
85});
86
87impl PllP {
88 /// Returns the numeric value of the P output divider.
89 pub fn to_div(self) -> u32 {
90 let val: u8 = self.into();
91 val as u32
92 }
93}
94
95/// Output divider for the PLL Q output.
96#[derive(Clone, Copy)]
97pub enum PllQ {
98 Div2,
99 Div4,
100 Div6,
101 Div8,
102}
103
104impl PllQ {
105 /// Returns the numeric value of the Q output divider.
106 pub fn to_div(self) -> u32 {
107 let val: u8 = self.into();
108 (val as u32 + 1) * 2
109 }
110}
111
112impl From<PllQ> for u8 {
113 /// Returns the register value for the Q output divider.
114 fn from(val: PllQ) -> u8 {
115 match val {
116 PllQ::Div2 => 0b00,
117 PllQ::Div4 => 0b01,
118 PllQ::Div6 => 0b10,
119 PllQ::Div8 => 0b11,
120 }
121 }
122}
123
124/// Output divider for the PLL R output.
125#[derive(Clone, Copy)]
126pub enum PllR {
127 Div2,
128 Div4,
129 Div6,
130 Div8,
131}
132
133impl PllR {
134 /// Returns the numeric value of the R output divider.
135 pub fn to_div(self) -> u32 {
136 let val: u8 = self.into();
137 (val as u32 + 1) * 2
138 }
139}
140
141impl From<PllR> for u8 {
142 /// Returns the register value for the R output divider.
143 fn from(val: PllR) -> u8 {
144 match val {
145 PllR::Div2 => 0b00,
146 PllR::Div4 => 0b01,
147 PllR::Div6 => 0b10,
148 PllR::Div8 => 0b11,
149 }
150 }
151}
152
153seq_macro::seq!(N in 8..=127 {
154 /// Multiplication factor for the PLL VCO input clock.
155 #[derive(Clone, Copy)]
156 pub enum PllN {
157 #(
158 Mul~N,
159 )*
160 }
161
162 impl From<PllN> for u8 {
163 /// Returns the register value for the N multiplication factor.
164 fn from(val: PllN) -> u8 {
165 match val {
166 #(
167 PllN::Mul~N => N,
168 )*
169 }
170 }
171 }
172
173 impl PllN {
174 /// Returns the numeric value of the N multiplication factor.
175 pub fn to_mul(self) -> u32 {
176 match self {
177 #(
178 PllN::Mul~N => N,
179 )*
180 }
181 }
182 }
183});
184
185/// PLL Pre-division. This must be set such that the PLL input is between 2.66 MHz and 16 MHz.
186#[derive(Copy, Clone)]
187pub enum PllM {
188 Div1,
189 Div2,
190 Div3,
191 Div4,
192 Div5,
193 Div6,
194 Div7,
195 Div8,
196 Div9,
197 Div10,
198 Div11,
199 Div12,
200 Div13,
201 Div14,
202 Div15,
203 Div16,
204}
205
206impl PllM {
207 /// Returns the numeric value of the M pre-division.
208 pub fn to_div(self) -> u32 {
209 let val: u8 = self.into();
210 val as u32 + 1
211 }
212}
213
214impl From<PllM> for u8 {
215 /// Returns the register value for the M pre-division.
216 fn from(val: PllM) -> u8 {
217 match val {
218 PllM::Div1 => 0b0000,
219 PllM::Div2 => 0b0001,
220 PllM::Div3 => 0b0010,
221 PllM::Div4 => 0b0011,
222 PllM::Div5 => 0b0100,
223 PllM::Div6 => 0b0101,
224 PllM::Div7 => 0b0110,
225 PllM::Div8 => 0b0111,
226 PllM::Div9 => 0b1000,
227 PllM::Div10 => 0b1001,
228 PllM::Div11 => 0b1010,
229 PllM::Div12 => 0b1011,
230 PllM::Div13 => 0b1100,
231 PllM::Div14 => 0b1101,
232 PllM::Div15 => 0b1110,
233 PllM::Div16 => 0b1111,
234 }
235 }
236}
237
238/// PLL Configuration
239///
240/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
241/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
242/// frequency ranges for each of these settings.
243pub struct Pll {
244 /// PLL Source clock selection.
245 pub source: PllSrc,
246
247 /// PLL pre-divider
248 pub prediv_m: PllM,
249
250 /// PLL multiplication factor for VCO
251 pub mul_n: PllN,
252
253 /// PLL division factor for P clock (ADC Clock)
254 pub div_p: Option<PllP>,
255
256 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
257 pub div_q: Option<PllQ>,
258
259 /// PLL division factor for R clock (SYSCLK)
260 pub div_r: Option<PllR>,
261}
262
44impl AHBPrescaler { 263impl AHBPrescaler {
45 const fn div(self) -> u32 { 264 const fn div(self) -> u32 {
46 match self { 265 match self {
@@ -104,6 +323,9 @@ pub struct Config {
104 pub apb1_pre: APBPrescaler, 323 pub apb1_pre: APBPrescaler,
105 pub apb2_pre: APBPrescaler, 324 pub apb2_pre: APBPrescaler,
106 pub low_power_run: bool, 325 pub low_power_run: bool,
326 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
327 /// MUST turn on the PLLR output.
328 pub pll: Option<Pll>,
107} 329}
108 330
109impl Default for Config { 331impl Default for Config {
@@ -115,11 +337,80 @@ impl Default for Config {
115 apb1_pre: APBPrescaler::NotDivided, 337 apb1_pre: APBPrescaler::NotDivided,
116 apb2_pre: APBPrescaler::NotDivided, 338 apb2_pre: APBPrescaler::NotDivided,
117 low_power_run: false, 339 low_power_run: false,
340 pll: None,
118 } 341 }
119 } 342 }
120} 343}
121 344
345pub struct PllFreq {
346 pub pll_p: Option<Hertz>,
347 pub pll_q: Option<Hertz>,
348 pub pll_r: Option<Hertz>,
349}
350
122pub(crate) unsafe fn init(config: Config) { 351pub(crate) unsafe fn init(config: Config) {
352 let pll_freq = config.pll.map(|pll_config| {
353 let src_freq = match pll_config.source {
354 PllSrc::HSI16 => {
355 RCC.cr().write(|w| w.set_hsion(true));
356 while !RCC.cr().read().hsirdy() {}
357
358 HSI_FREQ.0
359 }
360 PllSrc::HSE(freq) => {
361 RCC.cr().write(|w| w.set_hseon(true));
362 while !RCC.cr().read().hserdy() {}
363 freq.0
364 }
365 };
366
367 // Disable PLL before configuration
368 RCC.cr().modify(|w| w.set_pllon(false));
369 while RCC.cr().read().pllrdy() {}
370
371 let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul();
372
373 RCC.pllcfgr().write(|w| {
374 w.set_plln(pll_config.mul_n.into());
375 w.set_pllm(pll_config.prediv_m.into());
376 w.set_pllsrc(pll_config.source.into());
377 });
378
379 let pll_p_freq = pll_config.div_p.map(|div_p| {
380 RCC.pllcfgr().modify(|w| {
381 w.set_pllpdiv(div_p.into());
382 w.set_pllpen(true);
383 });
384 Hertz(internal_freq / div_p.to_div())
385 });
386
387 let pll_q_freq = pll_config.div_q.map(|div_q| {
388 RCC.pllcfgr().modify(|w| {
389 w.set_pllq(div_q.into());
390 w.set_pllqen(true);
391 });
392 Hertz(internal_freq / div_q.to_div())
393 });
394
395 let pll_r_freq = pll_config.div_r.map(|div_r| {
396 RCC.pllcfgr().modify(|w| {
397 w.set_pllr(div_r.into());
398 w.set_pllren(true);
399 });
400 Hertz(internal_freq / div_r.to_div())
401 });
402
403 // Enable the PLL
404 RCC.cr().modify(|w| w.set_pllon(true));
405 while !RCC.cr().read().pllrdy() {}
406
407 PllFreq {
408 pll_p: pll_p_freq,
409 pll_q: pll_q_freq,
410 pll_r: pll_r_freq,
411 }
412 });
413
123 let (sys_clk, sw) = match config.mux { 414 let (sys_clk, sw) = match config.mux {
124 ClockSrc::HSI16 => { 415 ClockSrc::HSI16 => {
125 // Enable HSI16 416 // Enable HSI16
@@ -135,6 +426,47 @@ pub(crate) unsafe fn init(config: Config) {
135 426
136 (freq.0, Sw::HSE) 427 (freq.0, Sw::HSE)
137 } 428 }
429 ClockSrc::PLL => {
430 assert!(pll_freq.is_some());
431 assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
432
433 let freq = pll_freq.unwrap().pll_r.unwrap().0;
434
435 assert!(freq <= 170_000_000);
436
437 if freq >= 150_000_000 {
438 // Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234)
439 PWR.cr5().modify(|w| w.set_r1mode(false));
440 // Set flash wait state in boost mode based on frequency ([RM0440] p191)
441 if freq <= 36_000_000 {
442 FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
443 } else if freq <= 68_000_000 {
444 FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
445 } else if freq <= 102_000_000 {
446 FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
447 } else if freq <= 136_000_000 {
448 FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
449 } else {
450 FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
451 }
452 } else {
453 PWR.cr5().modify(|w| w.set_r1mode(true));
454 // Set flash wait state in normal mode based on frequency ([RM0440] p191)
455 if freq <= 30_000_000 {
456 FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
457 } else if freq <= 60_000_000 {
458 FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
459 } else if freq <= 80_000_000 {
460 FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
461 } else if freq <= 120_000_000 {
462 FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
463 } else {
464 FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
465 }
466 }
467
468 (freq, Sw::PLLRCLK)
469 }
138 }; 470 };
139 471
140 RCC.cfgr().modify(|w| { 472 RCC.cfgr().modify(|w| {
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
index 17fbc6056..4025a4e05 100644
--- a/embassy-stm32/src/rcc/h5.rs
+++ b/embassy-stm32/src/rcc/h5.rs
@@ -462,7 +462,7 @@ struct PllOutput {
462 r: Option<Hertz>, 462 r: Option<Hertz>,
463} 463}
464 464
465unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { 465fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
466 let Some(config) = config else { 466 let Some(config) = config else {
467 // Stop PLL 467 // Stop PLL
468 RCC.cr().modify(|w| w.set_pllon(num, false)); 468 RCC.cr().modify(|w| w.set_pllon(num, false));
@@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
595 595
596 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); 596 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
597 597
598 // NOTE(unsafe) Atomic write 598 FLASH.acr().write(|w| {
599 unsafe { 599 w.set_wrhighfreq(wrhighfreq);
600 FLASH.acr().write(|w| { 600 w.set_latency(latency);
601 w.set_wrhighfreq(wrhighfreq); 601 });
602 w.set_latency(latency); 602 while FLASH.acr().read().latency() != latency {}
603 });
604 while FLASH.acr().read().latency() != latency {}
605 }
606} 603}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index 0185f7ae8..daa1cd61f 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -253,14 +253,11 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
253 }, 253 },
254 }; 254 };
255 255
256 // NOTE(unsafe) Atomic write 256 FLASH.acr().write(|w| {
257 unsafe { 257 w.set_wrhighfreq(progr_delay);
258 FLASH.acr().write(|w| { 258 w.set_latency(wait_states)
259 w.set_wrhighfreq(progr_delay); 259 });
260 w.set_latency(wait_states) 260 while FLASH.acr().read().latency() != wait_states {}
261 });
262 while FLASH.acr().read().latency() != wait_states {}
263 }
264} 261}
265 262
266pub enum McoClock { 263pub enum McoClock {
@@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) {
474 // Configure traceclk from PLL if needed 471 // Configure traceclk from PLL if needed
475 traceclk_setup(&mut config, sys_use_pll1_p); 472 traceclk_setup(&mut config, sys_use_pll1_p);
476 473
477 // NOTE(unsafe) We have exclusive access to the RCC
478 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); 474 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
479 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); 475 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
480 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); 476 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
@@ -756,7 +752,7 @@ mod pll {
756 /// # Safety 752 /// # Safety
757 /// 753 ///
758 /// Must have exclusive access to the RCC register block 754 /// Must have exclusive access to the RCC register block
759 unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { 755 fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
760 use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; 756 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
761 757
762 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); 758 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
@@ -785,11 +781,7 @@ mod pll {
785 /// # Safety 781 /// # Safety
786 /// 782 ///
787 /// Must have exclusive access to the RCC register block 783 /// Must have exclusive access to the RCC register block
788 pub(super) unsafe fn pll_setup( 784 pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
789 pll_src: u32,
790 config: &PllConfig,
791 plln: usize,
792 ) -> (Option<u32>, Option<u32>, Option<u32>) {
793 use crate::pac::rcc::vals::Divp; 785 use crate::pac::rcc::vals::Divp;
794 786
795 match config.p_ck { 787 match config.p_ck {
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 1e16b8478..b2faec53d 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -34,40 +34,34 @@ impl<'d, T: Instance> Rng<'d, T> {
34 pub fn reset(&mut self) { 34 pub fn reset(&mut self) {
35 // rng_v2 locks up on seed error, needs reset 35 // rng_v2 locks up on seed error, needs reset
36 #[cfg(rng_v2)] 36 #[cfg(rng_v2)]
37 if unsafe { T::regs().sr().read().seis() } { 37 if T::regs().sr().read().seis() {
38 T::reset(); 38 T::reset();
39 } 39 }
40 unsafe { 40 T::regs().cr().modify(|reg| {
41 T::regs().cr().modify(|reg| { 41 reg.set_rngen(true);
42 reg.set_rngen(true); 42 reg.set_ie(true);
43 reg.set_ie(true); 43 });
44 }); 44 T::regs().sr().modify(|reg| {
45 T::regs().sr().modify(|reg| { 45 reg.set_seis(false);
46 reg.set_seis(false); 46 reg.set_ceis(false);
47 reg.set_ceis(false); 47 });
48 });
49 }
50 // Reference manual says to discard the first. 48 // Reference manual says to discard the first.
51 let _ = self.next_u32(); 49 let _ = self.next_u32();
52 } 50 }
53 51
54 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 52 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
55 unsafe { 53 T::regs().cr().modify(|reg| {
56 T::regs().cr().modify(|reg| { 54 reg.set_rngen(true);
57 reg.set_rngen(true); 55 });
58 })
59 }
60 56
61 for chunk in dest.chunks_mut(4) { 57 for chunk in dest.chunks_mut(4) {
62 poll_fn(|cx| { 58 poll_fn(|cx| {
63 RNG_WAKER.register(cx.waker()); 59 RNG_WAKER.register(cx.waker());
64 unsafe { 60 T::regs().cr().modify(|reg| {
65 T::regs().cr().modify(|reg| { 61 reg.set_ie(true);
66 reg.set_ie(true); 62 });
67 });
68 }
69 63
70 let bits = unsafe { T::regs().sr().read() }; 64 let bits = T::regs().sr().read();
71 65
72 if bits.drdy() { 66 if bits.drdy() {
73 Poll::Ready(Ok(())) 67 Poll::Ready(Ok(()))
@@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> {
82 } 76 }
83 }) 77 })
84 .await?; 78 .await?;
85 let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes(); 79 let random_bytes = T::regs().dr().read().to_be_bytes();
86 for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) { 80 for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
87 *dest = *src 81 *dest = *src
88 } 82 }
@@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> {
95impl<'d, T: Instance> RngCore for Rng<'d, T> { 89impl<'d, T: Instance> RngCore for Rng<'d, T> {
96 fn next_u32(&mut self) -> u32 { 90 fn next_u32(&mut self) -> u32 {
97 loop { 91 loop {
98 let sr = unsafe { T::regs().sr().read() }; 92 let sr = T::regs().sr().read();
99 if sr.seis() | sr.ceis() { 93 if sr.seis() | sr.ceis() {
100 self.reset(); 94 self.reset();
101 } else if sr.drdy() { 95 } else if sr.drdy() {
102 return unsafe { T::regs().dr().read() }; 96 return T::regs().dr().read();
103 } 97 }
104 } 98 }
105 } 99 }
@@ -149,6 +143,7 @@ foreach_peripheral!(
149 }; 143 };
150); 144);
151 145
146#[cfg(feature = "rt")]
152macro_rules! irq { 147macro_rules! irq {
153 ($irq:ident) => { 148 ($irq:ident) => {
154 mod rng_irq { 149 mod rng_irq {
@@ -166,6 +161,7 @@ macro_rules! irq {
166 }; 161 };
167} 162}
168 163
164#[cfg(feature = "rt")]
169foreach_interrupt!( 165foreach_interrupt!(
170 (RNG) => { 166 (RNG) => {
171 irq!(RNG); 167 irq!(RNG);
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index 0a590c1bb..a9c48d88d 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -154,29 +154,27 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
154 let yr_offset = (yr - 1970_u16) as u8; 154 let yr_offset = (yr - 1970_u16) as u8;
155 let (yt, yu) = byte_to_bcd2(yr_offset); 155 let (yt, yu) = byte_to_bcd2(yr_offset);
156 156
157 unsafe { 157 use crate::pac::rtc::vals::Ampm;
158 use crate::pac::rtc::vals::Ampm; 158
159 159 rtc.tr().write(|w| {
160 rtc.tr().write(|w| { 160 w.set_ht(ht);
161 w.set_ht(ht); 161 w.set_hu(hu);
162 w.set_hu(hu); 162 w.set_mnt(mnt);
163 w.set_mnt(mnt); 163 w.set_mnu(mnu);
164 w.set_mnu(mnu); 164 w.set_st(st);
165 w.set_st(st); 165 w.set_su(su);
166 w.set_su(su); 166 w.set_pm(Ampm::AM);
167 w.set_pm(Ampm::AM); 167 });
168 }); 168
169 169 rtc.dr().write(|w| {
170 rtc.dr().write(|w| { 170 w.set_dt(dt);
171 w.set_dt(dt); 171 w.set_du(du);
172 w.set_du(du); 172 w.set_mt(mt > 0);
173 w.set_mt(mt > 0); 173 w.set_mu(mu);
174 w.set_mu(mu); 174 w.set_yt(yt);
175 w.set_yt(yt); 175 w.set_yu(yu);
176 w.set_yu(yu); 176 w.set_wdu(day_of_week_to_u8(t.day_of_week));
177 w.set_wdu(day_of_week_to_u8(t.day_of_week)); 177 });
178 });
179 }
180} 178}
181 179
182pub(super) fn datetime( 180pub(super) fn datetime(
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 962927fb1..12a2ac795 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod {
113 113
114impl<'d, T: Instance> Rtc<'d, T> { 114impl<'d, T: Instance> Rtc<'d, T> {
115 pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self { 115 pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
116 unsafe { T::enable_peripheral_clk() }; 116 T::enable_peripheral_clk();
117 117
118 let mut rtc_struct = Self { 118 let mut rtc_struct = Self {
119 phantom: PhantomData, 119 phantom: PhantomData,
@@ -144,34 +144,32 @@ impl<'d, T: Instance> Rtc<'d, T> {
144 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 144 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
145 pub fn now(&self) -> Result<DateTime, RtcError> { 145 pub fn now(&self) -> Result<DateTime, RtcError> {
146 let r = T::regs(); 146 let r = T::regs();
147 unsafe { 147 let tr = r.tr().read();
148 let tr = r.tr().read(); 148 let second = bcd2_to_byte((tr.st(), tr.su()));
149 let second = bcd2_to_byte((tr.st(), tr.su())); 149 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
150 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 150 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
151 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 151 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
152 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order 152 // calendar shadow registers until RTC_DR is read.
153 // calendar shadow registers until RTC_DR is read. 153 let dr = r.dr().read();
154 let dr = r.dr().read(); 154
155 155 let weekday = dr.wdu();
156 let weekday = dr.wdu(); 156 let day = bcd2_to_byte((dr.dt(), dr.du()));
157 let day = bcd2_to_byte((dr.dt(), dr.du())); 157 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
158 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 158 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
159 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 159
160 160 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
161 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
162 }
163 } 161 }
164 162
165 /// Check if daylight savings time is active. 163 /// Check if daylight savings time is active.
166 pub fn get_daylight_savings(&self) -> bool { 164 pub fn get_daylight_savings(&self) -> bool {
167 let cr = unsafe { T::regs().cr().read() }; 165 let cr = T::regs().cr().read();
168 cr.bkp() 166 cr.bkp()
169 } 167 }
170 168
171 /// Enable/disable daylight savings time. 169 /// Enable/disable daylight savings time.
172 pub fn set_daylight_savings(&mut self, daylight_savings: bool) { 170 pub fn set_daylight_savings(&mut self, daylight_savings: bool) {
173 self.write(true, |rtc| { 171 self.write(true, |rtc| {
174 unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) }; 172 rtc.cr().modify(|w| w.set_bkp(daylight_savings));
175 }) 173 })
176 } 174 }
177 175
@@ -228,7 +226,7 @@ pub(crate) mod sealed {
228 crate::pac::RTC 226 crate::pac::RTC
229 } 227 }
230 228
231 unsafe fn enable_peripheral_clk() {} 229 fn enable_peripheral_clk() {}
232 230
233 /// Read content of the backup register. 231 /// Read content of the backup register.
234 /// 232 ///
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index adaafe67a..e1615b34c 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -8,74 +8,72 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
8 /// It this changes the RTC clock source the time will be reset 8 /// It this changes the RTC clock source the time will be reset
9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { 9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
10 // Unlock the backup domain 10 // Unlock the backup domain
11 unsafe { 11 let clock_config = rtc_config.clock_config as u8;
12 let clock_config = rtc_config.clock_config as u8;
13 12
14 #[cfg(not(rtc_v2wb))] 13 #[cfg(not(rtc_v2wb))]
15 use stm32_metapac::rcc::vals::Rtcsel; 14 use stm32_metapac::rcc::vals::Rtcsel;
16 15
17 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] 16 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
18 let cr = crate::pac::PWR.cr(); 17 let cr = crate::pac::PWR.cr();
19 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] 18 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
20 let cr = crate::pac::PWR.cr1(); 19 let cr = crate::pac::PWR.cr1();
21 20
22 // TODO: Missing from PAC for l0 and f0? 21 // TODO: Missing from PAC for l0 and f0?
23 #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] 22 #[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
24 { 23 {
25 cr.modify(|w| w.set_dbp(true)); 24 cr.modify(|w| w.set_dbp(true));
26 while !cr.read().dbp() {} 25 while !cr.read().dbp() {}
27 } 26 }
28 27
29 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 28 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
30 let reg = crate::pac::RCC.bdcr().read(); 29 let reg = crate::pac::RCC.bdcr().read();
31 #[cfg(any(rtc_v2l0, rtc_v2l1))] 30 #[cfg(any(rtc_v2l0, rtc_v2l1))]
32 let reg = crate::pac::RCC.csr().read(); 31 let reg = crate::pac::RCC.csr().read();
33 32
34 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] 33 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
35 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 34 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
36 35
37 #[cfg(rtc_v2wb)] 36 #[cfg(rtc_v2wb)]
38 let rtcsel = reg.rtcsel(); 37 let rtcsel = reg.rtcsel();
39 #[cfg(not(rtc_v2wb))] 38 #[cfg(not(rtc_v2wb))]
40 let rtcsel = reg.rtcsel().0; 39 let rtcsel = reg.rtcsel().0;
41 40
42 if !reg.rtcen() || rtcsel != clock_config { 41 if !reg.rtcen() || rtcsel != clock_config {
43 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 42 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
44 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); 43 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
45 44
45 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
46 let cr = crate::pac::RCC.bdcr();
47 #[cfg(any(rtc_v2l0, rtc_v2l1))]
48 let cr = crate::pac::RCC.csr();
49
50 cr.modify(|w| {
51 // Reset
46 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 52 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
47 let cr = crate::pac::RCC.bdcr(); 53 w.set_bdrst(false);
48 #[cfg(any(rtc_v2l0, rtc_v2l1))] 54
49 let cr = crate::pac::RCC.csr(); 55 // Select RTC source
50 56 #[cfg(not(rtc_v2wb))]
51 cr.modify(|w| { 57 w.set_rtcsel(Rtcsel(clock_config));
52 // Reset 58 #[cfg(rtc_v2wb)]
53 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 59 w.set_rtcsel(clock_config);
54 w.set_bdrst(false); 60 w.set_rtcen(true);
55 61
56 // Select RTC source 62 // Restore bcdr
57 #[cfg(not(rtc_v2wb))] 63 #[cfg(any(rtc_v2l4, rtc_v2wb))]
58 w.set_rtcsel(Rtcsel(clock_config)); 64 w.set_lscosel(reg.lscosel());
59 #[cfg(rtc_v2wb)] 65 #[cfg(any(rtc_v2l4, rtc_v2wb))]
60 w.set_rtcsel(clock_config); 66 w.set_lscoen(reg.lscoen());
61 w.set_rtcen(true); 67
62 68 w.set_lseon(reg.lseon());
63 // Restore bcdr 69
64 #[cfg(any(rtc_v2l4, rtc_v2wb))] 70 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
65 w.set_lscosel(reg.lscosel()); 71 w.set_lsedrv(reg.lsedrv());
66 #[cfg(any(rtc_v2l4, rtc_v2wb))] 72 w.set_lsebyp(reg.lsebyp());
67 w.set_lscoen(reg.lscoen()); 73 });
68
69 w.set_lseon(reg.lseon());
70
71 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
72 w.set_lsedrv(reg.lsedrv());
73 w.set_lsebyp(reg.lsebyp());
74 });
75 }
76 } 74 }
77 75
78 self.write(true, |rtc| unsafe { 76 self.write(true, |rtc| {
79 rtc.cr().modify(|w| { 77 rtc.cr().modify(|w| {
80 #[cfg(rtc_v2f2)] 78 #[cfg(rtc_v2f2)]
81 w.set_fmt(false); 79 w.set_fmt(false);
@@ -117,47 +115,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
117 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; 115 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM;
118 116
119 self.write(false, |rtc| { 117 self.write(false, |rtc| {
120 unsafe { 118 rtc.calr().write(|w| {
121 rtc.calr().write(|w| { 119 match period {
122 match period { 120 super::RtcCalibrationCyclePeriod::Seconds8 => {
123 super::RtcCalibrationCyclePeriod::Seconds8 => { 121 w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
124 w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
125 }
126 super::RtcCalibrationCyclePeriod::Seconds16 => {
127 w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
128 }
129 super::RtcCalibrationCyclePeriod::Seconds32 => {
130 // Set neither `calw8` nor `calw16` to use 32 seconds
131 }
132 } 122 }
133 123 super::RtcCalibrationCyclePeriod::Seconds16 => {
134 // Extra pulses during calibration cycle period: CALP * 512 - CALM 124 w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
135 // 125 }
136 // CALP sets whether pulses are added or omitted. 126 super::RtcCalibrationCyclePeriod::Seconds32 => {
137 // 127 // Set neither `calw8` nor `calw16` to use 32 seconds
138 // CALM contains how many pulses (out of 512) are masked in a
139 // given calibration cycle period.
140 if clock_drift > 0.0 {
141 // Maximum (about 512.2) rounds to 512.
142 clock_drift += 0.5;
143
144 // When the offset is positive (0 to 512), the opposite of
145 // the offset (512 - offset) is masked, i.e. for the
146 // maximum offset (512), 0 pulses are masked.
147 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
148 w.set_calm(512 - clock_drift as u16);
149 } else {
150 // Minimum (about -510.7) rounds to -511.
151 clock_drift -= 0.5;
152
153 // When the offset is negative or zero (-511 to 0),
154 // the absolute offset is masked, i.e. for the minimum
155 // offset (-511), 511 pulses are masked.
156 w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
157 w.set_calm((clock_drift * -1.0) as u16);
158 } 128 }
159 }); 129 }
160 } 130
131 // Extra pulses during calibration cycle period: CALP * 512 - CALM
132 //
133 // CALP sets whether pulses are added or omitted.
134 //
135 // CALM contains how many pulses (out of 512) are masked in a
136 // given calibration cycle period.
137 if clock_drift > 0.0 {
138 // Maximum (about 512.2) rounds to 512.
139 clock_drift += 0.5;
140
141 // When the offset is positive (0 to 512), the opposite of
142 // the offset (512 - offset) is masked, i.e. for the
143 // maximum offset (512), 0 pulses are masked.
144 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
145 w.set_calm(512 - clock_drift as u16);
146 } else {
147 // Minimum (about -510.7) rounds to -511.
148 clock_drift -= 0.5;
149
150 // When the offset is negative or zero (-511 to 0),
151 // the absolute offset is masked, i.e. for the minimum
152 // offset (-511), 511 pulses are masked.
153 w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
154 w.set_calm((clock_drift * -1.0) as u16);
155 }
156 });
161 }) 157 })
162 } 158 }
163 159
@@ -168,31 +164,27 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
168 let r = T::regs(); 164 let r = T::regs();
169 // Disable write protection. 165 // Disable write protection.
170 // This is safe, as we're only writin the correct and expected values. 166 // This is safe, as we're only writin the correct and expected values.
171 unsafe { 167 r.wpr().write(|w| w.set_key(0xca));
172 r.wpr().write(|w| w.set_key(0xca)); 168 r.wpr().write(|w| w.set_key(0x53));
173 r.wpr().write(|w| w.set_key(0x53)); 169
174 170 // true if initf bit indicates RTC peripheral is in init mode
175 // true if initf bit indicates RTC peripheral is in init mode 171 if init_mode && !r.isr().read().initf() {
176 if init_mode && !r.isr().read().initf() { 172 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
177 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode 173 r.isr().modify(|w| w.set_init(Init::INITMODE));
178 r.isr().modify(|w| w.set_init(Init::INITMODE)); 174 // wait till init state entered
179 // wait till init state entered 175 // ~2 RTCCLK cycles
180 // ~2 RTCCLK cycles 176 while !r.isr().read().initf() {}
181 while !r.isr().read().initf() {}
182 }
183 } 177 }
184 178
185 let result = f(&r); 179 let result = f(&r);
186 180
187 unsafe { 181 if init_mode {
188 if init_mode { 182 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
189 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
190 }
191
192 // Re-enable write protection.
193 // This is safe, as the field accepts the full range of 8-bit values.
194 r.wpr().write(|w| w.set_key(0xff));
195 } 183 }
184
185 // Re-enable write protection.
186 // This is safe, as the field accepts the full range of 8-bit values.
187 r.wpr().write(|w| w.set_key(0xff));
196 result 188 result
197 } 189 }
198} 190}
@@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
200impl sealed::Instance for crate::peripherals::RTC { 192impl sealed::Instance for crate::peripherals::RTC {
201 const BACKUP_REGISTER_COUNT: usize = 20; 193 const BACKUP_REGISTER_COUNT: usize = 20;
202 194
203 unsafe fn enable_peripheral_clk() { 195 fn enable_peripheral_clk() {
204 #[cfg(any(rtc_v2l4, rtc_v2wb))] 196 #[cfg(any(rtc_v2l4, rtc_v2wb))]
205 { 197 {
206 // enable peripheral clock for communication 198 // enable peripheral clock for communication
@@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC {
213 205
214 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { 206 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
215 if register < Self::BACKUP_REGISTER_COUNT { 207 if register < Self::BACKUP_REGISTER_COUNT {
216 Some(unsafe { rtc.bkpr(register).read().bkp() }) 208 Some(rtc.bkpr(register).read().bkp())
217 } else { 209 } else {
218 None 210 None
219 } 211 }
@@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC {
221 213
222 fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { 214 fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
223 if register < Self::BACKUP_REGISTER_COUNT { 215 if register < Self::BACKUP_REGISTER_COUNT {
224 unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } 216 rtc.bkpr(register).write(|w| w.set_bkp(value));
225 } 217 }
226 } 218 }
227} 219}
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 546fe88c7..7c91046a2 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -8,75 +8,66 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
8 /// It this changes the RTC clock source the time will be reset 8 /// It this changes the RTC clock source the time will be reset
9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { 9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
10 // Unlock the backup domain 10 // Unlock the backup domain
11 unsafe { 11 #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
12 #[cfg(any(rtc_v3u5, rcc_g0, rcc_g4))] 12 {
13 use crate::pac::rcc::vals::Rtcsel; 13 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
14 #[cfg(not(any(rtc_v3u5, rcc_g0, rcc_g4, rcc_wl5, rcc_wle)))] 14 while !crate::pac::PWR.cr1().read().dbp() {}
15 use crate::pac::rtc::vals::Rtcsel; 15 }
16 16 #[cfg(any(rcc_wl5, rcc_wle))]
17 #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] 17 {
18 { 18 use crate::pac::pwr::vals::Dbp;
19 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); 19
20 while !crate::pac::PWR.cr1().read().dbp() {} 20 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
21 } 21 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
22 #[cfg(any(rcc_wl5, rcc_wle))] 22 }
23 { 23
24 use crate::pac::pwr::vals::Dbp; 24 let reg = crate::pac::RCC.bdcr().read();
25 25 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
26 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); 26
27 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} 27 let config_rtcsel = rtc_config.clock_config as u8;
28 } 28 #[cfg(not(any(rcc_wl5, rcc_wle)))]
29 29 let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel);
30 let reg = crate::pac::RCC.bdcr().read(); 30
31 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 31 if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
32 32 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
33 let config_rtcsel = rtc_config.clock_config as u8; 33
34 #[cfg(not(any(rcc_wl5, rcc_wle)))] 34 crate::pac::RCC.bdcr().modify(|w| {
35 let config_rtcsel = Rtcsel(config_rtcsel); 35 // Reset
36 36 w.set_bdrst(false);
37 if !reg.rtcen() || reg.rtcsel() != config_rtcsel { 37
38 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); 38 // Select RTC source
39 39 w.set_rtcsel(config_rtcsel);
40 crate::pac::RCC.bdcr().modify(|w| { 40
41 // Reset 41 w.set_rtcen(true);
42 w.set_bdrst(false); 42
43 43 // Restore bcdr
44 // Select RTC source 44 w.set_lscosel(reg.lscosel());
45 w.set_rtcsel(config_rtcsel); 45 w.set_lscoen(reg.lscoen());
46 46
47 w.set_rtcen(true); 47 w.set_lseon(reg.lseon());
48 48 w.set_lsedrv(reg.lsedrv());
49 // Restore bcdr 49 w.set_lsebyp(reg.lsebyp());
50 w.set_lscosel(reg.lscosel()); 50 });
51 w.set_lscoen(reg.lscoen());
52
53 w.set_lseon(reg.lseon());
54 w.set_lsedrv(reg.lsedrv());
55 w.set_lsebyp(reg.lsebyp());
56 });
57 }
58 } 51 }
59 52
60 self.write(true, |rtc| { 53 self.write(true, |rtc| {
61 unsafe { 54 rtc.cr().modify(|w| {
62 rtc.cr().modify(|w| { 55 w.set_fmt(Fmt::TWENTYFOURHOUR);
63 w.set_fmt(Fmt::TWENTYFOURHOUR); 56 w.set_osel(Osel::DISABLED);
64 w.set_osel(Osel::DISABLED); 57 w.set_pol(Pol::HIGH);
65 w.set_pol(Pol::HIGH); 58 });
66 }); 59
67 60 rtc.prer().modify(|w| {
68 rtc.prer().modify(|w| { 61 w.set_prediv_s(rtc_config.sync_prescaler);
69 w.set_prediv_s(rtc_config.sync_prescaler); 62 w.set_prediv_a(rtc_config.async_prescaler);
70 w.set_prediv_a(rtc_config.async_prescaler); 63 });
71 }); 64
72 65 // TODO: configuration for output pins
73 // TODO: configuration for output pins 66 rtc.cr().modify(|w| {
74 rtc.cr().modify(|w| { 67 w.set_out2en(false);
75 w.set_out2en(false); 68 w.set_tampalrm_type(TampalrmType::PUSHPULL);
76 w.set_tampalrm_type(TampalrmType::PUSHPULL); 69 w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
77 w.set_tampalrm_pu(TampalrmPu::NOPULLUP); 70 });
78 });
79 }
80 }); 71 });
81 72
82 self.rtc_config = rtc_config; 73 self.rtc_config = rtc_config;
@@ -104,47 +95,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
104 clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM; 95 clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM;
105 96
106 self.write(false, |rtc| { 97 self.write(false, |rtc| {
107 unsafe { 98 rtc.calr().write(|w| {
108 rtc.calr().write(|w| { 99 match period {
109 match period { 100 RtcCalibrationCyclePeriod::Seconds8 => {
110 RtcCalibrationCyclePeriod::Seconds8 => { 101 w.set_calw8(Calw8::EIGHTSECONDS);
111 w.set_calw8(Calw8::EIGHTSECONDS);
112 }
113 RtcCalibrationCyclePeriod::Seconds16 => {
114 w.set_calw16(Calw16::SIXTEENSECONDS);
115 }
116 RtcCalibrationCyclePeriod::Seconds32 => {
117 // Set neither `calw8` nor `calw16` to use 32 seconds
118 }
119 } 102 }
120 103 RtcCalibrationCyclePeriod::Seconds16 => {
121 // Extra pulses during calibration cycle period: CALP * 512 - CALM 104 w.set_calw16(Calw16::SIXTEENSECONDS);
122 //
123 // CALP sets whether pulses are added or omitted.
124 //
125 // CALM contains how many pulses (out of 512) are masked in a
126 // given calibration cycle period.
127 if clock_drift > 0.0 {
128 // Maximum (about 512.2) rounds to 512.
129 clock_drift += 0.5;
130
131 // When the offset is positive (0 to 512), the opposite of
132 // the offset (512 - offset) is masked, i.e. for the
133 // maximum offset (512), 0 pulses are masked.
134 w.set_calp(Calp::INCREASEFREQ);
135 w.set_calm(512 - clock_drift as u16);
136 } else {
137 // Minimum (about -510.7) rounds to -511.
138 clock_drift -= 0.5;
139
140 // When the offset is negative or zero (-511 to 0),
141 // the absolute offset is masked, i.e. for the minimum
142 // offset (-511), 511 pulses are masked.
143 w.set_calp(Calp::NOCHANGE);
144 w.set_calm((clock_drift * -1.0) as u16);
145 } 105 }
146 }); 106 RtcCalibrationCyclePeriod::Seconds32 => {
147 } 107 // Set neither `calw8` nor `calw16` to use 32 seconds
108 }
109 }
110
111 // Extra pulses during calibration cycle period: CALP * 512 - CALM
112 //
113 // CALP sets whether pulses are added or omitted.
114 //
115 // CALM contains how many pulses (out of 512) are masked in a
116 // given calibration cycle period.
117 if clock_drift > 0.0 {
118 // Maximum (about 512.2) rounds to 512.
119 clock_drift += 0.5;
120
121 // When the offset is positive (0 to 512), the opposite of
122 // the offset (512 - offset) is masked, i.e. for the
123 // maximum offset (512), 0 pulses are masked.
124 w.set_calp(Calp::INCREASEFREQ);
125 w.set_calm(512 - clock_drift as u16);
126 } else {
127 // Minimum (about -510.7) rounds to -511.
128 clock_drift -= 0.5;
129
130 // When the offset is negative or zero (-511 to 0),
131 // the absolute offset is masked, i.e. for the minimum
132 // offset (-511), 511 pulses are masked.
133 w.set_calp(Calp::NOCHANGE);
134 w.set_calm((clock_drift * -1.0) as u16);
135 }
136 });
148 }) 137 })
149 } 138 }
150 139
@@ -155,29 +144,26 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
155 let r = T::regs(); 144 let r = T::regs();
156 // Disable write protection. 145 // Disable write protection.
157 // This is safe, as we're only writin the correct and expected values. 146 // This is safe, as we're only writin the correct and expected values.
158 unsafe { 147 r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
159 r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); 148 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
160 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); 149
161 150 if init_mode && !r.icsr().read().initf() {
162 if init_mode && !r.icsr().read().initf() { 151 r.icsr().modify(|w| w.set_init(Init::INITMODE));
163 r.icsr().modify(|w| w.set_init(Init::INITMODE)); 152 // wait till init state entered
164 // wait till init state entered 153 // ~2 RTCCLK cycles
165 // ~2 RTCCLK cycles 154 while !r.icsr().read().initf() {}
166 while !r.icsr().read().initf() {}
167 }
168 } 155 }
169 156
170 let result = f(&r); 157 let result = f(&r);
171 158
172 unsafe { 159 if init_mode {
173 if init_mode { 160 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
174 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
175 }
176
177 // Re-enable write protection.
178 // This is safe, as the field accepts the full range of 8-bit values.
179 r.wpr().write(|w| w.set_key(Key::ACTIVATE));
180 } 161 }
162
163 // Re-enable write protection.
164 // This is safe, as the field accepts the full range of 8-bit values.
165 r.wpr().write(|w| w.set_key(Key::ACTIVATE));
166
181 result 167 result
182 } 168 }
183} 169}
@@ -197,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC {
197 fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { 183 fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
198 if register < Self::BACKUP_REGISTER_COUNT { 184 if register < Self::BACKUP_REGISTER_COUNT {
199 // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC 185 // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
200 //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } 186 //self.rtc.bkpr()[register].write(|w| w.bits(value))
201 } 187 }
202 } 188 }
203} 189}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index be03a1bac..80a336a48 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -14,7 +14,7 @@ use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID,
14use crate::dma::NoDma; 14use crate::dma::NoDma;
15use crate::gpio::sealed::{AFType, Pin}; 15use crate::gpio::sealed::{AFType, Pin};
16use crate::gpio::{AnyPin, Pull, Speed}; 16use crate::gpio::{AnyPin, Pull, Speed};
17use crate::interrupt::{Interrupt, InterruptExt}; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::sdmmc::Sdmmc as RegBlock; 18use crate::pac::sdmmc::Sdmmc as RegBlock;
19use crate::rcc::RccPeripheral; 19use crate::rcc::RccPeripheral;
20use crate::time::Hertz; 20use crate::time::Hertz;
@@ -28,21 +28,18 @@ pub struct InterruptHandler<T: Instance> {
28impl<T: Instance> InterruptHandler<T> { 28impl<T: Instance> InterruptHandler<T> {
29 fn data_interrupts(enable: bool) { 29 fn data_interrupts(enable: bool) {
30 let regs = T::regs(); 30 let regs = T::regs();
31 // NOTE(unsafe) Atomic write 31 regs.maskr().write(|w| {
32 unsafe { 32 w.set_dcrcfailie(enable);
33 regs.maskr().write(|w| { 33 w.set_dtimeoutie(enable);
34 w.set_dcrcfailie(enable); 34 w.set_dataendie(enable);
35 w.set_dtimeoutie(enable);
36 w.set_dataendie(enable);
37 35
38 #[cfg(sdmmc_v2)] 36 #[cfg(sdmmc_v2)]
39 w.set_dabortie(enable); 37 w.set_dabortie(enable);
40 }); 38 });
41 }
42 } 39 }
43} 40}
44 41
45impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 42impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
46 unsafe fn on_interrupt() { 43 unsafe fn on_interrupt() {
47 Self::data_interrupts(false); 44 Self::data_interrupts(false);
48 T::state().wake(); 45 T::state().wake();
@@ -276,7 +273,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
276impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { 273impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
277 pub fn new_1bit( 274 pub fn new_1bit(
278 sdmmc: impl Peripheral<P = T> + 'd, 275 sdmmc: impl Peripheral<P = T> + 'd,
279 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 276 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
280 dma: impl Peripheral<P = Dma> + 'd, 277 dma: impl Peripheral<P = Dma> + 'd,
281 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 278 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
282 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 279 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
285 ) -> Self { 282 ) -> Self {
286 into_ref!(clk, cmd, d0); 283 into_ref!(clk, cmd, d0);
287 284
288 critical_section::with(|_| unsafe { 285 critical_section::with(|_| {
289 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 286 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
290 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 287 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
291 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 288 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -310,7 +307,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
310 307
311 pub fn new_4bit( 308 pub fn new_4bit(
312 sdmmc: impl Peripheral<P = T> + 'd, 309 sdmmc: impl Peripheral<P = T> + 'd,
313 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 310 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
314 dma: impl Peripheral<P = Dma> + 'd, 311 dma: impl Peripheral<P = Dma> + 'd,
315 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 312 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
316 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 313 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
322 ) -> Self { 319 ) -> Self {
323 into_ref!(clk, cmd, d0, d1, d2, d3); 320 into_ref!(clk, cmd, d0, d1, d2, d3);
324 321
325 critical_section::with(|_| unsafe { 322 critical_section::with(|_| {
326 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 323 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
327 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 324 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
328 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 325 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -356,7 +353,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
356impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 353impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
357 pub fn new_1bit( 354 pub fn new_1bit(
358 sdmmc: impl Peripheral<P = T> + 'd, 355 sdmmc: impl Peripheral<P = T> + 'd,
359 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 356 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
360 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 357 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
361 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 358 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
362 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 359 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
364 ) -> Self { 361 ) -> Self {
365 into_ref!(clk, cmd, d0); 362 into_ref!(clk, cmd, d0);
366 363
367 critical_section::with(|_| unsafe { 364 critical_section::with(|_| {
368 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 365 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
369 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 366 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
370 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 367 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -389,7 +386,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
389 386
390 pub fn new_4bit( 387 pub fn new_4bit(
391 sdmmc: impl Peripheral<P = T> + 'd, 388 sdmmc: impl Peripheral<P = T> + 'd,
392 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 389 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
393 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 390 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
394 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 391 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
395 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 392 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
400 ) -> Self { 397 ) -> Self {
401 into_ref!(clk, cmd, d0, d1, d2, d3); 398 into_ref!(clk, cmd, d0, d1, d2, d3);
402 399
403 critical_section::with(|_| unsafe { 400 critical_section::with(|_| {
404 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 401 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
405 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 402 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
406 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 403 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -447,30 +444,28 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
447 T::enable(); 444 T::enable();
448 T::reset(); 445 T::reset();
449 446
450 unsafe { T::Interrupt::steal() }.unpend(); 447 T::Interrupt::unpend();
451 unsafe { T::Interrupt::steal() }.enable(); 448 unsafe { T::Interrupt::enable() };
452 449
453 let regs = T::regs(); 450 let regs = T::regs();
454 unsafe { 451 regs.clkcr().write(|w| {
455 regs.clkcr().write(|w| { 452 w.set_pwrsav(false);
456 w.set_pwrsav(false); 453 w.set_negedge(false);
457 w.set_negedge(false);
458
459 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
460 // See chip erratas for more details.
461 #[cfg(sdmmc_v1)]
462 w.set_hwfc_en(false);
463 #[cfg(sdmmc_v2)]
464 w.set_hwfc_en(true);
465 454
466 #[cfg(sdmmc_v1)] 455 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
467 w.set_clken(true); 456 // See chip erratas for more details.
468 }); 457 #[cfg(sdmmc_v1)]
458 w.set_hwfc_en(false);
459 #[cfg(sdmmc_v2)]
460 w.set_hwfc_en(true);
469 461
470 // Power off, writen 00: Clock to the card is stopped; 462 #[cfg(sdmmc_v1)]
471 // D[7:0], CMD, and CK are driven high. 463 w.set_clken(true);
472 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); 464 });
473 } 465
466 // Power off, writen 00: Clock to the card is stopped;
467 // D[7:0], CMD, and CK are driven high.
468 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
474 469
475 Self { 470 Self {
476 _peri: sdmmc, 471 _peri: sdmmc,
@@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
495 fn data_active() -> bool { 490 fn data_active() -> bool {
496 let regs = T::regs(); 491 let regs = T::regs();
497 492
498 // NOTE(unsafe) Atomic read with no side-effects 493 let status = regs.star().read();
499 unsafe { 494 #[cfg(sdmmc_v1)]
500 let status = regs.star().read(); 495 return status.rxact() || status.txact();
501 #[cfg(sdmmc_v1)] 496 #[cfg(sdmmc_v2)]
502 return status.rxact() || status.txact(); 497 return status.dpsmact();
503 #[cfg(sdmmc_v2)]
504 return status.dpsmact();
505 }
506 } 498 }
507 499
508 /// Coammand transfer is in progress 500 /// Coammand transfer is in progress
@@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
510 fn cmd_active() -> bool { 502 fn cmd_active() -> bool {
511 let regs = T::regs(); 503 let regs = T::regs();
512 504
513 // NOTE(unsafe) Atomic read with no side-effects 505 let status = regs.star().read();
514 unsafe { 506 #[cfg(sdmmc_v1)]
515 let status = regs.star().read(); 507 return status.cmdact();
516 #[cfg(sdmmc_v1)] 508 #[cfg(sdmmc_v2)]
517 return status.cmdact(); 509 return status.cpsmact();
518 #[cfg(sdmmc_v2)]
519 return status.cpsmact();
520 }
521 } 510 }
522 511
523 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 512 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
@@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
542 Self::wait_idle(); 531 Self::wait_idle();
543 Self::clear_interrupt_flags(); 532 Self::clear_interrupt_flags();
544 533
545 // NOTE(unsafe) We have exclusive access to the regisers 534 regs.dtimer()
546 unsafe { 535 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
547 regs.dtimer() 536 regs.dlenr().write(|w| w.set_datalength(length_bytes));
548 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
549 regs.dlenr().write(|w| w.set_datalength(length_bytes));
550 537
551 #[cfg(sdmmc_v1)] 538 #[cfg(sdmmc_v1)]
552 let transfer = { 539 let transfer = unsafe {
553 let request = self.dma.request(); 540 let request = self.dma.request();
554 Transfer::new_read( 541 Transfer::new_read(
555 &mut self.dma, 542 &mut self.dma,
556 request, 543 request,
557 regs.fifor().ptr() as *mut u32, 544 regs.fifor().as_ptr() as *mut u32,
558 buffer, 545 buffer,
559 DMA_TRANSFER_OPTIONS, 546 DMA_TRANSFER_OPTIONS,
560 ) 547 )
561 }; 548 };
562 #[cfg(sdmmc_v2)] 549 #[cfg(sdmmc_v2)]
563 let transfer = { 550 let transfer = {
564 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); 551 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
565 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 552 regs.idmactrlr().modify(|w| w.set_idmaen(true));
566 Transfer { 553 Transfer {
567 _dummy: core::marker::PhantomData, 554 _dummy: core::marker::PhantomData,
568 } 555 }
569 }; 556 };
570 557
571 regs.dctrl().modify(|w| { 558 regs.dctrl().modify(|w| {
572 w.set_dblocksize(block_size); 559 w.set_dblocksize(block_size);
573 w.set_dtdir(true); 560 w.set_dtdir(true);
574 #[cfg(sdmmc_v1)] 561 #[cfg(sdmmc_v1)]
575 { 562 {
576 w.set_dmaen(true); 563 w.set_dmaen(true);
577 w.set_dten(true); 564 w.set_dten(true);
578 } 565 }
579 }); 566 });
580 567
581 transfer 568 transfer
582 }
583 } 569 }
584 570
585 /// # Safety 571 /// # Safety
@@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
598 Self::wait_idle(); 584 Self::wait_idle();
599 Self::clear_interrupt_flags(); 585 Self::clear_interrupt_flags();
600 586
601 // NOTE(unsafe) We have exclusive access to the regisers 587 regs.dtimer()
602 unsafe { 588 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
603 regs.dtimer() 589 regs.dlenr().write(|w| w.set_datalength(length_bytes));
604 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
605 regs.dlenr().write(|w| w.set_datalength(length_bytes));
606 590
607 #[cfg(sdmmc_v1)] 591 #[cfg(sdmmc_v1)]
608 let transfer = { 592 let transfer = unsafe {
609 let request = self.dma.request(); 593 let request = self.dma.request();
610 Transfer::new_write( 594 Transfer::new_write(
611 &mut self.dma, 595 &mut self.dma,
612 request, 596 request,
613 buffer, 597 buffer,
614 regs.fifor().ptr() as *mut u32, 598 regs.fifor().as_ptr() as *mut u32,
615 DMA_TRANSFER_OPTIONS, 599 DMA_TRANSFER_OPTIONS,
616 ) 600 )
617 }; 601 };
618 #[cfg(sdmmc_v2)] 602 #[cfg(sdmmc_v2)]
619 let transfer = { 603 let transfer = {
620 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); 604 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
621 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 605 regs.idmactrlr().modify(|w| w.set_idmaen(true));
622 Transfer { 606 Transfer {
623 _dummy: core::marker::PhantomData, 607 _dummy: core::marker::PhantomData,
624 } 608 }
625 }; 609 };
626 610
627 regs.dctrl().modify(|w| { 611 regs.dctrl().modify(|w| {
628 w.set_dblocksize(block_size); 612 w.set_dblocksize(block_size);
629 w.set_dtdir(false); 613 w.set_dtdir(false);
630 #[cfg(sdmmc_v1)] 614 #[cfg(sdmmc_v1)]
631 { 615 {
632 w.set_dmaen(true); 616 w.set_dmaen(true);
633 w.set_dten(true); 617 w.set_dten(true);
634 } 618 }
635 }); 619 });
636 620
637 transfer 621 transfer
638 }
639 } 622 }
640 623
641 /// Stops the DMA datapath 624 /// Stops the DMA datapath
642 fn stop_datapath() { 625 fn stop_datapath() {
643 let regs = T::regs(); 626 let regs = T::regs();
644 627
645 unsafe { 628 #[cfg(sdmmc_v1)]
646 #[cfg(sdmmc_v1)] 629 regs.dctrl().modify(|w| {
647 regs.dctrl().modify(|w| { 630 w.set_dmaen(false);
648 w.set_dmaen(false); 631 w.set_dten(false);
649 w.set_dten(false); 632 });
650 }); 633 #[cfg(sdmmc_v2)]
651 #[cfg(sdmmc_v2)] 634 regs.idmactrlr().modify(|w| w.set_idmaen(false));
652 regs.idmactrlr().modify(|w| w.set_idmaen(false));
653 }
654 } 635 }
655 636
656 /// Sets the CLKDIV field in CLKCR. Updates clock field in self 637 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
@@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
673 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); 654 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
674 self.clock = new_clock; 655 self.clock = new_clock;
675 656
676 // NOTE(unsafe) We have exclusive access to the regblock 657 // CPSMACT and DPSMACT must be 0 to set CLKDIV
677 unsafe { 658 Self::wait_idle();
678 // CPSMACT and DPSMACT must be 0 to set CLKDIV 659 regs.clkcr().modify(|w| {
679 Self::wait_idle(); 660 w.set_clkdiv(clkdiv);
680 regs.clkcr().modify(|w| { 661 #[cfg(sdmmc_v1)]
681 w.set_clkdiv(clkdiv); 662 w.set_bypass(_bypass);
682 #[cfg(sdmmc_v1)] 663 });
683 w.set_bypass(_bypass);
684 });
685 }
686 664
687 Ok(()) 665 Ok(())
688 } 666 }
@@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
710 688
711 // Arm `OnDrop` after the buffer, so it will be dropped first 689 // Arm `OnDrop` after the buffer, so it will be dropped first
712 let regs = T::regs(); 690 let regs = T::regs();
713 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 691 let on_drop = OnDrop::new(|| Self::on_drop());
714 692
715 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 693 let transfer = self.prepare_datapath_read(&mut status, 64, 6);
716 InterruptHandler::<T>::data_interrupts(true); 694 InterruptHandler::<T>::data_interrupts(true);
@@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
718 696
719 let res = poll_fn(|cx| { 697 let res = poll_fn(|cx| {
720 T::state().register(cx.waker()); 698 T::state().register(cx.waker());
721 let status = unsafe { regs.star().read() }; 699 let status = regs.star().read();
722 700
723 if status.dcrcfail() { 701 if status.dcrcfail() {
724 return Poll::Ready(Err(Error::Crc)); 702 return Poll::Ready(Err(Error::Crc));
@@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
769 747
770 Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 748 Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
771 749
772 // NOTE(unsafe) Atomic read with no side-effects 750 let r1 = regs.respr(0).read().cardstatus();
773 let r1 = unsafe { regs.respr(0).read().cardstatus() };
774 Ok(r1.into()) 751 Ok(r1.into())
775 } 752 }
776 753
@@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
786 763
787 // Arm `OnDrop` after the buffer, so it will be dropped first 764 // Arm `OnDrop` after the buffer, so it will be dropped first
788 let regs = T::regs(); 765 let regs = T::regs();
789 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 766 let on_drop = OnDrop::new(|| Self::on_drop());
790 767
791 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 768 let transfer = self.prepare_datapath_read(&mut status, 64, 6);
792 InterruptHandler::<T>::data_interrupts(true); 769 InterruptHandler::<T>::data_interrupts(true);
@@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
794 771
795 let res = poll_fn(|cx| { 772 let res = poll_fn(|cx| {
796 T::state().register(cx.waker()); 773 T::state().register(cx.waker());
797 let status = unsafe { regs.star().read() }; 774 let status = regs.star().read();
798 775
799 if status.dcrcfail() { 776 if status.dcrcfail() {
800 return Poll::Ready(Err(Error::Crc)); 777 return Poll::Ready(Err(Error::Crc));
@@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
840 #[inline(always)] 817 #[inline(always)]
841 fn clear_interrupt_flags() { 818 fn clear_interrupt_flags() {
842 let regs = T::regs(); 819 let regs = T::regs();
843 // NOTE(unsafe) Atomic write 820 regs.icr().write(|w| {
844 unsafe { 821 w.set_ccrcfailc(true);
845 regs.icr().write(|w| { 822 w.set_dcrcfailc(true);
846 w.set_ccrcfailc(true); 823 w.set_ctimeoutc(true);
847 w.set_dcrcfailc(true); 824 w.set_dtimeoutc(true);
848 w.set_ctimeoutc(true); 825 w.set_txunderrc(true);
849 w.set_dtimeoutc(true); 826 w.set_rxoverrc(true);
850 w.set_txunderrc(true); 827 w.set_cmdrendc(true);
851 w.set_rxoverrc(true); 828 w.set_cmdsentc(true);
852 w.set_cmdrendc(true); 829 w.set_dataendc(true);
853 w.set_cmdsentc(true); 830 w.set_dbckendc(true);
854 w.set_dataendc(true); 831 w.set_sdioitc(true);
855 w.set_dbckendc(true);
856 w.set_sdioitc(true);
857 832
858 #[cfg(sdmmc_v2)] 833 #[cfg(sdmmc_v2)]
859 { 834 {
860 w.set_dholdc(true); 835 w.set_dholdc(true);
861 w.set_dabortc(true); 836 w.set_dabortc(true);
862 w.set_busyd0endc(true); 837 w.set_busyd0endc(true);
863 w.set_ackfailc(true); 838 w.set_ackfailc(true);
864 w.set_acktimeoutc(true); 839 w.set_acktimeoutc(true);
865 w.set_vswendc(true); 840 w.set_vswendc(true);
866 w.set_ckstopc(true); 841 w.set_ckstopc(true);
867 w.set_idmatec(true); 842 w.set_idmatec(true);
868 w.set_idmabtcc(true); 843 w.set_idmabtcc(true);
869 } 844 }
870 }); 845 });
871 }
872 } 846 }
873 847
874 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { 848 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
@@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
880 854
881 // Arm `OnDrop` after the buffer, so it will be dropped first 855 // Arm `OnDrop` after the buffer, so it will be dropped first
882 let regs = T::regs(); 856 let regs = T::regs();
883 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 857 let on_drop = OnDrop::new(|| Self::on_drop());
884 858
885 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); 859 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
886 InterruptHandler::<T>::data_interrupts(true); 860 InterruptHandler::<T>::data_interrupts(true);
@@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
888 862
889 let res = poll_fn(|cx| { 863 let res = poll_fn(|cx| {
890 T::state().register(cx.waker()); 864 T::state().register(cx.waker());
891 let status = unsafe { regs.star().read() }; 865 let status = regs.star().read();
892 866
893 if status.dcrcfail() { 867 if status.dcrcfail() {
894 return Poll::Ready(Err(Error::Crc)); 868 return Poll::Ready(Err(Error::Crc));
@@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
921 let regs = T::regs(); 895 let regs = T::regs();
922 896
923 Self::clear_interrupt_flags(); 897 Self::clear_interrupt_flags();
924 // NOTE(safety) Atomic operations 898 // CP state machine must be idle
925 unsafe { 899 while Self::cmd_active() {}
926 // CP state machine must be idle
927 while Self::cmd_active() {}
928 900
929 // Command arg 901 // Command arg
930 regs.argr().write(|w| w.set_cmdarg(cmd.arg)); 902 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
931
932 // Command index and start CP State Machine
933 regs.cmdr().write(|w| {
934 w.set_waitint(false);
935 w.set_waitresp(cmd.resp as u8);
936 w.set_cmdindex(cmd.cmd);
937 w.set_cpsmen(true);
938 903
939 #[cfg(sdmmc_v2)] 904 // Command index and start CP State Machine
940 { 905 regs.cmdr().write(|w| {
941 // Special mode in CP State Machine 906 w.set_waitint(false);
942 // CMD12: Stop Transmission 907 w.set_waitresp(cmd.resp as u8);
943 let cpsm_stop_transmission = cmd.cmd == 12; 908 w.set_cmdindex(cmd.cmd);
944 w.set_cmdstop(cpsm_stop_transmission); 909 w.set_cpsmen(true);
945 w.set_cmdtrans(data);
946 }
947 });
948 910
949 let mut status; 911 #[cfg(sdmmc_v2)]
950 if cmd.resp == Response::None { 912 {
951 // Wait for CMDSENT or a timeout 913 // Special mode in CP State Machine
952 while { 914 // CMD12: Stop Transmission
953 status = regs.star().read(); 915 let cpsm_stop_transmission = cmd.cmd == 12;
954 !(status.ctimeout() || status.cmdsent()) 916 w.set_cmdstop(cpsm_stop_transmission);
955 } {} 917 w.set_cmdtrans(data);
956 } else {
957 // Wait for CMDREND or CCRCFAIL or a timeout
958 while {
959 status = regs.star().read();
960 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
961 } {}
962 } 918 }
919 });
963 920
964 if status.ctimeout() { 921 let mut status;
965 return Err(Error::Timeout); 922 if cmd.resp == Response::None {
966 } else if status.ccrcfail() { 923 // Wait for CMDSENT or a timeout
967 return Err(Error::Crc); 924 while {
968 } 925 status = regs.star().read();
969 Ok(()) 926 !(status.ctimeout() || status.cmdsent())
927 } {}
928 } else {
929 // Wait for CMDREND or CCRCFAIL or a timeout
930 while {
931 status = regs.star().read();
932 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
933 } {}
934 }
935
936 if status.ctimeout() {
937 return Err(Error::Timeout);
938 } else if status.ccrcfail() {
939 return Err(Error::Crc);
970 } 940 }
941 Ok(())
971 } 942 }
972 943
973 /// # Safety 944 fn on_drop() {
974 ///
975 /// Ensure that `regs` has exclusive access to the regblocks
976 unsafe fn on_drop() {
977 let regs = T::regs(); 945 let regs = T::regs();
978 if Self::data_active() { 946 if Self::data_active() {
979 Self::clear_interrupt_flags(); 947 Self::clear_interrupt_flags();
@@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1017 false => BusWidth::One, 985 false => BusWidth::One,
1018 }; 986 };
1019 987
1020 // NOTE(unsafe) We have exclusive access to the peripheral 988 // While the SD/SDIO card or eMMC is in identification mode,
1021 unsafe { 989 // the SDMMC_CK frequency must be no more than 400 kHz.
1022 // While the SD/SDIO card or eMMC is in identification mode, 990 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1023 // the SDMMC_CK frequency must be no more than 400 kHz. 991 self.clock = init_clock;
1024 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1025 self.clock = init_clock;
1026
1027 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1028 Self::wait_idle();
1029
1030 regs.clkcr().modify(|w| {
1031 w.set_widbus(0);
1032 w.set_clkdiv(clkdiv);
1033 #[cfg(sdmmc_v1)]
1034 w.set_bypass(_bypass);
1035 });
1036 992
1037 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); 993 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1038 Self::cmd(Cmd::idle(), false)?; 994 Self::wait_idle();
1039 995
1040 // Check if cards supports CMD8 (with pattern) 996 regs.clkcr().modify(|w| {
1041 Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; 997 w.set_widbus(0);
1042 let r1 = regs.respr(0).read().cardstatus(); 998 w.set_clkdiv(clkdiv);
999 #[cfg(sdmmc_v1)]
1000 w.set_bypass(_bypass);
1001 });
1043 1002
1044 let mut card = if r1 == 0x1AA { 1003 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1045 // Card echoed back the pattern. Must be at least v2 1004 Self::cmd(Cmd::idle(), false)?;
1046 Card::default()
1047 } else {
1048 return Err(Error::UnsupportedCardVersion);
1049 };
1050 1005
1051 let ocr = loop { 1006 // Check if cards supports CMD8 (with pattern)
1052 // Signal that next command is a app command 1007 Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
1053 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 1008 let r1 = regs.respr(0).read().cardstatus();
1054 1009
1055 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 1010 let mut card = if r1 == 0x1AA {
1056 | CmdAppOper::HIGH_CAPACITY as u32 1011 // Card echoed back the pattern. Must be at least v2
1057 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; 1012 Card::default()
1013 } else {
1014 return Err(Error::UnsupportedCardVersion);
1015 };
1058 1016
1059 // Initialize card 1017 let ocr = loop {
1060 match Self::cmd(Cmd::app_op_cmd(arg), false) { 1018 // Signal that next command is a app command
1061 // ACMD41 1019 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
1062 Ok(_) => (),
1063 Err(Error::Crc) => (),
1064 Err(err) => return Err(err),
1065 }
1066 let ocr: OCR = regs.respr(0).read().cardstatus().into();
1067 if !ocr.is_busy() {
1068 // Power up done
1069 break ocr;
1070 }
1071 };
1072 1020
1073 if ocr.high_capacity() { 1021 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
1074 // Card is SDHC or SDXC or SDUC 1022 | CmdAppOper::HIGH_CAPACITY as u32
1075 card.card_type = CardCapacity::SDHC; 1023 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
1076 } else {
1077 card.card_type = CardCapacity::SDSC;
1078 }
1079 card.ocr = ocr;
1080
1081 Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
1082 let cid0 = regs.respr(0).read().cardstatus() as u128;
1083 let cid1 = regs.respr(1).read().cardstatus() as u128;
1084 let cid2 = regs.respr(2).read().cardstatus() as u128;
1085 let cid3 = regs.respr(3).read().cardstatus() as u128;
1086 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1087 card.cid = cid.into();
1088
1089 Self::cmd(Cmd::send_rel_addr(), false)?;
1090 card.rca = regs.respr(0).read().cardstatus() >> 16;
1091
1092 Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
1093 let csd0 = regs.respr(0).read().cardstatus() as u128;
1094 let csd1 = regs.respr(1).read().cardstatus() as u128;
1095 let csd2 = regs.respr(2).read().cardstatus() as u128;
1096 let csd3 = regs.respr(3).read().cardstatus() as u128;
1097 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1098 card.csd = csd.into();
1099
1100 self.select_card(Some(&card))?;
1101
1102 self.get_scr(&mut card).await?;
1103
1104 // Set bus width
1105 let (width, acmd_arg) = match bus_width {
1106 BusWidth::Eight => unimplemented!(),
1107 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
1108 _ => (BusWidth::One, 0),
1109 };
1110 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
1111 Self::cmd(Cmd::cmd6(acmd_arg), false)?;
1112
1113 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1114 Self::wait_idle();
1115
1116 regs.clkcr().modify(|w| {
1117 w.set_widbus(match width {
1118 BusWidth::One => 0,
1119 BusWidth::Four => 1,
1120 BusWidth::Eight => 2,
1121 _ => panic!("Invalid Bus Width"),
1122 })
1123 });
1124 1024
1125 // Set Clock 1025 // Initialize card
1126 if freq.0 <= 25_000_000 { 1026 match Self::cmd(Cmd::app_op_cmd(arg), false) {
1127 // Final clock frequency 1027 // ACMD41
1128 self.clkcr_set_clkdiv(freq.0, width)?; 1028 Ok(_) => (),
1129 } else { 1029 Err(Error::Crc) => (),
1130 // Switch to max clock for SDR12 1030 Err(err) => return Err(err),
1131 self.clkcr_set_clkdiv(25_000_000, width)?;
1132 } 1031 }
1032 let ocr: OCR = regs.respr(0).read().cardstatus().into();
1033 if !ocr.is_busy() {
1034 // Power up done
1035 break ocr;
1036 }
1037 };
1038
1039 if ocr.high_capacity() {
1040 // Card is SDHC or SDXC or SDUC
1041 card.card_type = CardCapacity::SDHC;
1042 } else {
1043 card.card_type = CardCapacity::SDSC;
1044 }
1045 card.ocr = ocr;
1046
1047 Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
1048 let cid0 = regs.respr(0).read().cardstatus() as u128;
1049 let cid1 = regs.respr(1).read().cardstatus() as u128;
1050 let cid2 = regs.respr(2).read().cardstatus() as u128;
1051 let cid3 = regs.respr(3).read().cardstatus() as u128;
1052 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1053 card.cid = cid.into();
1054
1055 Self::cmd(Cmd::send_rel_addr(), false)?;
1056 card.rca = regs.respr(0).read().cardstatus() >> 16;
1057
1058 Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
1059 let csd0 = regs.respr(0).read().cardstatus() as u128;
1060 let csd1 = regs.respr(1).read().cardstatus() as u128;
1061 let csd2 = regs.respr(2).read().cardstatus() as u128;
1062 let csd3 = regs.respr(3).read().cardstatus() as u128;
1063 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1064 card.csd = csd.into();
1065
1066 self.select_card(Some(&card))?;
1067
1068 self.get_scr(&mut card).await?;
1069
1070 // Set bus width
1071 let (width, acmd_arg) = match bus_width {
1072 BusWidth::Eight => unimplemented!(),
1073 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
1074 _ => (BusWidth::One, 0),
1075 };
1076 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
1077 Self::cmd(Cmd::cmd6(acmd_arg), false)?;
1078
1079 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1080 Self::wait_idle();
1133 1081
1134 self.card = Some(card); 1082 regs.clkcr().modify(|w| {
1083 w.set_widbus(match width {
1084 BusWidth::One => 0,
1085 BusWidth::Four => 1,
1086 BusWidth::Eight => 2,
1087 _ => panic!("Invalid Bus Width"),
1088 })
1089 });
1090
1091 // Set Clock
1092 if freq.0 <= 25_000_000 {
1093 // Final clock frequency
1094 self.clkcr_set_clkdiv(freq.0, width)?;
1095 } else {
1096 // Switch to max clock for SDR12
1097 self.clkcr_set_clkdiv(25_000_000, width)?;
1098 }
1135 1099
1136 // Read status 1100 self.card = Some(card);
1137 self.read_sd_status().await?;
1138 1101
1139 if freq.0 > 25_000_000 { 1102 // Read status
1140 // Switch to SDR25 1103 self.read_sd_status().await?;
1141 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1142 1104
1143 if self.signalling == Signalling::SDR25 { 1105 if freq.0 > 25_000_000 {
1144 // Set final clock frequency 1106 // Switch to SDR25
1145 self.clkcr_set_clkdiv(freq.0, width)?; 1107 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1146 1108
1147 if self.read_status(&card)?.state() != CurrentState::Transfer { 1109 if self.signalling == Signalling::SDR25 {
1148 return Err(Error::SignalingSwitchFailed); 1110 // Set final clock frequency
1149 } 1111 self.clkcr_set_clkdiv(freq.0, width)?;
1112
1113 if self.read_status(&card)?.state() != CurrentState::Transfer {
1114 return Err(Error::SignalingSwitchFailed);
1150 } 1115 }
1151 } 1116 }
1152 // Read status after signalling change
1153 self.read_sd_status().await?;
1154 } 1117 }
1118 // Read status after signalling change
1119 self.read_sd_status().await?;
1155 1120
1156 Ok(()) 1121 Ok(())
1157 } 1122 }
@@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1172 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1137 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
1173 1138
1174 let regs = T::regs(); 1139 let regs = T::regs();
1175 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 1140 let on_drop = OnDrop::new(|| Self::on_drop());
1176 1141
1177 let transfer = self.prepare_datapath_read(buffer, 512, 9); 1142 let transfer = self.prepare_datapath_read(buffer, 512, 9);
1178 InterruptHandler::<T>::data_interrupts(true); 1143 InterruptHandler::<T>::data_interrupts(true);
@@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1180 1145
1181 let res = poll_fn(|cx| { 1146 let res = poll_fn(|cx| {
1182 T::state().register(cx.waker()); 1147 T::state().register(cx.waker());
1183 let status = unsafe { regs.star().read() }; 1148 let status = regs.star().read();
1184 1149
1185 if status.dcrcfail() { 1150 if status.dcrcfail() {
1186 return Poll::Ready(Err(Error::Crc)); 1151 return Poll::Ready(Err(Error::Crc));
@@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1217 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1182 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
1218 1183
1219 let regs = T::regs(); 1184 let regs = T::regs();
1220 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 1185 let on_drop = OnDrop::new(|| Self::on_drop());
1221 1186
1222 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes 1187 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1223 #[cfg(sdmmc_v1)] 1188 #[cfg(sdmmc_v1)]
@@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1231 1196
1232 let res = poll_fn(|cx| { 1197 let res = poll_fn(|cx| {
1233 T::state().register(cx.waker()); 1198 T::state().register(cx.waker());
1234 let status = unsafe { regs.star().read() }; 1199 let status = regs.star().read();
1235 1200
1236 if status.dcrcfail() { 1201 if status.dcrcfail() {
1237 return Poll::Ready(Err(Error::Crc)); 1202 return Poll::Ready(Err(Error::Crc));
@@ -1288,10 +1253,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1288 1253
1289impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { 1254impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
1290 fn drop(&mut self) { 1255 fn drop(&mut self) {
1291 unsafe { T::Interrupt::steal() }.disable(); 1256 T::Interrupt::disable();
1292 unsafe { Self::on_drop() }; 1257 Self::on_drop();
1293 1258
1294 critical_section::with(|_| unsafe { 1259 critical_section::with(|_| {
1295 self.clk.set_as_disconnected(); 1260 self.clk.set_as_disconnected();
1296 self.cmd.set_as_disconnected(); 1261 self.cmd.set_as_disconnected();
1297 self.d0.set_as_disconnected(); 1262 self.d0.set_as_disconnected();
@@ -1401,7 +1366,7 @@ pub(crate) mod sealed {
1401 use super::*; 1366 use super::*;
1402 1367
1403 pub trait Instance { 1368 pub trait Instance {
1404 type Interrupt: Interrupt; 1369 type Interrupt: interrupt::typelevel::Interrupt;
1405 1370
1406 fn regs() -> RegBlock; 1371 fn regs() -> RegBlock;
1407 fn state() -> &'static AtomicWaker; 1372 fn state() -> &'static AtomicWaker;
@@ -1490,7 +1455,7 @@ cfg_if::cfg_if! {
1490foreach_peripheral!( 1455foreach_peripheral!(
1491 (sdmmc, $inst:ident) => { 1456 (sdmmc, $inst:ident) => {
1492 impl sealed::Instance for peripherals::$inst { 1457 impl sealed::Instance for peripherals::$inst {
1493 type Interrupt = crate::interrupt::$inst; 1458 type Interrupt = crate::interrupt::typelevel::$inst;
1494 1459
1495 fn regs() -> RegBlock { 1460 fn regs() -> RegBlock {
1496 crate::pac::$inst 1461 crate::pac::$inst
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 580971e45..1cddac992 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
98 Polarity::IdleHigh => Pull::Up, 98 Polarity::IdleHigh => Pull::Up,
99 }; 99 };
100 100
101 unsafe { 101 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
102 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); 102 sck.set_speed(crate::gpio::Speed::VeryHigh);
103 sck.set_speed(crate::gpio::Speed::VeryHigh); 103 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
104 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); 104 mosi.set_speed(crate::gpio::Speed::VeryHigh);
105 mosi.set_speed(crate::gpio::Speed::VeryHigh); 105 miso.set_as_af(miso.af_num(), AFType::Input);
106 miso.set_as_af(miso.af_num(), AFType::Input); 106 miso.set_speed(crate::gpio::Speed::VeryHigh);
107 miso.set_speed(crate::gpio::Speed::VeryHigh);
108 }
109 107
110 Self::new_inner( 108 Self::new_inner(
111 peri, 109 peri,
@@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
129 config: Config, 127 config: Config,
130 ) -> Self { 128 ) -> Self {
131 into_ref!(sck, miso); 129 into_ref!(sck, miso);
132 unsafe { 130 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
133 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 131 sck.set_speed(crate::gpio::Speed::VeryHigh);
134 sck.set_speed(crate::gpio::Speed::VeryHigh); 132 miso.set_as_af(miso.af_num(), AFType::Input);
135 miso.set_as_af(miso.af_num(), AFType::Input); 133 miso.set_speed(crate::gpio::Speed::VeryHigh);
136 miso.set_speed(crate::gpio::Speed::VeryHigh);
137 }
138 134
139 Self::new_inner( 135 Self::new_inner(
140 peri, 136 peri,
@@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
158 config: Config, 154 config: Config,
159 ) -> Self { 155 ) -> Self {
160 into_ref!(sck, mosi); 156 into_ref!(sck, mosi);
161 unsafe { 157 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
162 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 158 sck.set_speed(crate::gpio::Speed::VeryHigh);
163 sck.set_speed(crate::gpio::Speed::VeryHigh); 159 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
164 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); 160 mosi.set_speed(crate::gpio::Speed::VeryHigh);
165 mosi.set_speed(crate::gpio::Speed::VeryHigh);
166 }
167 161
168 Self::new_inner( 162 Self::new_inner(
169 peri, 163 peri,
@@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
186 config: Config, 180 config: Config,
187 ) -> Self { 181 ) -> Self {
188 into_ref!(mosi); 182 into_ref!(mosi);
189 unsafe { 183 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
190 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); 184 mosi.set_speed(crate::gpio::Speed::Medium);
191 mosi.set_speed(crate::gpio::Speed::Medium);
192 }
193 185
194 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config) 186 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
195 } 187 }
@@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
247 T::reset(); 239 T::reset();
248 240
249 #[cfg(any(spi_v1, spi_f1))] 241 #[cfg(any(spi_v1, spi_f1))]
250 unsafe { 242 {
251 T::REGS.cr2().modify(|w| { 243 T::REGS.cr2().modify(|w| {
252 w.set_ssoe(false); 244 w.set_ssoe(false);
253 }); 245 });
@@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
270 }); 262 });
271 } 263 }
272 #[cfg(spi_v2)] 264 #[cfg(spi_v2)]
273 unsafe { 265 {
274 T::REGS.cr2().modify(|w| { 266 T::REGS.cr2().modify(|w| {
275 let (ds, frxth) = <u8 as sealed::Word>::CONFIG; 267 let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
276 w.set_frxth(frxth); 268 w.set_frxth(frxth);
@@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
292 }); 284 });
293 } 285 }
294 #[cfg(any(spi_v3, spi_v4, spi_v5))] 286 #[cfg(any(spi_v3, spi_v4, spi_v5))]
295 unsafe { 287 {
296 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); 288 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
297 T::REGS.cfg2().modify(|w| { 289 T::REGS.cfg2().modify(|w| {
298 //w.set_ssoe(true); 290 //w.set_ssoe(true);
@@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
343 let lsbfirst = config.raw_byte_order(); 335 let lsbfirst = config.raw_byte_order();
344 336
345 #[cfg(any(spi_v1, spi_f1, spi_v2))] 337 #[cfg(any(spi_v1, spi_f1, spi_v2))]
346 unsafe { 338 T::REGS.cr1().modify(|w| {
347 T::REGS.cr1().modify(|w| { 339 w.set_cpha(cpha);
348 w.set_cpha(cpha); 340 w.set_cpol(cpol);
349 w.set_cpol(cpol); 341 w.set_lsbfirst(lsbfirst);
350 w.set_lsbfirst(lsbfirst); 342 });
351 });
352 }
353 343
354 #[cfg(any(spi_v3, spi_v4, spi_v5))] 344 #[cfg(any(spi_v3, spi_v4, spi_v5))]
355 unsafe { 345 T::REGS.cfg2().modify(|w| {
356 T::REGS.cfg2().modify(|w| { 346 w.set_cpha(cpha);
357 w.set_cpha(cpha); 347 w.set_cpol(cpol);
358 w.set_cpol(cpol); 348 w.set_lsbfirst(lsbfirst);
359 w.set_lsbfirst(lsbfirst); 349 });
360 });
361 }
362 } 350 }
363 351
364 pub fn get_current_config(&self) -> Config { 352 pub fn get_current_config(&self) -> Config {
365 #[cfg(any(spi_v1, spi_f1, spi_v2))] 353 #[cfg(any(spi_v1, spi_f1, spi_v2))]
366 let cfg = unsafe { T::REGS.cr1().read() }; 354 let cfg = T::REGS.cr1().read();
367 #[cfg(any(spi_v3, spi_v4, spi_v5))] 355 #[cfg(any(spi_v3, spi_v4, spi_v5))]
368 let cfg = unsafe { T::REGS.cfg2().read() }; 356 let cfg = T::REGS.cfg2().read();
369 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { 357 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
370 Polarity::IdleLow 358 Polarity::IdleLow
371 } else { 359 } else {
@@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
395 } 383 }
396 384
397 #[cfg(any(spi_v1, spi_f1))] 385 #[cfg(any(spi_v1, spi_f1))]
398 unsafe { 386 {
399 T::REGS.cr1().modify(|reg| { 387 T::REGS.cr1().modify(|reg| {
400 reg.set_spe(false); 388 reg.set_spe(false);
401 reg.set_dff(word_size) 389 reg.set_dff(word_size)
@@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
405 }); 393 });
406 } 394 }
407 #[cfg(spi_v2)] 395 #[cfg(spi_v2)]
408 unsafe { 396 {
409 T::REGS.cr1().modify(|w| { 397 T::REGS.cr1().modify(|w| {
410 w.set_spe(false); 398 w.set_spe(false);
411 }); 399 });
@@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
418 }); 406 });
419 } 407 }
420 #[cfg(any(spi_v3, spi_v4, spi_v5))] 408 #[cfg(any(spi_v3, spi_v4, spi_v5))]
421 unsafe { 409 {
422 T::REGS.cr1().modify(|w| { 410 T::REGS.cr1().modify(|w| {
423 w.set_csusp(true); 411 w.set_csusp(true);
424 }); 412 });
@@ -447,26 +435,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
447 } 435 }
448 436
449 self.set_word_size(W::CONFIG); 437 self.set_word_size(W::CONFIG);
450 unsafe { 438 T::REGS.cr1().modify(|w| {
451 T::REGS.cr1().modify(|w| { 439 w.set_spe(false);
452 w.set_spe(false); 440 });
453 });
454 }
455 441
456 let tx_request = self.txdma.request(); 442 let tx_request = self.txdma.request();
457 let tx_dst = T::REGS.tx_ptr(); 443 let tx_dst = T::REGS.tx_ptr();
458 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; 444 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
459 445
460 unsafe { 446 set_txdmaen(T::REGS, true);
461 set_txdmaen(T::REGS, true); 447 T::REGS.cr1().modify(|w| {
462 T::REGS.cr1().modify(|w| { 448 w.set_spe(true);
463 w.set_spe(true); 449 });
464 }); 450 #[cfg(any(spi_v3, spi_v4, spi_v5))]
465 #[cfg(any(spi_v3, spi_v4, spi_v5))] 451 T::REGS.cr1().modify(|w| {
466 T::REGS.cr1().modify(|w| { 452 w.set_cstart(true);
467 w.set_cstart(true); 453 });
468 });
469 }
470 454
471 tx_f.await; 455 tx_f.await;
472 456
@@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
485 } 469 }
486 470
487 self.set_word_size(W::CONFIG); 471 self.set_word_size(W::CONFIG);
488 unsafe { 472 T::REGS.cr1().modify(|w| {
489 T::REGS.cr1().modify(|w| { 473 w.set_spe(false);
490 w.set_spe(false); 474 });
491 });
492 }
493 475
494 // SPIv3 clears rxfifo on SPE=0 476 // SPIv3 clears rxfifo on SPE=0
495 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 477 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@@ -517,16 +499,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
517 ) 499 )
518 }; 500 };
519 501
520 unsafe { 502 set_txdmaen(T::REGS, true);
521 set_txdmaen(T::REGS, true); 503 T::REGS.cr1().modify(|w| {
522 T::REGS.cr1().modify(|w| { 504 w.set_spe(true);
523 w.set_spe(true); 505 });
524 }); 506 #[cfg(any(spi_v3, spi_v4, spi_v5))]
525 #[cfg(any(spi_v3, spi_v4, spi_v5))] 507 T::REGS.cr1().modify(|w| {
526 T::REGS.cr1().modify(|w| { 508 w.set_cstart(true);
527 w.set_cstart(true); 509 });
528 });
529 }
530 510
531 join(tx_f, rx_f).await; 511 join(tx_f, rx_f).await;
532 512
@@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
548 } 528 }
549 529
550 self.set_word_size(W::CONFIG); 530 self.set_word_size(W::CONFIG);
551 unsafe { 531 T::REGS.cr1().modify(|w| {
552 T::REGS.cr1().modify(|w| { 532 w.set_spe(false);
553 w.set_spe(false); 533 });
554 });
555 }
556 534
557 // SPIv3 clears rxfifo on SPE=0 535 // SPIv3 clears rxfifo on SPE=0
558 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 536 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@@ -568,16 +546,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
568 let tx_dst = T::REGS.tx_ptr(); 546 let tx_dst = T::REGS.tx_ptr();
569 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; 547 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
570 548
571 unsafe { 549 set_txdmaen(T::REGS, true);
572 set_txdmaen(T::REGS, true); 550 T::REGS.cr1().modify(|w| {
573 T::REGS.cr1().modify(|w| { 551 w.set_spe(true);
574 w.set_spe(true); 552 });
575 }); 553 #[cfg(any(spi_v3, spi_v4, spi_v5))]
576 #[cfg(any(spi_v3, spi_v4, spi_v5))] 554 T::REGS.cr1().modify(|w| {
577 T::REGS.cr1().modify(|w| { 555 w.set_cstart(true);
578 w.set_cstart(true); 556 });
579 });
580 }
581 557
582 join(tx_f, rx_f).await; 558 join(tx_f, rx_f).await;
583 559
@@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
603 } 579 }
604 580
605 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 581 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
606 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 582 T::REGS.cr1().modify(|w| w.set_spe(true));
607 flush_rx_fifo(T::REGS); 583 flush_rx_fifo(T::REGS);
608 self.set_word_size(W::CONFIG); 584 self.set_word_size(W::CONFIG);
609 for word in words.iter() { 585 for word in words.iter() {
@@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
613 } 589 }
614 590
615 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 591 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
616 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 592 T::REGS.cr1().modify(|w| w.set_spe(true));
617 flush_rx_fifo(T::REGS); 593 flush_rx_fifo(T::REGS);
618 self.set_word_size(W::CONFIG); 594 self.set_word_size(W::CONFIG);
619 for word in words.iter_mut() { 595 for word in words.iter_mut() {
@@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
623 } 599 }
624 600
625 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 601 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
626 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 602 T::REGS.cr1().modify(|w| w.set_spe(true));
627 flush_rx_fifo(T::REGS); 603 flush_rx_fifo(T::REGS);
628 self.set_word_size(W::CONFIG); 604 self.set_word_size(W::CONFIG);
629 for word in words.iter_mut() { 605 for word in words.iter_mut() {
@@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
633 } 609 }
634 610
635 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 611 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
636 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 612 T::REGS.cr1().modify(|w| w.set_spe(true));
637 flush_rx_fifo(T::REGS); 613 flush_rx_fifo(T::REGS);
638 self.set_word_size(W::CONFIG); 614 self.set_word_size(W::CONFIG);
639 let len = read.len().max(write.len()); 615 let len = read.len().max(write.len());
@@ -650,11 +626,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
650 626
651impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 627impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
652 fn drop(&mut self) { 628 fn drop(&mut self) {
653 unsafe { 629 self.sck.as_ref().map(|x| x.set_as_disconnected());
654 self.sck.as_ref().map(|x| x.set_as_disconnected()); 630 self.mosi.as_ref().map(|x| x.set_as_disconnected());
655 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 631 self.miso.as_ref().map(|x| x.set_as_disconnected());
656 self.miso.as_ref().map(|x| x.set_as_disconnected());
657 }
658 } 632 }
659} 633}
660 634
@@ -690,7 +664,7 @@ impl RegsExt for Regs {
690 let dr = self.dr(); 664 let dr = self.dr();
691 #[cfg(any(spi_v3, spi_v4, spi_v5))] 665 #[cfg(any(spi_v3, spi_v4, spi_v5))]
692 let dr = self.txdr(); 666 let dr = self.txdr();
693 dr.ptr() as *mut W 667 dr.as_ptr() as *mut W
694 } 668 }
695 669
696 fn rx_ptr<W>(&self) -> *mut W { 670 fn rx_ptr<W>(&self) -> *mut W {
@@ -698,7 +672,7 @@ impl RegsExt for Regs {
698 let dr = self.dr(); 672 let dr = self.dr();
699 #[cfg(any(spi_v3, spi_v4, spi_v5))] 673 #[cfg(any(spi_v3, spi_v4, spi_v5))]
700 let dr = self.rxdr(); 674 let dr = self.rxdr();
701 dr.ptr() as *mut W 675 dr.as_ptr() as *mut W
702 } 676 }
703} 677}
704 678
@@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
731 705
732fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { 706fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
733 loop { 707 loop {
734 let sr = unsafe { regs.sr().read() }; 708 let sr = regs.sr().read();
735 709
736 check_error_flags(sr)?; 710 check_error_flags(sr)?;
737 711
@@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
748 722
749fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { 723fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
750 loop { 724 loop {
751 let sr = unsafe { regs.sr().read() }; 725 let sr = regs.sr().read();
752 726
753 check_error_flags(sr)?; 727 check_error_flags(sr)?;
754 728
@@ -764,72 +738,64 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
764} 738}
765 739
766fn flush_rx_fifo(regs: Regs) { 740fn flush_rx_fifo(regs: Regs) {
767 unsafe { 741 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
768 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 742 while regs.sr().read().rxne() {
769 while regs.sr().read().rxne() { 743 let _ = regs.dr().read();
770 let _ = regs.dr().read(); 744 }
771 } 745 #[cfg(any(spi_v3, spi_v4, spi_v5))]
772 #[cfg(any(spi_v3, spi_v4, spi_v5))] 746 while regs.sr().read().rxp() {
773 while regs.sr().read().rxp() { 747 let _ = regs.rxdr().read();
774 let _ = regs.rxdr().read();
775 }
776 } 748 }
777} 749}
778 750
779fn set_txdmaen(regs: Regs, val: bool) { 751fn set_txdmaen(regs: Regs, val: bool) {
780 unsafe { 752 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
781 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 753 regs.cr2().modify(|reg| {
782 regs.cr2().modify(|reg| { 754 reg.set_txdmaen(val);
783 reg.set_txdmaen(val); 755 });
784 }); 756 #[cfg(any(spi_v3, spi_v4, spi_v5))]
785 #[cfg(any(spi_v3, spi_v4, spi_v5))] 757 regs.cfg1().modify(|reg| {
786 regs.cfg1().modify(|reg| { 758 reg.set_txdmaen(val);
787 reg.set_txdmaen(val); 759 });
788 });
789 }
790} 760}
791 761
792fn set_rxdmaen(regs: Regs, val: bool) { 762fn set_rxdmaen(regs: Regs, val: bool) {
793 unsafe { 763 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
794 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 764 regs.cr2().modify(|reg| {
795 regs.cr2().modify(|reg| { 765 reg.set_rxdmaen(val);
796 reg.set_rxdmaen(val); 766 });
797 }); 767 #[cfg(any(spi_v3, spi_v4, spi_v5))]
798 #[cfg(any(spi_v3, spi_v4, spi_v5))] 768 regs.cfg1().modify(|reg| {
799 regs.cfg1().modify(|reg| { 769 reg.set_rxdmaen(val);
800 reg.set_rxdmaen(val); 770 });
801 });
802 }
803} 771}
804 772
805fn finish_dma(regs: Regs) { 773fn finish_dma(regs: Regs) {
806 unsafe { 774 #[cfg(spi_v2)]
807 #[cfg(spi_v2)] 775 while regs.sr().read().ftlvl() > 0 {}
808 while regs.sr().read().ftlvl() > 0 {}
809 776
810 #[cfg(any(spi_v3, spi_v4, spi_v5))] 777 #[cfg(any(spi_v3, spi_v4, spi_v5))]
811 while !regs.sr().read().txc() {} 778 while !regs.sr().read().txc() {}
812 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 779 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
813 while regs.sr().read().bsy() {} 780 while regs.sr().read().bsy() {}
814 781
815 // Disable the spi peripheral 782 // Disable the spi peripheral
816 regs.cr1().modify(|w| { 783 regs.cr1().modify(|w| {
817 w.set_spe(false); 784 w.set_spe(false);
818 }); 785 });
819 786
820 // The peripheral automatically disables the DMA stream on completion without error, 787 // The peripheral automatically disables the DMA stream on completion without error,
821 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. 788 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2.
822 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 789 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
823 regs.cr2().modify(|reg| { 790 regs.cr2().modify(|reg| {
824 reg.set_txdmaen(false); 791 reg.set_txdmaen(false);
825 reg.set_rxdmaen(false); 792 reg.set_rxdmaen(false);
826 }); 793 });
827 #[cfg(any(spi_v3, spi_v4, spi_v5))] 794 #[cfg(any(spi_v3, spi_v4, spi_v5))]
828 regs.cfg1().modify(|reg| { 795 regs.cfg1().modify(|reg| {
829 reg.set_txdmaen(false); 796 reg.set_txdmaen(false);
830 reg.set_rxdmaen(false); 797 reg.set_rxdmaen(false);
831 }); 798 });
832 }
833} 799}
834 800
835fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { 801fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 2236fde28..2622442f4 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -11,7 +11,7 @@ use embassy_time::driver::{AlarmHandle, Driver};
11use embassy_time::TICK_HZ; 11use embassy_time::TICK_HZ;
12use stm32_metapac::timer::regs; 12use stm32_metapac::timer::regs;
13 13
14use crate::interrupt::InterruptExt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::timer::vals; 15use crate::pac::timer::vals;
16use crate::rcc::sealed::RccPeripheral; 16use crate::rcc::sealed::RccPeripheral;
17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; 17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
@@ -40,6 +40,7 @@ type T = peripherals::TIM15;
40foreach_interrupt! { 40foreach_interrupt! {
41 (TIM2, timer, $block:ident, UP, $irq:ident) => { 41 (TIM2, timer, $block:ident, UP, $irq:ident) => {
42 #[cfg(time_driver_tim2)] 42 #[cfg(time_driver_tim2)]
43 #[cfg(feature = "rt")]
43 #[interrupt] 44 #[interrupt]
44 fn $irq() { 45 fn $irq() {
45 DRIVER.on_interrupt() 46 DRIVER.on_interrupt()
@@ -47,6 +48,7 @@ foreach_interrupt! {
47 }; 48 };
48 (TIM3, timer, $block:ident, UP, $irq:ident) => { 49 (TIM3, timer, $block:ident, UP, $irq:ident) => {
49 #[cfg(time_driver_tim3)] 50 #[cfg(time_driver_tim3)]
51 #[cfg(feature = "rt")]
50 #[interrupt] 52 #[interrupt]
51 fn $irq() { 53 fn $irq() {
52 DRIVER.on_interrupt() 54 DRIVER.on_interrupt()
@@ -54,6 +56,7 @@ foreach_interrupt! {
54 }; 56 };
55 (TIM4, timer, $block:ident, UP, $irq:ident) => { 57 (TIM4, timer, $block:ident, UP, $irq:ident) => {
56 #[cfg(time_driver_tim4)] 58 #[cfg(time_driver_tim4)]
59 #[cfg(feature = "rt")]
57 #[interrupt] 60 #[interrupt]
58 fn $irq() { 61 fn $irq() {
59 DRIVER.on_interrupt() 62 DRIVER.on_interrupt()
@@ -61,6 +64,7 @@ foreach_interrupt! {
61 }; 64 };
62 (TIM5, timer, $block:ident, UP, $irq:ident) => { 65 (TIM5, timer, $block:ident, UP, $irq:ident) => {
63 #[cfg(time_driver_tim5)] 66 #[cfg(time_driver_tim5)]
67 #[cfg(feature = "rt")]
64 #[interrupt] 68 #[interrupt]
65 fn $irq() { 69 fn $irq() {
66 DRIVER.on_interrupt() 70 DRIVER.on_interrupt()
@@ -68,6 +72,7 @@ foreach_interrupt! {
68 }; 72 };
69 (TIM12, timer, $block:ident, UP, $irq:ident) => { 73 (TIM12, timer, $block:ident, UP, $irq:ident) => {
70 #[cfg(time_driver_tim12)] 74 #[cfg(time_driver_tim12)]
75 #[cfg(feature = "rt")]
71 #[interrupt] 76 #[interrupt]
72 fn $irq() { 77 fn $irq() {
73 DRIVER.on_interrupt() 78 DRIVER.on_interrupt()
@@ -75,6 +80,7 @@ foreach_interrupt! {
75 }; 80 };
76 (TIM15, timer, $block:ident, UP, $irq:ident) => { 81 (TIM15, timer, $block:ident, UP, $irq:ident) => {
77 #[cfg(time_driver_tim15)] 82 #[cfg(time_driver_tim15)]
83 #[cfg(feature = "rt")]
78 #[interrupt] 84 #[interrupt]
79 fn $irq() { 85 fn $irq() {
80 DRIVER.on_interrupt() 86 DRIVER.on_interrupt()
@@ -149,8 +155,7 @@ impl RtcDriver {
149 155
150 let timer_freq = T::frequency(); 156 let timer_freq = T::frequency();
151 157
152 // NOTE(unsafe) Critical section to use the unsafe methods 158 critical_section::with(|_| {
153 critical_section::with(|_| unsafe {
154 r.cr1().modify(|w| w.set_cen(false)); 159 r.cr1().modify(|w| w.set_cen(false));
155 r.cnt().write(|w| w.set_cnt(0)); 160 r.cnt().write(|w| w.set_cnt(0));
156 161
@@ -177,9 +182,8 @@ impl RtcDriver {
177 w.set_ccie(0, true); 182 w.set_ccie(0, true);
178 }); 183 });
179 184
180 let irq: <T as BasicInstance>::Interrupt = core::mem::transmute(()); 185 <T as BasicInstance>::Interrupt::unpend();
181 irq.unpend(); 186 unsafe { <T as BasicInstance>::Interrupt::enable() };
182 irq.enable();
183 187
184 r.cr1().modify(|w| w.set_cen(true)); 188 r.cr1().modify(|w| w.set_cen(true));
185 }) 189 })
@@ -188,9 +192,8 @@ impl RtcDriver {
188 fn on_interrupt(&self) { 192 fn on_interrupt(&self) {
189 let r = T::regs_gp16(); 193 let r = T::regs_gp16();
190 194
191 // NOTE(unsafe) Use critical section to access the methods
192 // XXX: reduce the size of this critical section ? 195 // XXX: reduce the size of this critical section ?
193 critical_section::with(|cs| unsafe { 196 critical_section::with(|cs| {
194 let sr = r.sr().read(); 197 let sr = r.sr().read();
195 let dier = r.dier().read(); 198 let dier = r.dier().read();
196 199
@@ -223,7 +226,7 @@ impl RtcDriver {
223 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; 226 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
224 let t = (period as u64) << 15; 227 let t = (period as u64) << 15;
225 228
226 critical_section::with(move |cs| unsafe { 229 critical_section::with(move |cs| {
227 r.dier().modify(move |w| { 230 r.dier().modify(move |w| {
228 for n in 0..ALARM_COUNT { 231 for n in 0..ALARM_COUNT {
229 let alarm = &self.alarms.borrow(cs)[n]; 232 let alarm = &self.alarms.borrow(cs)[n];
@@ -264,8 +267,7 @@ impl Driver for RtcDriver {
264 267
265 let period = self.period.load(Ordering::Relaxed); 268 let period = self.period.load(Ordering::Relaxed);
266 compiler_fence(Ordering::Acquire); 269 compiler_fence(Ordering::Acquire);
267 // NOTE(unsafe) Atomic read with no side-effects 270 let counter = r.cnt().read().cnt();
268 let counter = unsafe { r.cnt().read().cnt() };
269 calc_now(period, counter) 271 calc_now(period, counter)
270 } 272 }
271 273
@@ -305,7 +307,7 @@ impl Driver for RtcDriver {
305 if timestamp <= t { 307 if timestamp <= t {
306 // If alarm timestamp has passed the alarm will not fire. 308 // If alarm timestamp has passed the alarm will not fire.
307 // Disarm the alarm and return `false` to indicate that. 309 // Disarm the alarm and return `false` to indicate that.
308 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; 310 r.dier().modify(|w| w.set_ccie(n + 1, false));
309 311
310 alarm.timestamp.set(u64::MAX); 312 alarm.timestamp.set(u64::MAX);
311 313
@@ -316,12 +318,11 @@ impl Driver for RtcDriver {
316 318
317 // Write the CCR value regardless of whether we're going to enable it now or not. 319 // Write the CCR value regardless of whether we're going to enable it now or not.
318 // This way, when we enable it later, the right value is already set. 320 // This way, when we enable it later, the right value is already set.
319 unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) }; 321 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16));
320 322
321 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 323 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
322 let diff = timestamp - t; 324 let diff = timestamp - t;
323 // NOTE(unsafe) We're in a critical section 325 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
324 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
325 326
326 true 327 true
327 }) 328 })
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 772c67686..09b7a3776 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,6 +1,6 @@
1use stm32_metapac::timer::vals; 1use stm32_metapac::timer::vals;
2 2
3use crate::interrupt::Interrupt; 3use crate::interrupt;
4use crate::rcc::sealed::RccPeripheral as __RccPeri; 4use crate::rcc::sealed::RccPeripheral as __RccPeri;
5use crate::rcc::RccPeripheral; 5use crate::rcc::RccPeripheral;
6use crate::time::Hertz; 6use crate::time::Hertz;
@@ -13,7 +13,7 @@ pub mod low_level {
13pub(crate) mod sealed { 13pub(crate) mod sealed {
14 use super::*; 14 use super::*;
15 pub trait Basic16bitInstance: RccPeripheral { 15 pub trait Basic16bitInstance: RccPeripheral {
16 type Interrupt: Interrupt; 16 type Interrupt: interrupt::typelevel::Interrupt;
17 17
18 fn regs() -> crate::pac::timer::TimBasic; 18 fn regs() -> crate::pac::timer::TimBasic;
19 19
@@ -57,28 +57,22 @@ pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
57macro_rules! impl_basic_16bit_timer { 57macro_rules! impl_basic_16bit_timer {
58 ($inst:ident, $irq:ident) => { 58 ($inst:ident, $irq:ident) => {
59 impl sealed::Basic16bitInstance for crate::peripherals::$inst { 59 impl sealed::Basic16bitInstance for crate::peripherals::$inst {
60 type Interrupt = crate::interrupt::$irq; 60 type Interrupt = crate::interrupt::typelevel::$irq;
61 61
62 fn regs() -> crate::pac::timer::TimBasic { 62 fn regs() -> crate::pac::timer::TimBasic {
63 crate::pac::timer::TimBasic(crate::pac::$inst.0) 63 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
64 } 64 }
65 65
66 fn start(&mut self) { 66 fn start(&mut self) {
67 unsafe { 67 Self::regs().cr1().modify(|r| r.set_cen(true));
68 Self::regs().cr1().modify(|r| r.set_cen(true));
69 }
70 } 68 }
71 69
72 fn stop(&mut self) { 70 fn stop(&mut self) {
73 unsafe { 71 Self::regs().cr1().modify(|r| r.set_cen(false));
74 Self::regs().cr1().modify(|r| r.set_cen(false));
75 }
76 } 72 }
77 73
78 fn reset(&mut self) { 74 fn reset(&mut self) {
79 unsafe { 75 Self::regs().cnt().write(|r| r.set_cnt(0));
80 Self::regs().cnt().write(|r| r.set_cnt(0));
81 }
82 } 76 }
83 77
84 fn set_frequency(&mut self, frequency: Hertz) { 78 fn set_frequency(&mut self, frequency: Hertz) {
@@ -90,35 +84,29 @@ macro_rules! impl_basic_16bit_timer {
90 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); 84 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
91 85
92 let regs = Self::regs(); 86 let regs = Self::regs();
93 unsafe { 87 regs.psc().write(|r| r.set_psc(psc));
94 regs.psc().write(|r| r.set_psc(psc)); 88 regs.arr().write(|r| r.set_arr(arr));
95 regs.arr().write(|r| r.set_arr(arr));
96 89
97 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 90 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
98 regs.egr().write(|r| r.set_ug(true)); 91 regs.egr().write(|r| r.set_ug(true));
99 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 92 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
100 }
101 } 93 }
102 94
103 fn clear_update_interrupt(&mut self) -> bool { 95 fn clear_update_interrupt(&mut self) -> bool {
104 let regs = Self::regs(); 96 let regs = Self::regs();
105 unsafe { 97 let sr = regs.sr().read();
106 let sr = regs.sr().read(); 98 if sr.uif() {
107 if sr.uif() { 99 regs.sr().modify(|r| {
108 regs.sr().modify(|r| { 100 r.set_uif(false);
109 r.set_uif(false); 101 });
110 }); 102 true
111 true 103 } else {
112 } else { 104 false
113 false
114 }
115 } 105 }
116 } 106 }
117 107
118 fn enable_update_interrupt(&mut self, enable: bool) { 108 fn enable_update_interrupt(&mut self, enable: bool) {
119 unsafe { 109 Self::regs().dier().write(|r| r.set_uie(enable));
120 Self::regs().dier().write(|r| r.set_uie(enable));
121 }
122 } 110 }
123 } 111 }
124 }; 112 };
@@ -141,14 +129,12 @@ macro_rules! impl_32bit_timer {
141 let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); 129 let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
142 130
143 let regs = Self::regs_gp32(); 131 let regs = Self::regs_gp32();
144 unsafe { 132 regs.psc().write(|r| r.set_psc(psc));
145 regs.psc().write(|r| r.set_psc(psc)); 133 regs.arr().write(|r| r.set_arr(arr));
146 regs.arr().write(|r| r.set_arr(arr));
147 134
148 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 135 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
149 regs.egr().write(|r| r.set_ug(true)); 136 regs.egr().write(|r| r.set_ug(true));
150 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 137 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
151 }
152 } 138 }
153 } 139 }
154 }; 140 };
@@ -185,7 +171,7 @@ foreach_interrupt! {
185 171
186 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 172 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
187 fn regs_gp16() -> crate::pac::timer::TimGp16 { 173 fn regs_gp16() -> crate::pac::timer::TimGp16 {
188 crate::pac::timer::TimGp16(crate::pac::$inst.0) 174 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
189 } 175 }
190 } 176 }
191 177
@@ -206,7 +192,7 @@ foreach_interrupt! {
206 192
207 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 193 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
208 fn regs_gp16() -> crate::pac::timer::TimGp16 { 194 fn regs_gp16() -> crate::pac::timer::TimGp16 {
209 crate::pac::timer::TimGp16(crate::pac::$inst.0) 195 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
210 } 196 }
211 } 197 }
212 198
diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs
deleted file mode 100644
index 062377999..000000000
--- a/embassy-stm32/src/tl_mbox/ble.rs
+++ /dev/null
@@ -1,64 +0,0 @@
1use embassy_futures::block_on;
2
3use super::cmd::CmdSerial;
4use super::consts::TlPacketType;
5use super::evt::EvtBox;
6use super::unsafe_linked_list::LinkedListNode;
7use super::{
8 channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
9 TL_REF_TABLE,
10};
11use crate::tl_mbox::cmd::CmdPacket;
12use crate::tl_mbox::ipcc::Ipcc;
13
14pub struct Ble;
15
16impl Ble {
17 pub fn enable() {
18 unsafe {
19 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
20
21 TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
22 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
23 pcs_buffer: CS_BUFFER.as_mut_ptr().cast(),
24 pevt_queue: EVT_QUEUE.as_ptr().cast(),
25 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
26 });
27 }
28
29 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
30 }
31
32 pub fn evt_handler() {
33 unsafe {
34 let mut node_ptr = core::ptr::null_mut();
35 let node_ptr_ptr: *mut _ = &mut node_ptr;
36
37 while !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) {
38 LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
39
40 let event = node_ptr.cast();
41 let event = EvtBox::new(event);
42
43 block_on(TL_CHANNEL.send(event));
44 }
45 }
46
47 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
48 }
49
50 pub fn send_cmd(buf: &[u8]) {
51 unsafe {
52 let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
53 let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial;
54 let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
55
56 core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
57
58 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
59 cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
60 }
61
62 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
63 }
64}
diff --git a/embassy-stm32/src/tl_mbox/cmd.rs b/embassy-stm32/src/tl_mbox/cmd.rs
deleted file mode 100644
index 3507c3231..000000000
--- a/embassy-stm32/src/tl_mbox/cmd.rs
+++ /dev/null
@@ -1,49 +0,0 @@
1use super::PacketHeader;
2
3#[repr(C, packed)]
4#[derive(Copy, Clone)]
5pub struct Cmd {
6 pub cmd_code: u16,
7 pub payload_len: u8,
8 pub payload: [u8; 255],
9}
10
11impl Default for Cmd {
12 fn default() -> Self {
13 Self {
14 cmd_code: 0,
15 payload_len: 0,
16 payload: [0u8; 255],
17 }
18 }
19}
20
21#[repr(C, packed)]
22#[derive(Copy, Clone, Default)]
23pub struct CmdSerial {
24 pub ty: u8,
25 pub cmd: Cmd,
26}
27
28#[repr(C, packed)]
29#[derive(Copy, Clone, Default)]
30pub struct CmdPacket {
31 pub header: PacketHeader,
32 pub cmd_serial: CmdSerial,
33}
34
35#[repr(C, packed)]
36#[derive(Copy, Clone)]
37pub struct AclDataSerial {
38 pub ty: u8,
39 pub handle: u16,
40 pub length: u16,
41 pub acl_data: [u8; 1],
42}
43
44#[repr(C, packed)]
45#[derive(Copy, Clone)]
46pub struct AclDataPacket {
47 pub header: PacketHeader,
48 pub acl_data_serial: AclDataSerial,
49}
diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs
deleted file mode 100644
index 47a8b72fd..000000000
--- a/embassy-stm32/src/tl_mbox/evt.rs
+++ /dev/null
@@ -1,136 +0,0 @@
1use core::mem::MaybeUninit;
2
3use super::cmd::{AclDataPacket, AclDataSerial};
4use super::consts::TlPacketType;
5use super::{PacketHeader, TL_EVT_HEADER_SIZE};
6use crate::tl_mbox::mm::MemoryManager;
7
8/// the payload of [`Evt`] for a command status event
9#[derive(Copy, Clone)]
10#[repr(C, packed)]
11pub struct CsEvt {
12 pub status: u8,
13 pub num_cmd: u8,
14 pub cmd_code: u16,
15}
16
17/// the payload of [`Evt`] for a command complete event
18#[derive(Clone, Copy, Default)]
19#[repr(C, packed)]
20pub struct CcEvt {
21 pub num_cmd: u8,
22 pub cmd_code: u8,
23 pub payload: [u8; 1],
24}
25
26#[derive(Clone, Copy, Default)]
27#[repr(C, packed)]
28pub struct Evt {
29 pub evt_code: u8,
30 pub payload_len: u8,
31 pub payload: [u8; 1],
32}
33
34#[derive(Clone, Copy, Default)]
35#[repr(C, packed)]
36pub struct EvtSerial {
37 pub kind: u8,
38 pub evt: Evt,
39}
40
41/// This format shall be used for all events (asynchronous and command response) reported
42/// by the CPU2 except for the command response of a system command where the header is not there
43/// and the format to be used shall be `EvtSerial`.
44///
45/// ### Note:
46/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
47/// include the header and shall use `EvtPacket` format. Only the command response format on the
48/// system channel is different.
49#[derive(Clone, Copy, Default)]
50#[repr(C, packed)]
51pub struct EvtPacket {
52 pub header: PacketHeader,
53 pub evt_serial: EvtSerial,
54}
55
56/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop
57pub struct EvtBox {
58 ptr: *mut EvtPacket,
59}
60
61unsafe impl Send for EvtBox {}
62impl EvtBox {
63 pub(super) fn new(ptr: *mut EvtPacket) -> Self {
64 Self { ptr }
65 }
66
67 /// Copies the event data from inner pointer and returns and event structure
68 pub fn evt(&self) -> EvtPacket {
69 let mut evt = MaybeUninit::uninit();
70 unsafe {
71 self.ptr.copy_to(evt.as_mut_ptr(), 1);
72 evt.assume_init()
73 }
74 }
75
76 /// Returns the size of a buffer required to hold this event
77 pub fn size(&self) -> Result<usize, ()> {
78 unsafe {
79 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
80
81 if evt_kind == TlPacketType::AclData {
82 let acl_data: *const AclDataPacket = self.ptr.cast();
83 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
84
85 Ok((*acl_serial).length as usize + 5)
86 } else {
87 let evt_data: *const EvtPacket = self.ptr.cast();
88 let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
89
90 Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
91 }
92 }
93 }
94
95 /// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were
96 /// written. Returns an error if event kind is unkown or if provided buffer size is not enough
97 pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> {
98 unsafe {
99 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
100
101 let evt_data: *const EvtPacket = self.ptr.cast();
102 let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
103 let evt_serial_buf: *const u8 = evt_serial.cast();
104
105 let acl_data: *const AclDataPacket = self.ptr.cast();
106 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
107 let acl_serial_buf: *const u8 = acl_serial.cast();
108
109 if let TlPacketType::AclData = evt_kind {
110 let len = (*acl_serial).length as usize + 5;
111 if len > buf.len() {
112 return Err(());
113 }
114
115 core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
116
117 Ok(len)
118 } else {
119 let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
120 if len > buf.len() {
121 return Err(());
122 }
123
124 core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
125
126 Ok(len)
127 }
128 }
129 }
130}
131
132impl Drop for EvtBox {
133 fn drop(&mut self) {
134 MemoryManager::evt_drop(self.ptr);
135 }
136}
diff --git a/embassy-stm32/src/tl_mbox/ipcc.rs b/embassy-stm32/src/tl_mbox/ipcc.rs
deleted file mode 100644
index d1ac731ed..000000000
--- a/embassy-stm32/src/tl_mbox/ipcc.rs
+++ /dev/null
@@ -1,174 +0,0 @@
1use self::sealed::Instance;
2use crate::peripherals::IPCC;
3use crate::rcc::sealed::RccPeripheral;
4
5#[non_exhaustive]
6#[derive(Clone, Copy, Default)]
7pub struct Config {
8 // TODO: add IPCC peripheral configuration, if any, here
9 // reserved for future use
10}
11
12#[derive(Debug, Clone, Copy)]
13#[repr(C)]
14pub enum IpccChannel {
15 Channel1 = 0,
16 Channel2 = 1,
17 Channel3 = 2,
18 Channel4 = 3,
19 Channel5 = 4,
20 Channel6 = 5,
21}
22
23pub mod sealed {
24 pub trait Instance: crate::rcc::RccPeripheral {
25 fn regs() -> crate::pac::ipcc::Ipcc;
26 fn set_cpu2(enabled: bool);
27 }
28}
29
30pub struct Ipcc;
31
32impl Ipcc {
33 pub fn enable(_config: Config) {
34 IPCC::enable();
35 IPCC::reset();
36 IPCC::set_cpu2(true);
37
38 unsafe { _configure_pwr() };
39
40 let regs = IPCC::regs();
41
42 unsafe {
43 regs.cpu(0).cr().modify(|w| {
44 w.set_rxoie(true);
45 w.set_txfie(true);
46 })
47 }
48 }
49
50 pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) {
51 let regs = IPCC::regs();
52
53 // If bit is set to 1 then interrupt is disabled
54 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
55 }
56
57 pub fn c1_get_rx_channel(channel: IpccChannel) -> bool {
58 let regs = IPCC::regs();
59
60 // If bit is set to 1 then interrupt is disabled
61 unsafe { !regs.cpu(0).mr().read().chom(channel as usize) }
62 }
63
64 #[allow(dead_code)]
65 pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) {
66 let regs = IPCC::regs();
67
68 // If bit is set to 1 then interrupt is disabled
69 unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
70 }
71
72 #[allow(dead_code)]
73 pub fn c2_get_rx_channel(channel: IpccChannel) -> bool {
74 let regs = IPCC::regs();
75
76 // If bit is set to 1 then interrupt is disabled
77 unsafe { !regs.cpu(1).mr().read().chom(channel as usize) }
78 }
79
80 pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) {
81 let regs = IPCC::regs();
82
83 // If bit is set to 1 then interrupt is disabled
84 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
85 }
86
87 pub fn c1_get_tx_channel(channel: IpccChannel) -> bool {
88 let regs = IPCC::regs();
89
90 // If bit is set to 1 then interrupt is disabled
91 unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
92 }
93
94 #[allow(dead_code)]
95 pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) {
96 let regs = IPCC::regs();
97
98 // If bit is set to 1 then interrupt is disabled
99 unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
100 }
101
102 #[allow(dead_code)]
103 pub fn c2_get_tx_channel(channel: IpccChannel) -> bool {
104 let regs = IPCC::regs();
105
106 // If bit is set to 1 then interrupt is disabled
107 unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) }
108 }
109
110 /// clears IPCC receive channel status for CPU1
111 pub fn c1_clear_flag_channel(channel: IpccChannel) {
112 let regs = IPCC::regs();
113
114 unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
115 }
116
117 #[allow(dead_code)]
118 /// clears IPCC receive channel status for CPU2
119 pub fn c2_clear_flag_channel(channel: IpccChannel) {
120 let regs = IPCC::regs();
121
122 unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) }
123 }
124
125 pub fn c1_set_flag_channel(channel: IpccChannel) {
126 let regs = IPCC::regs();
127
128 unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
129 }
130
131 #[allow(dead_code)]
132 pub fn c2_set_flag_channel(channel: IpccChannel) {
133 let regs = IPCC::regs();
134
135 unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) }
136 }
137
138 pub fn c1_is_active_flag(channel: IpccChannel) -> bool {
139 let regs = IPCC::regs();
140
141 unsafe { regs.cpu(0).sr().read().chf(channel as usize) }
142 }
143
144 pub fn c2_is_active_flag(channel: IpccChannel) -> bool {
145 let regs = IPCC::regs();
146
147 unsafe { regs.cpu(1).sr().read().chf(channel as usize) }
148 }
149
150 pub fn is_tx_pending(channel: IpccChannel) -> bool {
151 !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel)
152 }
153
154 pub fn is_rx_pending(channel: IpccChannel) -> bool {
155 Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel)
156 }
157}
158
159impl sealed::Instance for crate::peripherals::IPCC {
160 fn regs() -> crate::pac::ipcc::Ipcc {
161 crate::pac::IPCC
162 }
163
164 fn set_cpu2(enabled: bool) {
165 unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
166 }
167}
168
169unsafe fn _configure_pwr() {
170 let rcc = crate::pac::RCC;
171
172 // set RF wake-up clock = LSE
173 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
174}
diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs
deleted file mode 100644
index e28a6aa0c..000000000
--- a/embassy-stm32/src/tl_mbox/mm.rs
+++ /dev/null
@@ -1,67 +0,0 @@
1use super::evt::EvtPacket;
2use super::unsafe_linked_list::LinkedListNode;
3use super::{
4 channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
5 SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
6};
7use crate::tl_mbox::ipcc::Ipcc;
8
9pub struct MemoryManager;
10
11impl MemoryManager {
12 pub fn enable() {
13 unsafe {
14 LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
15 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
16
17 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
18 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
19 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
20 ble_pool: EVT_POOL.as_ptr().cast(),
21 ble_pool_size: POOL_SIZE as u32,
22 pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(),
23 traces_evt_pool: core::ptr::null(),
24 traces_pool_size: 0,
25 });
26 }
27 }
28
29 pub fn evt_handler() {
30 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
31 Self::send_free_buf();
32 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
33 }
34
35 pub fn evt_drop(evt: *mut EvtPacket) {
36 unsafe {
37 let list_node = evt.cast();
38
39 LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
40 }
41
42 let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
43
44 // postpone event buffer freeing to IPCC interrupt handler
45 if channel_is_busy {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
47 } else {
48 Self::send_free_buf();
49 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
50 }
51 }
52
53 fn send_free_buf() {
54 unsafe {
55 let mut node_ptr = core::ptr::null_mut();
56 let node_ptr_ptr: *mut _ = &mut node_ptr;
57
58 while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
59 LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
60 LinkedListNode::insert_tail(
61 (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
62 node_ptr,
63 );
64 }
65 }
66 }
67}
diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs
deleted file mode 100644
index 616f7dc56..000000000
--- a/embassy-stm32/src/tl_mbox/mod.rs
+++ /dev/null
@@ -1,417 +0,0 @@
1use core::mem::MaybeUninit;
2
3use atomic_polyfill::{compiler_fence, Ordering};
4use bit_field::BitField;
5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
6use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::Channel;
9
10use self::ble::Ble;
11use self::cmd::{AclDataPacket, CmdPacket};
12use self::evt::{CsEvt, EvtBox};
13use self::mm::MemoryManager;
14use self::shci::{shci_ble_init, ShciBleInitCmdParam};
15use self::sys::Sys;
16use self::unsafe_linked_list::LinkedListNode;
17use crate::interrupt;
18use crate::peripherals::IPCC;
19pub use crate::tl_mbox::ipcc::Config;
20use crate::tl_mbox::ipcc::Ipcc;
21
22mod ble;
23mod channels;
24mod cmd;
25mod consts;
26mod evt;
27mod ipcc;
28mod mm;
29mod shci;
30mod sys;
31mod unsafe_linked_list;
32
33pub type PacketHeader = LinkedListNode;
34
35const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
36const TL_EVT_HEADER_SIZE: usize = 3;
37const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
38
39const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
40const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
41const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
42
43const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
44
45const fn divc(x: usize, y: usize) -> usize {
46 (x + y - 1) / y
47}
48
49#[repr(C, packed)]
50#[derive(Copy, Clone)]
51pub struct SafeBootInfoTable {
52 version: u32,
53}
54
55#[repr(C, packed)]
56#[derive(Copy, Clone)]
57pub struct FusInfoTable {
58 version: u32,
59 memory_size: u32,
60 fus_info: u32,
61}
62
63/// Interrupt handler.
64pub struct ReceiveInterruptHandler {}
65
66impl interrupt::Handler<interrupt::IPCC_C1_RX> for ReceiveInterruptHandler {
67 unsafe fn on_interrupt() {
68 // info!("ipcc rx interrupt");
69
70 if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
71 sys::Sys::evt_handler();
72 } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
73 ble::Ble::evt_handler();
74 } else {
75 todo!()
76 }
77 }
78}
79
80pub struct TransmitInterruptHandler {}
81
82impl interrupt::Handler<interrupt::IPCC_C1_TX> for TransmitInterruptHandler {
83 unsafe fn on_interrupt() {
84 // info!("ipcc tx interrupt");
85
86 if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
87 // TODO: handle this case
88 let _ = sys::Sys::cmd_evt_handler();
89 } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
90 mm::MemoryManager::evt_handler();
91 } else {
92 todo!()
93 }
94 }
95}
96
97/// # Version
98/// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version
99/// - 4 -> 7 = branch - 0: Mass Market - x: ...
100/// - 8 -> 15 = Subversion
101/// - 16 -> 23 = Version minor
102/// - 24 -> 31 = Version major
103/// # Memory Size
104/// - 0 -> 7 = Flash ( Number of 4k sector)
105/// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension )
106/// - 16 -> 23 = SRAM2b ( Number of 1k sector)
107/// - 24 -> 31 = SRAM2a ( Number of 1k sector)
108#[repr(C, packed)]
109#[derive(Copy, Clone)]
110pub struct WirelessFwInfoTable {
111 version: u32,
112 memory_size: u32,
113 info_stack: u32,
114 reserved: u32,
115}
116
117impl WirelessFwInfoTable {
118 pub fn version_major(&self) -> u8 {
119 let version = self.version;
120 (version.get_bits(24..31) & 0xff) as u8
121 }
122
123 pub fn version_minor(&self) -> u8 {
124 let version = self.version;
125 (version.get_bits(16..23) & 0xff) as u8
126 }
127
128 pub fn subversion(&self) -> u8 {
129 let version = self.version;
130 (version.get_bits(8..15) & 0xff) as u8
131 }
132
133 /// size of FLASH, expressed in number of 4K sectors
134 pub fn flash_size(&self) -> u8 {
135 let memory_size = self.memory_size;
136 (memory_size.get_bits(0..7) & 0xff) as u8
137 }
138
139 /// size for SRAM2a, expressed in number of 1K sectors
140 pub fn sram2a_size(&self) -> u8 {
141 let memory_size = self.memory_size;
142 (memory_size.get_bits(24..31) & 0xff) as u8
143 }
144
145 /// size of SRAM2b, expressed in number of 1K sectors
146 pub fn sram2b_size(&self) -> u8 {
147 let memory_size = self.memory_size;
148 (memory_size.get_bits(16..23) & 0xff) as u8
149 }
150}
151
152#[repr(C, packed)]
153#[derive(Copy, Clone)]
154pub struct DeviceInfoTable {
155 pub safe_boot_info_table: SafeBootInfoTable,
156 pub fus_info_table: FusInfoTable,
157 pub wireless_fw_info_table: WirelessFwInfoTable,
158}
159
160#[repr(C, packed)]
161struct BleTable {
162 pcmd_buffer: *mut CmdPacket,
163 pcs_buffer: *const u8,
164 pevt_queue: *const u8,
165 phci_acl_data_buffer: *mut AclDataPacket,
166}
167
168#[repr(C, packed)]
169struct ThreadTable {
170 no_stack_buffer: *const u8,
171 cli_cmd_rsp_buffer: *const u8,
172 ot_cmd_rsp_buffer: *const u8,
173}
174
175#[repr(C, packed)]
176struct SysTable {
177 pcmd_buffer: *mut CmdPacket,
178 sys_queue: *const LinkedListNode,
179}
180
181#[allow(dead_code)] // Not used currently but reserved
182#[repr(C, packed)]
183struct LldTestTable {
184 cli_cmd_rsp_buffer: *const u8,
185 m0_cmd_buffer: *const u8,
186}
187
188#[allow(dead_code)] // Not used currently but reserved
189#[repr(C, packed)]
190struct BleLldTable {
191 cmd_rsp_buffer: *const u8,
192 m0_cmd_buffer: *const u8,
193}
194
195#[allow(dead_code)] // Not used currently but reserved
196#[repr(C, packed)]
197struct ZigbeeTable {
198 notif_m0_to_m4_buffer: *const u8,
199 appli_cmd_m4_to_m0_buffer: *const u8,
200 request_m0_to_m4_buffer: *const u8,
201}
202
203#[repr(C, packed)]
204struct MemManagerTable {
205 spare_ble_buffer: *const u8,
206 spare_sys_buffer: *const u8,
207
208 ble_pool: *const u8,
209 ble_pool_size: u32,
210
211 pevt_free_buffer_queue: *mut LinkedListNode,
212
213 traces_evt_pool: *const u8,
214 traces_pool_size: u32,
215}
216
217#[repr(C, packed)]
218struct TracesTable {
219 traces_queue: *const u8,
220}
221
222#[repr(C, packed)]
223struct Mac802_15_4Table {
224 pcmd_rsp_buffer: *const u8,
225 pnotack_buffer: *const u8,
226 evt_queue: *const u8,
227}
228
229/// reference table. Contains pointers to all other tables
230#[repr(C, packed)]
231#[derive(Copy, Clone)]
232pub struct RefTable {
233 pub device_info_table: *const DeviceInfoTable,
234 ble_table: *const BleTable,
235 thread_table: *const ThreadTable,
236 sys_table: *const SysTable,
237 mem_manager_table: *const MemManagerTable,
238 traces_table: *const TracesTable,
239 mac_802_15_4_table: *const Mac802_15_4Table,
240 zigbee_table: *const ZigbeeTable,
241 lld_tests_table: *const LldTestTable,
242 ble_lld_table: *const BleLldTable,
243}
244
245#[link_section = "TL_REF_TABLE"]
246pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
247
248#[link_section = "MB_MEM1"]
249static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
250
251#[link_section = "MB_MEM1"]
252static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
253
254#[link_section = "MB_MEM1"]
255static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
256
257#[link_section = "MB_MEM1"]
258static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
259
260#[link_section = "MB_MEM1"]
261static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
262
263#[link_section = "MB_MEM1"]
264static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
265
266#[link_section = "MB_MEM1"]
267static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
268
269#[link_section = "MB_MEM1"]
270static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
271
272#[link_section = "MB_MEM1"]
273static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
274
275#[link_section = "MB_MEM1"]
276static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
277
278#[allow(dead_code)] // Not used currently but reserved
279#[link_section = "MB_MEM1"]
280static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
281
282// not in shared RAM
283static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
284
285#[link_section = "MB_MEM2"]
286static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
287 MaybeUninit::uninit();
288
289#[link_section = "MB_MEM2"]
290static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
291
292#[link_section = "MB_MEM2"]
293static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
294
295#[link_section = "MB_MEM2"]
296static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
297
298#[link_section = "MB_MEM2"]
299static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
300
301#[link_section = "MB_MEM2"]
302static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
303 MaybeUninit::uninit();
304
305#[link_section = "MB_MEM2"]
306static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
307 MaybeUninit::uninit();
308
309#[link_section = "MB_MEM2"]
310static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
311
312#[link_section = "MB_MEM2"]
313// "magic" numbers from ST ---v---v
314static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
315
316// TODO: get a better size, this is a placeholder
317pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
318
319pub struct TlMbox<'d> {
320 _ipcc: PeripheralRef<'d, IPCC>,
321}
322
323impl<'d> TlMbox<'d> {
324 /// initializes low-level transport between CPU1 and BLE stack on CPU2
325 pub fn new(
326 ipcc: impl Peripheral<P = IPCC> + 'd,
327 _irqs: impl interrupt::Binding<interrupt::IPCC_C1_RX, ReceiveInterruptHandler>
328 + interrupt::Binding<interrupt::IPCC_C1_TX, TransmitInterruptHandler>,
329 config: Config,
330 ) -> Self {
331 into_ref!(ipcc);
332
333 unsafe {
334 compiler_fence(Ordering::AcqRel);
335
336 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
337 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
338 ble_table: TL_BLE_TABLE.as_ptr(),
339 thread_table: TL_THREAD_TABLE.as_ptr(),
340 sys_table: TL_SYS_TABLE.as_ptr(),
341 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
342 traces_table: TL_TRACES_TABLE.as_ptr(),
343 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
344 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
345 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
346 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
347 });
348
349 // info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize);
350
351 compiler_fence(Ordering::AcqRel);
352
353 TL_SYS_TABLE = MaybeUninit::zeroed();
354 TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
355 TL_BLE_TABLE = MaybeUninit::zeroed();
356 TL_THREAD_TABLE = MaybeUninit::zeroed();
357 TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
358 TL_TRACES_TABLE = MaybeUninit::zeroed();
359 TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
360 TL_ZIGBEE_TABLE = MaybeUninit::zeroed();
361 TL_LLD_TESTS_TABLE = MaybeUninit::zeroed();
362 TL_BLE_LLD_TABLE = MaybeUninit::zeroed();
363
364 EVT_POOL = MaybeUninit::zeroed();
365 SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
366 BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
367
368 CS_BUFFER = MaybeUninit::zeroed();
369 BLE_CMD_BUFFER = MaybeUninit::zeroed();
370 HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
371
372 compiler_fence(Ordering::AcqRel);
373 }
374
375 Ipcc::enable(config);
376
377 Sys::enable();
378 Ble::enable();
379 MemoryManager::enable();
380
381 // enable interrupts
382 unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend();
383 unsafe { crate::interrupt::IPCC_C1_TX::steal() }.unpend();
384
385 unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable();
386 unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable();
387
388 Self { _ipcc: ipcc }
389 }
390
391 pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
392 let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
393
394 // zero version indicates that CPU2 wasn't active and didn't fill the information table
395 if info.version != 0 {
396 Some(*info)
397 } else {
398 None
399 }
400 }
401
402 pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) {
403 shci_ble_init(param);
404 }
405
406 pub fn send_ble_cmd(&self, buf: &[u8]) {
407 ble::Ble::send_cmd(buf);
408 }
409
410 // pub fn send_sys_cmd(&self, buf: &[u8]) {
411 // sys::Sys::send_cmd(buf);
412 // }
413
414 pub async fn read(&self) -> EvtBox {
415 TL_CHANNEL.recv().await
416 }
417}
diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs
deleted file mode 100644
index 9685fb920..000000000
--- a/embassy-stm32/src/tl_mbox/sys.rs
+++ /dev/null
@@ -1,83 +0,0 @@
1use embassy_futures::block_on;
2
3use super::cmd::{CmdPacket, CmdSerial};
4use super::consts::TlPacketType;
5use super::evt::{CcEvt, EvtBox, EvtSerial};
6use super::unsafe_linked_list::LinkedListNode;
7use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
8use crate::tl_mbox::ipcc::Ipcc;
9
10pub struct Sys;
11
12impl Sys {
13 pub fn enable() {
14 unsafe {
15 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
16
17 TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
18 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
19 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
20 });
21 }
22
23 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
24 }
25
26 pub fn evt_handler() {
27 unsafe {
28 let mut node_ptr = core::ptr::null_mut();
29 let node_ptr_ptr: *mut _ = &mut node_ptr;
30
31 while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
32 LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
33
34 let event = node_ptr.cast();
35 let event = EvtBox::new(event);
36
37 // TODO: not really happy about this
38 block_on(TL_CHANNEL.send(event));
39 }
40 }
41
42 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
43 }
44
45 pub fn cmd_evt_handler() -> CcEvt {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
47
48 // ST's command response data structure is really convoluted.
49 //
50 // for command response events on SYS channel, the header is missing
51 // and one should:
52 // 1. interpret the content of CMD_BUFFER as CmdPacket
53 // 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
54 // 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
55 // 4. CcEvt type is the actual SHCI response
56 // 5. profit
57 unsafe {
58 let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
59 let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial;
60 let evt_serial: *const EvtSerial = cmd_serial.cast();
61 let cc = (*evt_serial).evt.payload.as_ptr().cast();
62 *cc
63 }
64 }
65
66 #[allow(dead_code)]
67 pub fn send_cmd(buf: &[u8]) {
68 unsafe {
69 // TODO: check this
70 let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
71 let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial;
72 let cmd_serial_buf = cmd_serial.cast();
73
74 core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
75
76 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
77 cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8;
78
79 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
80 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
81 }
82 }
83}
diff --git a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs b/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs
deleted file mode 100644
index 482e2bf5a..000000000
--- a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs
+++ /dev/null
@@ -1,125 +0,0 @@
1//! Unsafe linked list.
2//! Translated from ST's C by `c2rust` tool.
3
4#![allow(
5 dead_code,
6 mutable_transmutes,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals,
10 unused_assignments,
11 unused_mut
12)]
13
14use cortex_m::interrupt;
15
16#[derive(Copy, Clone)]
17#[repr(C, packed(4))]
18pub struct LinkedListNode {
19 pub next: *mut LinkedListNode,
20 pub prev: *mut LinkedListNode,
21}
22
23impl Default for LinkedListNode {
24 fn default() -> Self {
25 LinkedListNode {
26 next: core::ptr::null_mut(),
27 prev: core::ptr::null_mut(),
28 }
29 }
30}
31
32impl LinkedListNode {
33 pub unsafe fn init_head(mut list_head: *mut LinkedListNode) {
34 (*list_head).next = list_head;
35 (*list_head).prev = list_head;
36 }
37
38 pub unsafe fn is_empty(mut list_head: *mut LinkedListNode) -> bool {
39 interrupt::free(|_| ((*list_head).next) == list_head)
40 }
41
42 pub unsafe fn insert_head(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
43 interrupt::free(|_| {
44 (*node).next = (*list_head).next;
45 (*node).prev = list_head;
46 (*list_head).next = node;
47 (*(*node).next).prev = node;
48 });
49 }
50
51 pub unsafe fn insert_tail(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
52 interrupt::free(|_| {
53 (*node).next = list_head;
54 (*node).prev = (*list_head).prev;
55 (*list_head).prev = node;
56 (*(*node).prev).next = node;
57 });
58 }
59
60 pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
61 interrupt::free(|_| {
62 (*(*node).prev).next = (*node).next;
63 (*(*node).next).prev = (*node).prev;
64 });
65 }
66
67 pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
68 interrupt::free(|_| {
69 *node = (*list_head).next;
70 Self::remove_node((*list_head).next);
71 });
72 }
73
74 pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
75 interrupt::free(|_| {
76 *node = (*list_head).prev;
77 Self::remove_node((*list_head).prev);
78 });
79 }
80
81 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
82 interrupt::free(|_| {
83 (*node).next = (*ref_node).next;
84 (*node).prev = ref_node;
85 (*ref_node).next = node;
86 (*(*node).next).prev = node;
87 });
88 }
89
90 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
91 interrupt::free(|_| {
92 (*node).next = ref_node;
93 (*node).prev = (*ref_node).prev;
94 (*ref_node).prev = node;
95 (*(*node).prev).next = node;
96 });
97 }
98
99 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
100 interrupt::free(|_| {
101 let mut size = 0;
102 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
103
104 temp = (*list_head).next;
105 while temp != list_head {
106 size += 1;
107 temp = (*temp).next
108 }
109
110 size
111 })
112 }
113
114 pub unsafe fn get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
115 interrupt::free(|_| {
116 *node = (*ref_node).next;
117 });
118 }
119
120 pub unsafe fn get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
121 interrupt::free(|_| {
122 *node = (*ref_node).prev;
123 });
124 }
125}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 9f1da3583..433ad299c 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -2,79 +2,81 @@ use core::future::poll_fn;
2use core::slice; 2use core::slice;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::atomic_ring_buffer::RingBuffer; 5use embassy_hal_common::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8 7
9use super::*; 8use super::*;
9use crate::interrupt::typelevel::Interrupt;
10 10
11/// Interrupt handler. 11/// Interrupt handler.
12pub struct InterruptHandler<T: BasicInstance> { 12pub struct InterruptHandler<T: BasicInstance> {
13 _phantom: PhantomData<T>, 13 _phantom: PhantomData<T>,
14} 14}
15 15
16impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 16impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
17 unsafe fn on_interrupt() { 17 unsafe fn on_interrupt() {
18 let r = T::regs(); 18 let r = T::regs();
19 let state = T::buffered_state(); 19 let state = T::buffered_state();
20 20
21 // RX 21 // RX
22 unsafe { 22 let sr_val = sr(r).read();
23 let sr = sr(r).read(); 23 // On v1 & v2, reading DR clears the rxne, error and idle interrupt
24 clear_interrupt_flags(r, sr); 24 // flags. Keep this close to the SR read to reduce the chance of a
25 25 // flag being set in-between.
26 if sr.rxne() { 26 let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
27 if sr.pe() { 27 Some(rdr(r).read_volatile())
28 warn!("Parity error"); 28 } else {
29 } 29 None
30 if sr.fe() { 30 };
31 warn!("Framing error"); 31 clear_interrupt_flags(r, sr_val);
32 } 32
33 if sr.ne() { 33 if sr_val.pe() {
34 warn!("Noise error"); 34 warn!("Parity error");
35 } 35 }
36 if sr.ore() { 36 if sr_val.fe() {
37 warn!("Overrun error"); 37 warn!("Framing error");
38 } 38 }
39 39 if sr_val.ne() {
40 let mut rx_writer = state.rx_buf.writer(); 40 warn!("Noise error");
41 let buf = rx_writer.push_slice(); 41 }
42 if !buf.is_empty() { 42 if sr_val.ore() {
43 // This read also clears the error and idle interrupt flags on v1. 43 warn!("Overrun error");
44 buf[0] = rdr(r).read_volatile(); 44 }
45 rx_writer.push_done(1); 45 if sr_val.rxne() {
46 } else { 46 let mut rx_writer = state.rx_buf.writer();
47 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 47 let buf = rx_writer.push_slice();
48 } 48 if !buf.is_empty() {
49 49 buf[0] = dr.unwrap();
50 if state.rx_buf.is_full() { 50 rx_writer.push_done(1);
51 state.rx_waker.wake(); 51 } else {
52 } 52 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
53 } 53 }
54 54
55 if sr.idle() { 55 if state.rx_buf.is_full() {
56 state.rx_waker.wake(); 56 state.rx_waker.wake();
57 }; 57 }
58 }
59
60 if sr_val.idle() {
61 state.rx_waker.wake();
58 } 62 }
59 63
60 // TX 64 // TX
61 unsafe { 65 if sr(r).read().txe() {
62 if sr(r).read().txe() { 66 let mut tx_reader = state.tx_buf.reader();
63 let mut tx_reader = state.tx_buf.reader(); 67 let buf = tx_reader.pop_slice();
64 let buf = tx_reader.pop_slice(); 68 if !buf.is_empty() {
65 if !buf.is_empty() { 69 r.cr1().modify(|w| {
66 r.cr1().modify(|w| { 70 w.set_txeie(true);
67 w.set_txeie(true); 71 });
68 }); 72 tdr(r).write_volatile(buf[0].into());
69 tdr(r).write_volatile(buf[0].into()); 73 tx_reader.pop_done(1);
70 tx_reader.pop_done(1); 74 state.tx_waker.wake();
71 state.tx_waker.wake(); 75 } else {
72 } else { 76 // Disable interrupt until we have something to transmit again
73 // Disable interrupt until we have something to transmit again 77 r.cr1().modify(|w| {
74 r.cr1().modify(|w| { 78 w.set_txeie(false);
75 w.set_txeie(false); 79 });
76 });
77 }
78 } 80 }
79 } 81 }
80 } 82 }
@@ -115,7 +117,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
115impl<'d, T: BasicInstance> BufferedUart<'d, T> { 117impl<'d, T: BasicInstance> BufferedUart<'d, T> {
116 pub fn new( 118 pub fn new(
117 peri: impl Peripheral<P = T> + 'd, 119 peri: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 120 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 121 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
120 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 122 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
121 tx_buffer: &'d mut [u8], 123 tx_buffer: &'d mut [u8],
@@ -130,7 +132,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
130 132
131 pub fn new_with_rtscts( 133 pub fn new_with_rtscts(
132 peri: impl Peripheral<P = T> + 'd, 134 peri: impl Peripheral<P = T> + 'd,
133 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 135 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
134 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 136 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
135 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 137 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
136 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 138 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
@@ -144,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
144 T::enable(); 146 T::enable();
145 T::reset(); 147 T::reset();
146 148
147 unsafe { 149 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
148 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 150 cts.set_as_af(cts.af_num(), AFType::Input);
149 cts.set_as_af(cts.af_num(), AFType::Input); 151 T::regs().cr3().write(|w| {
150 T::regs().cr3().write(|w| { 152 w.set_rtse(true);
151 w.set_rtse(true); 153 w.set_ctse(true);
152 w.set_ctse(true); 154 });
153 });
154 }
155 155
156 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 156 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
157 } 157 }
@@ -159,7 +159,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
159 #[cfg(not(any(usart_v1, usart_v2)))] 159 #[cfg(not(any(usart_v1, usart_v2)))]
160 pub fn new_with_de( 160 pub fn new_with_de(
161 peri: impl Peripheral<P = T> + 'd, 161 peri: impl Peripheral<P = T> + 'd,
162 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 162 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
163 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 163 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
164 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 164 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
165 de: impl Peripheral<P = impl DePin<T>> + 'd, 165 de: impl Peripheral<P = impl DePin<T>> + 'd,
@@ -172,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
172 T::enable(); 172 T::enable();
173 T::reset(); 173 T::reset();
174 174
175 unsafe { 175 de.set_as_af(de.af_num(), AFType::OutputPushPull);
176 de.set_as_af(de.af_num(), AFType::OutputPushPull); 176 T::regs().cr3().write(|w| {
177 T::regs().cr3().write(|w| { 177 w.set_dem(true);
178 w.set_dem(true); 178 });
179 });
180 }
181 179
182 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 180 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
183 } 181 }
@@ -199,25 +197,21 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
199 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 197 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
200 198
201 let r = T::regs(); 199 let r = T::regs();
202 unsafe { 200 rx.set_as_af(rx.af_num(), AFType::Input);
203 rx.set_as_af(rx.af_num(), AFType::Input); 201 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
204 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
205 }
206 202
207 configure(r, &config, T::frequency(), T::KIND, true, true); 203 configure(r, &config, T::frequency(), T::KIND, true, true);
208 204
209 unsafe { 205 r.cr1().modify(|w| {
210 r.cr1().modify(|w| { 206 #[cfg(lpuart_v2)]
211 #[cfg(lpuart_v2)] 207 w.set_fifoen(true);
212 w.set_fifoen(true);
213 208
214 w.set_rxneie(true); 209 w.set_rxneie(true);
215 w.set_idleie(true); 210 w.set_idleie(true);
216 }); 211 });
217 }
218 212
219 unsafe { T::Interrupt::steal() }.unpend(); 213 T::Interrupt::unpend();
220 unsafe { T::Interrupt::steal() }.enable(); 214 unsafe { T::Interrupt::enable() };
221 215
222 Self { 216 Self {
223 rx: BufferedUartRx { phantom: PhantomData }, 217 rx: BufferedUartRx { phantom: PhantomData },
@@ -245,7 +239,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
245 rx_reader.pop_done(len); 239 rx_reader.pop_done(len);
246 240
247 if do_pend { 241 if do_pend {
248 unsafe { T::Interrupt::steal().pend() }; 242 T::Interrupt::pend();
249 } 243 }
250 244
251 return Poll::Ready(Ok(len)); 245 return Poll::Ready(Ok(len));
@@ -271,7 +265,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
271 rx_reader.pop_done(len); 265 rx_reader.pop_done(len);
272 266
273 if do_pend { 267 if do_pend {
274 unsafe { T::Interrupt::steal().pend() }; 268 T::Interrupt::pend();
275 } 269 }
276 270
277 return Ok(len); 271 return Ok(len);
@@ -301,7 +295,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
301 let full = state.rx_buf.is_full(); 295 let full = state.rx_buf.is_full();
302 rx_reader.pop_done(amt); 296 rx_reader.pop_done(amt);
303 if full { 297 if full {
304 unsafe { T::Interrupt::steal().pend() }; 298 T::Interrupt::pend();
305 } 299 }
306 } 300 }
307} 301}
@@ -324,7 +318,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
324 tx_writer.push_done(n); 318 tx_writer.push_done(n);
325 319
326 if empty { 320 if empty {
327 unsafe { T::Interrupt::steal() }.pend(); 321 T::Interrupt::pend();
328 } 322 }
329 323
330 Poll::Ready(Ok(n)) 324 Poll::Ready(Ok(n))
@@ -358,7 +352,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
358 tx_writer.push_done(n); 352 tx_writer.push_done(n);
359 353
360 if empty { 354 if empty {
361 unsafe { T::Interrupt::steal() }.pend(); 355 T::Interrupt::pend();
362 } 356 }
363 357
364 return Ok(n); 358 return Ok(n);
@@ -385,7 +379,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
385 // TX is inactive if the the buffer is not available. 379 // TX is inactive if the the buffer is not available.
386 // We can now unregister the interrupt handler 380 // We can now unregister the interrupt handler
387 if state.tx_buf.len() == 0 { 381 if state.tx_buf.len() == 0 {
388 T::Interrupt::steal().disable(); 382 T::Interrupt::disable();
389 } 383 }
390 } 384 }
391 } 385 }
@@ -400,7 +394,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
400 // RX is inactive if the the buffer is not available. 394 // RX is inactive if the the buffer is not available.
401 // We can now unregister the interrupt handler 395 // We can now unregister the interrupt handler
402 if state.rx_buf.len() == 0 { 396 if state.rx_buf.len() == 0 {
403 T::Interrupt::steal().disable(); 397 T::Interrupt::disable();
404 } 398 }
405 } 399 }
406 } 400 }
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 05ccb8749..47a79c187 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -5,13 +5,13 @@ use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_hal_common::drop::OnDrop; 8use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
11use futures::future::{select, Either}; 10use futures::future::{select, Either};
12 11
13use crate::dma::{NoDma, Transfer}; 12use crate::dma::{NoDma, Transfer};
14use crate::gpio::sealed::AFType; 13use crate::gpio::sealed::AFType;
14use crate::interrupt::typelevel::Interrupt;
15#[cfg(not(any(usart_v1, usart_v2)))] 15#[cfg(not(any(usart_v1, usart_v2)))]
16#[allow(unused_imports)] 16#[allow(unused_imports)]
17use crate::pac::usart::regs::Isr as Sr; 17use crate::pac::usart::regs::Isr as Sr;
@@ -31,40 +31,36 @@ pub struct InterruptHandler<T: BasicInstance> {
31 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
32} 32}
33 33
34impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 34impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
35 unsafe fn on_interrupt() { 35 unsafe fn on_interrupt() {
36 let r = T::regs(); 36 let r = T::regs();
37 let s = T::state(); 37 let s = T::state();
38 38
39 let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; 39 let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read());
40 40
41 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); 41 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
42 if has_errors { 42 if has_errors {
43 // clear all interrupts and DMA Rx Request 43 // clear all interrupts and DMA Rx Request
44 unsafe { 44 r.cr1().modify(|w| {
45 r.cr1().modify(|w| { 45 // disable RXNE interrupt
46 // disable RXNE interrupt 46 w.set_rxneie(false);
47 w.set_rxneie(false); 47 // disable parity interrupt
48 // disable parity interrupt 48 w.set_peie(false);
49 w.set_peie(false); 49 // disable idle line interrupt
50 // disable idle line interrupt 50 w.set_idleie(false);
51 w.set_idleie(false); 51 });
52 }); 52 r.cr3().modify(|w| {
53 r.cr3().modify(|w| { 53 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
54 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 54 w.set_eie(false);
55 w.set_eie(false); 55 // disable DMA Rx Request
56 // disable DMA Rx Request 56 w.set_dmar(false);
57 w.set_dmar(false); 57 });
58 });
59 }
60 } else if cr1.idleie() && sr.idle() { 58 } else if cr1.idleie() && sr.idle() {
61 // IDLE detected: no more data will come 59 // IDLE detected: no more data will come
62 unsafe { 60 r.cr1().modify(|w| {
63 r.cr1().modify(|w| { 61 // disable idle line detection
64 // disable idle line detection 62 w.set_idleie(false);
65 w.set_idleie(false); 63 });
66 });
67 }
68 } else if cr1.rxneie() { 64 } else if cr1.rxneie() {
69 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller 65 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller
70 66
@@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
205 T::enable(); 201 T::enable();
206 T::reset(); 202 T::reset();
207 203
208 unsafe { 204 cts.set_as_af(cts.af_num(), AFType::Input);
209 cts.set_as_af(cts.af_num(), AFType::Input); 205 T::regs().cr3().write(|w| {
210 T::regs().cr3().write(|w| { 206 w.set_ctse(true);
211 w.set_ctse(true); 207 });
212 });
213 }
214 Self::new_inner(peri, tx, tx_dma, config) 208 Self::new_inner(peri, tx, tx_dma, config)
215 } 209 }
216 210
@@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
224 218
225 let r = T::regs(); 219 let r = T::regs();
226 220
227 unsafe { 221 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
228 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
229 }
230 222
231 configure(r, &config, T::frequency(), T::KIND, false, true); 223 configure(r, &config, T::frequency(), T::KIND, false, true);
232 224
@@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
245 { 237 {
246 let ch = &mut self.tx_dma; 238 let ch = &mut self.tx_dma;
247 let request = ch.request(); 239 let request = ch.request();
248 unsafe { 240 T::regs().cr3().modify(|reg| {
249 T::regs().cr3().modify(|reg| { 241 reg.set_dmat(true);
250 reg.set_dmat(true); 242 });
251 });
252 }
253 // If we don't assign future to a variable, the data register pointer 243 // If we don't assign future to a variable, the data register pointer
254 // is held across an await and makes the future non-Send. 244 // is held across an await and makes the future non-Send.
255 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; 245 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
@@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
258 } 248 }
259 249
260 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 250 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
261 unsafe { 251 let r = T::regs();
262 let r = T::regs(); 252 for &b in buffer {
263 for &b in buffer { 253 while !sr(r).read().txe() {}
264 while !sr(r).read().txe() {} 254 unsafe { tdr(r).write_volatile(b) };
265 tdr(r).write_volatile(b);
266 }
267 } 255 }
268 Ok(()) 256 Ok(())
269 } 257 }
270 258
271 pub fn blocking_flush(&mut self) -> Result<(), Error> { 259 pub fn blocking_flush(&mut self) -> Result<(), Error> {
272 unsafe { 260 let r = T::regs();
273 let r = T::regs(); 261 while !sr(r).read().tc() {}
274 while !sr(r).read().tc() {}
275 }
276 Ok(()) 262 Ok(())
277 } 263 }
278} 264}
@@ -281,7 +267,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
281 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 267 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
282 pub fn new( 268 pub fn new(
283 peri: impl Peripheral<P = T> + 'd, 269 peri: impl Peripheral<P = T> + 'd,
284 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 270 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
285 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 271 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
286 rx_dma: impl Peripheral<P = RxDma> + 'd, 272 rx_dma: impl Peripheral<P = RxDma> + 'd,
287 config: Config, 273 config: Config,
@@ -294,7 +280,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
294 280
295 pub fn new_with_rts( 281 pub fn new_with_rts(
296 peri: impl Peripheral<P = T> + 'd, 282 peri: impl Peripheral<P = T> + 'd,
297 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 283 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
298 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 284 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
299 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 285 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
300 rx_dma: impl Peripheral<P = RxDma> + 'd, 286 rx_dma: impl Peripheral<P = RxDma> + 'd,
@@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
305 T::enable(); 291 T::enable();
306 T::reset(); 292 T::reset();
307 293
308 unsafe { 294 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
309 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 295 T::regs().cr3().write(|w| {
310 T::regs().cr3().write(|w| { 296 w.set_rtse(true);
311 w.set_rtse(true); 297 });
312 });
313 }
314 298
315 Self::new_inner(peri, rx, rx_dma, config) 299 Self::new_inner(peri, rx, rx_dma, config)
316 } 300 }
@@ -325,14 +309,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
325 309
326 let r = T::regs(); 310 let r = T::regs();
327 311
328 unsafe { 312 rx.set_as_af(rx.af_num(), AFType::Input);
329 rx.set_as_af(rx.af_num(), AFType::Input);
330 }
331 313
332 configure(r, &config, T::frequency(), T::KIND, true, false); 314 configure(r, &config, T::frequency(), T::KIND, true, false);
333 315
334 unsafe { T::Interrupt::steal() }.unpend(); 316 T::Interrupt::unpend();
335 unsafe { T::Interrupt::steal() }.enable(); 317 unsafe { T::Interrupt::enable() };
336 318
337 // create state once! 319 // create state once!
338 let _s = T::state(); 320 let _s = T::state();
@@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
347 } 329 }
348 330
349 #[cfg(any(usart_v1, usart_v2))] 331 #[cfg(any(usart_v1, usart_v2))]
350 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { 332 fn check_rx_flags(&mut self) -> Result<bool, Error> {
351 let r = T::regs(); 333 let r = T::regs();
352 loop { 334 loop {
353 // Handle all buffered error flags. 335 // Handle all buffered error flags.
@@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
380 } 362 }
381 363
382 #[cfg(any(usart_v3, usart_v4))] 364 #[cfg(any(usart_v3, usart_v4))]
383 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { 365 fn check_rx_flags(&mut self) -> Result<bool, Error> {
384 let r = T::regs(); 366 let r = T::regs();
385 let sr = r.isr().read(); 367 let sr = r.isr().read();
386 if sr.pe() { 368 if sr.pe() {
@@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
410 392
411 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 393 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
412 let r = T::regs(); 394 let r = T::regs();
413 unsafe { 395 if self.check_rx_flags()? {
414 if self.check_rx_flags()? { 396 Ok(unsafe { rdr(r).read_volatile() })
415 Ok(rdr(r).read_volatile()) 397 } else {
416 } else { 398 Err(nb::Error::WouldBlock)
417 Err(nb::Error::WouldBlock)
418 }
419 } 399 }
420 } 400 }
421 401
422 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 402 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
423 unsafe { 403 let r = T::regs();
424 let r = T::regs(); 404 for b in buffer {
425 for b in buffer { 405 while !self.check_rx_flags()? {}
426 while !self.check_rx_flags()? {} 406 unsafe { *b = rdr(r).read_volatile() }
427 *b = rdr(r).read_volatile();
428 }
429 } 407 }
430 Ok(()) 408 Ok(())
431 } 409 }
@@ -451,23 +429,20 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
451 let on_drop = OnDrop::new(move || { 429 let on_drop = OnDrop::new(move || {
452 // defmt::trace!("Clear all USART interrupts and DMA Read Request"); 430 // defmt::trace!("Clear all USART interrupts and DMA Read Request");
453 // clear all interrupts and DMA Rx Request 431 // clear all interrupts and DMA Rx Request
454 // SAFETY: only clears Rx related flags 432 r.cr1().modify(|w| {
455 unsafe { 433 // disable RXNE interrupt
456 r.cr1().modify(|w| { 434 w.set_rxneie(false);
457 // disable RXNE interrupt 435 // disable parity interrupt
458 w.set_rxneie(false); 436 w.set_peie(false);
459 // disable parity interrupt 437 // disable idle line interrupt
460 w.set_peie(false); 438 w.set_idleie(false);
461 // disable idle line interrupt 439 });
462 w.set_idleie(false); 440 r.cr3().modify(|w| {
463 }); 441 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
464 r.cr3().modify(|w| { 442 w.set_eie(false);
465 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 443 // disable DMA Rx Request
466 w.set_eie(false); 444 w.set_dmar(false);
467 // disable DMA Rx Request 445 });
468 w.set_dmar(false);
469 });
470 }
471 }); 446 });
472 447
473 let ch = &mut self.rx_dma; 448 let ch = &mut self.rx_dma;
@@ -480,78 +455,74 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
480 // future which will complete when DMA Read request completes 455 // future which will complete when DMA Read request completes
481 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; 456 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
482 457
483 // SAFETY: The only way we might have a problem is using split rx and tx 458 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
484 // here we only modify or read Rx related flags, interrupts and DMA channel 459 if !self.detect_previous_overrun {
485 unsafe { 460 let sr = sr(r).read();
486 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer 461 // This read also clears the error and idle interrupt flags on v1.
487 if !self.detect_previous_overrun { 462 unsafe { rdr(r).read_volatile() };
488 let sr = sr(r).read(); 463 clear_interrupt_flags(r, sr);
489 // This read also clears the error and idle interrupt flags on v1. 464 }
490 rdr(r).read_volatile();
491 clear_interrupt_flags(r, sr);
492 }
493
494 r.cr1().modify(|w| {
495 // disable RXNE interrupt
496 w.set_rxneie(false);
497 // enable parity interrupt if not ParityNone
498 w.set_peie(w.pce());
499 });
500 465
501 r.cr3().modify(|w| { 466 r.cr1().modify(|w| {
502 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 467 // disable RXNE interrupt
503 w.set_eie(true); 468 w.set_rxneie(false);
504 // enable DMA Rx Request 469 // enable parity interrupt if not ParityNone
505 w.set_dmar(true); 470 w.set_peie(w.pce());
506 }); 471 });
507 472
508 compiler_fence(Ordering::SeqCst); 473 r.cr3().modify(|w| {
474 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
475 w.set_eie(true);
476 // enable DMA Rx Request
477 w.set_dmar(true);
478 });
509 479
510 // In case of errors already pending when reception started, interrupts may have already been raised 480 compiler_fence(Ordering::SeqCst);
511 // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
512 // have been disabled in interrupt handler and DMA Rx Request has been disabled.
513 481
514 let cr3 = r.cr3().read(); 482 // In case of errors already pending when reception started, interrupts may have already been raised
483 // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
484 // have been disabled in interrupt handler and DMA Rx Request has been disabled.
515 485
516 if !cr3.dmar() { 486 let cr3 = r.cr3().read();
517 // something went wrong
518 // because the only way to get this flag cleared is to have an interrupt
519 487
520 // DMA will be stopped when transfer is dropped 488 if !cr3.dmar() {
489 // something went wrong
490 // because the only way to get this flag cleared is to have an interrupt
521 491
522 let sr = sr(r).read(); 492 // DMA will be stopped when transfer is dropped
523 // This read also clears the error and idle interrupt flags on v1.
524 rdr(r).read_volatile();
525 clear_interrupt_flags(r, sr);
526 493
527 if sr.pe() { 494 let sr = sr(r).read();
528 return Err(Error::Parity); 495 // This read also clears the error and idle interrupt flags on v1.
529 } 496 unsafe { rdr(r).read_volatile() };
530 if sr.fe() { 497 clear_interrupt_flags(r, sr);
531 return Err(Error::Framing);
532 }
533 if sr.ne() {
534 return Err(Error::Noise);
535 }
536 if sr.ore() {
537 return Err(Error::Overrun);
538 }
539 498
540 unreachable!(); 499 if sr.pe() {
500 return Err(Error::Parity);
541 } 501 }
542 502 if sr.fe() {
543 if enable_idle_line_detection { 503 return Err(Error::Framing);
544 // clear idle flag
545 let sr = sr(r).read();
546 // This read also clears the error and idle interrupt flags on v1.
547 rdr(r).read_volatile();
548 clear_interrupt_flags(r, sr);
549
550 // enable idle interrupt
551 r.cr1().modify(|w| {
552 w.set_idleie(true);
553 });
554 } 504 }
505 if sr.ne() {
506 return Err(Error::Noise);
507 }
508 if sr.ore() {
509 return Err(Error::Overrun);
510 }
511
512 unreachable!();
513 }
514
515 if enable_idle_line_detection {
516 // clear idle flag
517 let sr = sr(r).read();
518 // This read also clears the error and idle interrupt flags on v1.
519 unsafe { rdr(r).read_volatile() };
520 clear_interrupt_flags(r, sr);
521
522 // enable idle interrupt
523 r.cr1().modify(|w| {
524 w.set_idleie(true);
525 });
555 } 526 }
556 527
557 compiler_fence(Ordering::SeqCst); 528 compiler_fence(Ordering::SeqCst);
@@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
562 533
563 s.rx_waker.register(cx.waker()); 534 s.rx_waker.register(cx.waker());
564 535
565 // SAFETY: read only and we only use Rx related flags 536 let sr = sr(r).read();
566 let sr = unsafe { sr(r).read() };
567 537
568 // SAFETY: only clears Rx related flags 538 // This read also clears the error and idle interrupt flags on v1.
569 unsafe { 539 unsafe { rdr(r).read_volatile() };
570 // This read also clears the error and idle interrupt flags on v1. 540 clear_interrupt_flags(r, sr);
571 rdr(r).read_volatile();
572 clear_interrupt_flags(r, sr);
573 }
574 541
575 compiler_fence(Ordering::SeqCst); 542 compiler_fence(Ordering::SeqCst);
576 543
@@ -650,7 +617,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
650 peri: impl Peripheral<P = T> + 'd, 617 peri: impl Peripheral<P = T> + 'd,
651 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 618 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
652 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 619 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
653 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 620 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
654 tx_dma: impl Peripheral<P = TxDma> + 'd, 621 tx_dma: impl Peripheral<P = TxDma> + 'd,
655 rx_dma: impl Peripheral<P = RxDma> + 'd, 622 rx_dma: impl Peripheral<P = RxDma> + 'd,
656 config: Config, 623 config: Config,
@@ -665,7 +632,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
665 peri: impl Peripheral<P = T> + 'd, 632 peri: impl Peripheral<P = T> + 'd,
666 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 633 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
667 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 634 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
668 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 635 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
669 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 636 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
670 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 637 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
671 tx_dma: impl Peripheral<P = TxDma> + 'd, 638 tx_dma: impl Peripheral<P = TxDma> + 'd,
@@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
677 T::enable(); 644 T::enable();
678 T::reset(); 645 T::reset();
679 646
680 unsafe { 647 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
681 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 648 cts.set_as_af(cts.af_num(), AFType::Input);
682 cts.set_as_af(cts.af_num(), AFType::Input); 649 T::regs().cr3().write(|w| {
683 T::regs().cr3().write(|w| { 650 w.set_rtse(true);
684 w.set_rtse(true); 651 w.set_ctse(true);
685 w.set_ctse(true); 652 });
686 });
687 }
688 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 653 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
689 } 654 }
690 655
@@ -693,7 +658,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
693 peri: impl Peripheral<P = T> + 'd, 658 peri: impl Peripheral<P = T> + 'd,
694 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 659 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
695 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 660 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
696 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 661 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
697 de: impl Peripheral<P = impl DePin<T>> + 'd, 662 de: impl Peripheral<P = impl DePin<T>> + 'd,
698 tx_dma: impl Peripheral<P = TxDma> + 'd, 663 tx_dma: impl Peripheral<P = TxDma> + 'd,
699 rx_dma: impl Peripheral<P = RxDma> + 'd, 664 rx_dma: impl Peripheral<P = RxDma> + 'd,
@@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
704 T::enable(); 669 T::enable();
705 T::reset(); 670 T::reset();
706 671
707 unsafe { 672 de.set_as_af(de.af_num(), AFType::OutputPushPull);
708 de.set_as_af(de.af_num(), AFType::OutputPushPull); 673 T::regs().cr3().write(|w| {
709 T::regs().cr3().write(|w| { 674 w.set_dem(true);
710 w.set_dem(true); 675 });
711 });
712 }
713 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 676 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
714 } 677 }
715 678
@@ -725,15 +688,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
725 688
726 let r = T::regs(); 689 let r = T::regs();
727 690
728 unsafe { 691 rx.set_as_af(rx.af_num(), AFType::Input);
729 rx.set_as_af(rx.af_num(), AFType::Input); 692 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
730 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
731 }
732 693
733 configure(r, &config, T::frequency(), T::KIND, true, true); 694 configure(r, &config, T::frequency(), T::KIND, true, true);
734 695
735 unsafe { T::Interrupt::steal() }.unpend(); 696 T::Interrupt::unpend();
736 unsafe { T::Interrupt::steal() }.enable(); 697 unsafe { T::Interrupt::enable() };
737 698
738 // create state once! 699 // create state once!
739 let _s = T::state(); 700 let _s = T::state();
@@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
847 if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { 808 if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
848 over8 = true; 809 over8 = true;
849 let div = div as u32; 810 let div = div as u32;
850 unsafe { 811 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
851 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); 812 #[cfg(usart_v4)]
852 #[cfg(usart_v4)] 813 r.presc().write(|w| w.set_prescaler(_presc_val));
853 r.presc().write(|w| w.set_prescaler(_presc_val));
854 }
855 found = Some(div); 814 found = Some(div);
856 break; 815 break;
857 } 816 }
@@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
860 819
861 if div < brr_max { 820 if div < brr_max {
862 let div = div as u32; 821 let div = div as u32;
863 unsafe { 822 r.brr().write_value(regs::Brr(div));
864 r.brr().write_value(regs::Brr(div)); 823 #[cfg(usart_v4)]
865 #[cfg(usart_v4)] 824 r.presc().write(|w| w.set_prescaler(_presc_val));
866 r.presc().write(|w| w.set_prescaler(_presc_val));
867 }
868 found = Some(div); 825 found = Some(div);
869 break; 826 break;
870 } 827 }
@@ -883,44 +840,42 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
883 pclk_freq.0 / div 840 pclk_freq.0 / div
884 ); 841 );
885 842
886 unsafe { 843 r.cr2().write(|w| {
887 r.cr2().write(|w| { 844 w.set_stop(match config.stop_bits {
888 w.set_stop(match config.stop_bits { 845 StopBits::STOP0P5 => vals::Stop::STOP0P5,
889 StopBits::STOP0P5 => vals::Stop::STOP0P5, 846 StopBits::STOP1 => vals::Stop::STOP1,
890 StopBits::STOP1 => vals::Stop::STOP1, 847 StopBits::STOP1P5 => vals::Stop::STOP1P5,
891 StopBits::STOP1P5 => vals::Stop::STOP1P5, 848 StopBits::STOP2 => vals::Stop::STOP2,
892 StopBits::STOP2 => vals::Stop::STOP2,
893 });
894 }); 849 });
895 r.cr1().write(|w| { 850 });
896 // enable uart 851 r.cr1().write(|w| {
897 w.set_ue(true); 852 // enable uart
898 // enable transceiver 853 w.set_ue(true);
899 w.set_te(enable_tx); 854 // enable transceiver
900 // enable receiver 855 w.set_te(enable_tx);
901 w.set_re(enable_rx); 856 // enable receiver
902 // configure word size 857 w.set_re(enable_rx);
903 w.set_m0(if config.parity != Parity::ParityNone { 858 // configure word size
904 vals::M0::BIT9 859 w.set_m0(if config.parity != Parity::ParityNone {
905 } else { 860 vals::M0::BIT9
906 vals::M0::BIT8 861 } else {
907 }); 862 vals::M0::BIT8
908 // configure parity
909 w.set_pce(config.parity != Parity::ParityNone);
910 w.set_ps(match config.parity {
911 Parity::ParityOdd => vals::Ps::ODD,
912 Parity::ParityEven => vals::Ps::EVEN,
913 _ => vals::Ps::EVEN,
914 });
915 #[cfg(not(usart_v1))]
916 w.set_over8(vals::Over8(over8 as _));
917 }); 863 });
918 864 // configure parity
919 #[cfg(not(usart_v1))] 865 w.set_pce(config.parity != Parity::ParityNone);
920 r.cr3().modify(|w| { 866 w.set_ps(match config.parity {
921 w.set_onebit(config.assume_noise_free); 867 Parity::ParityOdd => vals::Ps::ODD,
868 Parity::ParityEven => vals::Ps::EVEN,
869 _ => vals::Ps::EVEN,
922 }); 870 });
923 } 871 #[cfg(not(usart_v1))]
872 w.set_over8(vals::Over8(over8 as _));
873 });
874
875 #[cfg(not(usart_v1))]
876 r.cr3().modify(|w| {
877 w.set_onebit(config.assume_noise_free);
878 });
924} 879}
925 880
926mod eh02 { 881mod eh02 {
@@ -1111,12 +1066,12 @@ use self::sealed::Kind;
1111 1066
1112#[cfg(any(usart_v1, usart_v2))] 1067#[cfg(any(usart_v1, usart_v2))]
1113fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { 1068fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
1114 r.dr().ptr() as _ 1069 r.dr().as_ptr() as _
1115} 1070}
1116 1071
1117#[cfg(any(usart_v1, usart_v2))] 1072#[cfg(any(usart_v1, usart_v2))]
1118fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { 1073fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
1119 r.dr().ptr() as _ 1074 r.dr().as_ptr() as _
1120} 1075}
1121 1076
1122#[cfg(any(usart_v1, usart_v2))] 1077#[cfg(any(usart_v1, usart_v2))]
@@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p
1126 1081
1127#[cfg(any(usart_v1, usart_v2))] 1082#[cfg(any(usart_v1, usart_v2))]
1128#[allow(unused)] 1083#[allow(unused)]
1129unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { 1084fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
1130 // On v1 the flags are cleared implicitly by reads and writes to DR. 1085 // On v1 the flags are cleared implicitly by reads and writes to DR.
1131} 1086}
1132 1087
1133#[cfg(any(usart_v3, usart_v4))] 1088#[cfg(any(usart_v3, usart_v4))]
1134fn tdr(r: Regs) -> *mut u8 { 1089fn tdr(r: Regs) -> *mut u8 {
1135 r.tdr().ptr() as _ 1090 r.tdr().as_ptr() as _
1136} 1091}
1137 1092
1138#[cfg(any(usart_v3, usart_v4))] 1093#[cfg(any(usart_v3, usart_v4))]
1139fn rdr(r: Regs) -> *mut u8 { 1094fn rdr(r: Regs) -> *mut u8 {
1140 r.rdr().ptr() as _ 1095 r.rdr().as_ptr() as _
1141} 1096}
1142 1097
1143#[cfg(any(usart_v3, usart_v4))] 1098#[cfg(any(usart_v3, usart_v4))]
@@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
1147 1102
1148#[cfg(any(usart_v3, usart_v4))] 1103#[cfg(any(usart_v3, usart_v4))]
1149#[allow(unused)] 1104#[allow(unused)]
1150unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { 1105fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
1151 r.icr().write(|w| *w = regs::Icr(sr.0)); 1106 r.icr().write(|w| *w = regs::Icr(sr.0));
1152} 1107}
1153 1108
@@ -1179,7 +1134,7 @@ pub(crate) mod sealed {
1179 1134
1180 pub trait BasicInstance: crate::rcc::RccPeripheral { 1135 pub trait BasicInstance: crate::rcc::RccPeripheral {
1181 const KIND: Kind; 1136 const KIND: Kind;
1182 type Interrupt: crate::interrupt::Interrupt; 1137 type Interrupt: interrupt::typelevel::Interrupt;
1183 1138
1184 fn regs() -> Regs; 1139 fn regs() -> Regs;
1185 fn state() -> &'static State; 1140 fn state() -> &'static State;
@@ -1211,10 +1166,10 @@ macro_rules! impl_usart {
1211 ($inst:ident, $irq:ident, $kind:expr) => { 1166 ($inst:ident, $irq:ident, $kind:expr) => {
1212 impl sealed::BasicInstance for crate::peripherals::$inst { 1167 impl sealed::BasicInstance for crate::peripherals::$inst {
1213 const KIND: Kind = $kind; 1168 const KIND: Kind = $kind;
1214 type Interrupt = crate::interrupt::$irq; 1169 type Interrupt = crate::interrupt::typelevel::$irq;
1215 1170
1216 fn regs() -> Regs { 1171 fn regs() -> Regs {
1217 Regs(crate::pac::$inst.0) 1172 unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
1218 } 1173 }
1219 1174
1220 fn state() -> &'static crate::usart::sealed::State { 1175 fn state() -> &'static crate::usart::sealed::State {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 511b71c7f..c74d7e092 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -59,23 +59,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
59 59
60 let r = T::regs(); 60 let r = T::regs();
61 // clear all interrupts and DMA Rx Request 61 // clear all interrupts and DMA Rx Request
62 // SAFETY: only clears Rx related flags 62 r.cr1().modify(|w| {
63 unsafe { 63 // disable RXNE interrupt
64 r.cr1().modify(|w| { 64 w.set_rxneie(false);
65 // disable RXNE interrupt 65 // enable parity interrupt if not ParityNone
66 w.set_rxneie(false); 66 w.set_peie(w.pce());
67 // enable parity interrupt if not ParityNone 67 // enable idle line interrupt
68 w.set_peie(w.pce()); 68 w.set_idleie(true);
69 // enable idle line interrupt 69 });
70 w.set_idleie(true); 70 r.cr3().modify(|w| {
71 }); 71 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
72 r.cr3().modify(|w| { 72 w.set_eie(true);
73 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 73 // enable DMA Rx Request
74 w.set_eie(true); 74 w.set_dmar(true);
75 // enable DMA Rx Request 75 });
76 w.set_dmar(true);
77 });
78 }
79 } 76 }
80 77
81 /// Stop uart background receive 78 /// Stop uart background receive
@@ -84,23 +81,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
84 81
85 let r = T::regs(); 82 let r = T::regs();
86 // clear all interrupts and DMA Rx Request 83 // clear all interrupts and DMA Rx Request
87 // SAFETY: only clears Rx related flags 84 r.cr1().modify(|w| {
88 unsafe { 85 // disable RXNE interrupt
89 r.cr1().modify(|w| { 86 w.set_rxneie(false);
90 // disable RXNE interrupt 87 // disable parity interrupt
91 w.set_rxneie(false); 88 w.set_peie(false);
92 // disable parity interrupt 89 // disable idle line interrupt
93 w.set_peie(false); 90 w.set_idleie(false);
94 // disable idle line interrupt 91 });
95 w.set_idleie(false); 92 r.cr3().modify(|w| {
96 }); 93 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
97 r.cr3().modify(|w| { 94 w.set_eie(false);
98 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 95 // disable DMA Rx Request
99 w.set_eie(false); 96 w.set_dmar(false);
100 // disable DMA Rx Request 97 });
101 w.set_dmar(false);
102 });
103 }
104 98
105 compiler_fence(Ordering::SeqCst); 99 compiler_fence(Ordering::SeqCst);
106 } 100 }
@@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
117 let r = T::regs(); 111 let r = T::regs();
118 112
119 // Start background receive if it was not already started 113 // Start background receive if it was not already started
120 // SAFETY: read only 114 match r.cr3().read().dmar() {
121 match unsafe { r.cr3().read().dmar() } {
122 false => self.start()?, 115 false => self.start()?,
123 _ => {} 116 _ => {}
124 }; 117 };
@@ -213,19 +206,17 @@ fn check_for_errors(s: Sr) -> Result<(), Error> {
213 206
214/// Clear IDLE and return the Sr register 207/// Clear IDLE and return the Sr register
215fn clear_idle_flag(r: Regs) -> Sr { 208fn clear_idle_flag(r: Regs) -> Sr {
216 unsafe { 209 // SAFETY: read only and we only use Rx related flags
217 // SAFETY: read only and we only use Rx related flags
218 210
219 let sr = sr(r).read(); 211 let sr = sr(r).read();
220 212
221 // This read also clears the error and idle interrupt flags on v1. 213 // This read also clears the error and idle interrupt flags on v1.
222 rdr(r).read_volatile(); 214 unsafe { rdr(r).read_volatile() };
223 clear_interrupt_flags(r, sr); 215 clear_interrupt_flags(r, sr);
224 216
225 r.cr1().modify(|w| w.set_idleie(true)); 217 r.cr1().modify(|w| w.set_idleie(true));
226 218
227 sr 219 sr
228 }
229} 220}
230 221
231#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 222#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index fbd1fa823..bee287fe6 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,4 +1,4 @@
1use crate::interrupt::Interrupt; 1use crate::interrupt;
2use crate::rcc::RccPeripheral; 2use crate::rcc::RccPeripheral;
3 3
4#[cfg(feature = "nightly")] 4#[cfg(feature = "nightly")]
@@ -13,7 +13,7 @@ pub(crate) mod sealed {
13} 13}
14 14
15pub trait Instance: sealed::Instance + RccPeripheral + 'static { 15pub trait Instance: sealed::Instance + RccPeripheral + 'static {
16 type Interrupt: Interrupt; 16 type Interrupt: interrupt::typelevel::Interrupt;
17} 17}
18 18
19// Internal PHY pins 19// Internal PHY pins
@@ -29,7 +29,7 @@ foreach_interrupt!(
29 } 29 }
30 30
31 impl Instance for crate::peripherals::$inst { 31 impl Instance for crate::peripherals::$inst {
32 type Interrupt = crate::interrupt::$irq; 32 type Interrupt = crate::interrupt::typelevel::$irq;
33 } 33 }
34 }; 34 };
35); 35);
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index a9ff284ae..2367127e8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -14,7 +14,7 @@ use embassy_usb_driver::{
14 14
15use super::{DmPin, DpPin, Instance}; 15use super::{DmPin, DpPin, Instance};
16use crate::gpio::sealed::AFType; 16use crate::gpio::sealed::AFType;
17use crate::interrupt::{Interrupt, InterruptExt}; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::usb::regs; 18use crate::pac::usb::regs;
19use crate::pac::usb::vals::{EpType, Stat}; 19use crate::pac::usb::vals::{EpType, Stat};
20use crate::pac::USBRAM; 20use crate::pac::USBRAM;
@@ -26,84 +26,82 @@ pub struct InterruptHandler<T: Instance> {
26 _phantom: PhantomData<T>, 26 _phantom: PhantomData<T>,
27} 27}
28 28
29impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 29impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
30 unsafe fn on_interrupt() { 30 unsafe fn on_interrupt() {
31 unsafe { 31 let regs = T::regs();
32 let regs = T::regs(); 32 //let x = regs.istr().read().0;
33 //let x = regs.istr().read().0; 33 //trace!("USB IRQ: {:08x}", x);
34 //trace!("USB IRQ: {:08x}", x);
35
36 let istr = regs.istr().read();
37
38 if istr.susp() {
39 //trace!("USB IRQ: susp");
40 IRQ_SUSPEND.store(true, Ordering::Relaxed);
41 regs.cntr().modify(|w| {
42 w.set_fsusp(true);
43 w.set_lpmode(true);
44 });
45
46 // Write 0 to clear.
47 let mut clear = regs::Istr(!0);
48 clear.set_susp(false);
49 regs.istr().write_value(clear);
50
51 // Wake main thread.
52 BUS_WAKER.wake();
53 }
54 34
55 if istr.wkup() { 35 let istr = regs.istr().read();
56 //trace!("USB IRQ: wkup");
57 IRQ_RESUME.store(true, Ordering::Relaxed);
58 regs.cntr().modify(|w| {
59 w.set_fsusp(false);
60 w.set_lpmode(false);
61 });
62
63 // Write 0 to clear.
64 let mut clear = regs::Istr(!0);
65 clear.set_wkup(false);
66 regs.istr().write_value(clear);
67
68 // Wake main thread.
69 BUS_WAKER.wake();
70 }
71 36
72 if istr.reset() { 37 if istr.susp() {
73 //trace!("USB IRQ: reset"); 38 //trace!("USB IRQ: susp");
74 IRQ_RESET.store(true, Ordering::Relaxed); 39 IRQ_SUSPEND.store(true, Ordering::Relaxed);
40 regs.cntr().modify(|w| {
41 w.set_fsusp(true);
42 w.set_lpmode(true);
43 });
75 44
76 // Write 0 to clear. 45 // Write 0 to clear.
77 let mut clear = regs::Istr(!0); 46 let mut clear = regs::Istr(!0);
78 clear.set_reset(false); 47 clear.set_susp(false);
79 regs.istr().write_value(clear); 48 regs.istr().write_value(clear);
80 49
81 // Wake main thread. 50 // Wake main thread.
82 BUS_WAKER.wake(); 51 BUS_WAKER.wake();
83 } 52 }
84 53
85 if istr.ctr() { 54 if istr.wkup() {
86 let index = istr.ep_id() as usize; 55 //trace!("USB IRQ: wkup");
87 let mut epr = regs.epr(index).read(); 56 IRQ_RESUME.store(true, Ordering::Relaxed);
88 if epr.ctr_rx() { 57 regs.cntr().modify(|w| {
89 if index == 0 && epr.setup() { 58 w.set_fsusp(false);
90 EP0_SETUP.store(true, Ordering::Relaxed); 59 w.set_lpmode(false);
91 } 60 });
92 //trace!("EP {} RX, setup={}", index, epr.setup()); 61
93 EP_OUT_WAKERS[index].wake(); 62 // Write 0 to clear.
94 } 63 let mut clear = regs::Istr(!0);
95 if epr.ctr_tx() { 64 clear.set_wkup(false);
96 //trace!("EP {} TX", index); 65 regs.istr().write_value(clear);
97 EP_IN_WAKERS[index].wake(); 66
67 // Wake main thread.
68 BUS_WAKER.wake();
69 }
70
71 if istr.reset() {
72 //trace!("USB IRQ: reset");
73 IRQ_RESET.store(true, Ordering::Relaxed);
74
75 // Write 0 to clear.
76 let mut clear = regs::Istr(!0);
77 clear.set_reset(false);
78 regs.istr().write_value(clear);
79
80 // Wake main thread.
81 BUS_WAKER.wake();
82 }
83
84 if istr.ctr() {
85 let index = istr.ep_id() as usize;
86 let mut epr = regs.epr(index).read();
87 if epr.ctr_rx() {
88 if index == 0 && epr.setup() {
89 EP0_SETUP.store(true, Ordering::Relaxed);
98 } 90 }
99 epr.set_dtog_rx(false); 91 //trace!("EP {} RX, setup={}", index, epr.setup());
100 epr.set_dtog_tx(false); 92 EP_OUT_WAKERS[index].wake();
101 epr.set_stat_rx(Stat(0)); 93 }
102 epr.set_stat_tx(Stat(0)); 94 if epr.ctr_tx() {
103 epr.set_ctr_rx(!epr.ctr_rx()); 95 //trace!("EP {} TX", index);
104 epr.set_ctr_tx(!epr.ctr_tx()); 96 EP_IN_WAKERS[index].wake();
105 regs.epr(index).write_value(epr);
106 } 97 }
98 epr.set_dtog_rx(false);
99 epr.set_dtog_tx(false);
100 epr.set_stat_rx(Stat(0));
101 epr.set_stat_tx(Stat(0));
102 epr.set_ctr_rx(!epr.ctr_rx());
103 epr.set_ctr_tx(!epr.ctr_tx());
104 regs.epr(index).write_value(epr);
107 } 105 }
108 } 106 }
109} 107}
@@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) {
168mod btable { 166mod btable {
169 use super::*; 167 use super::*;
170 168
171 pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { 169 pub(super) fn write_in<T: Instance>(index: usize, addr: u16) {
172 USBRAM.mem(index * 4 + 0).write_value(addr); 170 USBRAM.mem(index * 4 + 0).write_value(addr);
173 } 171 }
174 172
175 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { 173 pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
176 USBRAM.mem(index * 4 + 1).write_value(len); 174 USBRAM.mem(index * 4 + 1).write_value(len);
177 } 175 }
178 176
179 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 177 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
180 USBRAM.mem(index * 4 + 2).write_value(addr); 178 USBRAM.mem(index * 4 + 2).write_value(addr);
181 USBRAM.mem(index * 4 + 3).write_value(max_len_bits); 179 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
182 } 180 }
183 181
184 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { 182 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
185 USBRAM.mem(index * 4 + 3).read() 183 USBRAM.mem(index * 4 + 3).read()
186 } 184 }
187} 185}
@@ -189,19 +187,19 @@ mod btable {
189mod btable { 187mod btable {
190 use super::*; 188 use super::*;
191 189
192 pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} 190 pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {}
193 191
194 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { 192 pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
195 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); 193 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
196 } 194 }
197 195
198 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 196 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
199 USBRAM 197 USBRAM
200 .mem(index * 2 + 1) 198 .mem(index * 2 + 1)
201 .write_value((addr as u32) | ((max_len_bits as u32) << 16)); 199 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
202 } 200 }
203 201
204 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { 202 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
205 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 203 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
206 } 204 }
207} 205}
@@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> {
216 fn read(&mut self, buf: &mut [u8]) { 214 fn read(&mut self, buf: &mut [u8]) {
217 assert!(buf.len() <= self.len as usize); 215 assert!(buf.len() <= self.len as usize);
218 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { 216 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
219 let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; 217 let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read();
220 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); 218 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
221 buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); 219 buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
222 } 220 }
@@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> {
233 let val = u16::from_le_bytes(val); 231 let val = u16::from_le_bytes(val);
234 #[cfg(usbram_32_2048)] 232 #[cfg(usbram_32_2048)]
235 let val = u32::from_le_bytes(val); 233 let val = u32::from_le_bytes(val);
236 unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; 234 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
237 } 235 }
238 } 236 }
239} 237}
@@ -255,47 +253,43 @@ pub struct Driver<'d, T: Instance> {
255impl<'d, T: Instance> Driver<'d, T> { 253impl<'d, T: Instance> Driver<'d, T> {
256 pub fn new( 254 pub fn new(
257 _usb: impl Peripheral<P = T> + 'd, 255 _usb: impl Peripheral<P = T> + 'd,
258 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 256 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
259 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 257 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
260 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 258 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
261 ) -> Self { 259 ) -> Self {
262 into_ref!(dp, dm); 260 into_ref!(dp, dm);
263 unsafe { T::Interrupt::steal() }.unpend(); 261 T::Interrupt::unpend();
264 unsafe { T::Interrupt::steal() }.enable(); 262 unsafe { T::Interrupt::enable() };
265 263
266 let regs = T::regs(); 264 let regs = T::regs();
267 265
268 #[cfg(stm32l5)] 266 #[cfg(stm32l5)]
269 unsafe { 267 {
270 crate::peripherals::PWR::enable(); 268 crate::peripherals::PWR::enable();
271 crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); 269 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
272 } 270 }
273 271
274 #[cfg(pwr_h5)] 272 #[cfg(pwr_h5)]
275 unsafe { 273 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
276 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))
277 }
278 274
279 unsafe { 275 <T as RccPeripheral>::enable();
280 <T as RccPeripheral>::enable(); 276 <T as RccPeripheral>::reset();
281 <T as RccPeripheral>::reset();
282 277
283 regs.cntr().write(|w| { 278 regs.cntr().write(|w| {
284 w.set_pdwn(false); 279 w.set_pdwn(false);
285 w.set_fres(true); 280 w.set_fres(true);
286 }); 281 });
287 282
288 #[cfg(time)] 283 #[cfg(time)]
289 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 284 embassy_time::block_for(embassy_time::Duration::from_millis(100));
290 #[cfg(not(time))] 285 #[cfg(not(time))]
291 cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10); 286 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10);
292 287
293 #[cfg(not(usb_v4))] 288 #[cfg(not(usb_v4))]
294 regs.btable().write(|w| w.set_btable(0)); 289 regs.btable().write(|w| w.set_btable(0));
295 290
296 dp.set_as_af(dp.af_num(), AFType::OutputPushPull); 291 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
297 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 292 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
298 }
299 293
300 // Initialize the bus so that it signals that power is available 294 // Initialize the bus so that it signals that power is available
301 BUS_WAKER.wake(); 295 BUS_WAKER.wake();
@@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
363 let addr = self.alloc_ep_mem(len); 357 let addr = self.alloc_ep_mem(len);
364 358
365 trace!(" len_bits = {:04x}", len_bits); 359 trace!(" len_bits = {:04x}", len_bits);
366 unsafe { btable::write_out::<T>(index, addr, len_bits) } 360 btable::write_out::<T>(index, addr, len_bits);
367 361
368 EndpointBuffer { 362 EndpointBuffer {
369 addr, 363 addr,
@@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> {
379 let addr = self.alloc_ep_mem(len); 373 let addr = self.alloc_ep_mem(len);
380 374
381 // ep_in_len is written when actually TXing packets. 375 // ep_in_len is written when actually TXing packets.
382 unsafe { btable::write_in::<T>(index, addr) } 376 btable::write_in::<T>(index, addr);
383 377
384 EndpointBuffer { 378 EndpointBuffer {
385 addr, 379 addr,
@@ -440,19 +434,17 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
440 434
441 let regs = T::regs(); 435 let regs = T::regs();
442 436
443 unsafe { 437 regs.cntr().write(|w| {
444 regs.cntr().write(|w| { 438 w.set_pdwn(false);
445 w.set_pdwn(false); 439 w.set_fres(false);
446 w.set_fres(false); 440 w.set_resetm(true);
447 w.set_resetm(true); 441 w.set_suspm(true);
448 w.set_suspm(true); 442 w.set_wkupm(true);
449 w.set_wkupm(true); 443 w.set_ctrm(true);
450 w.set_ctrm(true); 444 });
451 });
452 445
453 #[cfg(any(usb_v3, usb_v4))] 446 #[cfg(any(usb_v3, usb_v4))]
454 regs.bcdr().write(|w| w.set_dppu(true)) 447 regs.bcdr().write(|w| w.set_dppu(true));
455 }
456 448
457 trace!("enabled"); 449 trace!("enabled");
458 450
@@ -485,7 +477,7 @@ pub struct Bus<'d, T: Instance> {
485 477
486impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 478impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
487 async fn poll(&mut self) -> Event { 479 async fn poll(&mut self) -> Event {
488 poll_fn(move |cx| unsafe { 480 poll_fn(move |cx| {
489 BUS_WAKER.register(cx.waker()); 481 BUS_WAKER.register(cx.waker());
490 482
491 if self.inited { 483 if self.inited {
@@ -548,7 +540,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
548 match ep_addr.direction() { 540 match ep_addr.direction() {
549 Direction::In => { 541 Direction::In => {
550 loop { 542 loop {
551 let r = unsafe { reg.read() }; 543 let r = reg.read();
552 match r.stat_tx() { 544 match r.stat_tx() {
553 Stat::DISABLED => break, // if disabled, stall does nothing. 545 Stat::DISABLED => break, // if disabled, stall does nothing.
554 Stat::STALL => break, // done! 546 Stat::STALL => break, // done!
@@ -559,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
559 }; 551 };
560 let mut w = invariant(r); 552 let mut w = invariant(r);
561 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 553 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
562 unsafe { reg.write_value(w) }; 554 reg.write_value(w);
563 } 555 }
564 } 556 }
565 } 557 }
@@ -567,7 +559,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
567 } 559 }
568 Direction::Out => { 560 Direction::Out => {
569 loop { 561 loop {
570 let r = unsafe { reg.read() }; 562 let r = reg.read();
571 match r.stat_rx() { 563 match r.stat_rx() {
572 Stat::DISABLED => break, // if disabled, stall does nothing. 564 Stat::DISABLED => break, // if disabled, stall does nothing.
573 Stat::STALL => break, // done! 565 Stat::STALL => break, // done!
@@ -578,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
578 }; 570 };
579 let mut w = invariant(r); 571 let mut w = invariant(r);
580 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 572 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
581 unsafe { reg.write_value(w) }; 573 reg.write_value(w);
582 } 574 }
583 } 575 }
584 } 576 }
@@ -589,7 +581,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
589 581
590 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { 582 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
591 let regs = T::regs(); 583 let regs = T::regs();
592 let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; 584 let epr = regs.epr(ep_addr.index() as _).read();
593 match ep_addr.direction() { 585 match ep_addr.direction() {
594 Direction::In => epr.stat_tx() == Stat::STALL, 586 Direction::In => epr.stat_tx() == Stat::STALL,
595 Direction::Out => epr.stat_rx() == Stat::STALL, 587 Direction::Out => epr.stat_rx() == Stat::STALL,
@@ -600,7 +592,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
600 trace!("set_enabled {:x} {}", ep_addr, enabled); 592 trace!("set_enabled {:x} {}", ep_addr, enabled);
601 // This can race, so do a retry loop. 593 // This can race, so do a retry loop.
602 let reg = T::regs().epr(ep_addr.index() as _); 594 let reg = T::regs().epr(ep_addr.index() as _);
603 trace!("EPR before: {:04x}", unsafe { reg.read() }.0); 595 trace!("EPR before: {:04x}", reg.read().0);
604 match ep_addr.direction() { 596 match ep_addr.direction() {
605 Direction::In => { 597 Direction::In => {
606 loop { 598 loop {
@@ -608,13 +600,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
608 false => Stat::DISABLED, 600 false => Stat::DISABLED,
609 true => Stat::NAK, 601 true => Stat::NAK,
610 }; 602 };
611 let r = unsafe { reg.read() }; 603 let r = reg.read();
612 if r.stat_tx() == want_stat { 604 if r.stat_tx() == want_stat {
613 break; 605 break;
614 } 606 }
615 let mut w = invariant(r); 607 let mut w = invariant(r);
616 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 608 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
617 unsafe { reg.write_value(w) }; 609 reg.write_value(w);
618 } 610 }
619 EP_IN_WAKERS[ep_addr.index()].wake(); 611 EP_IN_WAKERS[ep_addr.index()].wake();
620 } 612 }
@@ -624,18 +616,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
624 false => Stat::DISABLED, 616 false => Stat::DISABLED,
625 true => Stat::VALID, 617 true => Stat::VALID,
626 }; 618 };
627 let r = unsafe { reg.read() }; 619 let r = reg.read();
628 if r.stat_rx() == want_stat { 620 if r.stat_rx() == want_stat {
629 break; 621 break;
630 } 622 }
631 let mut w = invariant(r); 623 let mut w = invariant(r);
632 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 624 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
633 unsafe { reg.write_value(w) }; 625 reg.write_value(w);
634 } 626 }
635 EP_OUT_WAKERS[ep_addr.index()].wake(); 627 EP_OUT_WAKERS[ep_addr.index()].wake();
636 } 628 }
637 } 629 }
638 trace!("EPR after: {:04x}", unsafe { reg.read() }.0); 630 trace!("EPR after: {:04x}", reg.read().0);
639 } 631 }
640 632
641 async fn enable(&mut self) {} 633 async fn enable(&mut self) {}
@@ -685,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
685 fn write_data(&mut self, buf: &[u8]) { 677 fn write_data(&mut self, buf: &[u8]) {
686 let index = self.info.addr.index(); 678 let index = self.info.addr.index();
687 self.buf.write(buf); 679 self.buf.write(buf);
688 unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } 680 btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _);
689 } 681 }
690 682
691 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 683 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
692 let index = self.info.addr.index(); 684 let index = self.info.addr.index();
693 let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; 685 let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF;
694 trace!("READ DONE, rx_len = {}", rx_len); 686 trace!("READ DONE, rx_len = {}", rx_len);
695 if rx_len > buf.len() { 687 if rx_len > buf.len() {
696 return Err(EndpointError::BufferOverflow); 688 return Err(EndpointError::BufferOverflow);
@@ -711,7 +703,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
711 poll_fn(|cx| { 703 poll_fn(|cx| {
712 EP_OUT_WAKERS[index].register(cx.waker()); 704 EP_OUT_WAKERS[index].register(cx.waker());
713 let regs = T::regs(); 705 let regs = T::regs();
714 if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED { 706 if regs.epr(index).read().stat_tx() == Stat::DISABLED {
715 Poll::Pending 707 Poll::Pending
716 } else { 708 } else {
717 Poll::Ready(()) 709 Poll::Ready(())
@@ -733,7 +725,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
733 poll_fn(|cx| { 725 poll_fn(|cx| {
734 EP_OUT_WAKERS[index].register(cx.waker()); 726 EP_OUT_WAKERS[index].register(cx.waker());
735 let regs = T::regs(); 727 let regs = T::regs();
736 if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED { 728 if regs.epr(index).read().stat_rx() == Stat::DISABLED {
737 Poll::Pending 729 Poll::Pending
738 } else { 730 } else {
739 Poll::Ready(()) 731 Poll::Ready(())
@@ -751,7 +743,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
751 let stat = poll_fn(|cx| { 743 let stat = poll_fn(|cx| {
752 EP_OUT_WAKERS[index].register(cx.waker()); 744 EP_OUT_WAKERS[index].register(cx.waker());
753 let regs = T::regs(); 745 let regs = T::regs();
754 let stat = unsafe { regs.epr(index).read() }.stat_rx(); 746 let stat = regs.epr(index).read().stat_rx();
755 if matches!(stat, Stat::NAK | Stat::DISABLED) { 747 if matches!(stat, Stat::NAK | Stat::DISABLED) {
756 Poll::Ready(stat) 748 Poll::Ready(stat)
757 } else { 749 } else {
@@ -767,16 +759,14 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
767 let rx_len = self.read_data(buf)?; 759 let rx_len = self.read_data(buf)?;
768 760
769 let regs = T::regs(); 761 let regs = T::regs();
770 unsafe { 762 regs.epr(index).write(|w| {
771 regs.epr(index).write(|w| { 763 w.set_ep_type(convert_type(self.info.ep_type));
772 w.set_ep_type(convert_type(self.info.ep_type)); 764 w.set_ea(self.info.addr.index() as _);
773 w.set_ea(self.info.addr.index() as _); 765 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
774 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 766 w.set_stat_tx(Stat(0));
775 w.set_stat_tx(Stat(0)); 767 w.set_ctr_rx(true); // don't clear
776 w.set_ctr_rx(true); // don't clear 768 w.set_ctr_tx(true); // don't clear
777 w.set_ctr_tx(true); // don't clear 769 });
778 })
779 };
780 trace!("READ OK, rx_len = {}", rx_len); 770 trace!("READ OK, rx_len = {}", rx_len);
781 771
782 Ok(rx_len) 772 Ok(rx_len)
@@ -795,7 +785,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
795 let stat = poll_fn(|cx| { 785 let stat = poll_fn(|cx| {
796 EP_IN_WAKERS[index].register(cx.waker()); 786 EP_IN_WAKERS[index].register(cx.waker());
797 let regs = T::regs(); 787 let regs = T::regs();
798 let stat = unsafe { regs.epr(index).read() }.stat_tx(); 788 let stat = regs.epr(index).read().stat_tx();
799 if matches!(stat, Stat::NAK | Stat::DISABLED) { 789 if matches!(stat, Stat::NAK | Stat::DISABLED) {
800 Poll::Ready(stat) 790 Poll::Ready(stat)
801 } else { 791 } else {
@@ -811,16 +801,14 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
811 self.write_data(buf); 801 self.write_data(buf);
812 802
813 let regs = T::regs(); 803 let regs = T::regs();
814 unsafe { 804 regs.epr(index).write(|w| {
815 regs.epr(index).write(|w| { 805 w.set_ep_type(convert_type(self.info.ep_type));
816 w.set_ep_type(convert_type(self.info.ep_type)); 806 w.set_ea(self.info.addr.index() as _);
817 w.set_ea(self.info.addr.index() as _); 807 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
818 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 808 w.set_stat_rx(Stat(0));
819 w.set_stat_rx(Stat(0)); 809 w.set_ctr_rx(true); // don't clear
820 w.set_ctr_rx(true); // don't clear 810 w.set_ctr_tx(true); // don't clear
821 w.set_ctr_tx(true); // don't clear 811 });
822 })
823 };
824 812
825 trace!("WRITE OK"); 813 trace!("WRITE OK");
826 814
@@ -889,22 +877,20 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
889 } 877 }
890 // Note: if this is the first AND last transfer, the above effectively 878 // Note: if this is the first AND last transfer, the above effectively
891 // changes stat_tx like NAK -> NAK, so noop. 879 // changes stat_tx like NAK -> NAK, so noop.
892 unsafe { 880 regs.epr(0).write(|w| {
893 regs.epr(0).write(|w| { 881 w.set_ep_type(EpType::CONTROL);
894 w.set_ep_type(EpType::CONTROL); 882 w.set_stat_rx(Stat(stat_rx));
895 w.set_stat_rx(Stat(stat_rx)); 883 w.set_stat_tx(Stat(stat_tx));
896 w.set_stat_tx(Stat(stat_tx)); 884 w.set_ctr_rx(true); // don't clear
897 w.set_ctr_rx(true); // don't clear 885 w.set_ctr_tx(true); // don't clear
898 w.set_ctr_tx(true); // don't clear 886 });
899 })
900 }
901 } 887 }
902 888
903 trace!("data_out WAITING, buf.len() = {}", buf.len()); 889 trace!("data_out WAITING, buf.len() = {}", buf.len());
904 poll_fn(|cx| { 890 poll_fn(|cx| {
905 EP_OUT_WAKERS[0].register(cx.waker()); 891 EP_OUT_WAKERS[0].register(cx.waker());
906 let regs = T::regs(); 892 let regs = T::regs();
907 if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK { 893 if regs.epr(0).read().stat_rx() == Stat::NAK {
908 Poll::Ready(()) 894 Poll::Ready(())
909 } else { 895 } else {
910 Poll::Pending 896 Poll::Pending
@@ -919,19 +905,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
919 905
920 let rx_len = self.ep_out.read_data(buf)?; 906 let rx_len = self.ep_out.read_data(buf)?;
921 907
922 unsafe { 908 regs.epr(0).write(|w| {
923 regs.epr(0).write(|w| { 909 w.set_ep_type(EpType::CONTROL);
924 w.set_ep_type(EpType::CONTROL); 910 w.set_stat_rx(Stat(match last {
925 w.set_stat_rx(Stat(match last { 911 // If last, set STAT_RX=STALL.
926 // If last, set STAT_RX=STALL. 912 true => Stat::NAK.0 ^ Stat::STALL.0,
927 true => Stat::NAK.0 ^ Stat::STALL.0, 913 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
928 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. 914 false => Stat::NAK.0 ^ Stat::VALID.0,
929 false => Stat::NAK.0 ^ Stat::VALID.0, 915 }));
930 })); 916 w.set_ctr_rx(true); // don't clear
931 w.set_ctr_rx(true); // don't clear 917 w.set_ctr_tx(true); // don't clear
932 w.set_ctr_tx(true); // don't clear 918 });
933 })
934 };
935 919
936 Ok(rx_len) 920 Ok(rx_len)
937 } 921 }
@@ -960,15 +944,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
960 } 944 }
961 // Note: if this is the first AND last transfer, the above effectively 945 // Note: if this is the first AND last transfer, the above effectively
962 // does a change of NAK -> VALID. 946 // does a change of NAK -> VALID.
963 unsafe { 947 regs.epr(0).write(|w| {
964 regs.epr(0).write(|w| { 948 w.set_ep_type(EpType::CONTROL);
965 w.set_ep_type(EpType::CONTROL); 949 w.set_stat_rx(Stat(stat_rx));
966 w.set_stat_rx(Stat(stat_rx)); 950 w.set_ep_kind(last); // set OUT_STATUS if last.
967 w.set_ep_kind(last); // set OUT_STATUS if last. 951 w.set_ctr_rx(true); // don't clear
968 w.set_ctr_rx(true); // don't clear 952 w.set_ctr_tx(true); // don't clear
969 w.set_ctr_tx(true); // don't clear 953 });
970 })
971 }
972 } 954 }
973 955
974 trace!("WRITE WAITING"); 956 trace!("WRITE WAITING");
@@ -976,7 +958,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
976 EP_IN_WAKERS[0].register(cx.waker()); 958 EP_IN_WAKERS[0].register(cx.waker());
977 EP_OUT_WAKERS[0].register(cx.waker()); 959 EP_OUT_WAKERS[0].register(cx.waker());
978 let regs = T::regs(); 960 let regs = T::regs();
979 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 961 if regs.epr(0).read().stat_tx() == Stat::NAK {
980 Poll::Ready(()) 962 Poll::Ready(())
981 } else { 963 } else {
982 Poll::Pending 964 Poll::Pending
@@ -992,15 +974,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
992 self.ep_in.write_data(data); 974 self.ep_in.write_data(data);
993 975
994 let regs = T::regs(); 976 let regs = T::regs();
995 unsafe { 977 regs.epr(0).write(|w| {
996 regs.epr(0).write(|w| { 978 w.set_ep_type(EpType::CONTROL);
997 w.set_ep_type(EpType::CONTROL); 979 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
998 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 980 w.set_ep_kind(last); // set OUT_STATUS if last.
999 w.set_ep_kind(last); // set OUT_STATUS if last. 981 w.set_ctr_rx(true); // don't clear
1000 w.set_ctr_rx(true); // don't clear 982 w.set_ctr_tx(true); // don't clear
1001 w.set_ctr_tx(true); // don't clear 983 });
1002 })
1003 };
1004 984
1005 trace!("WRITE OK"); 985 trace!("WRITE OK");
1006 986
@@ -1014,16 +994,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1014 self.ep_in.write_data(&[]); 994 self.ep_in.write_data(&[]);
1015 995
1016 // Set OUT=stall, IN=accept 996 // Set OUT=stall, IN=accept
1017 unsafe { 997 let epr = regs.epr(0).read();
1018 let epr = regs.epr(0).read(); 998 regs.epr(0).write(|w| {
1019 regs.epr(0).write(|w| { 999 w.set_ep_type(EpType::CONTROL);
1020 w.set_ep_type(EpType::CONTROL); 1000 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
1021 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1001 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
1022 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); 1002 w.set_ctr_rx(true); // don't clear
1023 w.set_ctr_rx(true); // don't clear 1003 w.set_ctr_tx(true); // don't clear
1024 w.set_ctr_tx(true); // don't clear 1004 });
1025 });
1026 }
1027 trace!("control: accept WAITING"); 1005 trace!("control: accept WAITING");
1028 1006
1029 // Wait is needed, so that we don't set the address too soon, breaking the status stage. 1007 // Wait is needed, so that we don't set the address too soon, breaking the status stage.
@@ -1031,7 +1009,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1031 poll_fn(|cx| { 1009 poll_fn(|cx| {
1032 EP_IN_WAKERS[0].register(cx.waker()); 1010 EP_IN_WAKERS[0].register(cx.waker());
1033 let regs = T::regs(); 1011 let regs = T::regs();
1034 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 1012 if regs.epr(0).read().stat_tx() == Stat::NAK {
1035 Poll::Ready(()) 1013 Poll::Ready(())
1036 } else { 1014 } else {
1037 Poll::Pending 1015 Poll::Pending
@@ -1047,16 +1025,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1047 trace!("control: reject"); 1025 trace!("control: reject");
1048 1026
1049 // Set IN+OUT to stall 1027 // Set IN+OUT to stall
1050 unsafe { 1028 let epr = regs.epr(0).read();
1051 let epr = regs.epr(0).read(); 1029 regs.epr(0).write(|w| {
1052 regs.epr(0).write(|w| { 1030 w.set_ep_type(EpType::CONTROL);
1053 w.set_ep_type(EpType::CONTROL); 1031 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
1054 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1032 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
1055 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); 1033 w.set_ctr_rx(true); // don't clear
1056 w.set_ctr_rx(true); // don't clear 1034 w.set_ctr_tx(true); // don't clear
1057 w.set_ctr_tx(true); // don't clear 1035 });
1058 });
1059 }
1060 } 1036 }
1061 1037
1062 async fn accept_set_address(&mut self, addr: u8) { 1038 async fn accept_set_address(&mut self, addr: u8) {
@@ -1064,11 +1040,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1064 1040
1065 let regs = T::regs(); 1041 let regs = T::regs();
1066 trace!("setting addr: {}", addr); 1042 trace!("setting addr: {}", addr);
1067 unsafe { 1043 regs.daddr().write(|w| {
1068 regs.daddr().write(|w| { 1044 w.set_ef(true);
1069 w.set_ef(true); 1045 w.set_add(addr);
1070 w.set_add(addr); 1046 });
1071 })
1072 }
1073 } 1047 }
1074} 1048}
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
index 193e0df0d..12e5f0e60 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -1,7 +1,5 @@
1use embassy_cortex_m::interrupt::Interrupt;
2
3use crate::peripherals;
4use crate::rcc::RccPeripheral; 1use crate::rcc::RccPeripheral;
2use crate::{interrupt, peripherals};
5 3
6#[cfg(feature = "nightly")] 4#[cfg(feature = "nightly")]
7mod usb; 5mod usb;
@@ -25,7 +23,7 @@ pub(crate) mod sealed {
25} 23}
26 24
27pub trait Instance: sealed::Instance + RccPeripheral { 25pub trait Instance: sealed::Instance + RccPeripheral {
28 type Interrupt: Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
29} 27}
30 28
31// Internal PHY pins 29// Internal PHY pins
@@ -109,7 +107,7 @@ foreach_interrupt!(
109 } 107 }
110 108
111 impl Instance for peripherals::USB_OTG_FS { 109 impl Instance for peripherals::USB_OTG_FS {
112 type Interrupt = crate::interrupt::$irq; 110 type Interrupt = crate::interrupt::typelevel::$irq;
113 } 111 }
114 }; 112 };
115 113
@@ -150,7 +148,7 @@ foreach_interrupt!(
150 148
151 fn regs() -> crate::pac::otg::Otg { 149 fn regs() -> crate::pac::otg::Otg {
152 // OTG HS registers are a superset of FS registers 150 // OTG HS registers are a superset of FS registers
153 crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0) 151 unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
154 } 152 }
155 153
156 #[cfg(feature = "nightly")] 154 #[cfg(feature = "nightly")]
@@ -161,7 +159,7 @@ foreach_interrupt!(
161 } 159 }
162 160
163 impl Instance for peripherals::USB_OTG_HS { 161 impl Instance for peripherals::USB_OTG_HS {
164 type Interrupt = crate::interrupt::$irq; 162 type Interrupt = crate::interrupt::typelevel::$irq;
165 } 163 }
166 }; 164 };
167); 165);
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 921a73c8b..8af5c7bd5 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -3,7 +3,6 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; 5use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
6use embassy_cortex_m::interrupt::InterruptExt;
7use embassy_hal_common::{into_ref, Peripheral}; 6use embassy_hal_common::{into_ref, Peripheral};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb_driver::{ 8use embassy_usb_driver::{
@@ -15,6 +14,7 @@ use futures::future::poll_fn;
15use super::*; 14use super::*;
16use crate::gpio::sealed::AFType; 15use crate::gpio::sealed::AFType;
17use crate::interrupt; 16use crate::interrupt;
17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::otg::{regs, vals}; 18use crate::pac::otg::{regs, vals};
19use crate::rcc::sealed::RccPeripheral; 19use crate::rcc::sealed::RccPeripheral;
20use crate::time::Hertz; 20use crate::time::Hertz;
@@ -24,25 +24,22 @@ pub struct InterruptHandler<T: Instance> {
24 _phantom: PhantomData<T>, 24 _phantom: PhantomData<T>,
25} 25}
26 26
27impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 27impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
28 unsafe fn on_interrupt() { 28 unsafe fn on_interrupt() {
29 trace!("irq"); 29 trace!("irq");
30 let r = T::regs(); 30 let r = T::regs();
31 let state = T::state(); 31 let state = T::state();
32 32
33 // SAFETY: atomic read/write 33 let ints = r.gintsts().read();
34 let ints = unsafe { r.gintsts().read() };
35 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { 34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
36 // Mask interrupts and notify `Bus` to process them 35 // Mask interrupts and notify `Bus` to process them
37 unsafe { r.gintmsk().write(|_| {}) }; 36 r.gintmsk().write(|_| {});
38 T::state().bus_waker.wake(); 37 T::state().bus_waker.wake();
39 } 38 }
40 39
41 // Handle RX 40 // Handle RX
42 // SAFETY: atomic read with no side effects 41 while r.gintsts().read().rxflvl() {
43 while unsafe { r.gintsts().read().rxflvl() } { 42 let status = r.grxstsp().read();
44 // SAFETY: atomic "pop" register
45 let status = unsafe { r.grxstsp().read() };
46 let ep_num = status.epnum() as usize; 43 let ep_num = status.epnum() as usize;
47 let len = status.bcnt() as usize; 44 let len = status.bcnt() as usize;
48 45
@@ -57,21 +54,15 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
57 if state.ep0_setup_ready.load(Ordering::Relaxed) == false { 54 if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
58 // SAFETY: exclusive access ensured by atomic bool 55 // SAFETY: exclusive access ensured by atomic bool
59 let data = unsafe { &mut *state.ep0_setup_data.get() }; 56 let data = unsafe { &mut *state.ep0_setup_data.get() };
60 // SAFETY: FIFO reads are exclusive to this IRQ 57 data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
61 unsafe { 58 data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
62 data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
63 data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
64 }
65 state.ep0_setup_ready.store(true, Ordering::Release); 59 state.ep0_setup_ready.store(true, Ordering::Release);
66 state.ep_out_wakers[0].wake(); 60 state.ep_out_wakers[0].wake();
67 } else { 61 } else {
68 error!("received SETUP before previous finished processing"); 62 error!("received SETUP before previous finished processing");
69 // discard FIFO 63 // discard FIFO
70 // SAFETY: FIFO reads are exclusive to IRQ 64 r.fifo(0).read();
71 unsafe { 65 r.fifo(0).read();
72 r.fifo(0).read();
73 r.fifo(0).read();
74 }
75 } 66 }
76 } 67 }
77 vals::Pktstsd::OUT_DATA_RX => { 68 vals::Pktstsd::OUT_DATA_RX => {
@@ -84,8 +75,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
84 75
85 for chunk in buf.chunks_mut(4) { 76 for chunk in buf.chunks_mut(4) {
86 // RX FIFO is shared so always read from fifo(0) 77 // RX FIFO is shared so always read from fifo(0)
87 // SAFETY: FIFO reads are exclusive to IRQ 78 let data = r.fifo(0).read().0;
88 let data = unsafe { r.fifo(0).read().0 };
89 chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); 79 chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
90 } 80 }
91 81
@@ -97,8 +87,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
97 // discard FIFO data 87 // discard FIFO data
98 let len_words = (len + 3) / 4; 88 let len_words = (len + 3) / 4;
99 for _ in 0..len_words { 89 for _ in 0..len_words {
100 // SAFETY: FIFO reads are exclusive to IRQ 90 r.fifo(0).read().data();
101 unsafe { r.fifo(0).read().data() };
102 } 91 }
103 } 92 }
104 } 93 }
@@ -114,24 +103,20 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
114 103
115 // IN endpoint interrupt 104 // IN endpoint interrupt
116 if ints.iepint() { 105 if ints.iepint() {
117 // SAFETY: atomic read with no side effects 106 let mut ep_mask = r.daint().read().iepint();
118 let mut ep_mask = unsafe { r.daint().read().iepint() };
119 let mut ep_num = 0; 107 let mut ep_num = 0;
120 108
121 // Iterate over endpoints while there are non-zero bits in the mask 109 // Iterate over endpoints while there are non-zero bits in the mask
122 while ep_mask != 0 { 110 while ep_mask != 0 {
123 if ep_mask & 1 != 0 { 111 if ep_mask & 1 != 0 {
124 // SAFETY: atomic read with no side effects 112 let ep_ints = r.diepint(ep_num).read();
125 let ep_ints = unsafe { r.diepint(ep_num).read() };
126 113
127 // clear all 114 // clear all
128 // SAFETY: DIEPINT is exclusive to IRQ 115 r.diepint(ep_num).write_value(ep_ints);
129 unsafe { r.diepint(ep_num).write_value(ep_ints) };
130 116
131 // TXFE is cleared in DIEPEMPMSK 117 // TXFE is cleared in DIEPEMPMSK
132 if ep_ints.txfe() { 118 if ep_ints.txfe() {
133 // SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW 119 critical_section::with(|_| {
134 critical_section::with(|_| unsafe {
135 r.diepempmsk().modify(|w| { 120 r.diepempmsk().modify(|w| {
136 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); 121 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
137 }); 122 });
@@ -172,8 +157,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
172macro_rules! config_ulpi_pins { 157macro_rules! config_ulpi_pins {
173 ($($pin:ident),*) => { 158 ($($pin:ident),*) => {
174 into_ref!($($pin),*); 159 into_ref!($($pin),*);
175 // NOTE(unsafe) Exclusive access to the registers 160 critical_section::with(|_| {
176 critical_section::with(|_| unsafe {
177 $( 161 $(
178 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 162 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
179 #[cfg(gpio_v2)] 163 #[cfg(gpio_v2)]
@@ -291,17 +275,15 @@ impl<'d, T: Instance> Driver<'d, T> {
291 /// Endpoint allocation will fail if it is too small. 275 /// Endpoint allocation will fail if it is too small.
292 pub fn new_fs( 276 pub fn new_fs(
293 _peri: impl Peripheral<P = T> + 'd, 277 _peri: impl Peripheral<P = T> + 'd,
294 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 278 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
295 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 279 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
296 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 280 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
297 ep_out_buffer: &'d mut [u8], 281 ep_out_buffer: &'d mut [u8],
298 ) -> Self { 282 ) -> Self {
299 into_ref!(dp, dm); 283 into_ref!(dp, dm);
300 284
301 unsafe { 285 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
302 dp.set_as_af(dp.af_num(), AFType::OutputPushPull); 286 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
303 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
304 }
305 287
306 Self { 288 Self {
307 phantom: PhantomData, 289 phantom: PhantomData,
@@ -322,7 +304,7 @@ impl<'d, T: Instance> Driver<'d, T> {
322 /// Endpoint allocation will fail if it is too small. 304 /// Endpoint allocation will fail if it is too small.
323 pub fn new_hs_ulpi( 305 pub fn new_hs_ulpi(
324 _peri: impl Peripheral<P = T> + 'd, 306 _peri: impl Peripheral<P = T> + 'd,
325 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 307 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
326 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd, 308 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
327 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd, 309 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
328 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd, 310 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
@@ -508,18 +490,15 @@ pub struct Bus<'d, T: Instance> {
508 490
509impl<'d, T: Instance> Bus<'d, T> { 491impl<'d, T: Instance> Bus<'d, T> {
510 fn restore_irqs() { 492 fn restore_irqs() {
511 // SAFETY: atomic write 493 T::regs().gintmsk().write(|w| {
512 unsafe { 494 w.set_usbrst(true);
513 T::regs().gintmsk().write(|w| { 495 w.set_enumdnem(true);
514 w.set_usbrst(true); 496 w.set_usbsuspm(true);
515 w.set_enumdnem(true); 497 w.set_wuim(true);
516 w.set_usbsuspm(true); 498 w.set_iepint(true);
517 w.set_wuim(true); 499 w.set_oepint(true);
518 w.set_iepint(true); 500 w.set_rxflvlm(true);
519 w.set_oepint(true); 501 });
520 w.set_rxflvlm(true);
521 });
522 }
523 } 502 }
524} 503}
525 504
@@ -533,8 +512,7 @@ impl<'d, T: Instance> Bus<'d, T> {
533 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); 512 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
534 trace!("configuring rx fifo size={}", rx_fifo_size_words); 513 trace!("configuring rx fifo size={}", rx_fifo_size_words);
535 514
536 // SAFETY: register is exclusive to `Bus` with `&mut self` 515 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
537 unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) };
538 516
539 // Configure TX (USB in direction) fifo size for each endpoint 517 // Configure TX (USB in direction) fifo size for each endpoint
540 let mut fifo_top = rx_fifo_size_words; 518 let mut fifo_top = rx_fifo_size_words;
@@ -549,13 +527,10 @@ impl<'d, T: Instance> Bus<'d, T> {
549 527
550 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; 528 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
551 529
552 // SAFETY: register is exclusive to `Bus` with `&mut self` 530 dieptxf.write(|w| {
553 unsafe { 531 w.set_fd(ep.fifo_size_words);
554 dieptxf.write(|w| { 532 w.set_sa(fifo_top);
555 w.set_fd(ep.fifo_size_words); 533 });
556 w.set_sa(fifo_top);
557 });
558 }
559 534
560 fifo_top += ep.fifo_size_words; 535 fifo_top += ep.fifo_size_words;
561 } 536 }
@@ -575,8 +550,7 @@ impl<'d, T: Instance> Bus<'d, T> {
575 // Configure IN endpoints 550 // Configure IN endpoints
576 for (index, ep) in self.ep_in.iter().enumerate() { 551 for (index, ep) in self.ep_in.iter().enumerate() {
577 if let Some(ep) = ep { 552 if let Some(ep) = ep {
578 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 553 critical_section::with(|_| {
579 critical_section::with(|_| unsafe {
580 r.diepctl(index).write(|w| { 554 r.diepctl(index).write(|w| {
581 if index == 0 { 555 if index == 0 {
582 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); 556 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@@ -593,8 +567,7 @@ impl<'d, T: Instance> Bus<'d, T> {
593 // Configure OUT endpoints 567 // Configure OUT endpoints
594 for (index, ep) in self.ep_out.iter().enumerate() { 568 for (index, ep) in self.ep_out.iter().enumerate() {
595 if let Some(ep) = ep { 569 if let Some(ep) = ep {
596 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW 570 critical_section::with(|_| {
597 critical_section::with(|_| unsafe {
598 r.doepctl(index).write(|w| { 571 r.doepctl(index).write(|w| {
599 if index == 0 { 572 if index == 0 {
600 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); 573 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@@ -618,26 +591,21 @@ impl<'d, T: Instance> Bus<'d, T> {
618 } 591 }
619 592
620 // Enable IRQs for allocated endpoints 593 // Enable IRQs for allocated endpoints
621 // SAFETY: register is exclusive to `Bus` with `&mut self` 594 r.daintmsk().modify(|w| {
622 unsafe { 595 w.set_iepm(ep_irq_mask(&self.ep_in));
623 r.daintmsk().modify(|w| { 596 // OUT interrupts not used, handled in RXFLVL
624 w.set_iepm(ep_irq_mask(&self.ep_in)); 597 // w.set_oepm(ep_irq_mask(&self.ep_out));
625 // OUT interrupts not used, handled in RXFLVL 598 });
626 // w.set_oepm(ep_irq_mask(&self.ep_out));
627 });
628 }
629 } 599 }
630 600
631 fn disable(&mut self) { 601 fn disable(&mut self) {
632 unsafe { T::Interrupt::steal() }.disable(); 602 T::Interrupt::disable();
633 603
634 <T as RccPeripheral>::disable(); 604 <T as RccPeripheral>::disable();
635 605
636 #[cfg(stm32l4)] 606 #[cfg(stm32l4)]
637 unsafe { 607 crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
638 crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); 608 // Cannot disable PWR, because other peripherals might be using it
639 // Cannot disable PWR, because other peripherals might be using it
640 }
641 } 609 }
642} 610}
643 611
@@ -653,7 +621,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
653 621
654 T::state().bus_waker.register(cx.waker()); 622 T::state().bus_waker.register(cx.waker());
655 623
656 let ints = unsafe { r.gintsts().read() }; 624 let ints = r.gintsts().read();
657 if ints.usbrst() { 625 if ints.usbrst() {
658 trace!("reset"); 626 trace!("reset");
659 627
@@ -661,34 +629,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
661 self.configure_endpoints(); 629 self.configure_endpoints();
662 630
663 // Reset address 631 // Reset address
664 // SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW 632 critical_section::with(|_| {
665 critical_section::with(|_| unsafe {
666 r.dcfg().modify(|w| { 633 r.dcfg().modify(|w| {
667 w.set_dad(0); 634 w.set_dad(0);
668 }); 635 });
669 }); 636 });
670 637
671 // SAFETY: atomic clear on rc_w1 register 638 r.gintsts().write(|w| w.set_usbrst(true)); // clear
672 unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear
673 Self::restore_irqs(); 639 Self::restore_irqs();
674 } 640 }
675 641
676 if ints.enumdne() { 642 if ints.enumdne() {
677 trace!("enumdne"); 643 trace!("enumdne");
678 644
679 // SAFETY: atomic read with no side effects 645 let speed = r.dsts().read().enumspd();
680 let speed = unsafe { r.dsts().read().enumspd() };
681 trace!(" speed={}", speed.0); 646 trace!(" speed={}", speed.0);
682 647
683 // SAFETY: register is only accessed by `Bus` under `&mut self` 648 r.gusbcfg().modify(|w| {
684 unsafe { 649 w.set_trdt(calculate_trdt(speed, T::frequency()));
685 r.gusbcfg().modify(|w| { 650 });
686 w.set_trdt(calculate_trdt(speed, T::frequency()));
687 })
688 };
689 651
690 // SAFETY: atomic clear on rc_w1 register 652 r.gintsts().write(|w| w.set_enumdne(true)); // clear
691 unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear
692 Self::restore_irqs(); 653 Self::restore_irqs();
693 654
694 return Poll::Ready(Event::Reset); 655 return Poll::Ready(Event::Reset);
@@ -696,16 +657,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
696 657
697 if ints.usbsusp() { 658 if ints.usbsusp() {
698 trace!("suspend"); 659 trace!("suspend");
699 // SAFETY: atomic clear on rc_w1 register 660 r.gintsts().write(|w| w.set_usbsusp(true)); // clear
700 unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear
701 Self::restore_irqs(); 661 Self::restore_irqs();
702 return Poll::Ready(Event::Suspend); 662 return Poll::Ready(Event::Suspend);
703 } 663 }
704 664
705 if ints.wkupint() { 665 if ints.wkupint() {
706 trace!("resume"); 666 trace!("resume");
707 // SAFETY: atomic clear on rc_w1 register 667 r.gintsts().write(|w| w.set_wkupint(true)); // clear
708 unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear
709 Self::restore_irqs(); 668 Self::restore_irqs();
710 return Poll::Ready(Event::Resume); 669 return Poll::Ready(Event::Resume);
711 } 670 }
@@ -727,8 +686,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
727 let regs = T::regs(); 686 let regs = T::regs();
728 match ep_addr.direction() { 687 match ep_addr.direction() {
729 Direction::Out => { 688 Direction::Out => {
730 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW 689 critical_section::with(|_| {
731 critical_section::with(|_| unsafe {
732 regs.doepctl(ep_addr.index()).modify(|w| { 690 regs.doepctl(ep_addr.index()).modify(|w| {
733 w.set_stall(stalled); 691 w.set_stall(stalled);
734 }); 692 });
@@ -737,8 +695,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
737 T::state().ep_out_wakers[ep_addr.index()].wake(); 695 T::state().ep_out_wakers[ep_addr.index()].wake();
738 } 696 }
739 Direction::In => { 697 Direction::In => {
740 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 698 critical_section::with(|_| {
741 critical_section::with(|_| unsafe {
742 regs.diepctl(ep_addr.index()).modify(|w| { 699 regs.diepctl(ep_addr.index()).modify(|w| {
743 w.set_stall(stalled); 700 w.set_stall(stalled);
744 }); 701 });
@@ -758,10 +715,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
758 715
759 let regs = T::regs(); 716 let regs = T::regs();
760 717
761 // SAFETY: atomic read with no side effects
762 match ep_addr.direction() { 718 match ep_addr.direction() {
763 Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() }, 719 Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
764 Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() }, 720 Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
765 } 721 }
766 } 722 }
767 723
@@ -777,8 +733,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
777 let r = T::regs(); 733 let r = T::regs();
778 match ep_addr.direction() { 734 match ep_addr.direction() {
779 Direction::Out => { 735 Direction::Out => {
780 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW 736 critical_section::with(|_| {
781 critical_section::with(|_| unsafe {
782 // cancel transfer if active 737 // cancel transfer if active
783 if !enabled && r.doepctl(ep_addr.index()).read().epena() { 738 if !enabled && r.doepctl(ep_addr.index()).read().epena() {
784 r.doepctl(ep_addr.index()).modify(|w| { 739 r.doepctl(ep_addr.index()).modify(|w| {
@@ -796,8 +751,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
796 T::state().ep_out_wakers[ep_addr.index()].wake(); 751 T::state().ep_out_wakers[ep_addr.index()].wake();
797 } 752 }
798 Direction::In => { 753 Direction::In => {
799 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 754 critical_section::with(|_| {
800 critical_section::with(|_| unsafe {
801 // cancel transfer if active 755 // cancel transfer if active
802 if !enabled && r.diepctl(ep_addr.index()).read().epena() { 756 if !enabled && r.diepctl(ep_addr.index()).read().epena() {
803 r.diepctl(ep_addr.index()).modify(|w| { 757 r.diepctl(ep_addr.index()).modify(|w| {
@@ -820,171 +774,192 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
820 async fn enable(&mut self) { 774 async fn enable(&mut self) {
821 trace!("enable"); 775 trace!("enable");
822 776
823 // SAFETY: registers are only accessed by `Bus` under `&mut self` 777 #[cfg(stm32l4)]
824 unsafe { 778 {
825 #[cfg(stm32l4)] 779 crate::peripherals::PWR::enable();
826 { 780 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
827 crate::peripherals::PWR::enable(); 781 }
828 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
829 }
830 782
831 #[cfg(stm32h7)] 783 #[cfg(stm32f7)]
832 { 784 {
833 // If true, VDD33USB is generated by internal regulator from VDD50USB 785 // Enable ULPI clock if external PHY is used
834 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) 786 let ulpien = !self.phy_type.internal();
835 // TODO: unhardcode 787 critical_section::with(|_| {
836 let internal_regulator = false; 788 crate::pac::RCC.ahb1enr().modify(|w| {
789 if T::HIGH_SPEED {
790 w.set_usb_otg_hsulpien(ulpien);
791 } else {
792 w.set_usb_otg_hsen(ulpien);
793 }
794 });
837 795
838 // Enable USB power 796 // Low power mode
839 critical_section::with(|_| { 797 crate::pac::RCC.ahb1lpenr().modify(|w| {
840 crate::pac::PWR.cr3().modify(|w| { 798 if T::HIGH_SPEED {
841 w.set_usb33den(true); 799 w.set_usb_otg_hsulpilpen(ulpien);
842 w.set_usbregen(internal_regulator); 800 } else {
843 }) 801 w.set_usb_otg_hslpen(ulpien);
802 }
844 }); 803 });
804 });
805 }
845 806
846 // Wait for USB power to stabilize 807 #[cfg(stm32h7)]
847 while !crate::pac::PWR.cr3().read().usb33rdy() {} 808 {
809 // If true, VDD33USB is generated by internal regulator from VDD50USB
810 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
811 // TODO: unhardcode
812 let internal_regulator = false;
813
814 // Enable USB power
815 critical_section::with(|_| {
816 crate::pac::PWR.cr3().modify(|w| {
817 w.set_usb33den(true);
818 w.set_usbregen(internal_regulator);
819 })
820 });
848 821
849 // Use internal 48MHz HSI clock. Should be enabled in RCC by default. 822 // Wait for USB power to stabilize
850 critical_section::with(|_| { 823 while !crate::pac::PWR.cr3().read().usb33rdy() {}
851 crate::pac::RCC
852 .d2ccip2r()
853 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
854 });
855 824
856 // Enable ULPI clock if external PHY is used 825 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
857 let ulpien = !self.phy_type.internal(); 826 critical_section::with(|_| {
858 critical_section::with(|_| { 827 crate::pac::RCC
859 crate::pac::RCC.ahb1enr().modify(|w| { 828 .d2ccip2r()
860 if T::HIGH_SPEED { 829 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
861 w.set_usb_otg_hs_ulpien(ulpien); 830 });
862 } else { 831
863 w.set_usb_otg_fs_ulpien(ulpien); 832 // Enable ULPI clock if external PHY is used
864 } 833 let ulpien = !self.phy_type.internal();
865 }); 834 critical_section::with(|_| {
866 crate::pac::RCC.ahb1lpenr().modify(|w| { 835 crate::pac::RCC.ahb1enr().modify(|w| {
867 if T::HIGH_SPEED { 836 if T::HIGH_SPEED {
868 w.set_usb_otg_hs_ulpilpen(ulpien); 837 w.set_usb_otg_hs_ulpien(ulpien);
869 } else { 838 } else {
870 w.set_usb_otg_fs_ulpilpen(ulpien); 839 w.set_usb_otg_fs_ulpien(ulpien);
871 } 840 }
872 });
873 }); 841 });
874 } 842 crate::pac::RCC.ahb1lpenr().modify(|w| {
843 if T::HIGH_SPEED {
844 w.set_usb_otg_hs_ulpilpen(ulpien);
845 } else {
846 w.set_usb_otg_fs_ulpilpen(ulpien);
847 }
848 });
849 });
850 }
875 851
876 #[cfg(stm32u5)] 852 #[cfg(stm32u5)]
877 { 853 {
878 // Enable USB power 854 // Enable USB power
879 critical_section::with(|_| { 855 critical_section::with(|_| {
880 crate::pac::RCC.ahb3enr().modify(|w| { 856 crate::pac::RCC.ahb3enr().modify(|w| {
881 w.set_pwren(true); 857 w.set_pwren(true);
882 }); 858 });
883 cortex_m::asm::delay(2); 859 cortex_m::asm::delay(2);
884 860
885 crate::pac::PWR.svmcr().modify(|w| { 861 crate::pac::PWR.svmcr().modify(|w| {
886 w.set_usv(true); 862 w.set_usv(true);
887 w.set_uvmen(true); 863 w.set_uvmen(true);
888 });
889 }); 864 });
865 });
890 866
891 // Wait for USB power to stabilize 867 // Wait for USB power to stabilize
892 while !crate::pac::PWR.svmsr().read().vddusbrdy() {} 868 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
893 869
894 // Select HSI48 as USB clock source. 870 // Select HSI48 as USB clock source.
895 critical_section::with(|_| { 871 critical_section::with(|_| {
896 crate::pac::RCC.ccipr1().modify(|w| { 872 crate::pac::RCC.ccipr1().modify(|w| {
897 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); 873 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
898 }) 874 })
899 }); 875 });
900 } 876 }
901 877
902 <T as RccPeripheral>::enable(); 878 <T as RccPeripheral>::enable();
903 <T as RccPeripheral>::reset(); 879 <T as RccPeripheral>::reset();
904 880
905 T::Interrupt::steal().unpend(); 881 T::Interrupt::unpend();
906 T::Interrupt::steal().enable(); 882 unsafe { T::Interrupt::enable() };
907 883
908 let r = T::regs(); 884 let r = T::regs();
909 let core_id = r.cid().read().0; 885 let core_id = r.cid().read().0;
910 info!("Core id {:08x}", core_id); 886 info!("Core id {:08x}", core_id);
911 887
912 // Wait for AHB ready. 888 // Wait for AHB ready.
913 while !r.grstctl().read().ahbidl() {} 889 while !r.grstctl().read().ahbidl() {}
914 890
915 // Configure as device. 891 // Configure as device.
916 r.gusbcfg().write(|w| { 892 r.gusbcfg().write(|w| {
917 // Force device mode 893 // Force device mode
918 w.set_fdmod(true); 894 w.set_fdmod(true);
919 // Enable internal full-speed PHY 895 // Enable internal full-speed PHY
920 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); 896 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
921 }); 897 });
922 898
923 // Configuring Vbus sense and SOF output 899 // Configuring Vbus sense and SOF output
924 match core_id { 900 match core_id {
925 0x0000_1200 | 0x0000_1100 => { 901 0x0000_1200 | 0x0000_1100 => {
926 assert!(self.phy_type != PhyType::InternalHighSpeed); 902 assert!(self.phy_type != PhyType::InternalHighSpeed);
927 903
928 r.gccfg_v1().modify(|w| { 904 r.gccfg_v1().modify(|w| {
929 // Enable internal full-speed PHY, logic is inverted 905 // Enable internal full-speed PHY, logic is inverted
930 w.set_pwrdwn(self.phy_type.internal()); 906 w.set_pwrdwn(self.phy_type.internal());
931 }); 907 });
932 908
933 // F429-like chips have the GCCFG.NOVBUSSENS bit 909 // F429-like chips have the GCCFG.NOVBUSSENS bit
934 r.gccfg_v1().modify(|w| { 910 r.gccfg_v1().modify(|w| {
935 w.set_novbussens(true); 911 w.set_novbussens(true);
936 w.set_vbusasen(false); 912 w.set_vbusasen(false);
937 w.set_vbusbsen(false); 913 w.set_vbusbsen(false);
938 w.set_sofouten(false); 914 w.set_sofouten(false);
939 }); 915 });
940 } 916 }
941 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { 917 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
942 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning 918 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
943 r.gccfg_v2().modify(|w| { 919 r.gccfg_v2().modify(|w| {
944 // Enable internal full-speed PHY, logic is inverted 920 // Enable internal full-speed PHY, logic is inverted
945 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); 921 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
946 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); 922 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
947 }); 923 });
948 924
949 r.gccfg_v2().modify(|w| { 925 r.gccfg_v2().modify(|w| {
950 w.set_vbden(false); 926 w.set_vbden(false);
951 }); 927 });
952 928
953 // Force B-peripheral session 929 // Force B-peripheral session
954 r.gotgctl().modify(|w| { 930 r.gotgctl().modify(|w| {
955 w.set_bvaloen(true); 931 w.set_bvaloen(true);
956 w.set_bvaloval(true); 932 w.set_bvaloval(true);
957 }); 933 });
958 }
959 _ => unimplemented!("Unknown USB core id {:X}", core_id),
960 } 934 }
935 _ => unimplemented!("Unknown USB core id {:X}", core_id),
936 }
961 937
962 // Soft disconnect. 938 // Soft disconnect.
963 r.dctl().write(|w| w.set_sdis(true)); 939 r.dctl().write(|w| w.set_sdis(true));
964 940
965 // Set speed. 941 // Set speed.
966 r.dcfg().write(|w| { 942 r.dcfg().write(|w| {
967 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); 943 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
968 w.set_dspd(self.phy_type.to_dspd()); 944 w.set_dspd(self.phy_type.to_dspd());
969 }); 945 });
970 946
971 // Unmask transfer complete EP interrupt 947 // Unmask transfer complete EP interrupt
972 r.diepmsk().write(|w| { 948 r.diepmsk().write(|w| {
973 w.set_xfrcm(true); 949 w.set_xfrcm(true);
974 }); 950 });
975 951
976 // Unmask and clear core interrupts 952 // Unmask and clear core interrupts
977 Bus::<T>::restore_irqs(); 953 Bus::<T>::restore_irqs();
978 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); 954 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
979 955
980 // Unmask global interrupt 956 // Unmask global interrupt
981 r.gahbcfg().write(|w| { 957 r.gahbcfg().write(|w| {
982 w.set_gint(true); // unmask global interrupt 958 w.set_gint(true); // unmask global interrupt
983 }); 959 });
984 960
985 // Connect 961 // Connect
986 r.dctl().write(|w| w.set_sdis(false)); 962 r.dctl().write(|w| w.set_sdis(false));
987 }
988 963
989 self.enabled = true; 964 self.enabled = true;
990 } 965 }
@@ -1042,8 +1017,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> {
1042 1017
1043 T::state().ep_in_wakers[ep_index].register(cx.waker()); 1018 T::state().ep_in_wakers[ep_index].register(cx.waker());
1044 1019
1045 // SAFETY: atomic read without side effects 1020 if T::regs().diepctl(ep_index).read().usbaep() {
1046 if unsafe { T::regs().diepctl(ep_index).read().usbaep() } {
1047 Poll::Ready(()) 1021 Poll::Ready(())
1048 } else { 1022 } else {
1049 Poll::Pending 1023 Poll::Pending
@@ -1064,8 +1038,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
1064 1038
1065 T::state().ep_out_wakers[ep_index].register(cx.waker()); 1039 T::state().ep_out_wakers[ep_index].register(cx.waker());
1066 1040
1067 // SAFETY: atomic read without side effects 1041 if T::regs().doepctl(ep_index).read().usbaep() {
1068 if unsafe { T::regs().doepctl(ep_index).read().usbaep() } {
1069 Poll::Ready(()) 1042 Poll::Ready(())
1070 } else { 1043 } else {
1071 Poll::Pending 1044 Poll::Pending
@@ -1100,8 +1073,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
1100 // Release buffer 1073 // Release buffer
1101 state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); 1074 state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
1102 1075
1103 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW 1076 critical_section::with(|_| {
1104 critical_section::with(|_| unsafe {
1105 // Receive 1 packet 1077 // Receive 1 packet
1106 T::regs().doeptsiz(index).modify(|w| { 1078 T::regs().doeptsiz(index).modify(|w| {
1107 w.set_xfrsiz(self.info.max_packet_size as _); 1079 w.set_xfrsiz(self.info.max_packet_size as _);
@@ -1139,8 +1111,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1139 poll_fn(|cx| { 1111 poll_fn(|cx| {
1140 state.ep_in_wakers[index].register(cx.waker()); 1112 state.ep_in_wakers[index].register(cx.waker());
1141 1113
1142 // SAFETY: atomic read with no side effects 1114 let diepctl = r.diepctl(index).read();
1143 let diepctl = unsafe { r.diepctl(index).read() };
1144 if !diepctl.usbaep() { 1115 if !diepctl.usbaep() {
1145 Poll::Ready(Err(EndpointError::Disabled)) 1116 Poll::Ready(Err(EndpointError::Disabled))
1146 } else if !diepctl.epena() { 1117 } else if !diepctl.epena() {
@@ -1157,12 +1128,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1157 1128
1158 let size_words = (buf.len() + 3) / 4; 1129 let size_words = (buf.len() + 3) / 4;
1159 1130
1160 // SAFETY: atomic read with no side effects 1131 let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize;
1161 let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize };
1162 if size_words > fifo_space { 1132 if size_words > fifo_space {
1163 // Not enough space in fifo, enable tx fifo empty interrupt 1133 // Not enough space in fifo, enable tx fifo empty interrupt
1164 // SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW 1134 critical_section::with(|_| {
1165 critical_section::with(|_| unsafe {
1166 r.diepempmsk().modify(|w| { 1135 r.diepempmsk().modify(|w| {
1167 w.set_ineptxfem(w.ineptxfem() | (1 << index)); 1136 w.set_ineptxfem(w.ineptxfem() | (1 << index));
1168 }); 1137 });
@@ -1178,18 +1147,14 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1178 .await 1147 .await
1179 } 1148 }
1180 1149
1181 // SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self` 1150 // Setup transfer size
1182 unsafe { 1151 r.dieptsiz(index).write(|w| {
1183 // Setup transfer size 1152 w.set_mcnt(1);
1184 r.dieptsiz(index).write(|w| { 1153 w.set_pktcnt(1);
1185 w.set_mcnt(1); 1154 w.set_xfrsiz(buf.len() as _);
1186 w.set_pktcnt(1); 1155 });
1187 w.set_xfrsiz(buf.len() as _);
1188 });
1189 }
1190 1156
1191 // SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW 1157 critical_section::with(|_| {
1192 critical_section::with(|_| unsafe {
1193 // Enable endpoint 1158 // Enable endpoint
1194 r.diepctl(index).modify(|w| { 1159 r.diepctl(index).modify(|w| {
1195 w.set_cnak(true); 1160 w.set_cnak(true);
@@ -1201,8 +1166,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1201 for chunk in buf.chunks(4) { 1166 for chunk in buf.chunks(4) {
1202 let mut tmp = [0u8; 4]; 1167 let mut tmp = [0u8; 4];
1203 tmp[0..chunk.len()].copy_from_slice(chunk); 1168 tmp[0..chunk.len()].copy_from_slice(chunk);
1204 // SAFETY: FIFO is exclusive to this endpoint under `&mut self` 1169 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
1205 unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) };
1206 } 1170 }
1207 1171
1208 trace!("write done ep={:?}", self.info.addr); 1172 trace!("write done ep={:?}", self.info.addr);
@@ -1234,17 +1198,15 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
1234 state.ep0_setup_ready.store(false, Ordering::Release); 1198 state.ep0_setup_ready.store(false, Ordering::Release);
1235 1199
1236 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section 1200 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1237 unsafe { 1201 // Receive 1 SETUP packet
1238 // Receive 1 SETUP packet 1202 T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1239 T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { 1203 w.set_rxdpid_stupcnt(1);
1240 w.set_rxdpid_stupcnt(1); 1204 });
1241 });
1242 1205
1243 // Clear NAK to indicate we are ready to receive more data 1206 // Clear NAK to indicate we are ready to receive more data
1244 T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { 1207 T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
1245 w.set_cnak(true); 1208 w.set_cnak(true);
1246 }); 1209 });
1247 }
1248 1210
1249 trace!("SETUP received: {:?}", data); 1211 trace!("SETUP received: {:?}", data);
1250 Poll::Ready(data) 1212 Poll::Ready(data)
@@ -1289,20 +1251,18 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
1289 trace!("control: reject"); 1251 trace!("control: reject");
1290 1252
1291 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section 1253 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1292 unsafe { 1254 let regs = T::regs();
1293 let regs = T::regs(); 1255 regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
1294 regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { 1256 w.set_stall(true);
1295 w.set_stall(true); 1257 });
1296 }); 1258 regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
1297 regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { 1259 w.set_stall(true);
1298 w.set_stall(true); 1260 });
1299 });
1300 }
1301 } 1261 }
1302 1262
1303 async fn accept_set_address(&mut self, addr: u8) { 1263 async fn accept_set_address(&mut self, addr: u8) {
1304 trace!("setting addr: {}", addr); 1264 trace!("setting addr: {}", addr);
1305 critical_section::with(|_| unsafe { 1265 critical_section::with(|_| {
1306 T::regs().dcfg().modify(|w| { 1266 T::regs().dcfg().modify(|w| {
1307 w.set_dad(addr); 1267 w.set_dad(addr);
1308 }); 1268 });
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 18ebf97d8..5907a4e54 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
48 let rl = reload_value(psc, timeout_us); 48 let rl = reload_value(psc, timeout_us);
49 49
50 let wdg = T::regs(); 50 let wdg = T::regs();
51 unsafe { 51 wdg.kr().write(|w| w.set_key(Key::ENABLE));
52 wdg.kr().write(|w| w.set_key(Key::ENABLE)); 52 wdg.pr().write(|w| w.set_pr(Pr(pr)));
53 wdg.pr().write(|w| w.set_pr(Pr(pr))); 53 wdg.rlr().write(|w| w.set_rl(rl));
54 wdg.rlr().write(|w| w.set_rl(rl));
55 }
56 54
57 trace!( 55 trace!(
58 "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})", 56 "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
@@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
67 } 65 }
68 } 66 }
69 67
70 pub unsafe fn unleash(&mut self) { 68 pub fn unleash(&mut self) {
71 T::regs().kr().write(|w| w.set_key(Key::START)); 69 T::regs().kr().write(|w| w.set_key(Key::START));
72 } 70 }
73 71
74 pub unsafe fn pet(&mut self) { 72 pub fn pet(&mut self) {
75 T::regs().kr().write(|w| w.set_key(Key::RESET)); 73 T::regs().kr().write(|w| w.set_key(Key::RESET));
76 } 74 }
77} 75}
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index bc06b92cd..340724eab 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -45,4 +45,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] }
45 45
46# Enable critical-section implementation for std, for tests 46# Enable critical-section implementation for std, for tests
47critical-section = { version = "1.1", features = ["std"] } 47critical-section = { version = "1.1", features = ["std"] }
48static_cell = "1.0" 48static_cell = "1.1"
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-sync/src/fmt.rs
+++ b/embassy-sync/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index ee27cdec8..db6ebb08b 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -294,6 +294,16 @@ where
294 WriteFuture { pipe: self, buf } 294 WriteFuture { pipe: self, buf }
295 } 295 }
296 296
297 /// Write all bytes to the pipe.
298 ///
299 /// This method writes all bytes from `buf` into the pipe
300 pub async fn write_all(&self, mut buf: &[u8]) {
301 while !buf.is_empty() {
302 let n = self.write(buf).await;
303 buf = &buf[n..];
304 }
305 }
306
297 /// Attempt to immediately write some bytes to the pipe. 307 /// Attempt to immediately write some bytes to the pipe.
298 /// 308 ///
299 /// This method will either write a nonzero amount of bytes to the pipe immediately, 309 /// This method will either write a nonzero amount of bytes to the pipe immediately,
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 1d8dd13ce..6e50c40ba 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -138,7 +138,7 @@ macro_rules! run {
138 ( $x:expr, $l:expr, $p:ident ) => { 138 ( $x:expr, $l:expr, $p:ident ) => {
139 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); 139 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new();
140 unsafe { 140 unsafe {
141 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level($l)); 141 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l));
142 } 142 }
143 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; 143 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await;
144 }; 144 };
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index 8d60f18be..c1dc99eec 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -30,3 +30,4 @@ debug = ["defmt-rtt", "defmt"]
30 30
31[profile.release] 31[profile.release]
32debug = true 32debug = true
33opt-level = 's'
diff --git a/examples/nrf52840-rtic/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml
new file mode 100644
index 000000000..3872e7189
--- /dev/null
+++ b/examples/nrf52840-rtic/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
new file mode 100644
index 000000000..0f9048b0f
--- /dev/null
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-rtic-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8rtic = { version = "2", features = ["thumbv7-backend"] }
9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/nrf52840-rtic/build.rs b/examples/nrf52840-rtic/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840-rtic/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf52840-rtic/memory.x b/examples/nrf52840-rtic/memory.x
new file mode 100644
index 000000000..9b04edec0
--- /dev/null
+++ b/examples/nrf52840-rtic/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
new file mode 100644
index 000000000..a682c1932
--- /dev/null
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use {defmt_rtt as _, panic_probe as _};
6
7#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])]
8mod app {
9 use defmt::info;
10 use embassy_nrf::gpio::{Level, Output, OutputDrive};
11 use embassy_nrf::peripherals;
12 use embassy_time::{Duration, Timer};
13
14 #[shared]
15 struct Shared {}
16
17 #[local]
18 struct Local {}
19
20 #[init]
21 fn init(_: init::Context) -> (Shared, Local) {
22 info!("Hello World!");
23
24 let p = embassy_nrf::init(Default::default());
25 blink::spawn(p.P0_13).map_err(|_| ()).unwrap();
26
27 (Shared {}, Local {})
28 }
29
30 #[task(priority = 1)]
31 async fn blink(_cx: blink::Context, pin: peripherals::P0_13) {
32 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
33
34 loop {
35 info!("off!");
36 led.set_high();
37 Timer::after(Duration::from_millis(300)).await;
38 info!("on!");
39 led.set_low();
40 Timer::after(Duration::from_millis(300)).await;
41 }
42 }
43}
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 0f75b3ab7..6627b7861 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", 9nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", "static_cell/nightly",
10 "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"] 10 "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"]
11 11
12[dependencies] 12[dependencies]
@@ -26,7 +26,7 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr
26defmt = "0.3" 26defmt = "0.3"
27defmt-rtt = "0.4" 27defmt-rtt = "0.4"
28 28
29static_cell = "1.0" 29static_cell = "1.1"
30cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 30cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
31cortex-m-rt = "0.7.0" 31cortex-m-rt = "0.7.0"
32panic-probe = { version = "0.3", features = ["print-defmt"] } 32panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 851e189ea..aab819117 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::{info, unwrap}; 61use defmt::{info, unwrap};
65use embassy_nrf::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_nrf::interrupt; 63use embassy_nrf::interrupt;
67use embassy_nrf::pac::Interrupt; 64use embassy_nrf::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_nrf::init(Default::default()); 129 let _p = embassy_nrf::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: SWI1_EGU1, priority level 6 131 // High-priority executor: SWI1_EGU1, priority level 6
136 unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) }; 132 interrupt::SWI1_EGU1.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1); 133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: SWI0_EGU0, priority level 7 136 // Medium-priority executor: SWI0_EGU0, priority level 7
141 unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) }; 137 interrupt::SWI0_EGU0.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0); 138 let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 786025c43..f527c0d7f 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -16,7 +16,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
17use embassy_usb::{Builder, Config, UsbDevice}; 17use embassy_usb::{Builder, Config, UsbDevice};
18use embedded_io::asynch::Write; 18use embedded_io::asynch::Write;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21 21
22bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
@@ -27,15 +27,6 @@ bind_interrupts!(struct Irqs {
27 27
28type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 28type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
29 29
30macro_rules! singleton {
31 ($val:expr) => {{
32 type T = impl Sized;
33 static STATIC_CELL: StaticCell<T> = StaticCell::new();
34 let (x,) = STATIC_CELL.init(($val,));
35 x
36 }};
37}
38
39const MTU: usize = 1514; 30const MTU: usize = 1514;
40 31
41#[embassy_executor::task] 32#[embassy_executor::task]
@@ -83,11 +74,11 @@ async fn main(spawner: Spawner) {
83 let mut builder = Builder::new( 74 let mut builder = Builder::new(
84 driver, 75 driver,
85 config, 76 config,
86 &mut singleton!([0; 256])[..], 77 &mut make_static!([0; 256])[..],
87 &mut singleton!([0; 256])[..], 78 &mut make_static!([0; 256])[..],
88 &mut singleton!([0; 256])[..], 79 &mut make_static!([0; 256])[..],
89 &mut singleton!([0; 128])[..], 80 &mut make_static!([0; 128])[..],
90 &mut singleton!([0; 128])[..], 81 &mut make_static!([0; 128])[..],
91 ); 82 );
92 83
93 // Our MAC addr. 84 // Our MAC addr.
@@ -96,22 +87,22 @@ async fn main(spawner: Spawner) {
96 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 87 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
97 88
98 // Create classes on the builder. 89 // Create classes on the builder.
99 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); 90 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
100 91
101 // Build the builder. 92 // Build the builder.
102 let usb = builder.build(); 93 let usb = builder.build();
103 94
104 unwrap!(spawner.spawn(usb_task(usb))); 95 unwrap!(spawner.spawn(usb_task(usb)));
105 96
106 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); 97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
107 unwrap!(spawner.spawn(usb_ncm_task(runner))); 98 unwrap!(spawner.spawn(usb_ncm_task(runner)));
108 99
109 let config = embassy_net::Config::Dhcp(Default::default()); 100 let config = embassy_net::Config::dhcpv4(Default::default());
110 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 101 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
111 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 102 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
112 // dns_servers: Vec::new(), 103 // dns_servers: Vec::new(),
113 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 104 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
114 //}); 105 // });
115 106
116 // Generate random seed 107 // Generate random seed
117 let mut rng = Rng::new(p.RNG, Irqs); 108 let mut rng = Rng::new(p.RNG, Irqs);
@@ -120,7 +111,12 @@ async fn main(spawner: Spawner) {
120 let seed = u64::from_le_bytes(seed); 111 let seed = u64::from_le_bytes(seed);
121 112
122 // Init network stack 113 // Init network stack
123 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 114 let stack = &*make_static!(Stack::new(
115 device,
116 config,
117 make_static!(StackResources::<2>::new()),
118 seed
119 ));
124 120
125 unwrap!(spawner.spawn(net_task(stack))); 121 unwrap!(spawner.spawn(net_task(stack)));
126 122
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index ac22d9499..cd4392903 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -12,7 +12,7 @@ use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
14use embassy_usb::{Builder, Config, UsbDevice}; 14use embassy_usb::{Builder, Config, UsbDevice};
15use static_cell::StaticCell; 15use static_cell::make_static;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18bind_interrupts!(struct Irqs { 18bind_interrupts!(struct Irqs {
@@ -20,15 +20,6 @@ bind_interrupts!(struct Irqs {
20 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 20 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
21}); 21});
22 22
23macro_rules! singleton {
24 ($val:expr) => {{
25 type T = impl Sized;
26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
27 let (x,) = STATIC_CELL.init(($val,));
28 x
29 }};
30}
31
32type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 23type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
33 24
34#[embassy_executor::task] 25#[embassy_executor::task]
@@ -73,17 +64,17 @@ async fn main(spawner: Spawner) {
73 config.device_protocol = 0x01; 64 config.device_protocol = 0x01;
74 config.composite_with_iads = true; 65 config.composite_with_iads = true;
75 66
76 let state = singleton!(State::new()); 67 let state = make_static!(State::new());
77 68
78 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
79 let mut builder = Builder::new( 70 let mut builder = Builder::new(
80 driver, 71 driver,
81 config, 72 config,
82 &mut singleton!([0; 256])[..], 73 &mut make_static!([0; 256])[..],
83 &mut singleton!([0; 256])[..], 74 &mut make_static!([0; 256])[..],
84 &mut singleton!([0; 256])[..], 75 &mut make_static!([0; 256])[..],
85 &mut singleton!([0; 128])[..], 76 &mut make_static!([0; 128])[..],
86 &mut singleton!([0; 128])[..], 77 &mut make_static!([0; 128])[..],
87 ); 78 );
88 79
89 // Create classes on the builder. 80 // Create classes on the builder.
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 40422e7df..efb66bae6 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -42,7 +42,7 @@ embedded-io = { version = "0.4.0", features = [ "async" ]}
42defmt = "0.3" 42defmt = "0.3"
43defmt-rtt = "0.4" 43defmt-rtt = "0.4"
44 44
45static_cell = "1.0" 45static_cell = { version = "1.1", features = ["nightly"]}
46cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 46cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
47cortex-m-rt = "0.7.0" 47cortex-m-rt = "0.7.0"
48panic-probe = { version = "0.3", features = ["print-defmt"] } 48panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 58b701915..48f3a26bb 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -45,7 +45,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
45embedded-hal-async = "0.2.0-alpha.1" 45embedded-hal-async = "0.2.0-alpha.1"
46embedded-io = { version = "0.4.0", features = ["async", "defmt"] } 46embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
47embedded-storage = { version = "0.3" } 47embedded-storage = { version = "0.3" }
48static_cell = "1.0.0" 48static_cell = { version = "1.1", features = ["nightly"]}
49log = "0.4" 49log = "0.4"
50pio-proc = "0.2" 50pio-proc = "0.2"
51pio = "0.2.1" 51pio = "0.2.1"
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index c5422c616..0d246c093 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -9,9 +9,12 @@ use {defmt_rtt as _, panic_probe as _};
9#[embassy_executor::main] 9#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 10async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 11 let p = embassy_rp::init(Default::default());
12 let button = Input::new(p.PIN_28, Pull::Up);
13 let mut led = Output::new(p.PIN_25, Level::Low); 12 let mut led = Output::new(p.PIN_25, Level::Low);
14 13
14 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
15 // You need to add your own button.
16 let button = Input::new(p.PIN_28, Pull::Up);
17
15 loop { 18 loop {
16 if button.is_high() { 19 if button.is_high() {
17 led.set_high(); 20 led.set_high();
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index c8e6d46a6..82568254a 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -19,18 +19,9 @@ use embassy_time::Duration;
19use embedded_hal_async::spi::ExclusiveDevice; 19use embedded_hal_async::spi::ExclusiveDevice;
20use embedded_io::asynch::Write; 20use embedded_io::asynch::Write;
21use rand::RngCore; 21use rand::RngCore;
22use static_cell::StaticCell; 22use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
24 24
25macro_rules! singleton {
26 ($val:expr) => {{
27 type T = impl Sized;
28 static STATIC_CELL: StaticCell<T> = StaticCell::new();
29 let (x,) = STATIC_CELL.init(($val,));
30 x
31 }};
32}
33
34#[embassy_executor::task] 25#[embassy_executor::task]
35async fn ethernet_task( 26async fn ethernet_task(
36 runner: Runner< 27 runner: Runner<
@@ -62,7 +53,7 @@ async fn main(spawner: Spawner) {
62 let w5500_reset = Output::new(p.PIN_20, Level::High); 53 let w5500_reset = Output::new(p.PIN_20, Level::High);
63 54
64 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
65 let state = singleton!(State::<8, 8>::new()); 56 let state = make_static!(State::<8, 8>::new());
66 let (device, runner) = 57 let (device, runner) =
67 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 58 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await;
68 unwrap!(spawner.spawn(ethernet_task(runner))); 59 unwrap!(spawner.spawn(ethernet_task(runner)));
@@ -71,10 +62,10 @@ async fn main(spawner: Spawner) {
71 let seed = rng.next_u64(); 62 let seed = rng.next_u64();
72 63
73 // Init network stack 64 // Init network stack
74 let stack = &*singleton!(Stack::new( 65 let stack = &*make_static!(Stack::new(
75 device, 66 device,
76 embassy_net::Config::Dhcp(Default::default()), 67 embassy_net::Config::dhcpv4(Default::default()),
77 singleton!(StackResources::<3>::new()), 68 make_static!(StackResources::<3>::new()),
78 seed 69 seed
79 )); 70 ));
80 71
@@ -129,9 +120,9 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16)
129 } 120 }
130} 121}
131 122
132async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 123async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
133 loop { 124 loop {
134 if let Some(config) = stack.config() { 125 if let Some(config) = stack.config_v4() {
135 return config.clone(); 126 return config.clone();
136 } 127 }
137 yield_now().await; 128 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 9a7c3ad19..d562defad 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -21,18 +21,9 @@ use embassy_time::{Duration, Timer};
21use embedded_hal_async::spi::ExclusiveDevice; 21use embedded_hal_async::spi::ExclusiveDevice;
22use embedded_io::asynch::Write; 22use embedded_io::asynch::Write;
23use rand::RngCore; 23use rand::RngCore;
24use static_cell::StaticCell; 24use static_cell::make_static;
25use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
26 26
27macro_rules! singleton {
28 ($val:expr) => {{
29 type T = impl Sized;
30 static STATIC_CELL: StaticCell<T> = StaticCell::new();
31 let (x,) = STATIC_CELL.init(($val,));
32 x
33 }};
34}
35
36#[embassy_executor::task] 27#[embassy_executor::task]
37async fn ethernet_task( 28async fn ethernet_task(
38 runner: Runner< 29 runner: Runner<
@@ -65,7 +56,7 @@ async fn main(spawner: Spawner) {
65 let w5500_reset = Output::new(p.PIN_20, Level::High); 56 let w5500_reset = Output::new(p.PIN_20, Level::High);
66 57
67 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
68 let state = singleton!(State::<8, 8>::new()); 59 let state = make_static!(State::<8, 8>::new());
69 let (device, runner) = 60 let (device, runner) =
70 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 61 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await;
71 unwrap!(spawner.spawn(ethernet_task(runner))); 62 unwrap!(spawner.spawn(ethernet_task(runner)));
@@ -74,10 +65,10 @@ async fn main(spawner: Spawner) {
74 let seed = rng.next_u64(); 65 let seed = rng.next_u64();
75 66
76 // Init network stack 67 // Init network stack
77 let stack = &*singleton!(Stack::new( 68 let stack = &*make_static!(Stack::new(
78 device, 69 device,
79 embassy_net::Config::Dhcp(Default::default()), 70 embassy_net::Config::dhcpv4(Default::default()),
80 singleton!(StackResources::<2>::new()), 71 make_static!(StackResources::<2>::new()),
81 seed 72 seed
82 )); 73 ));
83 74
@@ -117,9 +108,9 @@ async fn main(spawner: Spawner) {
117 } 108 }
118} 109}
119 110
120async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 111async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
121 loop { 112 loop {
122 if let Some(config) = stack.config() { 113 if let Some(config) = stack.config_v4() {
123 return config.clone(); 114 return config.clone();
124 } 115 }
125 yield_now().await; 116 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index f02543246..7f521cdb4 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -20,18 +20,8 @@ use embassy_time::Duration;
20use embedded_hal_async::spi::ExclusiveDevice; 20use embedded_hal_async::spi::ExclusiveDevice;
21use embedded_io::asynch::Write; 21use embedded_io::asynch::Write;
22use rand::RngCore; 22use rand::RngCore;
23use static_cell::StaticCell; 23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
25
26macro_rules! singleton {
27 ($val:expr) => {{
28 type T = impl Sized;
29 static STATIC_CELL: StaticCell<T> = StaticCell::new();
30 let (x,) = STATIC_CELL.init(($val,));
31 x
32 }};
33}
34
35#[embassy_executor::task] 25#[embassy_executor::task]
36async fn ethernet_task( 26async fn ethernet_task(
37 runner: Runner< 27 runner: Runner<
@@ -64,7 +54,7 @@ async fn main(spawner: Spawner) {
64 let w5500_reset = Output::new(p.PIN_20, Level::High); 54 let w5500_reset = Output::new(p.PIN_20, Level::High);
65 55
66 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
67 let state = singleton!(State::<8, 8>::new()); 57 let state = make_static!(State::<8, 8>::new());
68 let (device, runner) = 58 let (device, runner) =
69 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 59 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await;
70 unwrap!(spawner.spawn(ethernet_task(runner))); 60 unwrap!(spawner.spawn(ethernet_task(runner)));
@@ -73,10 +63,10 @@ async fn main(spawner: Spawner) {
73 let seed = rng.next_u64(); 63 let seed = rng.next_u64();
74 64
75 // Init network stack 65 // Init network stack
76 let stack = &*singleton!(Stack::new( 66 let stack = &*make_static!(Stack::new(
77 device, 67 device,
78 embassy_net::Config::Dhcp(Default::default()), 68 embassy_net::Config::dhcpv4(Default::default()),
79 singleton!(StackResources::<2>::new()), 69 make_static!(StackResources::<2>::new()),
80 seed 70 seed
81 )); 71 ));
82 72
@@ -126,9 +116,9 @@ async fn main(spawner: Spawner) {
126 } 116 }
127} 117}
128 118
129async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 119async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
130 loop { 120 loop {
131 if let Some(config) = stack.config() { 121 if let Some(config) = stack.config_v4() {
132 return config.clone(); 122 return config.clone();
133 } 123 }
134 yield_now().await; 124 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index 2c54f711e..ada86ae55 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -18,18 +18,8 @@ use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embedded_hal_async::spi::ExclusiveDevice; 19use embedded_hal_async::spi::ExclusiveDevice;
20use rand::RngCore; 20use rand::RngCore;
21use static_cell::StaticCell; 21use static_cell::make_static;
22use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
23
24macro_rules! singleton {
25 ($val:expr) => {{
26 type T = impl Sized;
27 static STATIC_CELL: StaticCell<T> = StaticCell::new();
28 let (x,) = STATIC_CELL.init(($val,));
29 x
30 }};
31}
32
33#[embassy_executor::task] 23#[embassy_executor::task]
34async fn ethernet_task( 24async fn ethernet_task(
35 runner: Runner< 25 runner: Runner<
@@ -61,7 +51,7 @@ async fn main(spawner: Spawner) {
61 let w5500_reset = Output::new(p.PIN_20, Level::High); 51 let w5500_reset = Output::new(p.PIN_20, Level::High);
62 52
63 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 53 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
64 let state = singleton!(State::<8, 8>::new()); 54 let state = make_static!(State::<8, 8>::new());
65 let (device, runner) = 55 let (device, runner) =
66 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 56 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await;
67 unwrap!(spawner.spawn(ethernet_task(runner))); 57 unwrap!(spawner.spawn(ethernet_task(runner)));
@@ -70,10 +60,10 @@ async fn main(spawner: Spawner) {
70 let seed = rng.next_u64(); 60 let seed = rng.next_u64();
71 61
72 // Init network stack 62 // Init network stack
73 let stack = &*singleton!(Stack::new( 63 let stack = &*make_static!(Stack::new(
74 device, 64 device,
75 embassy_net::Config::Dhcp(Default::default()), 65 embassy_net::Config::dhcpv4(Default::default()),
76 singleton!(StackResources::<2>::new()), 66 make_static!(StackResources::<2>::new()),
77 seed 67 seed
78 )); 68 ));
79 69
@@ -105,9 +95,9 @@ async fn main(spawner: Spawner) {
105 } 95 }
106} 96}
107 97
108async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 98async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
109 loop { 99 loop {
110 if let Some(config) = stack.config() { 100 if let Some(config) = stack.config_v4() {
111 return config.clone(); 101 return config.clone();
112 } 102 }
113 yield_now().await; 103 yield_now().await;
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
index 5585606d8..eef2f7a53 100644
--- a/examples/rp/src/bin/lora_p2p_send_multicore.rs
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -7,7 +7,6 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_executor::_export::StaticCell;
11use embassy_lora::iv::GenericSx126xInterfaceVariant; 10use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull}; 11use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull};
13use embassy_rp::multicore::{spawn_core1, Stack}; 12use embassy_rp::multicore::{spawn_core1, Stack};
@@ -19,6 +18,7 @@ use embassy_time::{Delay, Duration, Timer};
19use lora_phy::mod_params::*; 18use lora_phy::mod_params::*;
20use lora_phy::sx1261_2::SX1261_2; 19use lora_phy::sx1261_2::SX1261_2;
21use lora_phy::LoRa; 20use lora_phy::LoRa;
21use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
23 23
24static mut CORE1_STACK: Stack<4096> = Stack::new(); 24static mut CORE1_STACK: Stack<4096> = Stack::new();
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index 376b2b61e..57278dd6c 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -4,13 +4,13 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_executor::_export::StaticCell;
8use embassy_rp::gpio::{Level, Output}; 7use embassy_rp::gpio::{Level, Output};
9use embassy_rp::multicore::{spawn_core1, Stack}; 8use embassy_rp::multicore::{spawn_core1, Stack};
10use embassy_rp::peripherals::PIN_25; 9use embassy_rp::peripherals::PIN_25;
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
12use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
13use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use static_cell::StaticCell;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
16static mut CORE1_STACK: Stack<4096> = Stack::new(); 16static mut CORE1_STACK: Stack<4096> = Stack::new();
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
index 2f79ba49e..9ace4cd68 100644
--- a/examples/rp/src/bin/multiprio.rs
+++ b/examples/rp/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::{info, unwrap}; 61use defmt::{info, unwrap};
65use embassy_rp::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_rp::interrupt; 63use embassy_rp::interrupt;
67use embassy_rp::pac::Interrupt; 64use embassy_rp::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer, TICK_HZ}; 65use embassy_time::{Duration, Instant, Timer, TICK_HZ};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,18 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_rp::init(Default::default()); 129 let _p = embassy_rp::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: SWI_IRQ_1, priority level 2 131 // High-priority executor: SWI_IRQ_1, priority level 2
136 unsafe { nvic.set_priority(Interrupt::SWI_IRQ_1, 2 << 6) }; 132 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
137 info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_1)); 133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
138 let spawner = EXECUTOR_HIGH.start(Interrupt::SWI_IRQ_1);
139 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
140 135
141 // Medium-priority executor: SWI_IRQ_0, priority level 3 136 // Medium-priority executor: SWI_IRQ_0, priority level 3
142 unsafe { nvic.set_priority(Interrupt::SWI_IRQ_0, 3 << 6) }; 137 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
143 info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_0)); 138 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
144 let spawner = EXECUTOR_MED.start(Interrupt::SWI_IRQ_0);
145 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
146 140
147 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index d6f01b4de..9df99bd58 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -4,34 +4,25 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_executor::_export::StaticCell;
8use embassy_rp::bind_interrupts; 7use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::UART0; 8use embassy_rp::peripherals::UART0;
10use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; 9use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
11use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
12use embedded_io::asynch::{Read, Write}; 11use embedded_io::asynch::{Read, Write};
12use static_cell::make_static;
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 UART0_IRQ => BufferedInterruptHandler<UART0>; 16 UART0_IRQ => BufferedInterruptHandler<UART0>;
17}); 17});
18 18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 let (x,) = STATIC_CELL.init(($val,));
24 x
25 }};
26}
27
28#[embassy_executor::main] 19#[embassy_executor::main]
29async fn main(spawner: Spawner) { 20async fn main(spawner: Spawner) {
30 let p = embassy_rp::init(Default::default()); 21 let p = embassy_rp::init(Default::default());
31 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); 22 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
32 23
33 let tx_buf = &mut singleton!([0u8; 16])[..]; 24 let tx_buf = &mut make_static!([0u8; 16])[..];
34 let rx_buf = &mut singleton!([0u8; 16])[..]; 25 let rx_buf = &mut make_static!([0u8; 16])[..];
35 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 26 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
36 let (rx, mut tx) = uart.split(); 27 let (rx, mut tx) = uart.split();
37 28
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 38ff1620d..91d1ec8e7 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -13,7 +13,7 @@ use 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, Config, UsbDevice}; 14use embassy_usb::{Builder, Config, UsbDevice};
15use embedded_io::asynch::Write; 15use embedded_io::asynch::Write;
16use static_cell::StaticCell; 16use static_cell::make_static;
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -22,15 +22,6 @@ bind_interrupts!(struct Irqs {
22 22
23type MyDriver = Driver<'static, peripherals::USB>; 23type MyDriver = Driver<'static, peripherals::USB>;
24 24
25macro_rules! singleton {
26 ($val:expr) => {{
27 type T = impl Sized;
28 static STATIC_CELL: StaticCell<T> = StaticCell::new();
29 let (x,) = STATIC_CELL.init(($val,));
30 x
31 }};
32}
33
34const MTU: usize = 1514; 25const MTU: usize = 1514;
35 26
36#[embassy_executor::task] 27#[embassy_executor::task]
@@ -73,10 +64,10 @@ async fn main(spawner: Spawner) {
73 let mut builder = Builder::new( 64 let mut builder = Builder::new(
74 driver, 65 driver,
75 config, 66 config,
76 &mut singleton!([0; 256])[..], 67 &mut make_static!([0; 256])[..],
77 &mut singleton!([0; 256])[..], 68 &mut make_static!([0; 256])[..],
78 &mut singleton!([0; 256])[..], 69 &mut make_static!([0; 256])[..],
79 &mut singleton!([0; 128])[..], 70 &mut make_static!([0; 128])[..],
80 ); 71 );
81 72
82 // Our MAC addr. 73 // Our MAC addr.
@@ -85,18 +76,18 @@ async fn main(spawner: Spawner) {
85 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 76 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
86 77
87 // Create classes on the builder. 78 // Create classes on the builder.
88 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); 79 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
89 80
90 // Build the builder. 81 // Build the builder.
91 let usb = builder.build(); 82 let usb = builder.build();
92 83
93 unwrap!(spawner.spawn(usb_task(usb))); 84 unwrap!(spawner.spawn(usb_task(usb)));
94 85
95 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); 86 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
96 unwrap!(spawner.spawn(usb_ncm_task(runner))); 87 unwrap!(spawner.spawn(usb_ncm_task(runner)));
97 88
98 let config = embassy_net::Config::Dhcp(Default::default()); 89 let config = embassy_net::Config::dhcpv4(Default::default());
99 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 90 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
100 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 91 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
101 // dns_servers: Vec::new(), 92 // dns_servers: Vec::new(),
102 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 93 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -106,7 +97,12 @@ async fn main(spawner: Spawner) {
106 let seed = 1234; // guaranteed random, chosen by a fair dice roll 97 let seed = 1234; // guaranteed random, chosen by a fair dice roll
107 98
108 // Init network stack 99 // Init network stack
109 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 100 let stack = &*make_static!(Stack::new(
101 device,
102 config,
103 make_static!(StackResources::<2>::new()),
104 seed
105 ));
110 106
111 unwrap!(spawner.spawn(net_task(stack))); 107 unwrap!(spawner.spawn(net_task(stack)));
112 108
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 15264524e..e8197390c 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -16,17 +16,9 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio; 16use embassy_rp::pio::Pio;
17use embassy_time::Duration; 17use embassy_time::Duration;
18use embedded_io::asynch::Write; 18use embedded_io::asynch::Write;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21 21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val)
27 }};
28}
29
30#[embassy_executor::task] 22#[embassy_executor::task]
31async fn wifi_task( 23async fn wifi_task(
32 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 24 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -60,7 +52,7 @@ async fn main(spawner: Spawner) {
60 let mut pio = Pio::new(p.PIO0); 52 let mut pio = Pio::new(p.PIO0);
61 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 53 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
62 54
63 let state = singleton!(cyw43::State::new()); 55 let state = make_static!(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 56 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner))); 57 unwrap!(spawner.spawn(wifi_task(runner)));
66 58
@@ -70,7 +62,7 @@ async fn main(spawner: Spawner) {
70 .await; 62 .await;
71 63
72 // Use a link-local address for communication without DHCP server 64 // Use a link-local address for communication without DHCP server
73 let config = Config::Static(embassy_net::StaticConfig { 65 let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
74 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16), 66 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
75 dns_servers: heapless::Vec::new(), 67 dns_servers: heapless::Vec::new(),
76 gateway: None, 68 gateway: None,
@@ -80,10 +72,10 @@ async fn main(spawner: Spawner) {
80 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 72 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
81 73
82 // Init network stack 74 // Init network stack
83 let stack = &*singleton!(Stack::new( 75 let stack = &*make_static!(Stack::new(
84 net_device, 76 net_device,
85 config, 77 config,
86 singleton!(StackResources::<2>::new()), 78 make_static!(StackResources::<2>::new()),
87 seed 79 seed
88 )); 80 ));
89 81
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
new file mode 100644
index 000000000..be965807b
--- /dev/null
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -0,0 +1,59 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cyw43_pio::PioSpi;
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::gpio::{Level, Output};
9use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
10use embassy_rp::pio::Pio;
11use embassy_time::{Duration, Timer};
12use static_cell::make_static;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn wifi_task(
17 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
18) -> ! {
19 runner.run().await
20}
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
26 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
27
28 // To make flashing faster for development, you may want to flash the firmwares independently
29 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
30 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
31 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
32 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
33 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
34
35 let pwr = Output::new(p.PIN_23, Level::Low);
36 let cs = Output::new(p.PIN_25, Level::High);
37 let mut pio = Pio::new(p.PIO0);
38 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
39
40 let state = make_static!(cyw43::State::new());
41 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
42 unwrap!(spawner.spawn(wifi_task(runner)));
43
44 control.init(clm).await;
45 control
46 .set_power_management(cyw43::PowerManagementMode::PowerSave)
47 .await;
48
49 let delay = Duration::from_secs(1);
50 loop {
51 info!("led on!");
52 control.gpio_set(0, true).await;
53 Timer::after(delay).await;
54
55 info!("led off!");
56 control.gpio_set(0, false).await;
57 Timer::after(delay).await;
58 }
59}
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index aa5e5a399..79534f229 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -13,17 +13,9 @@ use embassy_net::Stack;
13use embassy_rp::gpio::{Level, Output}; 13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::Pio; 15use embassy_rp::pio::Pio;
16use static_cell::StaticCell; 16use static_cell::make_static;
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 STATIC_CELL.init_with(move || $val)
24 }};
25}
26
27#[embassy_executor::task] 19#[embassy_executor::task]
28async fn wifi_task( 20async fn wifi_task(
29 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 21 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -57,7 +49,7 @@ async fn main(spawner: Spawner) {
57 let mut pio = Pio::new(p.PIO0); 49 let mut pio = Pio::new(p.PIO0);
58 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 50 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
59 51
60 let state = singleton!(cyw43::State::new()); 52 let state = make_static!(cyw43::State::new());
61 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 53 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
62 unwrap!(spawner.spawn(wifi_task(runner))); 54 unwrap!(spawner.spawn(wifi_task(runner)));
63 55
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index eafa25f68..026e056fa 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -16,17 +16,9 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio; 16use embassy_rp::pio::Pio;
17use embassy_time::Duration; 17use embassy_time::Duration;
18use embedded_io::asynch::Write; 18use embedded_io::asynch::Write;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21 21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val)
27 }};
28}
29
30#[embassy_executor::task] 22#[embassy_executor::task]
31async fn wifi_task( 23async fn wifi_task(
32 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 24 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -60,7 +52,7 @@ async fn main(spawner: Spawner) {
60 let mut pio = Pio::new(p.PIO0); 52 let mut pio = Pio::new(p.PIO0);
61 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 53 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
62 54
63 let state = singleton!(cyw43::State::new()); 55 let state = make_static!(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 56 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner))); 57 unwrap!(spawner.spawn(wifi_task(runner)));
66 58
@@ -69,8 +61,8 @@ async fn main(spawner: Spawner) {
69 .set_power_management(cyw43::PowerManagementMode::PowerSave) 61 .set_power_management(cyw43::PowerManagementMode::PowerSave)
70 .await; 62 .await;
71 63
72 let config = Config::Dhcp(Default::default()); 64 let config = Config::dhcpv4(Default::default());
73 //let config = embassy_net::Config::Static(embassy_net::Config { 65 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
74 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 66 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
75 // dns_servers: Vec::new(), 67 // dns_servers: Vec::new(),
76 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 68 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
@@ -80,10 +72,10 @@ async fn main(spawner: Spawner) {
80 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 72 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
81 73
82 // Init network stack 74 // Init network stack
83 let stack = &*singleton!(Stack::new( 75 let stack = &*make_static!(Stack::new(
84 net_device, 76 net_device,
85 config, 77 config,
86 singleton!(StackResources::<2>::new()), 78 make_static!(StackResources::<2>::new()),
87 seed 79 seed
88 )); 80 ));
89 81
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 36770ca9c..878ad8c5a 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -22,4 +22,4 @@ libc = "0.2.101"
22clap = { version = "3.0.0-beta.5", features = ["derive"] } 22clap = { version = "3.0.0-beta.5", features = ["derive"] }
23rand_core = { version = "0.6.3", features = ["std"] } 23rand_core = { version = "0.6.3", features = ["std"] }
24heapless = { version = "0.7.5", default-features = false } 24heapless = { version = "0.7.5", default-features = false }
25static_cell = "1.0" 25static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index d93616254..3aadb029d 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -11,21 +11,12 @@ use embedded_io::asynch::Write;
11use heapless::Vec; 11use heapless::Vec;
12use log::*; 12use log::*;
13use rand_core::{OsRng, RngCore}; 13use rand_core::{OsRng, RngCore};
14use static_cell::StaticCell; 14use static_cell::{make_static, StaticCell};
15 15
16#[path = "../tuntap.rs"] 16#[path = "../tuntap.rs"]
17mod tuntap; 17mod tuntap;
18 18
19use crate::tuntap::TunTapDevice; 19use crate::tuntap::TunTapDevice;
20
21macro_rules! singleton {
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val)
26 }};
27}
28
29#[derive(Parser)] 20#[derive(Parser)]
30#[clap(version = "1.0")] 21#[clap(version = "1.0")]
31struct Opts { 22struct Opts {
@@ -51,13 +42,13 @@ async fn main_task(spawner: Spawner) {
51 42
52 // Choose between dhcp or static ip 43 // Choose between dhcp or static ip
53 let config = if opts.static_ip { 44 let config = if opts.static_ip {
54 Config::Static(embassy_net::StaticConfig { 45 Config::ipv4_static(embassy_net::StaticConfigV4 {
55 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 46 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
56 dns_servers: Vec::new(), 47 dns_servers: Vec::new(),
57 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 48 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
58 }) 49 })
59 } else { 50 } else {
60 Config::Dhcp(Default::default()) 51 Config::dhcpv4(Default::default())
61 }; 52 };
62 53
63 // Generate random seed 54 // Generate random seed
@@ -66,7 +57,12 @@ async fn main_task(spawner: Spawner) {
66 let seed = u64::from_le_bytes(seed); 57 let seed = u64::from_le_bytes(seed);
67 58
68 // Init network stack 59 // Init network stack
69 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); 60 let stack = &*make_static!(Stack::new(
61 device,
62 config,
63 make_static!(StackResources::<3>::new()),
64 seed
65 ));
70 66
71 // Launch network task 67 // Launch network task
72 spawner.spawn(net_task(stack)).unwrap(); 68 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index d1e1f8212..65b5a2cd9 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -9,21 +9,12 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
9use heapless::Vec; 9use heapless::Vec;
10use log::*; 10use log::*;
11use rand_core::{OsRng, RngCore}; 11use rand_core::{OsRng, RngCore};
12use static_cell::StaticCell; 12use static_cell::{make_static, StaticCell};
13 13
14#[path = "../tuntap.rs"] 14#[path = "../tuntap.rs"]
15mod tuntap; 15mod tuntap;
16 16
17use crate::tuntap::TunTapDevice; 17use crate::tuntap::TunTapDevice;
18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 STATIC_CELL.init_with(move || $val)
24 }};
25}
26
27#[derive(Parser)] 18#[derive(Parser)]
28#[clap(version = "1.0")] 19#[clap(version = "1.0")]
29struct Opts { 20struct Opts {
@@ -49,14 +40,14 @@ async fn main_task(spawner: Spawner) {
49 40
50 // Choose between dhcp or static ip 41 // Choose between dhcp or static ip
51 let config = if opts.static_ip { 42 let config = if opts.static_ip {
52 Config::Static(embassy_net::StaticConfig { 43 Config::ipv4_static(embassy_net::StaticConfigV4 {
53 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24), 44 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
54 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()]) 45 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()])
55 .unwrap(), 46 .unwrap(),
56 gateway: Some(Ipv4Address::new(192, 168, 69, 100)), 47 gateway: Some(Ipv4Address::new(192, 168, 69, 100)),
57 }) 48 })
58 } else { 49 } else {
59 Config::Dhcp(Default::default()) 50 Config::dhcpv4(Default::default())
60 }; 51 };
61 52
62 // Generate random seed 53 // Generate random seed
@@ -65,7 +56,12 @@ async fn main_task(spawner: Spawner) {
65 let seed = u64::from_le_bytes(seed); 56 let seed = u64::from_le_bytes(seed);
66 57
67 // Init network stack 58 // Init network stack
68 let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); 59 let stack: &Stack<_> = &*make_static!(Stack::new(
60 device,
61 config,
62 make_static!(StackResources::<3>::new()),
63 seed
64 ));
69 65
70 // Launch network task 66 // Launch network task
71 spawner.spawn(net_task(stack)).unwrap(); 67 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 4df23edf6..3fc46156c 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -7,21 +7,12 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
7use heapless::Vec; 7use heapless::Vec;
8use log::*; 8use log::*;
9use rand_core::{OsRng, RngCore}; 9use rand_core::{OsRng, RngCore};
10use static_cell::StaticCell; 10use static_cell::{make_static, StaticCell};
11 11
12#[path = "../tuntap.rs"] 12#[path = "../tuntap.rs"]
13mod tuntap; 13mod tuntap;
14 14
15use crate::tuntap::TunTapDevice; 15use crate::tuntap::TunTapDevice;
16
17macro_rules! singleton {
18 ($val:expr) => {{
19 type T = impl Sized;
20 static STATIC_CELL: StaticCell<T> = StaticCell::new();
21 STATIC_CELL.init_with(move || $val)
22 }};
23}
24
25#[derive(Parser)] 16#[derive(Parser)]
26#[clap(version = "1.0")] 17#[clap(version = "1.0")]
27struct Opts { 18struct Opts {
@@ -47,13 +38,13 @@ async fn main_task(spawner: Spawner) {
47 38
48 // Choose between dhcp or static ip 39 // Choose between dhcp or static ip
49 let config = if opts.static_ip { 40 let config = if opts.static_ip {
50 Config::Static(embassy_net::StaticConfig { 41 Config::ipv4_static(embassy_net::StaticConfigV4 {
51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 42 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
52 dns_servers: Vec::new(), 43 dns_servers: Vec::new(),
53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 44 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
54 }) 45 })
55 } else { 46 } else {
56 Config::Dhcp(Default::default()) 47 Config::dhcpv4(Default::default())
57 }; 48 };
58 49
59 // Generate random seed 50 // Generate random seed
@@ -62,7 +53,12 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 53 let seed = u64::from_le_bytes(seed);
63 54
64 // Init network stack 55 // Init network stack
65 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); 56 let stack = &*make_static!(Stack::new(
57 device,
58 config,
59 make_static!(StackResources::<3>::new()),
60 seed
61 ));
66 62
67 // Launch network task 63 // Launch network task
68 spawner.spawn(net_task(stack)).unwrap(); 64 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index 97ce77f42..df09986ac 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -12,21 +12,12 @@ use embedded_io::asynch::Write as _;
12use heapless::Vec; 12use heapless::Vec;
13use log::*; 13use log::*;
14use rand_core::{OsRng, RngCore}; 14use rand_core::{OsRng, RngCore};
15use static_cell::StaticCell; 15use static_cell::{make_static, StaticCell};
16 16
17#[path = "../tuntap.rs"] 17#[path = "../tuntap.rs"]
18mod tuntap; 18mod tuntap;
19 19
20use crate::tuntap::TunTapDevice; 20use crate::tuntap::TunTapDevice;
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val)
27 }};
28}
29
30#[derive(Parser)] 21#[derive(Parser)]
31#[clap(version = "1.0")] 22#[clap(version = "1.0")]
32struct Opts { 23struct Opts {
@@ -62,13 +53,13 @@ async fn main_task(spawner: Spawner) {
62 53
63 // Choose between dhcp or static ip 54 // Choose between dhcp or static ip
64 let config = if opts.static_ip { 55 let config = if opts.static_ip {
65 Config::Static(embassy_net::StaticConfig { 56 Config::ipv4_static(embassy_net::StaticConfigV4 {
66 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 57 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
67 dns_servers: Vec::new(), 58 dns_servers: Vec::new(),
68 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 59 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
69 }) 60 })
70 } else { 61 } else {
71 Config::Dhcp(Default::default()) 62 Config::dhcpv4(Default::default())
72 }; 63 };
73 64
74 // Generate random seed 65 // Generate random seed
@@ -77,7 +68,12 @@ async fn main_task(spawner: Spawner) {
77 let seed = u64::from_le_bytes(seed); 68 let seed = u64::from_le_bytes(seed);
78 69
79 // Init network stack 70 // Init network stack
80 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); 71 let stack = &*make_static!(Stack::new(
72 device,
73 config,
74 make_static!(StackResources::<3>::new()),
75 seed
76 ));
81 77
82 // Launch network task 78 // Launch network task
83 spawner.spawn(net_task(stack)).unwrap(); 79 spawner.spawn(net_task(stack)).unwrap();
@@ -112,7 +108,7 @@ async fn main_task(spawner: Spawner) {
112 info!("Closing the connection"); 108 info!("Closing the connection");
113 socket.abort(); 109 socket.abort();
114 info!("Flushing the RST out..."); 110 info!("Flushing the RST out...");
115 socket.flush().await; 111 _ = socket.flush().await;
116 info!("Finished with the socket"); 112 info!("Finished with the socket");
117 } 113 }
118} 114}
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index ad11fbd1c..43f432520 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
12 12
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 9c59c45c6..8d2248ed0 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -13,7 +13,7 @@ defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
14panic-probe = "0.3" 14panic-probe = "0.3"
15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } 18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
19static_cell = "1.0" 19static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index 430a805fc..988ffeef1 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -129,16 +126,15 @@ unsafe fn USART2() {
129fn main() -> ! { 126fn main() -> ! {
130 // Initialize and create handle for devicer peripherals 127 // Initialize and create handle for devicer peripherals
131 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
132 let mut nvic: NVIC = unsafe { mem::transmute(()) };
133 129
134 // High-priority executor: USART1, priority level 6 130 // High-priority executor: USART1, priority level 6
135 unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) }; 131 interrupt::USART1.set_priority(Priority::P6);
136 let spawner = EXECUTOR_HIGH.start(Interrupt::USART1); 132 let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
137 unwrap!(spawner.spawn(run_high())); 133 unwrap!(spawner.spawn(run_high()));
138 134
139 // Medium-priority executor: USART2, priority level 7 135 // Medium-priority executor: USART2, priority level 7
140 unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) }; 136 interrupt::USART2.set_priority(Priority::P7);
141 let spawner = EXECUTOR_MED.start(Interrupt::USART2); 137 let spawner = EXECUTOR_MED.start(interrupt::USART2);
142 unwrap!(spawner.spawn(run_med())); 138 unwrap!(spawner.spawn(run_med()));
143 139
144 // Low priority executor: runs in thread mode, using WFE/SEV 140 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs
index 80e76f901..a44b17528 100644
--- a/examples/stm32f0/src/bin/wdg.rs
+++ b/examples/stm32f0/src/bin/wdg.rs
@@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) {
16 let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); 16 let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00);
17 17
18 info!("Watchdog start"); 18 info!("Watchdog start");
19 unsafe { wdg.unleash() }; 19 wdg.unleash();
20 20
21 loop { 21 loop {
22 Timer::after(Duration::from_secs(1)).await; 22 Timer::after(Duration::from_secs(1)).await;
23 unsafe { wdg.pet() }; 23 wdg.pet();
24 } 24 }
25} 25}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 345e948a6..d34fd439a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index e4f97a589..5e3e0d0f7 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12 12
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 3d314e6c5..29ab2009c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
23heapless = { version = "0.7.5", default-features = false } 23heapless = { version = "0.7.5", default-features = false }
24nb = "1.0.0" 24nb = "1.0.0"
25embedded-storage = "0.3.0" 25embedded-storage = "0.3.0"
26static_cell = "1.0" 26static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 5d010f799..80bf59deb 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: UART4, priority level 6 131 // High-priority executor: UART4, priority level 6
136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; 132 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: UART5, priority level 7 136 // Medium-priority executor: UART5, priority level 7
141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; 137 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::UART5); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index f5f8b632d..7ecb64fce 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -25,7 +25,7 @@ heapless = { version = "0.7.5", default-features = false }
25nb = "1.0.0" 25nb = "1.0.0"
26embedded-storage = "0.3.0" 26embedded-storage = "0.3.0"
27micromath = "2.0.0" 27micromath = "2.0.0"
28static_cell = "1.0" 28static_cell = { version = "1.1", features = ["nightly"]}
29chrono = { version = "^0.4", default-features = false} 29chrono = { version = "^0.4", default-features = false}
30 30
31[profile.release] 31[profile.release]
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 5d010f799..80bf59deb 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: UART4, priority level 6 131 // High-priority executor: UART4, priority level 6
136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; 132 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: UART5, priority level 7 136 // Medium-priority executor: UART5, priority level 7
141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; 137 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::UART5); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index c4e395f0f..953d99a45 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -14,20 +14,11 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice}; 15use embassy_usb::{Builder, UsbDevice};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use static_cell::StaticCell; 17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; 20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>;
21 21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31const MTU: usize = 1514; 22const MTU: usize = 1514;
32 23
33#[embassy_executor::task] 24#[embassy_executor::task]
@@ -60,7 +51,7 @@ async fn main(spawner: Spawner) {
60 let p = embassy_stm32::init(config); 51 let p = embassy_stm32::init(config);
61 52
62 // Create the driver, from the HAL. 53 // Create the driver, from the HAL.
63 let ep_out_buffer = &mut singleton!([0; 256])[..]; 54 let ep_out_buffer = &mut make_static!([0; 256])[..];
64 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); 55 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer);
65 56
66 // Create embassy-usb Config 57 // Create embassy-usb Config
@@ -81,10 +72,10 @@ async fn main(spawner: Spawner) {
81 let mut builder = Builder::new( 72 let mut builder = Builder::new(
82 driver, 73 driver,
83 config, 74 config,
84 &mut singleton!([0; 256])[..], 75 &mut make_static!([0; 256])[..],
85 &mut singleton!([0; 256])[..], 76 &mut make_static!([0; 256])[..],
86 &mut singleton!([0; 256])[..], 77 &mut make_static!([0; 256])[..],
87 &mut singleton!([0; 128])[..], 78 &mut make_static!([0; 128])[..],
88 ); 79 );
89 80
90 // Our MAC addr. 81 // Our MAC addr.
@@ -93,18 +84,18 @@ async fn main(spawner: Spawner) {
93 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 84 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
94 85
95 // Create classes on the builder. 86 // Create classes on the builder.
96 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); 87 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
97 88
98 // Build the builder. 89 // Build the builder.
99 let usb = builder.build(); 90 let usb = builder.build();
100 91
101 unwrap!(spawner.spawn(usb_task(usb))); 92 unwrap!(spawner.spawn(usb_task(usb)));
102 93
103 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); 94 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
104 unwrap!(spawner.spawn(usb_ncm_task(runner))); 95 unwrap!(spawner.spawn(usb_ncm_task(runner)));
105 96
106 let config = embassy_net::Config::Dhcp(Default::default()); 97 let config = embassy_net::Config::dhcpv4(Default::default());
107 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 98 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
108 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 99 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
109 // dns_servers: Vec::new(), 100 // dns_servers: Vec::new(),
110 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 101 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -117,7 +108,12 @@ async fn main(spawner: Spawner) {
117 let seed = u64::from_le_bytes(seed); 108 let seed = u64::from_le_bytes(seed);
118 109
119 // Init network stack 110 // Init network stack
120 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 111 let stack = &*make_static!(Stack::new(
112 device,
113 config,
114 make_static!(StackResources::<2>::new()),
115 seed
116 ));
121 117
122 unwrap!(spawner.spawn(net_task(stack))); 118 unwrap!(spawner.spawn(net_task(stack)));
123 119
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs
index b2c587fa1..e5d122af7 100644
--- a/examples/stm32f4/src/bin/wdt.rs
+++ b/examples/stm32f4/src/bin/wdt.rs
@@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) {
17 let mut led = Output::new(p.PB7, Level::High, Speed::Low); 17 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
18 18
19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); 19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
20 unsafe { 20 wdt.unleash();
21 wdt.unleash();
22 }
23 21
24 let mut i = 0; 22 let mut i = 0;
25 23
@@ -36,9 +34,7 @@ async fn main(_spawner: Spawner) {
36 // MCU should restart in 1 second after the last pet. 34 // MCU should restart in 1 second after the last pet.
37 if i < 5 { 35 if i < 5 {
38 info!("Petting watchdog"); 36 info!("Petting watchdog");
39 unsafe { 37 wdt.pet();
40 wdt.pet();
41 }
42 } 38 }
43 39
44 i += 1; 40 i += 1;
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 6ddb7186e..657251c50 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
@@ -26,4 +26,4 @@ nb = "1.0.0"
26rand_core = "0.6.3" 26rand_core = "0.6.3"
27critical-section = "1.1" 27critical-section = "1.1"
28embedded-storage = "0.3.0" 28embedded-storage = "0.3.0"
29static_cell = "1.0" 29static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f7/build.rs b/examples/stm32f7/build.rs
index c4e15f19c..2b5d412a9 100644
--- a/examples/stm32f7/build.rs
+++ b/examples/stm32f7/build.rs
@@ -1,9 +1,8 @@
1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs 1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs
2use std::env;
3use std::fs::File; 2use std::fs::File;
4use std::io::prelude::*; 3use std::io::prelude::*;
5use std::io::{self};
6use std::path::PathBuf; 4use std::path::PathBuf;
5use std::{env, io};
7 6
8#[derive(Debug)] 7#[derive(Debug)]
9enum Error { 8enum Error {
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 6d286c368..fde6a7576 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -15,18 +15,8 @@ use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use rand_core::RngCore; 17use rand_core::RngCore;
18use static_cell::StaticCell; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20
21macro_rules! singleton {
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 let (x,) = STATIC_CELL.init(($val,));
26 x
27 }};
28}
29
30bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
31 ETH => eth::InterruptHandler; 21 ETH => eth::InterruptHandler;
32}); 22});
@@ -55,7 +45,7 @@ async fn main(spawner: Spawner) -> ! {
55 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 45 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
56 46
57 let device = Ethernet::new( 47 let device = Ethernet::new(
58 singleton!(PacketQueue::<16, 16>::new()), 48 make_static!(PacketQueue::<16, 16>::new()),
59 p.ETH, 49 p.ETH,
60 Irqs, 50 Irqs,
61 p.PA1, 51 p.PA1,
@@ -72,15 +62,20 @@ async fn main(spawner: Spawner) -> ! {
72 0, 62 0,
73 ); 63 );
74 64
75 let config = embassy_net::Config::Dhcp(Default::default()); 65 let config = embassy_net::Config::dhcpv4(Default::default());
76 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 66 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
77 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 67 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
78 // dns_servers: Vec::new(), 68 // dns_servers: Vec::new(),
79 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 69 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
80 //}); 70 //});
81 71
82 // Init network stack 72 // Init network stack
83 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 73 let stack = &*make_static!(Stack::new(
74 device,
75 config,
76 make_static!(StackResources::<2>::new()),
77 seed
78 ));
84 79
85 // Launch network task 80 // Launch network task
86 unwrap!(spawner.spawn(net_task(&stack))); 81 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 4d7fc4548..c5245757b 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
12 12
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 00e2dae4c..fbfbc6408 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -6,10 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
new file mode 100644
index 000000000..ef7d4800c
--- /dev/null
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
8use embassy_stm32::Config;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15
16 config.rcc.pll = Some(Pll {
17 source: PllSrc::HSI16,
18 prediv_m: PllM::Div4,
19 mul_n: PllN::Mul85,
20 div_p: None,
21 div_q: None,
22 // Main system clock at 170 MHz
23 div_r: Some(PllR::Div2),
24 });
25
26 config.rcc.mux = ClockSrc::PLL;
27
28 let _p = embassy_stm32::init(config);
29 info!("Hello World!");
30
31 loop {
32 Timer::after(Duration::from_millis(1000)).await;
33 info!("1s elapsed");
34 }
35}
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..c111a9787
--- /dev/null
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -0,0 +1,108 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{self, Driver, Instance};
10use embassy_stm32::{bind_interrupts, pac, peripherals, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 USB_LP => usb::InterruptHandler<peripherals::USB>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24
25 config.rcc.pll = Some(Pll {
26 source: PllSrc::HSE(Hertz(8000000)),
27 prediv_m: PllM::Div2,
28 mul_n: PllN::Mul72,
29 div_p: None,
30 // USB and CAN at 48 MHz
31 div_q: Some(PllQ::Div6),
32 // Main system clock at 144 MHz
33 div_r: Some(PllR::Div2),
34 });
35
36 config.rcc.mux = ClockSrc::PLL;
37
38 let p = embassy_stm32::init(config);
39 info!("Hello World!");
40
41 pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10));
42
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44
45 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
46 config.manufacturer = Some("Embassy");
47 config.product = Some("USB-Serial Example");
48 config.serial_number = Some("123456");
49
50 config.device_class = 0xEF;
51 config.device_sub_class = 0x02;
52 config.device_protocol = 0x01;
53 config.composite_with_iads = true;
54
55 let mut device_descriptor = [0; 256];
56 let mut config_descriptor = [0; 256];
57 let mut bos_descriptor = [0; 256];
58 let mut control_buf = [0; 64];
59
60 let mut state = State::new();
61
62 let mut builder = Builder::new(
63 driver,
64 config,
65 &mut device_descriptor,
66 &mut config_descriptor,
67 &mut bos_descriptor,
68 &mut control_buf,
69 );
70
71 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
72
73 let mut usb = builder.build();
74
75 let usb_fut = usb.run();
76
77 let echo_fut = async {
78 loop {
79 class.wait_connection().await;
80 info!("Connected");
81 let _ = echo(&mut class).await;
82 info!("Disconnected");
83 }
84 };
85
86 join(usb_fut, echo_fut).await;
87}
88
89struct Disconnected {}
90
91impl From<EndpointError> for Disconnected {
92 fn from(val: EndpointError) -> Self {
93 match val {
94 EndpointError::BufferOverflow => panic!("Buffer overflow"),
95 EndpointError::Disabled => Disconnected {},
96 }
97 }
98}
99
100async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
101 let mut buf = [0; 64];
102 loop {
103 let n = class.read_packet(&mut buf).await?;
104 let data = &buf[..n];
105 info!("data: {:x}", data);
106 class.write_packet(data).await?;
107 }
108}
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index b9204fba8..ebe511347 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
@@ -30,7 +30,7 @@ critical-section = "1.1"
30micromath = "2.0.0" 30micromath = "2.0.0"
31stm32-fmc = "0.2.4" 31stm32-fmc = "0.2.4"
32embedded-storage = "0.3.0" 32embedded-storage = "0.3.0"
33static_cell = "1.0" 33static_cell = { version = "1.1", features = ["nightly"]}
34 34
35# cargo build/run 35# cargo build/run
36[profile.dev] 36[profile.dev]
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index fa1f225fe..78c8282a6 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -16,18 +16,8 @@ use embassy_stm32::{bind_interrupts, eth, Config};
16use embassy_time::{Duration, Timer}; 16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::Write; 17use embedded_io::asynch::Write;
18use rand_core::RngCore; 18use rand_core::RngCore;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
32 ETH => eth::InterruptHandler; 22 ETH => eth::InterruptHandler;
33}); 23});
@@ -74,7 +64,7 @@ async fn main(spawner: Spawner) -> ! {
74 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
75 65
76 let device = Ethernet::new( 66 let device = Ethernet::new(
77 singleton!(PacketQueue::<4, 4>::new()), 67 make_static!(PacketQueue::<4, 4>::new()),
78 p.ETH, 68 p.ETH,
79 Irqs, 69 Irqs,
80 p.PA1, 70 p.PA1,
@@ -91,15 +81,20 @@ async fn main(spawner: Spawner) -> ! {
91 0, 81 0,
92 ); 82 );
93 83
94 let config = embassy_net::Config::Dhcp(Default::default()); 84 let config = embassy_net::Config::dhcpv4(Default::default());
95 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 85 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 86 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
97 // dns_servers: Vec::new(), 87 // dns_servers: Vec::new(),
98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 88 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
99 //}); 89 //});
100 90
101 // Init network stack 91 // Init network stack
102 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 92 let stack = &*make_static!(Stack::new(
93 device,
94 config,
95 make_static!(StackResources::<2>::new()),
96 seed
97 ));
103 98
104 // Launch network task 99 // Launch network task
105 unwrap!(spawner.spawn(net_task(&stack))); 100 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 3912327e2..336eed644 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -45,11 +45,9 @@ async fn main(_spawner: Spawner) {
45 45
46 info!("Hello World!"); 46 info!("Hello World!");
47 47
48 unsafe { 48 pac::RCC.ccipr4().write(|w| {
49 pac::RCC.ccipr4().write(|w| { 49 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
50 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); 50 });
51 });
52 }
53 51
54 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 53 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 8b534ca05..62ef5e9e4 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
@@ -30,7 +30,7 @@ critical-section = "1.1"
30micromath = "2.0.0" 30micromath = "2.0.0"
31stm32-fmc = "0.2.4" 31stm32-fmc = "0.2.4"
32embedded-storage = "0.3.0" 32embedded-storage = "0.3.0"
33static_cell = "1.0" 33static_cell = { version = "1.1", features = ["nightly"]}
34 34
35# cargo build/run 35# cargo build/run
36[profile.dev] 36[profile.dev]
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index dbfc90cf4..12d37f7a4 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -15,18 +15,8 @@ use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use rand_core::RngCore; 17use rand_core::RngCore;
18use static_cell::StaticCell; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20
21macro_rules! singleton {
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 let (x,) = STATIC_CELL.init(($val,));
26 x
27 }};
28}
29
30bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
31 ETH => eth::InterruptHandler; 21 ETH => eth::InterruptHandler;
32}); 22});
@@ -56,7 +46,7 @@ async fn main(spawner: Spawner) -> ! {
56 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 46 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
57 47
58 let device = Ethernet::new( 48 let device = Ethernet::new(
59 singleton!(PacketQueue::<16, 16>::new()), 49 make_static!(PacketQueue::<16, 16>::new()),
60 p.ETH, 50 p.ETH,
61 Irqs, 51 Irqs,
62 p.PA1, 52 p.PA1,
@@ -73,15 +63,20 @@ async fn main(spawner: Spawner) -> ! {
73 0, 63 0,
74 ); 64 );
75 65
76 let config = embassy_net::Config::Dhcp(Default::default()); 66 let config = embassy_net::Config::dhcpv4(Default::default());
77 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 67 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
78 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 68 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
79 // dns_servers: Vec::new(), 69 // dns_servers: Vec::new(),
80 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 70 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
81 //}); 71 //});
82 72
83 // Init network stack 73 // Init network stack
84 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 74 let stack = &*make_static!(Stack::new(
75 device,
76 config,
77 make_static!(StackResources::<2>::new()),
78 seed
79 ));
85 80
86 // Launch network task 81 // Launch network task
87 unwrap!(spawner.spawn(net_task(&stack))); 82 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 14e6b7914..6078fc3fe 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -16,18 +16,8 @@ use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; 17use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
18use rand_core::RngCore; 18use rand_core::RngCore;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
32 ETH => eth::InterruptHandler; 22 ETH => eth::InterruptHandler;
33}); 23});
@@ -57,7 +47,7 @@ async fn main(spawner: Spawner) -> ! {
57 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 47 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
58 48
59 let device = Ethernet::new( 49 let device = Ethernet::new(
60 singleton!(PacketQueue::<16, 16>::new()), 50 make_static!(PacketQueue::<16, 16>::new()),
61 p.ETH, 51 p.ETH,
62 Irqs, 52 Irqs,
63 p.PA1, 53 p.PA1,
@@ -74,15 +64,20 @@ async fn main(spawner: Spawner) -> ! {
74 0, 64 0,
75 ); 65 );
76 66
77 let config = embassy_net::Config::Dhcp(Default::default()); 67 let config = embassy_net::Config::dhcpv4(Default::default());
78 //let config = embassy_net::Config::StaticConfig(embassy_net::Config { 68 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
79 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 69 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
80 // dns_servers: Vec::new(), 70 // dns_servers: Vec::new(),
81 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 71 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
82 //}); 72 //});
83 73
84 // Init network stack 74 // Init network stack
85 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 75 let stack = &*make_static!(Stack::new(
76 device,
77 config,
78 make_static!(StackResources::<2>::new()),
79 seed
80 ));
86 81
87 // Launch network task 82 // Launch network task
88 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 1972f8ff2..d360df085 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -62,49 +62,39 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
62 T::enable(); 62 T::enable();
63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); 63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset();
64 64
65 unsafe { 65 ch1.set_speed(Speed::VeryHigh);
66 ch1.set_speed(Speed::VeryHigh); 66 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
67 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); 67 ch2.set_speed(Speed::VeryHigh);
68 ch2.set_speed(Speed::VeryHigh); 68 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull);
69 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); 69 ch3.set_speed(Speed::VeryHigh);
70 ch3.set_speed(Speed::VeryHigh); 70 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull);
71 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); 71 ch4.set_speed(Speed::VeryHigh);
72 ch4.set_speed(Speed::VeryHigh); 72 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
73 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
74 }
75 73
76 let mut this = Self { inner: tim }; 74 let mut this = Self { inner: tim };
77 75
78 this.set_freq(freq); 76 this.set_freq(freq);
79 this.inner.start(); 77 this.inner.start();
80 78
81 unsafe { 79 let r = T::regs_gp32();
82 T::regs_gp32() 80 r.ccmr_output(0)
83 .ccmr_output(0) 81 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
84 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 82 r.ccmr_output(0)
85 T::regs_gp32() 83 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
86 .ccmr_output(0) 84 r.ccmr_output(1)
87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); 85 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
88 T::regs_gp32() 86 r.ccmr_output(1)
89 .ccmr_output(1) 87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
90 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 88
91 T::regs_gp32()
92 .ccmr_output(1)
93 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
94 }
95 this 89 this
96 } 90 }
97 91
98 pub fn enable(&mut self, channel: Channel) { 92 pub fn enable(&mut self, channel: Channel) {
99 unsafe { 93 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
100 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
101 }
102 } 94 }
103 95
104 pub fn disable(&mut self, channel: Channel) { 96 pub fn disable(&mut self, channel: Channel) {
105 unsafe { 97 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
106 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
107 }
108 } 98 }
109 99
110 pub fn set_freq(&mut self, freq: Hertz) { 100 pub fn set_freq(&mut self, freq: Hertz) {
@@ -112,11 +102,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
112 } 102 }
113 103
114 pub fn get_max_duty(&self) -> u32 { 104 pub fn get_max_duty(&self) -> u32 {
115 unsafe { T::regs_gp32().arr().read().arr() } 105 T::regs_gp32().arr().read().arr()
116 } 106 }
117 107
118 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 108 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
119 defmt::assert!(duty < self.get_max_duty()); 109 defmt::assert!(duty < self.get_max_duty());
120 unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) } 110 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty))
121 } 111 }
122} 112}
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
index 2b0301aad..9181dfd67 100644
--- a/examples/stm32h7/src/bin/wdg.rs
+++ b/examples/stm32h7/src/bin/wdg.rs
@@ -15,10 +15,10 @@ async fn main(_spawner: Spawner) {
15 15
16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000); 16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
17 17
18 unsafe { wdg.unleash() }; 18 wdg.unleash();
19 19
20 loop { 20 loop {
21 Timer::after(Duration::from_secs(1)).await; 21 Timer::after(Duration::from_secs(1)).await;
22 unsafe { wdg.pet() }; 22 wdg.pet();
23 } 23 }
24} 24}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index ffb6cdb43..2ead714e4 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", 9nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", "embassy-executor/nightly",
10 "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"] 10 "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"]
11 11
12[dependencies] 12[dependencies]
@@ -31,4 +31,4 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
31futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
32heapless = { version = "0.7.5", default-features = false } 32heapless = { version = "0.7.5", default-features = false }
33embedded-hal = "0.2.6" 33embedded-hal = "0.2.6"
34static_cell = "1.0" 34static_cell = "1.1"
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 8b6508c87..93d48abeb 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12 12
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 29d091f94..3bb473ef5 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] }
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 281346e5f..1771e5202 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _};
12fn main() -> ! { 12fn main() -> ! {
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 unsafe { 15 pac::RCC.ccipr().modify(|w| {
16 pac::RCC.ccipr().modify(|w| { 16 w.set_adcsel(0b11);
17 w.set_adcsel(0b11); 17 });
18 }); 18 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
19 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
20 }
21 19
22 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
23 21
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index d6e744aa6..a36ed5d90 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -11,11 +11,9 @@ use {defmt_rtt as _, panic_probe as _};
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!"); 12 info!("Hello World!");
13 13
14 unsafe { 14 pac::RCC.apb1enr1().modify(|w| {
15 pac::RCC.apb1enr1().modify(|w| { 15 w.set_dac1en(true);
16 w.set_dac1en(true); 16 });
17 });
18 }
19 17
20 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
21 19
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index acb48c765..6035c291f 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -25,4 +25,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
25heapless = { version = "0.7.5", default-features = false } 25heapless = { version = "0.7.5", default-features = false }
26rand_core = { version = "0.6.3", default-features = false } 26rand_core = { version = "0.6.3", default-features = false }
27embedded-io = { version = "0.4.0", features = ["async"] } 27embedded-io = { version = "0.4.0", features = ["async"] }
28static_cell = "1.0" 28static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index b84e53d3a..32eba4277 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -15,20 +15,11 @@ use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice}; 15use embassy_usb::{Builder, UsbDevice};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use rand_core::RngCore; 17use rand_core::RngCore;
18use static_cell::StaticCell; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
21type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; 21type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>;
22 22
23macro_rules! singleton {
24 ($val:expr) => {{
25 type T = impl Sized;
26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
27 let (x,) = STATIC_CELL.init(($val,));
28 x
29 }};
30}
31
32const MTU: usize = 1514; 23const MTU: usize = 1514;
33 24
34bind_interrupts!(struct Irqs { 25bind_interrupts!(struct Irqs {
@@ -78,10 +69,10 @@ async fn main(spawner: Spawner) {
78 let mut builder = Builder::new( 69 let mut builder = Builder::new(
79 driver, 70 driver,
80 config, 71 config,
81 &mut singleton!([0; 256])[..], 72 &mut make_static!([0; 256])[..],
82 &mut singleton!([0; 256])[..], 73 &mut make_static!([0; 256])[..],
83 &mut singleton!([0; 256])[..], 74 &mut make_static!([0; 256])[..],
84 &mut singleton!([0; 128])[..], 75 &mut make_static!([0; 128])[..],
85 ); 76 );
86 77
87 // Our MAC addr. 78 // Our MAC addr.
@@ -90,18 +81,18 @@ async fn main(spawner: Spawner) {
90 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 81 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
91 82
92 // Create classes on the builder. 83 // Create classes on the builder.
93 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); 84 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
94 85
95 // Build the builder. 86 // Build the builder.
96 let usb = builder.build(); 87 let usb = builder.build();
97 88
98 unwrap!(spawner.spawn(usb_task(usb))); 89 unwrap!(spawner.spawn(usb_task(usb)));
99 90
100 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); 91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
101 unwrap!(spawner.spawn(usb_ncm_task(runner))); 92 unwrap!(spawner.spawn(usb_ncm_task(runner)));
102 93
103 let config = embassy_net::Config::Dhcp(Default::default()); 94 let config = embassy_net::Config::dhcpv4(Default::default());
104 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 95 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
105 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
106 // dns_servers: Vec::new(), 97 // dns_servers: Vec::new(),
107 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -112,7 +103,12 @@ async fn main(spawner: Spawner) {
112 let seed = rng.next_u64(); 103 let seed = rng.next_u64();
113 104
114 // Init network stack 105 // Init network stack
115 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 106 let stack = &*make_static!(Stack::new(
107 device,
108 config,
109 make_static!(StackResources::<2>::new()),
110 seed
111 ));
116 112
117 unwrap!(spawner.spawn(net_task(stack))); 113 unwrap!(spawner.spawn(net_task(stack)));
118 114
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index be205f880..e2318c3d6 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 8cfac772a..83a443754 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -6,9 +6,10 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
12embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
12 13
13defmt = "0.3" 14defmt = "0.3"
14defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index 8f4e70af0..9fc4b8aac 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -4,14 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
9use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
12bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
13 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 14 IPCC_C1_RX => ReceiveInterruptHandler;
14 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 15 IPCC_C1_TX => TransmitInterruptHandler;
15}); 16});
16 17
17#[embassy_executor::main] 18#[embassy_executor::main]
@@ -44,10 +45,10 @@ async fn main(_spawner: Spawner) {
44 info!("Hello World!"); 45 info!("Hello World!");
45 46
46 let config = Config::default(); 47 let config = Config::default();
47 let mbox = TlMbox::new(p.IPCC, Irqs, config); 48 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48 49
49 loop { 50 loop {
50 let wireless_fw_info = mbox.wireless_fw_info(); 51 let wireless_fw_info = mbox.sys_subsystem.wireless_fw_info();
51 match wireless_fw_info { 52 match wireless_fw_info {
52 None => info!("not yet initialized"), 53 None => info!("not yet initialized"),
53 Some(fw_info) => { 54 Some(fw_info) => {
diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
index 1724d946f..439bd01ac 100644
--- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
@@ -4,13 +4,14 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11bind_interrupts!(struct Irqs{ 12bind_interrupts!(struct Irqs{
12 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 13 IPCC_C1_RX => ReceiveInterruptHandler;
13 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 14 IPCC_C1_TX => TransmitInterruptHandler;
14}); 15});
15 16
16#[embassy_executor::main] 17#[embassy_executor::main]
@@ -43,55 +44,20 @@ async fn main(_spawner: Spawner) {
43 info!("Hello World!"); 44 info!("Hello World!");
44 45
45 let config = Config::default(); 46 let config = Config::default();
46 let mbox = TlMbox::new(p.IPCC, Irqs, config); 47 let mbox = TlMbox::init(p.IPCC, Irqs, config);
47 48
48 info!("waiting for coprocessor to boot"); 49 let sys_event = mbox.sys_subsystem.read().await;
49 let event_box = mbox.read().await; 50 info!("sys event: {}", sys_event.payload());
50 51
51 let mut payload = [0u8; 6]; 52 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
52 event_box.copy_into_slice(&mut payload).unwrap();
53 53
54 let event_packet = event_box.evt(); 54 info!("starting ble...");
55 let kind = event_packet.evt_serial.kind; 55 mbox.ble_subsystem.write(0x0c, &[]).await;
56 56
57 // means recieved SYS event, which indicates in this case that the coprocessor is ready 57 info!("waiting for ble...");
58 if kind == 0x12 { 58 let ble_event = mbox.ble_subsystem.read().await;
59 let code = event_packet.evt_serial.evt.evt_code;
60 let payload_len = event_packet.evt_serial.evt.payload_len;
61 59
62 info!( 60 info!("ble event: {}", ble_event.payload());
63 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
64 kind,
65 code,
66 payload_len,
67 payload[3..]
68 );
69 }
70
71 // initialize ble stack, does not return a response
72 mbox.shci_ble_init(Default::default());
73
74 info!("resetting BLE");
75 mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
76
77 let event_box = mbox.read().await;
78
79 let mut payload = [0u8; 7];
80 event_box.copy_into_slice(&mut payload).unwrap();
81
82 let event_packet = event_box.evt();
83 let kind = event_packet.evt_serial.kind;
84
85 let code = event_packet.evt_serial.evt.evt_code;
86 let payload_len = event_packet.evt_serial.evt.payload_len;
87
88 info!(
89 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
90 kind,
91 code,
92 payload_len,
93 payload[3..]
94 );
95 61
96 info!("Test OK"); 62 info!("Test OK");
97 cortex_m::asm::bkpt(); 63 cortex_m::asm::bkpt();
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 6191d01e9..260f9afa1 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] }
12embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" } 12embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" }
diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs
index e179c5ca1..805d21418 100644
--- a/examples/stm32wl/src/bin/lora_lorawan.rs
+++ b/examples/stm32wl/src/bin/lora_lorawan.rs
@@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) {
35 config.rcc.enable_lsi = true; // enable RNG 35 config.rcc.enable_lsi = true; // enable RNG
36 let p = embassy_stm32::init(config); 36 let p = embassy_stm32::init(config);
37 37
38 unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } 38 pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));
39 39
40 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); 40 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
41 41
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 182c607f9..d8562fca5 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -15,11 +15,9 @@ async fn main(_spawner: Spawner) {
15 config.rcc.enable_lsi = true; //Needed for RNG to work 15 config.rcc.enable_lsi = true; //Needed for RNG to work
16 16
17 let p = embassy_stm32::init(config); 17 let p = embassy_stm32::init(config);
18 unsafe { 18 pac::RCC.ccipr().modify(|w| {
19 pac::RCC.ccipr().modify(|w| { 19 w.set_rngsel(0b01);
20 w.set_rngsel(0b01); 20 });
21 });
22 }
23 21
24 info!("Hello World!"); 22 info!("Hello World!");
25 23
diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml
new file mode 100644
index 000000000..532039050
--- /dev/null
+++ b/tests/perf-server/Cargo.toml
@@ -0,0 +1,8 @@
1[package]
2name = "perf-server"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7log = "0.4.17"
8pretty_env_logger = "0.4.0"
diff --git a/tests/perf-server/deploy.sh b/tests/perf-server/deploy.sh
new file mode 100755
index 000000000..032e99c30
--- /dev/null
+++ b/tests/perf-server/deploy.sh
@@ -0,0 +1,11 @@
1#!/bin/bash
2
3set -euxo pipefail
4
5[email protected]
6
7cargo build --release
8ssh $HOST -- systemctl stop perf-server
9scp target/release/perf-server $HOST:/root
10scp perf-server.service $HOST:/etc/systemd/system/
11ssh $HOST -- 'systemctl daemon-reload; systemctl restart perf-server' \ No newline at end of file
diff --git a/tests/perf-server/perf-server.service b/tests/perf-server/perf-server.service
new file mode 100644
index 000000000..c14c5d16f
--- /dev/null
+++ b/tests/perf-server/perf-server.service
@@ -0,0 +1,16 @@
1[Unit]
2Description=perf-server
3After=network.target
4StartLimitIntervalSec=0
5
6[Service]
7Type=simple
8Restart=always
9RestartSec=1
10User=root
11ExecStart=/root/perf-server
12Environment=RUST_BACKTRACE=1
13Environment=RUST_LOG=info
14
15[Install]
16WantedBy=multi-user.target
diff --git a/tests/perf-server/src/main.rs b/tests/perf-server/src/main.rs
new file mode 100644
index 000000000..f6e7efc59
--- /dev/null
+++ b/tests/perf-server/src/main.rs
@@ -0,0 +1,90 @@
1use std::io::{Read, Write};
2use std::net::{TcpListener, TcpStream};
3use std::thread::spawn;
4use std::time::Duration;
5
6use log::info;
7
8fn main() {
9 pretty_env_logger::init();
10 spawn(|| rx_listen());
11 spawn(|| rxtx_listen());
12 tx_listen();
13}
14
15fn tx_listen() {
16 info!("tx: listening on 0.0.0.0:4321");
17 let listener = TcpListener::bind("0.0.0.0:4321").unwrap();
18 loop {
19 let (socket, addr) = listener.accept().unwrap();
20 info!("tx: received connection from: {}", addr);
21 spawn(|| tx_conn(socket));
22 }
23}
24
25fn tx_conn(mut socket: TcpStream) {
26 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
27 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
28
29 let buf = [0; 1024];
30 loop {
31 if let Err(e) = socket.write_all(&buf) {
32 info!("tx: failed to write to socket; err = {:?}", e);
33 return;
34 }
35 }
36}
37
38fn rx_listen() {
39 info!("rx: listening on 0.0.0.0:4322");
40 let listener = TcpListener::bind("0.0.0.0:4322").unwrap();
41 loop {
42 let (socket, addr) = listener.accept().unwrap();
43 info!("rx: received connection from: {}", addr);
44 spawn(|| rx_conn(socket));
45 }
46}
47
48fn rx_conn(mut socket: TcpStream) {
49 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
50 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
51
52 let mut buf = [0; 1024];
53 loop {
54 if let Err(e) = socket.read_exact(&mut buf) {
55 info!("rx: failed to read from socket; err = {:?}", e);
56 return;
57 }
58 }
59}
60
61fn rxtx_listen() {
62 info!("rxtx: listening on 0.0.0.0:4323");
63 let listener = TcpListener::bind("0.0.0.0:4323").unwrap();
64 loop {
65 let (socket, addr) = listener.accept().unwrap();
66 info!("rxtx: received connection from: {}", addr);
67 spawn(|| rxtx_conn(socket));
68 }
69}
70
71fn rxtx_conn(mut socket: TcpStream) {
72 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
73 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
74
75 let mut buf = [0; 1024];
76 loop {
77 match socket.read(&mut buf) {
78 Ok(n) => {
79 if let Err(e) = socket.write_all(&buf[..n]) {
80 info!("rxtx: failed to write to socket; err = {:?}", e);
81 return;
82 }
83 }
84 Err(e) => {
85 info!("rxtx: failed to read from socket; err = {:?}", e);
86 return;
87 }
88 }
89 }
90}
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 1786baee3..180d0ebbe 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -5,13 +5,16 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8teleprobe-meta = "1" 8teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
17cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
15 18
16defmt = "0.3.0" 19defmt = "0.3.0"
17defmt-rtt = "0.4" 20defmt-rtt = "0.4"
@@ -25,6 +28,7 @@ panic-probe = { version = "0.3.0", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26embedded-io = { version = "0.4.0", features = ["async"] } 29embedded-io = { version = "0.4.0", features = ["async"] }
27embedded-storage = { version = "0.3" } 30embedded-storage = { version = "0.3" }
31static_cell = { version = "1.1", features = ["nightly"]}
28 32
29[profile.dev] 33[profile.dev]
30debug = 2 34debug = 2
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
new file mode 100644
index 000000000..7a94ea191
--- /dev/null
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -0,0 +1,267 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use cyw43_pio::PioSpi;
8use defmt::{assert, panic, *};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::Pio;
16use embassy_rp::rom_data;
17use embassy_time::{with_timeout, Duration, Timer};
18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _};
20
21teleprobe_meta::timeout!(120);
22
23#[embassy_executor::task]
24async fn wifi_task(
25 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
26) -> ! {
27 runner.run().await
28}
29
30#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
32 stack.run().await
33}
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 info!("Hello World!");
38 let p = embassy_rp::init(Default::default());
39
40 // needed for reading the firmware from flash via XIP.
41 unsafe {
42 rom_data::flash_exit_xip();
43 rom_data::flash_enter_cmd_xip();
44 }
45
46 // cyw43 firmware needs to be flashed manually:
47 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000
48 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000
49 let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) };
50 let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) };
51
52 let pwr = Output::new(p.PIN_23, Level::Low);
53 let cs = Output::new(p.PIN_25, Level::High);
54 let mut pio = Pio::new(p.PIO0);
55 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
56
57 let state = make_static!(cyw43::State::new());
58 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
59 unwrap!(spawner.spawn(wifi_task(runner)));
60
61 control.init(clm).await;
62 control
63 .set_power_management(cyw43::PowerManagementMode::PowerSave)
64 .await;
65
66 let config = Config::dhcpv4(Default::default());
67 //let config = embassy_net::Config::Static(embassy_net::Config {
68 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
69 // dns_servers: Vec::new(),
70 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
71 //});
72
73 // Generate random seed
74 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
75
76 // Init network stack
77 let stack = &*make_static!(Stack::new(
78 net_device,
79 config,
80 make_static!(StackResources::<2>::new()),
81 seed
82 ));
83
84 unwrap!(spawner.spawn(net_task(stack)));
85
86 loop {
87 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await {
88 Ok(_) => break,
89 Err(err) => {
90 panic!("join failed with status={}", err.status);
91 }
92 }
93 }
94
95 info!("Waiting for DHCP up...");
96 while stack.config_v4().is_none() {
97 Timer::after(Duration::from_millis(100)).await;
98 }
99 info!("IP addressing up!");
100
101 let down = test_download(stack).await;
102 let up = test_upload(stack).await;
103 let updown = test_upload_download(stack).await;
104
105 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
106 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
107 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
108
109 info!("Test OK");
110 cortex_m::asm::bkpt();
111}
112
113// Test-only wifi network, no internet access!
114const WIFI_NETWORK: &str = "EmbassyTest";
115const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
116
117const TEST_DURATION: usize = 10;
118const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300;
119const TEST_EXPECTED_UPLOAD_KBPS: usize = 300;
120const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300;
121const RX_BUFFER_SIZE: usize = 4096;
122const TX_BUFFER_SIZE: usize = 4096;
123const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
124const DOWNLOAD_PORT: u16 = 4321;
125const UPLOAD_PORT: u16 = 4322;
126const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
127
128async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
129 info!("Testing download...");
130
131 let mut rx_buffer = [0; RX_BUFFER_SIZE];
132 let mut tx_buffer = [0; TX_BUFFER_SIZE];
133 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
134 socket.set_timeout(Some(Duration::from_secs(10)));
135
136 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
137 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
138 error!("connect error: {:?}", e);
139 return 0;
140 }
141 info!("connected, testing...");
142
143 let mut rx_buf = [0; 4096];
144 let mut total: usize = 0;
145 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
146 loop {
147 match socket.read(&mut rx_buf).await {
148 Ok(0) => {
149 error!("read EOF");
150 return 0;
151 }
152 Ok(n) => total += n,
153 Err(e) => {
154 error!("read error: {:?}", e);
155 return 0;
156 }
157 }
158 }
159 })
160 .await
161 .ok();
162
163 let kbps = (total + 512) / 1024 / TEST_DURATION;
164 info!("download: {} kB/s", kbps);
165 kbps
166}
167
168async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
169 info!("Testing upload...");
170
171 let mut rx_buffer = [0; RX_BUFFER_SIZE];
172 let mut tx_buffer = [0; TX_BUFFER_SIZE];
173 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
174 socket.set_timeout(Some(Duration::from_secs(10)));
175
176 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
177 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
178 error!("connect error: {:?}", e);
179 return 0;
180 }
181 info!("connected, testing...");
182
183 let buf = [0; 4096];
184 let mut total: usize = 0;
185 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
186 loop {
187 match socket.write(&buf).await {
188 Ok(0) => {
189 error!("write zero?!??!?!");
190 return 0;
191 }
192 Ok(n) => total += n,
193 Err(e) => {
194 error!("write error: {:?}", e);
195 return 0;
196 }
197 }
198 }
199 })
200 .await
201 .ok();
202
203 let kbps = (total + 512) / 1024 / TEST_DURATION;
204 info!("upload: {} kB/s", kbps);
205 kbps
206}
207
208async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
209 info!("Testing upload+download...");
210
211 let mut rx_buffer = [0; RX_BUFFER_SIZE];
212 let mut tx_buffer = [0; TX_BUFFER_SIZE];
213 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
214 socket.set_timeout(Some(Duration::from_secs(10)));
215
216 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
217 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
218 error!("connect error: {:?}", e);
219 return 0;
220 }
221 info!("connected, testing...");
222
223 let (mut reader, mut writer) = socket.split();
224
225 let tx_buf = [0; 4096];
226 let mut rx_buf = [0; 4096];
227 let mut total: usize = 0;
228 let tx_fut = async {
229 loop {
230 match writer.write(&tx_buf).await {
231 Ok(0) => {
232 error!("write zero?!??!?!");
233 return 0;
234 }
235 Ok(_) => {}
236 Err(e) => {
237 error!("write error: {:?}", e);
238 return 0;
239 }
240 }
241 }
242 };
243
244 let rx_fut = async {
245 loop {
246 match reader.read(&mut rx_buf).await {
247 Ok(0) => {
248 error!("read EOF");
249 return 0;
250 }
251 Ok(n) => total += n,
252 Err(e) => {
253 error!("read error: {:?}", e);
254 return 0;
255 }
256 }
257 }
258 };
259
260 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
261 .await
262 .ok();
263
264 let kbps = (total + 512) / 1024 / TEST_DURATION;
265 info!("upload+download: {} kB/s", kbps);
266 kbps
267}
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs
index 6a982507a..0e0de85fa 100644
--- a/tests/rp/src/bin/float.rs
+++ b/tests/rp/src/bin/float.rs
@@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) {
18 const PI_F: f32 = 3.1415926535f32; 18 const PI_F: f32 = 3.1415926535f32;
19 const PI_D: f64 = 3.14159265358979323846f64; 19 const PI_D: f64 = 3.14159265358979323846f64;
20 20
21 unsafe { 21 pac::BUSCTRL
22 pac::BUSCTRL 22 .perfsel(0)
23 .perfsel(0) 23 .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
24 .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
25 }
26 24
27 for i in 0..=360 { 25 for i in 0..=360 {
28 let rad_f = (i as f32) * PI_F / 180.0; 26 let rad_f = (i as f32) * PI_F / 180.0;
@@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) {
46 Timer::after(Duration::from_millis(10)).await; 44 Timer::after(Duration::from_millis(10)).await;
47 } 45 }
48 46
49 let rom_accesses = unsafe { pac::BUSCTRL.perfctr(0).read().perfctr() }; 47 let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr();
50 // every float operation used here uses at least 10 cycles 48 // every float operation used here uses at least 10 cycles
51 defmt::assert!(rom_accesses >= 360 * 12 * 10); 49 defmt::assert!(rom_accesses >= 360 * 12 * 10);
52 50
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 0f96c4ca3..365f631b7 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -12,24 +12,25 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo 12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo 13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo 14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo 15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo
16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo 16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
18 18
19sdmmc = [] 19sdmmc = []
20chrono = ["embassy-stm32/chrono", "dep:chrono"] 20chrono = ["embassy-stm32/chrono", "dep:chrono"]
21ble = []
22can = [] 21can = []
22ble = ["dep:embassy-stm32-wpan"]
23not-gpdma = [] 23not-gpdma = []
24 24
25[dependencies] 25[dependencies]
26teleprobe-meta = "1" 26teleprobe-meta = "1"
27 27
28embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 28embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
29embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 29embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
30embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } 30embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
31embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 31embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
32embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 32embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
33embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg"] }
33 34
34defmt = "0.3.0" 35defmt = "0.3.0"
35defmt-rtt = "0.4" 36defmt-rtt = "0.4"
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 32d35c42c..582df5753 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -24,10 +24,8 @@ async fn main(_spawner: Spawner) {
24 24
25 info!("Starting LSI"); 25 info!("Starting LSI");
26 26
27 unsafe { 27 pac::RCC.csr().modify(|w| w.set_lsion(true));
28 pac::RCC.csr().modify(|w| w.set_lsion(true)); 28 while !pac::RCC.csr().read().lsirdy() {}
29 while !pac::RCC.csr().read().lsirdy() {}
30 }
31 29
32 info!("Started LSI"); 30 info!("Started LSI");
33 31
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index fab9f0e1b..f6641ae31 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -6,49 +6,70 @@
6#[path = "../common.rs"] 6#[path = "../common.rs"]
7mod common; 7mod common;
8 8
9use core::mem;
10
9use common::*; 11use common::*;
10use embassy_executor::Spawner; 12use embassy_executor::Spawner;
11use embassy_stm32::tl_mbox::{Config, TlMbox}; 13use embassy_futures::poll_once;
12use embassy_stm32::{bind_interrupts, tl_mbox}; 14use embassy_stm32::bind_interrupts;
15use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
16use embassy_stm32_wpan::{mm, TlMbox};
13use embassy_time::{Duration, Timer}; 17use embassy_time::{Duration, Timer};
14 18
15bind_interrupts!(struct Irqs{ 19bind_interrupts!(struct Irqs{
16 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 20 IPCC_C1_RX => ReceiveInterruptHandler;
17 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 21 IPCC_C1_TX => TransmitInterruptHandler;
18}); 22});
19 23
24#[embassy_executor::task]
25async fn run_mm_queue(memory_manager: mm::MemoryManager) {
26 memory_manager.run_queue().await;
27}
28
20#[embassy_executor::main] 29#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 30async fn main(spawner: Spawner) {
22 let p = embassy_stm32::init(config()); 31 let p = embassy_stm32::init(config());
23 info!("Hello World!"); 32 info!("Hello World!");
24 33
25 let config = Config::default(); 34 let config = Config::default();
26 let mbox = TlMbox::new(p.IPCC, Irqs, config); 35 let mbox = TlMbox::init(p.IPCC, Irqs, config);
36
37 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
38
39 let ready_event = mbox.sys_subsystem.read().await;
40 let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not
41
42 info!("coprocessor ready {}", ready_event.payload());
43
44 // test memory manager
45 mem::drop(ready_event);
46
47 let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap();
48 let version_major = fw_info.version_major();
49 let version_minor = fw_info.version_minor();
50 let subversion = fw_info.subversion();
51
52 let sram2a_size = fw_info.sram2a_size();
53 let sram2b_size = fw_info.sram2b_size();
54
55 info!(
56 "version {}.{}.{} - SRAM2a {} - SRAM2b {}",
57 version_major, version_minor, subversion, sram2a_size, sram2b_size
58 );
27 59
28 loop { 60 Timer::after(Duration::from_millis(50)).await;
29 let wireless_fw_info = mbox.wireless_fw_info();
30 match wireless_fw_info {
31 None => {}
32 Some(fw_info) => {
33 let version_major = fw_info.version_major();
34 let version_minor = fw_info.version_minor();
35 let subversion = fw_info.subversion();
36 61
37 let sram2a_size = fw_info.sram2a_size(); 62 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
38 let sram2b_size = fw_info.sram2b_size();
39 63
40 info!( 64 info!("starting ble...");
41 "version {}.{}.{} - SRAM2a {} - SRAM2b {}", 65 mbox.ble_subsystem.write(0x0c, &[]).await;
42 version_major, version_minor, subversion, sram2a_size, sram2b_size
43 );
44 66
45 break; 67 info!("waiting for ble...");
46 } 68 let ble_event = mbox.ble_subsystem.read().await;
47 }
48 69
49 Timer::after(Duration::from_millis(50)).await; 70 info!("ble event: {}", ble_event.payload());
50 }
51 71
72 Timer::after(Duration::from_millis(150)).await;
52 info!("Test OK"); 73 info!("Test OK");
53 cortex_m::asm::bkpt(); 74 cortex_m::asm::bkpt();
54} 75}