aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-22 14:49:31 -0500
committerxoviat <[email protected]>2023-07-22 14:49:31 -0500
commitd42dff45de94522d7a5324773b352266a77f0c2c (patch)
treeb1d9e5d113405f60a211d046713f992a0f7c825b
parent0c49e6747c02e03fc6517969105cfdf20239fc64 (diff)
parent603ea9f31039f3c25a5314f53c2d8f8bcabe16af (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into hrtim
-rw-r--r--.gitattributes41
-rwxr-xr-x.github/ci/crlf.sh17
-rwxr-xr-x.github/ci/doc.sh52
-rwxr-xr-xci.sh4
-rw-r--r--cyw43/Cargo.toml4
-rw-r--r--cyw43/README.md2
-rw-r--r--cyw43/src/runner.rs20
-rw-r--r--embassy-embedded-hal/Cargo.toml7
-rw-r--r--embassy-embedded-hal/src/adapter/blocking_async.rs43
-rw-r--r--embassy-embedded-hal/src/adapter/yielding_async.rs39
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs126
-rw-r--r--embassy-embedded-hal/src/shared_bus/blocking/spi.rs120
-rw-r--r--embassy-embedded-hal/src/shared_bus/mod.rs4
-rw-r--r--embassy-executor/Cargo.toml4
-rw-r--r--embassy-executor/src/raw/mod.rs3
-rw-r--r--embassy-hal-common/src/peripheral.rs2
-rw-r--r--embassy-lora/Cargo.toml9
-rw-r--r--embassy-net-driver/src/lib.rs3
-rw-r--r--embassy-net-esp-hosted/Cargo.toml12
-rw-r--r--embassy-net-esp-hosted/src/control.rs12
-rw-r--r--embassy-net-esp-hosted/src/lib.rs4
-rw-r--r--embassy-net-w5500/Cargo.toml10
-rw-r--r--embassy-net-w5500/src/spi.rs8
-rw-r--r--embassy-net/Cargo.toml3
-rw-r--r--embassy-net/src/device.rs2
-rw-r--r--embassy-net/src/lib.rs119
-rw-r--r--embassy-net/src/udp.rs70
-rw-r--r--embassy-nrf/Cargo.toml24
-rw-r--r--embassy-nrf/src/gpiote.rs8
-rw-r--r--embassy-nrf/src/pdm.rs794
-rw-r--r--embassy-nrf/src/ppi/dppi.rs8
-rw-r--r--embassy-nrf/src/ppi/mod.rs37
-rw-r--r--embassy-nrf/src/ppi/ppi.rs8
-rw-r--r--embassy-nrf/src/pwm.rs22
-rw-r--r--embassy-nrf/src/saadc.rs4
-rw-r--r--embassy-nrf/src/spim.rs16
-rw-r--r--embassy-nrf/src/timer.rs12
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/adc.rs235
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/gpio.rs6
-rw-r--r--embassy-rp/src/i2c.rs5
-rw-r--r--embassy-rp/src/lib.rs1
-rw-r--r--embassy-rp/src/pio.rs78
-rw-r--r--embassy-rp/src/rtc/datetime_no_deps.rs1
-rw-r--r--embassy-rp/src/rtc/mod.rs50
-rw-r--r--embassy-rp/src/spi.rs20
-rw-r--r--embassy-rp/src/usb.rs3
-rw-r--r--embassy-rp/src/watchdog.rs32
-rw-r--r--embassy-stm32-wpan/Cargo.toml17
-rw-r--r--embassy-stm32-wpan/src/cmd.rs2
-rw-r--r--embassy-stm32-wpan/src/consts.rs3
-rw-r--r--embassy-stm32-wpan/src/lib.rs46
-rw-r--r--embassy-stm32-wpan/src/mac/commands.rs476
-rw-r--r--embassy-stm32-wpan/src/mac/consts.rs4
-rw-r--r--embassy-stm32-wpan/src/mac/control.rs95
-rw-r--r--embassy-stm32-wpan/src/mac/driver.rs122
-rw-r--r--embassy-stm32-wpan/src/mac/event.rs153
-rw-r--r--embassy-stm32-wpan/src/mac/indications.rs265
-rw-r--r--embassy-stm32-wpan/src/mac/macros.rs32
-rw-r--r--embassy-stm32-wpan/src/mac/mod.rs21
-rw-r--r--embassy-stm32-wpan/src/mac/opcodes.rs92
-rw-r--r--embassy-stm32-wpan/src/mac/responses.rs273
-rw-r--r--embassy-stm32-wpan/src/mac/runner.rs109
-rw-r--r--embassy-stm32-wpan/src/mac/typedefs.rs381
-rw-r--r--embassy-stm32-wpan/src/sub/mac.rs48
-rw-r--r--embassy-stm32-wpan/src/sub/mm.rs12
-rw-r--r--embassy-stm32-wpan/src/sub/sys.rs27
-rw-r--r--embassy-stm32-wpan/src/tables.rs92
-rw-r--r--embassy-stm32/Cargo.toml12
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/adc/mod.rs12
-rw-r--r--embassy-stm32/src/adc/sample_time.rs1
-rw-r--r--embassy-stm32/src/can/bxcan.rs89
-rw-r--r--embassy-stm32/src/can/fdcan.rs66
-rw-r--r--embassy-stm32/src/can/mod.rs1
-rw-r--r--embassy-stm32/src/dac/mod.rs7
-rw-r--r--embassy-stm32/src/dma/dma.rs3
-rw-r--r--embassy-stm32/src/eth/generic_smi.rs45
-rw-r--r--embassy-stm32/src/eth/mod.rs10
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs27
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs27
-rw-r--r--embassy-stm32/src/flash/asynch.rs2
-rw-r--r--embassy-stm32/src/flash/common.rs2
-rw-r--r--embassy-stm32/src/flash/f0.rs3
-rw-r--r--embassy-stm32/src/flash/f3.rs3
-rw-r--r--embassy-stm32/src/flash/f4.rs3
-rw-r--r--embassy-stm32/src/flash/h7.rs3
-rw-r--r--embassy-stm32/src/flash/l.rs3
-rw-r--r--embassy-stm32/src/fmc.rs18
-rw-r--r--embassy-stm32/src/i2c/v2.rs52
-rw-r--r--embassy-stm32/src/ipcc.rs3
-rw-r--r--embassy-stm32/src/qspi/mod.rs664
-rw-r--r--embassy-stm32/src/rcc/h5.rs4
-rw-r--r--embassy-stm32/src/rcc/h7.rs2
-rw-r--r--embassy-stm32/src/rcc/l4.rs23
-rw-r--r--embassy-stm32/src/rcc/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/wl.rs61
-rw-r--r--embassy-stm32/src/rtc/v3.rs1
-rw-r--r--embassy-stm32/src/spi/mod.rs23
-rw-r--r--embassy-stm32/src/usart/mod.rs27
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs21
-rw-r--r--embassy-sync/src/channel.rs22
-rw-r--r--embassy-time/CHANGELOG.md5
-rw-r--r--embassy-time/Cargo.toml8
-rw-r--r--embassy-time/src/driver.rs2
-rw-r--r--embassy-time/src/driver_std.rs2
-rw-r--r--embassy-time/src/driver_wasm.rs2
-rw-r--r--embassy-time/src/queue_generic.rs2
-rw-r--r--examples/boot/application/nrf/Cargo.toml2
-rw-r--r--examples/boot/application/rp/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml2
-rw-r--r--examples/nrf52840-rtic/Cargo.toml2
-rw-r--r--examples/nrf52840/Cargo.toml10
-rw-r--r--examples/nrf52840/src/bin/pdm.rs46
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs81
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs10
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml10
-rw-r--r--examples/rp/src/bin/adc.rs25
-rw-r--r--examples/rp/src/bin/blinky.rs4
-rw-r--r--examples/rp/src/bin/button.rs4
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs13
-rw-r--r--examples/rp/src/bin/flash.rs2
-rw-r--r--examples/rp/src/bin/gpio_async.rs6
-rw-r--r--examples/rp/src/bin/gpout.rs4
-rw-r--r--examples/rp/src/bin/i2c_async.rs5
-rw-r--r--examples/rp/src/bin/i2c_blocking.rs5
-rw-r--r--examples/rp/src/bin/lora_lorawan.rs1
-rw-r--r--examples/rp/src/bin/lora_p2p_receive.rs1
-rw-r--r--examples/rp/src/bin/lora_p2p_send.rs1
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs1
-rw-r--r--examples/rp/src/bin/multicore.rs4
-rw-r--r--examples/rp/src/bin/pio_async.rs20
-rw-r--r--examples/rp/src/bin/pio_dma.rs13
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs18
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs16
-rw-r--r--examples/rp/src/bin/pwm.rs4
-rw-r--r--examples/rp/src/bin/rtc.rs46
-rw-r--r--examples/rp/src/bin/spi.rs4
-rw-r--r--examples/rp/src/bin/spi_async.rs3
-rw-r--r--examples/rp/src/bin/spi_display.rs13
-rw-r--r--examples/rp/src/bin/uart.rs6
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs6
-rw-r--r--examples/rp/src/bin/uart_unidir.rs6
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs4
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs188
-rw-r--r--examples/rp/src/bin/usb_logger.rs4
-rw-r--r--examples/rp/src/bin/usb_serial.rs4
-rw-r--r--examples/rp/src/bin/watchdog.rs4
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs12
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs13
-rw-r--r--examples/rp/src/bin/wifi_scan.rs12
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs19
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/stm32c0/Cargo.toml2
-rw-r--r--examples/stm32f0/Cargo.toml2
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f4/Cargo.toml2
-rw-r--r--examples/stm32f4/src/bin/can.rs18
-rw-r--r--examples/stm32f4/src/bin/eth.rs111
-rw-r--r--examples/stm32f7/Cargo.toml2
-rw-r--r--examples/stm32f7/src/bin/can.rs66
-rw-r--r--examples/stm32f7/src/bin/eth.rs2
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32h5/Cargo.toml6
-rw-r--r--examples/stm32h5/src/bin/eth.rs2
-rw-r--r--examples/stm32h7/Cargo.toml6
-rw-r--r--examples/stm32h7/src/bin/eth.rs2
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs2
-rw-r--r--examples/stm32l0/Cargo.toml5
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/Cargo.toml9
-rw-r--r--examples/stm32l4/src/bin/rtc.rs49
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32u5/Cargo.toml2
-rw-r--r--examples/stm32wb/.cargo/config.toml2
-rw-r--r--examples/stm32wb/Cargo.toml22
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs2
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs397
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs185
-rw-r--r--examples/stm32wb/src/bin/mac_ffd_net.rs170
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs182
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs2
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs12
-rw-r--r--examples/stm32wl/.cargo/config.toml2
-rw-r--r--examples/stm32wl/Cargo.toml10
-rw-r--r--examples/stm32wl/src/bin/rtc.rs43
-rw-r--r--examples/wasm/Cargo.toml2
-rw-r--r--rust-toolchain.toml4
-rw-r--r--tests/nrf/Cargo.toml4
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs6
-rw-r--r--tests/riscv32/Cargo.toml2
-rw-r--r--tests/rp/Cargo.toml8
-rw-r--r--tests/rp/src/bin/adc.rs86
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs10
-rw-r--r--tests/rp/src/bin/gpio.rs36
-rw-r--r--tests/rp/src/bin/pio_irq.rs55
-rw-r--r--tests/stm32/Cargo.toml30
-rw-r--r--tests/stm32/src/bin/can.rs7
-rw-r--r--tests/stm32/src/bin/gpio.rs36
-rw-r--r--tests/stm32/src/bin/rtc.rs2
-rw-r--r--tests/stm32/src/bin/wpan_ble.rs (renamed from tests/stm32/src/bin/tl_mbox.rs)2
-rw-r--r--tests/stm32/src/bin/wpan_mac.rs124
217 files changed, 6485 insertions, 1629 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..4db9edae7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,41 @@
1* text=auto
2
3*.adoc text
4*.html text
5*.in text
6*.json text
7*.md text
8*.proto text
9*.py text
10*.rs text
11*.service text
12*.sh text
13*.toml text
14*.txt text
15*.x text
16*.yml text
17
18*.raw binary
19*.bin binary
20*.png binary
21*.jpg binary
22*.jpeg binary
23*.gif binary
24*.ico binary
25*.mov binary
26*.mp4 binary
27*.mp3 binary
28*.flv binary
29*.fla binary
30*.swf binary
31*.gz binary
32*.zip binary
33*.7z binary
34*.ttf binary
35*.eot binary
36*.woff binary
37*.pyc binary
38*.pdf binary
39*.ez binary
40*.bz2 binary
41*.swp binary \ No newline at end of file
diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh
new file mode 100755
index 000000000..457510407
--- /dev/null
+++ b/.github/ci/crlf.sh
@@ -0,0 +1,17 @@
1#!/bin/bash
2## on push branch~=gh-readonly-queue/main/.*
3## on pull_request
4
5set -euo pipefail
6
7FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true))
8
9if [ -z "$FILES_WITH_CRLF" ]; then
10 echo -e "No files with CRLF endings found."
11 exit 0
12else
13 NR_FILES=$(echo "$FILES_WITH_CRLF" | wc -l)
14 echo -e "ERROR: Found ${NR_FILES} files with CRLF endings."
15 echo "$FILES_WITH_CRLF"
16 exit "$NR_FILES"
17fi \ No newline at end of file
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 1402e742f..06c6fa00b 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -6,7 +6,7 @@ set -euo pipefail
6export RUSTUP_HOME=/ci/cache/rustup 6export RUSTUP_HOME=/ci/cache/rustup
7export CARGO_HOME=/ci/cache/cargo 7export CARGO_HOME=/ci/cache/cargo
8export CARGO_TARGET_DIR=/ci/cache/target 8export CARGO_TARGET_DIR=/ci/cache/target
9export BUILDER_THREADS=6 9export BUILDER_THREADS=4
10export BUILDER_COMPRESS=true 10export BUILDER_COMPRESS=true
11 11
12# force rustup to download the toolchain before starting building. 12# force rustup to download the toolchain before starting building.
@@ -15,30 +15,32 @@ export BUILDER_COMPRESS=true
15# which makes rustup very sad 15# which makes rustup very sad
16rustc --version > /dev/null 16rustc --version > /dev/null
17 17
18docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup 18docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
19docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup 19docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup
20docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup 20docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup
21docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup 21docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup
22docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup 22docserver-builder -i ./embassy-boot/stm32 -o webroot/crates/embassy-boot-stm32/git.zup
23docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup 23docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
24docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup 24docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
25docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup 25docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
26docserver-builder -i ./embassy-lora -o crates/embassy-lora/git.zup 26docserver-builder -i ./embassy-lora -o webroot/crates/embassy-lora/git.zup
27docserver-builder -i ./embassy-net -o crates/embassy-net/git.zup 27docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup
28docserver-builder -i ./embassy-net-driver -o crates/embassy-net-driver/git.zup 28docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
29docserver-builder -i ./embassy-net-driver-channel -o crates/embassy-net-driver-channel/git.zup 29docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
30docserver-builder -i ./embassy-nrf -o crates/embassy-nrf/git.zup 30docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
31docserver-builder -i ./embassy-rp -o crates/embassy-rp/git.zup 31docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
32docserver-builder -i ./embassy-sync -o crates/embassy-sync/git.zup 32docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
33docserver-builder -i ./embassy-time -o crates/embassy-time/git.zup 33docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup
34docserver-builder -i ./embassy-usb -o crates/embassy-usb/git.zup 34docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
35docserver-builder -i ./embassy-usb-driver -o crates/embassy-usb-driver/git.zup 35docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
36docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup 36docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
37docserver-builder -i ./cyw43 -o crates/cyw43/git.zup 37docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
38docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup 38docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
39docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup 39docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup
40docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup 40docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
41docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
41 42
42export KUBECONFIG=/ci/secrets/kubeconfig.yml 43export KUBECONFIG=/ci/secrets/kubeconfig.yml
43POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 44POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
44kubectl cp crates $POD:/data 45kubectl cp webroot/crates $POD:/data
46kubectl cp webroot/static $POD:/data \ No newline at end of file
diff --git a/ci.sh b/ci.sh
index ec6304f16..6c10a0630 100755
--- a/ci.sh
+++ b/ci.sh
@@ -5,10 +5,6 @@ set -euo pipefail
5export RUSTFLAGS=-Dwarnings 5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info 6export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
7 7
8# needed by wifi examples
9export WIFI_NETWORK=x
10export WIFI_PASSWORD=x
11
12TARGET=$(rustc -vV | sed -n 's|host: ||p') 8TARGET=$(rustc -vV | sed -n 's|host: ||p')
13 9
14BUILD_EXTRA="" 10BUILD_EXTRA=""
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 61caa0272..50fb7c5db 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -11,7 +11,7 @@ log = ["dep:log"]
11firmware-logs = [] 11firmware-logs = []
12 12
13[dependencies] 13[dependencies]
14embassy-time = { version = "0.1.0", path = "../embassy-time"} 14embassy-time = { version = "0.1.2", path = "../embassy-time"}
15embassy-sync = { version = "0.2.0", path = "../embassy-sync"} 15embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
16embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 16embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
17embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} 17embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
@@ -24,7 +24,7 @@ cortex-m = "0.7.6"
24cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
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.11" }
28num_enum = { version = "0.5.7", default-features = false } 28num_enum = { version = "0.5.7", default-features = false }
29 29
30[package.metadata.embassy_docs] 30[package.metadata.embassy_docs]
diff --git a/cyw43/README.md b/cyw43/README.md
index e4a81410d..5b8f3cf40 100644
--- a/cyw43/README.md
+++ b/cyw43/README.md
@@ -30,7 +30,7 @@ TODO:
30### Example 2: Create an access point (IP and credentials in the code) 30### Example 2: Create an access point (IP and credentials in the code)
31- `cargo run --release --bin wifi_ap_tcp_server` 31- `cargo run --release --bin wifi_ap_tcp_server`
32### Example 3: Connect to an existing network and create a server 32### Example 3: Connect to an existing network and create a server
33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release --bin wifi_tcp_server` 33- `cargo run --release --bin wifi_tcp_server`
34 34
35After a few seconds, you should see that DHCP picks up an IP address like this 35After a few seconds, you should see that DHCP picks up an IP address like this
36``` 36```
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index 5706696b4..1c187faa5 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -345,7 +345,9 @@ where
345 } 345 }
346 346
347 fn rx(&mut self, packet: &mut [u8]) { 347 fn rx(&mut self, packet: &mut [u8]) {
348 let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return }; 348 let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else {
349 return;
350 };
349 351
350 self.update_credit(&sdpcm_header); 352 self.update_credit(&sdpcm_header);
351 353
@@ -353,7 +355,9 @@ where
353 355
354 match channel { 356 match channel {
355 CHANNEL_TYPE_CONTROL => { 357 CHANNEL_TYPE_CONTROL => {
356 let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; }; 358 let Some((cdc_header, response)) = CdcHeader::parse(payload) else {
359 return;
360 };
357 trace!(" {:?}", cdc_header); 361 trace!(" {:?}", cdc_header);
358 362
359 if cdc_header.id == self.ioctl_id { 363 if cdc_header.id == self.ioctl_id {
@@ -417,8 +421,12 @@ where
417 let status = event_packet.msg.status; 421 let status = event_packet.msg.status;
418 let event_payload = match evt_type { 422 let event_payload = match evt_type {
419 Event::ESCAN_RESULT if status == EStatus::PARTIAL => { 423 Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
420 let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return }; 424 let Some((_, bss_info)) = ScanResults::parse(evt_data) else {
421 let Some(bss_info) = BssInfo::parse(bss_info) else { return }; 425 return;
426 };
427 let Some(bss_info) = BssInfo::parse(bss_info) else {
428 return;
429 };
422 events::Payload::BssInfo(*bss_info) 430 events::Payload::BssInfo(*bss_info)
423 } 431 }
424 Event::ESCAN_RESULT => events::Payload::None, 432 Event::ESCAN_RESULT => events::Payload::None,
@@ -439,7 +447,9 @@ where
439 } 447 }
440 } 448 }
441 CHANNEL_TYPE_DATA => { 449 CHANNEL_TYPE_DATA => {
442 let Some((_, packet)) = BdcHeader::parse(payload) else { return }; 450 let Some((_, packet)) = BdcHeader::parse(payload) else {
451 return;
452 };
443 trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); 453 trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
444 454
445 match self.ch.try_rx_buf() { 455 match self.ch.try_rx_buf() {
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 35c70bb63..bba3d48be 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -15,15 +15,18 @@ target = "x86_64-unknown-linux-gnu"
15std = [] 15std = []
16# Enable nightly-only features 16# Enable nightly-only features
17nightly = ["embassy-futures", "embedded-hal-async", "embedded-storage-async"] 17nightly = ["embassy-futures", "embedded-hal-async", "embedded-storage-async"]
18time = ["dep:embassy-time"]
19default = ["time"]
18 20
19[dependencies] 21[dependencies]
20embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } 22embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
21embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 23embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
24embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
22embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ 25embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
23 "unproven", 26 "unproven",
24] } 27] }
25embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
26embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true } 29embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true }
27embedded-storage = "0.3.0" 30embedded-storage = "0.3.0"
28embedded-storage-async = { version = "0.4.0", optional = true } 31embedded-storage-async = { version = "0.4.0", optional = true }
29nb = "1.0.0" 32nb = "1.0.0"
diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs
index b996d6a75..98ae2b02c 100644
--- a/embassy-embedded-hal/src/adapter/blocking_async.rs
+++ b/embassy-embedded-hal/src/adapter/blocking_async.rs
@@ -74,47 +74,30 @@ where
74 E: embedded_hal_1::spi::Error + 'static, 74 E: embedded_hal_1::spi::Error + 'static,
75 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 75 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
76{ 76{
77 async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> { 77 async fn flush(&mut self) -> Result<(), Self::Error> {
78 // Ensure we write the expected bytes
79 for i in 0..core::cmp::min(read.len(), write.len()) {
80 read[i] = write[i].clone();
81 }
82 self.wrapped.transfer(read)?;
83 Ok(()) 78 Ok(())
84 } 79 }
85 80
86 async fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Result<(), Self::Error> { 81 async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
87 todo!() 82 self.wrapped.write(data)?;
83 Ok(())
88 } 84 }
89}
90 85
91impl<T, E> embedded_hal_async::spi::SpiBusFlush for BlockingAsync<T> 86 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
92where 87 self.wrapped.transfer(data)?;
93 E: embedded_hal_1::spi::Error + 'static,
94 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
95{
96 async fn flush(&mut self) -> Result<(), Self::Error> {
97 Ok(()) 88 Ok(())
98 } 89 }
99}
100 90
101impl<T, E> embedded_hal_async::spi::SpiBusWrite<u8> for BlockingAsync<T> 91 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
102where 92 // Ensure we write the expected bytes
103 E: embedded_hal_1::spi::Error + 'static, 93 for i in 0..core::cmp::min(read.len(), write.len()) {
104 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 94 read[i] = write[i].clone();
105{ 95 }
106 async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> { 96 self.wrapped.transfer(read)?;
107 self.wrapped.write(data)?;
108 Ok(()) 97 Ok(())
109 } 98 }
110}
111 99
112impl<T, E> embedded_hal_async::spi::SpiBusRead<u8> for BlockingAsync<T> 100 async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
113where
114 E: embedded_hal_1::spi::Error + 'static,
115 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
116{
117 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
118 self.wrapped.transfer(data)?; 101 self.wrapped.transfer(data)?;
119 Ok(()) 102 Ok(())
120 } 103 }
diff --git a/embassy-embedded-hal/src/adapter/yielding_async.rs b/embassy-embedded-hal/src/adapter/yielding_async.rs
index f51e4076f..fe9c9c341 100644
--- a/embassy-embedded-hal/src/adapter/yielding_async.rs
+++ b/embassy-embedded-hal/src/adapter/yielding_async.rs
@@ -69,51 +69,36 @@ where
69 type Error = T::Error; 69 type Error = T::Error;
70} 70}
71 71
72impl<T> embedded_hal_async::spi::SpiBus<u8> for YieldingAsync<T> 72impl<T, Word: 'static + Copy> embedded_hal_async::spi::SpiBus<Word> for YieldingAsync<T>
73where 73where
74 T: embedded_hal_async::spi::SpiBus, 74 T: embedded_hal_async::spi::SpiBus<Word>,
75{ 75{
76 async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> { 76 async fn flush(&mut self) -> Result<(), Self::Error> {
77 self.wrapped.transfer(read, write).await?; 77 self.wrapped.flush().await?;
78 yield_now().await; 78 yield_now().await;
79 Ok(()) 79 Ok(())
80 } 80 }
81 81
82 async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Result<(), Self::Error> { 82 async fn write(&mut self, data: &[Word]) -> Result<(), Self::Error> {
83 self.wrapped.transfer_in_place(words).await?; 83 self.wrapped.write(data).await?;
84 yield_now().await; 84 yield_now().await;
85 Ok(()) 85 Ok(())
86 } 86 }
87}
88 87
89impl<T> embedded_hal_async::spi::SpiBusFlush for YieldingAsync<T> 88 async fn read(&mut self, data: &mut [Word]) -> Result<(), Self::Error> {
90where 89 self.wrapped.read(data).await?;
91 T: embedded_hal_async::spi::SpiBusFlush,
92{
93 async fn flush(&mut self) -> Result<(), Self::Error> {
94 self.wrapped.flush().await?;
95 yield_now().await; 90 yield_now().await;
96 Ok(()) 91 Ok(())
97 } 92 }
98}
99 93
100impl<T> embedded_hal_async::spi::SpiBusWrite<u8> for YieldingAsync<T> 94 async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
101where 95 self.wrapped.transfer(read, write).await?;
102 T: embedded_hal_async::spi::SpiBusWrite<u8>,
103{
104 async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
105 self.wrapped.write(data).await?;
106 yield_now().await; 96 yield_now().await;
107 Ok(()) 97 Ok(())
108 } 98 }
109}
110 99
111impl<T> embedded_hal_async::spi::SpiBusRead<u8> for YieldingAsync<T> 100 async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
112where 101 self.wrapped.transfer_in_place(words).await?;
113 T: embedded_hal_async::spi::SpiBusRead<u8>,
114{
115 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
116 self.wrapped.read(data).await?;
117 yield_now().await; 102 yield_now().await;
118 Ok(()) 103 Ok(())
119 } 104 }
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index b5549a6cd..030392183 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -56,62 +56,6 @@ where
56 type Error = SpiDeviceError<BUS::Error, CS::Error>; 56 type Error = SpiDeviceError<BUS::Error, CS::Error>;
57} 57}
58 58
59impl<M, BUS, CS> spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
60where
61 M: RawMutex,
62 BUS: spi::SpiBusRead,
63 CS: OutputPin,
64{
65 async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
66 let mut bus = self.bus.lock().await;
67 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
68
69 let op_res: Result<(), BUS::Error> = try {
70 for buf in operations {
71 bus.read(buf).await?;
72 }
73 };
74
75 // On failure, it's important to still flush and deassert CS.
76 let flush_res = bus.flush().await;
77 let cs_res = self.cs.set_high();
78
79 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
80 flush_res.map_err(SpiDeviceError::Spi)?;
81 cs_res.map_err(SpiDeviceError::Cs)?;
82
83 Ok(op_res)
84 }
85}
86
87impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
88where
89 M: RawMutex,
90 BUS: spi::SpiBusWrite,
91 CS: OutputPin,
92{
93 async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
94 let mut bus = self.bus.lock().await;
95 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
96
97 let op_res: Result<(), BUS::Error> = try {
98 for buf in operations {
99 bus.write(buf).await?;
100 }
101 };
102
103 // On failure, it's important to still flush and deassert CS.
104 let flush_res = bus.flush().await;
105 let cs_res = self.cs.set_high();
106
107 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
108 flush_res.map_err(SpiDeviceError::Spi)?;
109 cs_res.map_err(SpiDeviceError::Cs)?;
110
111 Ok(op_res)
112 }
113}
114
115impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 59impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
116where 60where
117 M: RawMutex, 61 M: RawMutex,
@@ -129,6 +73,12 @@ where
129 Operation::Write(buf) => bus.write(buf).await?, 73 Operation::Write(buf) => bus.write(buf).await?,
130 Operation::Transfer(read, write) => bus.transfer(read, write).await?, 74 Operation::Transfer(read, write) => bus.transfer(read, write).await?,
131 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?, 75 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
76 #[cfg(not(feature = "time"))]
77 Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
78 #[cfg(feature = "time")]
79 Operation::DelayUs(us) => {
80 embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
81 }
132 } 82 }
133 } 83 }
134 }; 84 };
@@ -172,64 +122,6 @@ where
172 type Error = SpiDeviceError<BUS::Error, CS::Error>; 122 type Error = SpiDeviceError<BUS::Error, CS::Error>;
173} 123}
174 124
175impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
176where
177 M: RawMutex,
178 BUS: spi::SpiBusWrite + SetConfig,
179 CS: OutputPin,
180{
181 async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
182 let mut bus = self.bus.lock().await;
183 bus.set_config(&self.config);
184 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
185
186 let op_res: Result<(), BUS::Error> = try {
187 for buf in operations {
188 bus.write(buf).await?;
189 }
190 };
191
192 // On failure, it's important to still flush and deassert CS.
193 let flush_res = bus.flush().await;
194 let cs_res = self.cs.set_high();
195
196 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
197 flush_res.map_err(SpiDeviceError::Spi)?;
198 cs_res.map_err(SpiDeviceError::Cs)?;
199
200 Ok(op_res)
201 }
202}
203
204impl<M, BUS, CS> spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
205where
206 M: RawMutex,
207 BUS: spi::SpiBusRead + SetConfig,
208 CS: OutputPin,
209{
210 async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
211 let mut bus = self.bus.lock().await;
212 bus.set_config(&self.config);
213 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
214
215 let op_res: Result<(), BUS::Error> = try {
216 for buf in operations {
217 bus.read(buf).await?;
218 }
219 };
220
221 // On failure, it's important to still flush and deassert CS.
222 let flush_res = bus.flush().await;
223 let cs_res = self.cs.set_high();
224
225 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
226 flush_res.map_err(SpiDeviceError::Spi)?;
227 cs_res.map_err(SpiDeviceError::Cs)?;
228
229 Ok(op_res)
230 }
231}
232
233impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 125impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
234where 126where
235 M: RawMutex, 127 M: RawMutex,
@@ -248,6 +140,12 @@ where
248 Operation::Write(buf) => bus.write(buf).await?, 140 Operation::Write(buf) => bus.write(buf).await?,
249 Operation::Transfer(read, write) => bus.transfer(read, write).await?, 141 Operation::Transfer(read, write) => bus.transfer(read, write).await?,
250 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?, 142 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
143 #[cfg(not(feature = "time"))]
144 Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
145 #[cfg(feature = "time")]
146 Operation::DelayUs(us) => {
147 embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
148 }
251 } 149 }
252 } 150 }
253 }; 151 };
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index 22e013be9..6d03d6263 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -22,7 +22,7 @@ use core::cell::RefCell;
22use embassy_sync::blocking_mutex::raw::RawMutex; 22use embassy_sync::blocking_mutex::raw::RawMutex;
23use embassy_sync::blocking_mutex::Mutex; 23use embassy_sync::blocking_mutex::Mutex;
24use embedded_hal_1::digital::OutputPin; 24use embedded_hal_1::digital::OutputPin;
25use embedded_hal_1::spi::{self, Operation, SpiBus, SpiBusRead, SpiBusWrite}; 25use embedded_hal_1::spi::{self, Operation, SpiBus};
26 26
27use crate::shared_bus::SpiDeviceError; 27use crate::shared_bus::SpiDeviceError;
28use crate::SetConfig; 28use crate::SetConfig;
@@ -48,58 +48,6 @@ where
48 type Error = SpiDeviceError<BUS::Error, CS::Error>; 48 type Error = SpiDeviceError<BUS::Error, CS::Error>;
49} 49}
50 50
51impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
52where
53 M: RawMutex,
54 BUS: SpiBusRead,
55 CS: OutputPin,
56{
57 fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
58 self.bus.lock(|bus| {
59 let mut bus = bus.borrow_mut();
60 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
61
62 let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
63
64 // On failure, it's important to still flush and deassert CS.
65 let flush_res = bus.flush();
66 let cs_res = self.cs.set_high();
67
68 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
69 flush_res.map_err(SpiDeviceError::Spi)?;
70 cs_res.map_err(SpiDeviceError::Cs)?;
71
72 Ok(op_res)
73 })
74 }
75}
76
77impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
78where
79 M: RawMutex,
80 BUS: SpiBusWrite,
81 CS: OutputPin,
82{
83 fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
84 self.bus.lock(|bus| {
85 let mut bus = bus.borrow_mut();
86 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
87
88 let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
89
90 // On failure, it's important to still flush and deassert CS.
91 let flush_res = bus.flush();
92 let cs_res = self.cs.set_high();
93
94 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
95 flush_res.map_err(SpiDeviceError::Spi)?;
96 cs_res.map_err(SpiDeviceError::Cs)?;
97
98 Ok(op_res)
99 })
100 }
101}
102
103impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS> 51impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
104where 52where
105 M: RawMutex, 53 M: RawMutex,
@@ -116,6 +64,13 @@ where
116 Operation::Write(buf) => bus.write(buf), 64 Operation::Write(buf) => bus.write(buf),
117 Operation::Transfer(read, write) => bus.transfer(read, write), 65 Operation::Transfer(read, write) => bus.transfer(read, write),
118 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf), 66 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
67 #[cfg(not(feature = "time"))]
68 Operation::DelayUs(_) => Err(SpiDeviceError::DelayUsNotSupported),
69 #[cfg(feature = "time")]
70 Operation::DelayUs(us) => {
71 embassy_time::block_for(embassy_time::Duration::from_micros(*us as _));
72 Ok(())
73 }
119 }); 74 });
120 75
121 // On failure, it's important to still flush and deassert CS. 76 // On failure, it's important to still flush and deassert CS.
@@ -199,58 +154,6 @@ where
199 type Error = SpiDeviceError<BUS::Error, CS::Error>; 154 type Error = SpiDeviceError<BUS::Error, CS::Error>;
200} 155}
201 156
202impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
203where
204 M: RawMutex,
205 BUS: SpiBusRead + SetConfig,
206 CS: OutputPin,
207{
208 fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
209 self.bus.lock(|bus| {
210 let mut bus = bus.borrow_mut();
211 bus.set_config(&self.config);
212 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
213
214 let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
215
216 // On failure, it's important to still flush and deassert CS.
217 let flush_res = bus.flush();
218 let cs_res = self.cs.set_high();
219
220 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
221 flush_res.map_err(SpiDeviceError::Spi)?;
222 cs_res.map_err(SpiDeviceError::Cs)?;
223 Ok(op_res)
224 })
225 }
226}
227
228impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
229where
230 M: RawMutex,
231 BUS: SpiBusWrite + SetConfig,
232 CS: OutputPin,
233{
234 fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
235 self.bus.lock(|bus| {
236 let mut bus = bus.borrow_mut();
237 bus.set_config(&self.config);
238 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
239
240 let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
241
242 // On failure, it's important to still flush and deassert CS.
243 let flush_res = bus.flush();
244 let cs_res = self.cs.set_high();
245
246 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
247 flush_res.map_err(SpiDeviceError::Spi)?;
248 cs_res.map_err(SpiDeviceError::Cs)?;
249 Ok(op_res)
250 })
251 }
252}
253
254impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS> 157impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
255where 158where
256 M: RawMutex, 159 M: RawMutex,
@@ -268,6 +171,13 @@ where
268 Operation::Write(buf) => bus.write(buf), 171 Operation::Write(buf) => bus.write(buf),
269 Operation::Transfer(read, write) => bus.transfer(read, write), 172 Operation::Transfer(read, write) => bus.transfer(read, write),
270 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf), 173 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
174 #[cfg(not(feature = "time"))]
175 Operation::DelayUs(_) => Err(SpiDeviceError::DelayUsNotSupported),
176 #[cfg(feature = "time")]
177 Operation::DelayUs(us) => {
178 embassy_time::block_for(embassy_time::Duration::from_micros(*us as _));
179 Ok(())
180 }
271 }); 181 });
272 182
273 // On failure, it's important to still flush and deassert CS. 183 // On failure, it's important to still flush and deassert CS.
diff --git a/embassy-embedded-hal/src/shared_bus/mod.rs b/embassy-embedded-hal/src/shared_bus/mod.rs
index 617d921e9..79a90bd52 100644
--- a/embassy-embedded-hal/src/shared_bus/mod.rs
+++ b/embassy-embedded-hal/src/shared_bus/mod.rs
@@ -30,11 +30,14 @@ where
30/// Error returned by SPI device implementations in this crate. 30/// Error returned by SPI device implementations in this crate.
31#[derive(Copy, Clone, Eq, PartialEq, Debug)] 31#[derive(Copy, Clone, Eq, PartialEq, Debug)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))] 32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33#[non_exhaustive]
33pub enum SpiDeviceError<BUS, CS> { 34pub enum SpiDeviceError<BUS, CS> {
34 /// An operation on the inner SPI bus failed. 35 /// An operation on the inner SPI bus failed.
35 Spi(BUS), 36 Spi(BUS),
36 /// Setting the value of the Chip Select (CS) pin failed. 37 /// Setting the value of the Chip Select (CS) pin failed.
37 Cs(CS), 38 Cs(CS),
39 /// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
40 DelayUsNotSupported,
38} 41}
39 42
40impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS> 43impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
@@ -46,6 +49,7 @@ where
46 match self { 49 match self {
47 Self::Spi(e) => e.kind(), 50 Self::Spi(e) => e.kind(),
48 Self::Cs(_) => spi::ErrorKind::Other, 51 Self::Cs(_) => spi::ErrorKind::Other,
52 Self::DelayUsNotSupported => spi::ErrorKind::Other,
49 } 53 }
50 } 54 }
51} 55}
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 1e5494ef8..590718e3e 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -61,8 +61,8 @@ log = { version = "0.4.14", optional = true }
61rtos-trace = { version = "0.1.2", optional = true } 61rtos-trace = { version = "0.1.2", optional = true }
62 62
63futures-util = { version = "0.3.17", default-features = false } 63futures-util = { version = "0.3.17", default-features = false }
64embassy-macros = { version = "0.2.0", path = "../embassy-macros" } 64embassy-macros = { version = "0.2.0", path = "../embassy-macros" }
65embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true} 65embassy-time = { version = "0.1.2", 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.1" 68static_cell = "1.1"
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index bd0cff26b..f3760f589 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -165,6 +165,9 @@ impl<F: Future + 'static> TaskStorage<F> {
165 Poll::Ready(_) => { 165 Poll::Ready(_) => {
166 this.future.drop_in_place(); 166 this.future.drop_in_place();
167 this.raw.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel); 167 this.raw.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel);
168
169 #[cfg(feature = "integrated-timers")]
170 this.raw.expires_at.set(Instant::MAX);
168 } 171 }
169 Poll::Pending => {} 172 Poll::Pending => {}
170 } 173 }
diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs
index c7133bac6..38b4c452e 100644
--- a/embassy-hal-common/src/peripheral.rs
+++ b/embassy-hal-common/src/peripheral.rs
@@ -161,7 +161,7 @@ pub trait Peripheral: Sized {
161 } 161 }
162} 162}
163 163
164impl<'b, T: Deref> Peripheral for T 164impl<'b, T: DerefMut> Peripheral for T
165where 165where
166 T::Target: Peripheral, 166 T::Target: Peripheral,
167{ 167{
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index 05b6fa2d0..e4524af5b 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -20,11 +20,11 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
20defmt = { version = "0.3", optional = true } 20defmt = { version = "0.3", optional = true }
21log = { version = "0.4.14", optional = true } 21log = { version = "0.4.14", optional = true }
22 22
23embassy-time = { version = "0.1.0", path = "../embassy-time" } 23embassy-time = { version = "0.1.2", path = "../embassy-time" }
24embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 24embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
25embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } 25embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
26embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 26embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
27embedded-hal-async = { version = "=0.2.0-alpha.1" } 27embedded-hal-async = { version = "=0.2.0-alpha.2" }
28embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } 28embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false }
29futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 29futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
30embedded-hal = { version = "0.2", features = ["unproven"] } 30embedded-hal = { version = "0.2", features = ["unproven"] }
@@ -32,3 +32,6 @@ bit_field = { version = "0.10" }
32 32
33lora-phy = { version = "1" } 33lora-phy = { version = "1" }
34lorawan-device = { version = "0.10.0", default-features = false, features = ["async"] } 34lorawan-device = { version = "0.10.0", default-features = false, features = ["async"] }
35
36[patch.crates-io]
37lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs
index 4149bf4a4..09def20c4 100644
--- a/embassy-net-driver/src/lib.rs
+++ b/embassy-net-driver/src/lib.rs
@@ -164,6 +164,9 @@ pub enum Medium {
164 /// 164 ///
165 /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode. 165 /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
166 Ip, 166 Ip,
167
168 /// IEEE 802_15_4 medium
169 Ieee802154,
167} 170}
168 171
169impl Default for Medium { 172impl Default for Medium {
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index a7e18ee09..0053c49a4 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -7,14 +7,20 @@ edition = "2021"
7defmt = { version = "0.3", optional = true } 7defmt = { version = "0.3", optional = true }
8log = { version = "0.4.14", optional = true } 8log = { version = "0.4.14", optional = true }
9 9
10embassy-time = { version = "0.1.0", path = "../embassy-time" } 10embassy-time = { version = "0.1.2", path = "../embassy-time" }
11embassy-sync = { version = "0.2.0", path = "../embassy-sync"} 11embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
12embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 12embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} 13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
14 14
15embedded-hal = { version = "1.0.0-alpha.10" } 15embedded-hal = { version = "1.0.0-alpha.11" }
16embedded-hal-async = { version = "=0.2.0-alpha.1" } 16embedded-hal-async = { version = "=0.2.0-alpha.2" }
17 17
18noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } 18noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] }
19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } 19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
20heapless = "0.7.16" 20heapless = "0.7.16"
21
22[package.metadata.embassy_docs]
23src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$VERSION/embassy-net-esp-hosted/src/"
24src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/"
25target = "thumbv7em-none-eabi"
26features = ["defmt"] \ No newline at end of file
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index fce82ade7..79f8cde7b 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -54,7 +54,9 @@ impl<'a> Control<'a> {
54 })), 54 })),
55 }; 55 };
56 let resp = self.ioctl(req).await; 56 let resp = self.ioctl(req).await;
57 let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; 57 let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else {
58 panic!("unexpected resp")
59 };
58 debug!("======= {:?}", Debug2Format(&resp)); 60 debug!("======= {:?}", Debug2Format(&resp));
59 assert_eq!(resp.resp, 0); 61 assert_eq!(resp.resp, 0);
60 self.state_ch.set_link_state(LinkState::Up); 62 self.state_ch.set_link_state(LinkState::Up);
@@ -71,7 +73,9 @@ impl<'a> Control<'a> {
71 )), 73 )),
72 }; 74 };
73 let resp = self.ioctl(req).await; 75 let resp = self.ioctl(req).await;
74 let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; 76 let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else {
77 panic!("unexpected resp")
78 };
75 assert_eq!(resp.resp, 0); 79 assert_eq!(resp.resp, 0);
76 80
77 // WHY IS THIS A STRING? WHYYYY 81 // WHY IS THIS A STRING? WHYYYY
@@ -100,7 +104,9 @@ impl<'a> Control<'a> {
100 payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })), 104 payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })),
101 }; 105 };
102 let resp = self.ioctl(req).await; 106 let resp = self.ioctl(req).await;
103 let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; 107 let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else {
108 panic!("unexpected resp")
109 };
104 assert_eq!(resp.resp, 0); 110 assert_eq!(resp.resp, 0);
105 } 111 }
106 112
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 44dfbe89c..a35adfca0 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -311,14 +311,14 @@ where
311 fn handle_event(&self, data: &[u8]) { 311 fn handle_event(&self, data: &[u8]) {
312 let Ok(event) = noproto::read::<CtrlMsg>(data) else { 312 let Ok(event) = noproto::read::<CtrlMsg>(data) else {
313 warn!("failed to parse event"); 313 warn!("failed to parse event");
314 return 314 return;
315 }; 315 };
316 316
317 debug!("event: {:?}", &event); 317 debug!("event: {:?}", &event);
318 318
319 let Some(payload) = &event.payload else { 319 let Some(payload) = &event.payload else {
320 warn!("event without payload?"); 320 warn!("event without payload?");
321 return 321 return;
322 }; 322 };
323 323
324 match payload { 324 match payload {
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-w5500/Cargo.toml
index 37d15c7ac..8972b814a 100644
--- a/embassy-net-w5500/Cargo.toml
+++ b/embassy-net-w5500/Cargo.toml
@@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9 9
10[dependencies] 10[dependencies]
11embedded-hal = { version = "1.0.0-alpha.10" } 11embedded-hal = { version = "1.0.0-alpha.11" }
12embedded-hal-async = { version = "=0.2.0-alpha.1" } 12embedded-hal-async = { version = "=0.2.0-alpha.2" }
13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} 13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
14embassy-time = { version = "0.1.0" } 14embassy-time = { version = "0.1.2", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0" } 15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
16defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
17 17
18[package.metadata.embassy_docs] 18[package.metadata.embassy_docs]
diff --git a/embassy-net-w5500/src/spi.rs b/embassy-net-w5500/src/spi.rs
index 6cd52c44d..07749d6be 100644
--- a/embassy-net-w5500/src/spi.rs
+++ b/embassy-net-w5500/src/spi.rs
@@ -22,7 +22,11 @@ impl<SPI: SpiDevice> SpiInterface<SPI> {
22 let address_phase = address.to_be_bytes(); 22 let address_phase = address.to_be_bytes();
23 let control_phase = [(block as u8) << 3 | 0b0000_0100]; 23 let control_phase = [(block as u8) << 3 | 0b0000_0100];
24 let data_phase = data; 24 let data_phase = data;
25 let operations = &[&address_phase[..], &control_phase, &data_phase]; 25 let operations = &mut [
26 self.0.write_transaction(operations).await 26 Operation::Write(&address_phase[..]),
27 Operation::Write(&control_phase),
28 Operation::Write(&data_phase),
29 ];
30 self.0.transaction(operations).await
27 } 31 }
28} 32}
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index e89039daa..9b6a11c16 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -37,6 +37,7 @@ proto-ipv4 = ["smoltcp/proto-ipv4"]
37proto-ipv6 = ["smoltcp/proto-ipv6"] 37proto-ipv6 = ["smoltcp/proto-ipv6"]
38medium-ethernet = ["smoltcp/medium-ethernet"] 38medium-ethernet = ["smoltcp/medium-ethernet"]
39medium-ip = ["smoltcp/medium-ip"] 39medium-ip = ["smoltcp/medium-ip"]
40medium-ieee802154 = ["smoltcp/medium-ieee802154"]
40igmp = ["smoltcp/proto-igmp"] 41igmp = ["smoltcp/proto-igmp"]
41 42
42[dependencies] 43[dependencies]
@@ -50,7 +51,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
50] } 51] }
51 52
52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 53embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
53embassy-time = { version = "0.1.0", path = "../embassy-time" } 54embassy-time = { version = "0.1.2", path = "../embassy-time" }
54embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 55embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
55embedded-io = { version = "0.4.0", optional = true } 56embedded-io = { version = "0.4.0", optional = true }
56 57
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index 4513c86d3..d29ab8970 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -51,6 +51,8 @@ where
51 Medium::Ethernet => phy::Medium::Ethernet, 51 Medium::Ethernet => phy::Medium::Ethernet,
52 #[cfg(feature = "medium-ip")] 52 #[cfg(feature = "medium-ip")]
53 Medium::Ip => phy::Medium::Ip, 53 Medium::Ip => phy::Medium::Ip,
54 #[cfg(feature = "medium-ieee802154")]
55 Medium::Ieee802154 => phy::Medium::Ieee802154,
54 #[allow(unreachable_patterns)] 56 #[allow(unreachable_patterns)]
55 _ => panic!( 57 _ => panic!(
56 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", 58 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 840d7a09a..81c751a2c 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -24,9 +24,11 @@ use embassy_net_driver::{Driver, LinkState, Medium};
24use embassy_sync::waitqueue::WakerRegistration; 24use embassy_sync::waitqueue::WakerRegistration;
25use embassy_time::{Instant, Timer}; 25use embassy_time::{Instant, Timer};
26use futures::pin_mut; 26use futures::pin_mut;
27#[allow(unused_imports)]
27use heapless::Vec; 28use heapless::Vec;
28#[cfg(feature = "igmp")] 29#[cfg(feature = "igmp")]
29pub use smoltcp::iface::MulticastError; 30pub use smoltcp::iface::MulticastError;
31#[allow(unused_imports)]
30use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; 32use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage};
31#[cfg(feature = "dhcpv4")] 33#[cfg(feature = "dhcpv4")]
32use smoltcp::socket::dhcpv4::{self, RetryConfig}; 34use smoltcp::socket::dhcpv4::{self, RetryConfig};
@@ -34,7 +36,9 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
34pub use smoltcp::wire::IpListenEndpoint; 36pub use smoltcp::wire::IpListenEndpoint;
35#[cfg(feature = "medium-ethernet")] 37#[cfg(feature = "medium-ethernet")]
36pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; 38pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
37pub use smoltcp::wire::{IpAddress, IpCidr}; 39#[cfg(feature = "medium-ieee802154")]
40pub use smoltcp::wire::{HardwareAddress, Ieee802154Address};
41pub use smoltcp::wire::{IpAddress, IpCidr, IpEndpoint};
38#[cfg(feature = "proto-ipv4")] 42#[cfg(feature = "proto-ipv4")]
39pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; 43pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
40#[cfg(feature = "proto-ipv6")] 44#[cfg(feature = "proto-ipv6")]
@@ -232,7 +236,7 @@ impl<D: Driver + 'static> Stack<D> {
232 resources: &'static mut StackResources<SOCK>, 236 resources: &'static mut StackResources<SOCK>,
233 random_seed: u64, 237 random_seed: u64,
234 ) -> Self { 238 ) -> Self {
235 #[cfg(feature = "medium-ethernet")] 239 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
236 let medium = device.capabilities().medium; 240 let medium = device.capabilities().medium;
237 241
238 let hardware_addr = match medium { 242 let hardware_addr = match medium {
@@ -240,6 +244,8 @@ impl<D: Driver + 'static> Stack<D> {
240 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())), 244 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())),
241 #[cfg(feature = "medium-ip")] 245 #[cfg(feature = "medium-ip")]
242 Medium::Ip => HardwareAddress::Ip, 246 Medium::Ip => HardwareAddress::Ip,
247 #[cfg(feature = "medium-ieee802154")]
248 Medium::Ieee802154 => HardwareAddress::Ieee802154(Ieee802154Address::Absent),
243 #[allow(unreachable_patterns)] 249 #[allow(unreachable_patterns)]
244 _ => panic!( 250 _ => panic!(
245 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", 251 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
@@ -262,6 +268,7 @@ impl<D: Driver + 'static> Stack<D> {
262 268
263 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; 269 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
264 270
271 #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))]
265 let mut socket = SocketStack { 272 let mut socket = SocketStack {
266 sockets, 273 sockets,
267 iface, 274 iface,
@@ -269,6 +276,7 @@ impl<D: Driver + 'static> Stack<D> {
269 next_local_port, 276 next_local_port,
270 }; 277 };
271 278
279 #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))]
272 let mut inner = Inner { 280 let mut inner = Inner {
273 device, 281 device,
274 link_up: false, 282 link_up: false,
@@ -287,6 +295,9 @@ impl<D: Driver + 'static> Stack<D> {
287 dns_waker: WakerRegistration::new(), 295 dns_waker: WakerRegistration::new(),
288 }; 296 };
289 297
298 #[cfg(feature = "medium-ieee802154")]
299 let _ = config;
300
290 #[cfg(feature = "proto-ipv4")] 301 #[cfg(feature = "proto-ipv4")]
291 match config.ipv4 { 302 match config.ipv4 {
292 ConfigV4::Static(config) => { 303 ConfigV4::Static(config) => {
@@ -479,30 +490,78 @@ impl<D: Driver + 'static> Stack<D> {
479} 490}
480 491
481#[cfg(feature = "igmp")] 492#[cfg(feature = "igmp")]
482impl<D: Driver + smoltcp::phy::Device + 'static> Stack<D> { 493impl<D: Driver + 'static> Stack<D> {
483 /// Join a multicast group. 494 /// Join a multicast group.
484 pub fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> 495 pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
496 where
497 T: Into<IpAddress>,
498 {
499 let addr = addr.into();
500
501 poll_fn(move |cx| self.poll_join_multicast_group(addr, cx)).await
502 }
503
504 /// Join a multicast group.
505 ///
506 /// When the send queue is full, this method will return `Poll::Pending`
507 /// and register the current task to be notified when the queue has space available.
508 pub fn poll_join_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
485 where 509 where
486 T: Into<IpAddress>, 510 T: Into<IpAddress>,
487 { 511 {
488 let addr = addr.into(); 512 let addr = addr.into();
489 513
490 self.with_mut(|s, i| { 514 self.with_mut(|s, i| {
491 s.iface 515 let mut smoldev = DriverAdapter {
492 .join_multicast_group(&mut i.device, addr, instant_to_smoltcp(Instant::now())) 516 cx: Some(cx),
517 inner: &mut i.device,
518 };
519
520 match s
521 .iface
522 .join_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
523 {
524 Ok(announce_sent) => Poll::Ready(Ok(announce_sent)),
525 Err(MulticastError::Exhausted) => Poll::Pending,
526 Err(other) => Poll::Ready(Err(other)),
527 }
493 }) 528 })
494 } 529 }
495 530
496 /// Leave a multicast group. 531 /// Leave a multicast group.
497 pub fn leave_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> 532 pub async fn leave_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
533 where
534 T: Into<IpAddress>,
535 {
536 let addr = addr.into();
537
538 poll_fn(move |cx| self.poll_leave_multicast_group(addr, cx)).await
539 }
540
541 /// Leave a multicast group.
542 ///
543 /// When the send queue is full, this method will return `Poll::Pending`
544 /// and register the current task to be notified when the queue has space available.
545 pub fn poll_leave_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
498 where 546 where
499 T: Into<IpAddress>, 547 T: Into<IpAddress>,
500 { 548 {
501 let addr = addr.into(); 549 let addr = addr.into();
502 550
503 self.with_mut(|s, i| { 551 self.with_mut(|s, i| {
504 s.iface 552 let mut smoldev = DriverAdapter {
505 .leave_multicast_group(&mut i.device, addr, instant_to_smoltcp(Instant::now())) 553 cx: Some(cx),
554 inner: &mut i.device,
555 };
556
557 match s
558 .iface
559 .leave_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
560 {
561 Ok(leave_sent) => Poll::Ready(Ok(leave_sent)),
562 Err(MulticastError::Exhausted) => Poll::Pending,
563 Err(other) => Poll::Ready(Err(other)),
564 }
506 }) 565 })
507 } 566 }
508 567
@@ -531,11 +590,14 @@ impl<D: Driver + 'static> Inner<D> {
531 590
532 debug!(" IP address: {}", config.address); 591 debug!(" IP address: {}", config.address);
533 s.iface.update_ip_addrs(|addrs| { 592 s.iface.update_ip_addrs(|addrs| {
534 if addrs.is_empty() { 593 if let Some((index, _)) = addrs
535 addrs.push(IpCidr::Ipv4(config.address)).unwrap(); 594 .iter()
536 } else { 595 .enumerate()
537 addrs[0] = IpCidr::Ipv4(config.address); 596 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
597 {
598 addrs.remove(index);
538 } 599 }
600 addrs.push(IpCidr::Ipv4(config.address)).unwrap();
539 }); 601 });
540 602
541 #[cfg(feature = "medium-ethernet")] 603 #[cfg(feature = "medium-ethernet")]
@@ -570,11 +632,14 @@ impl<D: Driver + 'static> Inner<D> {
570 632
571 debug!(" IP address: {}", config.address); 633 debug!(" IP address: {}", config.address);
572 s.iface.update_ip_addrs(|addrs| { 634 s.iface.update_ip_addrs(|addrs| {
573 if addrs.is_empty() { 635 if let Some((index, _)) = addrs
574 addrs.push(IpCidr::Ipv6(config.address)).unwrap(); 636 .iter()
575 } else { 637 .enumerate()
576 addrs[0] = IpCidr::Ipv6(config.address); 638 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv6(_)))
639 {
640 addrs.remove(index);
577 } 641 }
642 addrs.push(IpCidr::Ipv6(config.address)).unwrap();
578 }); 643 });
579 644
580 #[cfg(feature = "medium-ethernet")] 645 #[cfg(feature = "medium-ethernet")]
@@ -642,13 +707,21 @@ impl<D: Driver + 'static> Inner<D> {
642 socket.set_retry_config(config.retry_config); 707 socket.set_retry_config(config.retry_config);
643 } 708 }
644 709
645 #[allow(unused)] // used only with dhcp 710 #[cfg(feature = "dhcpv4")]
646 fn unapply_config(&mut self, s: &mut SocketStack) { 711 fn unapply_config_v4(&mut self, s: &mut SocketStack) {
647 #[cfg(feature = "medium-ethernet")] 712 #[cfg(feature = "medium-ethernet")]
648 let medium = self.device.capabilities().medium; 713 let medium = self.device.capabilities().medium;
649
650 debug!("Lost IP configuration"); 714 debug!("Lost IP configuration");
651 s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); 715 s.iface.update_ip_addrs(|ip_addrs| {
716 #[cfg(feature = "proto-ipv4")]
717 if let Some((index, _)) = ip_addrs
718 .iter()
719 .enumerate()
720 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
721 {
722 ip_addrs.remove(index);
723 }
724 });
652 #[cfg(feature = "medium-ethernet")] 725 #[cfg(feature = "medium-ethernet")]
653 if medium == Medium::Ethernet { 726 if medium == Medium::Ethernet {
654 #[cfg(feature = "proto-ipv4")] 727 #[cfg(feature = "proto-ipv4")]
@@ -695,7 +768,7 @@ impl<D: Driver + 'static> Inner<D> {
695 if self.link_up { 768 if self.link_up {
696 match socket.poll() { 769 match socket.poll() {
697 None => {} 770 None => {}
698 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), 771 Some(dhcpv4::Event::Deconfigured) => self.unapply_config_v4(s),
699 Some(dhcpv4::Event::Configured(config)) => { 772 Some(dhcpv4::Event::Configured(config)) => {
700 let config = StaticConfigV4 { 773 let config = StaticConfigV4 {
701 address: config.address, 774 address: config.address,
@@ -707,7 +780,7 @@ impl<D: Driver + 'static> Inner<D> {
707 } 780 }
708 } else if old_link_up { 781 } else if old_link_up {
709 socket.reset(); 782 socket.reset();
710 self.unapply_config(s); 783 self.unapply_config_v4(s);
711 } 784 }
712 } 785 }
713 //if old_link_up || self.link_up { 786 //if old_link_up || self.link_up {
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 36f8d06f2..0d97b6db1 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -3,7 +3,7 @@
3use core::cell::RefCell; 3use core::cell::RefCell;
4use core::future::poll_fn; 4use core::future::poll_fn;
5use core::mem; 5use core::mem;
6use core::task::Poll; 6use core::task::{Context, Poll};
7 7
8use embassy_net_driver::Driver; 8use embassy_net_driver::Driver;
9use smoltcp::iface::{Interface, SocketHandle}; 9use smoltcp::iface::{Interface, SocketHandle};
@@ -102,37 +102,61 @@ impl<'a> UdpSocket<'a> {
102 /// 102 ///
103 /// Returns the number of bytes received and the remote endpoint. 103 /// Returns the number of bytes received and the remote endpoint.
104 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { 104 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
105 poll_fn(move |cx| { 105 poll_fn(move |cx| self.poll_recv_from(buf, cx)).await
106 self.with_mut(|s, _| match s.recv_slice(buf) { 106 }
107 Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))), 107
108 // No data ready 108 /// Receive a datagram.
109 Err(udp::RecvError::Exhausted) => { 109 ///
110 s.register_recv_waker(cx.waker()); 110 /// When no datagram is available, this method will return `Poll::Pending` and
111 Poll::Pending 111 /// register the current task to be notified when a datagram is received.
112 } 112 ///
113 }) 113 /// When a datagram is received, this method will return `Poll::Ready` with the
114 /// number of bytes received and the remote endpoint.
115 pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<(usize, IpEndpoint), Error>> {
116 self.with_mut(|s, _| match s.recv_slice(buf) {
117 Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
118 // No data ready
119 Err(udp::RecvError::Exhausted) => {
120 s.register_recv_waker(cx.waker());
121 Poll::Pending
122 }
114 }) 123 })
115 .await
116 } 124 }
117 125
118 /// Send a datagram to the specified remote endpoint. 126 /// Send a datagram to the specified remote endpoint.
127 ///
128 /// This method will wait until the datagram has been sent.
129 ///
130 /// When the remote endpoint is not reachable, this method will return `Err(Error::NoRoute)`
119 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error> 131 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error>
120 where 132 where
121 T: Into<IpEndpoint>, 133 T: Into<IpEndpoint>,
122 { 134 {
123 let remote_endpoint = remote_endpoint.into(); 135 let remote_endpoint: IpEndpoint = remote_endpoint.into();
124 poll_fn(move |cx| { 136 poll_fn(move |cx| self.poll_send_to(buf, remote_endpoint, cx)).await
125 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { 137 }
126 // Entire datagram has been sent 138
127 Ok(()) => Poll::Ready(Ok(())), 139 /// Send a datagram to the specified remote endpoint.
128 Err(udp::SendError::BufferFull) => { 140 ///
129 s.register_send_waker(cx.waker()); 141 /// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
130 Poll::Pending 142 ///
131 } 143 /// When the socket's send buffer is full, this method will return `Poll::Pending`
132 Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)), 144 /// and register the current task to be notified when the buffer has space available.
133 }) 145 ///
146 /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`.
147 pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), Error>>
148 where
149 T: Into<IpEndpoint>,
150 {
151 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
152 // Entire datagram has been sent
153 Ok(()) => Poll::Ready(Ok(())),
154 Err(udp::SendError::BufferFull) => {
155 s.register_send_waker(cx.waker());
156 Poll::Pending
157 }
158 Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
134 }) 159 })
135 .await
136 } 160 }
137 161
138 /// Returns the local endpoint of the socket. 162 /// Returns the local endpoint of the socket.
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 3e858f854..57dd22f1c 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-nrf-v$VERSION/embassy-nrf/src/" 8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-nrf-v$VERSION/embassy-nrf/src/"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/src/" 9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/src/"
10 10
11features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "gpiote", "time-driver-rtc1"] 11features = ["nightly", "time", "defmt", "unstable-pac", "unstable-traits", "gpiote", "time-driver-rtc1"]
12flavors = [ 12flavors = [
13 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, 13 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
14 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, 14 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
@@ -91,22 +91,22 @@ _dppi = []
91_gpio-p1 = [] 91_gpio-p1 = []
92 92
93[dependencies] 93[dependencies]
94embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 94embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
95embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 95embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
96embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] } 96embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] }
97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
98embassy-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 }
99 99
100embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 100embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
101embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 101embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
102embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} 102embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
103embedded-io = { version = "0.4.0", features = ["async"], optional = true } 103embedded-io = { version = "0.4.0", features = ["async"], optional = true }
104 104
105defmt = { version = "0.3", optional = true } 105defmt = { version = "0.3", optional = true }
106log = { version = "0.4.14", optional = true } 106log = { version = "0.4.14", optional = true }
107cortex-m-rt = ">=0.6.15,<0.8" 107cortex-m-rt = ">=0.6.15,<0.8"
108cortex-m = "0.7.6" 108cortex-m = "0.7.6"
109futures = { version = "0.3.17", default-features = false } 109futures = { version = "0.3.17", default-features = false }
110critical-section = "1.1" 110critical-section = "1.1"
111rand_core = "0.6.3" 111rand_core = "0.6.3"
112fixed = "1.10.0" 112fixed = "1.10.0"
@@ -114,13 +114,13 @@ embedded-storage = "0.3.0"
114embedded-storage-async = { version = "0.4.0", optional = true } 114embedded-storage-async = { version = "0.4.0", optional = true }
115cfg-if = "1.0.0" 115cfg-if = "1.0.0"
116 116
117nrf52805-pac = { version = "0.12.0", optional = true } 117nrf52805-pac = { version = "0.12.0", optional = true }
118nrf52810-pac = { version = "0.12.0", optional = true } 118nrf52810-pac = { version = "0.12.0", optional = true }
119nrf52811-pac = { version = "0.12.0", optional = true } 119nrf52811-pac = { version = "0.12.0", optional = true }
120nrf52820-pac = { version = "0.12.0", optional = true } 120nrf52820-pac = { version = "0.12.0", optional = true }
121nrf52832-pac = { version = "0.12.0", optional = true } 121nrf52832-pac = { version = "0.12.0", optional = true }
122nrf52833-pac = { version = "0.12.0", optional = true } 122nrf52833-pac = { version = "0.12.0", optional = true }
123nrf52840-pac = { version = "0.12.0", optional = true } 123nrf52840-pac = { version = "0.12.0", optional = true }
124nrf5340-app-pac = { version = "0.12.0", optional = true } 124nrf5340-app-pac = { version = "0.12.0", optional = true }
125nrf5340-net-pac = { version = "0.12.0", optional = true } 125nrf5340-net-pac = { version = "0.12.0", optional = true }
126nrf9160-pac = { version = "0.12.0", optional = true } 126nrf9160-pac = { version = "0.12.0", optional = true }
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 21d0d9564..6550f2abd 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -221,7 +221,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
221 } 221 }
222 222
223 /// Returns the IN event, for use with PPI. 223 /// Returns the IN event, for use with PPI.
224 pub fn event_in(&self) -> Event { 224 pub fn event_in(&self) -> Event<'d> {
225 let g = regs(); 225 let g = regs();
226 Event::from_reg(&g.events_in[self.ch.number()]) 226 Event::from_reg(&g.events_in[self.ch.number()])
227 } 227 }
@@ -292,21 +292,21 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
292 } 292 }
293 293
294 /// Returns the OUT task, for use with PPI. 294 /// Returns the OUT task, for use with PPI.
295 pub fn task_out(&self) -> Task { 295 pub fn task_out(&self) -> Task<'d> {
296 let g = regs(); 296 let g = regs();
297 Task::from_reg(&g.tasks_out[self.ch.number()]) 297 Task::from_reg(&g.tasks_out[self.ch.number()])
298 } 298 }
299 299
300 /// Returns the CLR task, for use with PPI. 300 /// Returns the CLR task, for use with PPI.
301 #[cfg(not(feature = "nrf51"))] 301 #[cfg(not(feature = "nrf51"))]
302 pub fn task_clr(&self) -> Task { 302 pub fn task_clr(&self) -> Task<'d> {
303 let g = regs(); 303 let g = regs();
304 Task::from_reg(&g.tasks_clr[self.ch.number()]) 304 Task::from_reg(&g.tasks_clr[self.ch.number()])
305 } 305 }
306 306
307 /// Returns the SET task, for use with PPI. 307 /// Returns the SET task, for use with PPI.
308 #[cfg(not(feature = "nrf51"))] 308 #[cfg(not(feature = "nrf51"))]
309 pub fn task_set(&self) -> Task { 309 pub fn task_set(&self) -> Task<'d> {
310 let g = regs(); 310 let g = regs();
311 Task::from_reg(&g.tasks_set[self.ch.number()]) 311 Task::from_reg(&g.tasks_set[self.ch.number()])
312 } 312 }
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 0e30f7002..217884d1c 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,294 +1,500 @@
1//! Pulse Density Modulation (PDM) mirophone driver. 1//! Pulse Density Modulation (PDM) mirophone driver.
2 2
3#![macro_use] 3#![macro_use]
4 4
5use core::marker::PhantomData; 5use 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_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
11use futures::future::poll_fn; 11use fixed::types::I7F1;
12 12use futures::future::poll_fn;
13use crate::chip::EASY_DMA_SIZE; 13
14use crate::gpio::sealed::Pin; 14use crate::chip::EASY_DMA_SIZE;
15use crate::gpio::{AnyPin, Pin as GpioPin}; 15use crate::gpio::sealed::Pin;
16use crate::interrupt::typelevel::Interrupt; 16use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::{interrupt, Peripheral}; 17use crate::interrupt::typelevel::Interrupt;
18 18use crate::pac::pdm::mode::{EDGE_A, OPERATION_A};
19/// Interrupt handler. 19pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
20pub struct InterruptHandler<T: Instance> { 20#[cfg(any(
21 _phantom: PhantomData<T>, 21 feature = "nrf52840",
22} 22 feature = "nrf52833",
23 23 feature = "_nrf5340-app",
24impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 24 feature = "_nrf9160",
25 unsafe fn on_interrupt() { 25))]
26 T::regs().intenclr.write(|w| w.end().clear()); 26pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
27 T::state().waker.wake(); 27use crate::{interrupt, Peripheral};
28 } 28
29} 29/// Interrupt handler.
30 30pub struct InterruptHandler<T: Instance> {
31/// PDM microphone interface 31 _phantom: PhantomData<T>,
32pub struct Pdm<'d, T: Instance> { 32}
33 _peri: PeripheralRef<'d, T>, 33
34} 34impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
35 35 unsafe fn on_interrupt() {
36/// PDM error. 36 let r = T::regs();
37#[derive(Debug, Clone, Copy, PartialEq, Eq)] 37
38#[cfg_attr(feature = "defmt", derive(defmt::Format))] 38 if r.events_end.read().bits() != 0 {
39#[non_exhaustive] 39 r.intenclr.write(|w| w.end().clear());
40pub enum Error { 40 }
41 /// Buffer is too long. 41
42 BufferTooLong, 42 if r.events_started.read().bits() != 0 {
43 /// Buffer is empty 43 r.intenclr.write(|w| w.started().clear());
44 BufferZeroLength, 44 }
45 /// PDM is not running 45
46 NotRunning, 46 if r.events_stopped.read().bits() != 0 {
47} 47 r.intenclr.write(|w| w.stopped().clear());
48 48 }
49static DUMMY_BUFFER: [i16; 1] = [0; 1]; 49
50 50 T::state().waker.wake();
51impl<'d, T: Instance> Pdm<'d, T> { 51 }
52 /// Create PDM driver 52}
53 pub fn new( 53
54 pdm: impl Peripheral<P = T> + 'd, 54/// PDM microphone interface
55 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 55pub struct Pdm<'d, T: Instance> {
56 clk: impl Peripheral<P = impl GpioPin> + 'd, 56 _peri: PeripheralRef<'d, T>,
57 din: impl Peripheral<P = impl GpioPin> + 'd, 57}
58 config: Config, 58
59 ) -> Self { 59/// PDM error.
60 into_ref!(pdm, clk, din); 60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61 Self::new_inner(pdm, clk.map_into(), din.map_into(), config) 61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62 } 62#[non_exhaustive]
63 63pub enum Error {
64 fn new_inner( 64 /// Buffer is too long.
65 pdm: PeripheralRef<'d, T>, 65 BufferTooLong,
66 clk: PeripheralRef<'d, AnyPin>, 66 /// Buffer is empty
67 din: PeripheralRef<'d, AnyPin>, 67 BufferZeroLength,
68 config: Config, 68 /// PDM is not running
69 ) -> Self { 69 NotRunning,
70 into_ref!(pdm); 70 /// PDM is already running
71 71 AlreadyRunning,
72 let r = T::regs(); 72}
73 73
74 // setup gpio pins 74static DUMMY_BUFFER: [i16; 1] = [0; 1];
75 din.conf().write(|w| w.input().set_bit()); 75
76 r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); 76/// The state of a continuously running sampler. While it reflects
77 clk.set_low(); 77/// the progress of a sampler, it also signals what should be done
78 clk.conf().write(|w| w.dir().output()); 78/// next. For example, if the sampler has stopped then the Pdm implementation
79 r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); 79/// can then tear down its infrastructure.
80 80#[derive(PartialEq)]
81 // configure 81pub enum SamplerState {
82 // use default for 82 /// The sampler processed the samples and is ready for more.
83 // - gain right 83 Sampled,
84 // - gain left 84 /// The sampler is done processing samples.
85 // - clk 85 Stopped,
86 // - ratio 86}
87 r.mode.write(|w| { 87
88 w.edge().bit(config.edge == Edge::LeftRising); 88impl<'d, T: Instance> Pdm<'d, T> {
89 w.operation().bit(config.operation_mode == OperationMode::Mono); 89 /// Create PDM driver
90 w 90 pub fn new(
91 }); 91 pdm: impl Peripheral<P = T> + 'd,
92 r.gainl.write(|w| w.gainl().default_gain()); 92 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
93 r.gainr.write(|w| w.gainr().default_gain()); 93 clk: impl Peripheral<P = impl GpioPin> + 'd,
94 94 din: impl Peripheral<P = impl GpioPin> + 'd,
95 // IRQ 95 config: Config,
96 T::Interrupt::unpend(); 96 ) -> Self {
97 unsafe { T::Interrupt::enable() }; 97 into_ref!(pdm, clk, din);
98 98 Self::new_inner(pdm, clk.map_into(), din.map_into(), config)
99 r.enable.write(|w| w.enable().set_bit()); 99 }
100 100
101 Self { _peri: pdm } 101 fn new_inner(
102 } 102 pdm: PeripheralRef<'d, T>,
103 103 clk: PeripheralRef<'d, AnyPin>,
104 /// Start sampling microphon data into a dummy buffer 104 din: PeripheralRef<'d, AnyPin>,
105 /// Usefull to start the microphon and keep it active between recording samples 105 config: Config,
106 pub async fn start(&mut self) { 106 ) -> Self {
107 let r = T::regs(); 107 into_ref!(pdm);
108 108
109 // start dummy sampling because microphon needs some setup time 109 let r = T::regs();
110 r.sample 110
111 .ptr 111 // setup gpio pins
112 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); 112 din.conf().write(|w| w.input().set_bit());
113 r.sample 113 r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) });
114 .maxcnt 114 clk.set_low();
115 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); 115 clk.conf().write(|w| w.dir().output());
116 116 r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) });
117 r.tasks_start.write(|w| unsafe { w.bits(1) }); 117
118 } 118 // configure
119 119 r.pdmclkctrl.write(|w| w.freq().variant(config.frequency));
120 /// Stop sampling microphon data inta a dummy buffer 120 #[cfg(any(
121 pub async fn stop(&mut self) { 121 feature = "nrf52840",
122 let r = T::regs(); 122 feature = "nrf52833",
123 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 123 feature = "_nrf5340-app",
124 r.events_started.reset(); 124 feature = "_nrf9160",
125 } 125 ))]
126 126 r.ratio.write(|w| w.ratio().variant(config.ratio));
127 /// Sample data into the given buffer. 127 r.mode.write(|w| {
128 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { 128 w.operation().variant(config.operation_mode.into());
129 if buffer.len() == 0 { 129 w.edge().variant(config.edge.into());
130 return Err(Error::BufferZeroLength); 130 w
131 } 131 });
132 if buffer.len() > EASY_DMA_SIZE { 132
133 return Err(Error::BufferTooLong); 133 Self::_set_gain(r, config.gain_left, config.gain_right);
134 } 134
135 135 // Disable all events interrupts
136 let r = T::regs(); 136 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
137 137
138 if r.events_started.read().bits() == 0 { 138 // IRQ
139 return Err(Error::NotRunning); 139 T::Interrupt::unpend();
140 } 140 unsafe { T::Interrupt::enable() };
141 141
142 let drop = OnDrop::new(move || { 142 r.enable.write(|w| w.enable().set_bit());
143 r.intenclr.write(|w| w.end().clear()); 143
144 r.events_stopped.reset(); 144 Self { _peri: pdm }
145 145 }
146 // reset to dummy buffer 146
147 r.sample 147 fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) {
148 .ptr 148 let gain_left = gain_left
149 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); 149 .saturating_add(I7F1::from_bits(40))
150 r.sample 150 .saturating_to_num::<u8>()
151 .maxcnt 151 .clamp(0, 0x50);
152 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); 152 let gain_right = gain_right
153 153 .saturating_add(I7F1::from_bits(40))
154 while r.events_stopped.read().bits() == 0 {} 154 .saturating_to_num::<u8>()
155 }); 155 .clamp(0, 0x50);
156 156
157 // setup user buffer 157 r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) });
158 let ptr = buffer.as_ptr(); 158 r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) });
159 let len = buffer.len(); 159 }
160 r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); 160
161 r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); 161 /// Adjust the gain of the PDM microphone on the fly
162 162 pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) {
163 // wait till the current sample is finished and the user buffer sample is started 163 Self::_set_gain(T::regs(), gain_left, gain_right)
164 Self::wait_for_sample().await; 164 }
165 165
166 // reset the buffer back to the dummy buffer 166 /// Start sampling microphon data into a dummy buffer
167 r.sample 167 /// Usefull to start the microphon and keep it active between recording samples
168 .ptr 168 pub async fn start(&mut self) {
169 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); 169 let r = T::regs();
170 r.sample 170
171 .maxcnt 171 // start dummy sampling because microphon needs some setup time
172 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); 172 r.sample
173 173 .ptr
174 // wait till the user buffer is sampled 174 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
175 Self::wait_for_sample().await; 175 r.sample
176 176 .maxcnt
177 drop.defuse(); 177 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
178 178
179 Ok(()) 179 r.tasks_start.write(|w| unsafe { w.bits(1) });
180 } 180 }
181 181
182 async fn wait_for_sample() { 182 /// Stop sampling microphon data inta a dummy buffer
183 let r = T::regs(); 183 pub async fn stop(&mut self) {
184 184 let r = T::regs();
185 r.events_end.reset(); 185 r.tasks_stop.write(|w| unsafe { w.bits(1) });
186 r.intenset.write(|w| w.end().set()); 186 r.events_started.reset();
187 187 }
188 compiler_fence(Ordering::SeqCst); 188
189 189 /// Sample data into the given buffer.
190 poll_fn(|cx| { 190 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
191 T::state().waker.register(cx.waker()); 191 if buffer.len() == 0 {
192 if r.events_end.read().bits() != 0 { 192 return Err(Error::BufferZeroLength);
193 return Poll::Ready(()); 193 }
194 } 194 if buffer.len() > EASY_DMA_SIZE {
195 Poll::Pending 195 return Err(Error::BufferTooLong);
196 }) 196 }
197 .await; 197
198 198 let r = T::regs();
199 compiler_fence(Ordering::SeqCst); 199
200 } 200 if r.events_started.read().bits() == 0 {
201} 201 return Err(Error::NotRunning);
202 202 }
203/// PDM microphone driver Config 203
204pub struct Config { 204 let drop = OnDrop::new(move || {
205 /// Use stero or mono operation 205 r.intenclr.write(|w| w.end().clear());
206 pub operation_mode: OperationMode, 206 r.events_stopped.reset();
207 /// On which edge the left channel should be samples 207
208 pub edge: Edge, 208 // reset to dummy buffer
209} 209 r.sample
210 210 .ptr
211impl Default for Config { 211 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
212 fn default() -> Self { 212 r.sample
213 Self { 213 .maxcnt
214 operation_mode: OperationMode::Mono, 214 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
215 edge: Edge::LeftFalling, 215
216 } 216 while r.events_stopped.read().bits() == 0 {}
217 } 217 });
218} 218
219 219 // setup user buffer
220/// PDM operation mode. 220 let ptr = buffer.as_ptr();
221#[derive(PartialEq)] 221 let len = buffer.len();
222pub enum OperationMode { 222 r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) });
223 /// Mono (1 channel) 223 r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) });
224 Mono, 224
225 /// Stereo (2 channels) 225 // wait till the current sample is finished and the user buffer sample is started
226 Stereo, 226 Self::wait_for_sample().await;
227} 227
228 228 // reset the buffer back to the dummy buffer
229/// PDM edge polarity 229 r.sample
230#[derive(PartialEq)] 230 .ptr
231pub enum Edge { 231 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
232 /// Left edge is rising 232 r.sample
233 LeftRising, 233 .maxcnt
234 /// Left edge is falling 234 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
235 LeftFalling, 235
236} 236 // wait till the user buffer is sampled
237 237 Self::wait_for_sample().await;
238impl<'d, T: Instance> Drop for Pdm<'d, T> { 238
239 fn drop(&mut self) { 239 drop.defuse();
240 let r = T::regs(); 240
241 241 Ok(())
242 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 242 }
243 243
244 r.enable.write(|w| w.enable().disabled()); 244 async fn wait_for_sample() {
245 245 let r = T::regs();
246 r.psel.din.reset(); 246
247 r.psel.clk.reset(); 247 r.events_end.reset();
248 } 248 r.intenset.write(|w| w.end().set());
249} 249
250 250 compiler_fence(Ordering::SeqCst);
251pub(crate) mod sealed { 251
252 use embassy_sync::waitqueue::AtomicWaker; 252 poll_fn(|cx| {
253 253 T::state().waker.register(cx.waker());
254 /// Peripheral static state 254 if r.events_end.read().bits() != 0 {
255 pub struct State { 255 return Poll::Ready(());
256 pub waker: AtomicWaker, 256 }
257 } 257 Poll::Pending
258 258 })
259 impl State { 259 .await;
260 pub const fn new() -> Self { 260
261 Self { 261 compiler_fence(Ordering::SeqCst);
262 waker: AtomicWaker::new(), 262 }
263 } 263
264 } 264 /// Continuous sampling with double buffers.
265 } 265 ///
266 266 /// A sampler closure is provided that receives the buffer of samples, noting
267 pub trait Instance { 267 /// that the size of this buffer can be less than the original buffer's size.
268 fn regs() -> &'static crate::pac::pdm::RegisterBlock; 268 /// A command is return from the closure that indicates whether the sampling
269 fn state() -> &'static State; 269 /// should continue or stop.
270 } 270 ///
271} 271 /// NOTE: The time spent within the callback supplied should not exceed the time
272 272 /// taken to acquire the samples into a single buffer. You should measure the
273/// PDM peripheral instance. 273 /// time taken by the callback and set the sample buffer size accordingly.
274pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 274 /// Exceeding this time can lead to samples becoming dropped.
275 /// Interrupt for this peripheral. 275 pub async fn run_task_sampler<S, const N: usize>(
276 type Interrupt: interrupt::typelevel::Interrupt; 276 &mut self,
277} 277 bufs: &mut [[i16; N]; 2],
278 278 mut sampler: S,
279macro_rules! impl_pdm { 279 ) -> Result<(), Error>
280 ($type:ident, $pac_type:ident, $irq:ident) => { 280 where
281 impl crate::pdm::sealed::Instance for peripherals::$type { 281 S: FnMut(&[i16; N]) -> SamplerState,
282 fn regs() -> &'static crate::pac::pdm::RegisterBlock { 282 {
283 unsafe { &*pac::$pac_type::ptr() } 283 let r = T::regs();
284 } 284
285 fn state() -> &'static crate::pdm::sealed::State { 285 if r.events_started.read().bits() != 0 {
286 static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); 286 return Err(Error::AlreadyRunning);
287 &STATE 287 }
288 } 288
289 } 289 r.sample
290 impl crate::pdm::Instance for peripherals::$type { 290 .ptr
291 type Interrupt = crate::interrupt::typelevel::$irq; 291 .write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) });
292 } 292 r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) });
293 }; 293
294} 294 // Reset and enable the events
295 r.events_end.reset();
296 r.events_started.reset();
297 r.events_stopped.reset();
298 r.intenset.write(|w| {
299 w.end().set();
300 w.started().set();
301 w.stopped().set();
302 w
303 });
304
305 // Don't reorder the start event before the previous writes. Hopefully self
306 // wouldn't happen anyway.
307 compiler_fence(Ordering::SeqCst);
308
309 r.tasks_start.write(|w| unsafe { w.bits(1) });
310
311 let mut current_buffer = 0;
312
313 let mut done = false;
314
315 let drop = OnDrop::new(|| {
316 r.tasks_stop.write(|w| unsafe { w.bits(1) });
317 // N.B. It would be better if this were async, but Drop only support sync code.
318 while r.events_stopped.read().bits() != 0 {}
319 });
320
321 // Wait for events and complete when the sampler indicates it has had enough.
322 poll_fn(|cx| {
323 let r = T::regs();
324
325 T::state().waker.register(cx.waker());
326
327 if r.events_end.read().bits() != 0 {
328 compiler_fence(Ordering::SeqCst);
329
330 r.events_end.reset();
331 r.intenset.write(|w| w.end().set());
332
333 if !done {
334 // Discard the last buffer after the user requested a stop.
335 if sampler(&bufs[current_buffer]) == SamplerState::Sampled {
336 let next_buffer = 1 - current_buffer;
337 current_buffer = next_buffer;
338 } else {
339 r.tasks_stop.write(|w| unsafe { w.bits(1) });
340 done = true;
341 };
342 };
343 }
344
345 if r.events_started.read().bits() != 0 {
346 r.events_started.reset();
347 r.intenset.write(|w| w.started().set());
348
349 let next_buffer = 1 - current_buffer;
350 r.sample
351 .ptr
352 .write(|w| unsafe { w.sampleptr().bits(bufs[next_buffer].as_mut_ptr() as u32) });
353 }
354
355 if r.events_stopped.read().bits() != 0 {
356 return Poll::Ready(());
357 }
358
359 Poll::Pending
360 })
361 .await;
362 drop.defuse();
363 Ok(())
364 }
365}
366
367/// PDM microphone driver Config
368pub struct Config {
369 /// Use stero or mono operation
370 pub operation_mode: OperationMode,
371 /// On which edge the left channel should be samples
372 pub edge: Edge,
373 /// Clock frequency
374 pub frequency: Frequency,
375 /// Clock ratio
376 #[cfg(any(
377 feature = "nrf52840",
378 feature = "nrf52833",
379 feature = "_nrf5340-app",
380 feature = "_nrf9160",
381 ))]
382 pub ratio: Ratio,
383 /// Gain left in dB
384 pub gain_left: I7F1,
385 /// Gain right in dB
386 pub gain_right: I7F1,
387}
388
389impl Default for Config {
390 fn default() -> Self {
391 Self {
392 operation_mode: OperationMode::Mono,
393 edge: Edge::LeftFalling,
394 frequency: Frequency::DEFAULT,
395 #[cfg(any(
396 feature = "nrf52840",
397 feature = "nrf52833",
398 feature = "_nrf5340-app",
399 feature = "_nrf9160",
400 ))]
401 ratio: Ratio::RATIO80,
402 gain_left: I7F1::ZERO,
403 gain_right: I7F1::ZERO,
404 }
405 }
406}
407
408/// PDM operation mode.
409#[derive(PartialEq)]
410pub enum OperationMode {
411 /// Mono (1 channel)
412 Mono,
413 /// Stereo (2 channels)
414 Stereo,
415}
416
417impl From<OperationMode> for OPERATION_A {
418 fn from(mode: OperationMode) -> Self {
419 match mode {
420 OperationMode::Mono => OPERATION_A::MONO,
421 OperationMode::Stereo => OPERATION_A::STEREO,
422 }
423 }
424}
425
426/// PDM edge polarity
427#[derive(PartialEq)]
428pub enum Edge {
429 /// Left edge is rising
430 LeftRising,
431 /// Left edge is falling
432 LeftFalling,
433}
434
435impl From<Edge> for EDGE_A {
436 fn from(edge: Edge) -> Self {
437 match edge {
438 Edge::LeftRising => EDGE_A::LEFT_RISING,
439 Edge::LeftFalling => EDGE_A::LEFT_FALLING,
440 }
441 }
442}
443
444impl<'d, T: Instance> Drop for Pdm<'d, T> {
445 fn drop(&mut self) {
446 let r = T::regs();
447
448 r.tasks_stop.write(|w| unsafe { w.bits(1) });
449
450 r.enable.write(|w| w.enable().disabled());
451
452 r.psel.din.reset();
453 r.psel.clk.reset();
454 }
455}
456
457pub(crate) mod sealed {
458 use embassy_sync::waitqueue::AtomicWaker;
459
460 /// Peripheral static state
461 pub struct State {
462 pub waker: AtomicWaker,
463 }
464
465 impl State {
466 pub const fn new() -> Self {
467 Self {
468 waker: AtomicWaker::new(),
469 }
470 }
471 }
472
473 pub trait Instance {
474 fn regs() -> &'static crate::pac::pdm::RegisterBlock;
475 fn state() -> &'static State;
476 }
477}
478
479/// PDM peripheral instance.
480pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
481 /// Interrupt for this peripheral.
482 type Interrupt: interrupt::typelevel::Interrupt;
483}
484
485macro_rules! impl_pdm {
486 ($type:ident, $pac_type:ident, $irq:ident) => {
487 impl crate::pdm::sealed::Instance for peripherals::$type {
488 fn regs() -> &'static crate::pac::pdm::RegisterBlock {
489 unsafe { &*pac::$pac_type::ptr() }
490 }
491 fn state() -> &'static crate::pdm::sealed::State {
492 static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new();
493 &STATE
494 }
495 }
496 impl crate::pdm::Instance for peripherals::$type {
497 type Interrupt = crate::interrupt::typelevel::$irq;
498 }
499 };
500}
diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs
index 3a1e7f170..40ccb2f09 100644
--- a/embassy-nrf/src/ppi/dppi.rs
+++ b/embassy-nrf/src/ppi/dppi.rs
@@ -12,14 +12,14 @@ pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
12 12
13impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { 13impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
14 /// Configure PPI channel to trigger `task` on `event`. 14 /// Configure PPI channel to trigger `task` on `event`.
15 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self { 15 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self {
16 Ppi::new_many_to_many(ch, [event], [task]) 16 Ppi::new_many_to_many(ch, [event], [task])
17 } 17 }
18} 18}
19 19
20impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { 20impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
21 /// Configure PPI channel to trigger both `task1` and `task2` on `event`. 21 /// Configure PPI channel to trigger both `task1` and `task2` on `event`.
22 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { 22 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self {
23 Ppi::new_many_to_many(ch, [event], [task1, task2]) 23 Ppi::new_many_to_many(ch, [event], [task1, task2])
24 } 24 }
25} 25}
@@ -30,8 +30,8 @@ impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usi
30 /// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires. 30 /// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires.
31 pub fn new_many_to_many( 31 pub fn new_many_to_many(
32 ch: impl Peripheral<P = C> + 'd, 32 ch: impl Peripheral<P = C> + 'd,
33 events: [Event; EVENT_COUNT], 33 events: [Event<'d>; EVENT_COUNT],
34 tasks: [Task; TASK_COUNT], 34 tasks: [Task<'d>; TASK_COUNT],
35 ) -> Self { 35 ) -> Self {
36 into_ref!(ch); 36 into_ref!(ch);
37 37
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 76757a248..ff6593bd5 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -15,6 +15,7 @@
15//! many tasks and events, but any single task or event can only be coupled with one channel. 15//! many tasks and events, but any single task or event can only be coupled with one channel.
16//! 16//!
17 17
18use core::marker::PhantomData;
18use core::ptr::NonNull; 19use core::ptr::NonNull;
19 20
20use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 21use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
@@ -30,9 +31,9 @@ pub(crate) use _version::*;
30pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { 31pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
31 ch: PeripheralRef<'d, C>, 32 ch: PeripheralRef<'d, C>,
32 #[cfg(feature = "_dppi")] 33 #[cfg(feature = "_dppi")]
33 events: [Event; EVENT_COUNT], 34 events: [Event<'d>; EVENT_COUNT],
34 #[cfg(feature = "_dppi")] 35 #[cfg(feature = "_dppi")]
35 tasks: [Task; TASK_COUNT], 36 tasks: [Task<'d>; TASK_COUNT],
36} 37}
37 38
38/// PPI channel group driver. 39/// PPI channel group driver.
@@ -95,7 +96,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
95 /// Get a reference to the "enable all" task. 96 /// Get a reference to the "enable all" task.
96 /// 97 ///
97 /// When triggered, it will enable all the channels in this group. 98 /// When triggered, it will enable all the channels in this group.
98 pub fn task_enable_all(&self) -> Task { 99 pub fn task_enable_all(&self) -> Task<'d> {
99 let n = self.g.number(); 100 let n = self.g.number();
100 Task::from_reg(&regs().tasks_chg[n].en) 101 Task::from_reg(&regs().tasks_chg[n].en)
101 } 102 }
@@ -103,7 +104,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
103 /// Get a reference to the "disable all" task. 104 /// Get a reference to the "disable all" task.
104 /// 105 ///
105 /// When triggered, it will disable all the channels in this group. 106 /// When triggered, it will disable all the channels in this group.
106 pub fn task_disable_all(&self) -> Task { 107 pub fn task_disable_all(&self) -> Task<'d> {
107 let n = self.g.number(); 108 let n = self.g.number();
108 Task::from_reg(&regs().tasks_chg[n].dis) 109 Task::from_reg(&regs().tasks_chg[n].dis)
109 } 110 }
@@ -125,16 +126,16 @@ const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
125/// When a task is subscribed to a PPI channel, it will run when the channel is triggered by 126/// When a task is subscribed to a PPI channel, it will run when the channel is triggered by
126/// a published event. 127/// a published event.
127#[derive(PartialEq, Eq, Clone, Copy)] 128#[derive(PartialEq, Eq, Clone, Copy)]
128pub struct Task(NonNull<u32>); 129pub struct Task<'d>(NonNull<u32>, PhantomData<&'d ()>);
129 130
130impl Task { 131impl<'d> Task<'d> {
131 /// Create a new `Task` from a task register pointer 132 /// Create a new `Task` from a task register pointer
132 /// 133 ///
133 /// # Safety 134 /// # Safety
134 /// 135 ///
135 /// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral. 136 /// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral.
136 pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { 137 pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
137 Self(ptr) 138 Self(ptr, PhantomData)
138 } 139 }
139 140
140 /// Triggers this task. 141 /// Triggers this task.
@@ -143,7 +144,10 @@ impl Task {
143 } 144 }
144 145
145 pub(crate) fn from_reg<T>(reg: &T) -> Self { 146 pub(crate) fn from_reg<T>(reg: &T) -> Self {
146 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 147 Self(
148 unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
149 PhantomData,
150 )
147 } 151 }
148 152
149 /// Address of subscription register for this task. 153 /// Address of subscription register for this task.
@@ -156,26 +160,29 @@ impl Task {
156/// # Safety 160/// # Safety
157/// 161///
158/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. 162/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
159unsafe impl Send for Task {} 163unsafe impl Send for Task<'_> {}
160 164
161/// Represents an event that a peripheral can publish. 165/// Represents an event that a peripheral can publish.
162/// 166///
163/// An event can be set to publish on a PPI channel when the event happens. 167/// An event can be set to publish on a PPI channel when the event happens.
164#[derive(PartialEq, Eq, Clone, Copy)] 168#[derive(PartialEq, Eq, Clone, Copy)]
165pub struct Event(NonNull<u32>); 169pub struct Event<'d>(NonNull<u32>, PhantomData<&'d ()>);
166 170
167impl Event { 171impl<'d> Event<'d> {
168 /// Create a new `Event` from an event register pointer 172 /// Create a new `Event` from an event register pointer
169 /// 173 ///
170 /// # Safety 174 /// # Safety
171 /// 175 ///
172 /// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral. 176 /// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral.
173 pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { 177 pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
174 Self(ptr) 178 Self(ptr, PhantomData)
175 } 179 }
176 180
177 pub(crate) fn from_reg<T>(reg: &T) -> Self { 181 pub(crate) fn from_reg<T>(reg: &'d T) -> Self {
178 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 182 Self(
183 unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
184 PhantomData,
185 )
179 } 186 }
180 187
181 /// Describes whether this Event is currently in a triggered state. 188 /// Describes whether this Event is currently in a triggered state.
@@ -198,7 +205,7 @@ impl Event {
198/// # Safety 205/// # Safety
199/// 206///
200/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. 207/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
201unsafe impl Send for Event {} 208unsafe impl Send for Event<'_> {}
202 209
203// ====================== 210// ======================
204// traits 211// traits
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index f1eeaee1e..1fe898625 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -3,12 +3,12 @@ use embassy_hal_common::into_ref;
3use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; 3use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task};
4use crate::{pac, Peripheral}; 4use crate::{pac, Peripheral};
5 5
6impl Task { 6impl<'d> Task<'d> {
7 fn reg_val(&self) -> u32 { 7 fn reg_val(&self) -> u32 {
8 self.0.as_ptr() as _ 8 self.0.as_ptr() as _
9 } 9 }
10} 10}
11impl Event { 11impl<'d> Event<'d> {
12 fn reg_val(&self) -> u32 { 12 fn reg_val(&self) -> u32 {
13 self.0.as_ptr() as _ 13 self.0.as_ptr() as _
14 } 14 }
@@ -34,7 +34,7 @@ impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
34 34
35impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { 35impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
36 /// Configure PPI channel to trigger `task` on `event`. 36 /// Configure PPI channel to trigger `task` on `event`.
37 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self { 37 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self {
38 into_ref!(ch); 38 into_ref!(ch);
39 39
40 let r = regs(); 40 let r = regs();
@@ -49,7 +49,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
49#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task 49#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
50impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { 50impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
51 /// Configure PPI channel to trigger both `task1` and `task2` on `event`. 51 /// Configure PPI channel to trigger both `task1` and `task2` on `event`.
52 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { 52 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self {
53 into_ref!(ch); 53 into_ref!(ch);
54 54
55 let r = regs(); 55 let r = regs();
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 363a255d5..c8c81fa01 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -181,7 +181,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
181 181
182 /// Returns reference to `Stopped` event endpoint for PPI. 182 /// Returns reference to `Stopped` event endpoint for PPI.
183 #[inline(always)] 183 #[inline(always)]
184 pub fn event_stopped(&self) -> Event { 184 pub fn event_stopped(&self) -> Event<'d> {
185 let r = T::regs(); 185 let r = T::regs();
186 186
187 Event::from_reg(&r.events_stopped) 187 Event::from_reg(&r.events_stopped)
@@ -189,7 +189,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
189 189
190 /// Returns reference to `LoopsDone` event endpoint for PPI. 190 /// Returns reference to `LoopsDone` event endpoint for PPI.
191 #[inline(always)] 191 #[inline(always)]
192 pub fn event_loops_done(&self) -> Event { 192 pub fn event_loops_done(&self) -> Event<'d> {
193 let r = T::regs(); 193 let r = T::regs();
194 194
195 Event::from_reg(&r.events_loopsdone) 195 Event::from_reg(&r.events_loopsdone)
@@ -197,7 +197,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
197 197
198 /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. 198 /// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
199 #[inline(always)] 199 #[inline(always)]
200 pub fn event_pwm_period_end(&self) -> Event { 200 pub fn event_pwm_period_end(&self) -> Event<'d> {
201 let r = T::regs(); 201 let r = T::regs();
202 202
203 Event::from_reg(&r.events_pwmperiodend) 203 Event::from_reg(&r.events_pwmperiodend)
@@ -205,7 +205,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
205 205
206 /// Returns reference to `Seq0 End` event endpoint for PPI. 206 /// Returns reference to `Seq0 End` event endpoint for PPI.
207 #[inline(always)] 207 #[inline(always)]
208 pub fn event_seq_end(&self) -> Event { 208 pub fn event_seq_end(&self) -> Event<'d> {
209 let r = T::regs(); 209 let r = T::regs();
210 210
211 Event::from_reg(&r.events_seqend[0]) 211 Event::from_reg(&r.events_seqend[0])
@@ -213,7 +213,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
213 213
214 /// Returns reference to `Seq1 End` event endpoint for PPI. 214 /// Returns reference to `Seq1 End` event endpoint for PPI.
215 #[inline(always)] 215 #[inline(always)]
216 pub fn event_seq1_end(&self) -> Event { 216 pub fn event_seq1_end(&self) -> Event<'d> {
217 let r = T::regs(); 217 let r = T::regs();
218 218
219 Event::from_reg(&r.events_seqend[1]) 219 Event::from_reg(&r.events_seqend[1])
@@ -221,7 +221,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
221 221
222 /// Returns reference to `Seq0 Started` event endpoint for PPI. 222 /// Returns reference to `Seq0 Started` event endpoint for PPI.
223 #[inline(always)] 223 #[inline(always)]
224 pub fn event_seq0_started(&self) -> Event { 224 pub fn event_seq0_started(&self) -> Event<'d> {
225 let r = T::regs(); 225 let r = T::regs();
226 226
227 Event::from_reg(&r.events_seqstarted[0]) 227 Event::from_reg(&r.events_seqstarted[0])
@@ -229,7 +229,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
229 229
230 /// Returns reference to `Seq1 Started` event endpoint for PPI. 230 /// Returns reference to `Seq1 Started` event endpoint for PPI.
231 #[inline(always)] 231 #[inline(always)]
232 pub fn event_seq1_started(&self) -> Event { 232 pub fn event_seq1_started(&self) -> Event<'d> {
233 let r = T::regs(); 233 let r = T::regs();
234 234
235 Event::from_reg(&r.events_seqstarted[1]) 235 Event::from_reg(&r.events_seqstarted[1])
@@ -240,7 +240,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
240 /// 240 ///
241 /// Interacting with the sequence while it runs puts it in an unknown state 241 /// Interacting with the sequence while it runs puts it in an unknown state
242 #[inline(always)] 242 #[inline(always)]
243 pub unsafe fn task_start_seq0(&self) -> Task { 243 pub unsafe fn task_start_seq0(&self) -> Task<'d> {
244 let r = T::regs(); 244 let r = T::regs();
245 245
246 Task::from_reg(&r.tasks_seqstart[0]) 246 Task::from_reg(&r.tasks_seqstart[0])
@@ -251,7 +251,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
251 /// 251 ///
252 /// Interacting with the sequence while it runs puts it in an unknown state 252 /// Interacting with the sequence while it runs puts it in an unknown state
253 #[inline(always)] 253 #[inline(always)]
254 pub unsafe fn task_start_seq1(&self) -> Task { 254 pub unsafe fn task_start_seq1(&self) -> Task<'d> {
255 let r = T::regs(); 255 let r = T::regs();
256 256
257 Task::from_reg(&r.tasks_seqstart[1]) 257 Task::from_reg(&r.tasks_seqstart[1])
@@ -262,7 +262,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
262 /// 262 ///
263 /// Interacting with the sequence while it runs puts it in an unknown state 263 /// Interacting with the sequence while it runs puts it in an unknown state
264 #[inline(always)] 264 #[inline(always)]
265 pub unsafe fn task_next_step(&self) -> Task { 265 pub unsafe fn task_next_step(&self) -> Task<'d> {
266 let r = T::regs(); 266 let r = T::regs();
267 267
268 Task::from_reg(&r.tasks_nextstep) 268 Task::from_reg(&r.tasks_nextstep)
@@ -273,7 +273,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
273 /// 273 ///
274 /// Interacting with the sequence while it runs puts it in an unknown state 274 /// Interacting with the sequence while it runs puts it in an unknown state
275 #[inline(always)] 275 #[inline(always)]
276 pub unsafe fn task_stop(&self) -> Task { 276 pub unsafe fn task_stop(&self) -> Task<'d> {
277 let r = T::regs(); 277 let r = T::regs();
278 278
279 Task::from_reg(&r.tasks_stop) 279 Task::from_reg(&r.tasks_stop)
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index cf3fb9993..23292924c 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -320,7 +320,9 @@ impl<'d, const N: usize> Saadc<'d, N> {
320 timer.cc(0).write(sample_counter); 320 timer.cc(0).write(sample_counter);
321 timer.cc(0).short_compare_clear(); 321 timer.cc(0).short_compare_clear();
322 322
323 let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer.cc(0).event_compare(), Task::from_reg(&r.tasks_sample)); 323 let timer_cc = timer.cc(0);
324
325 let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample));
324 326
325 timer.start(); 327 timer.start();
326 328
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 66bbd1a8f..b7dc332e9 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -468,25 +468,19 @@ mod eh1 {
468 type Error = Error; 468 type Error = Error;
469 } 469 }
470 470
471 impl<'d, T: Instance> embedded_hal_1::spi::SpiBusFlush for Spim<'d, T> { 471 impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
472 fn flush(&mut self) -> Result<(), Self::Error> { 472 fn flush(&mut self) -> Result<(), Self::Error> {
473 Ok(()) 473 Ok(())
474 } 474 }
475 }
476 475
477 impl<'d, T: Instance> embedded_hal_1::spi::SpiBusRead<u8> for Spim<'d, T> {
478 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { 476 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
479 self.blocking_transfer(words, &[]) 477 self.blocking_transfer(words, &[])
480 } 478 }
481 }
482 479
483 impl<'d, T: Instance> embedded_hal_1::spi::SpiBusWrite<u8> for Spim<'d, T> {
484 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 480 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
485 self.blocking_write(words) 481 self.blocking_write(words)
486 } 482 }
487 }
488 483
489 impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
490 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { 484 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
491 self.blocking_transfer(read, write) 485 self.blocking_transfer(read, write)
492 } 486 }
@@ -502,25 +496,19 @@ mod eha {
502 496
503 use super::*; 497 use super::*;
504 498
505 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spim<'d, T> { 499 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
506 async fn flush(&mut self) -> Result<(), Error> { 500 async fn flush(&mut self) -> Result<(), Error> {
507 Ok(()) 501 Ok(())
508 } 502 }
509 }
510 503
511 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spim<'d, T> {
512 async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> { 504 async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
513 self.read(words).await 505 self.read(words).await
514 } 506 }
515 }
516 507
517 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spim<'d, T> {
518 async fn write(&mut self, data: &[u8]) -> Result<(), Error> { 508 async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
519 self.write(data).await 509 self.write(data).await
520 } 510 }
521 }
522 511
523 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
524 async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { 512 async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
525 self.transfer(rx, tx).await 513 self.transfer(rx, tx).await
526 } 514 }
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index dc3757856..04748238d 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -168,21 +168,21 @@ impl<'d, T: Instance> Timer<'d, T> {
168 /// Returns the START task, for use with PPI. 168 /// Returns the START task, for use with PPI.
169 /// 169 ///
170 /// When triggered, this task starts the timer. 170 /// When triggered, this task starts the timer.
171 pub fn task_start(&self) -> Task { 171 pub fn task_start(&self) -> Task<'d> {
172 Task::from_reg(&T::regs().tasks_start) 172 Task::from_reg(&T::regs().tasks_start)
173 } 173 }
174 174
175 /// Returns the STOP task, for use with PPI. 175 /// Returns the STOP task, for use with PPI.
176 /// 176 ///
177 /// When triggered, this task stops the timer. 177 /// When triggered, this task stops the timer.
178 pub fn task_stop(&self) -> Task { 178 pub fn task_stop(&self) -> Task<'d> {
179 Task::from_reg(&T::regs().tasks_stop) 179 Task::from_reg(&T::regs().tasks_stop)
180 } 180 }
181 181
182 /// Returns the CLEAR task, for use with PPI. 182 /// Returns the CLEAR task, for use with PPI.
183 /// 183 ///
184 /// When triggered, this task resets the timer's counter to 0. 184 /// When triggered, this task resets the timer's counter to 0.
185 pub fn task_clear(&self) -> Task { 185 pub fn task_clear(&self) -> Task<'d> {
186 Task::from_reg(&T::regs().tasks_clear) 186 Task::from_reg(&T::regs().tasks_clear)
187 } 187 }
188 188
@@ -190,7 +190,7 @@ impl<'d, T: Instance> Timer<'d, T> {
190 /// 190 ///
191 /// When triggered, this task increments the timer's counter by 1. 191 /// When triggered, this task increments the timer's counter by 1.
192 /// Only works in counter mode. 192 /// Only works in counter mode.
193 pub fn task_count(&self) -> Task { 193 pub fn task_count(&self) -> Task<'d> {
194 Task::from_reg(&T::regs().tasks_count) 194 Task::from_reg(&T::regs().tasks_count)
195 } 195 }
196 196
@@ -258,14 +258,14 @@ impl<'d, T: Instance> Cc<'d, T> {
258 /// Returns this CC register's CAPTURE task, for use with PPI. 258 /// Returns this CC register's CAPTURE task, for use with PPI.
259 /// 259 ///
260 /// When triggered, this task will capture the current value of the timer's counter in this register. 260 /// When triggered, this task will capture the current value of the timer's counter in this register.
261 pub fn task_capture(&self) -> Task { 261 pub fn task_capture(&self) -> Task<'d> {
262 Task::from_reg(&T::regs().tasks_capture) 262 Task::from_reg(&T::regs().tasks_capture)
263 } 263 }
264 264
265 /// Returns this CC register's COMPARE event, for use with PPI. 265 /// Returns this CC register's COMPARE event, for use with PPI.
266 /// 266 ///
267 /// This event will fire when the timer's counter reaches the value in this CC register. 267 /// This event will fire when the timer's counter reaches the value in this CC register.
268 pub fn event_compare(&self) -> Event { 268 pub fn event_compare(&self) -> Event<'d> {
269 Event::from_reg(&T::regs().events_compare[self.n]) 269 Event::from_reg(&T::regs().events_compare[self.n])
270 } 270 }
271 271
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 66823771a..8f3ed885d 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -56,7 +56,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
56 56
57[dependencies] 57[dependencies]
58embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 58embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
59embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 59embassy-time = { version = "0.1.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
60embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 60embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
61embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] } 61embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] }
62embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 62embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@@ -79,9 +79,9 @@ fixed = "1.23.1"
79rp-pac = { version = "6" } 79rp-pac = { version = "6" }
80 80
81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
83embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} 83embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
84embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} 84embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true}
85 85
86paste = "1.0" 86paste = "1.0"
87pio-proc = {version= "0.2" } 87pio-proc = {version= "0.2" }
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 699a0d61d..95780c068 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -3,22 +3,17 @@ 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_hal_common::{into_ref, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
7use embedded_hal_02::adc::{Channel, OneShot};
8 8
9use crate::gpio::Pin; 9use crate::gpio::sealed::Pin as GpioPin;
10use crate::gpio::{self, AnyPin, Pull};
10use crate::interrupt::typelevel::Binding; 11use crate::interrupt::typelevel::Binding;
11use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
12use crate::peripherals::ADC; 13use crate::peripherals::ADC;
13use crate::{interrupt, pac, peripherals, Peripheral}; 14use crate::{interrupt, pac, peripherals, Peripheral};
14static WAKER: AtomicWaker = AtomicWaker::new();
15 15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)] 16static WAKER: AtomicWaker = AtomicWaker::new();
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18#[non_exhaustive]
19pub enum Error {
20 // No errors for now
21}
22 17
23#[non_exhaustive] 18#[non_exhaustive]
24pub struct Config {} 19pub struct Config {}
@@ -28,11 +23,75 @@ impl Default for Config {
28 Self {} 23 Self {}
29 } 24 }
30} 25}
31pub struct Adc<'d> { 26
32 phantom: PhantomData<&'d ADC>, 27pub struct Pin<'p> {
28 pin: PeripheralRef<'p, AnyPin>,
29}
30
31impl<'p> Pin<'p> {
32 pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
33 into_ref!(pin);
34 pin.pad_ctrl().modify(|w| {
35 // manual says:
36 //
37 // > When using an ADC input shared with a GPIO pin, the pin’s
38 // > digital functions must be disabled by setting IE low and OD
39 // > high in the pin’s pad control register
40 w.set_ie(false);
41 w.set_od(true);
42 w.set_pue(pull == Pull::Up);
43 w.set_pde(pull == Pull::Down);
44 });
45 Self { pin: pin.map_into() }
46 }
47
48 fn channel(&self) -> u8 {
49 // this requires adc pins to be sequential and matching the adc channels,
50 // which is the case for rp2040
51 self.pin._pin() - 26
52 }
53}
54
55impl<'d> Drop for Pin<'d> {
56 fn drop(&mut self) {
57 self.pin.pad_ctrl().modify(|w| {
58 w.set_ie(true);
59 w.set_od(false);
60 w.set_pue(false);
61 w.set_pde(true);
62 });
63 }
64}
65
66#[derive(Debug, Eq, PartialEq, Copy, Clone)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68pub enum Error {
69 ConversionFailed,
70}
71
72pub trait Mode {}
73
74pub struct Async;
75impl Mode for Async {}
76
77pub struct Blocking;
78impl Mode for Blocking {}
79
80pub struct Adc<'d, M: Mode> {
81 phantom: PhantomData<(&'d ADC, M)>,
82}
83
84impl<'d, M: Mode> Drop for Adc<'d, M> {
85 fn drop(&mut self) {
86 let r = Self::regs();
87 // disable ADC. leaving it enabled comes with a ~150µA static
88 // current draw. the temperature sensor has already been disabled
89 // by the temperature-reading methods, so we don't need to touch that.
90 r.cs().write(|w| w.set_en(false));
91 }
33} 92}
34 93
35impl<'d> Adc<'d> { 94impl<'d, M: Mode> Adc<'d, M> {
36 #[inline] 95 #[inline]
37 fn regs() -> pac::adc::Adc { 96 fn regs() -> pac::adc::Adc {
38 pac::ADC 97 pac::ADC
@@ -45,11 +104,7 @@ impl<'d> Adc<'d> {
45 ret 104 ret
46 } 105 }
47 106
48 pub fn new( 107 fn setup() {
49 _inner: impl Peripheral<P = ADC> + 'd,
50 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
51 _config: Config,
52 ) -> Self {
53 let reset = Self::reset(); 108 let reset = Self::reset();
54 crate::reset::reset(reset); 109 crate::reset::reset(reset);
55 crate::reset::unreset_wait(reset); 110 crate::reset::unreset_wait(reset);
@@ -58,6 +113,43 @@ impl<'d> Adc<'d> {
58 r.cs().write(|w| w.set_en(true)); 113 r.cs().write(|w| w.set_en(true));
59 // Wait for ADC ready 114 // Wait for ADC ready
60 while !r.cs().read().ready() {} 115 while !r.cs().read().ready() {}
116 }
117
118 fn sample_blocking(channel: u8) -> Result<u16, Error> {
119 let r = Self::regs();
120 r.cs().modify(|w| {
121 w.set_ainsel(channel);
122 w.set_start_once(true);
123 w.set_err(true);
124 });
125 while !r.cs().read().ready() {}
126 match r.cs().read().err() {
127 true => Err(Error::ConversionFailed),
128 false => Ok(r.result().read().result().into()),
129 }
130 }
131
132 pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> {
133 Self::sample_blocking(pin.channel())
134 }
135
136 pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> {
137 let r = Self::regs();
138 r.cs().modify(|w| w.set_ts_en(true));
139 while !r.cs().read().ready() {}
140 let result = Self::sample_blocking(4);
141 r.cs().modify(|w| w.set_ts_en(false));
142 result
143 }
144}
145
146impl<'d> Adc<'d, Async> {
147 pub fn new(
148 _inner: impl Peripheral<P = ADC> + 'd,
149 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
150 _config: Config,
151 ) -> Self {
152 Self::setup();
61 153
62 // Setup IRQ 154 // Setup IRQ
63 interrupt::ADC_IRQ_FIFO.unpend(); 155 interrupt::ADC_IRQ_FIFO.unpend();
@@ -80,102 +172,77 @@ impl<'d> Adc<'d> {
80 .await; 172 .await;
81 } 173 }
82 174
83 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 175 async fn sample_async(channel: u8) -> Result<u16, Error> {
84 let r = Self::regs(); 176 let r = Self::regs();
85 // disable pull-down and pull-up resistors
86 // pull-down resistors are enabled by default
87 pin.pad_ctrl().modify(|w| {
88 w.set_ie(true);
89 let (pu, pd) = (false, false);
90 w.set_pue(pu);
91 w.set_pde(pd);
92 });
93 r.cs().modify(|w| { 177 r.cs().modify(|w| {
94 w.set_ainsel(PIN::channel()); 178 w.set_ainsel(channel);
95 w.set_start_once(true) 179 w.set_start_once(true);
180 w.set_err(true);
96 }); 181 });
97 Self::wait_for_ready().await; 182 Self::wait_for_ready().await;
98 r.result().read().result().into() 183 match r.cs().read().err() {
184 true => Err(Error::ConversionFailed),
185 false => Ok(r.result().read().result().into()),
186 }
187 }
188
189 pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> {
190 Self::sample_async(pin.channel()).await
99 } 191 }
100 192
101 pub async fn read_temperature(&mut self) -> u16 { 193 pub async fn read_temperature(&mut self) -> Result<u16, Error> {
102 let r = Self::regs(); 194 let r = Self::regs();
103 r.cs().modify(|w| w.set_ts_en(true)); 195 r.cs().modify(|w| w.set_ts_en(true));
104 if !r.cs().read().ready() { 196 if !r.cs().read().ready() {
105 Self::wait_for_ready().await; 197 Self::wait_for_ready().await;
106 } 198 }
107 r.cs().modify(|w| { 199 let result = Self::sample_async(4).await;
108 w.set_ainsel(4); 200 r.cs().modify(|w| w.set_ts_en(false));
109 w.set_start_once(true) 201 result
110 });
111 Self::wait_for_ready().await;
112 r.result().read().result().into()
113 } 202 }
203}
114 204
115 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 205impl<'d> Adc<'d, Blocking> {
116 let r = Self::regs(); 206 pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self {
117 pin.pad_ctrl().modify(|w| { 207 Self::setup();
118 w.set_ie(true);
119 let (pu, pd) = (false, false);
120 w.set_pue(pu);
121 w.set_pde(pd);
122 });
123 r.cs().modify(|w| {
124 w.set_ainsel(PIN::channel());
125 w.set_start_once(true)
126 });
127 while !r.cs().read().ready() {}
128 r.result().read().result().into()
129 }
130 208
131 pub fn blocking_read_temperature(&mut self) -> u16 { 209 Self { phantom: PhantomData }
132 let r = Self::regs();
133 r.cs().modify(|w| w.set_ts_en(true));
134 while !r.cs().read().ready() {}
135 r.cs().modify(|w| {
136 w.set_ainsel(4);
137 w.set_start_once(true)
138 });
139 while !r.cs().read().ready() {}
140 r.result().read().result().into()
141 } 210 }
142} 211}
143 212
144macro_rules! impl_pin {
145 ($pin:ident, $channel:expr) => {
146 impl Channel<Adc<'static>> for peripherals::$pin {
147 type ID = u8;
148 fn channel() -> u8 {
149 $channel
150 }
151 }
152 };
153}
154
155pub struct InterruptHandler { 213pub struct InterruptHandler {
156 _empty: (), 214 _empty: (),
157} 215}
158 216
159impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler { 217impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
160 unsafe fn on_interrupt() { 218 unsafe fn on_interrupt() {
161 let r = Adc::regs(); 219 let r = Adc::<Async>::regs();
162 r.inte().write(|w| w.set_fifo(false)); 220 r.inte().write(|w| w.set_fifo(false));
163 WAKER.wake(); 221 WAKER.wake();
164 } 222 }
165} 223}
166 224
225mod sealed {
226 pub trait AdcPin: crate::gpio::sealed::Pin {
227 fn channel(&mut self) -> u8;
228 }
229}
230
231pub trait AdcPin: sealed::AdcPin + gpio::Pin {}
232
233macro_rules! impl_pin {
234 ($pin:ident, $channel:expr) => {
235 impl sealed::AdcPin for peripherals::$pin {
236 fn channel(&mut self) -> u8 {
237 $channel
238 }
239 }
240
241 impl AdcPin for peripherals::$pin {}
242 };
243}
244
167impl_pin!(PIN_26, 0); 245impl_pin!(PIN_26, 0);
168impl_pin!(PIN_27, 1); 246impl_pin!(PIN_27, 1);
169impl_pin!(PIN_28, 2); 247impl_pin!(PIN_28, 2);
170impl_pin!(PIN_29, 3); 248impl_pin!(PIN_29, 3);
171
172impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
173where
174 WORD: From<u16>,
175 PIN: Channel<Adc<'static>, ID = u8> + Pin,
176{
177 type Error = ();
178 fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
179 Ok(self.blocking_read(pin).into())
180 }
181}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index ddd61d224..acb21dce5 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -308,6 +308,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
308 // - QSPI (we're using it to run this code!) 308 // - QSPI (we're using it to run this code!)
309 // - PLLs (it may be suicide if that's what's clocking us) 309 // - PLLs (it may be suicide if that's what's clocking us)
310 // - USB, SYSCFG (breaks usb-to-swd on core1) 310 // - USB, SYSCFG (breaks usb-to-swd on core1)
311 // - RTC (else there would be no more time...)
311 let mut peris = reset::ALL_PERIPHERALS; 312 let mut peris = reset::ALL_PERIPHERALS;
312 peris.set_io_qspi(false); 313 peris.set_io_qspi(false);
313 // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin 314 // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin
@@ -317,6 +318,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
317 // TODO investigate if usb should be unreset here 318 // TODO investigate if usb should be unreset here
318 peris.set_usbctrl(false); 319 peris.set_usbctrl(false);
319 peris.set_syscfg(false); 320 peris.set_syscfg(false);
321 peris.set_rtc(false);
320 reset::reset(peris); 322 reset::reset(peris);
321 323
322 // Disable resus that may be enabled from previous software 324 // Disable resus that may be enabled from previous software
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index f8048a4dd..a3d330cdc 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -41,7 +41,7 @@ impl From<Level> for bool {
41} 41}
42 42
43/// Represents a pull setting for an input. 43/// Represents a pull setting for an input.
44#[derive(Debug, Eq, PartialEq)] 44#[derive(Debug, Clone, Copy, Eq, PartialEq)]
45pub enum Pull { 45pub enum Pull {
46 None, 46 None,
47 Up, 47 Up,
@@ -566,13 +566,13 @@ impl<'d, T: Pin> Flex<'d, T> {
566 /// Is the output level high? 566 /// Is the output level high?
567 #[inline] 567 #[inline]
568 pub fn is_set_high(&self) -> bool { 568 pub fn is_set_high(&self) -> bool {
569 (self.pin.sio_out().value().read() & self.bit()) == 0 569 !self.is_set_low()
570 } 570 }
571 571
572 /// Is the output level low? 572 /// Is the output level low?
573 #[inline] 573 #[inline]
574 pub fn is_set_low(&self) -> bool { 574 pub fn is_set_low(&self) -> bool {
575 !self.is_set_high() 575 (self.pin.sio_out().value().read() & self.bit()) == 0
576 } 576 }
577 577
578 /// What level output is set to 578 /// What level output is set to
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 791c64554..9b85b2345 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -716,6 +716,9 @@ mod nightly {
716 async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { 716 async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
717 let addr: u16 = address.into(); 717 let addr: u16 = address.into();
718 718
719 if operations.len() > 0 {
720 Self::setup(addr)?;
721 }
719 let mut iterator = operations.iter_mut(); 722 let mut iterator = operations.iter_mut();
720 723
721 while let Some(op) = iterator.next() { 724 while let Some(op) = iterator.next() {
@@ -723,11 +726,9 @@ mod nightly {
723 726
724 match op { 727 match op {
725 Operation::Read(buffer) => { 728 Operation::Read(buffer) => {
726 Self::setup(addr)?;
727 self.read_async_internal(buffer, false, last).await?; 729 self.read_async_internal(buffer, false, last).await?;
728 } 730 }
729 Operation::Write(buffer) => { 731 Operation::Write(buffer) => {
730 Self::setup(addr)?;
731 self.write_async_internal(buffer.into_iter().cloned(), last).await?; 732 self.write_async_internal(buffer.into_iter().cloned(), last).await?;
732 } 733 }
733 } 734 }
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 4fd3cb46a..4f205a16e 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -252,7 +252,6 @@ pub fn init(config: config::Config) -> Peripherals {
252 #[cfg(feature = "time-driver")] 252 #[cfg(feature = "time-driver")]
253 timer::init(); 253 timer::init();
254 dma::init(); 254 dma::init();
255 pio::init();
256 gpio::init(); 255 gpio::init();
257 } 256 }
258 257
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 30648e8ea..72a2f44ed 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -16,12 +16,12 @@ use pio::{SideSet, Wrap};
16use crate::dma::{Channel, Transfer, Word}; 16use crate::dma::{Channel, Transfer, Word};
17use crate::gpio::sealed::Pin as SealedPin; 17use crate::gpio::sealed::Pin as SealedPin;
18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; 18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
19use crate::interrupt::InterruptExt; 19use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
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::{pac, peripherals, pio_instr_util, RegExt};
23 23
24struct Wakers([AtomicWaker; 12]); 24pub struct Wakers([AtomicWaker; 12]);
25 25
26impl Wakers { 26impl Wakers {
27 #[inline(always)] 27 #[inline(always)]
@@ -38,10 +38,6 @@ impl Wakers {
38 } 38 }
39} 39}
40 40
41const NEW_AW: AtomicWaker = AtomicWaker::new();
42const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
43static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2];
44
45#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 41#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))] 42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47#[repr(u8)] 43#[repr(u8)]
@@ -85,42 +81,20 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
85const TXNFULL_MASK: u32 = 1 << 4; 81const TXNFULL_MASK: u32 = 1 << 4;
86const SMIRQ_MASK: u32 = 1 << 8; 82const SMIRQ_MASK: u32 = 1 << 8;
87 83
88#[cfg(feature = "rt")] 84pub struct InterruptHandler<PIO: Instance> {
89#[interrupt] 85 _pio: PhantomData<PIO>,
90fn PIO0_IRQ_0() {
91 use crate::pac;
92 let ints = pac::PIO0.irqs(0).ints().read().0;
93 for bit in 0..12 {
94 if ints & (1 << bit) != 0 {
95 WAKERS[0].0[bit].wake();
96 }
97 }
98 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
99} 86}
100 87
101#[cfg(feature = "rt")] 88impl<PIO: Instance> Handler<PIO::Interrupt> for InterruptHandler<PIO> {
102#[interrupt] 89 unsafe fn on_interrupt() {
103fn PIO1_IRQ_0() { 90 let ints = PIO::PIO.irqs(0).ints().read().0;
104 use crate::pac; 91 for bit in 0..12 {
105 let ints = pac::PIO1.irqs(0).ints().read().0; 92 if ints & (1 << bit) != 0 {
106 for bit in 0..12 { 93 PIO::wakers().0[bit].wake();
107 if ints & (1 << bit) != 0 { 94 }
108 WAKERS[1].0[bit].wake();
109 } 95 }
96 PIO::PIO.irqs(0).inte().write_clear(|m| m.0 = ints);
110 } 97 }
111 pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints);
112}
113
114pub(crate) unsafe fn init() {
115 interrupt::PIO0_IRQ_0.disable();
116 interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
117 pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
118 interrupt::PIO0_IRQ_0.enable();
119
120 interrupt::PIO1_IRQ_0.disable();
121 interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
122 pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
123 interrupt::PIO1_IRQ_0.enable();
124} 98}
125 99
126/// Future that waits for TX-FIFO to become writable 100/// Future that waits for TX-FIFO to become writable
@@ -144,7 +118,7 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
144 if self.get_mut().sm_tx.try_push(value) { 118 if self.get_mut().sm_tx.try_push(value) {
145 Poll::Ready(()) 119 Poll::Ready(())
146 } else { 120 } else {
147 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); 121 PIO::wakers().fifo_out()[SM].register(cx.waker());
148 PIO::PIO.irqs(0).inte().write_set(|m| { 122 PIO::PIO.irqs(0).inte().write_set(|m| {
149 m.0 = TXNFULL_MASK << SM; 123 m.0 = TXNFULL_MASK << SM;
150 }); 124 });
@@ -181,7 +155,7 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
181 if let Some(v) = self.sm_rx.try_pull() { 155 if let Some(v) = self.sm_rx.try_pull() {
182 Poll::Ready(v) 156 Poll::Ready(v)
183 } else { 157 } else {
184 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); 158 PIO::wakers().fifo_in()[SM].register(cx.waker());
185 PIO::PIO.irqs(0).inte().write_set(|m| { 159 PIO::PIO.irqs(0).inte().write_set(|m| {
186 m.0 = RXNEMPTY_MASK << SM; 160 m.0 = RXNEMPTY_MASK << SM;
187 }); 161 });
@@ -217,7 +191,7 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
217 return Poll::Ready(()); 191 return Poll::Ready(());
218 } 192 }
219 193
220 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); 194 PIO::wakers().irq()[self.irq_no as usize].register(cx.waker());
221 PIO::PIO.irqs(0).inte().write_set(|m| { 195 PIO::PIO.irqs(0).inte().write_set(|m| {
222 m.0 = SMIRQ_MASK << self.irq_no; 196 m.0 = SMIRQ_MASK << self.irq_no;
223 }); 197 });
@@ -949,9 +923,11 @@ pub struct Pio<'d, PIO: Instance> {
949} 923}
950 924
951impl<'d, PIO: Instance> Pio<'d, PIO> { 925impl<'d, PIO: Instance> Pio<'d, PIO> {
952 pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self { 926 pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self {
953 PIO::state().users.store(5, Ordering::Release); 927 PIO::state().users.store(5, Ordering::Release);
954 PIO::state().used_pins.store(0, Ordering::Release); 928 PIO::state().used_pins.store(0, Ordering::Release);
929 PIO::Interrupt::unpend();
930 unsafe { PIO::Interrupt::enable() };
955 Self { 931 Self {
956 common: Common { 932 common: Common {
957 instructions_used: 0, 933 instructions_used: 0,
@@ -1017,6 +993,15 @@ mod sealed {
1017 const PIO_NO: u8; 993 const PIO_NO: u8;
1018 const PIO: &'static crate::pac::pio::Pio; 994 const PIO: &'static crate::pac::pio::Pio;
1019 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; 995 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
996 type Interrupt: crate::interrupt::typelevel::Interrupt;
997
998 #[inline]
999 fn wakers() -> &'static Wakers {
1000 const NEW_AW: AtomicWaker = AtomicWaker::new();
1001 static WAKERS: Wakers = Wakers([NEW_AW; 12]);
1002
1003 &WAKERS
1004 }
1020 1005
1021 #[inline] 1006 #[inline]
1022 fn state() -> &'static State { 1007 fn state() -> &'static State {
@@ -1033,18 +1018,19 @@ mod sealed {
1033pub trait Instance: sealed::Instance + Sized + Unpin {} 1018pub trait Instance: sealed::Instance + Sized + Unpin {}
1034 1019
1035macro_rules! impl_pio { 1020macro_rules! impl_pio {
1036 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { 1021 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident, $irq:ident) => {
1037 impl sealed::Instance for peripherals::$name { 1022 impl sealed::Instance for peripherals::$name {
1038 const PIO_NO: u8 = $pio; 1023 const PIO_NO: u8 = $pio;
1039 const PIO: &'static pac::pio::Pio = &pac::$pac; 1024 const PIO: &'static pac::pio::Pio = &pac::$pac;
1040 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; 1025 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
1026 type Interrupt = crate::interrupt::typelevel::$irq;
1041 } 1027 }
1042 impl Instance for peripherals::$name {} 1028 impl Instance for peripherals::$name {}
1043 }; 1029 };
1044} 1030}
1045 1031
1046impl_pio!(PIO0, 0, PIO0, PIO0_0); 1032impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1047impl_pio!(PIO1, 1, PIO1, PIO1_0); 1033impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1048 1034
1049pub trait PioPin: sealed::PioPin + gpio::Pin {} 1035pub trait PioPin: sealed::PioPin + gpio::Pin {}
1050 1036
diff --git a/embassy-rp/src/rtc/datetime_no_deps.rs b/embassy-rp/src/rtc/datetime_no_deps.rs
index 92770e984..ea899c339 100644
--- a/embassy-rp/src/rtc/datetime_no_deps.rs
+++ b/embassy-rp/src/rtc/datetime_no_deps.rs
@@ -25,6 +25,7 @@ pub enum Error {
25} 25}
26 26
27/// Structure containing date and time information 27/// Structure containing date and time information
28#[derive(Clone, Debug)]
28pub struct DateTime { 29pub struct DateTime {
29 /// 0..4095 30 /// 0..4095
30 pub year: u16, 31 pub year: u16,
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index b18f12fc4..1b33fdf8d 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -12,26 +12,24 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
12use crate::clocks::clk_rtc_freq; 12use crate::clocks::clk_rtc_freq;
13 13
14/// A reference to the real time clock of the system 14/// A reference to the real time clock of the system
15pub struct RealTimeClock<'d, T: Instance> { 15pub struct Rtc<'d, T: Instance> {
16 inner: PeripheralRef<'d, T>, 16 inner: PeripheralRef<'d, T>,
17} 17}
18 18
19impl<'d, T: Instance> RealTimeClock<'d, T> { 19impl<'d, T: Instance> Rtc<'d, T> {
20 /// Create a new instance of the real time clock, with the given date as an initial value. 20 /// Create a new instance of the real time clock, with the given date as an initial value.
21 /// 21 ///
22 /// # Errors 22 /// # Errors
23 /// 23 ///
24 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. 24 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
25 pub fn new(inner: impl Peripheral<P = T> + 'd, initial_date: DateTime) -> Result<Self, RtcError> { 25 pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
26 into_ref!(inner); 26 into_ref!(inner);
27 27
28 // Set the RTC divider 28 // Set the RTC divider
29 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 result = Self { inner };
32 result.set_leap_year_check(true); // should be on by default, make sure this is the case. 32 result
33 result.set_datetime(initial_date)?;
34 Ok(result)
35 } 33 }
36 34
37 /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. 35 /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check.
@@ -43,7 +41,37 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
43 }); 41 });
44 } 42 }
45 43
46 /// Checks to see if this RealTimeClock is running 44 /// Set the time from internal format
45 pub fn restore(&mut self, ymd: rp_pac::rtc::regs::Rtc1, hms: rp_pac::rtc::regs::Rtc0) {
46 // disable RTC while we configure it
47 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
48 while self.inner.regs().ctrl().read().rtc_active() {
49 core::hint::spin_loop();
50 }
51
52 self.inner.regs().setup_0().write(|w| {
53 *w = rp_pac::rtc::regs::Setup0(ymd.0);
54 });
55 self.inner.regs().setup_1().write(|w| {
56 *w = rp_pac::rtc::regs::Setup1(hms.0);
57 });
58
59 // Load the new datetime and re-enable RTC
60 self.inner.regs().ctrl().write(|w| w.set_load(true));
61 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
62 while !self.inner.regs().ctrl().read().rtc_active() {
63 core::hint::spin_loop();
64 }
65 }
66
67 /// Get the time in internal format
68 pub fn save(&mut self) -> (rp_pac::rtc::regs::Rtc1, rp_pac::rtc::regs::Rtc0) {
69 let rtc_0: rp_pac::rtc::regs::Rtc0 = self.inner.regs().rtc_0().read();
70 let rtc_1 = self.inner.regs().rtc_1().read();
71 (rtc_1, rtc_0)
72 }
73
74 /// Checks to see if this Rtc is running
47 pub fn is_running(&self) -> bool { 75 pub fn is_running(&self) -> bool {
48 self.inner.regs().ctrl().read().rtc_active() 76 self.inner.regs().ctrl().read().rtc_active()
49 } 77 }
@@ -113,8 +141,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
113 /// # fn main() { } 141 /// # fn main() { }
114 /// # #[cfg(not(feature = "chrono"))] 142 /// # #[cfg(not(feature = "chrono"))]
115 /// # fn main() { 143 /// # fn main() {
116 /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter}; 144 /// # use embassy_rp::rtc::{Rtc, DateTimeFilter};
117 /// # let mut real_time_clock: RealTimeClock<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() }; 145 /// # let mut real_time_clock: Rtc<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
118 /// let now = real_time_clock.now().unwrap(); 146 /// let now = real_time_clock.now().unwrap();
119 /// real_time_clock.schedule_alarm( 147 /// real_time_clock.schedule_alarm(
120 /// DateTimeFilter::default() 148 /// DateTimeFilter::default()
@@ -150,7 +178,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
150 } 178 }
151} 179}
152 180
153/// Errors that can occur on methods on [RealTimeClock] 181/// Errors that can occur on methods on [Rtc]
154#[derive(Clone, Debug, PartialEq, Eq)] 182#[derive(Clone, Debug, PartialEq, Eq)]
155pub enum RtcError { 183pub enum RtcError {
156 /// An invalid DateTime was given or stored on the hardware. 184 /// An invalid DateTime was given or stored on the hardware.
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index e817d074e..af101cf4a 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -545,25 +545,19 @@ mod eh1 {
545 type Error = Error; 545 type Error = Error;
546 } 546 }
547 547
548 impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusFlush for Spi<'d, T, M> { 548 impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
549 fn flush(&mut self) -> Result<(), Self::Error> { 549 fn flush(&mut self) -> Result<(), Self::Error> {
550 Ok(()) 550 Ok(())
551 } 551 }
552 }
553 552
554 impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusRead<u8> for Spi<'d, T, M> {
555 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { 553 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
556 self.blocking_transfer(words, &[]) 554 self.blocking_transfer(words, &[])
557 } 555 }
558 }
559 556
560 impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusWrite<u8> for Spi<'d, T, M> {
561 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 557 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
562 self.blocking_write(words) 558 self.blocking_write(words)
563 } 559 }
564 }
565 560
566 impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
567 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { 561 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
568 self.blocking_transfer(read, write) 562 self.blocking_transfer(read, write)
569 } 563 }
@@ -578,30 +572,24 @@ mod eh1 {
578mod eha { 572mod eha {
579 use super::*; 573 use super::*;
580 574
581 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Async> { 575 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
582 async fn flush(&mut self) -> Result<(), Self::Error> { 576 async fn flush(&mut self) -> Result<(), Self::Error> {
583 Ok(()) 577 Ok(())
584 } 578 }
585 }
586 579
587 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spi<'d, T, Async> {
588 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 580 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
589 self.write(words).await 581 self.write(words).await
590 } 582 }
591 }
592 583
593 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spi<'d, T, Async> {
594 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { 584 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
595 self.read(words).await 585 self.read(words).await
596 } 586 }
597 }
598 587
599 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> { 588 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
600 async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
601 self.transfer(read, write).await 589 self.transfer(read, write).await
602 } 590 }
603 591
604 async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Result<(), Self::Error> { 592 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
605 self.transfer_in_place(words).await 593 self.transfer_in_place(words).await
606 } 594 }
607 } 595 }
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index b3f3bd927..4ab881f6e 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -361,6 +361,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
361 361
362 let regs = T::regs(); 362 let regs = T::regs();
363 let siestatus = regs.sie_status().read(); 363 let siestatus = regs.sie_status().read();
364 let intrstatus = regs.intr().read();
364 365
365 if siestatus.resume() { 366 if siestatus.resume() {
366 regs.sie_status().write(|w| w.set_resume(true)); 367 regs.sie_status().write(|w| w.set_resume(true));
@@ -389,7 +390,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
389 return Poll::Ready(Event::Reset); 390 return Poll::Ready(Event::Reset);
390 } 391 }
391 392
392 if siestatus.suspended() { 393 if siestatus.suspended() && intrstatus.dev_suspend() {
393 regs.sie_status().write(|w| w.set_suspended(true)); 394 regs.sie_status().write(|w| w.set_suspended(true));
394 return Poll::Ready(Event::Suspend); 395 return Poll::Ready(Event::Suspend);
395 } 396 }
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index d37795cc9..f1e986ec7 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -107,4 +107,36 @@ impl Watchdog {
107 w.set_trigger(true); 107 w.set_trigger(true);
108 }) 108 })
109 } 109 }
110
111 /// Store data in scratch register
112 pub fn set_scratch(&mut self, index: usize, value: u32) {
113 let watchdog = pac::WATCHDOG;
114 match index {
115 0 => watchdog.scratch0().write(|w| *w = value),
116 1 => watchdog.scratch1().write(|w| *w = value),
117 2 => watchdog.scratch2().write(|w| *w = value),
118 3 => watchdog.scratch3().write(|w| *w = value),
119 4 => watchdog.scratch4().write(|w| *w = value),
120 5 => watchdog.scratch5().write(|w| *w = value),
121 6 => watchdog.scratch6().write(|w| *w = value),
122 7 => watchdog.scratch7().write(|w| *w = value),
123 _ => panic!("Invalid watchdog scratch index"),
124 }
125 }
126
127 /// Read data from scratch register
128 pub fn get_scratch(&mut self, index: usize) -> u32 {
129 let watchdog = pac::WATCHDOG;
130 match index {
131 0 => watchdog.scratch0().read(),
132 1 => watchdog.scratch1().read(),
133 2 => watchdog.scratch2().read(),
134 3 => watchdog.scratch3().read(),
135 4 => watchdog.scratch4().read(),
136 5 => watchdog.scratch5().read(),
137 6 => watchdog.scratch6().read(),
138 7 => watchdog.scratch7().read(),
139 _ => panic!("Invalid watchdog scratch index"),
140 }
141 }
110} 142}
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 4b830cab3..6cd122200 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -5,18 +5,19 @@ edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[package.metadata.embassy_docs] 7[package.metadata.embassy_docs]
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src" 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" 9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src/"
10target = "thumbv7em-none-eabihf" 10target = "thumbv7em-none-eabihf"
11features = ["stm32wb55rg"] 11features = ["stm32wb55rg"]
12 12
13[dependencies] 13[dependencies]
14embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } 14embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
15embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 15embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
16embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 16embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
17embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
18embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } 18embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
20embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver", optional=true }
20 21
21defmt = { version = "0.3", optional = true } 22defmt = { version = "0.3", optional = true }
22cortex-m = "0.7.6" 23cortex-m = "0.7.6"
@@ -25,13 +26,15 @@ aligned = "0.4.1"
25 26
26bit_field = "0.10.2" 27bit_field = "0.10.2"
27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 28stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
28stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true } 29stm32wb-hci = { version = "0.1.3", optional = true }
30futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
31bitflags = { version = "2.3.3", optional = true }
29 32
30[features] 33[features]
31defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] 34defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"]
32 35
33ble = ["dep:stm32wb-hci"] 36ble = ["dep:stm32wb-hci"]
34mac = [] 37mac = ["dep:bitflags", "dep:embassy-net-driver" ]
35 38
36stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] 39stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
37stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] 40stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
@@ -48,4 +51,4 @@ stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
48stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ] 51stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
49stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ] 52stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
50stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ] 53stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
51stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file 54stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ]
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs
index 8428b6ffc..928357384 100644
--- a/embassy-stm32-wpan/src/cmd.rs
+++ b/embassy-stm32-wpan/src/cmd.rs
@@ -37,7 +37,7 @@ pub struct CmdSerialStub {
37} 37}
38 38
39#[derive(Copy, Clone, Default)] 39#[derive(Copy, Clone, Default)]
40#[repr(C, packed(4))] 40#[repr(C, packed)]
41pub struct CmdPacket { 41pub struct CmdPacket {
42 pub header: PacketHeader, 42 pub header: PacketHeader,
43 pub cmdserial: CmdSerial, 43 pub cmdserial: CmdSerial,
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs
index f234151d7..bd70851ea 100644
--- a/embassy-stm32-wpan/src/consts.rs
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -6,6 +6,8 @@ use crate::PacketHeader;
6#[derive(Debug)] 6#[derive(Debug)]
7#[repr(C)] 7#[repr(C)]
8pub enum TlPacketType { 8pub enum TlPacketType {
9 MacCmd = 0x00,
10
9 BleCmd = 0x01, 11 BleCmd = 0x01,
10 AclData = 0x02, 12 AclData = 0x02,
11 BleEvt = 0x04, 13 BleEvt = 0x04,
@@ -79,6 +81,7 @@ pub const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
79pub const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE; 81pub const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
80 82
81pub const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); 83pub const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
84pub const C_SIZE_CMD_STRING: usize = 256;
82 85
83pub const fn divc(x: usize, y: usize) -> usize { 86pub const fn divc(x: usize, y: usize) -> usize {
84 (x + y - 1) / y 87 (x + y - 1) / y
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
index 99c610583..6836d7a8b 100644
--- a/embassy-stm32-wpan/src/lib.rs
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -1,5 +1,6 @@
1#![no_std] 1#![no_std]
2#![cfg_attr(feature = "ble", feature(async_fn_in_trait))] 2#![cfg_attr(any(feature = "ble", feature = "mac"), feature(async_fn_in_trait))]
3#![cfg_attr(feature = "mac", feature(type_alias_impl_trait, concat_bytes))]
3 4
4// This must go FIRST so that all the other modules see its macros. 5// This must go FIRST so that all the other modules see its macros.
5pub mod fmt; 6pub mod fmt;
@@ -26,6 +27,9 @@ pub mod sub;
26pub mod tables; 27pub mod tables;
27pub mod unsafe_linked_list; 28pub mod unsafe_linked_list;
28 29
30#[cfg(feature = "mac")]
31pub mod mac;
32
29#[cfg(feature = "ble")] 33#[cfg(feature = "ble")]
30pub use crate::sub::ble::hci; 34pub use crate::sub::ble::hci;
31 35
@@ -60,9 +64,9 @@ impl<'d> TlMbox<'d> {
60 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), 64 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
61 traces_table: TL_TRACES_TABLE.as_ptr(), 65 traces_table: TL_TRACES_TABLE.as_ptr(),
62 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), 66 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
63 // zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), 67 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
64 // lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), 68 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
65 // ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), 69 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
66 }); 70 });
67 71
68 TL_SYS_TABLE 72 TL_SYS_TABLE
@@ -87,15 +91,15 @@ impl<'d> TlMbox<'d> {
87 TL_MAC_802_15_4_TABLE 91 TL_MAC_802_15_4_TABLE
88 .as_mut_ptr() 92 .as_mut_ptr()
89 .write_volatile(MaybeUninit::zeroed().assume_init()); 93 .write_volatile(MaybeUninit::zeroed().assume_init());
90 // TL_ZIGBEE_TABLE 94 TL_ZIGBEE_TABLE
91 // .as_mut_ptr() 95 .as_mut_ptr()
92 // .write_volatile(MaybeUninit::zeroed().assume_init()); 96 .write_volatile(MaybeUninit::zeroed().assume_init());
93 // TL_LLD_TESTS_TABLE 97 TL_LLD_TESTS_TABLE
94 // .as_mut_ptr() 98 .as_mut_ptr()
95 // .write_volatile(MaybeUninit::zeroed().assume_init()); 99 .write_volatile(MaybeUninit::zeroed().assume_init());
96 // TL_BLE_LLD_TABLE 100 TL_BLE_LLD_TABLE
97 // .as_mut_ptr() 101 .as_mut_ptr()
98 // .write_volatile(MaybeUninit::zeroed().assume_init()); 102 .write_volatile(MaybeUninit::zeroed().assume_init());
99 103
100 EVT_POOL 104 EVT_POOL
101 .as_mut_ptr() 105 .as_mut_ptr()
@@ -103,18 +107,30 @@ impl<'d> TlMbox<'d> {
103 SYS_SPARE_EVT_BUF 107 SYS_SPARE_EVT_BUF
104 .as_mut_ptr() 108 .as_mut_ptr()
105 .write_volatile(MaybeUninit::zeroed().assume_init()); 109 .write_volatile(MaybeUninit::zeroed().assume_init());
106 BLE_SPARE_EVT_BUF 110 CS_BUFFER
107 .as_mut_ptr() 111 .as_mut_ptr()
108 .write_volatile(MaybeUninit::zeroed().assume_init()); 112 .write_volatile(MaybeUninit::zeroed().assume_init());
109 113
114 #[cfg(feature = "ble")]
110 { 115 {
116 BLE_SPARE_EVT_BUF
117 .as_mut_ptr()
118 .write_volatile(MaybeUninit::zeroed().assume_init());
119
111 BLE_CMD_BUFFER 120 BLE_CMD_BUFFER
112 .as_mut_ptr() 121 .as_mut_ptr()
113 .write_volatile(MaybeUninit::zeroed().assume_init()); 122 .write_volatile(MaybeUninit::zeroed().assume_init());
114 HCI_ACL_DATA_BUFFER 123 HCI_ACL_DATA_BUFFER
115 .as_mut_ptr() 124 .as_mut_ptr()
116 .write_volatile(MaybeUninit::zeroed().assume_init()); 125 .write_volatile(MaybeUninit::zeroed().assume_init());
117 CS_BUFFER 126 }
127
128 #[cfg(feature = "mac")]
129 {
130 MAC_802_15_4_CMD_BUFFER
131 .as_mut_ptr()
132 .write_volatile(MaybeUninit::zeroed().assume_init());
133 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER
118 .as_mut_ptr() 134 .as_mut_ptr()
119 .write_volatile(MaybeUninit::zeroed().assume_init()); 135 .write_volatile(MaybeUninit::zeroed().assume_init());
120 } 136 }
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs
new file mode 100644
index 000000000..8f6dcbbbc
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/commands.rs
@@ -0,0 +1,476 @@
1use core::{mem, slice};
2
3use super::opcodes::OpcodeM4ToM0;
4use super::typedefs::{
5 AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus,
6 PanId, PibId, ScanType, SecurityLevel,
7};
8
9pub trait MacCommand: Sized {
10 const OPCODE: OpcodeM4ToM0;
11
12 fn payload<'a>(&'a self) -> &'a [u8] {
13 unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
14 }
15}
16
17/// MLME ASSOCIATE Request used to request an association
18#[repr(C)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct AssociateRequest {
21 /// the logical channel on which to attempt association
22 pub channel_number: MacChannel,
23 /// the channel page on which to attempt association
24 pub channel_page: u8,
25 /// coordinator addressing mode
26 pub coord_addr_mode: AddressMode,
27 /// operational capabilities of the associating device
28 pub capability_information: Capabilities,
29 /// the identifier of the PAN with which to associate
30 pub coord_pan_id: PanId,
31 /// the security level to be used
32 pub security_level: SecurityLevel,
33 /// the mode used to identify the key to be used
34 pub key_id_mode: KeyIdMode,
35 /// the originator of the key to be used
36 pub key_source: [u8; 8],
37 /// Coordinator address
38 pub coord_address: MacAddress,
39 /// the index of the key to be used
40 pub key_index: u8,
41}
42
43impl MacCommand for AssociateRequest {
44 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq;
45}
46
47/// MLME DISASSOCIATE Request sed to request a disassociation
48#[repr(C)]
49#[cfg_attr(feature = "defmt", derive(defmt::Format))]
50pub struct DisassociateRequest {
51 /// device addressing mode used
52 pub device_addr_mode: AddressMode,
53 /// the identifier of the PAN of the device
54 pub device_pan_id: PanId,
55 /// the reason for the disassociation
56 pub disassociation_reason: DisassociationReason,
57 /// device address
58 pub device_address: MacAddress,
59 /// `true` if the disassociation notification command is to be sent indirectly
60 pub tx_indirect: bool,
61 /// the security level to be used
62 pub security_level: SecurityLevel,
63 /// the mode to be used to indetify the key to be used
64 pub key_id_mode: KeyIdMode,
65 /// the index of the key to be used
66 pub key_index: u8,
67 /// the originator of the key to be used
68 pub key_source: [u8; 8],
69}
70
71impl MacCommand for DisassociateRequest {
72 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq;
73}
74
75/// MLME GET Request used to request a PIB value
76#[repr(C)]
77#[derive(Default)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub struct GetRequest {
80 /// the name of the PIB attribute to read
81 pub pib_attribute: PibId,
82
83 /// byte stuffing to keep 32 bit alignment
84 pub a_stuffing: [u8; 3],
85}
86
87impl MacCommand for GetRequest {
88 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
89}
90
91/// MLME GTS Request used to request and maintain GTSs
92#[repr(C)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub struct GtsRequest {
95 /// the characteristics of the GTS
96 pub characteristics: GtsCharacteristics,
97 /// the security level to be used
98 pub security_level: SecurityLevel,
99 /// the mode used to identify the key to be used
100 pub key_id_mode: KeyIdMode,
101 /// the index of the key to be used
102 pub key_index: u8,
103 /// the originator of the key to be used
104 pub key_source: [u8; 8],
105}
106
107impl MacCommand for GtsRequest {
108 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
109}
110
111#[repr(C)]
112#[derive(Default)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114pub struct ResetRequest {
115 /// MAC PIB attributes are set to their default values or not during reset
116 pub set_default_pib: bool,
117 /// byte stuffing to keep 32 bit alignment
118 pub a_stuffing: [u8; 3],
119}
120
121impl MacCommand for ResetRequest {
122 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq;
123}
124
125/// MLME RX ENABLE Request used to request that the receiver is either enabled
126/// for a finite period of time or disabled
127#[repr(C)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct RxEnableRequest {
130 /// the request operation can be deferred or not
131 pub defer_permit: bool,
132 /// configure the transceiver to RX with ranging for a value of
133 /// RANGING_ON or to not enable ranging for RANGING_OFF
134 pub ranging_rx_control: u8,
135 /// byte stuffing to keep 32 bit alignment
136 pub a_stuffing: [u8; 2],
137 /// number of symbols measured before the receiver is to be enabled or disabled
138 pub rx_on_time: [u8; 4],
139 /// number of symbols for which the receiver is to be enabled
140 pub rx_on_duration: [u8; 4],
141}
142
143impl MacCommand for RxEnableRequest {
144 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq;
145}
146
147/// MLME SCAN Request used to initiate a channel scan over a given list of channels
148#[repr(C)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub struct ScanRequest {
151 /// the type of scan to be performed
152 pub scan_type: ScanType,
153 /// the time spent on scanning each channel
154 pub scan_duration: u8,
155 /// channel page on which to perform the scan
156 pub channel_page: u8,
157 /// security level to be used
158 pub security_level: SecurityLevel,
159 /// indicate which channels are to be scanned
160 pub scan_channels: [u8; 4],
161 /// originator the key to be used
162 pub key_source: [u8; 8],
163 /// mode used to identify the key to be used
164 pub key_id_mode: KeyIdMode,
165 /// index of the key to be used
166 pub key_index: u8,
167 /// byte stuffing to keep 32 bit alignment
168 pub a_stuffing: [u8; 2],
169}
170
171impl MacCommand for ScanRequest {
172 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq;
173}
174
175/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute
176#[repr(C)]
177#[cfg_attr(feature = "defmt", derive(defmt::Format))]
178pub struct SetRequest {
179 /// the pointer to the value of the PIB attribute to set
180 pub pib_attribute_ptr: *const u8,
181 /// the name of the PIB attribute to set
182 pub pib_attribute: PibId,
183}
184
185impl MacCommand for SetRequest {
186 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq;
187}
188
189/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe
190/// configuration
191#[repr(C)]
192#[derive(Default)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194pub struct StartRequest {
195 /// PAN indentifier to used by the device
196 pub pan_id: PanId,
197 /// logical channel on which to begin
198 pub channel_number: MacChannel,
199 /// channel page on which to begin
200 pub channel_page: u8,
201 /// time at which to begin transmitting beacons
202 pub start_time: [u8; 4],
203 /// indicated how often the beacon is to be transmitted
204 pub beacon_order: u8,
205 /// length of the active portion of the superframe
206 pub superframe_order: u8,
207 /// indicated wheter the device is a PAN coordinator or not
208 pub pan_coordinator: bool,
209 /// indicates if the receiver of the beaconing device is disabled or not
210 pub battery_life_extension: bool,
211 /// indicated if the coordinator realignment command is to be trasmitted
212 pub coord_realignment: u8,
213 /// indicated if the coordinator realignment command is to be trasmitted
214 pub coord_realign_security_level: SecurityLevel,
215 /// index of the key to be used
216 pub coord_realign_key_id_index: u8,
217 /// originator of the key to be used
218 pub coord_realign_key_source: [u8; 8],
219 /// security level to be used for beacon frames
220 pub beacon_security_level: SecurityLevel,
221 /// mode used to identify the key to be used
222 pub beacon_key_id_mode: KeyIdMode,
223 /// index of the key to be used
224 pub beacon_key_index: u8,
225 /// originator of the key to be used
226 pub beacon_key_source: [u8; 8],
227}
228
229impl MacCommand for StartRequest {
230 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq;
231}
232
233/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if
234/// specified, tracking its beacons
235#[repr(C)]
236#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub struct SyncRequest {
238 /// the channel number on which to attempt coordinator synchronization
239 pub channel_number: MacChannel,
240 /// the channel page on which to attempt coordinator synchronization
241 pub channel_page: u8,
242 /// `true` if the MLME is to synchronize with the next beacon and attempts
243 /// to track all future beacons.
244 ///
245 /// `false` if the MLME is to synchronize with only the next beacon
246 pub track_beacon: bool,
247 /// byte stuffing to keep 32 bit alignment
248 pub a_stuffing: [u8; 1],
249}
250
251impl MacCommand for SyncRequest {
252 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq;
253}
254
255/// MLME POLL Request propmts the device to request data from the coordinator
256#[repr(C)]
257#[cfg_attr(feature = "defmt", derive(defmt::Format))]
258pub struct PollRequest {
259 /// addressing mode of the coordinator
260 pub coord_addr_mode: AddressMode,
261 /// security level to be used
262 pub security_level: SecurityLevel,
263 /// mode used to identify the key to be used
264 pub key_id_mode: KeyIdMode,
265 /// index of the key to be used
266 pub key_index: u8,
267 /// coordinator address
268 pub coord_address: MacAddress,
269 /// originator of the key to be used
270 pub key_source: [u8; 8],
271 /// PAN identifier of the coordinator
272 pub coord_pan_id: PanId,
273 /// byte stuffing to keep 32 bit alignment
274 pub a_stuffing: [u8; 2],
275}
276
277impl MacCommand for PollRequest {
278 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq;
279}
280
281/// MLME DPS Request allows the next higher layer to request that the PHY utilize a
282/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration
283#[repr(C)]
284#[cfg_attr(feature = "defmt", derive(defmt::Format))]
285pub struct DpsRequest {
286 /// the index value for the transmitter
287 tx_dps_index: u8,
288 /// the index value of the receiver
289 rx_dps_index: u8,
290 /// the number of symbols for which the transmitter and receiver will utilize the
291 /// respective DPS indices
292 dps_index_duration: u8,
293 /// byte stuffing to keep 32 bit alignment
294 pub a_stuffing: [u8; 1],
295}
296
297impl MacCommand for DpsRequest {
298 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq;
299}
300
301/// MLME SOUNDING request primitive which is used by the next higher layer to request that
302/// the PHY respond with channel sounding information
303#[repr(C)]
304#[cfg_attr(feature = "defmt", derive(defmt::Format))]
305pub struct SoundingRequest {
306 /// byte stuffing to keep 32 bit alignment
307 pub a_stuffing: [u8; 4],
308}
309
310impl MacCommand for SoundingRequest {
311 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq;
312}
313
314/// MLME CALIBRATE request primitive which used to obtain the results of a ranging
315/// calibration request from an RDEV
316#[repr(C)]
317#[cfg_attr(feature = "defmt", derive(defmt::Format))]
318pub struct CalibrateRequest {
319 /// byte stuffing to keep 32 bit alignment
320 pub a_stuffing: [u8; 4],
321}
322
323impl MacCommand for CalibrateRequest {
324 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq;
325}
326
327/// MCPS DATA Request used for MAC data related requests from the application
328#[repr(C)]
329#[cfg_attr(feature = "defmt", derive(defmt::Format))]
330pub struct DataRequest {
331 /// the handle assocated with the MSDU to be transmitted
332 pub msdu_ptr: *const u8,
333 /// source addressing mode used
334 pub src_addr_mode: AddressMode,
335 /// destination addressing mode used
336 pub dst_addr_mode: AddressMode,
337 /// destination PAN Id
338 pub dst_pan_id: PanId,
339 /// destination address
340 pub dst_address: MacAddress,
341 /// the number of octets contained in the MSDU
342 pub msdu_length: u8,
343 /// the handle assocated with the MSDU to be transmitted
344 pub msdu_handle: u8,
345 /// the ACK transmittion options for the MSDU
346 pub ack_tx: u8,
347 /// `true` if a GTS is to be used for transmission
348 ///
349 /// `false` indicates that the CAP will be used
350 pub gts_tx: bool,
351 /// the pending bit transmission options for the MSDU
352 pub indirect_tx: u8,
353 /// the security level to be used
354 pub security_level: SecurityLevel,
355 /// the mode used to indentify the key to be used
356 pub key_id_mode: KeyIdMode,
357 /// the index of the key to be used
358 pub key_index: u8,
359 /// the originator of the key to be used
360 pub key_source: [u8; 8],
361 /// 2011 - the pulse repitition value
362 pub uwbprf: u8,
363 /// 2011 - the ranging configuration
364 pub ranging: u8,
365 /// 2011 - the preamble symbol repititions
366 pub uwb_preamble_symbol_repetitions: u8,
367 /// 2011 - indicates the data rate
368 pub datrate: u8,
369}
370
371impl DataRequest {
372 pub fn set_buffer<'a>(&'a mut self, buf: &'a [u8]) -> &mut Self {
373 self.msdu_ptr = buf as *const _ as *const u8;
374 self.msdu_length = buf.len() as u8;
375
376 self
377 }
378}
379
380impl Default for DataRequest {
381 fn default() -> Self {
382 Self {
383 msdu_ptr: 0 as *const u8,
384 src_addr_mode: AddressMode::NoAddress,
385 dst_addr_mode: AddressMode::NoAddress,
386 dst_pan_id: PanId([0, 0]),
387 dst_address: MacAddress { short: [0, 0] },
388 msdu_length: 0,
389 msdu_handle: 0,
390 ack_tx: 0,
391 gts_tx: false,
392 indirect_tx: 0,
393 security_level: SecurityLevel::Unsecure,
394 key_id_mode: KeyIdMode::Implicite,
395 key_index: 0,
396 key_source: [0u8; 8],
397 uwbprf: 0,
398 ranging: 0,
399 uwb_preamble_symbol_repetitions: 0,
400 datrate: 0,
401 }
402 }
403}
404
405impl MacCommand for DataRequest {
406 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq;
407}
408
409/// for MCPS PURGE Request used to purge an MSDU from the transaction queue
410#[repr(C)]
411#[cfg_attr(feature = "defmt", derive(defmt::Format))]
412pub struct PurgeRequest {
413 /// the handle associated with the MSDU to be purged from the transaction
414 /// queue
415 pub msdu_handle: u8,
416 /// byte stuffing to keep 32 bit alignment
417 pub a_stuffing: [u8; 3],
418}
419
420impl MacCommand for PurgeRequest {
421 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq;
422}
423
424/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication
425#[repr(C)]
426#[derive(Default)]
427#[cfg_attr(feature = "defmt", derive(defmt::Format))]
428pub struct AssociateResponse {
429 /// extended address of the device requesting association
430 pub device_address: [u8; 8],
431 /// 16-bitshort device address allocated by the coordinator on successful
432 /// association
433 pub assoc_short_address: [u8; 2],
434 /// status of the association attempt
435 pub status: MacStatus,
436 /// security level to be used
437 pub security_level: SecurityLevel,
438 /// the originator of the key to be used
439 pub key_source: [u8; 8],
440 /// the mode used to identify the key to be used
441 pub key_id_mode: KeyIdMode,
442 /// the index of the key to be used
443 pub key_index: u8,
444 /// byte stuffing to keep 32 bit alignment
445 pub a_stuffing: [u8; 2],
446}
447
448impl MacCommand for AssociateResponse {
449 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes;
450}
451
452/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication
453#[repr(C)]
454#[cfg_attr(feature = "defmt", derive(defmt::Format))]
455pub struct OrphanResponse {
456 /// extended address of the orphaned device
457 pub orphan_address: [u8; 8],
458 /// short address allocated to the orphaned device
459 pub short_address: [u8; 2],
460 /// if the orphaned device is associated with coordinator or not
461 pub associated_member: bool,
462 /// security level to be used
463 pub security_level: SecurityLevel,
464 /// the originator of the key to be used
465 pub key_source: [u8; 8],
466 /// the mode used to identify the key to be used
467 pub key_id_mode: KeyIdMode,
468 /// the index of the key to be used
469 pub key_index: u8,
470 /// byte stuffing to keep 32 bit alignment
471 pub a_stuffing: [u8; 2],
472}
473
474impl MacCommand for OrphanResponse {
475 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes;
476}
diff --git a/embassy-stm32-wpan/src/mac/consts.rs b/embassy-stm32-wpan/src/mac/consts.rs
new file mode 100644
index 000000000..56903d980
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/consts.rs
@@ -0,0 +1,4 @@
1pub const MAX_PAN_DESC_SUPPORTED: usize = 6;
2pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6;
3pub const MAX_PENDING_ADDRESS: usize = 7;
4pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16;
diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs
new file mode 100644
index 000000000..8a13de81c
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/control.rs
@@ -0,0 +1,95 @@
1use core::future::Future;
2use core::task;
3use core::task::Poll;
4
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::mutex::MutexGuard;
7use embassy_sync::signal::Signal;
8use futures::FutureExt;
9
10use super::commands::MacCommand;
11use super::event::MacEvent;
12use super::typedefs::MacError;
13use crate::mac::runner::Runner;
14
15pub struct Control<'a> {
16 runner: &'a Runner<'a>,
17}
18
19impl<'a> Control<'a> {
20 pub(crate) fn new(runner: &'a Runner<'a>) -> Self {
21 Self { runner: runner }
22 }
23
24 pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError>
25 where
26 T: MacCommand,
27 {
28 let _wm = self.runner.write_mutex.lock().await;
29
30 self.runner.mac_subsystem.send_command(cmd).await
31 }
32
33 pub async fn send_command_and_get_response<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError>
34 where
35 T: MacCommand,
36 {
37 let rm = self.runner.read_mutex.lock().await;
38 let _wm = self.runner.write_mutex.lock().await;
39 let token = EventToken::new(self.runner, rm);
40
41 self.runner.mac_subsystem.send_command(cmd).await?;
42
43 Ok(token)
44 }
45}
46
47pub struct EventToken<'a> {
48 runner: &'a Runner<'a>,
49 _mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>,
50}
51
52impl<'a> EventToken<'a> {
53 pub(crate) fn new(runner: &'a Runner<'a>, mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>) -> Self {
54 // Enable event receiving
55 runner.rx_event_channel.lock(|s| {
56 *s.borrow_mut() = Some(Signal::new());
57 });
58
59 Self {
60 runner: runner,
61 _mutex_guard: mutex_guard,
62 }
63 }
64}
65
66impl<'a> Future for EventToken<'a> {
67 type Output = MacEvent<'a>;
68
69 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
70 self.get_mut().runner.rx_event_channel.lock(|s| {
71 let signal = s.borrow_mut();
72 let signal = match &*signal {
73 Some(s) => s,
74 _ => unreachable!(),
75 };
76
77 let result = match signal.wait().poll_unpin(cx) {
78 Poll::Ready(mac_event) => Poll::Ready(mac_event),
79 Poll::Pending => Poll::Pending,
80 };
81
82 result
83 })
84 }
85}
86
87impl<'a> Drop for EventToken<'a> {
88 fn drop(&mut self) {
89 // Disable event receiving
90 // This will also drop the contained event, if it exists, and will free up receiving the next event
91 self.runner.rx_event_channel.lock(|s| {
92 *s.borrow_mut() = None;
93 });
94 }
95}
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs
new file mode 100644
index 000000000..fffbb9edc
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/driver.rs
@@ -0,0 +1,122 @@
1#![allow(incomplete_features)]
2#![deny(unused_must_use)]
3
4use core::task::Context;
5
6use embassy_net_driver::{Capabilities, LinkState, Medium};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::Channel;
9
10use crate::mac::event::MacEvent;
11use crate::mac::runner::Runner;
12use crate::mac::MTU;
13
14pub struct Driver<'d> {
15 runner: &'d Runner<'d>,
16}
17
18impl<'d> Driver<'d> {
19 pub(crate) fn new(runner: &'d Runner<'d>) -> Self {
20 Self { runner: runner }
21 }
22}
23
24impl<'d> embassy_net_driver::Driver for Driver<'d> {
25 // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
26 // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
27 type RxToken<'a> = RxToken<'d> where Self: 'a;
28 type TxToken<'a> = TxToken<'d> where Self: 'a;
29
30 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
31 if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_buf_channel.poll_ready_to_receive(cx) {
32 Some((
33 RxToken {
34 rx: &self.runner.rx_channel,
35 },
36 TxToken {
37 tx: &self.runner.tx_channel,
38 tx_buf: &self.runner.tx_buf_channel,
39 },
40 ))
41 } else {
42 None
43 }
44 }
45
46 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
47 if self.runner.tx_buf_channel.poll_ready_to_receive(cx) {
48 Some(TxToken {
49 tx: &self.runner.tx_channel,
50 tx_buf: &self.runner.tx_buf_channel,
51 })
52 } else {
53 None
54 }
55 }
56
57 fn capabilities(&self) -> Capabilities {
58 let mut caps = Capabilities::default();
59 caps.max_transmission_unit = MTU;
60 // caps.max_burst_size = Some(self.tx.len());
61
62 caps.medium = Medium::Ieee802154;
63 caps
64 }
65
66 fn link_state(&mut self, _cx: &mut Context) -> LinkState {
67 // if self.phy.poll_link(&mut self.station_management, cx) {
68 // LinkState::Up
69 // } else {
70 // LinkState::Down
71 // }
72
73 LinkState::Down
74 }
75
76 fn ethernet_address(&self) -> [u8; 6] {
77 // self.mac_addr
78
79 [0; 6]
80 }
81}
82
83pub struct RxToken<'d> {
84 rx: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>,
85}
86
87impl<'d> embassy_net_driver::RxToken for RxToken<'d> {
88 fn consume<R, F>(self, f: F) -> R
89 where
90 F: FnOnce(&mut [u8]) -> R,
91 {
92 // Only valid data events should be put into the queue
93
94 let data_event = match self.rx.try_recv().unwrap() {
95 MacEvent::McpsDataInd(data_event) => data_event,
96 _ => unreachable!(),
97 };
98
99 f(&mut data_event.payload())
100 }
101}
102
103pub struct TxToken<'d> {
104 tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), 5>,
105 tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], 5>,
106}
107
108impl<'d> embassy_net_driver::TxToken for TxToken<'d> {
109 fn consume<R, F>(self, len: usize, f: F) -> R
110 where
111 F: FnOnce(&mut [u8]) -> R,
112 {
113 // Only valid tx buffers should be put into the queue
114 let buf = self.tx_buf.try_recv().unwrap();
115 let r = f(&mut buf[..len]);
116
117 // The tx channel should always be of equal capacity to the tx_buf channel
118 self.tx.try_send((buf, len)).unwrap();
119
120 r
121 }
122}
diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs
new file mode 100644
index 000000000..9ca4f5a2a
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/event.rs
@@ -0,0 +1,153 @@
1use core::{mem, ptr};
2
3use super::indications::{
4 AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
5 DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication,
6};
7use super::responses::{
8 AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm,
9 PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm,
10};
11use crate::evt::{EvtBox, MemoryManager};
12use crate::mac::opcodes::OpcodeM0ToM4;
13use crate::sub::mac::{self, Mac};
14
15pub(crate) trait ParseableMacEvent: Sized {
16 fn from_buffer<'a>(buf: &'a [u8]) -> Result<&'a Self, ()> {
17 if buf.len() < mem::size_of::<Self>() {
18 Err(())
19 } else {
20 Ok(unsafe { &*(buf as *const _ as *const Self) })
21 }
22 }
23}
24
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[derive(Debug)]
27pub enum MacEvent<'a> {
28 MlmeAssociateCnf(&'a AssociateConfirm),
29 MlmeDisassociateCnf(&'a DisassociateConfirm),
30 MlmeGetCnf(&'a GetConfirm),
31 MlmeGtsCnf(&'a GtsConfirm),
32 MlmeResetCnf(&'a ResetConfirm),
33 MlmeRxEnableCnf(&'a RxEnableConfirm),
34 MlmeScanCnf(&'a ScanConfirm),
35 MlmeSetCnf(&'a SetConfirm),
36 MlmeStartCnf(&'a StartConfirm),
37 MlmePollCnf(&'a PollConfirm),
38 MlmeDpsCnf(&'a DpsConfirm),
39 MlmeSoundingCnf(&'a SoundingConfirm),
40 MlmeCalibrateCnf(&'a CalibrateConfirm),
41 McpsDataCnf(&'a DataConfirm),
42 McpsPurgeCnf(&'a PurgeConfirm),
43 MlmeAssociateInd(&'a AssociateIndication),
44 MlmeDisassociateInd(&'a DisassociateIndication),
45 MlmeBeaconNotifyInd(&'a BeaconNotifyIndication),
46 MlmeCommStatusInd(&'a CommStatusIndication),
47 MlmeGtsInd(&'a GtsIndication),
48 MlmeOrphanInd(&'a OrphanIndication),
49 MlmeSyncLossInd(&'a SyncLossIndication),
50 MlmeDpsInd(&'a DpsIndication),
51 McpsDataInd(&'a DataIndication),
52 MlmePollInd(&'a PollIndication),
53}
54
55impl<'a> MacEvent<'a> {
56 pub(crate) fn new(event_box: EvtBox<Mac>) -> Result<Self, ()> {
57 let payload = event_box.payload();
58 let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap());
59
60 let opcode = OpcodeM0ToM4::try_from(opcode)?;
61 let buf = &payload[2..];
62
63 // To avoid re-parsing the opcode, we store the result of the parse
64 // this requires use of unsafe because rust cannot assume that a reference will become
65 // invalid when the underlying result is moved. However, because we refer to a "heap"
66 // allocation, the underlying reference will not move until the struct is dropped.
67
68 let mac_event = match opcode {
69 OpcodeM0ToM4::MlmeAssociateCnf => {
70 MacEvent::MlmeAssociateCnf(unsafe { &*(AssociateConfirm::from_buffer(buf)? as *const _) })
71 }
72 OpcodeM0ToM4::MlmeDisassociateCnf => {
73 MacEvent::MlmeDisassociateCnf(unsafe { &*(DisassociateConfirm::from_buffer(buf)? as *const _) })
74 }
75 OpcodeM0ToM4::MlmeGetCnf => MacEvent::MlmeGetCnf(unsafe { &*(GetConfirm::from_buffer(buf)? as *const _) }),
76 OpcodeM0ToM4::MlmeGtsCnf => MacEvent::MlmeGtsCnf(unsafe { &*(GtsConfirm::from_buffer(buf)? as *const _) }),
77 OpcodeM0ToM4::MlmeResetCnf => {
78 MacEvent::MlmeResetCnf(unsafe { &*(ResetConfirm::from_buffer(buf)? as *const _) })
79 }
80 OpcodeM0ToM4::MlmeRxEnableCnf => {
81 MacEvent::MlmeRxEnableCnf(unsafe { &*(RxEnableConfirm::from_buffer(buf)? as *const _) })
82 }
83 OpcodeM0ToM4::MlmeScanCnf => {
84 MacEvent::MlmeScanCnf(unsafe { &*(ScanConfirm::from_buffer(buf)? as *const _) })
85 }
86 OpcodeM0ToM4::MlmeSetCnf => MacEvent::MlmeSetCnf(unsafe { &*(SetConfirm::from_buffer(buf)? as *const _) }),
87 OpcodeM0ToM4::MlmeStartCnf => {
88 MacEvent::MlmeStartCnf(unsafe { &*(StartConfirm::from_buffer(buf)? as *const _) })
89 }
90 OpcodeM0ToM4::MlmePollCnf => {
91 MacEvent::MlmePollCnf(unsafe { &*(PollConfirm::from_buffer(buf)? as *const _) })
92 }
93 OpcodeM0ToM4::MlmeDpsCnf => MacEvent::MlmeDpsCnf(unsafe { &*(DpsConfirm::from_buffer(buf)? as *const _) }),
94 OpcodeM0ToM4::MlmeSoundingCnf => {
95 MacEvent::MlmeSoundingCnf(unsafe { &*(SoundingConfirm::from_buffer(buf)? as *const _) })
96 }
97 OpcodeM0ToM4::MlmeCalibrateCnf => {
98 MacEvent::MlmeCalibrateCnf(unsafe { &*(CalibrateConfirm::from_buffer(buf)? as *const _) })
99 }
100 OpcodeM0ToM4::McpsDataCnf => {
101 MacEvent::McpsDataCnf(unsafe { &*(DataConfirm::from_buffer(buf)? as *const _) })
102 }
103 OpcodeM0ToM4::McpsPurgeCnf => {
104 MacEvent::McpsPurgeCnf(unsafe { &*(PurgeConfirm::from_buffer(buf)? as *const _) })
105 }
106 OpcodeM0ToM4::MlmeAssociateInd => {
107 MacEvent::MlmeAssociateInd(unsafe { &*(AssociateIndication::from_buffer(buf)? as *const _) })
108 }
109 OpcodeM0ToM4::MlmeDisassociateInd => {
110 MacEvent::MlmeDisassociateInd(unsafe { &*(DisassociateIndication::from_buffer(buf)? as *const _) })
111 }
112 OpcodeM0ToM4::MlmeBeaconNotifyInd => {
113 MacEvent::MlmeBeaconNotifyInd(unsafe { &*(BeaconNotifyIndication::from_buffer(buf)? as *const _) })
114 }
115 OpcodeM0ToM4::MlmeCommStatusInd => {
116 MacEvent::MlmeCommStatusInd(unsafe { &*(CommStatusIndication::from_buffer(buf)? as *const _) })
117 }
118 OpcodeM0ToM4::MlmeGtsInd => {
119 MacEvent::MlmeGtsInd(unsafe { &*(GtsIndication::from_buffer(buf)? as *const _) })
120 }
121 OpcodeM0ToM4::MlmeOrphanInd => {
122 MacEvent::MlmeOrphanInd(unsafe { &*(OrphanIndication::from_buffer(buf)? as *const _) })
123 }
124 OpcodeM0ToM4::MlmeSyncLossInd => {
125 MacEvent::MlmeSyncLossInd(unsafe { &*(SyncLossIndication::from_buffer(buf)? as *const _) })
126 }
127 OpcodeM0ToM4::MlmeDpsInd => {
128 MacEvent::MlmeDpsInd(unsafe { &*(DpsIndication::from_buffer(buf)? as *const _) })
129 }
130 OpcodeM0ToM4::McpsDataInd => {
131 MacEvent::McpsDataInd(unsafe { &*(DataIndication::from_buffer(buf)? as *const _) })
132 }
133 OpcodeM0ToM4::MlmePollInd => {
134 MacEvent::MlmePollInd(unsafe { &*(PollIndication::from_buffer(buf)? as *const _) })
135 }
136 };
137
138 // Forget the event box so that drop isn't called
139 // We want to handle the lifetime ourselves
140
141 mem::forget(event_box);
142
143 Ok(mac_event)
144 }
145}
146
147unsafe impl<'a> Send for MacEvent<'a> {}
148
149impl<'a> Drop for MacEvent<'a> {
150 fn drop(&mut self) {
151 unsafe { mac::Mac::drop_event_packet(ptr::null_mut()) };
152 }
153}
diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs
new file mode 100644
index 000000000..c0b86d745
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/indications.rs
@@ -0,0 +1,265 @@
1use core::slice;
2
3use super::consts::MAX_PENDING_ADDRESS;
4use super::event::ParseableMacEvent;
5use super::typedefs::{
6 AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor,
7 PanId, SecurityLevel,
8};
9
10/// MLME ASSOCIATE Indication which will be used by the MAC
11/// to indicate the reception of an association request command
12#[repr(C)]
13#[derive(Debug)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct AssociateIndication {
16 /// Extended address of the device requesting association
17 pub device_address: [u8; 8],
18 /// Operational capabilities of the device requesting association
19 pub capability_information: Capabilities,
20 /// Security level purportedly used by the received MAC command frame
21 pub security_level: SecurityLevel,
22 /// The mode used to identify the key used by the originator of frame
23 pub key_id_mode: KeyIdMode,
24 /// Index of the key used by the originator of the received frame
25 pub key_index: u8,
26 /// The originator of the key used by the originator of the received frame
27 pub key_source: [u8; 8],
28}
29
30impl ParseableMacEvent for AssociateIndication {}
31
32/// MLME DISASSOCIATE indication which will be used to send
33/// disassociation indication to the application.
34#[repr(C)]
35#[derive(Debug)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub struct DisassociateIndication {
38 /// Extended address of the device requesting association
39 pub device_address: [u8; 8],
40 /// The reason for the disassociation
41 pub disassociation_reason: DisassociationReason,
42 /// The security level to be used
43 pub security_level: SecurityLevel,
44 /// The mode used to identify the key to be used
45 pub key_id_mode: KeyIdMode,
46 /// The index of the key to be used
47 pub key_index: u8,
48 /// The originator of the key to be used
49 pub key_source: [u8; 8],
50}
51
52impl ParseableMacEvent for DisassociateIndication {}
53
54/// MLME BEACON NOTIIFY Indication which is used to send parameters contained
55/// within a beacon frame received by the MAC to the application
56#[repr(C)]
57#[derive(Debug)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct BeaconNotifyIndication {
60 /// he set of octets comprising the beacon payload to be transferred
61 /// from the MAC sublayer entity to the next higher layer
62 pub sdu_ptr: *const u8,
63 /// The PAN Descriptor for the received beacon
64 pub pan_descriptor: PanDescriptor,
65 /// The list of addresses of the devices
66 pub addr_list: [MacAddress; MAX_PENDING_ADDRESS],
67 /// Beacon Sequence Number
68 pub bsn: u8,
69 /// The beacon pending address specification
70 pub pend_addr_spec: u8,
71 /// Number of octets contained in the beacon payload of the beacon frame
72 pub sdu_length: u8,
73}
74
75impl ParseableMacEvent for BeaconNotifyIndication {}
76
77/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status
78#[repr(C)]
79#[derive(Debug)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub struct CommStatusIndication {
82 /// The 16-bit PAN identifier of the device from which the frame
83 /// was received or to which the frame was being sent
84 pub pan_id: PanId,
85 /// Source addressing mode
86 pub src_addr_mode: AddressMode,
87 /// Destination addressing mode
88 pub dst_addr_mode: AddressMode,
89 /// Source address
90 pub src_address: MacAddress,
91 /// Destination address
92 pub dst_address: MacAddress,
93 /// The communications status
94 pub status: MacStatus,
95 /// Security level to be used
96 pub security_level: SecurityLevel,
97 /// Mode used to identify the key to be used
98 pub key_id_mode: KeyIdMode,
99 /// Index of the key to be used
100 pub key_index: u8,
101 /// Originator of the key to be used
102 pub key_source: [u8; 8],
103}
104
105impl ParseableMacEvent for CommStatusIndication {}
106
107/// MLME GTS Indication indicates that a GTS has been allocated or that a
108/// previously allocated GTS has been deallocated
109#[repr(C)]
110#[derive(Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub struct GtsIndication {
113 /// The short address of the device that has been allocated or deallocated a GTS
114 pub device_address: [u8; 2],
115 /// The characteristics of the GTS
116 pub gts_characteristics: u8,
117 /// Security level to be used
118 pub security_level: SecurityLevel,
119 /// Mode used to identify the key to be used
120 pub key_id_mode: KeyIdMode,
121 /// Index of the key to be used
122 pub key_index: u8,
123 /// byte stuffing to keep 32 bit alignment
124 a_stuffing: [u8; 2],
125 /// Originator of the key to be used
126 pub key_source: [u8; 8],
127}
128
129impl ParseableMacEvent for GtsIndication {}
130
131/// MLME ORPHAN Indication which is used by the coordinator to notify the
132/// application of the presence of an orphaned device
133#[repr(C)]
134#[derive(Debug)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136pub struct OrphanIndication {
137 /// Extended address of the orphaned device
138 pub orphan_address: [u8; 8],
139 /// Originator of the key used by the originator of the received frame
140 pub key_source: [u8; 8],
141 /// Security level purportedly used by the received MAC command frame
142 pub security_level: SecurityLevel,
143 /// Mode used to identify the key used by originator of received frame
144 pub key_id_mode: KeyIdMode,
145 /// Index of the key used by the originator of the received frame
146 pub key_index: u8,
147 /// byte stuffing to keep 32 bit alignment
148 a_stuffing: [u8; 1],
149}
150
151impl ParseableMacEvent for OrphanIndication {}
152
153/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss
154/// of synchronization with the coordinator
155#[repr(C)]
156#[derive(Debug)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct SyncLossIndication {
159 /// The PAN identifier with which the device lost synchronization or to which it was realigned
160 pub pan_id: PanId,
161 /// The reason that synchronization was lost
162 pub loss_reason: u8,
163 /// The logical channel on which the device lost synchronization or to whi
164 pub channel_number: MacChannel,
165 /// The channel page on which the device lost synchronization or to which
166 pub channel_page: u8,
167 /// The security level used by the received MAC frame
168 pub security_level: SecurityLevel,
169 /// Mode used to identify the key used by originator of received frame
170 pub key_id_mode: KeyIdMode,
171 /// Index of the key used by the originator of the received frame
172 pub key_index: u8,
173 /// Originator of the key used by the originator of the received frame
174 pub key_source: [u8; 8],
175}
176
177impl ParseableMacEvent for SyncLossIndication {}
178
179/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration
180/// and the resetting of the DPS values in the PHY
181#[repr(C)]
182#[derive(Debug)]
183#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub struct DpsIndication {
185 /// byte stuffing to keep 32 bit alignment
186 a_stuffing: [u8; 4],
187}
188
189impl ParseableMacEvent for DpsIndication {}
190
191#[repr(C)]
192#[derive(Debug)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194pub struct DataIndication {
195 /// Pointer to the set of octets forming the MSDU being indicated
196 pub msdu_ptr: *const u8,
197 /// Source addressing mode used
198 pub src_addr_mode: AddressMode,
199 /// Source PAN ID
200 pub src_pan_id: PanId,
201 /// Source address
202 pub src_address: MacAddress,
203 /// Destination addressing mode used
204 pub dst_addr_mode: AddressMode,
205 /// Destination PAN ID
206 pub dst_pan_id: PanId,
207 /// Destination address
208 pub dst_address: MacAddress,
209 /// The number of octets contained in the MSDU being indicated
210 pub msdu_length: u8,
211 /// QI value measured during reception of the MPDU
212 pub mpdu_link_quality: u8,
213 /// The data sequence number of the received data frame
214 pub dsn: u8,
215 /// The time, in symbols, at which the data were received
216 pub time_stamp: [u8; 4],
217 /// The security level purportedly used by the received data frame
218 security_level: SecurityLevel,
219 /// Mode used to identify the key used by originator of received frame
220 key_id_mode: KeyIdMode,
221 /// The originator of the key
222 pub key_source: [u8; 8],
223 /// The index of the key
224 pub key_index: u8,
225 /// he pulse repetition value of the received PPDU
226 pub uwbprf: u8,
227 /// The preamble symbol repetitions of the UWB PHY frame
228 pub uwn_preamble_symbol_repetitions: u8,
229 /// Indicates the data rate
230 pub datrate: u8,
231 /// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange,
232 pub ranging_received: u8,
233 pub ranging_counter_start: u32,
234 pub ranging_counter_stop: u32,
235 /// ime units in a message exchange over which the tracking offset was measured
236 pub ranging_tracking_interval: u32,
237 /// time units slipped or advanced by the radio tracking system
238 pub ranging_offset: u32,
239 /// The FoM characterizing the ranging measurement
240 pub ranging_fom: u8,
241 /// The Received Signal Strength Indicator measured
242 pub rssi: u8,
243}
244
245impl ParseableMacEvent for DataIndication {}
246
247impl DataIndication {
248 pub fn payload<'a>(&'a self) -> &'a mut [u8] {
249 unsafe { slice::from_raw_parts_mut(self.msdu_ptr as *mut _, self.msdu_length as usize) }
250 }
251}
252
253/// MLME POLL Indication which will be used for indicating the Data Request
254/// reception to upper layer as defined in Zigbee r22 - D.8.2
255#[repr(C)]
256#[derive(Debug)]
257#[cfg_attr(feature = "defmt", derive(defmt::Format))]
258pub struct PollIndication {
259 /// addressing mode used
260 pub addr_mode: AddressMode,
261 /// Poll requester address
262 pub request_address: MacAddress,
263}
264
265impl ParseableMacEvent for PollIndication {}
diff --git a/embassy-stm32-wpan/src/mac/macros.rs b/embassy-stm32-wpan/src/mac/macros.rs
new file mode 100644
index 000000000..1a988a779
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/macros.rs
@@ -0,0 +1,32 @@
1#[macro_export]
2macro_rules! numeric_enum {
3 (#[repr($repr:ident)]
4 $(#$attrs:tt)* $vis:vis enum $name:ident {
5 $($(#$enum_attrs:tt)* $enum:ident = $constant:expr),* $(,)?
6 } ) => {
7 #[repr($repr)]
8 $(#$attrs)*
9 $vis enum $name {
10 $($(#$enum_attrs)* $enum = $constant),*
11 }
12
13 impl ::core::convert::TryFrom<$repr> for $name {
14 type Error = ();
15
16 fn try_from(value: $repr) -> ::core::result::Result<Self, ()> {
17 match value {
18 $($constant => Ok( $name :: $enum ),)*
19 _ => Err(())
20 }
21 }
22 }
23
24 impl ::core::convert::From<$name> for $repr {
25 fn from(value: $name) -> $repr {
26 match value {
27 $($name :: $enum => $constant,)*
28 }
29 }
30 }
31 }
32}
diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs
new file mode 100644
index 000000000..c847a5cca
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/mod.rs
@@ -0,0 +1,21 @@
1pub mod commands;
2mod consts;
3pub mod control;
4mod driver;
5pub mod event;
6pub mod indications;
7mod macros;
8mod opcodes;
9pub mod responses;
10pub mod runner;
11pub mod typedefs;
12
13pub use crate::mac::control::Control;
14use crate::mac::driver::Driver;
15pub use crate::mac::runner::Runner;
16
17const MTU: usize = 127;
18
19pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) {
20 (Control::new(runner), Driver::new(runner))
21}
diff --git a/embassy-stm32-wpan/src/mac/opcodes.rs b/embassy-stm32-wpan/src/mac/opcodes.rs
new file mode 100644
index 000000000..fd7011873
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/opcodes.rs
@@ -0,0 +1,92 @@
1const ST_VENDOR_OGF: u16 = 0x3F;
2const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280;
3
4const fn opcode(ocf: u16) -> isize {
5 ((ST_VENDOR_OGF << 9) | (MAC_802_15_4_CMD_OPCODE_OFFSET + ocf)) as isize
6}
7
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum OpcodeM4ToM0 {
10 MlmeAssociateReq = opcode(0x00),
11 MlmeAssociateRes = opcode(0x01),
12 MlmeDisassociateReq = opcode(0x02),
13 MlmeGetReq = opcode(0x03),
14 MlmeGtsReq = opcode(0x04),
15 MlmeOrphanRes = opcode(0x05),
16 MlmeResetReq = opcode(0x06),
17 MlmeRxEnableReq = opcode(0x07),
18 MlmeScanReq = opcode(0x08),
19 MlmeSetReq = opcode(0x09),
20 MlmeStartReq = opcode(0x0A),
21 MlmeSyncReq = opcode(0x0B),
22 MlmePollReq = opcode(0x0C),
23 MlmeDpsReq = opcode(0x0D),
24 MlmeSoundingReq = opcode(0x0E),
25 MlmeCalibrateReq = opcode(0x0F),
26 McpsDataReq = opcode(0x10),
27 McpsPurgeReq = opcode(0x11),
28}
29
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum OpcodeM0ToM4 {
32 MlmeAssociateCnf = 0x00,
33 MlmeDisassociateCnf,
34 MlmeGetCnf,
35 MlmeGtsCnf,
36 MlmeResetCnf,
37 MlmeRxEnableCnf,
38 MlmeScanCnf,
39 MlmeSetCnf,
40 MlmeStartCnf,
41 MlmePollCnf,
42 MlmeDpsCnf,
43 MlmeSoundingCnf,
44 MlmeCalibrateCnf,
45 McpsDataCnf,
46 McpsPurgeCnf,
47 MlmeAssociateInd,
48 MlmeDisassociateInd,
49 MlmeBeaconNotifyInd,
50 MlmeCommStatusInd,
51 MlmeGtsInd,
52 MlmeOrphanInd,
53 MlmeSyncLossInd,
54 MlmeDpsInd,
55 McpsDataInd,
56 MlmePollInd,
57}
58
59impl TryFrom<u16> for OpcodeM0ToM4 {
60 type Error = ();
61
62 fn try_from(value: u16) -> Result<Self, Self::Error> {
63 match value {
64 0 => Ok(Self::MlmeAssociateCnf),
65 1 => Ok(Self::MlmeDisassociateCnf),
66 2 => Ok(Self::MlmeGetCnf),
67 3 => Ok(Self::MlmeGtsCnf),
68 4 => Ok(Self::MlmeResetCnf),
69 5 => Ok(Self::MlmeRxEnableCnf),
70 6 => Ok(Self::MlmeScanCnf),
71 7 => Ok(Self::MlmeSetCnf),
72 8 => Ok(Self::MlmeStartCnf),
73 9 => Ok(Self::MlmePollCnf),
74 10 => Ok(Self::MlmeDpsCnf),
75 11 => Ok(Self::MlmeSoundingCnf),
76 12 => Ok(Self::MlmeCalibrateCnf),
77 13 => Ok(Self::McpsDataCnf),
78 14 => Ok(Self::McpsPurgeCnf),
79 15 => Ok(Self::MlmeAssociateInd),
80 16 => Ok(Self::MlmeDisassociateInd),
81 17 => Ok(Self::MlmeBeaconNotifyInd),
82 18 => Ok(Self::MlmeCommStatusInd),
83 19 => Ok(Self::MlmeGtsInd),
84 20 => Ok(Self::MlmeOrphanInd),
85 21 => Ok(Self::MlmeSyncLossInd),
86 22 => Ok(Self::MlmeDpsInd),
87 23 => Ok(Self::McpsDataInd),
88 24 => Ok(Self::MlmePollInd),
89 _ => Err(()),
90 }
91 }
92}
diff --git a/embassy-stm32-wpan/src/mac/responses.rs b/embassy-stm32-wpan/src/mac/responses.rs
new file mode 100644
index 000000000..544fdaae8
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/responses.rs
@@ -0,0 +1,273 @@
1use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED};
2use super::event::ParseableMacEvent;
3use super::typedefs::{
4 AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType,
5 SecurityLevel,
6};
7
8/// MLME ASSOCIATE Confirm used to inform of the initiating device whether
9/// its request to associate was successful or unsuccessful
10#[repr(C)]
11#[derive(Debug)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct AssociateConfirm {
14 /// short address allocated by the coordinator on successful association
15 pub assoc_short_address: [u8; 2],
16 /// status of the association request
17 pub status: AssociationStatus,
18 /// security level to be used
19 pub security_level: SecurityLevel,
20 /// the originator of the key to be used
21 pub key_source: [u8; 8],
22 /// the mode used to identify the key to be used
23 pub key_id_mode: KeyIdMode,
24 /// the index of the key to be used
25 pub key_index: u8,
26 /// byte stuffing to keep 32 bit alignment
27 a_stuffing: [u8; 2],
28}
29
30impl ParseableMacEvent for AssociateConfirm {}
31
32/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application.
33#[repr(C)]
34#[derive(Debug)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct DisassociateConfirm {
37 /// status of the disassociation attempt
38 pub status: MacStatus,
39 /// device addressing mode used
40 pub device_addr_mode: AddressMode,
41 /// the identifier of the PAN of the device
42 pub device_pan_id: PanId,
43 /// device address
44 pub device_address: MacAddress,
45}
46
47impl ParseableMacEvent for DisassociateConfirm {}
48
49/// MLME GET Confirm which requests information about a given PIB attribute
50#[repr(C)]
51#[derive(Debug)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub struct GetConfirm {
54 /// The pointer to the value of the PIB attribute attempted to read
55 pub pib_attribute_value_ptr: *const u8,
56 /// Status of the GET attempt
57 pub status: MacStatus,
58 /// The name of the PIB attribute attempted to read
59 pub pib_attribute: PibId,
60 /// The lenght of the PIB attribute Value return
61 pub pib_attribute_value_len: u8,
62 /// byte stuffing to keep 32 bit alignment
63 a_stuffing: [u8; 1],
64}
65
66impl ParseableMacEvent for GetConfirm {}
67
68/// MLME GTS Confirm which eports the results of a request to allocate a new GTS
69/// or to deallocate an existing GTS
70#[repr(C)]
71#[derive(Debug)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct GtsConfirm {
74 /// The characteristics of the GTS
75 pub gts_characteristics: u8,
76 /// The status of the GTS reques
77 pub status: MacStatus,
78 /// byte stuffing to keep 32 bit alignment
79 a_stuffing: [u8; 2],
80}
81
82impl ParseableMacEvent for GtsConfirm {}
83
84/// MLME RESET Confirm which is used to report the results of the reset operation
85#[repr(C)]
86#[derive(Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub struct ResetConfirm {
89 /// The result of the reset operation
90 pub status: MacStatus,
91 /// byte stuffing to keep 32 bit alignment
92 a_stuffing: [u8; 3],
93}
94
95impl ParseableMacEvent for ResetConfirm {}
96
97/// MLME RX ENABLE Confirm which is used to report the results of the attempt
98/// to enable or disable the receiver
99#[repr(C)]
100#[derive(Debug)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct RxEnableConfirm {
103 /// Result of the request to enable or disable the receiver
104 pub status: MacStatus,
105 /// byte stuffing to keep 32 bit alignment
106 a_stuffing: [u8; 3],
107}
108
109impl ParseableMacEvent for RxEnableConfirm {}
110
111/// MLME SCAN Confirm which is used to report the result of the channel scan request
112#[repr(C)]
113#[derive(Debug)]
114#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115pub struct ScanConfirm {
116 /// Status of the scan request
117 pub status: MacStatus,
118 /// The type of scan performed
119 pub scan_type: ScanType,
120 /// Channel page on which the scan was performed
121 pub channel_page: u8,
122 /// Channels given in the request which were not scanned
123 pub unscanned_channels: [u8; 4],
124 /// Number of elements returned in the appropriate result lists
125 pub result_list_size: u8,
126 /// List of energy measurements
127 pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
128 /// List of PAN descriptors
129 pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED],
130 /// Categorization of energy detected in channel
131 pub detected_category: u8,
132 /// For UWB PHYs, the list of energy measurements taken
133 pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
134}
135
136impl ParseableMacEvent for ScanConfirm {}
137
138/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute
139#[repr(C)]
140#[derive(Debug)]
141#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142pub struct SetConfirm {
143 /// The result of the set operation
144 pub status: MacStatus,
145 /// The name of the PIB attribute that was written
146 pub pin_attribute: PibId,
147 /// byte stuffing to keep 32 bit alignment
148 a_stuffing: [u8; 2],
149}
150
151impl ParseableMacEvent for SetConfirm {}
152
153/// MLME START Confirm which is used to report the results of the attempt to
154/// start using a new superframe configuration
155#[repr(C)]
156#[derive(Debug)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct StartConfirm {
159 /// Result of the attempt to start using an updated superframe configuration
160 pub status: MacStatus,
161 /// byte stuffing to keep 32 bit alignment
162 a_stuffing: [u8; 3],
163}
164
165impl ParseableMacEvent for StartConfirm {}
166
167/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data
168#[repr(C)]
169#[derive(Debug)]
170#[cfg_attr(feature = "defmt", derive(defmt::Format))]
171pub struct PollConfirm {
172 /// The status of the data request
173 pub status: MacStatus,
174 /// byte stuffing to keep 32 bit alignment
175 a_stuffing: [u8; 3],
176}
177
178impl ParseableMacEvent for PollConfirm {}
179
180/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS
181#[repr(C)]
182#[derive(Debug)]
183#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub struct DpsConfirm {
185 /// The status of the DPS request
186 pub status: MacStatus,
187 /// byte stuffing to keep 32 bit alignment
188 a_stuffing: [u8; 3],
189}
190
191impl ParseableMacEvent for DpsConfirm {}
192
193/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide
194/// channel sounding information
195#[repr(C)]
196#[derive(Debug)]
197#[cfg_attr(feature = "defmt", derive(defmt::Format))]
198pub struct SoundingConfirm {
199 /// Results of the sounding measurement
200 pub sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
201
202 status: u8,
203}
204
205impl ParseableMacEvent for SoundingConfirm {}
206
207/// MLME CALIBRATE Confirm which reports the result of a request to the PHY
208/// to provide internal propagation path information
209#[repr(C)]
210#[derive(Debug)]
211#[cfg_attr(feature = "defmt", derive(defmt::Format))]
212pub struct CalibrateConfirm {
213 /// The status of the attempt to return sounding data
214 pub status: MacStatus,
215 /// byte stuffing to keep 32 bit alignment
216 a_stuffing: [u8; 3],
217 /// A count of the propagation time from the ranging counter
218 /// to the transmit antenna
219 pub cal_tx_rmaker_offset: u32,
220 /// A count of the propagation time from the receive antenna
221 /// to the ranging counter
222 pub cal_rx_rmaker_offset: u32,
223}
224
225impl ParseableMacEvent for CalibrateConfirm {}
226
227/// MCPS DATA Confirm which will be used for reporting the results of
228/// MAC data related requests from the application
229#[repr(C)]
230#[derive(Debug)]
231#[cfg_attr(feature = "defmt", derive(defmt::Format))]
232pub struct DataConfirm {
233 /// The handle associated with the MSDU being confirmed
234 pub msdu_handle: u8,
235 /// The time, in symbols, at which the data were transmitted
236 pub time_stamp: [u8; 4],
237 /// ranging status
238 pub ranging_received: u8,
239 /// The status of the last MSDU transmission
240 pub status: MacStatus,
241 /// time units corresponding to an RMARKER at the antenna at
242 /// the beginning of a ranging exchange
243 pub ranging_counter_start: u32,
244 /// time units corresponding to an RMARKER at the antenna
245 /// at the end of a ranging exchange
246 pub ranging_counter_stop: u32,
247 /// time units in a message exchange over which the tracking offset was measured
248 pub ranging_tracking_interval: u32,
249 /// time units slipped or advanced by the radio tracking system
250 pub ranging_offset: u32,
251 /// The FoM characterizing the ranging measurement
252 pub ranging_fom: u8,
253 /// byte stuffing to keep 32 bit alignment
254 a_stuffing: [u8; 3],
255}
256
257impl ParseableMacEvent for DataConfirm {}
258
259/// MCPS PURGE Confirm which will be used by the MAC to notify the application of
260/// the status of its request to purge an MSDU from the transaction queue
261#[repr(C)]
262#[derive(Debug)]
263#[cfg_attr(feature = "defmt", derive(defmt::Format))]
264pub struct PurgeConfirm {
265 /// Handle associated with the MSDU requested to be purged from the transaction queue
266 pub msdu_handle: u8,
267 /// The status of the request
268 pub status: MacStatus,
269 /// byte stuffing to keep 32 bit alignment
270 a_stuffing: [u8; 2],
271}
272
273impl ParseableMacEvent for PurgeConfirm {}
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs
new file mode 100644
index 000000000..1be6df8a4
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/runner.rs
@@ -0,0 +1,109 @@
1use core::cell::RefCell;
2
3use embassy_futures::join;
4use embassy_sync::blocking_mutex;
5use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
6use embassy_sync::channel::Channel;
7use embassy_sync::mutex::Mutex;
8use embassy_sync::signal::Signal;
9
10use crate::mac::commands::DataRequest;
11use crate::mac::event::MacEvent;
12use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel};
13use crate::mac::MTU;
14use crate::sub::mac::Mac;
15
16type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>;
17
18pub struct Runner<'a> {
19 pub(crate) mac_subsystem: Mac,
20 // rx event backpressure is already provided through the MacEvent drop mechanism
21 // therefore, we don't need to worry about overwriting events
22 pub(crate) rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>,
23 pub(crate) read_mutex: Mutex<CriticalSectionRawMutex, ()>,
24 pub(crate) write_mutex: Mutex<CriticalSectionRawMutex, ()>,
25 pub(crate) rx_channel: Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>,
26 pub(crate) tx_channel: Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), 5>,
27 pub(crate) tx_buf_channel: Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], 5>,
28}
29
30impl<'a> Runner<'a> {
31 pub fn new(mac: Mac, tx_buf_queue: [&'a mut [u8; MTU]; 5]) -> Self {
32 let this = Self {
33 mac_subsystem: mac,
34 rx_event_channel: blocking_mutex::Mutex::new(RefCell::new(None)),
35 read_mutex: Mutex::new(()),
36 write_mutex: Mutex::new(()),
37 rx_channel: Channel::new(),
38 tx_channel: Channel::new(),
39 tx_buf_channel: Channel::new(),
40 };
41
42 for buf in tx_buf_queue {
43 this.tx_buf_channel.try_send(buf).unwrap();
44 }
45
46 this
47 }
48
49 pub async fn run(&'a self) -> ! {
50 join::join(
51 async {
52 loop {
53 if let Ok(mac_event) = self.mac_subsystem.read().await {
54 match mac_event {
55 MacEvent::McpsDataInd(_) => {
56 self.rx_channel.send(mac_event).await;
57 }
58 _ => {
59 self.rx_event_channel.lock(|s| {
60 match &*s.borrow() {
61 Some(signal) => {
62 signal.signal(mac_event);
63 }
64 None => {}
65 };
66 });
67 }
68 }
69 }
70 }
71 },
72 async {
73 let mut msdu_handle = 0x02;
74
75 loop {
76 let (buf, len) = self.tx_channel.recv().await;
77 let _wm = self.write_mutex.lock().await;
78
79 // The mutex should be dropped on the next loop iteration
80 self.mac_subsystem
81 .send_command(
82 DataRequest {
83 src_addr_mode: AddressMode::Short,
84 dst_addr_mode: AddressMode::Short,
85 dst_pan_id: PanId([0x1A, 0xAA]),
86 dst_address: MacAddress::BROADCAST,
87 msdu_handle: msdu_handle,
88 ack_tx: 0x00,
89 gts_tx: false,
90 security_level: SecurityLevel::Unsecure,
91 ..Default::default()
92 }
93 .set_buffer(&buf[..len]),
94 )
95 .await
96 .unwrap();
97
98 msdu_handle = msdu_handle.wrapping_add(1);
99
100 // The tx channel should always be of equal capacity to the tx_buf channel
101 self.tx_buf_channel.try_send(buf).unwrap();
102 }
103 },
104 )
105 .await;
106
107 loop {}
108 }
109}
diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs
new file mode 100644
index 000000000..0552b8ea1
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/typedefs.rs
@@ -0,0 +1,381 @@
1use core::fmt::Debug;
2
3use crate::numeric_enum;
4
5#[derive(Debug)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub enum MacError {
8 Error = 0x01,
9 NotImplemented = 0x02,
10 NotSupported = 0x03,
11 HardwareNotSupported = 0x04,
12 Undefined = 0x05,
13}
14
15impl From<u8> for MacError {
16 fn from(value: u8) -> Self {
17 match value {
18 0x01 => Self::Error,
19 0x02 => Self::NotImplemented,
20 0x03 => Self::NotSupported,
21 0x04 => Self::HardwareNotSupported,
22 0x05 => Self::Undefined,
23 _ => Self::Undefined,
24 }
25 }
26}
27
28numeric_enum! {
29 #[repr(u8)]
30 #[derive(Debug, Default)]
31 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
32 pub enum MacStatus {
33 #[default]
34 Success = 0x00,
35 Failure = 0xFF
36 }
37}
38
39numeric_enum! {
40 #[repr(u8)]
41 /// this enum contains all the MAC PIB Ids
42 #[derive(Default, Debug)]
43 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
44 pub enum PibId {
45 // PHY
46 #[default]
47 CurrentChannel = 0x00,
48 ChannelsSupported = 0x01,
49 TransmitPower = 0x02,
50 CCAMode = 0x03,
51 CurrentPage = 0x04,
52 MaxFrameDuration = 0x05,
53 SHRDuration = 0x06,
54 SymbolsPerOctet = 0x07,
55
56 // MAC
57 AckWaitDuration = 0x40,
58 AssociationPermit = 0x41,
59 AutoRequest = 0x42,
60 BeaconPayload = 0x45,
61 BeaconPayloadLength = 0x46,
62 BeaconOrder = 0x47,
63 Bsn = 0x49,
64 CoordExtendedAdddress = 0x4A,
65 CoordShortAddress = 0x4B,
66 Dsn = 0x4C,
67 MaxFrameTotalWaitTime = 0x58,
68 MaxFrameRetries = 0x59,
69 PanId = 0x50,
70 ResponseWaitTime = 0x5A,
71 RxOnWhenIdle = 0x52,
72 SecurityEnabled = 0x5D,
73 ShortAddress = 0x53,
74 SuperframeOrder = 0x54,
75 TimestampSupported = 0x5C,
76 TransactionPersistenceTime = 0x55,
77 MaxBe = 0x57,
78 LifsPeriod = 0x5E,
79 SifsPeriod = 0x5F,
80 MaxCsmaBackoffs = 0x4E,
81 MinBe = 0x4F,
82 PanCoordinator = 0x10,
83 AssocPanCoordinator = 0x11,
84 ExtendedAddress = 0x6F,
85 AclEntryDescriptor = 0x70,
86 AclEntryDescriptorSize = 0x71,
87 DefaultSecurity = 0x72,
88 DefaultSecurityMaterialLength = 0x73,
89 DefaultSecurityMaterial = 0x74,
90 DefaultSecuritySuite = 0x75,
91 SecurityMode = 0x76,
92 CurrentAclEntries = 0x80,
93 DefaultSecurityExtendedAddress = 0x81,
94 AssociatedPanCoordinator = 0x56,
95 PromiscuousMode = 0x51,
96 }
97}
98
99numeric_enum! {
100 #[repr(u8)]
101 #[derive(Default, Clone, Copy, Debug)]
102 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
103 pub enum AddressMode {
104 #[default]
105 NoAddress = 0x00,
106 Reserved = 0x01,
107 Short = 0x02,
108 Extended = 0x03,
109}
110}
111
112#[derive(Clone, Copy)]
113pub union MacAddress {
114 pub short: [u8; 2],
115 pub extended: [u8; 8],
116}
117
118impl Debug for MacAddress {
119 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120 unsafe {
121 write!(
122 fmt,
123 "MacAddress {{ short: {:?}, extended: {:?} }}",
124 self.short, self.extended
125 )
126 }
127 }
128}
129
130#[cfg(feature = "defmt")]
131impl defmt::Format for MacAddress {
132 fn format(&self, fmt: defmt::Formatter) {
133 unsafe {
134 defmt::write!(
135 fmt,
136 "MacAddress {{ short: {}, extended: {} }}",
137 self.short,
138 self.extended
139 )
140 }
141 }
142}
143
144impl Default for MacAddress {
145 fn default() -> Self {
146 Self { short: [0, 0] }
147 }
148}
149
150impl MacAddress {
151 pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] };
152}
153
154impl TryFrom<&[u8]> for MacAddress {
155 type Error = ();
156
157 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
158 const SIZE: usize = 8;
159 if buf.len() < SIZE {
160 return Err(());
161 }
162
163 Ok(Self {
164 extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
165 })
166 }
167}
168
169#[cfg_attr(feature = "defmt", derive(defmt::Format))]
170pub struct GtsCharacteristics {
171 pub fields: u8,
172}
173
174/// MAC PAN Descriptor which contains the network details of the device from
175/// which the beacon is received
176#[derive(Default, Clone, Copy, Debug)]
177#[cfg_attr(feature = "defmt", derive(defmt::Format))]
178pub struct PanDescriptor {
179 /// PAN identifier of the coordinator
180 pub coord_pan_id: PanId,
181 /// Coordinator addressing mode
182 pub coord_addr_mode: AddressMode,
183 /// The current logical channel occupied by the network
184 pub logical_channel: MacChannel,
185 /// Coordinator address
186 pub coord_addr: MacAddress,
187 /// The current channel page occupied by the network
188 pub channel_page: u8,
189 /// PAN coordinator is accepting GTS requests or not
190 pub gts_permit: bool,
191 /// Superframe specification as specified in the received beacon frame
192 pub superframe_spec: [u8; 2],
193 /// The time at which the beacon frame was received, in symbols
194 pub time_stamp: [u8; 4],
195 /// The LQI at which the network beacon was received
196 pub link_quality: u8,
197 /// Security level purportedly used by the received beacon frame
198 pub security_level: u8,
199}
200
201impl TryFrom<&[u8]> for PanDescriptor {
202 type Error = ();
203
204 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
205 const SIZE: usize = 22;
206 if buf.len() < SIZE {
207 return Err(());
208 }
209
210 let coord_addr_mode = AddressMode::try_from(buf[2])?;
211 let coord_addr = match coord_addr_mode {
212 AddressMode::NoAddress => MacAddress { short: [0, 0] },
213 AddressMode::Reserved => MacAddress { short: [0, 0] },
214 AddressMode::Short => MacAddress {
215 short: [buf[4], buf[5]],
216 },
217 AddressMode::Extended => MacAddress {
218 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
219 },
220 };
221
222 Ok(Self {
223 coord_pan_id: PanId([buf[0], buf[1]]),
224 coord_addr_mode,
225 logical_channel: MacChannel::try_from(buf[3])?,
226 coord_addr,
227 channel_page: buf[12],
228 gts_permit: buf[13] != 0,
229 superframe_spec: [buf[14], buf[15]],
230 time_stamp: [buf[16], buf[17], buf[18], buf[19]],
231 link_quality: buf[20],
232 security_level: buf[21],
233 // 2 byte stuffing
234 })
235 }
236}
237
238numeric_enum! {
239 #[repr(u8)]
240 #[derive(Default, Clone, Copy, Debug)]
241 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
242 /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3
243 pub enum MacChannel {
244 Channel11 = 0x0B,
245 Channel12 = 0x0C,
246 Channel13 = 0x0D,
247 Channel14 = 0x0E,
248 Channel15 = 0x0F,
249 #[default]
250 Channel16 = 0x10,
251 Channel17 = 0x11,
252 Channel18 = 0x12,
253 Channel19 = 0x13,
254 Channel20 = 0x14,
255 Channel21 = 0x15,
256 Channel22 = 0x16,
257 Channel23 = 0x17,
258 Channel24 = 0x18,
259 Channel25 = 0x19,
260 Channel26 = 0x1A,
261 }
262}
263
264#[cfg(not(feature = "defmt"))]
265bitflags::bitflags! {
266 pub struct Capabilities: u8 {
267 /// 1 if the device is capabaleof becoming a PAN coordinator
268 const IS_COORDINATOR_CAPABLE = 0b00000001;
269 /// 1 if the device is an FFD, 0 if it is an RFD
270 const IS_FFD = 0b00000010;
271 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
272 const IS_MAINS_POWERED = 0b00000100;
273 /// 1 if the device does not disable its receiver to conserver power during idle periods
274 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
275 // 0b00010000 reserved
276 // 0b00100000 reserved
277 /// 1 if the device is capable of sending and receiving secured MAC frames
278 const IS_SECURE = 0b01000000;
279 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
280 const ALLOCATE_ADDRESS = 0b10000000;
281 }
282}
283
284#[cfg(feature = "defmt")]
285defmt::bitflags! {
286 pub struct Capabilities: u8 {
287 /// 1 if the device is capabaleof becoming a PAN coordinator
288 const IS_COORDINATOR_CAPABLE = 0b00000001;
289 /// 1 if the device is an FFD, 0 if it is an RFD
290 const IS_FFD = 0b00000010;
291 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
292 const IS_MAINS_POWERED = 0b00000100;
293 /// 1 if the device does not disable its receiver to conserver power during idle periods
294 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
295 // 0b00010000 reserved
296 // 0b00100000 reserved
297 /// 1 if the device is capable of sending and receiving secured MAC frames
298 const IS_SECURE = 0b01000000;
299 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
300 const ALLOCATE_ADDRESS = 0b10000000;
301 }
302}
303
304numeric_enum! {
305 #[repr(u8)]
306 #[derive(Default, Clone, Copy, Debug)]
307 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
308 pub enum KeyIdMode {
309 #[default]
310 /// the key is determined implicitly from the originator and recipient(s) of the frame
311 Implicite = 0x00,
312 /// the key is determined explicitly using a 1 bytes key source and a 1 byte key index
313 Explicite1Byte = 0x01,
314 /// the key is determined explicitly using a 4 bytes key source and a 1 byte key index
315 Explicite4Byte = 0x02,
316 /// the key is determined explicitly using a 8 bytes key source and a 1 byte key index
317 Explicite8Byte = 0x03,
318 }
319}
320
321numeric_enum! {
322 #[repr(u8)]
323 #[derive(Debug)]
324 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
325 pub enum AssociationStatus {
326 /// Association successful
327 Success = 0x00,
328 /// PAN at capacity
329 PanAtCapacity = 0x01,
330 /// PAN access denied
331 PanAccessDenied = 0x02
332 }
333}
334
335numeric_enum! {
336 #[repr(u8)]
337 #[derive(Clone, Copy, Debug)]
338 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
339 pub enum DisassociationReason {
340 /// The coordinator wishes the device to leave the PAN.
341 CoordRequested = 0x01,
342 /// The device wishes to leave the PAN.
343 DeviceRequested = 0x02,
344 }
345}
346
347numeric_enum! {
348 #[repr(u8)]
349 #[derive(Default, Clone, Copy, Debug)]
350 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
351 pub enum SecurityLevel {
352 /// MAC Unsecured Mode Security
353 #[default]
354 Unsecure = 0x00,
355 /// MAC ACL Mode Security
356 AclMode = 0x01,
357 /// MAC Secured Mode Security
358 Secured = 0x02,
359 }
360}
361
362numeric_enum! {
363 #[repr(u8)]
364 #[derive(Debug)]
365 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
366 pub enum ScanType {
367 EdScan = 0x00,
368 Active = 0x01,
369 Passive = 0x02,
370 Orphan = 0x03
371 }
372}
373
374/// newtype for Pan Id
375#[derive(Default, Clone, Copy, Debug)]
376#[cfg_attr(feature = "defmt", derive(defmt::Format))]
377pub struct PanId(pub [u8; 2]);
378
379impl PanId {
380 pub const BROADCAST: Self = Self([0xFF, 0xFF]);
381}
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
index fd8af8609..b0cf0248a 100644
--- a/embassy-stm32-wpan/src/sub/mac.rs
+++ b/embassy-stm32-wpan/src/sub/mac.rs
@@ -11,9 +11,10 @@ use embassy_sync::waitqueue::AtomicWaker;
11use crate::cmd::CmdPacket; 11use crate::cmd::CmdPacket;
12use crate::consts::TlPacketType; 12use crate::consts::TlPacketType;
13use crate::evt::{EvtBox, EvtPacket}; 13use crate::evt::{EvtBox, EvtPacket};
14use crate::tables::{ 14use crate::mac::commands::MacCommand;
15 Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE, 15use crate::mac::event::MacEvent;
16}; 16use crate::mac::typedefs::MacError;
17use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER};
17use crate::{channels, evt}; 18use crate::{channels, evt};
18 19
19static MAC_WAKER: AtomicWaker = AtomicWaker::new(); 20static MAC_WAKER: AtomicWaker = AtomicWaker::new();
@@ -25,21 +26,13 @@ pub struct Mac {
25 26
26impl Mac { 27impl Mac {
27 pub(crate) fn new() -> Self { 28 pub(crate) fn new() -> Self {
28 unsafe {
29 TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
30 p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
31 p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
32 evt_queue: ptr::null_mut(),
33 });
34 }
35
36 Self { phantom: PhantomData } 29 Self { phantom: PhantomData }
37 } 30 }
38 31
39 /// `HW_IPCC_MAC_802_15_4_EvtNot` 32 /// `HW_IPCC_MAC_802_15_4_EvtNot`
40 /// 33 ///
41 /// This function will stall if the previous `EvtBox` has not been dropped 34 /// This function will stall if the previous `EvtBox` has not been dropped
42 pub async fn read(&self) -> EvtBox<Self> { 35 pub async fn tl_read(&self) -> EvtBox<Self> {
43 // Wait for the last event box to be dropped 36 // Wait for the last event box to be dropped
44 poll_fn(|cx| { 37 poll_fn(|cx| {
45 MAC_WAKER.register(cx.waker()); 38 MAC_WAKER.register(cx.waker());
@@ -63,9 +56,9 @@ impl Mac {
63 } 56 }
64 57
65 /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` 58 /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
66 pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { 59 pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
67 self.write(opcode, payload).await; 60 self.tl_write(opcode, payload).await;
68 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; 61 Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await;
69 62
70 unsafe { 63 unsafe {
71 let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; 64 let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
@@ -76,22 +69,41 @@ impl Mac {
76 } 69 }
77 70
78 /// `TL_MAC_802_15_4_SendCmd` 71 /// `TL_MAC_802_15_4_SendCmd`
79 pub async fn write(&self, opcode: u16, payload: &[u8]) { 72 pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
80 Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { 73 Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
81 CmdPacket::write_into( 74 CmdPacket::write_into(
82 MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), 75 MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
83 TlPacketType::OtCmd, 76 TlPacketType::MacCmd,
84 opcode, 77 opcode,
85 payload, 78 payload,
86 ); 79 );
87 }) 80 })
88 .await; 81 .await;
89 } 82 }
83
84 pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError>
85 where
86 T: MacCommand,
87 {
88 let response = self.tl_write_and_get_response(T::OPCODE as u16, cmd.payload()).await;
89
90 if response == 0x00 {
91 Ok(())
92 } else {
93 Err(MacError::from(response))
94 }
95 }
96
97 pub async fn read(&self) -> Result<MacEvent<'_>, ()> {
98 MacEvent::new(self.tl_read().await)
99 }
90} 100}
91 101
92impl evt::MemoryManager for Mac { 102impl evt::MemoryManager for Mac {
93 /// SAFETY: passing a pointer to something other than a managed event packet is UB 103 /// SAFETY: passing a pointer to something other than a managed event packet is UB
94 unsafe fn drop_event_packet(_: *mut EvtPacket) { 104 unsafe fn drop_event_packet(_: *mut EvtPacket) {
105 trace!("mac drop event");
106
95 // Write the ack 107 // Write the ack
96 CmdPacket::write_into( 108 CmdPacket::write_into(
97 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, 109 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _,
@@ -101,7 +113,7 @@ impl evt::MemoryManager for Mac {
101 ); 113 );
102 114
103 // Clear the rx flag 115 // Clear the rx flag
104 let _ = poll_once(Ipcc::receive::<bool>( 116 let _ = poll_once(Ipcc::receive::<()>(
105 channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, 117 channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
106 || None, 118 || None,
107 )); 119 ));
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
index 1f2ecac2e..da05ad1dd 100644
--- a/embassy-stm32-wpan/src/sub/mm.rs
+++ b/embassy-stm32-wpan/src/sub/mm.rs
@@ -4,20 +4,21 @@ use core::marker::PhantomData;
4use core::mem::MaybeUninit; 4use core::mem::MaybeUninit;
5use core::task::Poll; 5use core::task::Poll;
6 6
7use aligned::{Aligned, A4};
7use cortex_m::interrupt; 8use cortex_m::interrupt;
8use embassy_stm32::ipcc::Ipcc; 9use embassy_stm32::ipcc::Ipcc;
9use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
10 11
11use crate::consts::POOL_SIZE; 12use crate::consts::POOL_SIZE;
12use crate::evt::EvtPacket; 13use crate::evt::EvtPacket;
13use crate::tables::{ 14#[cfg(feature = "ble")]
14 MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, 15use crate::tables::BLE_SPARE_EVT_BUF;
15}; 16use crate::tables::{MemManagerTable, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE};
16use crate::unsafe_linked_list::LinkedListNode; 17use crate::unsafe_linked_list::LinkedListNode;
17use crate::{channels, evt}; 18use crate::{channels, evt};
18 19
19static MM_WAKER: AtomicWaker = AtomicWaker::new(); 20static MM_WAKER: AtomicWaker = AtomicWaker::new();
20static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 21static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
21 22
22pub struct MemoryManager { 23pub struct MemoryManager {
23 phantom: PhantomData<MemoryManager>, 24 phantom: PhantomData<MemoryManager>,
@@ -30,7 +31,10 @@ impl MemoryManager {
30 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); 31 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
31 32
32 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { 33 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
34 #[cfg(feature = "ble")]
33 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), 35 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
36 #[cfg(not(feature = "ble"))]
37 spare_ble_buffer: core::ptr::null(),
34 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), 38 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
35 blepool: EVT_POOL.as_ptr().cast(), 39 blepool: EVT_POOL.as_ptr().cast(),
36 blepoolsize: POOL_SIZE as u32, 40 blepoolsize: POOL_SIZE as u32,
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
index af652860d..c17fd531d 100644
--- a/embassy-stm32-wpan/src/sub/sys.rs
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -50,7 +50,7 @@ impl Sys {
50 } 50 }
51 51
52 /// `HW_IPCC_SYS_CmdEvtNot` 52 /// `HW_IPCC_SYS_CmdEvtNot`
53 pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus { 53 pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> Result<SchiCommandStatus, ()> {
54 self.write(opcode, payload).await; 54 self.write(opcode, payload).await;
55 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; 55 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
56 56
@@ -59,17 +59,36 @@ impl Sys {
59 let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt; 59 let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
60 let p_payload = &((*p_command_event).payload) as *const u8; 60 let p_payload = &((*p_command_event).payload) as *const u8;
61 61
62 ptr::read_volatile(p_payload).try_into().unwrap() 62 ptr::read_volatile(p_payload).try_into()
63 } 63 }
64 } 64 }
65 65
66 #[cfg(feature = "mac")] 66 #[cfg(feature = "mac")]
67 pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus { 67 pub async fn shci_c2_mac_802_15_4_init(&self) -> Result<SchiCommandStatus, ()> {
68 use crate::tables::{
69 Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER,
70 TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE,
71 };
72
73 unsafe {
74 LinkedListNode::init_head(TRACES_EVT_QUEUE.as_mut_ptr() as *mut _);
75
76 TL_TRACES_TABLE.as_mut_ptr().write_volatile(TracesTable {
77 traces_queue: TRACES_EVT_QUEUE.as_ptr() as *const _,
78 });
79
80 TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
81 p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
82 p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
83 evt_queue: core::ptr::null_mut(),
84 });
85 };
86
68 self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await 87 self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
69 } 88 }
70 89
71 #[cfg(feature = "ble")] 90 #[cfg(feature = "ble")]
72 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus { 91 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> {
73 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await 92 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
74 } 93 }
75 94
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs
index 1b5dcdf2e..f2c250527 100644
--- a/embassy-stm32-wpan/src/tables.rs
+++ b/embassy-stm32-wpan/src/tables.rs
@@ -4,6 +4,8 @@ use aligned::{Aligned, A4};
4use bit_field::BitField; 4use bit_field::BitField;
5 5
6use crate::cmd::{AclDataPacket, CmdPacket}; 6use crate::cmd::{AclDataPacket, CmdPacket};
7#[cfg(feature = "mac")]
8use crate::consts::C_SIZE_CMD_STRING;
7use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; 9use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
8use crate::unsafe_linked_list::LinkedListNode; 10use crate::unsafe_linked_list::LinkedListNode;
9 11
@@ -80,7 +82,7 @@ impl WirelessFwInfoTable {
80} 82}
81 83
82#[derive(Debug, Clone)] 84#[derive(Debug, Clone)]
83#[repr(C, align(4))] 85#[repr(C)]
84pub struct DeviceInfoTable { 86pub struct DeviceInfoTable {
85 pub safe_boot_info_table: SafeBootInfoTable, 87 pub safe_boot_info_table: SafeBootInfoTable,
86 pub rss_info_table: RssInfoTable, 88 pub rss_info_table: RssInfoTable,
@@ -88,7 +90,7 @@ pub struct DeviceInfoTable {
88} 90}
89 91
90#[derive(Debug)] 92#[derive(Debug)]
91#[repr(C, align(4))] 93#[repr(C)]
92pub struct BleTable { 94pub struct BleTable {
93 pub pcmd_buffer: *mut CmdPacket, 95 pub pcmd_buffer: *mut CmdPacket,
94 pub pcs_buffer: *const u8, 96 pub pcs_buffer: *const u8,
@@ -97,16 +99,15 @@ pub struct BleTable {
97} 99}
98 100
99#[derive(Debug)] 101#[derive(Debug)]
100#[repr(C, align(4))] 102#[repr(C)]
101pub struct ThreadTable { 103pub struct ThreadTable {
102 pub nostack_buffer: *const u8, 104 pub nostack_buffer: *const u8,
103 pub clicmdrsp_buffer: *const u8, 105 pub clicmdrsp_buffer: *const u8,
104 pub otcmdrsp_buffer: *const u8, 106 pub otcmdrsp_buffer: *const u8,
105} 107}
106 108
107// TODO: use later
108#[derive(Debug)] 109#[derive(Debug)]
109#[repr(C, align(4))] 110#[repr(C)]
110pub struct LldTestsTable { 111pub struct LldTestsTable {
111 pub clicmdrsp_buffer: *const u8, 112 pub clicmdrsp_buffer: *const u8,
112 pub m0cmd_buffer: *const u8, 113 pub m0cmd_buffer: *const u8,
@@ -114,7 +115,7 @@ pub struct LldTestsTable {
114 115
115// TODO: use later 116// TODO: use later
116#[derive(Debug)] 117#[derive(Debug)]
117#[repr(C, align(4))] 118#[repr(C)]
118pub struct BleLldTable { 119pub struct BleLldTable {
119 pub cmdrsp_buffer: *const u8, 120 pub cmdrsp_buffer: *const u8,
120 pub m0cmd_buffer: *const u8, 121 pub m0cmd_buffer: *const u8,
@@ -122,7 +123,7 @@ pub struct BleLldTable {
122 123
123// TODO: use later 124// TODO: use later
124#[derive(Debug)] 125#[derive(Debug)]
125#[repr(C, align(4))] 126#[repr(C)]
126pub struct ZigbeeTable { 127pub struct ZigbeeTable {
127 pub notif_m0_to_m4_buffer: *const u8, 128 pub notif_m0_to_m4_buffer: *const u8,
128 pub appli_cmd_m4_to_m0_bufer: *const u8, 129 pub appli_cmd_m4_to_m0_bufer: *const u8,
@@ -130,14 +131,14 @@ pub struct ZigbeeTable {
130} 131}
131 132
132#[derive(Debug)] 133#[derive(Debug)]
133#[repr(C, align(4))] 134#[repr(C)]
134pub struct SysTable { 135pub struct SysTable {
135 pub pcmd_buffer: *mut CmdPacket, 136 pub pcmd_buffer: *mut CmdPacket,
136 pub sys_queue: *const LinkedListNode, 137 pub sys_queue: *const LinkedListNode,
137} 138}
138 139
139#[derive(Debug)] 140#[derive(Debug)]
140#[repr(C, align(4))] 141#[repr(C)]
141pub struct MemManagerTable { 142pub struct MemManagerTable {
142 pub spare_ble_buffer: *const u8, 143 pub spare_ble_buffer: *const u8,
143 pub spare_sys_buffer: *const u8, 144 pub spare_sys_buffer: *const u8,
@@ -152,13 +153,13 @@ pub struct MemManagerTable {
152} 153}
153 154
154#[derive(Debug)] 155#[derive(Debug)]
155#[repr(C, align(4))] 156#[repr(C)]
156pub struct TracesTable { 157pub struct TracesTable {
157 pub traces_queue: *const u8, 158 pub traces_queue: *const u8,
158} 159}
159 160
160#[derive(Debug)] 161#[derive(Debug)]
161#[repr(C, align(4))] 162#[repr(C)]
162pub struct Mac802_15_4Table { 163pub struct Mac802_15_4Table {
163 pub p_cmdrsp_buffer: *const u8, 164 pub p_cmdrsp_buffer: *const u8,
164 pub p_notack_buffer: *const u8, 165 pub p_notack_buffer: *const u8,
@@ -176,6 +177,9 @@ pub struct RefTable {
176 pub mem_manager_table: *const MemManagerTable, 177 pub mem_manager_table: *const MemManagerTable,
177 pub traces_table: *const TracesTable, 178 pub traces_table: *const TracesTable,
178 pub mac_802_15_4_table: *const Mac802_15_4Table, 179 pub mac_802_15_4_table: *const Mac802_15_4Table,
180 pub zigbee_table: *const ZigbeeTable,
181 pub lld_tests_table: *const LldTestsTable,
182 pub ble_lld_table: *const BleLldTable,
179} 183}
180 184
181// --------------------- ref table --------------------- 185// --------------------- ref table ---------------------
@@ -183,57 +187,57 @@ pub struct RefTable {
183pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit(); 187pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
184 188
185#[link_section = "MB_MEM1"] 189#[link_section = "MB_MEM1"]
186pub static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit(); 190pub static mut TL_DEVICE_INFO_TABLE: Aligned<A4, MaybeUninit<DeviceInfoTable>> = Aligned(MaybeUninit::uninit());
187 191
188#[link_section = "MB_MEM1"] 192#[link_section = "MB_MEM1"]
189pub static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit(); 193pub static mut TL_BLE_TABLE: Aligned<A4, MaybeUninit<BleTable>> = Aligned(MaybeUninit::uninit());
190 194
191#[link_section = "MB_MEM1"] 195#[link_section = "MB_MEM1"]
192pub static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit(); 196pub static mut TL_THREAD_TABLE: Aligned<A4, MaybeUninit<ThreadTable>> = Aligned(MaybeUninit::uninit());
193 197
194// #[link_section = "MB_MEM1"] 198#[link_section = "MB_MEM1"]
195// pub static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit(); 199pub static mut TL_LLD_TESTS_TABLE: Aligned<A4, MaybeUninit<LldTestsTable>> = Aligned(MaybeUninit::uninit());
196 200
197// #[link_section = "MB_MEM1"] 201#[link_section = "MB_MEM1"]
198// pub static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit(); 202pub static mut TL_BLE_LLD_TABLE: Aligned<A4, MaybeUninit<BleLldTable>> = Aligned(MaybeUninit::uninit());
199 203
200#[link_section = "MB_MEM1"] 204#[link_section = "MB_MEM1"]
201pub static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit(); 205pub static mut TL_SYS_TABLE: Aligned<A4, MaybeUninit<SysTable>> = Aligned(MaybeUninit::uninit());
202 206
203#[link_section = "MB_MEM1"] 207#[link_section = "MB_MEM1"]
204pub static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit(); 208pub static mut TL_MEM_MANAGER_TABLE: Aligned<A4, MaybeUninit<MemManagerTable>> = Aligned(MaybeUninit::uninit());
205 209
206#[link_section = "MB_MEM1"] 210#[link_section = "MB_MEM1"]
207pub static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit(); 211pub static mut TL_TRACES_TABLE: Aligned<A4, MaybeUninit<TracesTable>> = Aligned(MaybeUninit::uninit());
208 212
209#[link_section = "MB_MEM1"] 213#[link_section = "MB_MEM1"]
210pub static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit(); 214pub static mut TL_MAC_802_15_4_TABLE: Aligned<A4, MaybeUninit<Mac802_15_4Table>> = Aligned(MaybeUninit::uninit());
211 215
212// #[link_section = "MB_MEM1"] 216#[link_section = "MB_MEM1"]
213// pub static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit(); 217pub static mut TL_ZIGBEE_TABLE: Aligned<A4, MaybeUninit<ZigbeeTable>> = Aligned(MaybeUninit::uninit());
214 218
215// --------------------- tables --------------------- 219// --------------------- tables ---------------------
216#[link_section = "MB_MEM1"] 220#[link_section = "MB_MEM1"]
217pub static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 221pub static mut FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
218 222
219#[allow(dead_code)] 223#[allow(dead_code)]
220#[link_section = "MB_MEM1"] 224#[link_section = "MB_MEM1"]
221pub static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 225pub static mut TRACES_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
222 226
223#[link_section = "MB_MEM2"] 227#[link_section = "MB_MEM2"]
224pub static mut CS_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> = 228pub static mut CS_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> =
225 MaybeUninit::uninit(); 229 Aligned(MaybeUninit::uninit());
226 230
227#[link_section = "MB_MEM2"] 231#[link_section = "MB_MEM2"]
228pub static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 232pub static mut EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
229 233
230#[link_section = "MB_MEM2"] 234#[link_section = "MB_MEM2"]
231pub static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 235pub static mut SYSTEM_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
232 236
233// --------------------- app tables --------------------- 237// --------------------- app tables ---------------------
234#[cfg(feature = "mac")] 238#[cfg(feature = "mac")]
235#[link_section = "MB_MEM2"] 239#[link_section = "MB_MEM2"]
236pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); 240pub static mut MAC_802_15_4_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
237 241
238#[cfg(feature = "mac")] 242#[cfg(feature = "mac")]
239#[link_section = "MB_MEM2"] 243#[link_section = "MB_MEM2"]
@@ -242,23 +246,31 @@ pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<
242> = MaybeUninit::uninit(); 246> = MaybeUninit::uninit();
243 247
244#[link_section = "MB_MEM2"] 248#[link_section = "MB_MEM2"]
245pub static mut EVT_POOL: MaybeUninit<Aligned<A4, [u8; POOL_SIZE]>> = MaybeUninit::uninit(); 249pub static mut EVT_POOL: Aligned<A4, MaybeUninit<[u8; POOL_SIZE]>> = Aligned(MaybeUninit::uninit());
250
251#[link_section = "MB_MEM2"]
252pub static mut SYS_CMD_BUF: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
246 253
247#[link_section = "MB_MEM2"] 254#[link_section = "MB_MEM2"]
248pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); 255pub static mut SYS_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
256 Aligned(MaybeUninit::uninit());
249 257
258#[cfg(feature = "mac")]
250#[link_section = "MB_MEM2"] 259#[link_section = "MB_MEM2"]
251pub static mut SYS_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = 260pub static mut MAC_802_15_4_CNFINDNOT: Aligned<A4, MaybeUninit<[u8; C_SIZE_CMD_STRING]>> =
252 MaybeUninit::uninit(); 261 Aligned(MaybeUninit::uninit());
253 262
263#[cfg(feature = "ble")]
254#[link_section = "MB_MEM1"] 264#[link_section = "MB_MEM1"]
255pub static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); 265pub static mut BLE_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
256 266
267#[cfg(feature = "ble")]
257#[link_section = "MB_MEM2"] 268#[link_section = "MB_MEM2"]
258pub static mut BLE_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = 269pub static mut BLE_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
259 MaybeUninit::uninit(); 270 Aligned(MaybeUninit::uninit());
260 271
272#[cfg(feature = "ble")]
261#[link_section = "MB_MEM2"] 273#[link_section = "MB_MEM2"]
262// fuck these "magic" numbers from ST ---v---v 274// fuck these "magic" numbers from ST ---v---v
263pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> = 275pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> =
264 MaybeUninit::uninit(); 276 Aligned(MaybeUninit::uninit());
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index b3fe9c1f5..0fb6fdb56 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -32,7 +32,7 @@ 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-time = { version = "0.1.0", path = "../embassy-time", optional = true } 35embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
36embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 36embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
37embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] } 37embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
38embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 38embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@@ -40,9 +40,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
40embassy-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 }
41 41
42embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 42embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
44embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} 44embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
45embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} 45embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true}
46 46
47embedded-storage = "0.3.0" 47embedded-storage = "0.3.0"
48embedded-storage-async = { version = "0.4.0", optional = true } 48embedded-storage-async = { version = "0.4.0", optional = true }
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
57embedded-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 }
58critical-section = "1.1" 58critical-section = "1.1"
59atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
60stm32-metapac = "12" 60stm32-metapac = "13"
61vcell = "0.1.3" 61vcell = "0.1.3"
62bxcan = "0.7.0" 62bxcan = "0.7.0"
63nb = "1.0.0" 63nb = "1.0.0"
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
74[build-dependencies] 74[build-dependencies]
75proc-macro2 = "1.0.36" 75proc-macro2 = "1.0.36"
76quote = "1.0.15" 76quote = "1.0.15"
77stm32-metapac = { version = "12", default-features = false, features = ["metadata"]} 77stm32-metapac = { version = "13", default-features = false, features = ["metadata"]}
78 78
79[features] 79[features]
80default = ["rt"] 80default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index d628bcf04..d2b1cfd05 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -348,9 +348,7 @@ fn main() {
348 g.extend(quote! { 348 g.extend(quote! {
349 impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { 349 impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
350 fn frequency() -> crate::time::Hertz { 350 fn frequency() -> crate::time::Hertz {
351 critical_section::with(|_| unsafe { 351 unsafe { crate::rcc::get_freqs().#clk }
352 crate::rcc::get_freqs().#clk
353 })
354 } 352 }
355 fn enable() { 353 fn enable() {
356 critical_section::with(|_| { 354 critical_section::with(|_| {
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 56ecd63ca..94a8538bf 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg(not(adc_f3))]
3#[cfg_attr(adc_f1, path = "f1.rs")] 4#[cfg_attr(adc_f1, path = "f1.rs")]
4#[cfg_attr(adc_v1, path = "v1.rs")] 5#[cfg_attr(adc_v1, path = "v1.rs")]
5#[cfg_attr(adc_v2, path = "v2.rs")] 6#[cfg_attr(adc_v2, path = "v2.rs")]
@@ -7,14 +8,16 @@
7#[cfg_attr(adc_v4, path = "v4.rs")] 8#[cfg_attr(adc_v4, path = "v4.rs")]
8mod _version; 9mod _version;
9 10
10#[cfg(not(adc_f1))] 11#[cfg(not(any(adc_f1, adc_f3)))]
11mod resolution; 12mod resolution;
12mod sample_time; 13mod sample_time;
13 14
15#[cfg(not(adc_f3))]
14#[allow(unused)] 16#[allow(unused)]
15pub use _version::*; 17pub use _version::*;
16#[cfg(not(adc_f1))] 18#[cfg(not(any(adc_f1, adc_f3)))]
17pub use resolution::Resolution; 19pub use resolution::Resolution;
20#[cfg(not(adc_f3))]
18pub use sample_time::SampleTime; 21pub use sample_time::SampleTime;
19 22
20use crate::peripherals; 23use crate::peripherals;
@@ -22,13 +25,14 @@ use crate::peripherals;
22pub struct Adc<'d, T: Instance> { 25pub struct Adc<'d, T: Instance> {
23 #[allow(unused)] 26 #[allow(unused)]
24 adc: crate::PeripheralRef<'d, T>, 27 adc: crate::PeripheralRef<'d, T>,
28 #[cfg(not(adc_f3))]
25 sample_time: SampleTime, 29 sample_time: SampleTime,
26} 30}
27 31
28pub(crate) mod sealed { 32pub(crate) mod sealed {
29 pub trait Instance { 33 pub trait Instance {
30 fn regs() -> crate::pac::adc::Adc; 34 fn regs() -> crate::pac::adc::Adc;
31 #[cfg(all(not(adc_f1), not(adc_v1)))] 35 #[cfg(not(any(adc_f1, adc_v1, adc_f3)))]
32 fn common_regs() -> crate::pac::adccommon::AdcCommon; 36 fn common_regs() -> crate::pac::adccommon::AdcCommon;
33 } 37 }
34 38
@@ -56,7 +60,7 @@ foreach_peripheral!(
56 fn regs() -> crate::pac::adc::Adc { 60 fn regs() -> crate::pac::adc::Adc {
57 crate::pac::$inst 61 crate::pac::$inst
58 } 62 }
59 #[cfg(all(not(adc_f1), not(adc_v1)))] 63 #[cfg(not(any(adc_f1, adc_v1, adc_f3)))]
60 fn common_regs() -> crate::pac::adccommon::AdcCommon { 64 fn common_regs() -> crate::pac::adccommon::AdcCommon {
61 foreach_peripheral!{ 65 foreach_peripheral!{
62 (adccommon, $common_inst:ident) => { 66 (adccommon, $common_inst:ident) => {
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 0faa1e3c0..df0525560 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -1,3 +1,4 @@
1#[cfg(not(adc_f3))]
1macro_rules! impl_sample_time { 2macro_rules! impl_sample_time {
2 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { 3 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
3 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] 4 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 73861776a..5a0153464 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -1,3 +1,4 @@
1use core::cell::{RefCell, RefMut};
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut}; 4use core::ops::{Deref, DerefMut};
@@ -72,7 +73,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
72} 73}
73 74
74pub struct Can<'d, T: Instance> { 75pub struct Can<'d, T: Instance> {
75 can: bxcan::Can<BxcanInstance<'d, T>>, 76 pub can: RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
76} 77}
77 78
78#[derive(Debug)] 79#[derive(Debug)]
@@ -147,19 +148,24 @@ impl<'d, T: Instance> Can<'d, T> {
147 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 148 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
148 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 let can_ref_cell = RefCell::new(can);
152 Self { can: can_ref_cell }
151 } 153 }
152 154
153 pub fn set_bitrate(&mut self, bitrate: u32) { 155 pub fn set_bitrate(&mut self, bitrate: u32) {
154 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); 156 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
155 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); 157 self.can
158 .borrow_mut()
159 .modify_config()
160 .set_bit_timing(bit_timing)
161 .leave_disabled();
156 } 162 }
157 163
158 /// Queues the message to be sent but exerts backpressure 164 /// Queues the message to be sent but exerts backpressure
159 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 165 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
160 poll_fn(|cx| { 166 poll_fn(|cx| {
161 T::state().tx_waker.register(cx.waker()); 167 T::state().tx_waker.register(cx.waker());
162 if let Ok(status) = self.can.transmit(frame) { 168 if let Ok(status) = self.can.borrow_mut().transmit(frame) {
163 return Poll::Ready(status); 169 return Poll::Ready(status);
164 } 170 }
165 171
@@ -341,6 +347,79 @@ impl<'d, T: Instance> Can<'d, T> {
341 // Pack into BTR register values 347 // Pack into BTR register values
342 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1)) 348 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
343 } 349 }
350
351 pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
352 (CanTx { can: &self.can }, CanRx { can: &self.can })
353 }
354
355 pub fn as_mut(&self) -> RefMut<'_, bxcan::Can<BxcanInstance<'d, T>>> {
356 self.can.borrow_mut()
357 }
358}
359
360pub struct CanTx<'c, 'd, T: Instance> {
361 can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
362}
363
364impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
365 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
366 poll_fn(|cx| {
367 T::state().tx_waker.register(cx.waker());
368 if let Ok(status) = self.can.borrow_mut().transmit(frame) {
369 return Poll::Ready(status);
370 }
371
372 Poll::Pending
373 })
374 .await
375 }
376
377 pub async fn flush(&self, mb: bxcan::Mailbox) {
378 poll_fn(|cx| {
379 T::state().tx_waker.register(cx.waker());
380 if T::regs().tsr().read().tme(mb.index()) {
381 return Poll::Ready(());
382 }
383
384 Poll::Pending
385 })
386 .await;
387 }
388}
389
390#[allow(dead_code)]
391pub struct CanRx<'c, 'd, T: Instance> {
392 can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
393}
394
395impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
396 pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
397 poll_fn(|cx| {
398 T::state().err_waker.register(cx.waker());
399 if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
400 return Poll::Ready(Ok((time, frame)));
401 } else if let Some(err) = self.curr_error() {
402 return Poll::Ready(Err(err));
403 }
404
405 Poll::Pending
406 })
407 .await
408 }
409
410 fn curr_error(&self) -> Option<BusError> {
411 let err = { T::regs().esr().read() };
412 if err.boff() {
413 return Some(BusError::BusOff);
414 } else if err.epvf() {
415 return Some(BusError::BusPassive);
416 } else if err.ewgf() {
417 return Some(BusError::BusWarning);
418 } else if let Some(err) = err.lec().into_bus_err() {
419 return Some(err);
420 }
421 None
422 }
344} 423}
345 424
346enum RxFifo { 425enum RxFifo {
@@ -358,7 +437,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
358} 437}
359 438
360impl<'d, T: Instance> Deref for Can<'d, T> { 439impl<'d, T: Instance> Deref for Can<'d, T> {
361 type Target = bxcan::Can<BxcanInstance<'d, T>>; 440 type Target = RefCell<bxcan::Can<BxcanInstance<'d, T>>>;
362 441
363 fn deref(&self) -> &Self::Target { 442 fn deref(&self) -> &Self::Target {
364 &self.can 443 &self.can
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
new file mode 100644
index 000000000..c31a7fc63
--- /dev/null
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -0,0 +1,66 @@
1pub use bxcan;
2use embassy_hal_common::PeripheralRef;
3
4use crate::peripherals;
5
6pub(crate) mod sealed {
7 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8 use embassy_sync::channel::Channel;
9 use embassy_sync::waitqueue::AtomicWaker;
10
11 pub struct State {
12 pub tx_waker: AtomicWaker,
13 pub err_waker: AtomicWaker,
14 pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
15 }
16
17 impl State {
18 pub const fn new() -> Self {
19 Self {
20 tx_waker: AtomicWaker::new(),
21 err_waker: AtomicWaker::new(),
22 rx_queue: Channel::new(),
23 }
24 }
25 }
26
27 pub trait Instance {
28 const REGISTERS: *mut bxcan::RegisterBlock;
29
30 fn regs() -> &'static crate::pac::can::Fdcan;
31 fn state() -> &'static State;
32 }
33}
34
35pub trait InterruptableInstance {}
36pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
37
38pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
39
40unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
41 const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
42}
43
44foreach_peripheral!(
45 (can, $inst:ident) => {
46 impl sealed::Instance for peripherals::$inst {
47 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
48
49 fn regs() -> &'static crate::pac::can::Fdcan {
50 &crate::pac::$inst
51 }
52
53 fn state() -> &'static sealed::State {
54 static STATE: sealed::State = sealed::State::new();
55 &STATE
56 }
57 }
58
59 impl Instance for peripherals::$inst {}
60
61 impl InterruptableInstance for peripherals::$inst {}
62 };
63);
64
65pin_trait!(RxPin, Instance);
66pin_trait!(TxPin, Instance);
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
index c7e2e620a..4ff5aa0de 100644
--- a/embassy-stm32/src/can/mod.rs
+++ b/embassy-stm32/src/can/mod.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(can_bxcan, path = "bxcan.rs")] 3#[cfg_attr(can_bxcan, path = "bxcan.rs")]
4#[cfg_attr(can_fdcan, path = "fdcan.rs")]
4mod _version; 5mod _version;
5pub use _version::*; 6pub use _version::*;
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 1dc13949d..3d58914b3 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -51,7 +51,10 @@ impl Ch1Trigger {
51 fn tsel(&self) -> dac::vals::Tsel1 { 51 fn tsel(&self) -> dac::vals::Tsel1 {
52 match self { 52 match self {
53 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO, 53 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
54 #[cfg(not(dac_v3))]
54 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO, 55 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
56 #[cfg(dac_v3)]
57 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM1_TRGO,
55 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO, 58 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
56 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO, 59 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
57 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO, 60 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
@@ -264,7 +267,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
264 }); 267 });
265 268
266 let tx_request = self.dma.request(); 269 let tx_request = self.dma.request();
267 let dma_channel = &self.dma; 270 let dma_channel = &mut self.dma;
268 271
269 let tx_options = crate::dma::TransferOptions { 272 let tx_options = crate::dma::TransferOptions {
270 circular, 273 circular,
@@ -376,7 +379,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
376 }); 379 });
377 380
378 let tx_request = self.dma.request(); 381 let tx_request = self.dma.request();
379 let dma_channel = &self.dma; 382 let dma_channel = &mut self.dma;
380 383
381 let tx_options = crate::dma::TransferOptions { 384 let tx_options = crate::dma::TransferOptions {
382 circular, 385 circular,
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 8abe541d3..58d438af8 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -1,10 +1,9 @@
1use core::future::Future; 1use core::future::Future;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::pin::Pin; 3use core::pin::Pin;
4use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, AtomicUsize, Ordering};
5use core::task::{Context, Poll, Waker}; 5use core::task::{Context, Poll, Waker};
6 6
7use atomic_polyfill::AtomicUsize;
8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 7use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
10 9
diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs
index 968256046..2ed46ca2c 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_smi.rs
@@ -1,5 +1,11 @@
1//! Generic SMI Ethernet PHY 1//! Generic SMI Ethernet PHY
2 2
3#[cfg(feature = "time")]
4use embassy_time::{Duration, Timer};
5use futures::task::Context;
6#[cfg(feature = "time")]
7use futures::FutureExt;
8
3use super::{StationManagement, PHY}; 9use super::{StationManagement, PHY};
4 10
5#[allow(dead_code)] 11#[allow(dead_code)]
@@ -36,25 +42,47 @@ mod phy_consts {
36use self::phy_consts::*; 42use self::phy_consts::*;
37 43
38/// Generic SMI Ethernet PHY 44/// Generic SMI Ethernet PHY
39pub struct GenericSMI; 45pub struct GenericSMI {
46 #[cfg(feature = "time")]
47 poll_interval: Duration,
48 #[cfg(not(feature = "time"))]
49 _private: (),
50}
51
52impl GenericSMI {
53 pub fn new() -> Self {
54 Self {
55 #[cfg(feature = "time")]
56 poll_interval: Duration::from_millis(500),
57 #[cfg(not(feature = "time"))]
58 _private: (),
59 }
60 }
61}
40 62
41unsafe impl PHY for GenericSMI { 63unsafe impl PHY for GenericSMI {
42 /// Reset PHY and wait for it to come out of reset. 64 /// Reset PHY and wait for it to come out of reset.
43 fn phy_reset<S: StationManagement>(sm: &mut S) { 65 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
44 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); 66 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
45 while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} 67 while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
46 } 68 }
47 69
48 /// PHY initialisation. 70 /// PHY initialisation.
49 fn phy_init<S: StationManagement>(sm: &mut S) { 71 fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
50 // Clear WU CSR 72 // Clear WU CSR
51 Self::smi_write_ext(sm, PHY_REG_WUCSR, 0); 73 self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
52 74
53 // Enable auto-negotiation 75 // Enable auto-negotiation
54 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M); 76 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
55 } 77 }
56 78
57 fn poll_link<S: StationManagement>(sm: &mut S) -> bool { 79 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
80 #[cfg(not(feature = "time"))]
81 cx.waker().wake_by_ref();
82
83 #[cfg(feature = "time")]
84 let _ = Timer::after(self.poll_interval).poll_unpin(cx);
85
58 let bsr = sm.smi_read(PHY_REG_BSR); 86 let bsr = sm.smi_read(PHY_REG_BSR);
59 87
60 // No link without autonegotiate 88 // No link without autonegotiate
@@ -73,8 +101,13 @@ unsafe impl PHY for GenericSMI {
73 101
74/// Public functions for the PHY 102/// Public functions for the PHY
75impl GenericSMI { 103impl GenericSMI {
104 #[cfg(feature = "time")]
105 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
106 self.poll_interval = poll_interval
107 }
108
76 // Writes a value to an extended PHY register in MMD address space 109 // Writes a value to an extended PHY register in MMD address space
77 fn smi_write_ext<S: StationManagement>(sm: &mut S, reg_addr: u16, reg_data: u16) { 110 fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
78 sm.smi_write(PHY_REG_CTL, 0x0003); // set address 111 sm.smi_write(PHY_REG_CTL, 0x0003); // set address
79 sm.smi_write(PHY_REG_ADDAR, reg_addr); 112 sm.smi_write(PHY_REG_ADDAR, reg_addr);
80 sm.smi_write(PHY_REG_CTL, 0x4003); // set data 113 sm.smi_write(PHY_REG_CTL, 0x4003); // set data
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 4989e17c7..1687cb319 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -81,9 +81,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
81 } 81 }
82 82
83 fn link_state(&mut self, cx: &mut Context) -> LinkState { 83 fn link_state(&mut self, cx: &mut Context) -> LinkState {
84 // TODO: wake cx.waker on link state change 84 if self.phy.poll_link(&mut self.station_management, cx) {
85 cx.waker().wake_by_ref();
86 if P::poll_link(self) {
87 LinkState::Up 85 LinkState::Up
88 } else { 86 } else {
89 LinkState::Down 87 LinkState::Down
@@ -148,11 +146,11 @@ pub unsafe trait StationManagement {
148/// The methods cannot move S 146/// The methods cannot move S
149pub unsafe trait PHY { 147pub unsafe trait PHY {
150 /// Reset PHY and wait for it to come out of reset. 148 /// Reset PHY and wait for it to come out of reset.
151 fn phy_reset<S: StationManagement>(sm: &mut S); 149 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S);
152 /// PHY initialisation. 150 /// PHY initialisation.
153 fn phy_init<S: StationManagement>(sm: &mut S); 151 fn phy_init<S: StationManagement>(&mut self, sm: &mut S);
154 /// Poll link to see if it is up and FD with 100Mbps 152 /// Poll link to see if it is up and FD with 100Mbps
155 fn poll_link<S: StationManagement>(sm: &mut S) -> bool; 153 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool;
156} 154}
157 155
158pub(crate) mod sealed { 156pub(crate) mod sealed {
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index b53c2d0fa..2a6ea35ff 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -3,6 +3,7 @@
3mod rx_desc; 3mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData;
6use core::sync::atomic::{fence, Ordering}; 7use core::sync::atomic::{fence, Ordering};
7 8
8use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
@@ -48,9 +49,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
48 pub(crate) rx: RDesRing<'d>, 49 pub(crate) rx: RDesRing<'d>,
49 50
50 pins: [PeripheralRef<'d, AnyPin>; 9], 51 pins: [PeripheralRef<'d, AnyPin>; 9],
51 _phy: P, 52 pub(crate) phy: P,
52 clock_range: Cr, 53 pub(crate) station_management: EthernetStationManagement<T>,
53 phy_addr: u8,
54 pub(crate) mac_addr: [u8; 6], 54 pub(crate) mac_addr: [u8; 6],
55} 55}
56 56
@@ -224,9 +224,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
224 let mut this = Self { 224 let mut this = Self {
225 _peri: peri, 225 _peri: peri,
226 pins, 226 pins,
227 _phy: phy, 227 phy: phy,
228 clock_range, 228 station_management: EthernetStationManagement {
229 phy_addr, 229 peri: PhantomData,
230 clock_range: clock_range,
231 phy_addr: phy_addr,
232 },
230 mac_addr, 233 mac_addr,
231 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 234 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
232 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 235 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
@@ -256,8 +259,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
256 w.set_tie(true); 259 w.set_tie(true);
257 }); 260 });
258 261
259 P::phy_reset(&mut this); 262 this.phy.phy_reset(&mut this.station_management);
260 P::phy_init(&mut this); 263 this.phy.phy_init(&mut this.station_management);
261 264
262 interrupt::ETH.unpend(); 265 interrupt::ETH.unpend();
263 unsafe { interrupt::ETH.enable() }; 266 unsafe { interrupt::ETH.enable() };
@@ -266,7 +269,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
266 } 269 }
267} 270}
268 271
269unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 272pub struct EthernetStationManagement<T: Instance> {
273 peri: PhantomData<T>,
274 clock_range: Cr,
275 phy_addr: u8,
276}
277
278unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
270 fn smi_read(&mut self, reg: u8) -> u16 { 279 fn smi_read(&mut self, reg: u8) -> u16 {
271 let mac = ETH.ethernet_mac(); 280 let mac = ETH.ethernet_mac();
272 281
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 600e1d3bc..bb681c42b 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,5 +1,6 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData;
3use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, Ordering};
4 5
5use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
@@ -40,9 +41,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
40 pub(crate) tx: TDesRing<'d>, 41 pub(crate) tx: TDesRing<'d>,
41 pub(crate) rx: RDesRing<'d>, 42 pub(crate) rx: RDesRing<'d>,
42 pins: [PeripheralRef<'d, AnyPin>; 9], 43 pins: [PeripheralRef<'d, AnyPin>; 9],
43 _phy: P, 44 pub(crate) phy: P,
44 clock_range: u8, 45 pub(crate) station_management: EthernetStationManagement<T>,
45 phy_addr: u8,
46 pub(crate) mac_addr: [u8; 6], 46 pub(crate) mac_addr: [u8; 6],
47} 47}
48 48
@@ -201,9 +201,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
203 pins, 203 pins,
204 _phy: phy, 204 phy: phy,
205 clock_range, 205 station_management: EthernetStationManagement {
206 phy_addr, 206 peri: PhantomData,
207 clock_range: clock_range,
208 phy_addr: phy_addr,
209 },
207 mac_addr, 210 mac_addr,
208 }; 211 };
209 212
@@ -229,8 +232,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
229 w.set_tie(true); 232 w.set_tie(true);
230 }); 233 });
231 234
232 P::phy_reset(&mut this); 235 this.phy.phy_reset(&mut this.station_management);
233 P::phy_init(&mut this); 236 this.phy.phy_init(&mut this.station_management);
234 237
235 interrupt::ETH.unpend(); 238 interrupt::ETH.unpend();
236 unsafe { interrupt::ETH.enable() }; 239 unsafe { interrupt::ETH.enable() };
@@ -239,7 +242,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
239 } 242 }
240} 243}
241 244
242unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 245pub struct EthernetStationManagement<T: Instance> {
246 peri: PhantomData<T>,
247 clock_range: u8,
248 phy_addr: u8,
249}
250
251unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
243 fn smi_read(&mut self, reg: u8) -> u16 { 252 fn smi_read(&mut self, reg: u8) -> u16 {
244 let mac = ETH.ethernet_mac(); 253 let mac = ETH.ethernet_mac();
245 254
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 70a5ded62..f175349cd 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,6 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering};
2 3
3use atomic_polyfill::{fence, Ordering};
4use embassy_hal_common::drop::OnDrop; 4use embassy_hal_common::drop::OnDrop;
5use embassy_hal_common::into_ref; 5use embassy_hal_common::into_ref;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index c6cdc574b..2a374733d 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,6 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering};
2 3
3use atomic_polyfill::{fence, Ordering};
4use embassy_hal_common::drop::OnDrop; 4use embassy_hal_common::drop::OnDrop;
5use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
6use stm32_metapac::FLASH_BASE; 6use stm32_metapac::FLASH_BASE;
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 02bd4cc1f..ec8343e7c 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,7 +1,6 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3use core::sync::atomic::{fence, Ordering};
4use atomic_polyfill::{fence, Ordering};
5 4
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error; 6use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index b093a7837..40335d643 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -1,7 +1,6 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3use core::sync::atomic::{fence, Ordering};
4use atomic_polyfill::{fence, Ordering};
5 4
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error; 6use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 242d99278..4cb39e033 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -1,8 +1,7 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, AtomicBool, Ordering};
4 4
5use atomic_polyfill::AtomicBool;
6use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
7use pac::flash::regs::Sr; 6use pac::flash::regs::Sr;
8use pac::FLASH_SIZE; 7use pac::FLASH_SIZE;
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 9baf059ee..bf17b5b18 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,7 +1,6 @@
1use core::convert::TryInto; 1use core::convert::TryInto;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3 3use core::sync::atomic::{fence, Ordering};
4use atomic_polyfill::{fence, Ordering};
5 4
6use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 5use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error; 6use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index deefd05ed..243c8b51d 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,6 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2 2use core::sync::atomic::{fence, Ordering};
3use atomic_polyfill::{fence, Ordering};
4 3
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index a4f3b9686..60d7a00ee 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -86,6 +86,24 @@ macro_rules! fmc_sdram_constructor {
86} 86}
87 87
88impl<'d, T: Instance> Fmc<'d, T> { 88impl<'d, T: Instance> Fmc<'d, T> {
89 fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank1: (
90 bank: stm32_fmc::SdramTargetBank::Bank1,
91 addr: [
92 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin)
93 ],
94 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
95 d: [
96 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
97 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
98 ],
99 nbl: [
100 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
101 ],
102 ctrl: [
103 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
104 ]
105 ));
106
89 fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank1: ( 107 fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank1: (
90 bank: stm32_fmc::SdramTargetBank::Bank1, 108 bank: stm32_fmc::SdramTargetBank::Bank1,
91 addr: [ 109 addr: [
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 1f036d55c..208d1527d 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -382,13 +382,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
382 // I2C start 382 // I2C start
383 // 383 //
384 // ST SAD+W 384 // ST SAD+W
385 Self::master_write( 385 if let Err(err) = Self::master_write(
386 address, 386 address,
387 write.len().min(255), 387 write.len().min(255),
388 Stop::Software, 388 Stop::Software,
389 last_chunk_idx != 0, 389 last_chunk_idx != 0,
390 &check_timeout, 390 &check_timeout,
391 )?; 391 ) {
392 if send_stop {
393 self.master_stop();
394 }
395 return Err(err);
396 }
392 397
393 for (number, chunk) in write.chunks(255).enumerate() { 398 for (number, chunk) in write.chunks(255).enumerate() {
394 if number != 0 { 399 if number != 0 {
@@ -399,18 +404,22 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
399 // Wait until we are allowed to send data 404 // Wait until we are allowed to send data
400 // (START has been ACKed or last byte when 405 // (START has been ACKed or last byte when
401 // through) 406 // through)
402 self.wait_txe(&check_timeout)?; 407 if let Err(err) = self.wait_txe(&check_timeout) {
408 if send_stop {
409 self.master_stop();
410 }
411 return Err(err);
412 }
403 413
404 T::regs().txdr().write(|w| w.set_txdata(*byte)); 414 T::regs().txdr().write(|w| w.set_txdata(*byte));
405 } 415 }
406 } 416 }
407 // Wait until the write finishes 417 // Wait until the write finishes
408 self.wait_tc(&check_timeout)?; 418 let result = self.wait_tc(&check_timeout);
409
410 if send_stop { 419 if send_stop {
411 self.master_stop(); 420 self.master_stop();
412 } 421 }
413 Ok(()) 422 result
414 } 423 }
415 424
416 async fn write_dma_internal( 425 async fn write_dma_internal(
@@ -707,13 +716,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
707 let first_length = write[0].len(); 716 let first_length = write[0].len();
708 let last_slice_index = write.len() - 1; 717 let last_slice_index = write.len() - 1;
709 718
710 Self::master_write( 719 if let Err(err) = Self::master_write(
711 address, 720 address,
712 first_length.min(255), 721 first_length.min(255),
713 Stop::Software, 722 Stop::Software,
714 (first_length > 255) || (last_slice_index != 0), 723 (first_length > 255) || (last_slice_index != 0),
715 &check_timeout, 724 &check_timeout,
716 )?; 725 ) {
726 self.master_stop();
727 return Err(err);
728 }
717 729
718 for (idx, slice) in write.iter().enumerate() { 730 for (idx, slice) in write.iter().enumerate() {
719 let slice_len = slice.len(); 731 let slice_len = slice.len();
@@ -726,27 +738,36 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
726 let last_chunk_idx = total_chunks.saturating_sub(1); 738 let last_chunk_idx = total_chunks.saturating_sub(1);
727 739
728 if idx != 0 { 740 if idx != 0 {
729 Self::master_continue( 741 if let Err(err) = Self::master_continue(
730 slice_len.min(255), 742 slice_len.min(255),
731 (idx != last_slice_index) || (slice_len > 255), 743 (idx != last_slice_index) || (slice_len > 255),
732 &check_timeout, 744 &check_timeout,
733 )?; 745 ) {
746 self.master_stop();
747 return Err(err);
748 }
734 } 749 }
735 750
736 for (number, chunk) in slice.chunks(255).enumerate() { 751 for (number, chunk) in slice.chunks(255).enumerate() {
737 if number != 0 { 752 if number != 0 {
738 Self::master_continue( 753 if let Err(err) = Self::master_continue(
739 chunk.len(), 754 chunk.len(),
740 (number != last_chunk_idx) || (idx != last_slice_index), 755 (number != last_chunk_idx) || (idx != last_slice_index),
741 &check_timeout, 756 &check_timeout,
742 )?; 757 ) {
758 self.master_stop();
759 return Err(err);
760 }
743 } 761 }
744 762
745 for byte in chunk { 763 for byte in chunk {
746 // Wait until we are allowed to send data 764 // Wait until we are allowed to send data
747 // (START has been ACKed or last byte when 765 // (START has been ACKed or last byte when
748 // through) 766 // through)
749 self.wait_txe(&check_timeout)?; 767 if let Err(err) = self.wait_txe(&check_timeout) {
768 self.master_stop();
769 return Err(err);
770 }
750 771
751 // Put byte on the wire 772 // Put byte on the wire
752 //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); 773 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
@@ -755,10 +776,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
755 } 776 }
756 } 777 }
757 // Wait until the write finishes 778 // Wait until the write finishes
758 self.wait_tc(&check_timeout)?; 779 let result = self.wait_tc(&check_timeout);
759 self.master_stop(); 780 self.master_stop();
760 781 result
761 Ok(())
762 } 782 }
763 783
764 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { 784 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 37f840c73..a24cba9f0 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,8 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::sync::atomic::{compiler_fence, Ordering};
2use core::task::Poll; 3use core::task::Poll;
3 4
4use atomic_polyfill::{compiler_fence, Ordering};
5
6use self::sealed::Instance; 5use self::sealed::Instance;
7use crate::interrupt; 6use crate::interrupt;
8use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index e9db934bf..31b676088 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -1,332 +1,332 @@
1#![macro_use] 1#![macro_use]
2 2
3pub mod enums; 3pub mod enums;
4 4
5use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
6use enums::*; 6use enums::*;
7 7
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9use crate::gpio::sealed::AFType; 9use crate::gpio::sealed::AFType;
10use crate::gpio::AnyPin; 10use crate::gpio::AnyPin;
11use crate::pac::quadspi::Quadspi as Regs; 11use crate::pac::quadspi::Quadspi as Regs;
12use crate::rcc::RccPeripheral; 12use crate::rcc::RccPeripheral;
13use crate::{peripherals, Peripheral}; 13use crate::{peripherals, Peripheral};
14 14
15pub struct TransferConfig { 15pub struct TransferConfig {
16 /// Instraction width (IMODE) 16 /// Instraction width (IMODE)
17 pub iwidth: QspiWidth, 17 pub iwidth: QspiWidth,
18 /// Address width (ADMODE) 18 /// Address width (ADMODE)
19 pub awidth: QspiWidth, 19 pub awidth: QspiWidth,
20 /// Data width (DMODE) 20 /// Data width (DMODE)
21 pub dwidth: QspiWidth, 21 pub dwidth: QspiWidth,
22 /// Instruction Id 22 /// Instruction Id
23 pub instruction: u8, 23 pub instruction: u8,
24 /// Flash memory address 24 /// Flash memory address
25 pub address: Option<u32>, 25 pub address: Option<u32>,
26 /// Number of dummy cycles (DCYC) 26 /// Number of dummy cycles (DCYC)
27 pub dummy: DummyCycles, 27 pub dummy: DummyCycles,
28 /// Length of data 28 /// Length of data
29 pub data_len: Option<usize>, 29 pub data_len: Option<usize>,
30} 30}
31 31
32impl Default for TransferConfig { 32impl Default for TransferConfig {
33 fn default() -> Self { 33 fn default() -> Self {
34 Self { 34 Self {
35 iwidth: QspiWidth::NONE, 35 iwidth: QspiWidth::NONE,
36 awidth: QspiWidth::NONE, 36 awidth: QspiWidth::NONE,
37 dwidth: QspiWidth::NONE, 37 dwidth: QspiWidth::NONE,
38 instruction: 0, 38 instruction: 0,
39 address: None, 39 address: None,
40 dummy: DummyCycles::_0, 40 dummy: DummyCycles::_0,
41 data_len: None, 41 data_len: None,
42 } 42 }
43 } 43 }
44} 44}
45 45
46pub struct Config { 46pub struct Config {
47 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 47 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
48 /// If you need other value the whose predefined use `Other` variant. 48 /// If you need other value the whose predefined use `Other` variant.
49 pub memory_size: MemorySize, 49 pub memory_size: MemorySize,
50 /// Address size (8/16/24/32-bit) 50 /// Address size (8/16/24/32-bit)
51 pub address_size: AddressSize, 51 pub address_size: AddressSize,
52 /// Scalar factor for generating CLK [0-255] 52 /// Scalar factor for generating CLK [0-255]
53 pub prescaler: u8, 53 pub prescaler: u8,
54 /// Number of bytes to trigger FIFO threshold flag. 54 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel, 55 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands 56 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime, 57 pub cs_high_time: ChipSelectHightTime,
58} 58}
59 59
60impl Default for Config { 60impl Default for Config {
61 fn default() -> Self { 61 fn default() -> Self {
62 Self { 62 Self {
63 memory_size: MemorySize::Other(0), 63 memory_size: MemorySize::Other(0),
64 address_size: AddressSize::_24bit, 64 address_size: AddressSize::_24bit,
65 prescaler: 128, 65 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes, 66 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle, 67 cs_high_time: ChipSelectHightTime::_5Cycle,
68 } 68 }
69 } 69 }
70} 70}
71 71
72#[allow(dead_code)] 72#[allow(dead_code)]
73pub struct Qspi<'d, T: Instance, Dma> { 73pub struct Qspi<'d, T: Instance, Dma> {
74 _peri: PeripheralRef<'d, T>, 74 _peri: PeripheralRef<'d, T>,
75 sck: Option<PeripheralRef<'d, AnyPin>>, 75 sck: Option<PeripheralRef<'d, AnyPin>>,
76 d0: Option<PeripheralRef<'d, AnyPin>>, 76 d0: Option<PeripheralRef<'d, AnyPin>>,
77 d1: Option<PeripheralRef<'d, AnyPin>>, 77 d1: Option<PeripheralRef<'d, AnyPin>>,
78 d2: Option<PeripheralRef<'d, AnyPin>>, 78 d2: Option<PeripheralRef<'d, AnyPin>>,
79 d3: Option<PeripheralRef<'d, AnyPin>>, 79 d3: Option<PeripheralRef<'d, AnyPin>>,
80 nss: Option<PeripheralRef<'d, AnyPin>>, 80 nss: Option<PeripheralRef<'d, AnyPin>>,
81 dma: PeripheralRef<'d, Dma>, 81 dma: PeripheralRef<'d, Dma>,
82 config: Config, 82 config: Config,
83} 83}
84 84
85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
86 pub fn new( 86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd, 87 peri: impl Peripheral<P = T> + 'd,
88 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 88 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
89 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 89 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
90 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 90 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
91 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 91 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
92 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 92 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
93 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 93 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
94 dma: impl Peripheral<P = Dma> + 'd, 94 dma: impl Peripheral<P = Dma> + 'd,
95 config: Config, 95 config: Config,
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 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 99 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
100 sck.set_speed(crate::gpio::Speed::VeryHigh); 100 sck.set_speed(crate::gpio::Speed::VeryHigh);
101 nss.set_as_af(nss.af_num(), AFType::OutputPushPull); 101 nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
102 nss.set_speed(crate::gpio::Speed::VeryHigh); 102 nss.set_speed(crate::gpio::Speed::VeryHigh);
103 d0.set_as_af(d0.af_num(), AFType::OutputPushPull); 103 d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
104 d0.set_speed(crate::gpio::Speed::VeryHigh); 104 d0.set_speed(crate::gpio::Speed::VeryHigh);
105 d1.set_as_af(d1.af_num(), AFType::OutputPushPull); 105 d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
106 d1.set_speed(crate::gpio::Speed::VeryHigh); 106 d1.set_speed(crate::gpio::Speed::VeryHigh);
107 d2.set_as_af(d2.af_num(), AFType::OutputPushPull); 107 d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
108 d2.set_speed(crate::gpio::Speed::VeryHigh); 108 d2.set_speed(crate::gpio::Speed::VeryHigh);
109 d3.set_as_af(d3.af_num(), AFType::OutputPushPull); 109 d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
110 d3.set_speed(crate::gpio::Speed::VeryHigh); 110 d3.set_speed(crate::gpio::Speed::VeryHigh);
111 111
112 Self::new_inner( 112 Self::new_inner(
113 peri, 113 peri,
114 Some(d0.map_into()), 114 Some(d0.map_into()),
115 Some(d1.map_into()), 115 Some(d1.map_into()),
116 Some(d2.map_into()), 116 Some(d2.map_into()),
117 Some(d3.map_into()), 117 Some(d3.map_into()),
118 Some(sck.map_into()), 118 Some(sck.map_into()),
119 Some(nss.map_into()), 119 Some(nss.map_into()),
120 dma, 120 dma,
121 config, 121 config,
122 ) 122 )
123 } 123 }
124 124
125 fn new_inner( 125 fn new_inner(
126 peri: impl Peripheral<P = T> + 'd, 126 peri: impl Peripheral<P = T> + 'd,
127 d0: Option<PeripheralRef<'d, AnyPin>>, 127 d0: Option<PeripheralRef<'d, AnyPin>>,
128 d1: Option<PeripheralRef<'d, AnyPin>>, 128 d1: Option<PeripheralRef<'d, AnyPin>>,
129 d2: Option<PeripheralRef<'d, AnyPin>>, 129 d2: Option<PeripheralRef<'d, AnyPin>>,
130 d3: Option<PeripheralRef<'d, AnyPin>>, 130 d3: Option<PeripheralRef<'d, AnyPin>>,
131 sck: Option<PeripheralRef<'d, AnyPin>>, 131 sck: Option<PeripheralRef<'d, AnyPin>>,
132 nss: Option<PeripheralRef<'d, AnyPin>>, 132 nss: Option<PeripheralRef<'d, AnyPin>>,
133 dma: impl Peripheral<P = Dma> + 'd, 133 dma: impl Peripheral<P = Dma> + 'd,
134 config: Config, 134 config: Config,
135 ) -> Self { 135 ) -> Self {
136 into_ref!(peri, dma); 136 into_ref!(peri, dma);
137 137
138 T::enable(); 138 T::enable();
139 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); 139 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
140 140
141 while T::REGS.sr().read().busy() {} 141 while T::REGS.sr().read().busy() {}
142 142
143 T::REGS.cr().write(|w| { 143 T::REGS.cr().write(|w| {
144 w.set_prescaler(config.prescaler); 144 w.set_prescaler(config.prescaler);
145 w.set_en(true); 145 w.set_en(true);
146 }); 146 });
147 T::REGS.dcr().write(|w| { 147 T::REGS.dcr().write(|w| {
148 w.set_fsize(config.memory_size.into()); 148 w.set_fsize(config.memory_size.into());
149 w.set_csht(config.cs_high_time.into()); 149 w.set_csht(config.cs_high_time.into());
150 w.set_ckmode(false); 150 w.set_ckmode(false);
151 }); 151 });
152 152
153 Self { 153 Self {
154 _peri: peri, 154 _peri: peri,
155 sck, 155 sck,
156 d0, 156 d0,
157 d1, 157 d1,
158 d2, 158 d2,
159 d3, 159 d3,
160 nss, 160 nss,
161 dma, 161 dma,
162 config, 162 config,
163 } 163 }
164 } 164 }
165 165
166 pub fn command(&mut self, transaction: TransferConfig) { 166 pub fn command(&mut self, transaction: TransferConfig) {
167 T::REGS.cr().modify(|v| v.set_dmaen(false)); 167 T::REGS.cr().modify(|v| v.set_dmaen(false));
168 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 168 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
169 169
170 while !T::REGS.sr().read().tcf() {} 170 while !T::REGS.sr().read().tcf() {}
171 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 171 T::REGS.fcr().modify(|v| v.set_ctcf(true));
172 } 172 }
173 173
174 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 174 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
175 T::REGS.cr().modify(|v| v.set_dmaen(false)); 175 T::REGS.cr().modify(|v| v.set_dmaen(false));
176 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 176 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
177 177
178 if let Some(len) = transaction.data_len { 178 if let Some(len) = transaction.data_len {
179 let current_ar = T::REGS.ar().read().address(); 179 let current_ar = T::REGS.ar().read().address();
180 T::REGS.ccr().modify(|v| { 180 T::REGS.ccr().modify(|v| {
181 v.set_fmode(QspiMode::IndirectRead.into()); 181 v.set_fmode(QspiMode::IndirectRead.into());
182 }); 182 });
183 T::REGS.ar().write(|v| { 183 T::REGS.ar().write(|v| {
184 v.set_address(current_ar); 184 v.set_address(current_ar);
185 }); 185 });
186 186
187 for idx in 0..len { 187 for idx in 0..len {
188 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} 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() }; 189 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
190 } 190 }
191 } 191 }
192 192
193 while !T::REGS.sr().read().tcf() {} 193 while !T::REGS.sr().read().tcf() {}
194 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 194 T::REGS.fcr().modify(|v| v.set_ctcf(true));
195 } 195 }
196 196
197 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 197 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
198 T::REGS.cr().modify(|v| v.set_dmaen(false)); 198 T::REGS.cr().modify(|v| v.set_dmaen(false));
199 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 199 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
200 200
201 if let Some(len) = transaction.data_len { 201 if let Some(len) = transaction.data_len {
202 T::REGS.ccr().modify(|v| { 202 T::REGS.ccr().modify(|v| {
203 v.set_fmode(QspiMode::IndirectWrite.into()); 203 v.set_fmode(QspiMode::IndirectWrite.into());
204 }); 204 });
205 205
206 for idx in 0..len { 206 for idx in 0..len {
207 while !T::REGS.sr().read().ftf() {} 207 while !T::REGS.sr().read().ftf() {}
208 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; 208 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
209 } 209 }
210 } 210 }
211 211
212 while !T::REGS.sr().read().tcf() {} 212 while !T::REGS.sr().read().tcf() {}
213 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 213 T::REGS.fcr().modify(|v| v.set_ctcf(true));
214 } 214 }
215 215
216 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)
217 where 217 where
218 Dma: QuadDma<T>, 218 Dma: QuadDma<T>,
219 { 219 {
220 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 220 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
221 221
222 T::REGS.ccr().modify(|v| { 222 T::REGS.ccr().modify(|v| {
223 v.set_fmode(QspiMode::IndirectRead.into()); 223 v.set_fmode(QspiMode::IndirectRead.into());
224 }); 224 });
225 let current_ar = T::REGS.ar().read().address(); 225 let current_ar = T::REGS.ar().read().address();
226 T::REGS.ar().write(|v| { 226 T::REGS.ar().write(|v| {
227 v.set_address(current_ar); 227 v.set_address(current_ar);
228 }); 228 });
229 229
230 let request = self.dma.request(); 230 let request = self.dma.request();
231 let transfer = unsafe { 231 let transfer = unsafe {
232 Transfer::new_read( 232 Transfer::new_read(
233 &mut self.dma, 233 &mut self.dma,
234 request, 234 request,
235 T::REGS.dr().as_ptr() as *mut u8, 235 T::REGS.dr().as_ptr() as *mut u8,
236 buf, 236 buf,
237 Default::default(), 237 Default::default(),
238 ) 238 )
239 }; 239 };
240 240
241 T::REGS.cr().modify(|v| v.set_dmaen(true)); 241 T::REGS.cr().modify(|v| v.set_dmaen(true));
242 242
243 transfer.blocking_wait(); 243 transfer.blocking_wait();
244 } 244 }
245 245
246 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 246 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
247 where 247 where
248 Dma: QuadDma<T>, 248 Dma: QuadDma<T>,
249 { 249 {
250 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 250 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
251 251
252 T::REGS.ccr().modify(|v| { 252 T::REGS.ccr().modify(|v| {
253 v.set_fmode(QspiMode::IndirectWrite.into()); 253 v.set_fmode(QspiMode::IndirectWrite.into());
254 }); 254 });
255 255
256 let request = self.dma.request(); 256 let request = self.dma.request();
257 let transfer = unsafe { 257 let transfer = unsafe {
258 Transfer::new_write( 258 Transfer::new_write(
259 &mut self.dma, 259 &mut self.dma,
260 request, 260 request,
261 buf, 261 buf,
262 T::REGS.dr().as_ptr() as *mut u8, 262 T::REGS.dr().as_ptr() as *mut u8,
263 Default::default(), 263 Default::default(),
264 ) 264 )
265 }; 265 };
266 266
267 T::REGS.cr().modify(|v| v.set_dmaen(true)); 267 T::REGS.cr().modify(|v| v.set_dmaen(true));
268 268
269 transfer.blocking_wait(); 269 transfer.blocking_wait();
270 } 270 }
271 271
272 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { 272 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
273 T::REGS.fcr().modify(|v| { 273 T::REGS.fcr().modify(|v| {
274 v.set_csmf(true); 274 v.set_csmf(true);
275 v.set_ctcf(true); 275 v.set_ctcf(true);
276 v.set_ctef(true); 276 v.set_ctef(true);
277 v.set_ctof(true); 277 v.set_ctof(true);
278 }); 278 });
279 279
280 while T::REGS.sr().read().busy() {} 280 while T::REGS.sr().read().busy() {}
281 281
282 if let Some(len) = transaction.data_len { 282 if let Some(len) = transaction.data_len {
283 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));
284 } 284 }
285 285
286 T::REGS.ccr().write(|v| { 286 T::REGS.ccr().write(|v| {
287 v.set_fmode(fmode.into()); 287 v.set_fmode(fmode.into());
288 v.set_imode(transaction.iwidth.into()); 288 v.set_imode(transaction.iwidth.into());
289 v.set_instruction(transaction.instruction); 289 v.set_instruction(transaction.instruction);
290 v.set_admode(transaction.awidth.into()); 290 v.set_admode(transaction.awidth.into());
291 v.set_adsize(self.config.address_size.into()); 291 v.set_adsize(self.config.address_size.into());
292 v.set_dmode(transaction.dwidth.into()); 292 v.set_dmode(transaction.dwidth.into());
293 v.set_abmode(QspiWidth::NONE.into()); 293 v.set_abmode(QspiWidth::NONE.into());
294 v.set_dcyc(transaction.dummy.into()); 294 v.set_dcyc(transaction.dummy.into());
295 }); 295 });
296 296
297 if let Some(addr) = transaction.address { 297 if let Some(addr) = transaction.address {
298 T::REGS.ar().write(|v| { 298 T::REGS.ar().write(|v| {
299 v.set_address(addr); 299 v.set_address(addr);
300 }); 300 });
301 } 301 }
302 } 302 }
303} 303}
304 304
305pub(crate) mod sealed { 305pub(crate) mod sealed {
306 use super::*; 306 use super::*;
307 307
308 pub trait Instance { 308 pub trait Instance {
309 const REGS: Regs; 309 const REGS: Regs;
310 } 310 }
311} 311}
312 312
313pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 313pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
314 314
315pin_trait!(SckPin, Instance); 315pin_trait!(SckPin, Instance);
316pin_trait!(D0Pin, Instance); 316pin_trait!(D0Pin, Instance);
317pin_trait!(D1Pin, Instance); 317pin_trait!(D1Pin, Instance);
318pin_trait!(D2Pin, Instance); 318pin_trait!(D2Pin, Instance);
319pin_trait!(D3Pin, Instance); 319pin_trait!(D3Pin, Instance);
320pin_trait!(NSSPin, Instance); 320pin_trait!(NSSPin, Instance);
321 321
322dma_trait!(QuadDma, Instance); 322dma_trait!(QuadDma, Instance);
323 323
324foreach_peripheral!( 324foreach_peripheral!(
325 (quadspi, $inst:ident) => { 325 (quadspi, $inst:ident) => {
326 impl sealed::Instance for peripherals::$inst { 326 impl sealed::Instance for peripherals::$inst {
327 const REGS: Regs = crate::pac::$inst; 327 const REGS: Regs = crate::pac::$inst;
328 } 328 }
329 329
330 impl Instance for peripherals::$inst {} 330 impl Instance for peripherals::$inst {}
331 }; 331 };
332); 332);
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
index 4025a4e05..7e2f75ab7 100644
--- a/embassy-stm32/src/rcc/h5.rs
+++ b/embassy-stm32/src/rcc/h5.rs
@@ -473,11 +473,11 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
473 w.set_divm(0); 473 w.set_divm(0);
474 }); 474 });
475 475
476 return PllOutput{ 476 return PllOutput {
477 p: None, 477 p: None,
478 q: None, 478 q: None,
479 r: None, 479 r: None,
480 } 480 };
481 }; 481 };
482 482
483 assert!(1 <= config.prediv && config.prediv <= 63); 483 assert!(1 <= config.prediv && config.prediv <= 63);
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index f3a98c794..7e5cd0d1a 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -740,7 +740,7 @@ mod pll {
740 } 740 }
741 }; 741 };
742 742
743 let vco_ck = output + pll_x_p; 743 let vco_ck = output * pll_x_p;
744 744
745 assert!(pll_x_p < 128); 745 assert!(pll_x_p < 128);
746 assert!(vco_ck >= VCO_MIN); 746 assert!(vco_ck >= VCO_MIN);
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index 20cb8c91c..8a9b4adbf 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -1,6 +1,7 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_hal_common::into_ref; 3use embassy_hal_common::into_ref;
4use stm32_metapac::rcc::regs::Cfgr;
4use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; 5use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel};
5 6
6use crate::gpio::sealed::AFType; 7use crate::gpio::sealed::AFType;
@@ -439,6 +440,26 @@ impl<'d, T: McoInstance> Mco<'d, T> {
439} 440}
440 441
441pub(crate) unsafe fn init(config: Config) { 442pub(crate) unsafe fn init(config: Config) {
443 // Switch to MSI to prevent problems with PLL configuration.
444 if !RCC.cr().read().msion() {
445 // Turn on MSI and configure it to 4MHz.
446 RCC.cr().modify(|w| {
447 w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
448 w.set_msirange(MSIRange::default().into());
449 w.set_msipllen(false);
450 w.set_msion(true)
451 });
452
453 // Wait until MSI is running
454 while !RCC.cr().read().msirdy() {}
455 }
456 if RCC.cfgr().read().sws() != Sw::MSI {
457 // Set MSI as a clock source, reset prescalers.
458 RCC.cfgr().write_value(Cfgr::default());
459 // Wait for clock switch status bits to change.
460 while RCC.cfgr().read().sws() != Sw::MSI {}
461 }
462
442 match config.rtc_mux { 463 match config.rtc_mux {
443 RtcClockSource::LSE32 => { 464 RtcClockSource::LSE32 => {
444 // 1. Unlock the backup domain 465 // 1. Unlock the backup domain
@@ -660,6 +681,8 @@ pub(crate) unsafe fn init(config: Config) {
660 } 681 }
661 }; 682 };
662 683
684 RCC.apb1enr1().modify(|w| w.set_pwren(true));
685
663 set_freqs(Clocks { 686 set_freqs(Clocks {
664 sys: Hertz(sys_clk), 687 sys: Hertz(sys_clk),
665 ahb1: Hertz(ahb_freq), 688 ahb1: Hertz(ahb_freq),
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d6816d6a8..886fc0b93 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -83,12 +83,12 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
83/// Safety: Sets a mutable global. 83/// Safety: Sets a mutable global.
84pub(crate) unsafe fn set_freqs(freqs: Clocks) { 84pub(crate) unsafe fn set_freqs(freqs: Clocks) {
85 debug!("rcc: {:?}", freqs); 85 debug!("rcc: {:?}", freqs);
86 CLOCK_FREQS.as_mut_ptr().write(freqs); 86 CLOCK_FREQS = MaybeUninit::new(freqs);
87} 87}
88 88
89/// Safety: Reads a mutable global. 89/// Safety: Reads a mutable global.
90pub(crate) unsafe fn get_freqs() -> &'static Clocks { 90pub(crate) unsafe fn get_freqs() -> &'static Clocks {
91 &*CLOCK_FREQS.as_ptr() 91 CLOCK_FREQS.assume_init_ref()
92} 92}
93 93
94#[cfg(feature = "unstable-pac")] 94#[cfg(feature = "unstable-pac")]
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs
index 7072db984..6b69bb1cb 100644
--- a/embassy-stm32/src/rcc/wl.rs
+++ b/embassy-stm32/src/rcc/wl.rs
@@ -1,4 +1,5 @@
1use crate::pac::{FLASH, RCC}; 1use crate::pac::pwr::vals::Dbp;
2use crate::pac::{FLASH, PWR, RCC};
2use crate::rcc::{set_freqs, Clocks}; 3use crate::rcc::{set_freqs, Clocks};
3use crate::time::Hertz; 4use crate::time::Hertz;
4 5
@@ -184,6 +185,8 @@ pub struct Config {
184 pub apb1_pre: APBPrescaler, 185 pub apb1_pre: APBPrescaler,
185 pub apb2_pre: APBPrescaler, 186 pub apb2_pre: APBPrescaler,
186 pub enable_lsi: bool, 187 pub enable_lsi: bool,
188 pub enable_rtc_apb: bool,
189 pub rtc_mux: RtcClockSource,
187} 190}
188 191
189impl Default for Config { 192impl Default for Config {
@@ -196,10 +199,25 @@ impl Default for Config {
196 apb1_pre: APBPrescaler::NotDivided, 199 apb1_pre: APBPrescaler::NotDivided,
197 apb2_pre: APBPrescaler::NotDivided, 200 apb2_pre: APBPrescaler::NotDivided,
198 enable_lsi: false, 201 enable_lsi: false,
202 enable_rtc_apb: false,
203 rtc_mux: RtcClockSource::LSI32,
199 } 204 }
200 } 205 }
201} 206}
202 207
208pub enum RtcClockSource {
209 LSE32,
210 LSI32,
211}
212
213#[repr(u8)]
214pub enum Lsedrv {
215 Low = 0,
216 MediumLow = 1,
217 MediumHigh = 2,
218 High = 3,
219}
220
203pub(crate) unsafe fn init(config: Config) { 221pub(crate) unsafe fn init(config: Config) {
204 let (sys_clk, sw, vos) = match config.mux { 222 let (sys_clk, sw, vos) = match config.mux {
205 ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Range2), 223 ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Range2),
@@ -266,6 +284,32 @@ pub(crate) unsafe fn init(config: Config) {
266 284
267 while FLASH.acr().read().latency() != ws {} 285 while FLASH.acr().read().latency() != ws {}
268 286
287 match config.rtc_mux {
288 RtcClockSource::LSE32 => {
289 // 1. Unlock the backup domain
290 PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
291
292 // 2. Setup the LSE
293 RCC.bdcr().modify(|w| {
294 // Enable LSE
295 w.set_lseon(true);
296 // Max drive strength
297 // TODO: should probably be settable
298 w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented
299 });
300
301 // Wait until LSE is running
302 while !RCC.bdcr().read().lserdy() {}
303 }
304 RtcClockSource::LSI32 => {
305 // Turn on the internal 32 kHz LSI oscillator
306 RCC.csr().modify(|w| w.set_lsion(true));
307
308 // Wait until LSI is running
309 while !RCC.csr().read().lsirdy() {}
310 }
311 }
312
269 match config.mux { 313 match config.mux {
270 ClockSrc::HSI16 => { 314 ClockSrc::HSI16 => {
271 // Enable HSI16 315 // Enable HSI16
@@ -287,11 +331,26 @@ pub(crate) unsafe fn init(config: Config) {
287 w.set_msirgsel(true); 331 w.set_msirgsel(true);
288 w.set_msirange(range.into()); 332 w.set_msirange(range.into());
289 w.set_msion(true); 333 w.set_msion(true);
334
335 if let RtcClockSource::LSE32 = config.rtc_mux {
336 // If LSE is enabled, enable calibration of MSI
337 w.set_msipllen(true);
338 } else {
339 w.set_msipllen(false);
340 }
290 }); 341 });
291 while !RCC.cr().read().msirdy() {} 342 while !RCC.cr().read().msirdy() {}
292 } 343 }
293 } 344 }
294 345
346 if config.enable_rtc_apb {
347 // enable peripheral clock for communication
348 crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
349
350 // read to allow the pwr clock to enable
351 crate::pac::PWR.cr1().read();
352 }
353
295 RCC.extcfgr().modify(|w| { 354 RCC.extcfgr().modify(|w| {
296 if config.shd_ahb_pre == AHBPrescaler::NotDivided { 355 if config.shd_ahb_pre == AHBPrescaler::NotDivided {
297 w.set_shdhpre(0); 356 w.set_shdhpre(0);
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 7e5c64d90..8ef0ec51d 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -172,6 +172,7 @@ impl sealed::Instance for crate::peripherals::RTC {
172 const BACKUP_REGISTER_COUNT: usize = 32; 172 const BACKUP_REGISTER_COUNT: usize = 32;
173 173
174 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { 174 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
175 #[allow(clippy::if_same_then_else)]
175 if register < Self::BACKUP_REGISTER_COUNT { 176 if register < Self::BACKUP_REGISTER_COUNT {
176 //Some(rtc.bkpr()[register].read().bits()) 177 //Some(rtc.bkpr()[register].read().bits())
177 None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC 178 None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c3224073d..d5f63f84e 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -852,25 +852,19 @@ mod eh1 {
852 type Error = Error; 852 type Error = Error;
853 } 853 }
854 854
855 impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> { 855 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
856 fn flush(&mut self) -> Result<(), Self::Error> { 856 fn flush(&mut self) -> Result<(), Self::Error> {
857 Ok(()) 857 Ok(())
858 } 858 }
859 }
860 859
861 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, Tx, Rx> {
862 fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> { 860 fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
863 self.blocking_read(words) 861 self.blocking_read(words)
864 } 862 }
865 }
866 863
867 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
868 fn write(&mut self, words: &[W]) -> Result<(), Self::Error> { 864 fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
869 self.blocking_write(words) 865 self.blocking_write(words)
870 } 866 }
871 }
872 867
873 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
874 fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> { 868 fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
875 self.blocking_transfer(read, write) 869 self.blocking_transfer(read, write)
876 } 870 }
@@ -895,32 +889,25 @@ mod eh1 {
895#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 889#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
896mod eha { 890mod eha {
897 use super::*; 891 use super::*;
898 impl<'d, T: Instance, Tx, Rx> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> { 892
893 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
899 async fn flush(&mut self) -> Result<(), Self::Error> { 894 async fn flush(&mut self) -> Result<(), Self::Error> {
900 Ok(()) 895 Ok(())
901 } 896 }
902 }
903 897
904 impl<'d, T: Instance, Tx: TxDma<T>, Rx, W: Word> embedded_hal_async::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
905 async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> { 898 async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
906 self.write(words).await 899 self.write(words).await
907 } 900 }
908 }
909 901
910 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBusRead<W>
911 for Spi<'d, T, Tx, Rx>
912 {
913 async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> { 902 async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
914 self.read(words).await 903 self.read(words).await
915 } 904 }
916 }
917 905
918 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 906 async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
919 async fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Result<(), Self::Error> {
920 self.transfer(read, write).await 907 self.transfer(read, write).await
921 } 908 }
922 909
923 async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Result<(), Self::Error> { 910 async fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
924 self.transfer_in_place(words).await 911 self.transfer_in_place(words).await
925 } 912 }
926 } 913 }
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index c97efbf0a..ea8e525ea 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -116,6 +116,10 @@ pub struct Config {
116 /// but will effectively disable noise detection. 116 /// but will effectively disable noise detection.
117 #[cfg(not(usart_v1))] 117 #[cfg(not(usart_v1))]
118 pub assume_noise_free: bool, 118 pub assume_noise_free: bool,
119
120 /// Set this to true to swap the RX and TX pins.
121 #[cfg(any(usart_v3, usart_v4))]
122 pub swap_rx_tx: bool,
119} 123}
120 124
121impl Default for Config { 125impl Default for Config {
@@ -129,6 +133,8 @@ impl Default for Config {
129 detect_previous_overrun: false, 133 detect_previous_overrun: false,
130 #[cfg(not(usart_v1))] 134 #[cfg(not(usart_v1))]
131 assume_noise_free: false, 135 assume_noise_free: false,
136 #[cfg(any(usart_v3, usart_v4))]
137 swap_rx_tx: false,
132 } 138 }
133 } 139 }
134} 140}
@@ -688,8 +694,22 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
688 694
689 let r = T::regs(); 695 let r = T::regs();
690 696
691 rx.set_as_af(rx.af_num(), AFType::Input); 697 // Some chips do not have swap_rx_tx bit
692 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 698 cfg_if::cfg_if! {
699 if #[cfg(any(usart_v3, usart_v4))] {
700 if config.swap_rx_tx {
701 let (rx, tx) = (tx, rx);
702 rx.set_as_af(rx.af_num(), AFType::Input);
703 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
704 } else {
705 rx.set_as_af(rx.af_num(), AFType::Input);
706 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
707 }
708 } else {
709 rx.set_as_af(rx.af_num(), AFType::Input);
710 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
711 }
712 }
693 713
694 configure(r, &config, T::frequency(), T::KIND, true, true); 714 configure(r, &config, T::frequency(), T::KIND, true, true);
695 715
@@ -847,6 +867,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
847 StopBits::STOP1P5 => vals::Stop::STOP1P5, 867 StopBits::STOP1P5 => vals::Stop::STOP1P5,
848 StopBits::STOP2 => vals::Stop::STOP2, 868 StopBits::STOP2 => vals::Stop::STOP2,
849 }); 869 });
870
871 #[cfg(any(usart_v3, usart_v4))]
872 w.set_swap(config.swap_rx_tx);
850 }); 873 });
851 r.cr1().write(|w| { 874 r.cr1().write(|w| {
852 // enable uart 875 // enable uart
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 6783db28d..fd0e22adf 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -1,8 +1,8 @@
1use core::cell::UnsafeCell; 1use core::cell::UnsafeCell;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::sync::atomic::{AtomicBool, AtomicU16, Ordering};
3use core::task::Poll; 4use core::task::Poll;
4 5
5use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
6use embassy_hal_common::{into_ref, Peripheral}; 6use embassy_hal_common::{into_ref, Peripheral};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embassy_usb_driver::{ 8use embassy_usb_driver::{
@@ -648,7 +648,7 @@ impl<'d, T: Instance> Bus<'d, T> {
648 648
649 let r = T::regs(); 649 let r = T::regs();
650 let core_id = r.cid().read().0; 650 let core_id = r.cid().read().0;
651 info!("Core id {:08x}", core_id); 651 trace!("Core id {:08x}", core_id);
652 652
653 // Wait for AHB ready. 653 // Wait for AHB ready.
654 while !r.grstctl().read().ahbidl() {} 654 while !r.grstctl().read().ahbidl() {}
@@ -1154,14 +1154,22 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
1154 trace!("read start len={}", buf.len()); 1154 trace!("read start len={}", buf.len());
1155 1155
1156 poll_fn(|cx| { 1156 poll_fn(|cx| {
1157 let r = T::regs();
1157 let index = self.info.addr.index(); 1158 let index = self.info.addr.index();
1158 let state = T::state(); 1159 let state = T::state();
1159 1160
1160 state.ep_out_wakers[index].register(cx.waker()); 1161 state.ep_out_wakers[index].register(cx.waker());
1161 1162
1163 let doepctl = r.doepctl(index).read();
1164 trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,);
1165 if !doepctl.usbaep() {
1166 trace!("read ep={:?} error disabled", self.info.addr);
1167 return Poll::Ready(Err(EndpointError::Disabled));
1168 }
1169
1162 let len = state.ep_out_size[index].load(Ordering::Relaxed); 1170 let len = state.ep_out_size[index].load(Ordering::Relaxed);
1163 if len != EP_OUT_BUFFER_EMPTY { 1171 if len != EP_OUT_BUFFER_EMPTY {
1164 trace!("read done len={}", len); 1172 trace!("read ep={:?} done len={}", self.info.addr, len);
1165 1173
1166 if len as usize > buf.len() { 1174 if len as usize > buf.len() {
1167 return Poll::Ready(Err(EndpointError::BufferOverflow)); 1175 return Poll::Ready(Err(EndpointError::BufferOverflow));
@@ -1214,7 +1222,12 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1214 1222
1215 let diepctl = r.diepctl(index).read(); 1223 let diepctl = r.diepctl(index).read();
1216 let dtxfsts = r.dtxfsts(index).read(); 1224 let dtxfsts = r.dtxfsts(index).read();
1217 info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0); 1225 trace!(
1226 "write ep={:?}: diepctl {:08x} ftxfsts {:08x}",
1227 self.info.addr,
1228 diepctl.0,
1229 dtxfsts.0
1230 );
1218 if !diepctl.usbaep() { 1231 if !diepctl.usbaep() {
1219 trace!("write ep={:?} wait for prev: error disabled", self.info.addr); 1232 trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1220 Poll::Ready(Err(EndpointError::Disabled)) 1233 Poll::Ready(Err(EndpointError::Disabled))
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 77352874d..f421af392 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -335,6 +335,12 @@ impl<T, const N: usize> ChannelState<T, N> {
335 } 335 }
336 } 336 }
337 337
338 fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> bool {
339 self.receiver_waker.register(cx.waker());
340
341 !self.queue.is_empty()
342 }
343
338 fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> { 344 fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> {
339 self.try_send_with_context(message, None) 345 self.try_send_with_context(message, None)
340 } 346 }
@@ -353,6 +359,12 @@ impl<T, const N: usize> ChannelState<T, N> {
353 } 359 }
354 } 360 }
355 } 361 }
362
363 fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> bool {
364 self.senders_waker.register(cx.waker());
365
366 !self.queue.is_full()
367 }
356} 368}
357 369
358/// A bounded channel for communicating between asynchronous tasks 370/// A bounded channel for communicating between asynchronous tasks
@@ -401,6 +413,16 @@ where
401 self.lock(|c| c.try_send_with_context(m, cx)) 413 self.lock(|c| c.try_send_with_context(m, cx))
402 } 414 }
403 415
416 /// Allows a poll_fn to poll until the channel is ready to receive
417 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> bool {
418 self.lock(|c| c.poll_ready_to_receive(cx))
419 }
420
421 /// Allows a poll_fn to poll until the channel is ready to send
422 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> bool {
423 self.lock(|c| c.poll_ready_to_send(cx))
424 }
425
404 /// Get a sender for this channel. 426 /// Get a sender for this channel.
405 pub fn sender(&self) -> Sender<'_, M, T, N> { 427 pub fn sender(&self) -> Sender<'_, M, T, N> {
406 Sender { channel: self } 428 Sender { channel: self }
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index f4a7860e6..26640d930 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8## 0.1.2 - 2023-07-05
9
10- Update `embedded-hal-async` to `0.2.0-alpha.2`.
11- Update `embedded-hal v1` to `1.0.0-alpha.11`. (Note: v0.2 support is kept unchanged).
12
8## 0.1.1 - 2023-04-13 13## 0.1.1 - 2023-04-13
9 14
10- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits). 15- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits).
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 857da5467..0afb1103d 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-time" 2name = "embassy-time"
3version = "0.1.1" 3version = "0.1.2"
4edition = "2021" 4edition = "2021"
5description = "Instant and Duration for embedded no-std systems, with async timer support" 5description = "Instant and Duration for embedded no-std systems, with async timer support"
6repository = "https://github.com/embassy-rs/embassy" 6repository = "https://github.com/embassy-rs/embassy"
@@ -23,7 +23,7 @@ target = "x86_64-unknown-linux-gnu"
23features = ["nightly", "defmt", "unstable-traits", "std"] 23features = ["nightly", "defmt", "unstable-traits", "std"]
24 24
25[features] 25[features]
26std = ["tick-hz-1_000_000"] 26std = ["tick-hz-1_000_000", "critical-section/std"]
27wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] 27wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
28 28
29# Enable nightly-only features 29# Enable nightly-only features
@@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true }
152log = { version = "0.4.14", optional = true } 152log = { version = "0.4.14", optional = true }
153 153
154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } 154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
156embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} 156embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
157 157
158futures-util = { version = "0.3.17", default-features = false } 158futures-util = { version = "0.3.17", default-features = false }
159atomic-polyfill = "1.0.1" 159atomic-polyfill = "1.0.1"
diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs
index d6436369b..5fe7becaf 100644
--- a/embassy-time/src/driver.rs
+++ b/embassy-time/src/driver.rs
@@ -36,7 +36,7 @@
36//! ``` 36//! ```
37//! use embassy_time::driver::{Driver, AlarmHandle}; 37//! use embassy_time::driver::{Driver, AlarmHandle};
38//! 38//!
39//! struct MyDriver{}; // not public! 39//! struct MyDriver{} // not public!
40//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); 40//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
41//! 41//!
42//! impl Driver for MyDriver { 42//! impl Driver for MyDriver {
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs
index 9f8c57b5c..32db47a37 100644
--- a/embassy-time/src/driver_std.rs
+++ b/embassy-time/src/driver_std.rs
@@ -1,10 +1,10 @@
1use core::sync::atomic::{AtomicU8, Ordering};
1use std::cell::{RefCell, UnsafeCell}; 2use std::cell::{RefCell, UnsafeCell};
2use std::mem::MaybeUninit; 3use std::mem::MaybeUninit;
3use std::sync::{Condvar, Mutex, Once}; 4use std::sync::{Condvar, Mutex, Once};
4use std::time::{Duration as StdDuration, Instant as StdInstant}; 5use std::time::{Duration as StdDuration, Instant as StdInstant};
5use std::{mem, ptr, thread}; 6use std::{mem, ptr, thread};
6 7
7use atomic_polyfill::{AtomicU8, Ordering};
8use critical_section::Mutex as CsMutex; 8use critical_section::Mutex as CsMutex;
9 9
10use crate::driver::{AlarmHandle, Driver}; 10use crate::driver::{AlarmHandle, Driver};
diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs
index 63d049897..0f672dc75 100644
--- a/embassy-time/src/driver_wasm.rs
+++ b/embassy-time/src/driver_wasm.rs
@@ -1,9 +1,9 @@
1use core::sync::atomic::{AtomicU8, Ordering};
1use std::cell::UnsafeCell; 2use std::cell::UnsafeCell;
2use std::mem::MaybeUninit; 3use std::mem::MaybeUninit;
3use std::ptr; 4use std::ptr;
4use std::sync::{Mutex, Once}; 5use std::sync::{Mutex, Once};
5 6
6use atomic_polyfill::{AtomicU8, Ordering};
7use wasm_bindgen::prelude::*; 7use wasm_bindgen::prelude::*;
8use wasm_timer::Instant as StdInstant; 8use wasm_timer::Instant as StdInstant;
9 9
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs
index 4795eb2f3..77947ab29 100644
--- a/embassy-time/src/queue_generic.rs
+++ b/embassy-time/src/queue_generic.rs
@@ -16,7 +16,7 @@ const QUEUE_SIZE: usize = 16;
16#[cfg(feature = "generic-queue-32")] 16#[cfg(feature = "generic-queue-32")]
17const QUEUE_SIZE: usize = 32; 17const QUEUE_SIZE: usize = 32;
18#[cfg(feature = "generic-queue-64")] 18#[cfg(feature = "generic-queue-64")]
19const QUEUE_SIZE: usize = 32; 19const QUEUE_SIZE: usize = 64;
20#[cfg(feature = "generic-queue-128")] 20#[cfg(feature = "generic-queue-128")]
21const QUEUE_SIZE: usize = 128; 21const QUEUE_SIZE: usize = 128;
22#[cfg(not(any( 22#[cfg(not(any(
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index b98f73f39..2a0cf7818 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] } 11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] } 12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
13embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] } 13embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index 007b6839c..95b2da954 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } 11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] } 12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 5b3faf8f8..3b0fc4d9d 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index b6a6f9cd8..323b4ab2c 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 0a7e19b1d..b2abdc891 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 998df4dc0..0b7e72d5e 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 10b58c172..5f3f365c1 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 713a6527e..44eb5aba8 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 4c8bbd73f..fdad55060 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index a3acc56b8..30b67b7b2 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -18,7 +18,7 @@ log = [
18[dependencies] 18[dependencies]
19embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } 19embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
20embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } 20embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
21embassy-time = { version = "0.1.0", path = "../../embassy-time" } 21embassy-time = { version = "0.1.2", path = "../../embassy-time" }
22embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 22embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
23 23
24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index 0f9048b0f..ded3b7db8 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -9,7 +9,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] }
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 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"] } 12embassy-time = { version = "0.1.2", 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"] } 13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 8c4175966..9b41ec5ab 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -29,7 +29,7 @@ nightly = [
29embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 29embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
30embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 30embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
31embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 31embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
32embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 32embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
33embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 33embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
34embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } 34embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
35embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } 35embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
@@ -43,6 +43,7 @@ embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-host
43defmt = "0.3" 43defmt = "0.3"
44defmt-rtt = "0.4" 44defmt-rtt = "0.4"
45 45
46fixed = "1.10.0"
46static_cell = "1.1" 47static_cell = "1.1"
47cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 48cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
48cortex-m-rt = "0.7.0" 49cortex-m-rt = "0.7.0"
@@ -52,4 +53,9 @@ rand = { version = "0.8.4", default-features = false }
52embedded-storage = "0.3.0" 53embedded-storage = "0.3.0"
53usbd-hid = "0.6.0" 54usbd-hid = "0.6.0"
54serde = { version = "1.0.136", default-features = false } 55serde = { version = "1.0.136", default-features = false }
55embedded-hal-async = { version = "0.2.0-alpha.1", optional = true } 56embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
57num-integer = { version = "0.1.45", default-features = false }
58microfft = "0.5.0"
59
60[patch.crates-io]
61lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
index 6b41320ca..444b9137f 100644
--- a/examples/nrf52840/src/bin/pdm.rs
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -7,6 +7,8 @@ use embassy_executor::Spawner;
7use embassy_nrf::pdm::{self, Config, Pdm}; 7use embassy_nrf::pdm::{self, Config, Pdm};
8use embassy_nrf::{bind_interrupts, peripherals}; 8use embassy_nrf::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use fixed::types::I7F1;
11use num_integer::Roots;
10use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
11 13
12bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -20,18 +22,36 @@ async fn main(_p: Spawner) {
20 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config); 22 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
21 23
22 loop { 24 loop {
23 pdm.start().await; 25 for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
24 26 pdm.set_gain(gain, gain);
25 // wait some time till the microphon settled 27 info!("Gain = {} dB", defmt::Debug2Format(&gain));
26 Timer::after(Duration::from_millis(1000)).await; 28 pdm.start().await;
27 29
28 const SAMPLES: usize = 2048; 30 // wait some time till the microphon settled
29 let mut buf = [0i16; SAMPLES]; 31 Timer::after(Duration::from_millis(1000)).await;
30 pdm.sample(&mut buf).await.unwrap(); 32
31 33 const SAMPLES: usize = 2048;
32 info!("samples: {:?}", &buf); 34 let mut buf = [0i16; SAMPLES];
33 35 pdm.sample(&mut buf).await.unwrap();
34 pdm.stop().await; 36
35 Timer::after(Duration::from_millis(100)).await; 37 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
38 info!(
39 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
40 buf.len(),
41 buf.iter().min().unwrap(),
42 buf.iter().max().unwrap(),
43 mean,
44 (buf.iter()
45 .map(|v| i32::from(*v - mean).pow(2))
46 .fold(0i32, |a, b| a.saturating_add(b))
47 / buf.len() as i32)
48 .sqrt() as i16,
49 );
50
51 info!("samples: {:?}", &buf);
52
53 pdm.stop().await;
54 Timer::after(Duration::from_millis(100)).await;
55 }
36 } 56 }
37} 57}
diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
new file mode 100644
index 000000000..7d8531475
--- /dev/null
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -0,0 +1,81 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::cmp::Ordering;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_nrf::pdm::{self, Config, Frequency, OperationMode, Pdm, Ratio, SamplerState};
10use embassy_nrf::{bind_interrupts, peripherals};
11use fixed::types::I7F1;
12use microfft::real::rfft_1024;
13use num_integer::Roots;
14use {defmt_rtt as _, panic_probe as _};
15
16// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
17
18bind_interrupts!(struct Irqs {
19 PDM => pdm::InterruptHandler<peripherals::PDM>;
20});
21
22#[embassy_executor::main]
23async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default());
25 let mut config = Config::default();
26 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
27 config.frequency = Frequency::_1280K; // 16 kHz sample rate
28 config.ratio = Ratio::RATIO80;
29 config.operation_mode = OperationMode::Mono;
30 config.gain_left = I7F1::from_bits(5); // 2.5 dB
31 let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config);
32
33 let mut bufs = [[0; 1024]; 2];
34
35 pdm.run_task_sampler(&mut bufs, move |buf| {
36 // NOTE: It is important that the time spent within this callback
37 // does not exceed the time taken to acquire the 1500 samples we
38 // have in this example, which would be 10us + 2us per
39 // sample * 1500 = 18ms. You need to measure the time taken here
40 // and set the sample buffer size accordingly. Exceeding this
41 // time can lead to the peripheral re-writing the other buffer.
42 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
43 let (peak_freq_index, peak_mag) = fft_peak_freq(&buf);
44 let peak_freq = peak_freq_index * 16000 / buf.len();
45 info!(
46 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}, peak {} @ {} Hz",
47 buf.len(),
48 buf.iter().min().unwrap(),
49 buf.iter().max().unwrap(),
50 mean,
51 (buf.iter()
52 .map(|v| i32::from(*v - mean).pow(2))
53 .fold(0i32, |a, b| a.saturating_add(b))
54 / buf.len() as i32)
55 .sqrt() as i16,
56 peak_mag,
57 peak_freq,
58 );
59 SamplerState::Sampled
60 })
61 .await
62 .unwrap();
63}
64
65fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {
66 let mut f = [0f32; 1024];
67 for i in 0..input.len() {
68 f[i] = (input[i] as f32) / 32768.0;
69 }
70 // N.B. rfft_1024 does the FFT in-place so result is actually also a reference to f.
71 let result = rfft_1024(&mut f);
72 result[0].im = 0.0;
73
74 result
75 .iter()
76 .map(|c| c.norm_sqr())
77 .enumerate()
78 .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
79 .map(|(i, v)| (i, ((v * 32768.0) as u32).sqrt()))
80 .unwrap()
81}
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 4eb31b105..112e41bcd 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -10,11 +10,15 @@ use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
11use embassy_nrf::spim::{self, Spim}; 11use embassy_nrf::spim::{self, Spim};
12use embassy_nrf::{bind_interrupts, peripherals}; 12use embassy_nrf::{bind_interrupts, peripherals};
13use embassy_time::Delay;
13use embedded_hal_async::spi::ExclusiveDevice; 14use embedded_hal_async::spi::ExclusiveDevice;
14use embedded_io::asynch::Write; 15use embedded_io::asynch::Write;
15use static_cell::make_static; 16use static_cell::make_static;
16use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; 17use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
17 18
19const WIFI_NETWORK: &str = "EmbassyTest";
20const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
21
18bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
19 SPIM3 => spim::InterruptHandler<peripherals::SPI3>; 23 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
20 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; 24 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
@@ -24,7 +28,7 @@ bind_interrupts!(struct Irqs {
24async fn wifi_task( 28async fn wifi_task(
25 runner: hosted::Runner< 29 runner: hosted::Runner<
26 'static, 30 'static,
27 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>>, 31 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>,
28 Input<'static, AnyPin>, 32 Input<'static, AnyPin>,
29 Output<'static, peripherals::P1_05>, 33 Output<'static, peripherals::P1_05>,
30 >, 34 >,
@@ -55,7 +59,7 @@ async fn main(spawner: Spawner) {
55 config.frequency = spim::Frequency::M32; 59 config.frequency = spim::Frequency::M32;
56 config.mode = spim::MODE_2; // !!! 60 config.mode = spim::MODE_2; // !!!
57 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); 61 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
58 let spi = ExclusiveDevice::new(spi, cs); 62 let spi = ExclusiveDevice::new(spi, cs, Delay);
59 63
60 let (device, mut control, runner) = embassy_net_esp_hosted::new( 64 let (device, mut control, runner) = embassy_net_esp_hosted::new(
61 make_static!(embassy_net_esp_hosted::State::new()), 65 make_static!(embassy_net_esp_hosted::State::new()),
@@ -69,7 +73,7 @@ async fn main(spawner: Spawner) {
69 unwrap!(spawner.spawn(wifi_task(runner))); 73 unwrap!(spawner.spawn(wifi_task(runner)));
70 74
71 control.init().await; 75 control.init().await;
72 control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await; 76 control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
73 77
74 let config = embassy_net::Config::dhcpv4(Default::default()); 78 let config = embassy_net::Config::dhcpv4(Default::default());
75 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { 79 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index efb66bae6..f1d45f336 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -14,7 +14,7 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature
14 "defmt", 14 "defmt",
15 "integrated-timers", 15 "integrated-timers",
16] } 16] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = [ 17embassy-time = { version = "0.1.2", path = "../../embassy-time", features = [
18 "defmt", 18 "defmt",
19 "defmt-timestamp-uptime", 19 "defmt-timestamp-uptime",
20] } 20] }
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 48f3a26bb..c812cb3ee 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
@@ -40,9 +40,10 @@ display-interface = "0.4.1"
40byte-slice-cast = { version = "1.2.0", default-features = false } 40byte-slice-cast = { version = "1.2.0", default-features = false }
41smart-leds = "0.3.0" 41smart-leds = "0.3.0"
42heapless = "0.7.15" 42heapless = "0.7.15"
43usbd-hid = "0.6.1"
43 44
44embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
45embedded-hal-async = "0.2.0-alpha.1" 46embedded-hal-async = "0.2.0-alpha.2"
46embedded-io = { version = "0.4.0", features = ["async", "defmt"] } 47embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
47embedded-storage = { version = "0.3" } 48embedded-storage = { version = "0.3" }
48static_cell = { version = "1.1", features = ["nightly"]} 49static_cell = { version = "1.1", features = ["nightly"]}
@@ -53,3 +54,6 @@ rand = { version = "0.8.5", default-features = false }
53 54
54[profile.release] 55[profile.release]
55debug = true 56debug = true
57
58[patch.crates-io]
59lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
index 7c2ca19f7..81a8b8340 100644
--- a/examples/rp/src/bin/adc.rs
+++ b/examples/rp/src/bin/adc.rs
@@ -1,11 +1,15 @@
1//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28.
2//! It also reads the temperature sensor in the chip.
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
4 7
5use defmt::*; 8use defmt::*;
6use embassy_executor::Spawner; 9use embassy_executor::Spawner;
7use embassy_rp::adc::{Adc, Config, InterruptHandler}; 10use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
8use embassy_rp::bind_interrupts; 11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::Pull;
9use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
11 15
@@ -18,18 +22,18 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_rp::init(Default::default()); 22 let p = embassy_rp::init(Default::default());
19 let mut adc = Adc::new(p.ADC, Irqs, Config::default()); 23 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
20 24
21 let mut p26 = p.PIN_26; 25 let mut p26 = Pin::new(p.PIN_26, Pull::None);
22 let mut p27 = p.PIN_27; 26 let mut p27 = Pin::new(p.PIN_27, Pull::None);
23 let mut p28 = p.PIN_28; 27 let mut p28 = Pin::new(p.PIN_28, Pull::None);
24 28
25 loop { 29 loop {
26 let level = adc.read(&mut p26).await; 30 let level = adc.read(&mut p26).await.unwrap();
27 info!("Pin 26 ADC: {}", level); 31 info!("Pin 26 ADC: {}", level);
28 let level = adc.read(&mut p27).await; 32 let level = adc.read(&mut p27).await.unwrap();
29 info!("Pin 27 ADC: {}", level); 33 info!("Pin 27 ADC: {}", level);
30 let level = adc.read(&mut p28).await; 34 let level = adc.read(&mut p28).await.unwrap();
31 info!("Pin 28 ADC: {}", level); 35 info!("Pin 28 ADC: {}", level);
32 let temp = adc.read_temperature().await; 36 let temp = adc.read_temperature().await.unwrap();
33 info!("Temp: {} degrees", convert_to_celsius(temp)); 37 info!("Temp: {} degrees", convert_to_celsius(temp));
34 Timer::after(Duration::from_secs(1)).await; 38 Timer::after(Duration::from_secs(1)).await;
35 } 39 }
@@ -37,5 +41,8 @@ async fn main(_spawner: Spawner) {
37 41
38fn convert_to_celsius(raw_temp: u16) -> f32 { 42fn convert_to_celsius(raw_temp: u16) -> f32 {
39 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet 43 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
40 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721 as f32 44 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721;
45 let sign = if temp < 0.0 { -1.0 } else { 1.0 };
46 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
47 (rounded_temp_x10 as f32) / 10.0
41} 48}
diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs
index 7aa36a19f..295b000f3 100644
--- a/examples/rp/src/bin/blinky.rs
+++ b/examples/rp/src/bin/blinky.rs
@@ -1,3 +1,7 @@
1//! This example test the RP Pico on board LED.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index 0d246c093..d7aa89410 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -1,3 +1,7 @@
1//! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board.
2//!
3//! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index 82568254a..e81da177b 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -15,7 +15,7 @@ use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull}; 15use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 17use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::Duration; 18use embassy_time::{Delay, 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;
@@ -26,7 +26,7 @@ use {defmt_rtt as _, panic_probe as _};
26async fn ethernet_task( 26async fn ethernet_task(
27 runner: Runner< 27 runner: Runner<
28 'static, 28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>>, 29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>, 30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>, 31 Output<'static, PIN_20>,
32 >, 32 >,
@@ -54,8 +54,14 @@ async fn main(spawner: Spawner) {
54 54
55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
56 let state = make_static!(State::<8, 8>::new()); 56 let state = make_static!(State::<8, 8>::new());
57 let (device, runner) = 57 let (device, runner) = embassy_net_w5500::new(
58 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 58 mac_addr,
59 state,
60 ExclusiveDevice::new(spi, cs, Delay),
61 w5500_int,
62 w5500_reset,
63 )
64 .await;
59 unwrap!(spawner.spawn(ethernet_task(runner))); 65 unwrap!(spawner.spawn(ethernet_task(runner)));
60 66
61 // Generate random seed 67 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index d562defad..9dd7ae973 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -17,7 +17,7 @@ use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Input, Level, Output, Pull}; 17use embassy_rp::gpio::{Input, Level, Output, Pull};
18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
19use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Duration, Timer}; 20use embassy_time::{Delay, 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;
@@ -28,7 +28,7 @@ use {defmt_rtt as _, panic_probe as _};
28async fn ethernet_task( 28async fn ethernet_task(
29 runner: Runner< 29 runner: Runner<
30 'static, 30 'static,
31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>>, 31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
32 Input<'static, PIN_21>, 32 Input<'static, PIN_21>,
33 Output<'static, PIN_20>, 33 Output<'static, PIN_20>,
34 >, 34 >,
@@ -57,8 +57,14 @@ async fn main(spawner: Spawner) {
57 57
58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
59 let state = make_static!(State::<8, 8>::new()); 59 let state = make_static!(State::<8, 8>::new());
60 let (device, runner) = 60 let (device, runner) = embassy_net_w5500::new(
61 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 61 mac_addr,
62 state,
63 ExclusiveDevice::new(spi, cs, Delay),
64 w5500_int,
65 w5500_reset,
66 )
67 .await;
62 unwrap!(spawner.spawn(ethernet_task(runner))); 68 unwrap!(spawner.spawn(ethernet_task(runner)));
63 69
64 // Generate random seed 70 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 7f521cdb4..db21c2b6f 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -16,7 +16,7 @@ use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 17use 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 embassy_time::Duration; 19use embassy_time::{Delay, 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;
@@ -26,7 +26,7 @@ use {defmt_rtt as _, panic_probe as _};
26async fn ethernet_task( 26async fn ethernet_task(
27 runner: Runner< 27 runner: Runner<
28 'static, 28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>>, 29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>, 30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>, 31 Output<'static, PIN_20>,
32 >, 32 >,
@@ -55,8 +55,14 @@ async fn main(spawner: Spawner) {
55 55
56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
57 let state = make_static!(State::<8, 8>::new()); 57 let state = make_static!(State::<8, 8>::new());
58 let (device, runner) = 58 let (device, runner) = embassy_net_w5500::new(
59 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 59 mac_addr,
60 state,
61 ExclusiveDevice::new(spi, cs, Delay),
62 w5500_int,
63 w5500_reset,
64 )
65 .await;
60 unwrap!(spawner.spawn(ethernet_task(runner))); 66 unwrap!(spawner.spawn(ethernet_task(runner)));
61 67
62 // Generate random seed 68 // Generate random seed
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index ada86ae55..038432b17 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -16,6 +16,7 @@ use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 17use 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 embassy_time::Delay;
19use embedded_hal_async::spi::ExclusiveDevice; 20use embedded_hal_async::spi::ExclusiveDevice;
20use rand::RngCore; 21use rand::RngCore;
21use static_cell::make_static; 22use static_cell::make_static;
@@ -24,7 +25,7 @@ use {defmt_rtt as _, panic_probe as _};
24async fn ethernet_task( 25async fn ethernet_task(
25 runner: Runner< 26 runner: Runner<
26 'static, 27 'static,
27 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>>, 28 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
28 Input<'static, PIN_21>, 29 Input<'static, PIN_21>,
29 Output<'static, PIN_20>, 30 Output<'static, PIN_20>,
30 >, 31 >,
@@ -52,8 +53,14 @@ async fn main(spawner: Spawner) {
52 53
53 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 54 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
54 let state = make_static!(State::<8, 8>::new()); 55 let state = make_static!(State::<8, 8>::new());
55 let (device, runner) = 56 let (device, runner) = embassy_net_w5500::new(
56 embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; 57 mac_addr,
58 state,
59 ExclusiveDevice::new(spi, cs, Delay),
60 w5500_int,
61 w5500_reset,
62 )
63 .await;
57 unwrap!(spawner.spawn(ethernet_task(runner))); 64 unwrap!(spawner.spawn(ethernet_task(runner)));
58 65
59 // Generate random seed 66 // Generate random seed
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
index 19076150c..4c4982acc 100644
--- a/examples/rp/src/bin/flash.rs
+++ b/examples/rp/src/bin/flash.rs
@@ -1,3 +1,5 @@
1//! This example test the flash connected to the RP2040 chip.
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs
index 52d13a9d5..bf58044d5 100644
--- a/examples/rp/src/bin/gpio_async.rs
+++ b/examples/rp/src/bin/gpio_async.rs
@@ -1,3 +1,7 @@
1//! This example shows how async gpio can be used with a RP2040.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -9,8 +13,6 @@ use embassy_time::{Duration, Timer};
9use gpio::{Input, Level, Output, Pull}; 13use gpio::{Input, Level, Output, Pull};
10use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
11 15
12/// This example shows how async gpio can be used with a RP2040.
13///
14/// It requires an external signal to be manually triggered on PIN 16. For 16/// It requires an external signal to be manually triggered on PIN 16. For
15/// example, this could be accomplished using an external power source with a 17/// example, this could be accomplished using an external power source with a
16/// button so that it is possible to toggle the signal from low to high. 18/// button so that it is possible to toggle the signal from low to high.
diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs
index 64461fc5f..0a3b5fa98 100644
--- a/examples/rp/src/bin/gpout.rs
+++ b/examples/rp/src/bin/gpout.rs
@@ -1,3 +1,7 @@
1//! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
index cf3cf742c..93224bc43 100644
--- a/examples/rp/src/bin/i2c_async.rs
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -1,3 +1,8 @@
1//! This example shows how to communicate asynchronous using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
1#![no_std] 6#![no_std]
2#![no_main] 7#![no_main]
3#![feature(type_alias_impl_trait)] 8#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/i2c_blocking.rs b/examples/rp/src/bin/i2c_blocking.rs
index 7623e33c8..1c8c2039d 100644
--- a/examples/rp/src/bin/i2c_blocking.rs
+++ b/examples/rp/src/bin/i2c_blocking.rs
@@ -1,3 +1,8 @@
1//! This example shows how to communicate using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
1#![no_std] 6#![no_std]
2#![no_main] 7#![no_main]
3#![feature(type_alias_impl_trait)] 8#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/lora_lorawan.rs b/examples/rp/src/bin/lora_lorawan.rs
index a9c84bf95..d631fafa1 100644
--- a/examples/rp/src/bin/lora_lorawan.rs
+++ b/examples/rp/src/bin/lora_lorawan.rs
@@ -1,5 +1,6 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio. 1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LoRaWAN join functionality. 2//! It demonstrates LoRaWAN join functionality.
3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
5#![macro_use] 6#![macro_use]
diff --git a/examples/rp/src/bin/lora_p2p_receive.rs b/examples/rp/src/bin/lora_p2p_receive.rs
index 250419202..396d669de 100644
--- a/examples/rp/src/bin/lora_p2p_receive.rs
+++ b/examples/rp/src/bin/lora_p2p_receive.rs
@@ -1,5 +1,6 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio. 1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example. 2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
5#![macro_use] 6#![macro_use]
diff --git a/examples/rp/src/bin/lora_p2p_send.rs b/examples/rp/src/bin/lora_p2p_send.rs
index 3a0544b17..a0f70fa5c 100644
--- a/examples/rp/src/bin/lora_p2p_send.rs
+++ b/examples/rp/src/bin/lora_p2p_send.rs
@@ -1,5 +1,6 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio. 1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality. 2//! It demonstrates LORA P2P send functionality.
3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
5#![macro_use] 6#![macro_use]
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
index eef2f7a53..89a62818d 100644
--- a/examples/rp/src/bin/lora_p2p_send_multicore.rs
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -1,5 +1,6 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio. 1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality using the second core, with data provided by the first core. 2//! It demonstrates LORA P2P send functionality using the second core, with data provided by the first core.
3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
5#![macro_use] 6#![macro_use]
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index 57278dd6c..893b724bf 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -1,3 +1,7 @@
1//! This example shows how to send messages between the two cores in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index 79eda1a09..c001d6440 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -1,15 +1,22 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
4use defmt::info; 6use defmt::info;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
6use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
7use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine}; 10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
8use embassy_rp::relocate::RelocatedProgram; 11use embassy_rp::relocate::RelocatedProgram;
9use fixed::traits::ToFixed; 12use fixed::traits::ToFixed;
10use fixed_macro::types::U56F8; 13use fixed_macro::types::U56F8;
11use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
12 15
16bind_interrupts!(struct Irqs {
17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
18});
19
13fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { 20fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
14 // Setup sm0 21 // Setup sm0
15 22
@@ -49,7 +56,14 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
49 // Setupm sm1 56 // Setupm sm1
50 57
51 // Read 0b10101 repeatedly until ISR is full 58 // Read 0b10101 repeatedly until ISR is full
52 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); 59 let prg = pio_proc::pio_asm!(
60 //
61 ".origin 8",
62 "set x, 0x15",
63 ".wrap_target",
64 "in x, 5 [31]",
65 ".wrap",
66 );
53 67
54 let relocated = RelocatedProgram::new(&prg.program); 68 let relocated = RelocatedProgram::new(&prg.program);
55 let mut cfg = Config::default(); 69 let mut cfg = Config::default();
@@ -110,7 +124,7 @@ async fn main(spawner: Spawner) {
110 mut sm1, 124 mut sm1,
111 mut sm2, 125 mut sm2,
112 .. 126 ..
113 } = Pio::new(pio); 127 } = Pio::new(pio, Irqs);
114 128
115 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0); 129 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
116 setup_pio_task_sm1(&mut common, &mut sm1); 130 setup_pio_task_sm1(&mut common, &mut sm1);
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 05c0ebb16..9ab72e1f3 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -1,16 +1,23 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
4use defmt::info; 6use defmt::info;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
7use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection}; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
8use embassy_rp::relocate::RelocatedProgram; 11use embassy_rp::relocate::RelocatedProgram;
9use embassy_rp::Peripheral; 12use embassy_rp::{bind_interrupts, Peripheral};
10use fixed::traits::ToFixed; 13use fixed::traits::ToFixed;
11use fixed_macro::types::U56F8; 14use fixed_macro::types::U56F8;
12use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
13 16
17bind_interrupts!(struct Irqs {
18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
19});
20
14fn swap_nibbles(v: u32) -> u32 { 21fn swap_nibbles(v: u32) -> u32 {
15 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4; 22 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
16 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8; 23 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
@@ -25,7 +32,7 @@ async fn main(_spawner: Spawner) {
25 mut common, 32 mut common,
26 sm0: mut sm, 33 sm0: mut sm,
27 .. 34 ..
28 } = Pio::new(pio); 35 } = Pio::new(pio, Irqs);
29 36
30 let prg = pio_proc::pio_asm!( 37 let prg = pio_proc::pio_asm!(
31 ".origin 0", 38 ".origin 0",
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index bfc6c9908..8aedd24b6 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -1,3 +1,6 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display.
2//! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -7,13 +10,19 @@ use core::fmt::Write;
7use embassy_executor::Spawner; 10use embassy_executor::Spawner;
8use embassy_rp::dma::{AnyChannel, Channel}; 11use embassy_rp::dma::{AnyChannel, Channel};
9use embassy_rp::peripherals::PIO0; 12use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; 13use embassy_rp::pio::{
14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
15};
11use embassy_rp::pwm::{self, Pwm}; 16use embassy_rp::pwm::{self, Pwm};
12use embassy_rp::relocate::RelocatedProgram; 17use embassy_rp::relocate::RelocatedProgram;
13use embassy_rp::{into_ref, Peripheral, PeripheralRef}; 18use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
14use embassy_time::{Duration, Instant, Timer}; 19use embassy_time::{Duration, Instant, Timer};
15use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
16 21
22bind_interrupts!(pub struct Irqs {
23 PIO0_IRQ_0 => InterruptHandler<PIO0>;
24});
25
17#[embassy_executor::main] 26#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
19 // this test assumes a 2x16 HD44780 display attached as follow: 28 // this test assumes a 2x16 HD44780 display attached as follow:
@@ -37,7 +46,7 @@ async fn main(_spawner: Spawner) {
37 }); 46 });
38 47
39 let mut hd = HD44780::new( 48 let mut hd = HD44780::new(
40 p.PIO0, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, 49 p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6,
41 ) 50 )
42 .await; 51 .await;
43 52
@@ -72,6 +81,7 @@ pub struct HD44780<'l> {
72impl<'l> HD44780<'l> { 81impl<'l> HD44780<'l> {
73 pub async fn new( 82 pub async fn new(
74 pio: impl Peripheral<P = PIO0> + 'l, 83 pio: impl Peripheral<P = PIO0> + 'l,
84 irq: Irqs,
75 dma: impl Peripheral<P = impl Channel> + 'l, 85 dma: impl Peripheral<P = impl Channel> + 'l,
76 rs: impl PioPin, 86 rs: impl PioPin,
77 rw: impl PioPin, 87 rw: impl PioPin,
@@ -88,7 +98,7 @@ impl<'l> HD44780<'l> {
88 mut irq0, 98 mut irq0,
89 mut sm0, 99 mut sm0,
90 .. 100 ..
91 } = Pio::new(pio); 101 } = Pio::new(pio, irq);
92 102
93 // takes command words (<wait:24> <command:4> <0:4>) 103 // takes command words (<wait:24> <command:4> <0:4>)
94 let prg = pio_proc::pio_asm!( 104 let prg = pio_proc::pio_asm!(
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index 26422421f..3de2bd48d 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -1,3 +1,6 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules.
2//! See (https://www.sparkfun.com/categories/tags/ws2812)
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -5,15 +8,22 @@
5use defmt::*; 8use defmt::*;
6use embassy_executor::Spawner; 9use embassy_executor::Spawner;
7use embassy_rp::dma::{AnyChannel, Channel}; 10use embassy_rp::dma::{AnyChannel, Channel};
8use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; 11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{
13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
14};
9use embassy_rp::relocate::RelocatedProgram; 15use embassy_rp::relocate::RelocatedProgram;
10use embassy_rp::{clocks, into_ref, Peripheral, PeripheralRef}; 16use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
11use embassy_time::{Duration, Timer}; 17use embassy_time::{Duration, Timer};
12use fixed::types::U24F8; 18use fixed::types::U24F8;
13use fixed_macro::fixed; 19use fixed_macro::fixed;
14use smart_leds::RGB8; 20use smart_leds::RGB8;
15use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
16 22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
17pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { 27pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
18 dma: PeripheralRef<'d, AnyChannel>, 28 dma: PeripheralRef<'d, AnyChannel>,
19 sm: StateMachine<'d, P, S>, 29 sm: StateMachine<'d, P, S>,
@@ -123,7 +133,7 @@ async fn main(_spawner: Spawner) {
123 info!("Start"); 133 info!("Start");
124 let p = embassy_rp::init(Default::default()); 134 let p = embassy_rp::init(Default::default());
125 135
126 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0); 136 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
127 137
128 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit 138 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
129 // feather boards for the 2040 both have one built in. 139 // feather boards for the 2040 both have one built in.
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
index 2b3d5d97a..9d919287c 100644
--- a/examples/rp/src/bin/pwm.rs
+++ b/examples/rp/src/bin/pwm.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs
new file mode 100644
index 000000000..15aa8243f
--- /dev/null
+++ b/examples/rp/src/bin/rtc.rs
@@ -0,0 +1,46 @@
1//! This example shows how to use RTC (Real Time Clock) in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_rp::init(Default::default());
16 info!("Wait for 20s");
17
18 let mut rtc = Rtc::new(p.RTC);
19
20 if !rtc.is_running() {
21 info!("Start RTC");
22 let now = DateTime {
23 year: 2000,
24 month: 1,
25 day: 1,
26 day_of_week: DayOfWeek::Saturday,
27 hour: 0,
28 minute: 0,
29 second: 0,
30 };
31 rtc.set_datetime(now).unwrap();
32 }
33
34 Timer::after(Duration::from_millis(20000)).await;
35
36 if let Ok(dt) = rtc.now() {
37 info!(
38 "Now: {}-{:02}-{:02} {}:{:02}:{:02}",
39 dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second,
40 );
41 }
42
43 info!("Reboot.");
44 Timer::after(Duration::from_millis(200)).await;
45 cortex_m::peripheral::SCB::sys_reset();
46}
diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs
index a830a17a2..602348f7a 100644
--- a/examples/rp/src/bin/spi.rs
+++ b/examples/rp/src/bin/spi.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example for resistive touch sensor in Waveshare Pico-ResTouch
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs
index 671a9caaf..328074e8b 100644
--- a/examples/rp/src/bin/spi_async.rs
+++ b/examples/rp/src/bin/spi_async.rs
@@ -1,3 +1,6 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back.
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index 85a19ce07..26c258e1c 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -1,3 +1,8 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
5
1#![no_std] 6#![no_std]
2#![no_main] 7#![no_main]
3#![feature(type_alias_impl_trait)] 8#![feature(type_alias_impl_trait)]
@@ -175,7 +180,7 @@ mod touch {
175mod my_display_interface { 180mod my_display_interface {
176 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; 181 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
177 use embedded_hal_1::digital::OutputPin; 182 use embedded_hal_1::digital::OutputPin;
178 use embedded_hal_1::spi::SpiDeviceWrite; 183 use embedded_hal_1::spi::SpiDevice;
179 184
180 /// SPI display interface. 185 /// SPI display interface.
181 /// 186 ///
@@ -187,7 +192,7 @@ mod my_display_interface {
187 192
188 impl<SPI, DC> SPIDeviceInterface<SPI, DC> 193 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
189 where 194 where
190 SPI: SpiDeviceWrite, 195 SPI: SpiDevice,
191 DC: OutputPin, 196 DC: OutputPin,
192 { 197 {
193 /// Create new SPI interface for communciation with a display driver 198 /// Create new SPI interface for communciation with a display driver
@@ -198,7 +203,7 @@ mod my_display_interface {
198 203
199 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> 204 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
200 where 205 where
201 SPI: SpiDeviceWrite, 206 SPI: SpiDevice,
202 DC: OutputPin, 207 DC: OutputPin,
203 { 208 {
204 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { 209 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
@@ -218,7 +223,7 @@ mod my_display_interface {
218 } 223 }
219 } 224 }
220 225
221 fn send_u8<T: SpiDeviceWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { 226 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
222 match words { 227 match words {
223 DataFormat::U8(slice) => spi.write(slice), 228 DataFormat::U8(slice) => spi.write(slice),
224 DataFormat::U16(slice) => { 229 DataFormat::U16(slice) => {
diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs
index 05177a6b4..451c3c396 100644
--- a/examples/rp/src/bin/uart.rs
+++ b/examples/rp/src/bin/uart.rs
@@ -1,3 +1,9 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. Only output on pin 0 is tested.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
1#![no_std] 7#![no_std]
2#![no_main] 8#![no_main]
3#![feature(type_alias_impl_trait)] 9#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index 9df99bd58..735201718 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -1,3 +1,9 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
1#![no_std] 7#![no_std]
2#![no_main] 8#![no_main]
3#![feature(type_alias_impl_trait)] 9#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
index c0943a1b8..c1515a911 100644
--- a/examples/rp/src/bin/uart_unidir.rs
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -1,5 +1,9 @@
1//! test TX-only and RX-only UARTs. You need to connect GPIO0 to GPIO5 for 1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for
2//! this to work 4//! this to work
5//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
6//! with its UART port.
3 7
4#![no_std] 8#![no_std]
5#![no_main] 9#![no_main]
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 91d1ec8e7..0a08f667e 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This is a CDC-NCM class implementation, aka Ethernet over USB.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..99af1f02f
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,188 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::sync::atomic::{AtomicBool, Ordering};
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
15use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBCTRL_IRQ => InterruptHandler<USB>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27 // Create the driver, from the HAL.
28 let driver = Driver::new(p.USB, Irqs);
29
30 // Create embassy-usb Config
31 let mut config = Config::new(0xc0de, 0xcafe);
32 config.manufacturer = Some("Embassy");
33 config.product = Some("HID keyboard example");
34 config.serial_number = Some("12345678");
35 config.max_power = 100;
36 config.max_packet_size_0 = 64;
37
38 // Create embassy-usb DeviceBuilder using the driver and config.
39 // It needs some buffers for building the descriptors.
40 let mut device_descriptor = [0; 256];
41 let mut config_descriptor = [0; 256];
42 let mut bos_descriptor = [0; 256];
43 // You can also add a Microsoft OS descriptor.
44 // let mut msos_descriptor = [0; 256];
45 let mut control_buf = [0; 64];
46 let request_handler = MyRequestHandler {};
47 let mut device_handler = MyDeviceHandler::new();
48
49 let mut state = State::new();
50
51 let mut builder = Builder::new(
52 driver,
53 config,
54 &mut device_descriptor,
55 &mut config_descriptor,
56 &mut bos_descriptor,
57 // &mut msos_descriptor,
58 &mut control_buf,
59 );
60
61 builder.handler(&mut device_handler);
62
63 // Create classes on the builder.
64 let config = embassy_usb::class::hid::Config {
65 report_descriptor: KeyboardReport::desc(),
66 request_handler: Some(&request_handler),
67 poll_ms: 60,
68 max_packet_size: 64,
69 };
70 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Set up the signal pin that will be used to trigger the keyboard.
79 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
80
81 let (reader, mut writer) = hid.split();
82
83 // Do stuff with the class!
84 let in_fut = async {
85 loop {
86 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier)
90 let report = KeyboardReport {
91 keycodes: [4, 0, 0, 0, 0, 0],
92 leds: 0,
93 modifier: 0,
94 reserved: 0,
95 };
96 // Send the report.
97 match writer.write_serialize(&report).await {
98 Ok(()) => {}
99 Err(e) => warn!("Failed to send report: {:?}", e),
100 };
101 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED");
103 let report = KeyboardReport {
104 keycodes: [0, 0, 0, 0, 0, 0],
105 leds: 0,
106 modifier: 0,
107 reserved: 0,
108 };
109 match writer.write_serialize(&report).await {
110 Ok(()) => {}
111 Err(e) => warn!("Failed to send report: {:?}", e),
112 };
113 }
114 };
115
116 let out_fut = async {
117 reader.run(false, &request_handler).await;
118 };
119
120 // Run everything concurrently.
121 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
122 join(usb_fut, join(in_fut, out_fut)).await;
123}
124
125struct MyRequestHandler {}
126
127impl RequestHandler for MyRequestHandler {
128 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
129 info!("Get report for {:?}", id);
130 None
131 }
132
133 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
134 info!("Set report for {:?}: {=[u8]}", id, data);
135 OutResponse::Accepted
136 }
137
138 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur);
140 }
141
142 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
143 info!("Get idle rate for {:?}", id);
144 None
145 }
146}
147
148struct MyDeviceHandler {
149 configured: AtomicBool,
150}
151
152impl MyDeviceHandler {
153 fn new() -> Self {
154 MyDeviceHandler {
155 configured: AtomicBool::new(false),
156 }
157 }
158}
159
160impl Handler for MyDeviceHandler {
161 fn enabled(&mut self, enabled: bool) {
162 self.configured.store(false, Ordering::Relaxed);
163 if enabled {
164 info!("Device enabled");
165 } else {
166 info!("Device disabled");
167 }
168 }
169
170 fn reset(&mut self) {
171 self.configured.store(false, Ordering::Relaxed);
172 info!("Bus reset, the Vbus current limit is 100mA");
173 }
174
175 fn addressed(&mut self, addr: u8) {
176 self.configured.store(false, Ordering::Relaxed);
177 info!("USB address set to: {}", addr);
178 }
179
180 fn configured(&mut self, configured: bool) {
181 self.configured.store(configured, Ordering::Relaxed);
182 if configured {
183 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
184 } else {
185 info!("Device is no longer configured, the Vbus current limit is 100mA.");
186 }
187 }
188}
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
index 7c90d0ca3..9c5e6897d 100644
--- a/examples/rp/src/bin/usb_logger.rs
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates the possibility to send log::info/warn/error/debug! to USB serial port.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index ca728536c..164e2052d 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a USB serial port that echos.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs
index ece5cfe38..fe5eaf926 100644
--- a/examples/rp/src/bin/watchdog.rs
+++ b/examples/rp/src/bin/watchdog.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use Watchdog in the RP2040 chip.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 310e84d92..e3e393445 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -1,3 +1,6 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Creates an Access point Wifi network and creates a TCP endpoint on port 1234.
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -11,14 +14,19 @@ use defmt::*;
11use embassy_executor::Spawner; 14use embassy_executor::Spawner;
12use embassy_net::tcp::TcpSocket; 15use embassy_net::tcp::TcpSocket;
13use embassy_net::{Config, Stack, StackResources}; 16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
14use embassy_rp::gpio::{Level, Output}; 18use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio; 20use embassy_rp::pio::{InterruptHandler, Pio};
17use embassy_time::Duration; 21use embassy_time::Duration;
18use embedded_io::asynch::Write; 22use embedded_io::asynch::Write;
19use static_cell::make_static; 23use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
21 25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
22#[embassy_executor::task] 30#[embassy_executor::task]
23async fn wifi_task( 31async fn wifi_task(
24 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 32 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -49,7 +57,7 @@ async fn main(spawner: Spawner) {
49 57
50 let pwr = Output::new(p.PIN_23, Level::Low); 58 let pwr = Output::new(p.PIN_23, Level::Low);
51 let cs = Output::new(p.PIN_25, Level::High); 59 let cs = Output::new(p.PIN_25, Level::High);
52 let mut pio = Pio::new(p.PIO0); 60 let mut pio = Pio::new(p.PIO0, Irqs);
53 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 61 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
54 62
55 let state = make_static!(cyw43::State::new()); 63 let state = make_static!(cyw43::State::new());
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index bbcb1b5ec..33d43788c 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -1,3 +1,7 @@
1//! This example test the RP Pico W on board LED.
2//!
3//! It does not work with the RP Pico board. See blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -5,13 +9,18 @@
5use cyw43_pio::PioSpi; 9use cyw43_pio::PioSpi;
6use defmt::*; 10use defmt::*;
7use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
8use embassy_rp::gpio::{Level, Output}; 13use embassy_rp::gpio::{Level, Output};
9use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
10use embassy_rp::pio::Pio; 15use embassy_rp::pio::{InterruptHandler, Pio};
11use embassy_time::{Duration, Timer}; 16use embassy_time::{Duration, Timer};
12use static_cell::make_static; 17use static_cell::make_static;
13use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
14 19
20bind_interrupts!(struct Irqs {
21 PIO0_IRQ_0 => InterruptHandler<PIO0>;
22});
23
15#[embassy_executor::task] 24#[embassy_executor::task]
16async fn wifi_task( 25async fn wifi_task(
17 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 26 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -34,7 +43,7 @@ async fn main(spawner: Spawner) {
34 43
35 let pwr = Output::new(p.PIN_23, Level::Low); 44 let pwr = Output::new(p.PIN_23, Level::Low);
36 let cs = Output::new(p.PIN_25, Level::High); 45 let cs = Output::new(p.PIN_25, Level::High);
37 let mut pio = Pio::new(p.PIO0); 46 let mut pio = Pio::new(p.PIO0, Irqs);
38 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 47 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
39 48
40 let state = make_static!(cyw43::State::new()); 49 let state = make_static!(cyw43::State::new());
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 391e12282..743fab617 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -1,3 +1,6 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Scans Wifi for ssid names.
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -10,12 +13,17 @@ use cyw43_pio::PioSpi;
10use defmt::*; 13use defmt::*;
11use embassy_executor::Spawner; 14use embassy_executor::Spawner;
12use embassy_net::Stack; 15use embassy_net::Stack;
16use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 18use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::Pio; 19use embassy_rp::pio::{InterruptHandler, Pio};
16use static_cell::make_static; 20use static_cell::make_static;
17use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
18 22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
19#[embassy_executor::task] 27#[embassy_executor::task]
20async fn wifi_task( 28async fn wifi_task(
21 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 29 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -46,7 +54,7 @@ async fn main(spawner: Spawner) {
46 54
47 let pwr = Output::new(p.PIN_23, Level::Low); 55 let pwr = Output::new(p.PIN_23, Level::Low);
48 let cs = Output::new(p.PIN_25, Level::High); 56 let cs = Output::new(p.PIN_25, Level::High);
49 let mut pio = Pio::new(p.PIO0); 57 let mut pio = Pio::new(p.PIO0, Irqs);
50 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 58 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
51 59
52 let state = make_static!(cyw43::State::new()); 60 let state = make_static!(cyw43::State::new());
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index e9d1079a6..0223a3636 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -1,3 +1,6 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Connects to specified Wifi network and creates a TCP endpoint on port 1234.
3
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -11,14 +14,22 @@ use defmt::*;
11use embassy_executor::Spawner; 14use embassy_executor::Spawner;
12use embassy_net::tcp::TcpSocket; 15use embassy_net::tcp::TcpSocket;
13use embassy_net::{Config, Stack, StackResources}; 16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
14use embassy_rp::gpio::{Level, Output}; 18use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio; 20use embassy_rp::pio::{InterruptHandler, Pio};
17use embassy_time::Duration; 21use embassy_time::Duration;
18use embedded_io::asynch::Write; 22use embedded_io::asynch::Write;
19use static_cell::make_static; 23use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
21 25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30const WIFI_NETWORK: &str = "EmbassyTest";
31const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
32
22#[embassy_executor::task] 33#[embassy_executor::task]
23async fn wifi_task( 34async fn wifi_task(
24 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, 35 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
@@ -49,7 +60,7 @@ async fn main(spawner: Spawner) {
49 60
50 let pwr = Output::new(p.PIN_23, Level::Low); 61 let pwr = Output::new(p.PIN_23, Level::Low);
51 let cs = Output::new(p.PIN_25, Level::High); 62 let cs = Output::new(p.PIN_25, Level::High);
52 let mut pio = Pio::new(p.PIO0); 63 let mut pio = Pio::new(p.PIO0, Irqs);
53 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 64 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
54 65
55 let state = make_static!(cyw43::State::new()); 66 let state = make_static!(cyw43::State::new());
@@ -82,8 +93,8 @@ async fn main(spawner: Spawner) {
82 unwrap!(spawner.spawn(net_task(stack))); 93 unwrap!(spawner.spawn(net_task(stack)));
83 94
84 loop { 95 loop {
85 //control.join_open(env!("WIFI_NETWORK")).await; 96 //control.join_open(WIFI_NETWORK).await;
86 match control.join_wpa2(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await { 97 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await {
87 Ok(_) => break, 98 Ok(_) => break,
88 Err(err) => { 99 Err(err) => {
89 info!("join failed with status={}", err.status); 100 info!("join failed with status={}", err.status);
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 878ad8c5a..92933ab50 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "std", "nightly"] }
11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "unstable-traits", "proto-ipv6"] } 11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "unstable-traits", "proto-ipv6"] }
12embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" } 12embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" }
13embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] } 13embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] }
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 43f432520..26837abef 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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
13defmt = "0.3" 13defmt = "0.3"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 8d2248ed0..b7b5eaa99 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -14,6 +14,6 @@ defmt-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 = ["nightly", "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.2", 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 = { version = "1.1", features = ["nightly"]} 19static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index d34fd439a..29cad5b67 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 5e3e0d0f7..652210c7f 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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
13defmt = "0.3" 13defmt = "0.3"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 29ab2009c..489d0ff4c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 7ecb64fce..c1c821364 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } 13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index da8955053..08bed88db 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -2,8 +2,8 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::can::bxcan::filter::Mask32; 8use embassy_stm32::can::bxcan::filter::Mask32;
9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
@@ -19,8 +19,8 @@ bind_interrupts!(struct Irqs {
19 CAN1_TX => TxInterruptHandler<CAN1>; 19 CAN1_TX => TxInterruptHandler<CAN1>;
20}); 20});
21 21
22#[entry] 22#[embassy_executor::main]
23fn main() -> ! { 23async fn main(_spawner: Spawner) {
24 info!("Hello World!"); 24 info!("Hello World!");
25 25
26 let mut p = embassy_stm32::init(Default::default()); 26 let mut p = embassy_stm32::init(Default::default());
@@ -34,9 +34,12 @@ fn main() -> ! {
34 34
35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); 35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
36 36
37 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 37 can.as_mut()
38 .modify_filters()
39 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
38 40
39 can.modify_config() 41 can.as_mut()
42 .modify_config()
40 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/ 43 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
41 .set_loopback(true) // Receive own frames 44 .set_loopback(true) // Receive own frames
42 .set_silent(true) 45 .set_silent(true)
@@ -45,9 +48,8 @@ fn main() -> ! {
45 let mut i: u8 = 0; 48 let mut i: u8 = 0;
46 loop { 49 loop {
47 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 50 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
48 unwrap!(nb::block!(can.transmit(&tx_frame))); 51 can.write(&tx_frame).await;
49 while !can.is_transmitter_idle() {} 52 let (_, rx_frame) = can.read().await.unwrap();
50 let rx_frame = unwrap!(nb::block!(can.receive()));
51 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]); 53 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
52 i += 1; 54 i += 1;
53 } 55 }
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
new file mode 100644
index 000000000..d0b164393
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -0,0 +1,111 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz;
14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write;
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19bind_interrupts!(struct Irqs {
20 ETH => eth::InterruptHandler;
21});
22
23type Device = Ethernet<'static, ETH, GenericSMI>;
24
25#[embassy_executor::task]
26async fn net_task(stack: &'static Stack<Device>) -> ! {
27 stack.run().await
28}
29
30#[embassy_executor::main]
31async fn main(spawner: Spawner) -> ! {
32 let mut config = Config::default();
33 config.rcc.sys_ck = Some(mhz(200));
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 // Generate random seed.
39 let mut rng = Rng::new(p.RNG);
40 let mut seed = [0; 8];
41 let _ = rng.async_fill_bytes(&mut seed).await;
42 let seed = u64::from_le_bytes(seed);
43
44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
45
46 let device = Ethernet::new(
47 make_static!(PacketQueue::<16, 16>::new()),
48 p.ETH,
49 Irqs,
50 p.PA1,
51 p.PA2,
52 p.PC1,
53 p.PA7,
54 p.PC4,
55 p.PC5,
56 p.PG13,
57 p.PB13,
58 p.PG11,
59 GenericSMI::new(),
60 mac_addr,
61 0,
62 );
63
64 let config = embassy_net::Config::dhcpv4(Default::default());
65 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
66 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
67 // dns_servers: Vec::new(),
68 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
69 //});
70
71 // Init network stack
72 let stack = &*make_static!(Stack::new(
73 device,
74 config,
75 make_static!(StackResources::<2>::new()),
76 seed
77 ));
78
79 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack)));
81
82 info!("Network task initialized");
83
84 // Then we can use it!
85 let mut rx_buffer = [0; 4096];
86 let mut tx_buffer = [0; 4096];
87
88 loop {
89 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
90
91 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
92
93 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
94 info!("connecting...");
95 let r = socket.connect(remote_endpoint).await;
96 if let Err(e) = r {
97 info!("connect error: {:?}", e);
98 continue;
99 }
100 info!("connected!");
101 let buf = [0; 1024];
102 loop {
103 let r = socket.write_all(&buf).await;
104 if let Err(e) = r {
105 info!("write error: {:?}", e);
106 continue;
107 }
108 Timer::after(Duration::from_secs(1)).await;
109 }
110 }
111}
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 657251c50..84d7b79c5 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embedded-io = { version = "0.4.0", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
new file mode 100644
index 000000000..1b5b377ea
--- /dev/null
+++ b/examples/stm32f7/src/bin/can.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::can::bxcan::filter::Mask32;
9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
10use embassy_stm32::can::{
11 Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
12};
13use embassy_stm32::gpio::{Input, Pull};
14use embassy_stm32::peripherals::CAN3;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 CAN3_RX0 => Rx0InterruptHandler<CAN3>;
19 CAN3_RX1 => Rx1InterruptHandler<CAN3>;
20 CAN3_SCE => SceInterruptHandler<CAN3>;
21 CAN3_TX => TxInterruptHandler<CAN3>;
22});
23
24#[embassy_executor::task]
25pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) {
26 loop {
27 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]);
28 tx.write(&frame).await;
29 embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
30 }
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 info!("Hello World!");
36
37 let mut p = embassy_stm32::init(Default::default());
38
39 // The next two lines are a workaround for testing without transceiver.
40 // To synchronise to the bus the RX input needs to see a high level.
41 // Use `mem::forget()` to release the borrow on the pin but keep the
42 // pull-up resistor enabled.
43 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
44 core::mem::forget(rx_pin);
45
46 let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
47 can.as_mut()
48 .modify_filters()
49 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
50
51 can.as_mut()
52 .modify_config()
53 .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
54 .set_loopback(true)
55 .enable();
56
57 let (tx, mut rx) = can.split();
58
59 let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx);
60 spawner.spawn(send_can_message(tx)).unwrap();
61
62 loop {
63 let frame = rx.read().await.unwrap();
64 println!("Received: {:?}", frame);
65 }
66}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index fde6a7576..c6b2ba45c 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -57,7 +57,7 @@ async fn main(spawner: Spawner) -> ! {
57 p.PG13, 57 p.PG13,
58 p.PB13, 58 p.PB13,
59 p.PG11, 59 p.PG11,
60 GenericSMI, 60 GenericSMI::new(),
61 mac_addr, 61 mac_addr,
62 0, 62 0,
63 ); 63 );
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index c5245757b..c88282d91 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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
13defmt = "0.3" 13defmt = "0.3"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index fbfbc6408..18bd03c39 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index ebe511347..227bc28b4 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embedded-io = { version = "0.4.0", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
23embedded-hal-async = { version = "=0.2.0-alpha.1" } 23embedded-hal-async = { version = "=0.2.0-alpha.2" }
24embedded-nal-async = "0.4.0" 24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 78c8282a6..0bff85ed8 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -76,7 +76,7 @@ async fn main(spawner: Spawner) -> ! {
76 p.PG13, 76 p.PG13,
77 p.PB15, 77 p.PB15,
78 p.PG11, 78 p.PG11,
79 GenericSMI, 79 GenericSMI::new(),
80 mac_addr, 80 mac_addr,
81 0, 81 0,
82 ); 82 );
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 62ef5e9e4..768702fa9 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embedded-io = { version = "0.4.0", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
23embedded-hal-async = { version = "=0.2.0-alpha.1" } 23embedded-hal-async = { version = "=0.2.0-alpha.2" }
24embedded-nal-async = "0.4.0" 24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 12d37f7a4..cfafcaed1 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -58,7 +58,7 @@ async fn main(spawner: Spawner) -> ! {
58 p.PG13, 58 p.PG13,
59 p.PB13, 59 p.PB13,
60 p.PG11, 60 p.PG11,
61 GenericSMI, 61 GenericSMI::new(),
62 mac_addr, 62 mac_addr,
63 0, 63 0,
64 ); 64 );
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 6078fc3fe..4ed737578 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -59,7 +59,7 @@ async fn main(spawner: Spawner) -> ! {
59 p.PG13, 59 p.PG13,
60 p.PB13, 60 p.PB13,
61 p.PG11, 61 p.PG11,
62 GenericSMI, 62 GenericSMI::new(),
63 mac_addr, 63 mac_addr,
64 0, 64 0,
65 ); 65 );
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 2ead714e4..747cec7bf 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -12,7 +12,7 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab
12[dependencies] 12[dependencies]
13embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 13embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
14embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 14embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
15embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 15embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
16embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 16embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
17embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } 17embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
18lora-phy = { version = "1", optional = true } 18lora-phy = { version = "1", optional = true }
@@ -32,3 +32,6 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
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.1" 34static_cell = "1.1"
35
36[patch.crates-io]
37lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 93d48abeb..dcca1cc3d 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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
13defmt = "0.3" 13defmt = "0.3"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 3bb473ef5..c55558518 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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", "chrono"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
@@ -18,10 +18,11 @@ defmt-rtt = "0.4"
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
22embedded-hal-async = { version = "=0.2.0-alpha.1" } 22embedded-hal-async = { version = "=0.2.0-alpha.2" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.7.5", default-features = false } 25heapless = { version = "0.7.5", default-features = false }
26chrono = { version = "^0.4", default-features = false }
26 27
27micromath = "2.0.0" 28micromath = "2.0.0"
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
new file mode 100644
index 000000000..d72d5ddb6
--- /dev/null
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::{self, ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv};
9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::time::Hertz;
11use embassy_stm32::Config;
12use embassy_time::{Duration, Timer};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = {
18 let mut config = Config::default();
19 config.rcc.mux = ClockSrc::PLL(
20 PLLSource::HSE(Hertz::mhz(8)),
21 PLLClkDiv::Div2,
22 PLLSrcDiv::Div1,
23 PLLMul::Mul20,
24 None,
25 );
26 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32;
27 embassy_stm32::init(config)
28 };
29 info!("Hello World!");
30
31 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
32 .unwrap()
33 .and_hms_opt(10, 30, 15)
34 .unwrap();
35
36 let mut rtc = Rtc::new(
37 p.RTC,
38 RtcConfig::default().clock_config(embassy_stm32::rtc::RtcClockSource::LSE),
39 );
40 info!("Got RTC! {:?}", now.timestamp());
41
42 rtc.set_datetime(now.into()).expect("datetime not set");
43
44 // In reality the delay would be much longer
45 Timer::after(Duration::from_millis(20000)).await;
46
47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.timestamp());
49}
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 6035c291f..54911482e 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index e2318c3d6..835e32940 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] }
13 13
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 8b6d6d754..51c499ee7 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index fbb2d918b..7c0b83e65 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -7,9 +7,10 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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"] } 12embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ieee802154", "nightly"], optional=true }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -20,11 +21,11 @@ embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.7.5", default-features = false } 23heapless = { version = "0.7.5", default-features = false }
23 24static_cell = { version = "1.1", features = ["nightly"]}
24 25
25[features] 26[features]
26default = ["ble"] 27default = ["ble", "mac"]
27mac = ["embassy-stm32-wpan/mac"] 28mac = ["embassy-stm32-wpan/mac", "dep:embassy-net"]
28ble = ["embassy-stm32-wpan/ble"] 29ble = ["embassy-stm32-wpan/ble"]
29 30
30[[bin]] 31[[bin]]
@@ -36,8 +37,17 @@ name = "tl_mbox_mac"
36required-features = ["mac"] 37required-features = ["mac"]
37 38
38[[bin]] 39[[bin]]
40name = "mac_ffd"
41required-features = ["mac"]
42
43[[bin]]
44name = "mac_ffd_net"
45required-features = ["mac"]
46
47[[bin]]
39name = "eddystone_beacon" 48name = "eddystone_beacon"
40required-features = ["ble"] 49required-features = ["ble"]
41 50
42[patch.crates-io] 51[[bin]]
43stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"} \ No newline at end of file 52name = "gatt_server"
53required-features = ["ble"] \ No newline at end of file
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index b99f8cb2e..451bd7d29 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) {
63 let sys_event = mbox.sys_subsystem.read().await; 63 let sys_event = mbox.sys_subsystem.read().await;
64 info!("sys event: {}", sys_event.payload()); 64 info!("sys event: {}", sys_event.payload());
65 65
66 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 66 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
67 67
68 info!("resetting BLE..."); 68 info!("resetting BLE...");
69 mbox.ble_subsystem.reset().await; 69 mbox.ble_subsystem.reset().await;
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
new file mode 100644
index 000000000..0f6419d45
--- /dev/null
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -0,0 +1,397 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::time::Duration;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::bind_interrupts;
10use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
11use embassy_stm32_wpan::hci::event::command::{CommandComplete, ReturnParameters};
12use embassy_stm32_wpan::hci::host::uart::{Packet, UartHci};
13use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
14use embassy_stm32_wpan::hci::types::AdvertisingType;
15use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
16 AddressType, AuthenticationRequirements, DiscoverableParameters, GapCommands, IoCapability, LocalName, Pin, Role,
17 SecureConnectionSupport,
18};
19use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::{
20 AddCharacteristicParameters, AddServiceParameters, CharacteristicEvent, CharacteristicPermission,
21 CharacteristicProperty, EncryptionKeySize, GattCommands, ServiceType, UpdateCharacteristicValueParameters, Uuid,
22 WriteResponseParameters,
23};
24use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
25use embassy_stm32_wpan::hci::vendor::stm32wb::event::{self, AttributeHandle, Stm32Wb5xEvent};
26use embassy_stm32_wpan::hci::{BdAddr, Event};
27use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
28use embassy_stm32_wpan::sub::ble::Ble;
29use embassy_stm32_wpan::TlMbox;
30use {defmt_rtt as _, panic_probe as _};
31
32bind_interrupts!(struct Irqs{
33 IPCC_C1_RX => ReceiveInterruptHandler;
34 IPCC_C1_TX => TransmitInterruptHandler;
35});
36
37const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 /*
42 How to make this work:
43
44 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
45 - Download and Install STM32CubeProgrammer.
46 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
47 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
48 - Open STM32CubeProgrammer
49 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
50 - Once complete, click connect to connect to the device.
51 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
52 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
53 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
54 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
55 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
56 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
57 - Select "Start Wireless Stack".
58 - Disconnect from the device.
59 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
60 - Run this example.
61
62 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
63 */
64
65 let p = embassy_stm32::init(Default::default());
66 info!("Hello World!");
67
68 let config = Config::default();
69 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
70
71 let sys_event = mbox.sys_subsystem.read().await;
72 info!("sys event: {}", sys_event.payload());
73
74 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
75
76 info!("resetting BLE...");
77 mbox.ble_subsystem.reset().await;
78 let response = mbox.ble_subsystem.read().await;
79 defmt::debug!("{}", response);
80
81 info!("config public address...");
82 mbox.ble_subsystem
83 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
84 .await;
85 let response = mbox.ble_subsystem.read().await;
86 defmt::debug!("{}", response);
87
88 info!("config random address...");
89 mbox.ble_subsystem
90 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
91 .await;
92 let response = mbox.ble_subsystem.read().await;
93 defmt::debug!("{}", response);
94
95 info!("config identity root...");
96 mbox.ble_subsystem
97 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
98 .await;
99 let response = mbox.ble_subsystem.read().await;
100 defmt::debug!("{}", response);
101
102 info!("config encryption root...");
103 mbox.ble_subsystem
104 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
105 .await;
106 let response = mbox.ble_subsystem.read().await;
107 defmt::debug!("{}", response);
108
109 info!("config tx power level...");
110 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
111 let response = mbox.ble_subsystem.read().await;
112 defmt::debug!("{}", response);
113
114 info!("GATT init...");
115 mbox.ble_subsystem.init_gatt().await;
116 let response = mbox.ble_subsystem.read().await;
117 defmt::debug!("{}", response);
118
119 info!("GAP init...");
120 mbox.ble_subsystem
121 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
122 .await;
123 let response = mbox.ble_subsystem.read().await;
124 defmt::debug!("{}", response);
125
126 info!("set IO capabilities...");
127 mbox.ble_subsystem.set_io_capability(IoCapability::DisplayConfirm).await;
128 let response = mbox.ble_subsystem.read().await;
129 defmt::debug!("{}", response);
130
131 info!("set authentication requirements...");
132 mbox.ble_subsystem
133 .set_authentication_requirement(&AuthenticationRequirements {
134 bonding_required: false,
135 keypress_notification_support: false,
136 mitm_protection_required: false,
137 encryption_key_size_range: (8, 16),
138 fixed_pin: Pin::Requested,
139 identity_address_type: AddressType::Public,
140 secure_connection_support: SecureConnectionSupport::Optional,
141 })
142 .await
143 .unwrap();
144 let response = mbox.ble_subsystem.read().await;
145 defmt::debug!("{}", response);
146
147 info!("set scan response data...");
148 mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap();
149 let response = mbox.ble_subsystem.read().await;
150 defmt::debug!("{}", response);
151
152 info!("set scan response data...");
153 mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap();
154 let response = mbox.ble_subsystem.read().await;
155 defmt::debug!("{}", response);
156
157 defmt::info!("initializing services and characteristics...");
158 let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap();
159 defmt::info!("{}", ble_context);
160
161 let discovery_params = DiscoverableParameters {
162 advertising_type: AdvertisingType::ConnectableUndirected,
163 advertising_interval: Some((Duration::from_millis(100), Duration::from_millis(100))),
164 address_type: OwnAddressType::Public,
165 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
166 local_name: Some(LocalName::Complete(b"TXTX")),
167 advertising_data: &[],
168 conn_interval: (None, None),
169 };
170
171 info!("set discoverable...");
172 mbox.ble_subsystem.set_discoverable(&discovery_params).await.unwrap();
173 let response = mbox.ble_subsystem.read().await;
174 defmt::debug!("{}", response);
175
176 loop {
177 let response = mbox.ble_subsystem.read().await;
178 defmt::debug!("{}", response);
179
180 if let Ok(Packet::Event(event)) = response {
181 match event {
182 Event::LeConnectionComplete(_) => {
183 defmt::info!("connected");
184 }
185 Event::DisconnectionComplete(_) => {
186 defmt::info!("disconnected");
187 ble_context.is_subscribed = false;
188 mbox.ble_subsystem.set_discoverable(&discovery_params).await.unwrap();
189 }
190 Event::Vendor(vendor_event) => match vendor_event {
191 Stm32Wb5xEvent::AttReadPermitRequest(read_req) => {
192 defmt::info!("read request received {}, allowing", read_req);
193 mbox.ble_subsystem.allow_read(read_req.conn_handle).await
194 }
195 Stm32Wb5xEvent::AttWritePermitRequest(write_req) => {
196 defmt::info!("write request received {}, allowing", write_req);
197 mbox.ble_subsystem
198 .write_response(&WriteResponseParameters {
199 conn_handle: write_req.conn_handle,
200 attribute_handle: write_req.attribute_handle,
201 status: Ok(()),
202 value: write_req.value(),
203 })
204 .await
205 .unwrap()
206 }
207 Stm32Wb5xEvent::GattAttributeModified(attribute) => {
208 defmt::info!("{}", ble_context);
209 if attribute.attr_handle.0 == ble_context.chars.notify.0 + 2 {
210 if attribute.data()[0] == 0x01 {
211 defmt::info!("subscribed");
212 ble_context.is_subscribed = true;
213 } else {
214 defmt::info!("unsubscribed");
215 ble_context.is_subscribed = false;
216 }
217 }
218 }
219 _ => {}
220 },
221 _ => {}
222 }
223 }
224 }
225}
226
227fn get_bd_addr() -> BdAddr {
228 let mut bytes = [0u8; 6];
229
230 let lhci_info = LhciC1DeviceInformationCcrp::new();
231 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
232 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
233 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
234 bytes[3] = lhci_info.device_type_id;
235 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
236 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
237
238 BdAddr(bytes)
239}
240
241fn get_random_addr() -> BdAddr {
242 let mut bytes = [0u8; 6];
243
244 let lhci_info = LhciC1DeviceInformationCcrp::new();
245 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
246 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
247 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
248 bytes[3] = 0;
249 bytes[4] = 0x6E;
250 bytes[5] = 0xED;
251
252 BdAddr(bytes)
253}
254
255const BLE_CFG_IRK: [u8; 16] = [
256 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
257];
258const BLE_CFG_ERK: [u8; 16] = [
259 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
260];
261
262fn get_irk() -> EncryptionKey {
263 EncryptionKey(BLE_CFG_IRK)
264}
265
266fn get_erk() -> EncryptionKey {
267 EncryptionKey(BLE_CFG_ERK)
268}
269
270#[derive(defmt::Format)]
271pub struct BleContext {
272 pub service_handle: AttributeHandle,
273 pub chars: CharHandles,
274 pub is_subscribed: bool,
275}
276
277#[derive(defmt::Format)]
278pub struct CharHandles {
279 pub read: AttributeHandle,
280 pub write: AttributeHandle,
281 pub notify: AttributeHandle,
282}
283
284pub async fn init_gatt_services(ble_subsystem: &mut Ble) -> Result<BleContext, ()> {
285 let service_handle = gatt_add_service(ble_subsystem, Uuid::Uuid16(0x500)).await?;
286
287 let read = gatt_add_char(
288 ble_subsystem,
289 service_handle,
290 Uuid::Uuid16(0x501),
291 CharacteristicProperty::READ,
292 Some(b"Hello from embassy!"),
293 )
294 .await?;
295
296 let write = gatt_add_char(
297 ble_subsystem,
298 service_handle,
299 Uuid::Uuid16(0x502),
300 CharacteristicProperty::WRITE_WITHOUT_RESPONSE | CharacteristicProperty::WRITE | CharacteristicProperty::READ,
301 None,
302 )
303 .await?;
304
305 let notify = gatt_add_char(
306 ble_subsystem,
307 service_handle,
308 Uuid::Uuid16(0x503),
309 CharacteristicProperty::NOTIFY | CharacteristicProperty::READ,
310 None,
311 )
312 .await?;
313
314 Ok(BleContext {
315 service_handle,
316 is_subscribed: false,
317 chars: CharHandles { read, write, notify },
318 })
319}
320
321async fn gatt_add_service(ble_subsystem: &mut Ble, uuid: Uuid) -> Result<AttributeHandle, ()> {
322 ble_subsystem
323 .add_service(&AddServiceParameters {
324 uuid,
325 service_type: ServiceType::Primary,
326 max_attribute_records: 8,
327 })
328 .await;
329 let response = ble_subsystem.read().await;
330 defmt::debug!("{}", response);
331
332 if let Ok(Packet::Event(Event::CommandComplete(CommandComplete {
333 return_params:
334 ReturnParameters::Vendor(event::command::ReturnParameters::GattAddService(event::command::GattService {
335 service_handle,
336 ..
337 })),
338 ..
339 }))) = response
340 {
341 Ok(service_handle)
342 } else {
343 Err(())
344 }
345}
346
347async fn gatt_add_char(
348 ble_subsystem: &mut Ble,
349 service_handle: AttributeHandle,
350 characteristic_uuid: Uuid,
351 characteristic_properties: CharacteristicProperty,
352 default_value: Option<&[u8]>,
353) -> Result<AttributeHandle, ()> {
354 ble_subsystem
355 .add_characteristic(&AddCharacteristicParameters {
356 service_handle,
357 characteristic_uuid,
358 characteristic_properties,
359 characteristic_value_len: 32,
360 security_permissions: CharacteristicPermission::empty(),
361 gatt_event_mask: CharacteristicEvent::all(),
362 encryption_key_size: EncryptionKeySize::with_value(7).unwrap(),
363 is_variable: true,
364 })
365 .await;
366 let response = ble_subsystem.read().await;
367 defmt::debug!("{}", response);
368
369 if let Ok(Packet::Event(Event::CommandComplete(CommandComplete {
370 return_params:
371 ReturnParameters::Vendor(event::command::ReturnParameters::GattAddCharacteristic(
372 event::command::GattCharacteristic {
373 characteristic_handle, ..
374 },
375 )),
376 ..
377 }))) = response
378 {
379 if let Some(value) = default_value {
380 ble_subsystem
381 .update_characteristic_value(&UpdateCharacteristicValueParameters {
382 service_handle,
383 characteristic_handle,
384 offset: 0,
385 value,
386 })
387 .await
388 .unwrap();
389
390 let response = ble_subsystem.read().await;
391 defmt::debug!("{}", response);
392 }
393 Ok(characteristic_handle)
394 } else {
395 Err(())
396 }
397}
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
new file mode 100644
index 000000000..1379ac6ba
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -0,0 +1,185 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest};
10use embassy_stm32_wpan::mac::event::MacEvent;
11use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel};
12use embassy_stm32_wpan::sub::mm;
13use embassy_stm32_wpan::TlMbox;
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs{
17 IPCC_C1_RX => ReceiveInterruptHandler;
18 IPCC_C1_TX => TransmitInterruptHandler;
19});
20
21#[embassy_executor::task]
22async fn run_mm_queue(memory_manager: mm::MemoryManager) {
23 memory_manager.run_queue().await;
24}
25
26#[embassy_executor::main]
27async fn main(spawner: Spawner) {
28 /*
29 How to make this work:
30
31 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
32 - Download and Install STM32CubeProgrammer.
33 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
34 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
35 - Open STM32CubeProgrammer
36 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
37 - Once complete, click connect to connect to the device.
38 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
39 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
41 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
42 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
43 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
44 - Select "Start Wireless Stack".
45 - Disconnect from the device.
46 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
47 - Run this example.
48
49 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
50 */
51
52 let p = embassy_stm32::init(Default::default());
53 info!("Hello World!");
54
55 let config = Config::default();
56 let mbox = TlMbox::init(p.IPCC, Irqs, config);
57
58 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
59
60 let sys_event = mbox.sys_subsystem.read().await;
61 info!("sys event: {}", sys_event.payload());
62
63 core::mem::drop(sys_event);
64
65 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
66 info!("initialized mac: {}", result);
67
68 info!("resetting");
69 mbox.mac_subsystem
70 .send_command(&ResetRequest {
71 set_default_pib: true,
72 ..Default::default()
73 })
74 .await
75 .unwrap();
76 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
77
78 info!("setting extended address");
79 let extended_address: u64 = 0xACDE480000000001;
80 mbox.mac_subsystem
81 .send_command(&SetRequest {
82 pib_attribute_ptr: &extended_address as *const _ as *const u8,
83 pib_attribute: PibId::ExtendedAddress,
84 })
85 .await
86 .unwrap();
87 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
88
89 info!("setting short address");
90 let short_address: u16 = 0x1122;
91 mbox.mac_subsystem
92 .send_command(&SetRequest {
93 pib_attribute_ptr: &short_address as *const _ as *const u8,
94 pib_attribute: PibId::ShortAddress,
95 })
96 .await
97 .unwrap();
98 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
99
100 info!("setting association permit");
101 let association_permit: bool = true;
102 mbox.mac_subsystem
103 .send_command(&SetRequest {
104 pib_attribute_ptr: &association_permit as *const _ as *const u8,
105 pib_attribute: PibId::AssociationPermit,
106 })
107 .await
108 .unwrap();
109 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
110
111 info!("setting TX power");
112 let transmit_power: i8 = 2;
113 mbox.mac_subsystem
114 .send_command(&SetRequest {
115 pib_attribute_ptr: &transmit_power as *const _ as *const u8,
116 pib_attribute: PibId::TransmitPower,
117 })
118 .await
119 .unwrap();
120 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
121
122 info!("starting FFD device");
123 mbox.mac_subsystem
124 .send_command(&StartRequest {
125 pan_id: PanId([0x1A, 0xAA]),
126 channel_number: MacChannel::Channel16,
127 beacon_order: 0x0F,
128 superframe_order: 0x0F,
129 pan_coordinator: true,
130 battery_life_extension: false,
131 ..Default::default()
132 })
133 .await
134 .unwrap();
135 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
136
137 info!("setting RX on when idle");
138 let rx_on_while_idle: bool = true;
139 mbox.mac_subsystem
140 .send_command(&SetRequest {
141 pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
142 pib_attribute: PibId::RxOnWhenIdle,
143 })
144 .await
145 .unwrap();
146 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
147
148 loop {
149 let evt = mbox.mac_subsystem.read().await;
150 if let Ok(evt) = evt {
151 defmt::info!("parsed mac event");
152 defmt::info!("{:#x}", evt);
153
154 match evt {
155 MacEvent::MlmeAssociateInd(association) => mbox
156 .mac_subsystem
157 .send_command(&AssociateResponse {
158 device_address: association.device_address,
159 assoc_short_address: [0x33, 0x44],
160 status: MacStatus::Success,
161 security_level: SecurityLevel::Unsecure,
162 ..Default::default()
163 })
164 .await
165 .unwrap(),
166 MacEvent::McpsDataInd(data_ind) => {
167 let payload = data_ind.payload();
168 let ref_payload = b"Hello from embassy!";
169 info!("{}", payload);
170
171 if payload == ref_payload {
172 info!("success");
173 } else {
174 info!("ref payload: {}", ref_payload);
175 }
176 }
177 _ => {
178 defmt::info!("other mac event");
179 }
180 }
181 } else {
182 defmt::info!("failed to parse mac event");
183 }
184 }
185}
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs
new file mode 100644
index 000000000..bbcd0a70f
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_ffd_net.rs
@@ -0,0 +1,170 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::mac::commands::{ResetRequest, SetRequest, StartRequest};
10use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId};
11use embassy_stm32_wpan::mac::{self, Runner};
12use embassy_stm32_wpan::sub::mm;
13use embassy_stm32_wpan::TlMbox;
14use static_cell::make_static;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs{
18 IPCC_C1_RX => ReceiveInterruptHandler;
19 IPCC_C1_TX => TransmitInterruptHandler;
20});
21
22#[embassy_executor::task]
23async fn run_mm_queue(memory_manager: mm::MemoryManager) {
24 memory_manager.run_queue().await;
25}
26
27#[embassy_executor::task]
28async fn run_mac(runner: &'static Runner<'static>) {
29 runner.run().await;
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) {
34 /*
35 How to make this work:
36
37 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
38 - Download and Install STM32CubeProgrammer.
39 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
40 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
41 - Open STM32CubeProgrammer
42 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
43 - Once complete, click connect to connect to the device.
44 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
45 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
46 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
47 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
48 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
49 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
50 - Select "Start Wireless Stack".
51 - Disconnect from the device.
52 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
53 - Run this example.
54
55 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
56 */
57
58 let p = embassy_stm32::init(Default::default());
59 info!("Hello World!");
60
61 let config = Config::default();
62 let mbox = TlMbox::init(p.IPCC, Irqs, config);
63
64 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
65
66 let sys_event = mbox.sys_subsystem.read().await;
67 info!("sys event: {}", sys_event.payload());
68
69 core::mem::drop(sys_event);
70
71 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
72 info!("initialized mac: {}", result);
73
74 info!("resetting");
75 mbox.mac_subsystem
76 .send_command(&ResetRequest {
77 set_default_pib: true,
78 ..Default::default()
79 })
80 .await
81 .unwrap();
82 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
83
84 info!("setting extended address");
85 let extended_address: u64 = 0xACDE480000000001;
86 mbox.mac_subsystem
87 .send_command(&SetRequest {
88 pib_attribute_ptr: &extended_address as *const _ as *const u8,
89 pib_attribute: PibId::ExtendedAddress,
90 })
91 .await
92 .unwrap();
93 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
94
95 info!("setting short address");
96 let short_address: u16 = 0x1122;
97 mbox.mac_subsystem
98 .send_command(&SetRequest {
99 pib_attribute_ptr: &short_address as *const _ as *const u8,
100 pib_attribute: PibId::ShortAddress,
101 })
102 .await
103 .unwrap();
104 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
105
106 info!("setting association permit");
107 let association_permit: bool = true;
108 mbox.mac_subsystem
109 .send_command(&SetRequest {
110 pib_attribute_ptr: &association_permit as *const _ as *const u8,
111 pib_attribute: PibId::AssociationPermit,
112 })
113 .await
114 .unwrap();
115 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
116
117 info!("setting TX power");
118 let transmit_power: i8 = 2;
119 mbox.mac_subsystem
120 .send_command(&SetRequest {
121 pib_attribute_ptr: &transmit_power as *const _ as *const u8,
122 pib_attribute: PibId::TransmitPower,
123 })
124 .await
125 .unwrap();
126 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
127
128 info!("starting FFD device");
129 mbox.mac_subsystem
130 .send_command(&StartRequest {
131 pan_id: PanId([0x1A, 0xAA]),
132 channel_number: MacChannel::Channel16,
133 beacon_order: 0x0F,
134 superframe_order: 0x0F,
135 pan_coordinator: true,
136 battery_life_extension: false,
137 ..Default::default()
138 })
139 .await
140 .unwrap();
141 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
142
143 info!("setting RX on when idle");
144 let rx_on_while_idle: bool = true;
145 mbox.mac_subsystem
146 .send_command(&SetRequest {
147 pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
148 pib_attribute: PibId::RxOnWhenIdle,
149 })
150 .await
151 .unwrap();
152 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
153
154 let tx_queue = [
155 make_static!([0u8; 127]),
156 make_static!([0u8; 127]),
157 make_static!([0u8; 127]),
158 make_static!([0u8; 127]),
159 make_static!([0u8; 127]),
160 ];
161
162 let runner = make_static!(Runner::new(mbox.mac_subsystem, tx_queue));
163
164 spawner.spawn(run_mac(runner)).unwrap();
165
166 let (driver, control) = mac::new(runner).await;
167
168 let _ = driver;
169 let _ = control;
170}
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
new file mode 100644
index 000000000..4d8b6601a
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -0,0 +1,182 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest};
10use embassy_stm32_wpan::mac::event::MacEvent;
11use embassy_stm32_wpan::mac::typedefs::{
12 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
13};
14use embassy_stm32_wpan::sub::mm;
15use embassy_stm32_wpan::TlMbox;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs{
19 IPCC_C1_RX => ReceiveInterruptHandler;
20 IPCC_C1_TX => TransmitInterruptHandler;
21});
22
23#[embassy_executor::task]
24async fn run_mm_queue(memory_manager: mm::MemoryManager) {
25 memory_manager.run_queue().await;
26}
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 /*
31 How to make this work:
32
33 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
34 - Download and Install STM32CubeProgrammer.
35 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
36 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
37 - Open STM32CubeProgrammer
38 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
39 - Once complete, click connect to connect to the device.
40 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
41 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
42 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
43 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
44 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Select "Start Wireless Stack".
47 - Disconnect from the device.
48 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
49 - Run this example.
50
51 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
52 */
53
54 let p = embassy_stm32::init(Default::default());
55 info!("Hello World!");
56
57 let config = Config::default();
58 let mbox = TlMbox::init(p.IPCC, Irqs, config);
59
60 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
61
62 let sys_event = mbox.sys_subsystem.read().await;
63 info!("sys event: {}", sys_event.payload());
64
65 core::mem::drop(sys_event);
66
67 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
68 info!("initialized mac: {}", result);
69
70 info!("resetting");
71 mbox.mac_subsystem
72 .send_command(&ResetRequest {
73 set_default_pib: true,
74 ..Default::default()
75 })
76 .await
77 .unwrap();
78 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
79
80 info!("setting extended address");
81 let extended_address: u64 = 0xACDE480000000002;
82 mbox.mac_subsystem
83 .send_command(&SetRequest {
84 pib_attribute_ptr: &extended_address as *const _ as *const u8,
85 pib_attribute: PibId::ExtendedAddress,
86 })
87 .await
88 .unwrap();
89 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
90
91 info!("getting extended address");
92 mbox.mac_subsystem
93 .send_command(&GetRequest {
94 pib_attribute: PibId::ExtendedAddress,
95 ..Default::default()
96 })
97 .await
98 .unwrap();
99
100 {
101 let evt = mbox.mac_subsystem.read().await.unwrap();
102 info!("{:#x}", evt);
103
104 if let MacEvent::MlmeGetCnf(evt) = evt {
105 if evt.pib_attribute_value_len == 8 {
106 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
107
108 info!("value {:#x}", value)
109 }
110 }
111 }
112
113 info!("assocation request");
114 let a = AssociateRequest {
115 channel_number: MacChannel::Channel16,
116 channel_page: 0,
117 coord_addr_mode: AddressMode::Short,
118 coord_address: MacAddress { short: [34, 17] },
119 capability_information: Capabilities::ALLOCATE_ADDRESS,
120 coord_pan_id: PanId([0x1A, 0xAA]),
121 security_level: SecurityLevel::Unsecure,
122 key_id_mode: KeyIdMode::Implicite,
123 key_source: [0; 8],
124 key_index: 152,
125 };
126 info!("{}", a);
127 mbox.mac_subsystem.send_command(&a).await.unwrap();
128 let short_addr = {
129 let evt = mbox.mac_subsystem.read().await.unwrap();
130 info!("{:#x}", evt);
131
132 if let MacEvent::MlmeAssociateCnf(conf) = evt {
133 conf.assoc_short_address
134 } else {
135 defmt::panic!()
136 }
137 };
138
139 info!("setting short address");
140 mbox.mac_subsystem
141 .send_command(&SetRequest {
142 pib_attribute_ptr: &short_addr as *const _ as *const u8,
143 pib_attribute: PibId::ShortAddress,
144 })
145 .await
146 .unwrap();
147 {
148 let evt = mbox.mac_subsystem.read().await.unwrap();
149 info!("{:#x}", evt);
150 }
151
152 info!("sending data");
153 let data = b"Hello from embassy!";
154 mbox.mac_subsystem
155 .send_command(
156 DataRequest {
157 src_addr_mode: AddressMode::Short,
158 dst_addr_mode: AddressMode::Short,
159 dst_pan_id: PanId([0x1A, 0xAA]),
160 dst_address: MacAddress::BROADCAST,
161 msdu_handle: 0x02,
162 ack_tx: 0x00,
163 gts_tx: false,
164 security_level: SecurityLevel::Unsecure,
165 ..Default::default()
166 }
167 .set_buffer(data),
168 )
169 .await
170 .unwrap();
171 {
172 let evt = mbox.mac_subsystem.read().await.unwrap();
173 info!("{:#x}", evt);
174 }
175
176 loop {
177 match mbox.mac_subsystem.read().await {
178 Ok(evt) => info!("{:#x}", evt),
179 _ => continue,
180 };
181 }
182}
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index a511e89aa..90349422e 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) {
49 let sys_event = mbox.sys_subsystem.read().await; 49 let sys_event = mbox.sys_subsystem.read().await;
50 info!("sys event: {}", sys_event.payload()); 50 info!("sys event: {}", sys_event.payload());
51 51
52 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 52 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
53 53
54 info!("starting ble..."); 54 info!("starting ble...");
55 mbox.ble_subsystem.tl_write(0x0c, &[]).await; 55 mbox.ble_subsystem.tl_write(0x0c, &[]).await;
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index f67be4682..5931c392b 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -6,6 +6,7 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; 8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::sub::mm;
9use embassy_stm32_wpan::TlMbox; 10use embassy_stm32_wpan::TlMbox;
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
@@ -14,8 +15,13 @@ bind_interrupts!(struct Irqs{
14 IPCC_C1_TX => TransmitInterruptHandler; 15 IPCC_C1_TX => TransmitInterruptHandler;
15}); 16});
16 17
18#[embassy_executor::task]
19async fn run_mm_queue(memory_manager: mm::MemoryManager) {
20 memory_manager.run_queue().await;
21}
22
17#[embassy_executor::main] 23#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 24async fn main(spawner: Spawner) {
19 /* 25 /*
20 How to make this work: 26 How to make this work:
21 27
@@ -46,9 +52,13 @@ async fn main(_spawner: Spawner) {
46 let config = Config::default(); 52 let config = Config::default();
47 let mbox = TlMbox::init(p.IPCC, Irqs, config); 53 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48 54
55 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
56
49 let sys_event = mbox.sys_subsystem.read().await; 57 let sys_event = mbox.sys_subsystem.read().await;
50 info!("sys event: {}", sys_event.payload()); 58 info!("sys event: {}", sys_event.payload());
51 59
60 core::mem::drop(sys_event);
61
52 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; 62 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
53 info!("initialized mac: {}", result); 63 info!("initialized mac: {}", result);
54 64
diff --git a/examples/stm32wl/.cargo/config.toml b/examples/stm32wl/.cargo/config.toml
index 4f8094ff2..ee416fcbc 100644
--- a/examples/stm32wl/.cargo/config.toml
+++ b/examples/stm32wl/.cargo/config.toml
@@ -3,7 +3,7 @@
3runner = "probe-rs run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabi"
7 7
8[env] 8[env]
9DEFMT_LOG = "trace" 9DEFMT_LOG = "trace"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 260f9afa1..e2c66f456 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
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 = ["nightly", "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.2", 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", "chrono"] }
12embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" } 12embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
13embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } 13embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
14lora-phy = { version = "1" } 14lora-phy = { version = "1" }
15lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } 15lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] }
@@ -25,3 +25,7 @@ embedded-storage = "0.3.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
28chrono = { version = "^0.4", default-features = false }
29
30[patch.crates-io]
31lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
new file mode 100644
index 000000000..e11825499
--- /dev/null
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::{self, ClockSrc};
9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::Config;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = {
17 let mut config = Config::default();
18 config.rcc.mux = ClockSrc::HSE32;
19 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32;
20 config.rcc.enable_rtc_apb = true;
21 embassy_stm32::init(config)
22 };
23 info!("Hello World!");
24
25 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
26 .unwrap()
27 .and_hms_opt(10, 30, 15)
28 .unwrap();
29
30 let mut rtc = Rtc::new(
31 p.RTC,
32 RtcConfig::default().clock_config(embassy_stm32::rtc::RtcClockSource::LSE),
33 );
34 info!("Got RTC! {:?}", now.timestamp());
35
36 rtc.set_datetime(now.into()).expect("datetime not set");
37
38 // In reality the delay would be much longer
39 Timer::after(Duration::from_millis(20000)).await;
40
41 let then: NaiveDateTime = rtc.now().unwrap().into();
42 info!("Got RTC! {:?}", then.timestamp());
43}
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 437e443a7..3679e3857 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
13embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } 13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
14 14
15wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
16wasm-bindgen = "0.2" 16wasm-bindgen = "0.2"
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index fd454db26..179ed1d6a 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,7 +1,7 @@
1# Before upgrading check that everything is available on all tier1 targets here: 1# Before upgrading check that everything is available on all tier1 targets here:
2# https://rust-lang.github.io/rustup-components-history 2# https://rust-lang.github.io/rustup-components-history
3[toolchain] 3[toolchain]
4channel = "nightly-2023-05-18" 4channel = "nightly-2023-06-28"
5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] 5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
6targets = [ 6targets = [
7 "thumbv7em-none-eabi", 7 "thumbv7em-none-eabi",
@@ -11,4 +11,4 @@ targets = [
11 "thumbv8m.main-none-eabihf", 11 "thumbv8m.main-none-eabihf",
12 "riscv32imac-unknown-none-elf", 12 "riscv32imac-unknown-none-elf",
13 "wasm32-unknown-unknown", 13 "wasm32-unknown-unknown",
14] 14] \ No newline at end of file
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 4f9ecc47a..7ce51aa5e 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -10,12 +10,12 @@ teleprobe-meta = "1"
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } 11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
13embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
15embedded-io = { version = "0.4.0", features = ["async"] } 15embedded-io = { version = "0.4.0", features = ["async"] }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } 16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embedded-hal-async = { version = "0.2.0-alpha.1" } 18embedded-hal-async = { version = "0.2.0-alpha.2" }
19static_cell = { version = "1.1", features = [ "nightly" ] } 19static_cell = { version = "1.1", features = [ "nightly" ] }
20 20
21defmt = "0.3" 21defmt = "0.3"
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index 277b985c5..398ab9d27 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -14,7 +14,7 @@ use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
14use embassy_nrf::rng::Rng; 14use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim}; 15use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals}; 16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Duration, Timer}; 17use embassy_time::{with_timeout, Delay, Duration, Timer};
18use embedded_hal_async::spi::ExclusiveDevice; 18use embedded_hal_async::spi::ExclusiveDevice;
19use static_cell::make_static; 19use static_cell::make_static;
20use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; 20use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
@@ -30,7 +30,7 @@ bind_interrupts!(struct Irqs {
30async fn wifi_task( 30async fn wifi_task(
31 runner: hosted::Runner< 31 runner: hosted::Runner<
32 'static, 32 'static,
33 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>>, 33 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>,
34 Input<'static, AnyPin>, 34 Input<'static, AnyPin>,
35 Output<'static, peripherals::P1_05>, 35 Output<'static, peripherals::P1_05>,
36 >, 36 >,
@@ -63,7 +63,7 @@ async fn main(spawner: Spawner) {
63 config.frequency = spim::Frequency::M32; 63 config.frequency = spim::Frequency::M32;
64 config.mode = spim::MODE_2; // !!! 64 config.mode = spim::MODE_2; // !!!
65 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); 65 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
66 let spi = ExclusiveDevice::new(spi, cs); 66 let spi = ExclusiveDevice::new(spi, cs, Delay);
67 67
68 let (device, mut control, runner) = embassy_net_esp_hosted::new( 68 let (device, mut control, runner) = embassy_net_esp_hosted::new(
69 make_static!(embassy_net_esp_hosted::State::new()), 69 make_static!(embassy_net_esp_hosted::State::new()),
diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml
index 81bfdfab6..61f886c0c 100644
--- a/tests/riscv32/Cargo.toml
+++ b/tests/riscv32/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8critical-section = { version = "1.1.1", features = ["restore-state-bool"] } 8critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
9embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } 9embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
10embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] } 10embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time" } 11embassy-time = { version = "0.1.2", path = "../../embassy-time" }
12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 13
14riscv-rt = "0.11" 14riscv-rt = "0.11"
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 180d0ebbe..f2c902787 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -9,7 +9,7 @@ teleprobe-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 = ["nightly", "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.2", 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", "run-from-ram"] } 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"] } 15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
@@ -22,13 +22,15 @@ defmt-rtt = "0.4"
22cortex-m = { version = "0.7.6" } 22cortex-m = { version = "0.7.6" }
23cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 25embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
26embedded-hal-async = { version = "=0.2.0-alpha.1" } 26embedded-hal-async = { version = "=0.2.0-alpha.2" }
27panic-probe = { version = "0.3.0", features = ["print-defmt"] } 27panic-probe = { version = "0.3.0", features = ["print-defmt"] }
28futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29embedded-io = { version = "0.4.0", features = ["async"] } 29embedded-io = { version = "0.4.0", features = ["async"] }
30embedded-storage = { version = "0.3" } 30embedded-storage = { version = "0.3" }
31static_cell = { version = "1.1", features = ["nightly"]} 31static_cell = { version = "1.1", features = ["nightly"]}
32pio = "0.2"
33pio-proc = "0.2"
32 34
33[profile.dev] 35[profile.dev]
34debug = 2 36debug = 2
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs
new file mode 100644
index 000000000..e659844ae
--- /dev/null
+++ b/tests/rp/src/bin/adc.rs
@@ -0,0 +1,86 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::Pull;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 ADC_IRQ_FIFO => InterruptHandler;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let mut p = embassy_rp::init(Default::default());
21 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
22
23 {
24 {
25 let mut p = Pin::new(&mut p.PIN_26, Pull::Down);
26 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
27 defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000);
28 }
29 {
30 let mut p = Pin::new(&mut p.PIN_26, Pull::Up);
31 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
32 defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000);
33 }
34 }
35 // not bothering with async reads from now on
36 {
37 {
38 let mut p = Pin::new(&mut p.PIN_27, Pull::Down);
39 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
40 }
41 {
42 let mut p = Pin::new(&mut p.PIN_27, Pull::Up);
43 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
44 }
45 }
46 {
47 {
48 let mut p = Pin::new(&mut p.PIN_28, Pull::Down);
49 defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000);
50 }
51 {
52 let mut p = Pin::new(&mut p.PIN_28, Pull::Up);
53 defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000);
54 }
55 }
56 {
57 // gp29 is connected to vsys through a 200k/100k divider,
58 // adding pulls should change the value
59 let low = {
60 let mut p = Pin::new(&mut p.PIN_29, Pull::Down);
61 adc.blocking_read(&mut p).unwrap()
62 };
63 let none = {
64 let mut p = Pin::new(&mut p.PIN_29, Pull::None);
65 adc.blocking_read(&mut p).unwrap()
66 };
67 let up = {
68 let mut p = Pin::new(&mut p.PIN_29, Pull::Up);
69 adc.blocking_read(&mut p).unwrap()
70 };
71 defmt::assert!(low < none);
72 defmt::assert!(none < up);
73 }
74
75 let temp = convert_to_celsius(adc.read_temperature().await.unwrap());
76 defmt::assert!(temp > 0.0);
77 defmt::assert!(temp < 60.0);
78
79 info!("Test OK");
80 cortex_m::asm::bkpt();
81}
82
83fn convert_to_celsius(raw_temp: u16) -> f32 {
84 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
85 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721 as f32
86}
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 1ecaab266..bc127e2e5 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -12,12 +12,16 @@ use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources}; 12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
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::{InterruptHandler, Pio};
16use embassy_rp::rom_data; 16use embassy_rp::{bind_interrupts, rom_data};
17use embassy_time::{with_timeout, Duration, Timer}; 17use embassy_time::{with_timeout, Duration, Timer};
18use static_cell::make_static; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
21bind_interrupts!(struct Irqs {
22 PIO0_IRQ_0 => InterruptHandler<PIO0>;
23});
24
21teleprobe_meta::timeout!(120); 25teleprobe_meta::timeout!(120);
22 26
23#[embassy_executor::task] 27#[embassy_executor::task]
@@ -51,7 +55,7 @@ async fn main(spawner: Spawner) {
51 55
52 let pwr = Output::new(p.PIN_23, Level::Low); 56 let pwr = Output::new(p.PIN_23, Level::Low);
53 let cs = Output::new(p.PIN_25, Level::High); 57 let cs = Output::new(p.PIN_25, Level::High);
54 let mut pio = Pio::new(p.PIO0); 58 let mut pio = Pio::new(p.PIO0, Irqs);
55 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 59 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
56 60
57 let state = make_static!(cyw43::State::new()); 61 let state = make_static!(cyw43::State::new());
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index 51112d319..946b7dc88 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -21,14 +21,46 @@ async fn main(_spawner: Spawner) {
21 let b = Input::new(&mut b, Pull::None); 21 let b = Input::new(&mut b, Pull::None);
22 22
23 { 23 {
24 let _a = Output::new(&mut a, Level::Low); 24 let a = Output::new(&mut a, Level::Low);
25 delay(); 25 delay();
26 assert!(b.is_low()); 26 assert!(b.is_low());
27 assert!(!b.is_high());
28 assert!(a.is_set_low());
29 assert!(!a.is_set_high());
27 } 30 }
28 { 31 {
29 let _a = Output::new(&mut a, Level::High); 32 let mut a = Output::new(&mut a, Level::High);
30 delay(); 33 delay();
34 assert!(!b.is_low());
31 assert!(b.is_high()); 35 assert!(b.is_high());
36 assert!(!a.is_set_low());
37 assert!(a.is_set_high());
38
39 // Test is_set_low / is_set_high
40 a.set_low();
41 delay();
42 assert!(b.is_low());
43 assert!(a.is_set_low());
44 assert!(!a.is_set_high());
45
46 a.set_high();
47 delay();
48 assert!(b.is_high());
49 assert!(!a.is_set_low());
50 assert!(a.is_set_high());
51
52 // Test toggle
53 a.toggle();
54 delay();
55 assert!(b.is_low());
56 assert!(a.is_set_low());
57 assert!(!a.is_set_high());
58
59 a.toggle();
60 delay();
61 assert!(b.is_high());
62 assert!(!a.is_set_low());
63 assert!(a.is_set_high());
32 } 64 }
33 } 65 }
34 66
diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs
new file mode 100644
index 000000000..45004424a
--- /dev/null
+++ b/tests/rp/src/bin/pio_irq.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Config, InterruptHandler, Pio};
12use embassy_rp::relocate::RelocatedProgram;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 PIO0_IRQ_0 => InterruptHandler<PIO0>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_rp::init(Default::default());
22 let pio = p.PIO0;
23 let Pio {
24 mut common,
25 sm0: mut sm,
26 irq_flags,
27 ..
28 } = Pio::new(pio, Irqs);
29
30 let prg = pio_proc::pio_asm!(
31 "irq set 0",
32 "irq wait 0",
33 "irq set 1",
34 // pause execution here
35 "irq wait 1",
36 );
37
38 let relocated = RelocatedProgram::new(&prg.program);
39 let mut cfg = Config::default();
40 cfg.use_program(&common.load_program(&relocated), &[]);
41 sm.set_config(&cfg);
42 sm.set_enable(true);
43
44 // not using the wait futures on purpose because they clear the irq bits,
45 // and we want to see in which order they are set.
46 while !irq_flags.check(0) {}
47 cortex_m::asm::nop();
48 assert!(!irq_flags.check(1));
49 irq_flags.clear(0);
50 cortex_m::asm::nop();
51 assert!(irq_flags.check(1));
52
53 info!("Test OK");
54 cortex_m::asm::bkpt();
55}
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index c2422f7bc..3007cd1e6 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -12,14 +12,16 @@ 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", "mac" ] # 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"]
21can = [] 21can = []
22ble = ["dep:embassy-stm32-wpan"] 22ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
23mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
24embassy-stm32-wpan = []
23not-gpdma = [] 25not-gpdma = []
24 26
25[dependencies] 27[dependencies]
@@ -27,7 +29,7 @@ teleprobe-meta = "1"
27 29
28embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 30embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
29embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 31embassy-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"] } 32embassy-time = { version = "0.1.2", 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"] } 33embassy-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" } 34embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
33embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } 35embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
@@ -38,25 +40,17 @@ defmt-rtt = "0.4"
38cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 40cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
39cortex-m-rt = "0.7.0" 41cortex-m-rt = "0.7.0"
40embedded-hal = "0.2.6" 42embedded-hal = "0.2.6"
41embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } 43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
42embedded-hal-async = { version = "=0.2.0-alpha.1" } 44embedded-hal-async = { version = "=0.2.0-alpha.2" }
43panic-probe = { version = "0.3.0", features = ["print-defmt"] } 45panic-probe = { version = "0.3.0", features = ["print-defmt"] }
44rand_core = { version = "0.6", default-features = false } 46rand_core = { version = "0.6", default-features = false }
45rand_chacha = { version = "0.3", default-features = false } 47rand_chacha = { version = "0.3", default-features = false }
46 48
47chrono = { version = "^0.4", default-features = false, optional = true} 49chrono = { version = "^0.4", default-features = false, optional = true}
48 50
49[patch.crates-io]
50stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"}
51
52# BEGIN TESTS 51# BEGIN TESTS
53# Generated by gen_test.py. DO NOT EDIT. 52# Generated by gen_test.py. DO NOT EDIT.
54[[bin]] 53[[bin]]
55name = "tl_mbox"
56path = "src/bin/tl_mbox.rs"
57required-features = [ "ble",]
58
59[[bin]]
60name = "can" 54name = "can"
61path = "src/bin/can.rs" 55path = "src/bin/can.rs"
62required-features = [ "can",] 56required-features = [ "can",]
@@ -106,6 +100,16 @@ name = "usart_rx_ringbuffered"
106path = "src/bin/usart_rx_ringbuffered.rs" 100path = "src/bin/usart_rx_ringbuffered.rs"
107required-features = [ "not-gpdma",] 101required-features = [ "not-gpdma",]
108 102
103[[bin]]
104name = "wpan_ble"
105path = "src/bin/wpan_ble.rs"
106required-features = [ "ble",]
107
108[[bin]]
109name = "wpan_mac"
110path = "src/bin/wpan_mac.rs"
111required-features = [ "mac",]
112
109# END TESTS 113# END TESTS
110 114
111[profile.dev] 115[profile.dev]
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index 33d63d546..8bdd3c24f 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -43,10 +43,13 @@ async fn main(_spawner: Spawner) {
43 43
44 info!("Configuring can..."); 44 info!("Configuring can...");
45 45
46 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 46 can.as_mut()
47 .modify_filters()
48 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
47 49
48 can.set_bitrate(1_000_000); 50 can.set_bitrate(1_000_000);
49 can.modify_config() 51 can.as_mut()
52 .modify_config()
50 .set_loopback(true) // Receive own frames 53 .set_loopback(true) // Receive own frames
51 .set_silent(true) 54 .set_silent(true)
52 // .set_bit_timing(0x001c0003) 55 // .set_bit_timing(0x001c0003)
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index 67f44317e..aad174431 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -40,14 +40,46 @@ async fn main(_spawner: Spawner) {
40 let b = Input::new(&mut b, Pull::None); 40 let b = Input::new(&mut b, Pull::None);
41 41
42 { 42 {
43 let _a = Output::new(&mut a, Level::Low, Speed::Low); 43 let a = Output::new(&mut a, Level::Low, Speed::Low);
44 delay(); 44 delay();
45 assert!(b.is_low()); 45 assert!(b.is_low());
46 assert!(!b.is_high());
47 assert!(a.is_set_low());
48 assert!(!a.is_set_high());
46 } 49 }
47 { 50 {
48 let _a = Output::new(&mut a, Level::High, Speed::Low); 51 let mut a = Output::new(&mut a, Level::High, Speed::Low);
49 delay(); 52 delay();
53 assert!(!b.is_low());
50 assert!(b.is_high()); 54 assert!(b.is_high());
55 assert!(!a.is_set_low());
56 assert!(a.is_set_high());
57
58 // Test is_set_low / is_set_high
59 a.set_low();
60 delay();
61 assert!(b.is_low());
62 assert!(a.is_set_low());
63 assert!(!a.is_set_high());
64
65 a.set_high();
66 delay();
67 assert!(b.is_high());
68 assert!(!a.is_set_low());
69 assert!(a.is_set_high());
70
71 // Test toggle
72 a.toggle();
73 delay();
74 assert!(b.is_low());
75 assert!(a.is_set_low());
76 assert!(!a.is_set_high());
77
78 a.toggle();
79 delay();
80 assert!(b.is_high());
81 assert!(!a.is_set_low());
82 assert!(a.is_set_high());
51 } 83 }
52 } 84 }
53 85
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 582df5753..194b153d5 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -1,3 +1,5 @@
1// required-features: chrono
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/wpan_ble.rs
index af3832709..3ad8aca4e 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/wpan_ble.rs
@@ -64,7 +64,7 @@ async fn main(spawner: Spawner) {
64 version_major, version_minor, subversion, sram2a_size, sram2b_size 64 version_major, version_minor, subversion, sram2a_size, sram2b_size
65 ); 65 );
66 66
67 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 67 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
68 68
69 info!("resetting BLE..."); 69 info!("resetting BLE...");
70 mbox.ble_subsystem.reset().await; 70 mbox.ble_subsystem.reset().await;
diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs
new file mode 100644
index 000000000..b04a19ee9
--- /dev/null
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -0,0 +1,124 @@
1// required-features: mac
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use common::*;
10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest};
14use embassy_stm32_wpan::mac::event::MacEvent;
15use embassy_stm32_wpan::mac::typedefs::{
16 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
17};
18use embassy_stm32_wpan::sub::mm;
19use embassy_stm32_wpan::TlMbox;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs{
23 IPCC_C1_RX => ReceiveInterruptHandler;
24 IPCC_C1_TX => TransmitInterruptHandler;
25});
26
27#[embassy_executor::task]
28async fn run_mm_queue(memory_manager: mm::MemoryManager) {
29 memory_manager.run_queue().await;
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) {
34 let p = embassy_stm32::init(config());
35 info!("Hello World!");
36
37 let config = Config::default();
38 let mbox = TlMbox::init(p.IPCC, Irqs, config);
39
40 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
41
42 let sys_event = mbox.sys_subsystem.read().await;
43 info!("sys event: {}", sys_event.payload());
44
45 core::mem::drop(sys_event);
46
47 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
48 info!("initialized mac: {}", result);
49
50 info!("resetting");
51 mbox.mac_subsystem
52 .send_command(&ResetRequest {
53 set_default_pib: true,
54 ..Default::default()
55 })
56 .await
57 .unwrap();
58 {
59 let evt = mbox.mac_subsystem.read().await.unwrap();
60 info!("{:#x}", evt);
61 }
62
63 info!("setting extended address");
64 let extended_address: u64 = 0xACDE480000000002;
65 mbox.mac_subsystem
66 .send_command(&SetRequest {
67 pib_attribute_ptr: &extended_address as *const _ as *const u8,
68 pib_attribute: PibId::ExtendedAddress,
69 })
70 .await
71 .unwrap();
72 {
73 let evt = mbox.mac_subsystem.read().await.unwrap();
74 info!("{:#x}", evt);
75 }
76
77 info!("getting extended address");
78 mbox.mac_subsystem
79 .send_command(&GetRequest {
80 pib_attribute: PibId::ExtendedAddress,
81 ..Default::default()
82 })
83 .await
84 .unwrap();
85
86 {
87 let evt = mbox.mac_subsystem.read().await.unwrap();
88 info!("{:#x}", evt);
89
90 if let MacEvent::MlmeGetCnf(evt) = evt {
91 if evt.pib_attribute_value_len == 8 {
92 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
93
94 info!("value {:#x}", value)
95 }
96 }
97 }
98
99 info!("assocation request");
100 let a = AssociateRequest {
101 channel_number: MacChannel::Channel16,
102 channel_page: 0,
103 coord_addr_mode: AddressMode::Short,
104 coord_address: MacAddress { short: [34, 17] },
105 capability_information: Capabilities::ALLOCATE_ADDRESS,
106 coord_pan_id: PanId([0x1A, 0xAA]),
107 security_level: SecurityLevel::Unsecure,
108 key_id_mode: KeyIdMode::Implicite,
109 key_source: [0; 8],
110 key_index: 152,
111 };
112 info!("{}", a);
113 mbox.mac_subsystem.send_command(&a).await.unwrap();
114 let short_addr = if let MacEvent::MlmeAssociateCnf(conf) = mbox.mac_subsystem.read().await.unwrap() {
115 conf.assoc_short_address
116 } else {
117 defmt::panic!()
118 };
119
120 info!("{}", short_addr);
121
122 info!("Test OK");
123 cortex_m::asm::bkpt();
124}