aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler <[email protected]>2023-07-16 19:08:01 -0500
committerGitHub <[email protected]>2023-07-16 19:08:01 -0500
commit6d8a5c6c20953c998df6ddd26906abe520df946d (patch)
tree32cfdf85a1aa132cb0f1aac56a934ceed93fc597
parent3aedbce5c2775ff1ab10c3ca95ea1311043f4be4 (diff)
parentc7ec45a004750f590c1d9ea4a721972efe133b8e (diff)
Merge pull request #2 from embassy-rs/main
Pull changes from base embassy repo
-rwxr-xr-x.github/ci/doc.sh51
-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-esp-hosted/Cargo.toml6
-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.toml2
-rw-r--r--embassy-net/src/lib.rs2
-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/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.rs225
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/gpio.rs6
-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.toml15
-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.rs43
-rw-r--r--embassy-stm32-wpan/src/mac/commands.rs467
-rw-r--r--embassy-stm32-wpan/src/mac/consts.rs4
-rw-r--r--embassy-stm32-wpan/src/mac/event.rs94
-rw-r--r--embassy-stm32-wpan/src/mac/helpers.rs7
-rw-r--r--embassy-stm32-wpan/src/mac/indications.rs470
-rw-r--r--embassy-stm32-wpan/src/mac/macros.rs32
-rw-r--r--embassy-stm32-wpan/src/mac/mod.rs9
-rw-r--r--embassy-stm32-wpan/src/mac/opcodes.rs92
-rw-r--r--embassy-stm32-wpan/src/mac/responses.rs433
-rw-r--r--embassy-stm32-wpan/src/mac/typedefs.rs363
-rw-r--r--embassy-stm32-wpan/src/sub/mac.rs54
-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.toml8
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/can/bxcan.rs89
-rw-r--r--embassy-stm32/src/dac/mod.rs4
-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/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/usb_otg/usb.rs21
-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.toml7
-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.toml13
-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.rs183
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs170
-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.rs108
199 files changed, 4973 insertions, 954 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 1402e742f..9e9c78a42 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,31 @@ 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-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
41 41
42export KUBECONFIG=/ci/secrets/kubeconfig.yml 42export KUBECONFIG=/ci/secrets/kubeconfig.yml
43POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 43POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
44kubectl cp crates $POD:/data 44kubectl cp webroot/crates $POD:/data
45kubectl cp webroot/static $POD:/data \ No newline at end of file
diff --git a/ci.sh b/ci.sh
index a03efb856..376cc8f44 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-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index a7e18ee09..26f5b40bd 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -7,13 +7,13 @@ 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"] }
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..6dc429ddc 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -50,7 +50,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
50] } 50] }
51 51
52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
53embassy-time = { version = "0.1.0", path = "../embassy-time" } 53embassy-time = { version = "0.1.2", path = "../embassy-time" }
54embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 54embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
55embedded-io = { version = "0.4.0", optional = true } 55embedded-io = { version = "0.4.0", optional = true }
56 56
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 840d7a09a..0d0a986f6 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -34,7 +34,7 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
34pub use smoltcp::wire::IpListenEndpoint; 34pub use smoltcp::wire::IpListenEndpoint;
35#[cfg(feature = "medium-ethernet")] 35#[cfg(feature = "medium-ethernet")]
36pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; 36pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
37pub use smoltcp::wire::{IpAddress, IpCidr}; 37pub use smoltcp::wire::{IpAddress, IpCidr, IpEndpoint};
38#[cfg(feature = "proto-ipv4")] 38#[cfg(feature = "proto-ipv4")]
39pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; 39pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
40#[cfg(feature = "proto-ipv6")] 40#[cfg(feature = "proto-ipv6")]
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/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..dfa1b877a 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,65 @@ 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)>,
33} 82}
34 83
35impl<'d> Adc<'d> { 84impl<'d, M: Mode> Adc<'d, M> {
36 #[inline] 85 #[inline]
37 fn regs() -> pac::adc::Adc { 86 fn regs() -> pac::adc::Adc {
38 pac::ADC 87 pac::ADC
@@ -45,11 +94,7 @@ impl<'d> Adc<'d> {
45 ret 94 ret
46 } 95 }
47 96
48 pub fn new( 97 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(); 98 let reset = Self::reset();
54 crate::reset::reset(reset); 99 crate::reset::reset(reset);
55 crate::reset::unreset_wait(reset); 100 crate::reset::unreset_wait(reset);
@@ -58,6 +103,43 @@ impl<'d> Adc<'d> {
58 r.cs().write(|w| w.set_en(true)); 103 r.cs().write(|w| w.set_en(true));
59 // Wait for ADC ready 104 // Wait for ADC ready
60 while !r.cs().read().ready() {} 105 while !r.cs().read().ready() {}
106 }
107
108 fn sample_blocking(channel: u8) -> Result<u16, Error> {
109 let r = Self::regs();
110 r.cs().modify(|w| {
111 w.set_ainsel(channel);
112 w.set_start_once(true);
113 w.set_err(true);
114 });
115 while !r.cs().read().ready() {}
116 match r.cs().read().err() {
117 true => Err(Error::ConversionFailed),
118 false => Ok(r.result().read().result().into()),
119 }
120 }
121
122 pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> {
123 Self::sample_blocking(pin.channel())
124 }
125
126 pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> {
127 let r = Self::regs();
128 r.cs().modify(|w| w.set_ts_en(true));
129 while !r.cs().read().ready() {}
130 let result = Self::sample_blocking(4);
131 r.cs().modify(|w| w.set_ts_en(false));
132 result
133 }
134}
135
136impl<'d> Adc<'d, Async> {
137 pub fn new(
138 _inner: impl Peripheral<P = ADC> + 'd,
139 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
140 _config: Config,
141 ) -> Self {
142 Self::setup();
61 143
62 // Setup IRQ 144 // Setup IRQ
63 interrupt::ADC_IRQ_FIFO.unpend(); 145 interrupt::ADC_IRQ_FIFO.unpend();
@@ -80,102 +162,77 @@ impl<'d> Adc<'d> {
80 .await; 162 .await;
81 } 163 }
82 164
83 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 165 async fn sample_async(channel: u8) -> Result<u16, Error> {
84 let r = Self::regs(); 166 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| { 167 r.cs().modify(|w| {
94 w.set_ainsel(PIN::channel()); 168 w.set_ainsel(channel);
95 w.set_start_once(true) 169 w.set_start_once(true);
170 w.set_err(true);
96 }); 171 });
97 Self::wait_for_ready().await; 172 Self::wait_for_ready().await;
98 r.result().read().result().into() 173 match r.cs().read().err() {
174 true => Err(Error::ConversionFailed),
175 false => Ok(r.result().read().result().into()),
176 }
99 } 177 }
100 178
101 pub async fn read_temperature(&mut self) -> u16 { 179 pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> {
180 Self::sample_async(pin.channel()).await
181 }
182
183 pub async fn read_temperature(&mut self) -> Result<u16, Error> {
102 let r = Self::regs(); 184 let r = Self::regs();
103 r.cs().modify(|w| w.set_ts_en(true)); 185 r.cs().modify(|w| w.set_ts_en(true));
104 if !r.cs().read().ready() { 186 if !r.cs().read().ready() {
105 Self::wait_for_ready().await; 187 Self::wait_for_ready().await;
106 } 188 }
107 r.cs().modify(|w| { 189 let result = Self::sample_async(4).await;
108 w.set_ainsel(4); 190 r.cs().modify(|w| w.set_ts_en(false));
109 w.set_start_once(true) 191 result
110 });
111 Self::wait_for_ready().await;
112 r.result().read().result().into()
113 } 192 }
193}
114 194
115 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 195impl<'d> Adc<'d, Blocking> {
116 let r = Self::regs(); 196 pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self {
117 pin.pad_ctrl().modify(|w| { 197 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 198
131 pub fn blocking_read_temperature(&mut self) -> u16 { 199 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 } 200 }
142} 201}
143 202
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 { 203pub struct InterruptHandler {
156 _empty: (), 204 _empty: (),
157} 205}
158 206
159impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler { 207impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
160 unsafe fn on_interrupt() { 208 unsafe fn on_interrupt() {
161 let r = Adc::regs(); 209 let r = Adc::<Async>::regs();
162 r.inte().write(|w| w.set_fifo(false)); 210 r.inte().write(|w| w.set_fifo(false));
163 WAKER.wake(); 211 WAKER.wake();
164 } 212 }
165} 213}
166 214
215mod sealed {
216 pub trait AdcPin: crate::gpio::sealed::Pin {
217 fn channel(&mut self) -> u8;
218 }
219}
220
221pub trait AdcPin: sealed::AdcPin + gpio::Pin {}
222
223macro_rules! impl_pin {
224 ($pin:ident, $channel:expr) => {
225 impl sealed::AdcPin for peripherals::$pin {
226 fn channel(&mut self) -> u8 {
227 $channel
228 }
229 }
230
231 impl AdcPin for peripherals::$pin {}
232 };
233}
234
167impl_pin!(PIN_26, 0); 235impl_pin!(PIN_26, 0);
168impl_pin!(PIN_27, 1); 236impl_pin!(PIN_27, 1);
169impl_pin!(PIN_28, 2); 237impl_pin!(PIN_28, 2);
170impl_pin!(PIN_29, 3); 238impl_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/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..868bffe74 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -5,15 +5,15 @@ 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" }
@@ -25,13 +25,14 @@ aligned = "0.4.1"
25 25
26bit_field = "0.10.2" 26bit_field = "0.10.2"
27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
28stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true } 28stm32wb-hci = { version = "0.1.3", optional = true }
29bitflags = { version = "2.3.3", optional = true }
29 30
30[features] 31[features]
31defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] 32defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"]
32 33
33ble = ["dep:stm32wb-hci"] 34ble = ["dep:stm32wb-hci"]
34mac = [] 35mac = ["dep:bitflags"]
35 36
36stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] 37stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
37stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] 38stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
@@ -48,4 +49,4 @@ stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
48stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ] 49stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
49stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ] 50stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
50stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ] 51stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
51stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file 52stm32wb55vy = [ "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..57f0dc4fa 100644
--- a/embassy-stm32-wpan/src/lib.rs
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -26,6 +26,9 @@ pub mod sub;
26pub mod tables; 26pub mod tables;
27pub mod unsafe_linked_list; 27pub mod unsafe_linked_list;
28 28
29#[cfg(feature = "mac")]
30pub mod mac;
31
29#[cfg(feature = "ble")] 32#[cfg(feature = "ble")]
30pub use crate::sub::ble::hci; 33pub use crate::sub::ble::hci;
31 34
@@ -60,9 +63,9 @@ impl<'d> TlMbox<'d> {
60 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), 63 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
61 traces_table: TL_TRACES_TABLE.as_ptr(), 64 traces_table: TL_TRACES_TABLE.as_ptr(),
62 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), 65 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
63 // zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), 66 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
64 // lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), 67 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
65 // ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), 68 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
66 }); 69 });
67 70
68 TL_SYS_TABLE 71 TL_SYS_TABLE
@@ -87,15 +90,15 @@ impl<'d> TlMbox<'d> {
87 TL_MAC_802_15_4_TABLE 90 TL_MAC_802_15_4_TABLE
88 .as_mut_ptr() 91 .as_mut_ptr()
89 .write_volatile(MaybeUninit::zeroed().assume_init()); 92 .write_volatile(MaybeUninit::zeroed().assume_init());
90 // TL_ZIGBEE_TABLE 93 TL_ZIGBEE_TABLE
91 // .as_mut_ptr() 94 .as_mut_ptr()
92 // .write_volatile(MaybeUninit::zeroed().assume_init()); 95 .write_volatile(MaybeUninit::zeroed().assume_init());
93 // TL_LLD_TESTS_TABLE 96 TL_LLD_TESTS_TABLE
94 // .as_mut_ptr() 97 .as_mut_ptr()
95 // .write_volatile(MaybeUninit::zeroed().assume_init()); 98 .write_volatile(MaybeUninit::zeroed().assume_init());
96 // TL_BLE_LLD_TABLE 99 TL_BLE_LLD_TABLE
97 // .as_mut_ptr() 100 .as_mut_ptr()
98 // .write_volatile(MaybeUninit::zeroed().assume_init()); 101 .write_volatile(MaybeUninit::zeroed().assume_init());
99 102
100 EVT_POOL 103 EVT_POOL
101 .as_mut_ptr() 104 .as_mut_ptr()
@@ -103,18 +106,30 @@ impl<'d> TlMbox<'d> {
103 SYS_SPARE_EVT_BUF 106 SYS_SPARE_EVT_BUF
104 .as_mut_ptr() 107 .as_mut_ptr()
105 .write_volatile(MaybeUninit::zeroed().assume_init()); 108 .write_volatile(MaybeUninit::zeroed().assume_init());
106 BLE_SPARE_EVT_BUF 109 CS_BUFFER
107 .as_mut_ptr() 110 .as_mut_ptr()
108 .write_volatile(MaybeUninit::zeroed().assume_init()); 111 .write_volatile(MaybeUninit::zeroed().assume_init());
109 112
113 #[cfg(feature = "ble")]
110 { 114 {
115 BLE_SPARE_EVT_BUF
116 .as_mut_ptr()
117 .write_volatile(MaybeUninit::zeroed().assume_init());
118
111 BLE_CMD_BUFFER 119 BLE_CMD_BUFFER
112 .as_mut_ptr() 120 .as_mut_ptr()
113 .write_volatile(MaybeUninit::zeroed().assume_init()); 121 .write_volatile(MaybeUninit::zeroed().assume_init());
114 HCI_ACL_DATA_BUFFER 122 HCI_ACL_DATA_BUFFER
115 .as_mut_ptr() 123 .as_mut_ptr()
116 .write_volatile(MaybeUninit::zeroed().assume_init()); 124 .write_volatile(MaybeUninit::zeroed().assume_init());
117 CS_BUFFER 125 }
126
127 #[cfg(feature = "mac")]
128 {
129 MAC_802_15_4_CMD_BUFFER
130 .as_mut_ptr()
131 .write_volatile(MaybeUninit::zeroed().assume_init());
132 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER
118 .as_mut_ptr() 133 .as_mut_ptr()
119 .write_volatile(MaybeUninit::zeroed().assume_init()); 134 .write_volatile(MaybeUninit::zeroed().assume_init());
120 } 135 }
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs
new file mode 100644
index 000000000..8cfa0a054
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/commands.rs
@@ -0,0 +1,467 @@
1use super::opcodes::OpcodeM4ToM0;
2use super::typedefs::{
3 AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus,
4 PanId, PibId, ScanType, SecurityLevel,
5};
6
7pub trait MacCommand {
8 const OPCODE: OpcodeM4ToM0;
9 const SIZE: usize;
10
11 fn copy_into_slice(&self, buf: &mut [u8]) {
12 unsafe { core::ptr::copy(self as *const _ as *const u8, buf as *mut _ as *mut u8, Self::SIZE) };
13 }
14}
15
16/// MLME ASSOCIATE Request used to request an association
17#[repr(C)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub struct AssociateRequest {
20 /// the logical channel on which to attempt association
21 pub channel_number: MacChannel,
22 /// the channel page on which to attempt association
23 pub channel_page: u8,
24 /// coordinator addressing mode
25 pub coord_addr_mode: AddressMode,
26 /// operational capabilities of the associating device
27 pub capability_information: Capabilities,
28 /// the identifier of the PAN with which to associate
29 pub coord_pan_id: PanId,
30 /// the security level to be used
31 pub security_level: SecurityLevel,
32 /// the mode used to identify the key to be used
33 pub key_id_mode: KeyIdMode,
34 /// the originator of the key to be used
35 pub key_source: [u8; 8],
36 /// Coordinator address
37 pub coord_address: MacAddress,
38 /// the index of the key to be used
39 pub key_index: u8,
40}
41
42impl MacCommand for AssociateRequest {
43 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq;
44 const SIZE: usize = 25;
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 const SIZE: usize = 24;
74}
75
76/// MLME GET Request used to request a PIB value
77#[repr(C)]
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
84impl MacCommand for GetRequest {
85 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
86 const SIZE: usize = 4;
87}
88
89/// MLME GTS Request used to request and maintain GTSs
90#[repr(C)]
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92pub struct GtsRequest {
93 /// the characteristics of the GTS
94 pub characteristics: GtsCharacteristics,
95 /// the security level to be used
96 pub security_level: SecurityLevel,
97 /// the mode used to identify the key to be used
98 pub key_id_mode: KeyIdMode,
99 /// the index of the key to be used
100 pub key_index: u8,
101 /// the originator of the key to be used
102 pub key_source: [u8; 8],
103}
104
105impl MacCommand for GtsRequest {
106 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
107 const SIZE: usize = 12;
108}
109
110#[repr(C)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub struct ResetRequest {
113 /// MAC PIB attributes are set to their default values or not during reset
114 pub set_default_pib: bool,
115}
116
117impl MacCommand for ResetRequest {
118 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq;
119 const SIZE: usize = 4;
120}
121
122/// MLME RX ENABLE Request used to request that the receiver is either enabled
123/// for a finite period of time or disabled
124#[repr(C)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126pub struct RxEnableRequest {
127 /// the request operation can be deferred or not
128 pub defer_permit: bool,
129 /// configure the transceiver to RX with ranging for a value of
130 /// RANGING_ON or to not enable ranging for RANGING_OFF
131 pub ranging_rx_control: u8,
132 /// number of symbols measured before the receiver is to be enabled or disabled
133 pub rx_on_time: [u8; 4],
134 /// number of symbols for which the receiver is to be enabled
135 pub rx_on_duration: [u8; 4],
136}
137
138impl MacCommand for RxEnableRequest {
139 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq;
140 const SIZE: usize = 12;
141
142 fn copy_into_slice(&self, buf: &mut [u8]) {
143 buf[0] = self.defer_permit as u8;
144 buf[1] = self.ranging_rx_control as u8;
145
146 // stuffing to keep 32bit alignment
147 buf[2] = 0;
148 buf[3] = 0;
149
150 buf[4..8].copy_from_slice(&self.rx_on_time);
151 buf[8..12].copy_from_slice(&self.rx_on_duration);
152 }
153}
154
155/// MLME SCAN Request used to initiate a channel scan over a given list of channels
156#[repr(C)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct ScanRequest {
159 /// the type of scan to be performed
160 pub scan_type: ScanType,
161 /// the time spent on scanning each channel
162 pub scan_duration: u8,
163 /// channel page on which to perform the scan
164 pub channel_page: u8,
165 /// security level to be used
166 pub security_level: SecurityLevel,
167 /// indicate which channels are to be scanned
168 pub scan_channels: [u8; 4],
169 /// originator the key to be used
170 pub key_source: [u8; 8],
171 /// mode used to identify the key to be used
172 pub key_id_mode: KeyIdMode,
173 /// index of the key to be used
174 pub key_index: u8,
175}
176
177impl MacCommand for ScanRequest {
178 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq;
179 const SIZE: usize = 20;
180}
181
182/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute
183#[repr(C)]
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185pub struct SetRequest {
186 /// the pointer to the value of the PIB attribute to set
187 pub pib_attribute_ptr: *const u8,
188 /// the name of the PIB attribute to set
189 pub pib_attribute: PibId,
190}
191
192impl MacCommand for SetRequest {
193 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq;
194 const SIZE: usize = 8;
195}
196
197/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe
198/// configuration
199#[derive(Default)]
200#[repr(C)]
201#[cfg_attr(feature = "defmt", derive(defmt::Format))]
202pub struct StartRequest {
203 /// PAN indentifier to used by the device
204 pub pan_id: PanId,
205 /// logical channel on which to begin
206 pub channel_number: MacChannel,
207 /// channel page on which to begin
208 pub channel_page: u8,
209 /// time at which to begin transmitting beacons
210 pub start_time: [u8; 4],
211 /// indicated how often the beacon is to be transmitted
212 pub beacon_order: u8,
213 /// length of the active portion of the superframe
214 pub superframe_order: u8,
215 /// indicated wheter the device is a PAN coordinator or not
216 pub pan_coordinator: bool,
217 /// indicates if the receiver of the beaconing device is disabled or not
218 pub battery_life_extension: bool,
219 /// indicated if the coordinator realignment command is to be trasmitted
220 pub coord_realignment: u8,
221 /// indicated if the coordinator realignment command is to be trasmitted
222 pub coord_realign_security_level: SecurityLevel,
223 /// index of the key to be used
224 pub coord_realign_key_id_index: u8,
225 /// originator of the key to be used
226 pub coord_realign_key_source: [u8; 8],
227 /// security level to be used for beacon frames
228 pub beacon_security_level: SecurityLevel,
229 /// mode used to identify the key to be used
230 pub beacon_key_id_mode: KeyIdMode,
231 /// index of the key to be used
232 pub beacon_key_index: u8,
233 /// originator of the key to be used
234 pub beacon_key_source: [u8; 8],
235}
236
237impl MacCommand for StartRequest {
238 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq;
239 const SIZE: usize = 35;
240}
241
242/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if
243/// specified, tracking its beacons
244#[repr(C)]
245#[cfg_attr(feature = "defmt", derive(defmt::Format))]
246pub struct SyncRequest {
247 /// the channel number on which to attempt coordinator synchronization
248 pub channel_number: MacChannel,
249 /// the channel page on which to attempt coordinator synchronization
250 pub channel_page: u8,
251 /// `true` if the MLME is to synchronize with the next beacon and attempts
252 /// to track all future beacons.
253 ///
254 /// `false` if the MLME is to synchronize with only the next beacon
255 pub track_beacon: bool,
256}
257
258impl MacCommand for SyncRequest {
259 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq;
260 const SIZE: usize = 4;
261}
262
263/// MLME POLL Request propmts the device to request data from the coordinator
264#[repr(C)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub struct PollRequest {
267 /// addressing mode of the coordinator
268 pub coord_addr_mode: AddressMode,
269 /// security level to be used
270 pub security_level: SecurityLevel,
271 /// mode used to identify the key to be used
272 pub key_id_mode: KeyIdMode,
273 /// index of the key to be used
274 pub key_index: u8,
275 /// coordinator address
276 pub coord_address: MacAddress,
277 /// originator of the key to be used
278 pub key_source: [u8; 8],
279 /// PAN identifier of the coordinator
280 pub coord_pan_id: PanId,
281}
282
283impl MacCommand for PollRequest {
284 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq;
285 const SIZE: usize = 24;
286}
287
288/// MLME DPS Request allows the next higher layer to request that the PHY utilize a
289/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration
290#[repr(C)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub struct DpsRequest {
293 /// the index value for the transmitter
294 tx_dps_index: u8,
295 /// the index value of the receiver
296 rx_dps_index: u8,
297 /// the number of symbols for which the transmitter and receiver will utilize the
298 /// respective DPS indices
299 dps_index_duration: u8,
300}
301
302impl MacCommand for DpsRequest {
303 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq;
304 const SIZE: usize = 4;
305}
306
307/// MLME SOUNDING request primitive which is used by the next higher layer to request that
308/// the PHY respond with channel sounding information
309#[repr(C)]
310#[cfg_attr(feature = "defmt", derive(defmt::Format))]
311pub struct SoundingRequest;
312
313impl MacCommand for SoundingRequest {
314 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq;
315 const SIZE: usize = 4;
316}
317
318/// MLME CALIBRATE request primitive which used to obtain the results of a ranging
319/// calibration request from an RDEV
320#[repr(C)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))]
322pub struct CalibrateRequest;
323
324impl MacCommand for CalibrateRequest {
325 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq;
326 const SIZE: usize = 4;
327}
328
329/// MCPS DATA Request used for MAC data related requests from the application
330#[repr(C)]
331#[cfg_attr(feature = "defmt", derive(defmt::Format))]
332pub struct DataRequest {
333 /// the handle assocated with the MSDU to be transmitted
334 pub msdu_ptr: *const u8,
335 /// source addressing mode used
336 pub src_addr_mode: AddressMode,
337 /// destination addressing mode used
338 pub dst_addr_mode: AddressMode,
339 /// destination PAN Id
340 pub dst_pan_id: PanId,
341 /// destination address
342 pub dst_address: MacAddress,
343 /// the number of octets contained in the MSDU
344 pub msdu_length: u8,
345 /// the handle assocated with the MSDU to be transmitted
346 pub msdu_handle: u8,
347 /// the ACK transmittion options for the MSDU
348 pub ack_tx: u8,
349 /// `true` if a GTS is to be used for transmission
350 ///
351 /// `false` indicates that the CAP will be used
352 pub gts_tx: bool,
353 /// the pending bit transmission options for the MSDU
354 pub indirect_tx: u8,
355 /// the security level to be used
356 pub security_level: SecurityLevel,
357 /// the mode used to indentify the key to be used
358 pub key_id_mode: KeyIdMode,
359 /// the index of the key to be used
360 pub key_index: u8,
361 /// the originator of the key to be used
362 pub key_source: [u8; 8],
363 /// 2011 - the pulse repitition value
364 pub uwbprf: u8,
365 /// 2011 - the ranging configuration
366 pub ranging: u8,
367 /// 2011 - the preamble symbol repititions
368 pub uwb_preamble_symbol_repetitions: u8,
369 /// 2011 - indicates the data rate
370 pub datrate: u8,
371}
372
373impl Default for DataRequest {
374 fn default() -> Self {
375 Self {
376 msdu_ptr: 0 as *const u8,
377 src_addr_mode: AddressMode::NoAddress,
378 dst_addr_mode: AddressMode::NoAddress,
379 dst_pan_id: PanId([0, 0]),
380 dst_address: MacAddress { short: [0, 0] },
381 msdu_length: 0,
382 msdu_handle: 0,
383 ack_tx: 0,
384 gts_tx: false,
385 indirect_tx: 0,
386 security_level: SecurityLevel::Unsecure,
387 key_id_mode: KeyIdMode::Implicite,
388 key_index: 0,
389 key_source: [0u8; 8],
390 uwbprf: 0,
391 ranging: 0,
392 uwb_preamble_symbol_repetitions: 0,
393 datrate: 0,
394 }
395 }
396}
397
398impl MacCommand for DataRequest {
399 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq;
400 const SIZE: usize = 40;
401}
402
403/// for MCPS PURGE Request used to purge an MSDU from the transaction queue
404#[repr(C)]
405#[cfg_attr(feature = "defmt", derive(defmt::Format))]
406pub struct PurgeRequest {
407 /// the handle associated with the MSDU to be purged from the transaction
408 /// queue
409 pub msdu_handle: u8,
410}
411
412impl MacCommand for PurgeRequest {
413 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq;
414 const SIZE: usize = 4;
415}
416
417/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication
418#[repr(C)]
419#[derive(Default)]
420#[cfg_attr(feature = "defmt", derive(defmt::Format))]
421pub struct AssociateResponse {
422 /// extended address of the device requesting association
423 pub device_address: [u8; 8],
424 /// 16-bitshort device address allocated by the coordinator on successful
425 /// association
426 pub assoc_short_address: [u8; 2],
427 /// status of the association attempt
428 pub status: MacStatus,
429 /// security level to be used
430 pub security_level: SecurityLevel,
431 /// the originator of the key to be used
432 pub key_source: [u8; 8],
433 /// the mode used to identify the key to be used
434 pub key_id_mode: KeyIdMode,
435 /// the index of the key to be used
436 pub key_index: u8,
437}
438
439impl MacCommand for AssociateResponse {
440 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes;
441 const SIZE: usize = 24;
442}
443
444/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication
445#[repr(C)]
446#[cfg_attr(feature = "defmt", derive(defmt::Format))]
447pub struct OrphanResponse {
448 /// extended address of the orphaned device
449 pub orphan_address: [u8; 8],
450 /// short address allocated to the orphaned device
451 pub short_address: [u8; 2],
452 /// if the orphaned device is associated with coordinator or not
453 pub associated_member: bool,
454 /// security level to be used
455 pub security_level: SecurityLevel,
456 /// the originator of the key to be used
457 pub key_source: [u8; 8],
458 /// the mode used to identify the key to be used
459 pub key_id_mode: KeyIdMode,
460 /// the index of the key to be used
461 pub key_index: u8,
462}
463
464impl MacCommand for OrphanResponse {
465 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes;
466 const SIZE: usize = 24;
467}
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/event.rs b/embassy-stm32-wpan/src/mac/event.rs
new file mode 100644
index 000000000..dfce21fea
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/event.rs
@@ -0,0 +1,94 @@
1use super::helpers::to_u16;
2use super::indications::{
3 AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
4 DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication,
5};
6use super::responses::{
7 AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm,
8 PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm,
9};
10use crate::mac::opcodes::OpcodeM0ToM4;
11
12pub trait ParseableMacEvent {
13 const SIZE: usize;
14
15 fn validate(buf: &[u8]) -> Result<(), ()> {
16 if buf.len() < Self::SIZE {
17 return Err(());
18 }
19
20 Ok(())
21 }
22
23 fn try_parse(buf: &[u8]) -> Result<Self, ()>
24 where
25 Self: Sized;
26}
27
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum MacEvent {
30 MlmeAssociateCnf(AssociateConfirm),
31 MlmeDisassociateCnf(DisassociateConfirm),
32 MlmeGetCnf(GetConfirm),
33 MlmeGtsCnf(GtsConfirm),
34 MlmeResetCnf(ResetConfirm),
35 MlmeRxEnableCnf(RxEnableConfirm),
36 MlmeScanCnf(ScanConfirm),
37 MlmeSetCnf(SetConfirm),
38 MlmeStartCnf(StartConfirm),
39 MlmePollCnf(PollConfirm),
40 MlmeDpsCnf(DpsConfirm),
41 MlmeSoundingCnf(SoundingConfirm),
42 MlmeCalibrateCnf(CalibrateConfirm),
43 McpsDataCnf(DataConfirm),
44 McpsPurgeCnf(PurgeConfirm),
45 MlmeAssociateInd(AssociateIndication),
46 MlmeDisassociateInd(DisassociateIndication),
47 MlmeBeaconNotifyInd(BeaconNotifyIndication),
48 MlmeCommStatusInd(CommStatusIndication),
49 MlmeGtsInd(GtsIndication),
50 MlmeOrphanInd(OrphanIndication),
51 MlmeSyncLossInd(SyncLossIndication),
52 MlmeDpsInd(DpsIndication),
53 McpsDataInd(DataIndication),
54 MlmePollInd(PollIndication),
55}
56
57impl TryFrom<&[u8]> for MacEvent {
58 type Error = ();
59
60 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
61 let opcode = to_u16(&value[0..2]);
62 let opcode = OpcodeM0ToM4::try_from(opcode)?;
63
64 let buf = &value[2..];
65
66 match opcode {
67 OpcodeM0ToM4::MlmeAssociateCnf => Ok(Self::MlmeAssociateCnf(AssociateConfirm::try_parse(buf)?)),
68 OpcodeM0ToM4::MlmeDisassociateCnf => Ok(Self::MlmeDisassociateCnf(DisassociateConfirm::try_parse(buf)?)),
69 OpcodeM0ToM4::MlmeGetCnf => Ok(Self::MlmeGetCnf(GetConfirm::try_parse(buf)?)),
70 OpcodeM0ToM4::MlmeGtsCnf => Ok(Self::MlmeGtsCnf(GtsConfirm::try_parse(buf)?)),
71 OpcodeM0ToM4::MlmeResetCnf => Ok(Self::MlmeResetCnf(ResetConfirm::try_parse(buf)?)),
72 OpcodeM0ToM4::MlmeRxEnableCnf => Ok(Self::MlmeRxEnableCnf(RxEnableConfirm::try_parse(buf)?)),
73 OpcodeM0ToM4::MlmeScanCnf => Ok(Self::MlmeScanCnf(ScanConfirm::try_parse(buf)?)),
74 OpcodeM0ToM4::MlmeSetCnf => Ok(Self::MlmeSetCnf(SetConfirm::try_parse(buf)?)),
75 OpcodeM0ToM4::MlmeStartCnf => Ok(Self::MlmeStartCnf(StartConfirm::try_parse(buf)?)),
76 OpcodeM0ToM4::MlmePollCnf => Ok(Self::MlmePollCnf(PollConfirm::try_parse(buf)?)),
77 OpcodeM0ToM4::MlmeDpsCnf => Ok(Self::MlmeDpsCnf(DpsConfirm::try_parse(buf)?)),
78 OpcodeM0ToM4::MlmeSoundingCnf => Ok(Self::MlmeSoundingCnf(SoundingConfirm::try_parse(buf)?)),
79 OpcodeM0ToM4::MlmeCalibrateCnf => Ok(Self::MlmeCalibrateCnf(CalibrateConfirm::try_parse(buf)?)),
80 OpcodeM0ToM4::McpsDataCnf => Ok(Self::McpsDataCnf(DataConfirm::try_parse(buf)?)),
81 OpcodeM0ToM4::McpsPurgeCnf => Ok(Self::McpsPurgeCnf(PurgeConfirm::try_parse(buf)?)),
82 OpcodeM0ToM4::MlmeAssociateInd => Ok(Self::MlmeAssociateInd(AssociateIndication::try_parse(buf)?)),
83 OpcodeM0ToM4::MlmeDisassociateInd => Ok(Self::MlmeDisassociateInd(DisassociateIndication::try_parse(buf)?)),
84 OpcodeM0ToM4::MlmeBeaconNotifyInd => Ok(Self::MlmeBeaconNotifyInd(BeaconNotifyIndication::try_parse(buf)?)),
85 OpcodeM0ToM4::MlmeCommStatusInd => Ok(Self::MlmeCommStatusInd(CommStatusIndication::try_parse(buf)?)),
86 OpcodeM0ToM4::MlmeGtsInd => Ok(Self::MlmeGtsInd(GtsIndication::try_parse(buf)?)),
87 OpcodeM0ToM4::MlmeOrphanInd => Ok(Self::MlmeOrphanInd(OrphanIndication::try_parse(buf)?)),
88 OpcodeM0ToM4::MlmeSyncLossInd => Ok(Self::MlmeSyncLossInd(SyncLossIndication::try_parse(buf)?)),
89 OpcodeM0ToM4::MlmeDpsInd => Ok(Self::MlmeDpsInd(DpsIndication::try_parse(buf)?)),
90 OpcodeM0ToM4::McpsDataInd => Ok(Self::McpsDataInd(DataIndication::try_parse(buf)?)),
91 OpcodeM0ToM4::MlmePollInd => Ok(Self::MlmePollInd(PollIndication::try_parse(buf)?)),
92 }
93 }
94}
diff --git a/embassy-stm32-wpan/src/mac/helpers.rs b/embassy-stm32-wpan/src/mac/helpers.rs
new file mode 100644
index 000000000..5a5bf8a85
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/helpers.rs
@@ -0,0 +1,7 @@
1pub fn to_u16(buf: &[u8]) -> u16 {
2 ((buf[1] as u16) << 8) | buf[0] as u16
3}
4
5pub fn to_u32(buf: &[u8]) -> u32 {
6 ((buf[0] as u32) << 0) + ((buf[1] as u32) << 8) + ((buf[2] as u32) << 16) + ((buf[3] as u32) << 24)
7}
diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs
new file mode 100644
index 000000000..6df4aa23a
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/indications.rs
@@ -0,0 +1,470 @@
1use super::consts::MAX_PENDING_ADDRESS;
2use super::event::ParseableMacEvent;
3use super::helpers::to_u32;
4use super::typedefs::{
5 AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor,
6 PanId, SecurityLevel,
7};
8
9/// MLME ASSOCIATE Indication which will be used by the MAC
10/// to indicate the reception of an association request command
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct AssociateIndication {
13 /// Extended address of the device requesting association
14 pub device_address: [u8; 8],
15 /// Operational capabilities of the device requesting association
16 pub capability_information: Capabilities,
17 /// Security level purportedly used by the received MAC command frame
18 pub security_level: SecurityLevel,
19 /// The mode used to identify the key used by the originator of frame
20 pub key_id_mode: KeyIdMode,
21 /// Index of the key used by the originator of the received frame
22 pub key_index: u8,
23 /// The originator of the key used by the originator of the received frame
24 pub key_source: [u8; 8],
25}
26
27impl ParseableMacEvent for AssociateIndication {
28 const SIZE: usize = 20;
29
30 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
31 Self::validate(buf)?;
32
33 Ok(Self {
34 device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
35 capability_information: Capabilities::from_bits(buf[8]).ok_or(())?,
36 security_level: SecurityLevel::try_from(buf[9])?,
37 key_id_mode: KeyIdMode::try_from(buf[10])?,
38 key_index: buf[11],
39 key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
40 })
41 }
42}
43
44/// MLME DISASSOCIATE indication which will be used to send
45/// disassociation indication to the application.
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct DisassociateIndication {
48 /// Extended address of the device requesting association
49 pub device_address: [u8; 8],
50 /// The reason for the disassociation
51 pub disassociation_reason: DisassociationReason,
52 /// The security level to be used
53 pub security_level: SecurityLevel,
54 /// The mode used to identify the key to be used
55 pub key_id_mode: KeyIdMode,
56 /// The index of the key to be used
57 pub key_index: u8,
58 /// The originator of the key to be used
59 pub key_source: [u8; 8],
60}
61
62impl ParseableMacEvent for DisassociateIndication {
63 const SIZE: usize = 20;
64
65 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
66 Self::validate(buf)?;
67
68 Ok(Self {
69 device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
70 disassociation_reason: DisassociationReason::try_from(buf[8])?,
71 security_level: SecurityLevel::try_from(buf[9])?,
72 key_id_mode: KeyIdMode::try_from(buf[10])?,
73 key_index: buf[11],
74 key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
75 })
76 }
77}
78
79/// MLME BEACON NOTIIFY Indication which is used to send parameters contained
80/// within a beacon frame received by the MAC to the application
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub struct BeaconNotifyIndication {
83 /// he set of octets comprising the beacon payload to be transferred
84 /// from the MAC sublayer entity to the next higher layer
85 pub sdu_ptr: *const u8,
86 /// The PAN Descriptor for the received beacon
87 pub pan_descriptor: PanDescriptor,
88 /// The list of addresses of the devices
89 pub addr_list: [MacAddress; MAX_PENDING_ADDRESS],
90 /// Beacon Sequence Number
91 pub bsn: u8,
92 /// The beacon pending address specification
93 pub pend_addr_spec: u8,
94 /// Number of octets contained in the beacon payload of the beacon frame
95 pub sdu_length: u8,
96}
97
98impl ParseableMacEvent for BeaconNotifyIndication {
99 const SIZE: usize = 88;
100
101 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
102 // TODO: this is unchecked
103
104 Self::validate(buf)?;
105
106 let addr_list = [
107 MacAddress::try_from(&buf[26..34])?,
108 MacAddress::try_from(&buf[34..42])?,
109 MacAddress::try_from(&buf[42..50])?,
110 MacAddress::try_from(&buf[50..58])?,
111 MacAddress::try_from(&buf[58..66])?,
112 MacAddress::try_from(&buf[66..74])?,
113 MacAddress::try_from(&buf[74..82])?,
114 ];
115
116 Ok(Self {
117 sdu_ptr: to_u32(&buf[0..4]) as *const u8,
118 pan_descriptor: PanDescriptor::try_from(&buf[4..26])?,
119 addr_list,
120 bsn: buf[82],
121 pend_addr_spec: buf[83],
122 sdu_length: buf[83],
123 })
124 }
125}
126
127/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct CommStatusIndication {
130 /// The 16-bit PAN identifier of the device from which the frame
131 /// was received or to which the frame was being sent
132 pub pan_id: PanId,
133 /// Source addressing mode
134 pub src_addr_mode: AddressMode,
135 /// Destination addressing mode
136 pub dst_addr_mode: AddressMode,
137 /// Source address
138 pub src_address: MacAddress,
139 /// Destination address
140 pub dst_address: MacAddress,
141 /// The communications status
142 pub status: MacStatus,
143 /// Security level to be used
144 pub security_level: SecurityLevel,
145 /// Mode used to identify the key to be used
146 pub key_id_mode: KeyIdMode,
147 /// Index of the key to be used
148 pub key_index: u8,
149 /// Originator of the key to be used
150 pub key_source: [u8; 8],
151}
152
153impl ParseableMacEvent for CommStatusIndication {
154 const SIZE: usize = 32;
155
156 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
157 Self::validate(buf)?;
158
159 let src_addr_mode = AddressMode::try_from(buf[2])?;
160 let dst_addr_mode = AddressMode::try_from(buf[3])?;
161
162 let src_address = match src_addr_mode {
163 AddressMode::NoAddress => MacAddress { short: [0, 0] },
164 AddressMode::Reserved => MacAddress { short: [0, 0] },
165 AddressMode::Short => MacAddress {
166 short: [buf[4], buf[5]],
167 },
168 AddressMode::Extended => MacAddress {
169 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
170 },
171 };
172
173 let dst_address = match dst_addr_mode {
174 AddressMode::NoAddress => MacAddress { short: [0, 0] },
175 AddressMode::Reserved => MacAddress { short: [0, 0] },
176 AddressMode::Short => MacAddress {
177 short: [buf[12], buf[13]],
178 },
179 AddressMode::Extended => MacAddress {
180 extended: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
181 },
182 };
183
184 Ok(Self {
185 pan_id: PanId([buf[0], buf[1]]),
186 src_addr_mode,
187 dst_addr_mode,
188 src_address,
189 dst_address,
190 status: MacStatus::try_from(buf[20])?,
191 security_level: SecurityLevel::try_from(buf[21])?,
192 key_id_mode: KeyIdMode::try_from(buf[22])?,
193 key_index: buf[23],
194 key_source: [buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]],
195 })
196 }
197}
198
199/// MLME GTS Indication indicates that a GTS has been allocated or that a
200/// previously allocated GTS has been deallocated
201#[cfg_attr(feature = "defmt", derive(defmt::Format))]
202pub struct GtsIndication {
203 /// The short address of the device that has been allocated or deallocated a GTS
204 pub device_address: [u8; 2],
205 /// The characteristics of the GTS
206 pub gts_characteristics: u8,
207 /// Security level to be used
208 pub security_level: SecurityLevel,
209 /// Mode used to identify the key to be used
210 pub key_id_mode: KeyIdMode,
211 /// Index of the key to be used
212 pub key_index: u8,
213 /// Originator of the key to be used
214 pub key_source: [u8; 8],
215}
216
217impl ParseableMacEvent for GtsIndication {
218 const SIZE: usize = 16;
219
220 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
221 Self::validate(buf)?;
222
223 Ok(Self {
224 device_address: [buf[0], buf[1]],
225 gts_characteristics: buf[2],
226 security_level: SecurityLevel::try_from(buf[3])?,
227 key_id_mode: KeyIdMode::try_from(buf[4])?,
228 key_index: buf[5],
229 // 2 byte stuffing
230 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
231 })
232 }
233}
234
235/// MLME ORPHAN Indication which is used by the coordinator to notify the
236/// application of the presence of an orphaned device
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub struct OrphanIndication {
239 /// Extended address of the orphaned device
240 pub orphan_address: [u8; 8],
241 /// Originator of the key used by the originator of the received frame
242 pub key_source: [u8; 8],
243 /// Security level purportedly used by the received MAC command frame
244 pub security_level: SecurityLevel,
245 /// Mode used to identify the key used by originator of received frame
246 pub key_id_mode: KeyIdMode,
247 /// Index of the key used by the originator of the received frame
248 pub key_index: u8,
249}
250
251impl ParseableMacEvent for OrphanIndication {
252 const SIZE: usize = 20;
253
254 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
255 Self::validate(buf)?;
256
257 Ok(Self {
258 orphan_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
259 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
260 security_level: SecurityLevel::try_from(buf[16])?,
261 key_id_mode: KeyIdMode::try_from(buf[17])?,
262 key_index: buf[18],
263 // 1 byte stuffing
264 })
265 }
266}
267
268/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss
269/// of synchronization with the coordinator
270#[cfg_attr(feature = "defmt", derive(defmt::Format))]
271pub struct SyncLossIndication {
272 /// The PAN identifier with which the device lost synchronization or to which it was realigned
273 pub pan_id: PanId,
274 /// The reason that synchronization was lost
275 pub loss_reason: u8,
276 /// The logical channel on which the device lost synchronization or to whi
277 pub channel_number: MacChannel,
278 /// The channel page on which the device lost synchronization or to which
279 pub channel_page: u8,
280 /// The security level used by the received MAC frame
281 pub security_level: SecurityLevel,
282 /// Mode used to identify the key used by originator of received frame
283 pub key_id_mode: KeyIdMode,
284 /// Index of the key used by the originator of the received frame
285 pub key_index: u8,
286 /// Originator of the key used by the originator of the received frame
287 pub key_source: [u8; 8],
288}
289
290impl ParseableMacEvent for SyncLossIndication {
291 const SIZE: usize = 16;
292
293 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
294 Self::validate(buf)?;
295
296 Ok(Self {
297 pan_id: PanId([buf[0], buf[1]]),
298 loss_reason: buf[2],
299 channel_number: MacChannel::try_from(buf[3])?,
300 channel_page: buf[4],
301 security_level: SecurityLevel::try_from(buf[5])?,
302 key_id_mode: KeyIdMode::try_from(buf[6])?,
303 key_index: buf[7],
304 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
305 })
306 }
307}
308
309/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration
310/// and the resetting of the DPS values in the PHY
311#[cfg_attr(feature = "defmt", derive(defmt::Format))]
312pub struct DpsIndication;
313
314impl ParseableMacEvent for DpsIndication {
315 const SIZE: usize = 4;
316
317 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
318 Self::validate(buf)?;
319
320 Ok(Self)
321 }
322}
323
324#[cfg_attr(feature = "defmt", derive(defmt::Format))]
325#[repr(C, align(8))]
326pub struct DataIndication {
327 /// Pointer to the set of octets forming the MSDU being indicated
328 pub msdu_ptr: *const u8,
329 /// Source addressing mode used
330 pub src_addr_mode: AddressMode,
331 /// Source PAN ID
332 pub src_pan_id: PanId,
333 /// Source address
334 pub src_address: MacAddress,
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 being indicated
342 pub msdu_length: u8,
343 /// QI value measured during reception of the MPDU
344 pub mpdu_link_quality: u8,
345 /// The data sequence number of the received data frame
346 pub dsn: u8,
347 /// The time, in symbols, at which the data were received
348 pub time_stamp: [u8; 4],
349 /// The security level purportedly used by the received data frame
350 pub security_level: SecurityLevel,
351 /// Mode used to identify the key used by originator of received frame
352 pub key_id_mode: KeyIdMode,
353 /// The originator of the key
354 pub key_source: [u8; 8],
355 /// The index of the key
356 pub key_index: u8,
357 /// he pulse repetition value of the received PPDU
358 pub uwbprf: u8,
359 /// The preamble symbol repetitions of the UWB PHY frame
360 pub uwn_preamble_symbol_repetitions: u8,
361 /// Indicates the data rate
362 pub datrate: u8,
363 /// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange,
364 pub ranging_received: u8,
365 pub ranging_counter_start: u32,
366 pub ranging_counter_stop: u32,
367 /// ime units in a message exchange over which the tracking offset was measured
368 pub ranging_tracking_interval: u32,
369 /// time units slipped or advanced by the radio tracking system
370 pub ranging_offset: u32,
371 /// The FoM characterizing the ranging measurement
372 pub ranging_fom: u8,
373 /// The Received Signal Strength Indicator measured
374 pub rssi: u8,
375}
376
377impl ParseableMacEvent for DataIndication {
378 const SIZE: usize = 68;
379
380 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
381 Self::validate(buf)?;
382
383 let src_addr_mode = AddressMode::try_from(buf[4])?;
384 let src_address = match src_addr_mode {
385 AddressMode::NoAddress => MacAddress { short: [0, 0] },
386 AddressMode::Reserved => MacAddress { short: [0, 0] },
387 AddressMode::Short => MacAddress {
388 short: [buf[7], buf[8]],
389 },
390 AddressMode::Extended => MacAddress {
391 extended: [buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]],
392 },
393 };
394
395 let dst_addr_mode = AddressMode::try_from(buf[15])?;
396 let dst_address = match dst_addr_mode {
397 AddressMode::NoAddress => MacAddress { short: [0, 0] },
398 AddressMode::Reserved => MacAddress { short: [0, 0] },
399 AddressMode::Short => MacAddress {
400 short: [buf[18], buf[19]],
401 },
402 AddressMode::Extended => MacAddress {
403 extended: [buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25]],
404 },
405 };
406
407 Ok(Self {
408 msdu_ptr: to_u32(&buf[0..4]) as *const u8,
409 src_addr_mode,
410 src_pan_id: PanId([buf[5], buf[6]]),
411 src_address,
412 dst_addr_mode,
413 dst_pan_id: PanId([buf[16], buf[17]]),
414 dst_address,
415 msdu_length: buf[26],
416 mpdu_link_quality: buf[27],
417 dsn: buf[28],
418 time_stamp: [buf[29], buf[30], buf[31], buf[32]],
419 security_level: SecurityLevel::try_from(buf[33]).unwrap_or(SecurityLevel::Unsecure), // TODO: this is totaly wrong, but I'm too smol brain to fix it
420 key_id_mode: KeyIdMode::try_from(buf[34]).unwrap_or(KeyIdMode::Implicite), // TODO: this is totaly wrong, but I'm too smol brain to fix it
421 key_source: [buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42]],
422 key_index: buf[43],
423 uwbprf: buf[44],
424 uwn_preamble_symbol_repetitions: buf[45],
425 datrate: buf[46],
426 ranging_received: buf[47],
427 ranging_counter_start: to_u32(&buf[48..52]),
428 ranging_counter_stop: to_u32(&buf[52..56]),
429 ranging_tracking_interval: to_u32(&buf[56..60]),
430 ranging_offset: to_u32(&buf[60..64]),
431 ranging_fom: buf[65],
432 rssi: buf[66],
433 })
434 }
435}
436
437/// MLME POLL Indication which will be used for indicating the Data Request
438/// reception to upper layer as defined in Zigbee r22 - D.8.2
439#[cfg_attr(feature = "defmt", derive(defmt::Format))]
440pub struct PollIndication {
441 /// addressing mode used
442 pub addr_mode: AddressMode,
443 /// Poll requester address
444 pub request_address: MacAddress,
445}
446
447impl ParseableMacEvent for PollIndication {
448 const SIZE: usize = 9;
449
450 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
451 Self::validate(buf)?;
452
453 let addr_mode = AddressMode::try_from(buf[0])?;
454 let request_address = match addr_mode {
455 AddressMode::NoAddress => MacAddress { short: [0, 0] },
456 AddressMode::Reserved => MacAddress { short: [0, 0] },
457 AddressMode::Short => MacAddress {
458 short: [buf[1], buf[2]],
459 },
460 AddressMode::Extended => MacAddress {
461 extended: [buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]],
462 },
463 };
464
465 Ok(Self {
466 addr_mode,
467 request_address,
468 })
469 }
470}
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..1af8fe6ba
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/mod.rs
@@ -0,0 +1,9 @@
1pub mod commands;
2mod consts;
3pub mod event;
4mod helpers;
5pub mod indications;
6mod macros;
7mod opcodes;
8pub mod responses;
9pub mod typedefs;
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..2f6f5bf58
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/responses.rs
@@ -0,0 +1,433 @@
1use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED};
2use super::event::ParseableMacEvent;
3use super::helpers::to_u32;
4use super::typedefs::{
5 AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType,
6 SecurityLevel,
7};
8
9/// MLME ASSOCIATE Confirm used to inform of the initiating device whether
10/// its request to associate was successful or unsuccessful
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct AssociateConfirm {
13 /// short address allocated by the coordinator on successful association
14 pub assoc_short_address: [u8; 2],
15 /// status of the association request
16 pub status: AssociationStatus,
17 /// security level to be used
18 pub security_level: SecurityLevel,
19 /// the originator of the key to be used
20 pub key_source: [u8; 8],
21 /// the mode used to identify the key to be used
22 pub key_id_mode: KeyIdMode,
23 /// the index of the key to be used
24 pub key_index: u8,
25}
26
27impl ParseableMacEvent for AssociateConfirm {
28 const SIZE: usize = 16;
29
30 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
31 Self::validate(buf)?;
32
33 Ok(Self {
34 assoc_short_address: [buf[0], buf[1]],
35 status: AssociationStatus::try_from(buf[2])?,
36 security_level: SecurityLevel::try_from(buf[3])?,
37 key_source: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
38 key_id_mode: KeyIdMode::try_from(buf[12])?,
39 key_index: buf[13],
40 })
41 }
42}
43
44/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application.
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct DisassociateConfirm {
47 /// status of the disassociation attempt
48 pub status: MacStatus,
49 /// device addressing mode used
50 pub device_addr_mode: AddressMode,
51 /// the identifier of the PAN of the device
52 pub device_pan_id: PanId,
53 /// device address
54 pub device_address: MacAddress,
55}
56
57impl ParseableMacEvent for DisassociateConfirm {
58 const SIZE: usize = 12;
59
60 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
61 Self::validate(buf)?;
62
63 let device_addr_mode = AddressMode::try_from(buf[1])?;
64 let device_address = match device_addr_mode {
65 AddressMode::NoAddress => MacAddress { short: [0, 0] },
66 AddressMode::Reserved => MacAddress { short: [0, 0] },
67 AddressMode::Short => MacAddress {
68 short: [buf[4], buf[5]],
69 },
70 AddressMode::Extended => MacAddress {
71 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
72 },
73 };
74
75 Ok(Self {
76 status: MacStatus::try_from(buf[0])?,
77 device_addr_mode,
78 device_pan_id: PanId([buf[2], buf[3]]),
79 device_address,
80 })
81 }
82}
83
84/// MLME GET Confirm which requests information about a given PIB attribute
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct GetConfirm {
87 /// The pointer to the value of the PIB attribute attempted to read
88 pub pib_attribute_value_ptr: *const u8,
89 /// Status of the GET attempt
90 pub status: MacStatus,
91 /// The name of the PIB attribute attempted to read
92 pub pib_attribute: PibId,
93 /// The lenght of the PIB attribute Value return
94 pub pib_attribute_value_len: u8,
95}
96
97impl ParseableMacEvent for GetConfirm {
98 const SIZE: usize = 8;
99
100 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
101 Self::validate(buf)?;
102
103 let address = to_u32(&buf[0..4]);
104
105 Ok(Self {
106 pib_attribute_value_ptr: address as *const u8,
107 status: MacStatus::try_from(buf[4])?,
108 pib_attribute: PibId::try_from(buf[5])?,
109 pib_attribute_value_len: buf[6],
110 })
111 }
112}
113
114/// MLME GTS Confirm which eports the results of a request to allocate a new GTS
115/// or to deallocate an existing GTS
116#[cfg_attr(feature = "defmt", derive(defmt::Format))]
117pub struct GtsConfirm {
118 /// The characteristics of the GTS
119 pub gts_characteristics: u8,
120 /// The status of the GTS reques
121 pub status: MacStatus,
122}
123
124impl ParseableMacEvent for GtsConfirm {
125 const SIZE: usize = 4;
126
127 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
128 Self::validate(buf)?;
129
130 Ok(Self {
131 gts_characteristics: buf[0],
132 status: MacStatus::try_from(buf[1])?,
133 })
134 }
135}
136
137/// MLME RESET Confirm which is used to report the results of the reset operation
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub struct ResetConfirm {
140 /// The result of the reset operation
141 status: MacStatus,
142}
143
144impl ParseableMacEvent for ResetConfirm {
145 const SIZE: usize = 4;
146
147 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
148 Self::validate(buf)?;
149
150 Ok(Self {
151 status: MacStatus::try_from(buf[0])?,
152 })
153 }
154}
155
156/// MLME RX ENABLE Confirm which is used to report the results of the attempt
157/// to enable or disable the receiver
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
159pub struct RxEnableConfirm {
160 /// Result of the request to enable or disable the receiver
161 status: MacStatus,
162}
163
164impl ParseableMacEvent for RxEnableConfirm {
165 const SIZE: usize = 4;
166
167 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
168 Self::validate(buf)?;
169
170 Ok(Self {
171 status: MacStatus::try_from(buf[0])?,
172 })
173 }
174}
175
176/// MLME SCAN Confirm which is used to report the result of the channel scan request
177#[cfg_attr(feature = "defmt", derive(defmt::Format))]
178pub struct ScanConfirm {
179 /// Status of the scan request
180 pub status: MacStatus,
181 /// The type of scan performed
182 pub scan_type: ScanType,
183 /// Channel page on which the scan was performed
184 pub channel_page: u8,
185 /// Channels given in the request which were not scanned
186 pub unscanned_channels: [u8; 4],
187 /// Number of elements returned in the appropriate result lists
188 pub result_list_size: u8,
189 /// List of energy measurements
190 pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
191 /// List of PAN descriptors
192 pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED],
193 /// Categorization of energy detected in channel
194 pub detected_category: u8,
195 /// For UWB PHYs, the list of energy measurements taken
196 pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
197}
198
199impl ParseableMacEvent for ScanConfirm {
200 const SIZE: usize = 185;
201
202 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
203 // TODO: this is unchecked
204
205 Self::validate(buf)?;
206
207 let mut energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
208 energy_detect_list.copy_from_slice(&buf[8..24]);
209
210 let pan_descriptor_list = [
211 PanDescriptor::try_from(&buf[24..46])?,
212 PanDescriptor::try_from(&buf[46..68])?,
213 PanDescriptor::try_from(&buf[68..90])?,
214 PanDescriptor::try_from(&buf[90..102])?,
215 PanDescriptor::try_from(&buf[102..124])?,
216 PanDescriptor::try_from(&buf[124..146])?,
217 ];
218
219 let mut uwb_energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
220 uwb_energy_detect_list.copy_from_slice(&buf[147..163]);
221
222 Ok(Self {
223 status: MacStatus::try_from(buf[0])?,
224 scan_type: ScanType::try_from(buf[1])?,
225 channel_page: buf[2],
226 unscanned_channels: [buf[3], buf[4], buf[5], buf[6]],
227 result_list_size: buf[7],
228 energy_detect_list,
229 pan_descriptor_list,
230 detected_category: buf[146],
231 uwb_energy_detect_list,
232 })
233 }
234}
235
236/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub struct SetConfirm {
239 /// The result of the set operation
240 pub status: MacStatus,
241 /// The name of the PIB attribute that was written
242 pub pin_attribute: PibId,
243}
244
245impl ParseableMacEvent for SetConfirm {
246 const SIZE: usize = 4;
247
248 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
249 Self::validate(buf)?;
250
251 Ok(Self {
252 status: MacStatus::try_from(buf[0])?,
253 pin_attribute: PibId::try_from(buf[1])?,
254 })
255 }
256}
257
258/// MLME START Confirm which is used to report the results of the attempt to
259/// start using a new superframe configuration
260#[cfg_attr(feature = "defmt", derive(defmt::Format))]
261pub struct StartConfirm {
262 /// Result of the attempt to start using an updated superframe configuration
263 pub status: MacStatus,
264}
265
266impl ParseableMacEvent for StartConfirm {
267 const SIZE: usize = 4;
268
269 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
270 Self::validate(buf)?;
271
272 Ok(Self {
273 status: MacStatus::try_from(buf[0])?,
274 })
275 }
276}
277
278/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data
279#[cfg_attr(feature = "defmt", derive(defmt::Format))]
280pub struct PollConfirm {
281 /// The status of the data request
282 pub status: MacStatus,
283}
284
285impl ParseableMacEvent for PollConfirm {
286 const SIZE: usize = 4;
287
288 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
289 Self::validate(buf)?;
290
291 Ok(Self {
292 status: MacStatus::try_from(buf[0])?,
293 })
294 }
295}
296
297/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS
298#[cfg_attr(feature = "defmt", derive(defmt::Format))]
299pub struct DpsConfirm {
300 /// The status of the DPS request
301 pub status: MacStatus,
302}
303
304impl ParseableMacEvent for DpsConfirm {
305 const SIZE: usize = 4;
306
307 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
308 Self::validate(buf)?;
309
310 Ok(Self {
311 status: MacStatus::try_from(buf[0])?,
312 })
313 }
314}
315
316/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide
317/// channel sounding information
318#[cfg_attr(feature = "defmt", derive(defmt::Format))]
319pub struct SoundingConfirm {
320 /// Results of the sounding measurement
321 sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
322}
323
324impl ParseableMacEvent for SoundingConfirm {
325 const SIZE: usize = 1;
326
327 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
328 Self::validate(buf)?;
329
330 let mut sounding_list = [0u8; MAX_SOUNDING_LIST_SUPPORTED];
331 sounding_list[..buf.len()].copy_from_slice(buf);
332
333 Ok(Self { sounding_list })
334 }
335}
336
337/// MLME CALIBRATE Confirm which reports the result of a request to the PHY
338/// to provide internal propagation path information
339#[cfg_attr(feature = "defmt", derive(defmt::Format))]
340pub struct CalibrateConfirm {
341 /// The status of the attempt to return sounding data
342 pub status: MacStatus,
343 /// A count of the propagation time from the ranging counter
344 /// to the transmit antenna
345 pub cal_tx_rmaker_offset: u32,
346 /// A count of the propagation time from the receive antenna
347 /// to the ranging counter
348 pub cal_rx_rmaker_offset: u32,
349}
350
351impl ParseableMacEvent for CalibrateConfirm {
352 const SIZE: usize = 12;
353
354 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
355 Self::validate(buf)?;
356
357 Ok(Self {
358 status: MacStatus::try_from(buf[0])?,
359 // 3 byte stuffing
360 cal_tx_rmaker_offset: to_u32(&buf[4..8]),
361 cal_rx_rmaker_offset: to_u32(&buf[8..12]),
362 })
363 }
364}
365
366/// MCPS DATA Confirm which will be used for reporting the results of
367/// MAC data related requests from the application
368#[cfg_attr(feature = "defmt", derive(defmt::Format))]
369pub struct DataConfirm {
370 /// The handle associated with the MSDU being confirmed
371 pub msdu_handle: u8,
372 /// The time, in symbols, at which the data were transmitted
373 pub time_stamp: [u8; 4],
374 /// ranging status
375 pub ranging_received: u8,
376 /// The status of the last MSDU transmission
377 pub status: MacStatus,
378 /// time units corresponding to an RMARKER at the antenna at
379 /// the beginning of a ranging exchange
380 pub ranging_counter_start: u32,
381 /// time units corresponding to an RMARKER at the antenna
382 /// at the end of a ranging exchange
383 pub ranging_counter_stop: u32,
384 /// time units in a message exchange over which the tracking offset was measured
385 pub ranging_tracking_interval: u32,
386 /// time units slipped or advanced by the radio tracking system
387 pub ranging_offset: u32,
388 /// The FoM characterizing the ranging measurement
389 pub ranging_fom: u8,
390}
391
392impl ParseableMacEvent for DataConfirm {
393 const SIZE: usize = 28;
394
395 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
396 Self::validate(buf)?;
397
398 Ok(Self {
399 msdu_handle: buf[0],
400 time_stamp: [buf[1], buf[2], buf[3], buf[4]],
401 ranging_received: buf[5],
402 status: MacStatus::try_from(buf[6])?,
403 ranging_counter_start: to_u32(&buf[7..11]),
404 ranging_counter_stop: to_u32(&buf[11..15]),
405 ranging_tracking_interval: to_u32(&buf[15..19]),
406 ranging_offset: to_u32(&buf[19..23]),
407 ranging_fom: buf[24],
408 })
409 }
410}
411
412/// MCPS PURGE Confirm which will be used by the MAC to notify the application of
413/// the status of its request to purge an MSDU from the transaction queue
414#[cfg_attr(feature = "defmt", derive(defmt::Format))]
415pub struct PurgeConfirm {
416 /// Handle associated with the MSDU requested to be purged from the transaction queue
417 pub msdu_handle: u8,
418 /// The status of the request
419 pub status: MacStatus,
420}
421
422impl ParseableMacEvent for PurgeConfirm {
423 const SIZE: usize = 4;
424
425 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
426 Self::validate(buf)?;
427
428 Ok(Self {
429 msdu_handle: buf[0],
430 status: MacStatus::try_from(buf[1])?,
431 })
432 }
433}
diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs
new file mode 100644
index 000000000..30c7731b2
--- /dev/null
+++ b/embassy-stm32-wpan/src/mac/typedefs.rs
@@ -0,0 +1,363 @@
1use crate::numeric_enum;
2
3#[derive(Debug)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum MacError {
6 Error = 0x01,
7 NotImplemented = 0x02,
8 NotSupported = 0x03,
9 HardwareNotSupported = 0x04,
10 Undefined = 0x05,
11}
12
13impl From<u8> for MacError {
14 fn from(value: u8) -> Self {
15 match value {
16 0x01 => Self::Error,
17 0x02 => Self::NotImplemented,
18 0x03 => Self::NotSupported,
19 0x04 => Self::HardwareNotSupported,
20 0x05 => Self::Undefined,
21 _ => Self::Undefined,
22 }
23 }
24}
25
26numeric_enum! {
27 #[repr(u8)]
28 #[derive(Debug, Default)]
29 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
30 pub enum MacStatus {
31 #[default]
32 Success = 0x00,
33 Failure = 0xFF
34 }
35}
36
37numeric_enum! {
38 #[repr(u8)]
39 /// this enum contains all the MAC PIB Ids
40 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
41 pub enum PibId {
42 // PHY
43 CurrentChannel = 0x00,
44 ChannelsSupported = 0x01,
45 TransmitPower = 0x02,
46 CCAMode = 0x03,
47 CurrentPage = 0x04,
48 MaxFrameDuration = 0x05,
49 SHRDuration = 0x06,
50 SymbolsPerOctet = 0x07,
51
52 // MAC
53 AckWaitDuration = 0x40,
54 AssociationPermit = 0x41,
55 AutoRequest = 0x42,
56 BeaconPayload = 0x45,
57 BeaconPayloadLength = 0x46,
58 BeaconOrder = 0x47,
59 Bsn = 0x49,
60 CoordExtendedAdddress = 0x4A,
61 CoordShortAddress = 0x4B,
62 Dsn = 0x4C,
63 MaxFrameTotalWaitTime = 0x58,
64 MaxFrameRetries = 0x59,
65 PanId = 0x50,
66 ResponseWaitTime = 0x5A,
67 RxOnWhenIdle = 0x52,
68 SecurityEnabled = 0x5D,
69 ShortAddress = 0x53,
70 SuperframeOrder = 0x54,
71 TimestampSupported = 0x5C,
72 TransactionPersistenceTime = 0x55,
73 MaxBe = 0x57,
74 LifsPeriod = 0x5E,
75 SifsPeriod = 0x5F,
76 MaxCsmaBackoffs = 0x4E,
77 MinBe = 0x4F,
78 PanCoordinator = 0x10,
79 AssocPanCoordinator = 0x11,
80 ExtendedAddress = 0x6F,
81 AclEntryDescriptor = 0x70,
82 AclEntryDescriptorSize = 0x71,
83 DefaultSecurity = 0x72,
84 DefaultSecurityMaterialLength = 0x73,
85 DefaultSecurityMaterial = 0x74,
86 DefaultSecuritySuite = 0x75,
87 SecurityMode = 0x76,
88 CurrentAclEntries = 0x80,
89 DefaultSecurityExtendedAddress = 0x81,
90 AssociatedPanCoordinator = 0x56,
91 PromiscuousMode = 0x51,
92 }
93}
94
95numeric_enum! {
96 #[repr(u8)]
97 #[derive(Default, Clone, Copy)]
98 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
99 pub enum AddressMode {
100 #[default]
101 NoAddress = 0x00,
102 Reserved = 0x01,
103 Short = 0x02,
104 Extended = 0x03,
105}
106}
107
108#[derive(Clone, Copy)]
109pub union MacAddress {
110 pub short: [u8; 2],
111 pub extended: [u8; 8],
112}
113
114#[cfg(feature = "defmt")]
115impl defmt::Format for MacAddress {
116 fn format(&self, fmt: defmt::Formatter) {
117 unsafe {
118 defmt::write!(
119 fmt,
120 "MacAddress {{ short: {}, extended: {} }}",
121 self.short,
122 self.extended
123 )
124 }
125 }
126}
127
128impl Default for MacAddress {
129 fn default() -> Self {
130 Self { short: [0, 0] }
131 }
132}
133
134impl MacAddress {
135 pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] };
136}
137
138impl TryFrom<&[u8]> for MacAddress {
139 type Error = ();
140
141 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
142 const SIZE: usize = 8;
143 if buf.len() < SIZE {
144 return Err(());
145 }
146
147 Ok(Self {
148 extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
149 })
150 }
151}
152
153#[cfg_attr(feature = "defmt", derive(defmt::Format))]
154pub struct GtsCharacteristics {
155 pub fields: u8,
156}
157
158/// MAC PAN Descriptor which contains the network details of the device from
159/// which the beacon is received
160#[derive(Default, Clone, Copy)]
161#[cfg_attr(feature = "defmt", derive(defmt::Format))]
162pub struct PanDescriptor {
163 /// PAN identifier of the coordinator
164 pub coord_pan_id: PanId,
165 /// Coordinator addressing mode
166 pub coord_addr_mode: AddressMode,
167 /// The current logical channel occupied by the network
168 pub logical_channel: MacChannel,
169 /// Coordinator address
170 pub coord_addr: MacAddress,
171 /// The current channel page occupied by the network
172 pub channel_page: u8,
173 /// PAN coordinator is accepting GTS requests or not
174 pub gts_permit: bool,
175 /// Superframe specification as specified in the received beacon frame
176 pub superframe_spec: [u8; 2],
177 /// The time at which the beacon frame was received, in symbols
178 pub time_stamp: [u8; 4],
179 /// The LQI at which the network beacon was received
180 pub link_quality: u8,
181 /// Security level purportedly used by the received beacon frame
182 pub security_level: u8,
183}
184
185impl TryFrom<&[u8]> for PanDescriptor {
186 type Error = ();
187
188 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
189 const SIZE: usize = 22;
190 if buf.len() < SIZE {
191 return Err(());
192 }
193
194 let coord_addr_mode = AddressMode::try_from(buf[2])?;
195 let coord_addr = match coord_addr_mode {
196 AddressMode::NoAddress => MacAddress { short: [0, 0] },
197 AddressMode::Reserved => MacAddress { short: [0, 0] },
198 AddressMode::Short => MacAddress {
199 short: [buf[4], buf[5]],
200 },
201 AddressMode::Extended => MacAddress {
202 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
203 },
204 };
205
206 Ok(Self {
207 coord_pan_id: PanId([buf[0], buf[1]]),
208 coord_addr_mode,
209 logical_channel: MacChannel::try_from(buf[3])?,
210 coord_addr,
211 channel_page: buf[12],
212 gts_permit: buf[13] != 0,
213 superframe_spec: [buf[14], buf[15]],
214 time_stamp: [buf[16], buf[17], buf[18], buf[19]],
215 link_quality: buf[20],
216 security_level: buf[21],
217 // 2 byte stuffing
218 })
219 }
220}
221
222numeric_enum! {
223 #[repr(u8)]
224 #[derive(Default, Clone, Copy)]
225 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
226 /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3
227 pub enum MacChannel {
228 Channel11 = 0x0B,
229 Channel12 = 0x0C,
230 Channel13 = 0x0D,
231 Channel14 = 0x0E,
232 Channel15 = 0x0F,
233 #[default]
234 Channel16 = 0x10,
235 Channel17 = 0x11,
236 Channel18 = 0x12,
237 Channel19 = 0x13,
238 Channel20 = 0x14,
239 Channel21 = 0x15,
240 Channel22 = 0x16,
241 Channel23 = 0x17,
242 Channel24 = 0x18,
243 Channel25 = 0x19,
244 Channel26 = 0x1A,
245 }
246}
247
248#[cfg(not(feature = "defmt"))]
249bitflags::bitflags! {
250 pub struct Capabilities: u8 {
251 /// 1 if the device is capabaleof becoming a PAN coordinator
252 const IS_COORDINATOR_CAPABLE = 0b00000001;
253 /// 1 if the device is an FFD, 0 if it is an RFD
254 const IS_FFD = 0b00000010;
255 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
256 const IS_MAINS_POWERED = 0b00000100;
257 /// 1 if the device does not disable its receiver to conserver power during idle periods
258 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
259 // 0b00010000 reserved
260 // 0b00100000 reserved
261 /// 1 if the device is capable of sending and receiving secured MAC frames
262 const IS_SECURE = 0b01000000;
263 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
264 const ALLOCATE_ADDRESS = 0b10000000;
265 }
266}
267
268#[cfg(feature = "defmt")]
269defmt::bitflags! {
270 pub struct Capabilities: u8 {
271 /// 1 if the device is capabaleof becoming a PAN coordinator
272 const IS_COORDINATOR_CAPABLE = 0b00000001;
273 /// 1 if the device is an FFD, 0 if it is an RFD
274 const IS_FFD = 0b00000010;
275 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
276 const IS_MAINS_POWERED = 0b00000100;
277 /// 1 if the device does not disable its receiver to conserver power during idle periods
278 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
279 // 0b00010000 reserved
280 // 0b00100000 reserved
281 /// 1 if the device is capable of sending and receiving secured MAC frames
282 const IS_SECURE = 0b01000000;
283 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
284 const ALLOCATE_ADDRESS = 0b10000000;
285 }
286}
287
288numeric_enum! {
289 #[repr(u8)]
290 #[derive(Default, Clone, Copy)]
291 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
292 pub enum KeyIdMode {
293 #[default]
294 /// the key is determined implicitly from the originator and recipient(s) of the frame
295 Implicite = 0x00,
296 /// the key is determined explicitly using a 1 bytes key source and a 1 byte key index
297 Explicite1Byte = 0x01,
298 /// the key is determined explicitly using a 4 bytes key source and a 1 byte key index
299 Explicite4Byte = 0x02,
300 /// the key is determined explicitly using a 8 bytes key source and a 1 byte key index
301 Explicite8Byte = 0x03,
302 }
303}
304
305numeric_enum! {
306 #[repr(u8)]
307 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
308 pub enum AssociationStatus {
309 /// Association successful
310 Success = 0x00,
311 /// PAN at capacity
312 PanAtCapacity = 0x01,
313 /// PAN access denied
314 PanAccessDenied = 0x02
315 }
316}
317
318numeric_enum! {
319 #[repr(u8)]
320 #[derive(Clone, Copy)]
321 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
322 pub enum DisassociationReason {
323 /// The coordinator wishes the device to leave the PAN.
324 CoordRequested = 0x01,
325 /// The device wishes to leave the PAN.
326 DeviceRequested = 0x02,
327 }
328}
329
330numeric_enum! {
331 #[repr(u8)]
332 #[derive(Default, Clone, Copy)]
333 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
334 pub enum SecurityLevel {
335 /// MAC Unsecured Mode Security
336 #[default]
337 Unsecure = 0x00,
338 /// MAC ACL Mode Security
339 AclMode = 0x01,
340 /// MAC Secured Mode Security
341 Secured = 0x02,
342 }
343}
344
345numeric_enum! {
346 #[repr(u8)]
347 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
348 pub enum ScanType {
349 EdScan = 0x00,
350 Active = 0x01,
351 Passive = 0x02,
352 Orphan = 0x03
353 }
354}
355
356/// newtype for Pan Id
357#[derive(Default, Clone, Copy)]
358#[cfg_attr(feature = "defmt", derive(defmt::Format))]
359pub struct PanId(pub [u8; 2]);
360
361impl PanId {
362 pub const BROADCAST: Self = Self([0xFF, 0xFF]);
363}
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
index fd8af8609..4893cb47b 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,19 +69,46 @@ 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 mut payload = [0u8; MAX_PACKET_SIZE];
89 cmd.copy_into_slice(&mut payload);
90
91 let response = self
92 .tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE])
93 .await;
94
95 if response == 0x00 {
96 Ok(())
97 } else {
98 Err(MacError::from(response))
99 }
100 }
101
102 pub async fn read(&self) -> Result<MacEvent, ()> {
103 let evt_box = self.tl_read().await;
104 let payload = evt_box.payload();
105
106 MacEvent::try_from(payload)
107 }
90} 108}
91 109
110const MAX_PACKET_SIZE: usize = 255;
111
92impl evt::MemoryManager for Mac { 112impl evt::MemoryManager for Mac {
93 /// SAFETY: passing a pointer to something other than a managed event packet is UB 113 /// SAFETY: passing a pointer to something other than a managed event packet is UB
94 unsafe fn drop_event_packet(_: *mut EvtPacket) { 114 unsafe fn drop_event_packet(_: *mut EvtPacket) {
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..ec934e8be 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 }
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index fa66da1f6..995ad1443 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/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/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 1dc13949d..31a2d8863 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -264,7 +264,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
264 }); 264 });
265 265
266 let tx_request = self.dma.request(); 266 let tx_request = self.dma.request();
267 let dma_channel = &self.dma; 267 let dma_channel = &mut self.dma;
268 268
269 let tx_options = crate::dma::TransferOptions { 269 let tx_options = crate::dma::TransferOptions {
270 circular, 270 circular,
@@ -376,7 +376,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
376 }); 376 });
377 377
378 let tx_request = self.dma.request(); 378 let tx_request = self.dma.request();
379 let dma_channel = &self.dma; 379 let dma_channel = &mut self.dma;
380 380
381 let tx_options = crate::dma::TransferOptions { 381 let tx_options = crate::dma::TransferOptions {
382 circular, 382 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..90631b175 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,48 @@ 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}
49
50impl GenericSMI {
51 #[cfg(feature = "time")]
52 pub fn new() -> Self {
53 Self {
54 poll_interval: Duration::from_millis(500),
55 }
56 }
57
58 #[cfg(not(feature = "time"))]
59 pub fn new() -> Self {
60 Self {}
61 }
62}
40 63
41unsafe impl PHY for GenericSMI { 64unsafe impl PHY for GenericSMI {
42 /// Reset PHY and wait for it to come out of reset. 65 /// Reset PHY and wait for it to come out of reset.
43 fn phy_reset<S: StationManagement>(sm: &mut S) { 66 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
44 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); 67 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 {} 68 while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
46 } 69 }
47 70
48 /// PHY initialisation. 71 /// PHY initialisation.
49 fn phy_init<S: StationManagement>(sm: &mut S) { 72 fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
50 // Clear WU CSR 73 // Clear WU CSR
51 Self::smi_write_ext(sm, PHY_REG_WUCSR, 0); 74 self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
52 75
53 // Enable auto-negotiation 76 // Enable auto-negotiation
54 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M); 77 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
55 } 78 }
56 79
57 fn poll_link<S: StationManagement>(sm: &mut S) -> bool { 80 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
81 #[cfg(not(feature = "time"))]
82 cx.waker().wake_by_ref();
83
84 #[cfg(feature = "time")]
85 let _ = Timer::after(self.poll_interval).poll_unpin(cx);
86
58 let bsr = sm.smi_read(PHY_REG_BSR); 87 let bsr = sm.smi_read(PHY_REG_BSR);
59 88
60 // No link without autonegotiate 89 // No link without autonegotiate
@@ -73,8 +102,12 @@ unsafe impl PHY for GenericSMI {
73 102
74/// Public functions for the PHY 103/// Public functions for the PHY
75impl GenericSMI { 104impl GenericSMI {
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/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/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-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..7b9c371bb 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 }
@@ -52,4 +52,7 @@ rand = { version = "0.8.4", default-features = false }
52embedded-storage = "0.3.0" 52embedded-storage = "0.3.0"
53usbd-hid = "0.6.0" 53usbd-hid = "0.6.0"
54serde = { version = "1.0.136", default-features = false } 54serde = { version = "1.0.136", default-features = false }
55embedded-hal-async = { version = "0.2.0-alpha.1", optional = true } 55embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
56
57[patch.crates-io]
58lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
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..becf2d3fb 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/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", "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"] }
13 13
@@ -23,7 +23,7 @@ heapless = { version = "0.7.5", default-features = false }
23 23
24 24
25[features] 25[features]
26default = ["ble"] 26default = ["ble", "mac"]
27mac = ["embassy-stm32-wpan/mac"] 27mac = ["embassy-stm32-wpan/mac"]
28ble = ["embassy-stm32-wpan/ble"] 28ble = ["embassy-stm32-wpan/ble"]
29 29
@@ -36,8 +36,13 @@ name = "tl_mbox_mac"
36required-features = ["mac"] 36required-features = ["mac"]
37 37
38[[bin]] 38[[bin]]
39name = "mac_ffd"
40required-features = ["mac"]
41
42[[bin]]
39name = "eddystone_beacon" 43name = "eddystone_beacon"
40required-features = ["ble"] 44required-features = ["ble"]
41 45
42[patch.crates-io] 46[[bin]]
43stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"} \ No newline at end of file 47name = "gatt_server"
48required-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..e4d81997e
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -0,0 +1,183 @@
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 { set_default_pib: true })
71 .await
72 .unwrap();
73 let evt = mbox.mac_subsystem.read().await;
74 defmt::info!("{:#x}", evt);
75
76 info!("setting extended address");
77 let extended_address: u64 = 0xACDE480000000001;
78 mbox.mac_subsystem
79 .send_command(&SetRequest {
80 pib_attribute_ptr: &extended_address as *const _ as *const u8,
81 pib_attribute: PibId::ExtendedAddress,
82 })
83 .await
84 .unwrap();
85 let evt = mbox.mac_subsystem.read().await;
86 defmt::info!("{:#x}", evt);
87
88 info!("setting short address");
89 let short_address: u16 = 0x1122;
90 mbox.mac_subsystem
91 .send_command(&SetRequest {
92 pib_attribute_ptr: &short_address as *const _ as *const u8,
93 pib_attribute: PibId::ShortAddress,
94 })
95 .await
96 .unwrap();
97 let evt = mbox.mac_subsystem.read().await;
98 defmt::info!("{:#x}", evt);
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 let evt = mbox.mac_subsystem.read().await;
110 defmt::info!("{:#x}", evt);
111
112 info!("setting TX power");
113 let transmit_power: i8 = 2;
114 mbox.mac_subsystem
115 .send_command(&SetRequest {
116 pib_attribute_ptr: &transmit_power as *const _ as *const u8,
117 pib_attribute: PibId::TransmitPower,
118 })
119 .await
120 .unwrap();
121 let evt = mbox.mac_subsystem.read().await;
122 defmt::info!("{:#x}", evt);
123
124 info!("starting FFD device");
125 mbox.mac_subsystem
126 .send_command(&StartRequest {
127 pan_id: PanId([0x1A, 0xAA]),
128 channel_number: MacChannel::Channel16,
129 beacon_order: 0x0F,
130 superframe_order: 0x0F,
131 pan_coordinator: true,
132 battery_life_extension: false,
133 ..Default::default()
134 })
135 .await
136 .unwrap();
137 let evt = mbox.mac_subsystem.read().await;
138 defmt::info!("{:#x}", evt);
139
140 info!("setting RX on when idle");
141 let rx_on_while_idle: bool = true;
142 mbox.mac_subsystem
143 .send_command(&SetRequest {
144 pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
145 pib_attribute: PibId::RxOnWhenIdle,
146 })
147 .await
148 .unwrap();
149 let evt = mbox.mac_subsystem.read().await;
150 defmt::info!("{:#x}", evt);
151
152 loop {
153 let evt = mbox.mac_subsystem.read().await;
154 defmt::info!("{:#x}", evt);
155
156 if let Ok(evt) = evt {
157 match evt {
158 MacEvent::MlmeAssociateInd(association) => mbox
159 .mac_subsystem
160 .send_command(&AssociateResponse {
161 device_address: association.device_address,
162 assoc_short_address: [0x33, 0x44],
163 status: MacStatus::Success,
164 security_level: SecurityLevel::Unsecure,
165 ..Default::default()
166 })
167 .await
168 .unwrap(),
169 MacEvent::McpsDataInd(data_ind) => {
170 let data_addr = data_ind.msdu_ptr;
171 let mut data = [0u8; 256];
172 unsafe { data_addr.copy_to(&mut data as *mut _, data_ind.msdu_length as usize) }
173 info!("{}", data[..data_ind.msdu_length as usize]);
174
175 if &data[..data_ind.msdu_length as usize] == b"Hello from embassy!" {
176 info!("success");
177 }
178 }
179 _ => {}
180 }
181 }
182 }
183}
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
new file mode 100644
index 000000000..b2dac72cc
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_rfd.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::{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 { set_default_pib: true })
73 .await
74 .unwrap();
75 let evt = mbox.mac_subsystem.read().await;
76 info!("{:#x}", evt);
77
78 info!("setting extended address");
79 let extended_address: u64 = 0xACDE480000000002;
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 let evt = mbox.mac_subsystem.read().await;
88 info!("{:#x}", evt);
89
90 info!("getting extended address");
91 mbox.mac_subsystem
92 .send_command(&GetRequest {
93 pib_attribute: PibId::ExtendedAddress,
94 })
95 .await
96 .unwrap();
97 let evt = mbox.mac_subsystem.read().await;
98 info!("{:#x}", evt);
99
100 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
101 if evt.pib_attribute_value_len == 8 {
102 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
103
104 info!("value {:#x}", value)
105 }
106 }
107
108 info!("assocation request");
109 let a = AssociateRequest {
110 channel_number: MacChannel::Channel16,
111 channel_page: 0,
112 coord_addr_mode: AddressMode::Short,
113 coord_address: MacAddress { short: [34, 17] },
114 capability_information: Capabilities::ALLOCATE_ADDRESS,
115 coord_pan_id: PanId([0x1A, 0xAA]),
116 security_level: SecurityLevel::Unsecure,
117 key_id_mode: KeyIdMode::Implicite,
118 key_source: [0; 8],
119 key_index: 152,
120 };
121 info!("{}", a);
122 mbox.mac_subsystem.send_command(&a).await.unwrap();
123 let evt = mbox.mac_subsystem.read().await;
124 info!("{:#x}", evt);
125
126 let short_addr = if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt {
127 conf.assoc_short_address
128 } else {
129 defmt::panic!()
130 };
131
132 info!("setting short address");
133 mbox.mac_subsystem
134 .send_command(&SetRequest {
135 pib_attribute_ptr: &short_addr as *const _ as *const u8,
136 pib_attribute: PibId::ShortAddress,
137 })
138 .await
139 .unwrap();
140 let evt = mbox.mac_subsystem.read().await;
141 info!("{:#x}", evt);
142
143 info!("sending data");
144 let mut data_buffer = [0u8; 256];
145 let data = b"Hello from embassy!";
146 data_buffer[..data.len()].copy_from_slice(data);
147 mbox.mac_subsystem
148 .send_command(&DataRequest {
149 src_addr_mode: AddressMode::Short,
150 dst_addr_mode: AddressMode::Short,
151 dst_pan_id: PanId([0x1A, 0xAA]),
152 dst_address: MacAddress::BROADCAST,
153 msdu_handle: 0x02,
154 ack_tx: 0x00,
155 gts_tx: false,
156 msdu_ptr: &data_buffer as *const _ as *const u8,
157 msdu_length: data.len() as u8,
158 security_level: SecurityLevel::Unsecure,
159 ..Default::default()
160 })
161 .await
162 .unwrap();
163 let evt = mbox.mac_subsystem.read().await;
164 info!("{:#x}", evt);
165
166 loop {
167 let evt = mbox.mac_subsystem.read().await;
168 info!("{:#x}", evt);
169 }
170}
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..cfa0aca3b
--- /dev/null
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -0,0 +1,108 @@
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 { set_default_pib: true })
53 .await
54 .unwrap();
55 let evt = mbox.mac_subsystem.read().await;
56 info!("{:#x}", evt);
57
58 info!("setting extended address");
59 let extended_address: u64 = 0xACDE480000000002;
60 mbox.mac_subsystem
61 .send_command(&SetRequest {
62 pib_attribute_ptr: &extended_address as *const _ as *const u8,
63 pib_attribute: PibId::ExtendedAddress,
64 })
65 .await
66 .unwrap();
67 let evt = mbox.mac_subsystem.read().await;
68 info!("{:#x}", evt);
69
70 info!("getting extended address");
71 mbox.mac_subsystem
72 .send_command(&GetRequest {
73 pib_attribute: PibId::ExtendedAddress,
74 })
75 .await
76 .unwrap();
77 let evt = mbox.mac_subsystem.read().await;
78 info!("{:#x}", evt);
79
80 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
81 if evt.pib_attribute_value_len == 8 {
82 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
83
84 info!("value {:#x}", value)
85 }
86 }
87
88 info!("assocation request");
89 let a = AssociateRequest {
90 channel_number: MacChannel::Channel16,
91 channel_page: 0,
92 coord_addr_mode: AddressMode::Short,
93 coord_address: MacAddress { short: [34, 17] },
94 capability_information: Capabilities::ALLOCATE_ADDRESS,
95 coord_pan_id: PanId([0x1A, 0xAA]),
96 security_level: SecurityLevel::Unsecure,
97 key_id_mode: KeyIdMode::Implicite,
98 key_source: [0; 8],
99 key_index: 152,
100 };
101 info!("{}", a);
102 mbox.mac_subsystem.send_command(&a).await.unwrap();
103 let evt = mbox.mac_subsystem.read().await;
104 info!("{:#x}", evt);
105
106 info!("Test OK");
107 cortex_m::asm::bkpt();
108}