aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/bors.toml4
-rwxr-xr-x.github/ci/build-stable.sh4
-rwxr-xr-x.github/ci/build.sh5
-rwxr-xr-x.github/ci/doc.sh3
-rwxr-xr-x.github/ci/test.sh6
-rwxr-xr-xci.sh27
-rw-r--r--cyw43/Cargo.toml6
-rw-r--r--cyw43/src/consts.rs1
-rw-r--r--cyw43/src/control.rs21
-rw-r--r--cyw43/src/fmt.rs18
-rw-r--r--cyw43/src/lib.rs2
-rw-r--r--docs/modules/ROOT/nav.adoc2
-rw-r--r--docs/modules/ROOT/pages/developer.adoc1
-rw-r--r--docs/modules/ROOT/pages/developer_stm32.adoc79
-rw-r--r--docs/modules/ROOT/pages/index.adoc9
-rw-r--r--embassy-boot/boot/Cargo.toml2
-rw-r--r--embassy-boot/boot/src/fmt.rs45
-rw-r--r--embassy-boot/nrf/src/fmt.rs45
-rw-r--r--embassy-boot/rp/src/fmt.rs45
-rw-r--r--embassy-boot/stm32/src/fmt.rs45
-rw-r--r--embassy-embedded-hal/Cargo.toml4
-rw-r--r--embassy-executor/CHANGELOG.md3
-rw-r--r--embassy-executor/Cargo.toml4
-rw-r--r--embassy-executor/src/arch/cortex_m.rs5
-rw-r--r--embassy-executor/src/arch/wasm.rs5
-rw-r--r--embassy-executor/src/fmt.rs45
-rw-r--r--embassy-executor/src/raw/mod.rs2
-rw-r--r--embassy-executor/src/raw/util.rs5
-rw-r--r--embassy-futures/src/fmt.rs45
-rw-r--r--embassy-hal-internal/src/fmt.rs45
-rw-r--r--embassy-lora/Cargo.toml11
-rw-r--r--embassy-lora/src/fmt.rs45
-rw-r--r--embassy-lora/src/iv.rs20
-rw-r--r--embassy-macros/Cargo.toml2
-rw-r--r--embassy-net-adin1110/Cargo.toml42
-rw-r--r--embassy-net-adin1110/README.md88
-rw-r--r--embassy-net-adin1110/src/crc32.rs359
-rw-r--r--embassy-net-adin1110/src/crc8.rs53
-rw-r--r--embassy-net-adin1110/src/fmt.rs254
-rw-r--r--embassy-net-adin1110/src/lib.rs1323
-rw-r--r--embassy-net-adin1110/src/mdio.rs176
-rw-r--r--embassy-net-adin1110/src/phy.rs143
-rw-r--r--embassy-net-adin1110/src/regs.rs416
-rw-r--r--embassy-net-driver-channel/Cargo.toml2
-rw-r--r--embassy-net-driver-channel/src/fmt.rs45
-rw-r--r--embassy-net-driver-channel/src/lib.rs254
-rw-r--r--embassy-net-enc28j60/Cargo.toml4
-rw-r--r--embassy-net-enc28j60/src/fmt.rs45
-rw-r--r--embassy-net-enc28j60/src/lib.rs14
-rw-r--r--embassy-net-esp-hosted/Cargo.toml6
-rw-r--r--embassy-net-esp-hosted/src/control.rs85
-rw-r--r--embassy-net-esp-hosted/src/fmt.rs5
-rw-r--r--embassy-net-ppp/Cargo.toml28
-rw-r--r--embassy-net-ppp/README.md19
-rw-r--r--embassy-net-ppp/src/fmt.rs258
-rw-r--r--embassy-net-ppp/src/lib.rs185
-rw-r--r--embassy-net-wiznet/Cargo.toml4
-rw-r--r--embassy-net/Cargo.toml5
-rw-r--r--embassy-net/src/device.rs4
-rw-r--r--embassy-net/src/fmt.rs45
-rw-r--r--embassy-net/src/lib.rs385
-rw-r--r--embassy-net/src/tcp.rs4
-rw-r--r--embassy-net/src/udp.rs11
-rw-r--r--embassy-nrf/Cargo.toml9
-rw-r--r--embassy-nrf/src/fmt.rs45
-rw-r--r--embassy-nrf/src/gpiote.rs1
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/spim.rs130
-rw-r--r--embassy-nrf/src/spis.rs45
-rw-r--r--embassy-nrf/src/temp.rs1
-rw-r--r--embassy-nrf/src/twim.rs9
-rw-r--r--embassy-rp/Cargo.toml5
-rw-r--r--embassy-rp/src/clocks.rs8
-rw-r--r--embassy-rp/src/fmt.rs45
-rw-r--r--embassy-rp/src/i2c.rs9
-rw-r--r--embassy-rp/src/i2c_slave.rs338
-rw-r--r--embassy-rp/src/lib.rs4
-rw-r--r--embassy-rp/src/pio.rs41
-rw-r--r--embassy-stm32-wpan/Cargo.toml4
-rw-r--r--embassy-stm32-wpan/src/fmt.rs45
-rw-r--r--embassy-stm32-wpan/src/sub/ble.rs5
-rw-r--r--embassy-stm32-wpan/src/sub/mac.rs5
-rw-r--r--embassy-stm32-wpan/src/sub/mm.rs5
-rw-r--r--embassy-stm32-wpan/src/sub/sys.rs5
-rw-r--r--embassy-stm32/Cargo.toml21
-rw-r--r--embassy-stm32/build.rs96
-rw-r--r--embassy-stm32/src/adc/f1.rs53
-rw-r--r--embassy-stm32/src/adc/f3.rs195
-rw-r--r--embassy-stm32/src/adc/mod.rs113
-rw-r--r--embassy-stm32/src/adc/resolution.rs8
-rw-r--r--embassy-stm32/src/adc/sample_time.rs18
-rw-r--r--embassy-stm32/src/adc/v1.rs150
-rw-r--r--embassy-stm32/src/adc/v2.rs44
-rw-r--r--embassy-stm32/src/adc/v3.rs41
-rw-r--r--embassy-stm32/src/adc/v4.rs189
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs1
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs9
-rw-r--r--embassy-stm32/src/exti.rs14
-rw-r--r--embassy-stm32/src/fmt.rs45
-rw-r--r--embassy-stm32/src/gpio.rs3
-rw-r--r--embassy-stm32/src/hrtim/mod.rs36
-rw-r--r--embassy-stm32/src/hrtim/traits.rs175
-rw-r--r--embassy-stm32/src/i2c/v1.rs6
-rw-r--r--embassy-stm32/src/i2c/v2.rs6
-rw-r--r--embassy-stm32/src/lib.rs16
-rw-r--r--embassy-stm32/src/low_power.rs92
-rw-r--r--embassy-stm32/src/rcc/bd.rs176
-rw-r--r--embassy-stm32/src/rcc/bus.rs56
-rw-r--r--embassy-stm32/src/rcc/c0.rs27
-rw-r--r--embassy-stm32/src/rcc/common.rs174
-rw-r--r--embassy-stm32/src/rcc/f1.rs6
-rw-r--r--embassy-stm32/src/rcc/f2.rs51
-rw-r--r--embassy-stm32/src/rcc/f3.rs164
-rw-r--r--embassy-stm32/src/rcc/f4.rs25
-rw-r--r--embassy-stm32/src/rcc/f7.rs26
-rw-r--r--embassy-stm32/src/rcc/g0.rs8
-rw-r--r--embassy-stm32/src/rcc/g4.rs144
-rw-r--r--embassy-stm32/src/rcc/h.rs772
-rw-r--r--embassy-stm32/src/rcc/h5.rs511
-rw-r--r--embassy-stm32/src/rcc/h7.rs879
-rw-r--r--embassy-stm32/src/rcc/l0.rs61
-rw-r--r--embassy-stm32/src/rcc/l1.rs14
-rw-r--r--embassy-stm32/src/rcc/l4.rs67
-rw-r--r--embassy-stm32/src/rcc/l5.rs19
-rw-r--r--embassy-stm32/src/rcc/mco.rs71
-rw-r--r--embassy-stm32/src/rcc/mod.rs53
-rw-r--r--embassy-stm32/src/rcc/u5.rs80
-rw-r--r--embassy-stm32/src/rcc/wb.rs71
-rw-r--r--embassy-stm32/src/rcc/wba.rs154
-rw-r--r--embassy-stm32/src/rcc/wl.rs138
-rw-r--r--embassy-stm32/src/rng.rs46
-rw-r--r--embassy-stm32/src/rtc/datetime.rs2
-rw-r--r--embassy-stm32/src/rtc/mod.rs215
-rw-r--r--embassy-stm32/src/rtc/v2.rs281
-rw-r--r--embassy-stm32/src/rtc/v3.rs71
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs56
-rw-r--r--embassy-stm32/src/spi/mod.rs6
-rw-r--r--embassy-stm32/src/time_driver.rs134
-rw-r--r--embassy-stm32/src/timer/mod.rs262
-rw-r--r--embassy-stm32/src/timer/qei.rs96
-rw-r--r--embassy-stm32/src/usart/buffered.rs64
-rw-r--r--embassy-stm32/src/usart/mod.rs215
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs33
-rw-r--r--embassy-stm32/src/usb/usb.rs5
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs12
-rw-r--r--embassy-sync/CHANGELOG.md9
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/channel.rs2
-rw-r--r--embassy-sync/src/fmt.rs45
-rw-r--r--embassy-sync/src/lib.rs1
-rw-r--r--embassy-sync/src/mutex.rs2
-rw-r--r--embassy-sync/src/pipe.rs306
-rw-r--r--embassy-sync/src/ring_buffer.rs46
-rw-r--r--embassy-sync/src/zerocopy_channel.rs260
-rw-r--r--embassy-time/CHANGELOG.md11
-rw-r--r--embassy-time/Cargo.toml64
-rw-r--r--embassy-time/gen_tick.py4
-rw-r--r--embassy-time/src/fmt.rs45
-rw-r--r--embassy-time/src/instant.rs2
-rw-r--r--embassy-time/src/tick.rs186
-rw-r--r--embassy-time/src/timer.rs8
-rw-r--r--embassy-usb-logger/Cargo.toml2
-rw-r--r--embassy-usb/Cargo.toml2
-rw-r--r--embassy-usb/src/fmt.rs45
-rw-r--r--examples/boot/application/nrf/Cargo.toml4
-rw-r--r--examples/boot/application/rp/Cargo.toml5
-rw-r--r--examples/boot/application/rp/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml5
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml5
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml5
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml5
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml5
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml5
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml5
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml4
-rw-r--r--examples/nrf52840-rtic/Cargo.toml4
-rw-r--r--examples/nrf52840/Cargo.toml13
-rw-r--r--examples/nrf52840/src/bin/lora_cad.rs4
-rw-r--r--examples/nrf52840/src/bin/lora_lorawan.rs11
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_receive.rs6
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs8
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_send.rs6
-rw-r--r--examples/nrf5340/Cargo.toml4
-rw-r--r--examples/rp/Cargo.toml13
-rw-r--r--examples/rp/src/bin/i2c_slave.rs118
-rw-r--r--examples/rp/src/bin/lora_lorawan.rs17
-rw-r--r--examples/rp/src/bin/lora_p2p_receive.rs12
-rw-r--r--examples/rp/src/bin/lora_p2p_send.rs12
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs11
-rw-r--r--examples/rp/src/bin/pio_uart.rs10
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs7
-rw-r--r--examples/std/Cargo.toml8
-rw-r--r--examples/std/src/bin/net_ppp.rs218
-rw-r--r--examples/stm32c0/Cargo.toml4
-rw-r--r--examples/stm32f0/Cargo.toml4
-rw-r--r--examples/stm32f0/src/bin/adc.rs12
-rw-r--r--examples/stm32f1/Cargo.toml4
-rw-r--r--examples/stm32f1/src/bin/adc.rs10
-rw-r--r--examples/stm32f2/Cargo.toml4
-rw-r--r--examples/stm32f2/src/bin/pll.rs4
-rw-r--r--examples/stm32f3/Cargo.toml4
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32f334/Cargo.toml2
-rw-r--r--examples/stm32f334/src/bin/adc.rs56
-rw-r--r--examples/stm32f334/src/bin/pwm.rs2
-rw-r--r--examples/stm32f4/Cargo.toml4
-rw-r--r--examples/stm32f4/src/bin/adc.rs6
-rw-r--r--examples/stm32f4/src/bin/eth.rs8
-rw-r--r--examples/stm32f4/src/bin/rtc.rs18
-rw-r--r--examples/stm32f4/src/bin/usart.rs2
-rw-r--r--examples/stm32f4/src/bin/usart_buffered.rs2
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32f7/Cargo.toml4
-rw-r--r--examples/stm32f7/src/bin/adc.rs2
-rw-r--r--examples/stm32f7/src/bin/eth.rs8
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32g0/Cargo.toml4
-rw-r--r--examples/stm32g4/Cargo.toml6
-rw-r--r--examples/stm32g4/src/bin/adc.rs41
-rw-r--r--examples/stm32h5/Cargo.toml6
-rw-r--r--examples/stm32h5/src/bin/eth.rs13
-rw-r--r--examples/stm32h5/src/bin/usart.rs2
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs2
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs8
-rw-r--r--examples/stm32h7/Cargo.toml6
-rw-r--r--examples/stm32h7/src/bin/adc.rs34
-rw-r--r--examples/stm32h7/src/bin/camera.rs33
-rw-r--r--examples/stm32h7/src/bin/dac.rs32
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs33
-rw-r--r--examples/stm32h7/src/bin/eth.rs31
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs35
-rw-r--r--examples/stm32h7/src/bin/fmc.rs24
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs30
-rw-r--r--examples/stm32h7/src/bin/mco.rs4
-rw-r--r--examples/stm32h7/src/bin/pwm.rs29
-rw-r--r--examples/stm32h7/src/bin/rng.rs6
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs21
-rw-r--r--examples/stm32h7/src/bin/spi.rs23
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs23
-rw-r--r--examples/stm32h7/src/bin/usart.rs2
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs2
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs25
-rw-r--r--examples/stm32l0/Cargo.toml13
-rw-r--r--examples/stm32l0/src/bin/lora_cad.rs4
-rw-r--r--examples/stm32l0/src/bin/lora_lorawan.rs11
-rw-r--r--examples/stm32l0/src/bin/lora_p2p_receive.rs6
-rw-r--r--examples/stm32l0/src/bin/lora_p2p_send.rs6
-rw-r--r--examples/stm32l0/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs8
-rw-r--r--examples/stm32l1/Cargo.toml4
-rw-r--r--examples/stm32l4/.cargo/config.toml2
-rw-r--r--examples/stm32l4/Cargo.toml16
-rw-r--r--examples/stm32l4/src/bin/rtc.rs3
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs450
-rw-r--r--examples/stm32l4/src/bin/usart.rs2
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs2
-rw-r--r--examples/stm32l5/Cargo.toml4
-rw-r--r--examples/stm32u5/Cargo.toml4
-rw-r--r--examples/stm32wb/Cargo.toml6
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs4
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs4
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs4
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs4
-rw-r--r--examples/stm32wba/.cargo/config.toml8
-rw-r--r--examples/stm32wba/Cargo.toml26
-rw-r--r--examples/stm32wba/build.rs10
-rw-r--r--examples/stm32wba/src/bin/blinky.rs27
-rw-r--r--examples/stm32wba/src/bin/button_exti.rs27
-rw-r--r--examples/stm32wl/Cargo.toml13
-rw-r--r--examples/stm32wl/src/bin/lora_lorawan.rs13
-rw-r--r--examples/stm32wl/src/bin/lora_p2p_receive.rs6
-rw-r--r--examples/stm32wl/src/bin/lora_p2p_send.rs6
-rw-r--r--examples/stm32wl/src/bin/random.rs2
-rw-r--r--examples/stm32wl/src/bin/rtc.rs9
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs4
-rw-r--r--examples/wasm/Cargo.toml4
-rw-r--r--tests/nrf/.cargo/config.toml2
-rw-r--r--tests/nrf/Cargo.toml7
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs182
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs190
-rw-r--r--tests/perf-client/Cargo.toml12
-rw-r--r--tests/perf-client/src/lib.rs179
-rw-r--r--tests/riscv32/Cargo.toml4
-rw-r--r--tests/rp/.cargo/config.toml2
-rw-r--r--tests/rp/Cargo.toml5
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs189
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs182
-rw-r--r--tests/rp/src/bin/i2c.rs212
-rw-r--r--tests/stm32/.cargo/config.toml7
-rw-r--r--tests/stm32/Cargo.toml18
-rw-r--r--tests/stm32/build.rs3
-rw-r--r--tests/stm32/src/bin/gpio.rs20
-rw-r--r--tests/stm32/src/bin/rtc.rs7
-rw-r--r--tests/stm32/src/bin/spi.rs22
-rw-r--r--tests/stm32/src/bin/spi_dma.rs24
-rw-r--r--tests/stm32/src/bin/stop.rs71
-rw-r--r--tests/stm32/src/bin/usart.rs95
-rw-r--r--tests/stm32/src/bin/usart_dma.rs53
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs105
-rw-r--r--tests/stm32/src/common.rs205
304 files changed, 11841 insertions, 5101 deletions
diff --git a/.github/bors.toml b/.github/bors.toml
deleted file mode 100644
index 1ecc9d8de..000000000
--- a/.github/bors.toml
+++ /dev/null
@@ -1,4 +0,0 @@
1status = [
2 "all",
3]
4delete_merged_branches = true
diff --git a/.github/ci/build-stable.sh b/.github/ci/build-stable.sh
index 0dadd6102..8012f6923 100755
--- a/.github/ci/build-stable.sh
+++ b/.github/ci/build-stable.sh
@@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10 10
11# needed for "dumb HTTP" transport support
12# used when pointing stm32-metapac to a CI-built one.
13export CARGO_NET_GIT_FETCH_WITH_CLI=true
14
11hashtime restore /ci/cache/filetime.json || true 15hashtime restore /ci/cache/filetime.json || true
12hashtime save /ci/cache/filetime.json 16hashtime save /ci/cache/filetime.json
13 17
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index 30ca1e6f0..78ab976df 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -11,8 +11,13 @@ if [ -f /ci/secrets/teleprobe-token.txt ]; then
11 echo Got teleprobe token! 11 echo Got teleprobe token!
12 export TELEPROBE_HOST=https://teleprobe.embassy.dev 12 export TELEPROBE_HOST=https://teleprobe.embassy.dev
13 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) 13 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt)
14 export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json
14fi 15fi
15 16
17# needed for "dumb HTTP" transport support
18# used when pointing stm32-metapac to a CI-built one.
19export CARGO_NET_GIT_FETCH_WITH_CLI=true
20
16hashtime restore /ci/cache/filetime.json || true 21hashtime restore /ci/cache/filetime.json || true
17hashtime save /ci/cache/filetime.json 22hashtime save /ci/cache/filetime.json
18 23
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 57184dc1d..66caa9150 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -39,6 +39,7 @@ docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/g
39docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup 39docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup
40docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup 40docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
41docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static 41docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
42docserver-builder -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup
42 43
43export KUBECONFIG=/ci/secrets/kubeconfig.yml 44export KUBECONFIG=/ci/secrets/kubeconfig.yml
44POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 45POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
@@ -47,8 +48,8 @@ kubectl cp webroot/static $POD:/data
47 48
48# build and upload stm32 last 49# build and upload stm32 last
49# so that it doesn't prevent other crates from getting docs updates when it breaks. 50# so that it doesn't prevent other crates from getting docs updates when it breaks.
51
50rm -rf webroot 52rm -rf webroot
51docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup 53docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
52
53POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 54POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
54kubectl cp webroot/crates $POD:/data 55kubectl cp webroot/crates $POD:/data
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 2892bcf8d..af0f21c2a 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10 10
11# needed for "dumb HTTP" transport support
12# used when pointing stm32-metapac to a CI-built one.
13export CARGO_NET_GIT_FETCH_WITH_CLI=true
14
11hashtime restore /ci/cache/filetime.json || true 15hashtime restore /ci/cache/filetime.json || true
12hashtime save /ci/cache/filetime.json 16hashtime save /ci/cache/filetime.json
13 17
@@ -28,3 +32,5 @@ cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --featu
28cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti 32cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti
29cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti 33cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti
30cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f769ni,exti,time-driver-any,exti 34cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f769ni,exti,time-driver-any,exti
35
36cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml
diff --git a/ci.sh b/ci.sh
index e83b3b847..af98d6ed2 100755
--- a/ci.sh
+++ b/ci.sh
@@ -19,6 +19,19 @@ cargo batch \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ 19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ 20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
30 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
31 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
32 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
33 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
34 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
22 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 35 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
23 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ 36 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
24 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ 37 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
@@ -72,6 +85,8 @@ cargo batch \
72 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ 85 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
73 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ 86 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
74 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \ 87 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
88 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
89 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
75 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ 90 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
76 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ 91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
77 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ 92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
@@ -79,6 +94,7 @@ cargo batch \
79 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \ 94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
80 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ 95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
81 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ 96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \
82 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ 98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
83 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ 99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
84 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \ 100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
@@ -131,9 +147,10 @@ cargo batch \
131 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ 147 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
132 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ 148 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
133 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ 149 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
150 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
134 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ 151 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
135 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf \ 152 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
136 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf \ 153 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
137 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ 154 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
138 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ 155 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
139 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \ 156 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
@@ -156,11 +173,17 @@ cargo batch \
156 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \ 173 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
157 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \ 174 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
158 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \ 175 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
176 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
177 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
178 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
179 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \
180 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \
159 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 181 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
160 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ 182 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
161 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ 183 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
162 $BUILD_EXTRA 184 $BUILD_EXTRA
163 185
186rm out/tests/nrf52840-dk/wifi_esp_hosted_perf
164 187
165if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 188if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
166 echo No teleprobe token found, skipping running HIL tests 189 echo No teleprobe token found, skipping running HIL tests
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 855d54b11..dae7419c1 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -11,8 +11,8 @@ log = ["dep:log"]
11firmware-logs = [] 11firmware-logs = []
12 12
13[dependencies] 13[dependencies]
14embassy-time = { version = "0.1.2", path = "../embassy-time"} 14embassy-time = { version = "0.1.3", path = "../embassy-time"}
15embassy-sync = { version = "0.2.0", path = "../embassy-sync"} 15embassy-sync = { version = "0.3.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"}
18atomic-polyfill = "0.1.5" 18atomic-polyfill = "0.1.5"
@@ -31,4 +31,4 @@ num_enum = { version = "0.5.7", default-features = false }
31src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" 31src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
32src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" 32src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
33target = "thumbv6m-none-eabi" 33target = "thumbv6m-none-eabi"
34features = ["defmt", "firmware-logs"] \ No newline at end of file 34features = ["defmt", "firmware-logs"]
diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs
index 1f6551589..4e2836f3b 100644
--- a/cyw43/src/consts.rs
+++ b/cyw43/src/consts.rs
@@ -96,6 +96,7 @@ pub(crate) const IOCTL_CMD_UP: u32 = 2;
96pub(crate) const IOCTL_CMD_DOWN: u32 = 3; 96pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
97pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; 97pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
98pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; 98pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
99pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52;
99pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; 100pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
100pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; 101pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
101pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; 102pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index c67614dd6..a6d1f0bf5 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -124,7 +124,7 @@ impl<'a> Control<'a> {
124 Timer::after(Duration::from_millis(100)).await; 124 Timer::after(Duration::from_millis(100)).await;
125 125
126 // set wifi up 126 // set wifi up
127 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; 127 self.up().await;
128 128
129 Timer::after(Duration::from_millis(100)).await; 129 Timer::after(Duration::from_millis(100)).await;
130 130
@@ -138,6 +138,16 @@ impl<'a> Control<'a> {
138 debug!("INIT DONE"); 138 debug!("INIT DONE");
139 } 139 }
140 140
141 /// Set the WiFi interface up.
142 async fn up(&mut self) {
143 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
144 }
145
146 /// Set the interface down.
147 async fn down(&mut self) {
148 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
149 }
150
141 pub async fn set_power_management(&mut self, mode: PowerManagementMode) { 151 pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
142 // power save mode 152 // power save mode
143 let mode_num = mode.mode(); 153 let mode_num = mode.mode();
@@ -256,13 +266,13 @@ impl<'a> Control<'a> {
256 } 266 }
257 267
258 // Temporarily set wifi down 268 // Temporarily set wifi down
259 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; 269 self.down().await;
260 270
261 // Turn off APSTA mode 271 // Turn off APSTA mode
262 self.set_iovar_u32("apsta", 0).await; 272 self.set_iovar_u32("apsta", 0).await;
263 273
264 // Set wifi up again 274 // Set wifi up again
265 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; 275 self.up().await;
266 276
267 // Turn on AP mode 277 // Turn on AP mode
268 self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; 278 self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await;
@@ -423,6 +433,11 @@ impl<'a> Control<'a> {
423 events: &self.events, 433 events: &self.events,
424 } 434 }
425 } 435 }
436 /// Leave the wifi, with which we are currently associated.
437 pub async fn leave(&mut self) {
438 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
439 info!("Disassociated")
440 }
426} 441}
427 442
428pub struct Scanner<'a> { 443pub struct Scanner<'a> {
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs
index 9534c101c..78e583c1c 100644
--- a/cyw43/src/fmt.rs
+++ b/cyw43/src/fmt.rs
@@ -83,14 +83,17 @@ macro_rules! todo {
83 }; 83 };
84} 84}
85 85
86#[cfg(not(feature = "defmt"))]
86macro_rules! unreachable { 87macro_rules! unreachable {
87 ($($x:tt)*) => { 88 ($($x:tt)*) => {
88 { 89 ::core::unreachable!($($x)*)
89 #[cfg(not(feature = "defmt"))] 90 };
90 ::core::unreachable!($($x)*); 91}
91 #[cfg(feature = "defmt")] 92
92 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
93 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
94 }; 97 };
95} 98}
96 99
@@ -226,7 +229,8 @@ impl<T, E> Try for Result<T, E> {
226 } 229 }
227} 230}
228 231
229pub struct Bytes<'a>(pub &'a [u8]); 232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
230 234
231impl<'a> Debug for Bytes<'a> { 235impl<'a> Debug for Bytes<'a> {
232 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
index 30a3d5f26..6b124cf7f 100644
--- a/cyw43/src/lib.rs
+++ b/cyw43/src/lib.rs
@@ -27,7 +27,7 @@ use ioctl::IoctlState;
27 27
28use crate::bus::Bus; 28use crate::bus::Bus;
29pub use crate::bus::SpiBusCyw43; 29pub use crate::bus::SpiBusCyw43;
30pub use crate::control::{Control, Error as ControlError}; 30pub use crate::control::{Control, Error as ControlError, Scanner};
31pub use crate::runner::Runner; 31pub use crate::runner::Runner;
32pub use crate::structs::BssInfo; 32pub use crate::structs::BssInfo;
33 33
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index 86f2996f1..261a3c19c 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -8,3 +8,5 @@
8* xref:bootloader.adoc[Bootloader] 8* xref:bootloader.adoc[Bootloader]
9 9
10* xref:examples.adoc[Examples] 10* xref:examples.adoc[Examples]
11* xref:developer.adoc[Developer]
12** xref:developer_stm32.adoc[Developer: STM32] \ No newline at end of file
diff --git a/docs/modules/ROOT/pages/developer.adoc b/docs/modules/ROOT/pages/developer.adoc
new file mode 100644
index 000000000..e03ee51a8
--- /dev/null
+++ b/docs/modules/ROOT/pages/developer.adoc
@@ -0,0 +1 @@
= Developer Documentation \ No newline at end of file
diff --git a/docs/modules/ROOT/pages/developer_stm32.adoc b/docs/modules/ROOT/pages/developer_stm32.adoc
new file mode 100644
index 000000000..7c04ab1a4
--- /dev/null
+++ b/docs/modules/ROOT/pages/developer_stm32.adoc
@@ -0,0 +1,79 @@
1= Developer Documentation: STM32
2
3== Understanding metapac
4
5When a project that imports `embassy-stm32` is compiled, that project selects the feature corresponding to the chip that project is using. Based on that feature, `embassy-stm32` selects supported link:https://anysilicon.com/ip-intellectual-property-core-semiconductors/[IP] for the chip, and enables the corresponding HAL implementations. But how does `embassy-stm32` know what IP the chip contains, out of the hundreds of chips that we support? It's a long story that starts with `stm32-data-sources`.
6
7== `stm32-data-sources`
8
9link:https://github.com/embassy-rs/stm32-data-sources[`stm32-data-sources`] is as mostly barren repository. It has no README, no documentation, and few watchers. But it's the core of what makes `embassy-stm32` possible. The data for every chip that we support is taken in part from a corresponding XML file like link:https://github.com/embassy-rs/stm32-data-sources/blob/b8b85202e22a954d6c59d4a43d9795d34cff05cf/cubedb/mcu/STM32F051K4Ux.xml[`STM32F051K4Ux.xml`]. In that file, you'll see lines like the following:
10
11[source,xml]
12----
13 <IP InstanceName="I2C1" Name="I2C" Version="i2c2_v1_1_Cube"/>
14 <!-- snip -->
15 <IP ConfigFile="TIM-STM32F0xx" InstanceName="TIM1" Name="TIM1_8F0" Version="gptimer2_v2_x_Cube"/>
16----
17
18These lines indicate that this chip has an i2c, and that it's version is "v1_1". It also indicates that it has a general purpose timer that with a version of "v2_x". From this data, it's possible to determine which implementations should be included in `embassy-stm32`. But actually doing that is another matter.
19
20
21== `stm32-data`
22
23While all users of this project are familiar with `embassy-stm32`, fewer are familiar with the project that powers it: `stm32-data`. This project doesn't just aim to generate data for `embassy-stm32`, but for machine consumption in general. To acheive this, information from multiple files from the `stm32-data-sources` project are combined and parsed to assign register block implementations for each supported IP. The core of this matching resides in `chips.rs`:
24
25[source,rust]
26----
27 (".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")),
28 // snip
29 (r".*TIM\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")),
30----
31
32In this case, the i2c version corresponds to our "v2" and the general purpose timer version corresponds to our "v1". Therefore, the `i2c_v2.yaml` and `timer_v1.yaml` register block implementations are assigned to those IP, respectively. The result is that these lines arr generated in `STM32F051K4.json`:
33
34[source,json]
35----
36 {
37 "name": "I2C1",
38 "address": 1073763328,
39 "registers": {
40 "kind": "i2c",
41 "version": "v2",
42 "block": "I2C"
43 },
44 // snip
45 }
46 // snip
47 {
48 "name": "TIM1",
49 "address": 1073818624,
50 "registers": {
51 "kind": "timer",
52 "version": "v1",
53 "block": "TIM_ADV"
54 },
55 // snip
56 }
57----
58
59In addition to register blocks, data for pin and RCC mapping is also generated and consumed by `embassy-stm32`. `stm32-metapac-gen` is used to package and publish the data as a crate.
60
61
62== `embassy-stm32`
63
64In the `lib.rs` file located in the root of `embassy-stm32`, you'll see this line:
65
66[source,rust]
67----
68#[cfg(i2c)]
69pub mod i2c;
70----
71
72And in the `mod.rs` of the i2c mod, you'll see this:
73
74[source,rust]
75----
76#[cfg_attr(i2c_v2, path = "v2.rs")]
77----
78
79Because i2c is supported for STM32F051K4 and its version corresponds to our "v2", the `i2c` and `i2c_v2`, configuration directives will be present, and `embassy-stm32` will include these files, respectively. This and other configuration directives and tables are generated from the data for chip, allowing `embassy-stm32` to expressively and clearly adapt logic and implementations to what is required for each chip. Compared to other projects across the embedded ecosystem, `embassy-stm32` is the only project that can re-use code across the entire stm32 lineup and remove difficult-to-implement unsafe logic to the HAL. \ No newline at end of file
diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc
index 0a17c6739..805a1e70e 100644
--- a/docs/modules/ROOT/pages/index.adoc
+++ b/docs/modules/ROOT/pages/index.adoc
@@ -4,14 +4,9 @@ Embassy is a project to make async/await a first-class option for embedded devel
4 4
5== What is async? 5== What is async?
6 6
7Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations. 7When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task, known as a thread, can be executed if available, or the CPU can be put to sleep until another such task is ready to perform more work. Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. But if tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In Rust, these lightweight tasks, known as 'coroutines' or 'goroutines' in other languages, are implemented with async.
8 8
9With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads. 9Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
10
11The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support,
12this requires building a complex loop checking for events.
13
14In Rust, non-blocking operations can be implemented using async-await. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
15 10
16== What is Embassy? 11== What is Embassy?
17 12
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 415d7960f..6a334f01a 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -28,7 +28,7 @@ digest = "0.10"
28log = { version = "0.4", optional = true } 28log = { version = "0.4", optional = true }
29ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } 29ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
30embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 30embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
31embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } 31embassy-sync = { version = "0.3.0", path = "../../embassy-sync" }
32embedded-storage = "0.3.0" 32embedded-storage = "0.3.0"
33embedded-storage-async = { version = "0.4.0", optional = true } 33embedded-storage-async = { version = "0.4.0", optional = true }
34salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true } 34salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
diff --git a/embassy-boot/boot/src/fmt.rs b/embassy-boot/boot/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-boot/boot/src/fmt.rs
+++ b/embassy-boot/boot/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-boot/nrf/src/fmt.rs b/embassy-boot/nrf/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-boot/nrf/src/fmt.rs
+++ b/embassy-boot/nrf/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-boot/rp/src/fmt.rs b/embassy-boot/rp/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-boot/rp/src/fmt.rs
+++ b/embassy-boot/rp/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-boot/stm32/src/fmt.rs b/embassy-boot/stm32/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-boot/stm32/src/fmt.rs
+++ b/embassy-boot/stm32/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index fd921d277..62a95ed91 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -20,8 +20,8 @@ default = ["time"]
20 20
21[dependencies] 21[dependencies]
22embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } 22embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
23embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 23embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
24embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } 24embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
25embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ 25embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
26 "unproven", 26 "unproven",
27] } 27] }
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 4853ba29b..ccbca1eb3 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -5,11 +5,12 @@ 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.3.0 - TBD 8## 0.3.0 - 2023-08-25
9 9
10- Replaced Pender. Implementations now must define an extern function called `__pender`. 10- Replaced Pender. Implementations now must define an extern function called `__pender`.
11- Made `raw::AvailableTask` public 11- Made `raw::AvailableTask` public
12- Made `SpawnToken::new_failed` public 12- Made `SpawnToken::new_failed` public
13- You can now use arbitrary expressions to specify `#[task(pool_size = X)]`
13 14
14## 0.2.1 - 2023-08-10 15## 0.2.1 - 2023-08-10
15 16
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 2a67f70da..35944625f 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -58,8 +58,8 @@ log = { version = "0.4.14", optional = true }
58rtos-trace = { version = "0.1.2", optional = true } 58rtos-trace = { version = "0.1.2", optional = true }
59 59
60futures-util = { version = "0.3.17", default-features = false } 60futures-util = { version = "0.3.17", default-features = false }
61embassy-macros = { version = "0.2.0", path = "../embassy-macros" } 61embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
62embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true} 62embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true}
63atomic-polyfill = "1.0.1" 63atomic-polyfill = "1.0.1"
64critical-section = "1.1" 64critical-section = "1.1"
65static_cell = "1.1" 65static_cell = "1.1"
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index 0806a22ab..fde862f3c 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -1,5 +1,3 @@
1const THREAD_PENDER: usize = usize::MAX;
2
3#[export_name = "__pender"] 1#[export_name = "__pender"]
4#[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] 2#[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))]
5fn __pender(context: *mut ()) { 3fn __pender(context: *mut ()) {
@@ -48,13 +46,14 @@ fn __pender(context: *mut ()) {
48pub use thread::*; 46pub use thread::*;
49#[cfg(feature = "executor-thread")] 47#[cfg(feature = "executor-thread")]
50mod thread { 48mod thread {
49 pub(super) const THREAD_PENDER: usize = usize::MAX;
50
51 use core::arch::asm; 51 use core::arch::asm;
52 use core::marker::PhantomData; 52 use core::marker::PhantomData;
53 53
54 #[cfg(feature = "nightly")] 54 #[cfg(feature = "nightly")]
55 pub use embassy_macros::main_cortex_m as main; 55 pub use embassy_macros::main_cortex_m as main;
56 56
57 use crate::arch::THREAD_PENDER;
58 use crate::{raw, Spawner}; 57 use crate::{raw, Spawner};
59 58
60 /// Thread mode executor, using WFE/SEV. 59 /// Thread mode executor, using WFE/SEV.
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs
index 934fd69e5..15aed867a 100644
--- a/embassy-executor/src/arch/wasm.rs
+++ b/embassy-executor/src/arch/wasm.rs
@@ -73,9 +73,10 @@ mod thread {
73 pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { 73 pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
74 unsafe { 74 unsafe {
75 let executor = &self.inner; 75 let executor = &self.inner;
76 self.ctx.closure.write(Closure::new(move |_| { 76 let future = Closure::new(move |_| {
77 executor.poll(); 77 executor.poll();
78 })); 78 });
79 self.ctx.closure.write_in_place(|| future);
79 init(self.inner.spawner()); 80 init(self.inner.spawner());
80 } 81 }
81 } 82 }
diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-executor/src/fmt.rs
+++ b/embassy-executor/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index c1d82e18a..6d2c1c18a 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -203,7 +203,7 @@ impl<F: Future + 'static> AvailableTask<F> {
203 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { 203 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
204 unsafe { 204 unsafe {
205 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); 205 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
206 self.task.future.write(future()); 206 self.task.future.write_in_place(future);
207 207
208 let task = TaskRef::new(self.task); 208 let task = TaskRef::new(self.task);
209 209
diff --git a/embassy-executor/src/raw/util.rs b/embassy-executor/src/raw/util.rs
index e2e8f4df8..c46085e45 100644
--- a/embassy-executor/src/raw/util.rs
+++ b/embassy-executor/src/raw/util.rs
@@ -17,8 +17,9 @@ impl<T> UninitCell<T> {
17 &mut *self.as_mut_ptr() 17 &mut *self.as_mut_ptr()
18 } 18 }
19 19
20 pub unsafe fn write(&self, val: T) { 20 #[inline(never)]
21 ptr::write(self.as_mut_ptr(), val) 21 pub unsafe fn write_in_place(&self, func: impl FnOnce() -> T) {
22 ptr::write(self.as_mut_ptr(), func())
22 } 23 }
23 24
24 pub unsafe fn drop_in_place(&self) { 25 pub unsafe fn drop_in_place(&self) {
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-futures/src/fmt.rs
+++ b/embassy-futures/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-hal-internal/src/fmt.rs
+++ b/embassy-hal-internal/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index feea06582..88f815cd0 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -20,15 +20,12 @@ 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.2", path = "../embassy-time", optional = true } 23embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
24embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 24embassy-sync = { version = "0.3.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-async = { version = "=1.0.0-rc.1" } 26embedded-hal-async = { version = "=1.0.0-rc.1" }
27embedded-hal = { version = "0.2", features = ["unproven"] } 27embedded-hal = { version = "0.2", features = ["unproven"] }
28 28
29futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 29futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
30lora-phy = { version = "1" } 30lora-phy = { version = "2" }
31lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } 31lorawan-device = { version = "0.11.0", default-features = false, features = ["async"], optional = true }
32
33[patch.crates-io]
34lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file
diff --git a/embassy-lora/src/fmt.rs b/embassy-lora/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-lora/src/fmt.rs
+++ b/embassy-lora/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs
index 136973fe3..d22beb337 100644
--- a/embassy-lora/src/iv.rs
+++ b/embassy-lora/src/iv.rs
@@ -67,24 +67,20 @@ where
67 self.board_type = board_type; 67 self.board_type = board_type;
68 } 68 }
69 async fn set_nss_low(&mut self) -> Result<(), RadioError> { 69 async fn set_nss_low(&mut self) -> Result<(), RadioError> {
70 let pwr = pac::PWR; 70 pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
71 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
72 Ok(()) 71 Ok(())
73 } 72 }
74 async fn set_nss_high(&mut self) -> Result<(), RadioError> { 73 async fn set_nss_high(&mut self) -> Result<(), RadioError> {
75 let pwr = pac::PWR; 74 pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
76 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
77 Ok(()) 75 Ok(())
78 } 76 }
79 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { 77 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
80 let rcc = pac::RCC; 78 pac::RCC.csr().modify(|w| w.set_rfrst(true));
81 rcc.csr().modify(|w| w.set_rfrst(true)); 79 pac::RCC.csr().modify(|w| w.set_rfrst(false));
82 rcc.csr().modify(|w| w.set_rfrst(false));
83 Ok(()) 80 Ok(())
84 } 81 }
85 async fn wait_on_busy(&mut self) -> Result<(), RadioError> { 82 async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
86 let pwr = pac::PWR; 83 while pac::PWR.sr2().read().rfbusys() {}
87 while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
88 Ok(()) 84 Ok(())
89 } 85 }
90 86
@@ -284,11 +280,7 @@ where
284 self.busy.wait_for_low().await.map_err(|_| Busy) 280 self.busy.wait_for_low().await.map_err(|_| Busy)
285 } 281 }
286 async fn await_irq(&mut self) -> Result<(), RadioError> { 282 async fn await_irq(&mut self) -> Result<(), RadioError> {
287 if self.board_type != BoardType::RpPicoWaveshareSx1262 { 283 self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
288 self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
289 } else {
290 self.dio1.wait_for_rising_edge().await.map_err(|_| DIO1)?;
291 }
292 Ok(()) 284 Ok(())
293 } 285 }
294 286
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index 3b8fe8b44..a893cd30f 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-macros" 2name = "embassy-macros"
3version = "0.2.0" 3version = "0.2.1"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "macros for creating the entry point and tasks for embassy-executor" 6description = "macros for creating the entry point and tasks for embassy-executor"
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
new file mode 100644
index 000000000..8de8eadea
--- /dev/null
+++ b/embassy-net-adin1110/Cargo.toml
@@ -0,0 +1,42 @@
1[package]
2name = "embassy-net-adin1110"
3version = "0.2.0"
4description = "embassy-net driver for the ADIN1110 ethernet chip"
5keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0"
8edition = "2021"
9
10# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11
12[dependencies]
13heapless = "0.7.16"
14defmt = { version = "0.3", optional = true }
15log = { version = "0.4", default-features = false, optional = true }
16embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
17embedded-hal-async = { version = "=1.0.0-rc.1" }
18embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
19embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
20embassy-time = { version = "0.1.3" }
21embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
22bitfield = "0.14.0"
23
24[dev-dependencies]
25# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged.
26#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] }
27embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
28crc = "3.0.1"
29env_logger = "0.10"
30critical-section = { version = "1.1.2", features = ["std"] }
31futures-test = "0.3.28"
32
33[features]
34default = [ ]
35defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ]
36log = ["dep:log"]
37
38[package.metadata.embassy_docs]
39src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/"
40src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/"
41target = "thumbv7em-none-eabi"
42features = ["defmt"]
diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md
new file mode 100644
index 000000000..8ea10b714
--- /dev/null
+++ b/embassy-net-adin1110/README.md
@@ -0,0 +1,88 @@
1# SPE ADIN1110 `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for the `Analog ADIN1110` SPI SPE ethernet chips.
4
5## What is SPE or Single Pair Ethernet / 10 BASE-T1L
6
7SPE stands for Single Pair Ethernet. As the names implies, SPE uses differential signalling with 2 wires (a twisted-pair) in a cable as the physical medium.
8SPE is full-duplex - it can transmit and receive ethernet packets at the same time. SPE is still ethernet, only the physical layer is different.
9
10SPE also supports [`PoDL (Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similar to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but an additional hardware and handshake protocol are needed.
11
12SPE has many link speeds but only `10 BASE-T1L` is able to reach cable lengths up to 1000 meters in `2.4 Vpp` transmit amplitude.
13Currently in 2023, none of the standards are compatible with each other.
14Thus `10 BASE-T1L` won't work with a `10 BASE-T1S`, `100 BASE-T1` or any standard `x BASE-T`.
15
16In the industry SPE is also called [`APL (Advanced Physical Layer)`](https://www.ethernet-apl.org), and is based on the `10 BASE-T1L` standard.
17
18APL can be used in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has its own name and standard called [`2-WISE (2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292).
19
20`10 BASE-T1L` and `ADIN1110` are designed to support intrinsic safety applications. The power supply energy is fixed and PDoL is not supported.
21
22## Supported SPI modes
23
24`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
25
26Both modes support with and without additional CRC.
27Currently only `Generic` SPI with or without CRC is supported.
28
29*NOTE:* SPI Mode is selected by the hardware pins `SPI_CFG0` and `SPI_CFG1`. Software can't detect nor change the mode.
30
31## Hardware
32
33- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) for an example.
34- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit (End Of Life)`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!**
35
36## Other SPE chips
37
38* [`Analog ADIN2111`](https://www.analog.com/en/products/adin2111.html) 2 Port SPI version. Can work with this driver.
39* [`Analog ADIN1100`](https://www.analog.com/en/products/adin1100.html) RGMII version.
40
41## Testing
42
43ADIN1110 library can tested on the host with a mock SPI driver.
44
45$ `cargo test --target x86_64-unknown-linux-gnu`
46
47## Benchmark
48
49- Benchmarked on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html), with [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example.
50
51Basic `ping` benchmark
52```rust,ignore
53# ping <IP> -c 60
54
5560 packets transmitted, 60 received, 0% packet loss, time 59066ms
56rtt min/avg/max/mdev = 1.089/1.161/1.237/0.018 ms
57
58# ping <IP> -s 1472 -M do -c 60
59
6060 packets transmitted, 60 received, 0% packet loss, time 59066ms
61rtt min/avg/max/mdev = 5.122/5.162/6.177/0.133 ms
62```
63
64HTTP load generator benchmark with [`oha`](https://github.com/hatoo/oha)
65```rust,ignore
66# oha -c 1 http://<IP> -z 60s
67Summary:
68 Success rate: 50.00%
69 Total: 60.0005 secs
70 Slowest: 0.0055 secs
71 Fastest: 0.0033 secs
72 Average: 0.0034 secs
73 Requests/sec: 362.1971
74
75 Total data: 2.99 MiB
76 Size/request: 289 B
77 Size/sec: 51.11 KiB
78```
79
80## License
81
82This work is licensed under either of
83
84- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
85 http://www.apache.org/licenses/LICENSE-2.0)
86- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
87
88at your option.
diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs
new file mode 100644
index 000000000..ec020b70c
--- /dev/null
+++ b/embassy-net-adin1110/src/crc32.rs
@@ -0,0 +1,359 @@
1pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
2 0x0000_0000,
3 0x7707_3096,
4 0xEE0E_612C,
5 0x9909_51BA,
6 0x076D_C419,
7 0x706A_F48F,
8 0xE963_A535,
9 0x9E64_95A3,
10 0x0EDB_8832,
11 0x79DC_B8A4,
12 0xE0D5_E91E,
13 0x97D2_D988,
14 0x09B6_4C2B,
15 0x7EB1_7CBD,
16 0xE7B8_2D07,
17 0x90BF_1D91,
18 0x1DB7_1064,
19 0x6AB0_20F2,
20 0xF3B9_7148,
21 0x84BE_41DE,
22 0x1ADA_D47D,
23 0x6DDD_E4EB,
24 0xF4D4_B551,
25 0x83D3_85C7,
26 0x136C_9856,
27 0x646B_A8C0,
28 0xFD62_F97A,
29 0x8A65_C9EC,
30 0x1401_5C4F,
31 0x6306_6CD9,
32 0xFA0F_3D63,
33 0x8D08_0DF5,
34 0x3B6E_20C8,
35 0x4C69_105E,
36 0xD560_41E4,
37 0xA267_7172,
38 0x3C03_E4D1,
39 0x4B04_D447,
40 0xD20D_85FD,
41 0xA50A_B56B,
42 0x35B5_A8FA,
43 0x42B2_986C,
44 0xDBBB_C9D6,
45 0xACBC_F940,
46 0x32D8_6CE3,
47 0x45DF_5C75,
48 0xDCD6_0DCF,
49 0xABD1_3D59,
50 0x26D9_30AC,
51 0x51DE_003A,
52 0xC8D7_5180,
53 0xBFD0_6116,
54 0x21B4_F4B5,
55 0x56B3_C423,
56 0xCFBA_9599,
57 0xB8BD_A50F,
58 0x2802_B89E,
59 0x5F05_8808,
60 0xC60C_D9B2,
61 0xB10B_E924,
62 0x2F6F_7C87,
63 0x5868_4C11,
64 0xC161_1DAB,
65 0xB666_2D3D,
66 0x76DC_4190,
67 0x01DB_7106,
68 0x98D2_20BC,
69 0xEFD5_102A,
70 0x71B1_8589,
71 0x06B6_B51F,
72 0x9FBF_E4A5,
73 0xE8B8_D433,
74 0x7807_C9A2,
75 0x0F00_F934,
76 0x9609_A88E,
77 0xE10E_9818,
78 0x7F6A_0DBB,
79 0x086D_3D2D,
80 0x9164_6C97,
81 0xE663_5C01,
82 0x6B6B_51F4,
83 0x1C6C_6162,
84 0x8565_30D8,
85 0xF262_004E,
86 0x6C06_95ED,
87 0x1B01_A57B,
88 0x8208_F4C1,
89 0xF50F_C457,
90 0x65B0_D9C6,
91 0x12B7_E950,
92 0x8BBE_B8EA,
93 0xFCB9_887C,
94 0x62DD_1DDF,
95 0x15DA_2D49,
96 0x8CD3_7CF3,
97 0xFBD4_4C65,
98 0x4DB2_6158,
99 0x3AB5_51CE,
100 0xA3BC_0074,
101 0xD4BB_30E2,
102 0x4ADF_A541,
103 0x3DD8_95D7,
104 0xA4D1_C46D,
105 0xD3D6_F4FB,
106 0x4369_E96A,
107 0x346E_D9FC,
108 0xAD67_8846,
109 0xDA60_B8D0,
110 0x4404_2D73,
111 0x3303_1DE5,
112 0xAA0A_4C5F,
113 0xDD0D_7CC9,
114 0x5005_713C,
115 0x2702_41AA,
116 0xBE0B_1010,
117 0xC90C_2086,
118 0x5768_B525,
119 0x206F_85B3,
120 0xB966_D409,
121 0xCE61_E49F,
122 0x5EDE_F90E,
123 0x29D9_C998,
124 0xB0D0_9822,
125 0xC7D7_A8B4,
126 0x59B3_3D17,
127 0x2EB4_0D81,
128 0xB7BD_5C3B,
129 0xC0BA_6CAD,
130 0xEDB8_8320,
131 0x9ABF_B3B6,
132 0x03B6_E20C,
133 0x74B1_D29A,
134 0xEAD5_4739,
135 0x9DD2_77AF,
136 0x04DB_2615,
137 0x73DC_1683,
138 0xE363_0B12,
139 0x9464_3B84,
140 0x0D6D_6A3E,
141 0x7A6A_5AA8,
142 0xE40E_CF0B,
143 0x9309_FF9D,
144 0x0A00_AE27,
145 0x7D07_9EB1,
146 0xF00F_9344,
147 0x8708_A3D2,
148 0x1E01_F268,
149 0x6906_C2FE,
150 0xF762_575D,
151 0x8065_67CB,
152 0x196C_3671,
153 0x6E6B_06E7,
154 0xFED4_1B76,
155 0x89D3_2BE0,
156 0x10DA_7A5A,
157 0x67DD_4ACC,
158 0xF9B9_DF6F,
159 0x8EBE_EFF9,
160 0x17B7_BE43,
161 0x60B0_8ED5,
162 0xD6D6_A3E8,
163 0xA1D1_937E,
164 0x38D8_C2C4,
165 0x4FDF_F252,
166 0xD1BB_67F1,
167 0xA6BC_5767,
168 0x3FB5_06DD,
169 0x48B2_364B,
170 0xD80D_2BDA,
171 0xAF0A_1B4C,
172 0x3603_4AF6,
173 0x4104_7A60,
174 0xDF60_EFC3,
175 0xA867_DF55,
176 0x316E_8EEF,
177 0x4669_BE79,
178 0xCB61_B38C,
179 0xBC66_831A,
180 0x256F_D2A0,
181 0x5268_E236,
182 0xCC0C_7795,
183 0xBB0B_4703,
184 0x2202_16B9,
185 0x5505_262F,
186 0xC5BA_3BBE,
187 0xB2BD_0B28,
188 0x2BB4_5A92,
189 0x5CB3_6A04,
190 0xC2D7_FFA7,
191 0xB5D0_CF31,
192 0x2CD9_9E8B,
193 0x5BDE_AE1D,
194 0x9B64_C2B0,
195 0xEC63_F226,
196 0x756A_A39C,
197 0x026D_930A,
198 0x9C09_06A9,
199 0xEB0E_363F,
200 0x7207_6785,
201 0x0500_5713,
202 0x95BF_4A82,
203 0xE2B8_7A14,
204 0x7BB1_2BAE,
205 0x0CB6_1B38,
206 0x92D2_8E9B,
207 0xE5D5_BE0D,
208 0x7CDC_EFB7,
209 0x0BDB_DF21,
210 0x86D3_D2D4,
211 0xF1D4_E242,
212 0x68DD_B3F8,
213 0x1FDA_836E,
214 0x81BE_16CD,
215 0xF6B9_265B,
216 0x6FB0_77E1,
217 0x18B7_4777,
218 0x8808_5AE6,
219 0xFF0F_6A70,
220 0x6606_3BCA,
221 0x1101_0B5C,
222 0x8F65_9EFF,
223 0xF862_AE69,
224 0x616B_FFD3,
225 0x166C_CF45,
226 0xA00A_E278,
227 0xD70D_D2EE,
228 0x4E04_8354,
229 0x3903_B3C2,
230 0xA767_2661,
231 0xD060_16F7,
232 0x4969_474D,
233 0x3E6E_77DB,
234 0xAED1_6A4A,
235 0xD9D6_5ADC,
236 0x40DF_0B66,
237 0x37D8_3BF0,
238 0xA9BC_AE53,
239 0xDEBB_9EC5,
240 0x47B2_CF7F,
241 0x30B5_FFE9,
242 0xBDBD_F21C,
243 0xCABA_C28A,
244 0x53B3_9330,
245 0x24B4_A3A6,
246 0xBAD0_3605,
247 0xCDD7_0693,
248 0x54DE_5729,
249 0x23D9_67BF,
250 0xB366_7A2E,
251 0xC461_4AB8,
252 0x5D68_1B02,
253 0x2A6F_2B94,
254 0xB40B_BE37,
255 0xC30C_8EA1,
256 0x5A05_DF1B,
257 0x2D02_EF8D,
258];
259
260/// Generate Ethernet Frame Check Sequence
261#[allow(non_camel_case_types)]
262#[derive(Debug)]
263pub struct ETH_FCS(pub u32);
264
265impl ETH_FCS {
266 pub const CRC32_OK: u32 = 0x2144_df1c;
267
268 #[must_use]
269 pub fn new(data: &[u8]) -> Self {
270 let fcs = data.iter().fold(u32::MAX, |crc, byte| {
271 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
272 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
273 }) ^ u32::MAX;
274 Self(fcs)
275 }
276
277 #[must_use]
278 pub fn update(self, data: &[u8]) -> Self {
279 let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
280 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
281 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
282 }) ^ u32::MAX;
283 Self(fcs)
284 }
285
286 #[must_use]
287 pub fn crc_ok(&self) -> bool {
288 self.0 == Self::CRC32_OK
289 }
290
291 #[must_use]
292 pub fn hton_bytes(&self) -> [u8; 4] {
293 self.0.to_le_bytes()
294 }
295
296 #[must_use]
297 pub fn hton(&self) -> u32 {
298 self.0.to_le()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn crc32_ethernet_frame() {
308 let packet_a = &[
309 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xff, 0x06, 0x00, 0x01, 0x08, 0x00,
310 0x06, 0x04, 0x00, 0x01, 0x00, 0xe0, 0x4c, 0x68, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0xc0, 0xa8, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x65, 0x90, 0x3d,
313 ];
314
315 let packet_b = &[
316 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00,
317 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78,
318 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c,
320 ];
321
322 // Packet A
323 let own_crc = ETH_FCS::new(&packet_a[0..60]);
324 let crc_bytes = own_crc.hton_bytes();
325 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
326 assert_eq!(&crc_bytes, &packet_a[60..64]);
327
328 let own_crc = ETH_FCS::new(packet_a);
329 println!("{:08x}", own_crc.0);
330 assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
331
332 // Packet B
333 let own_crc = ETH_FCS::new(&packet_b[0..60]);
334 let crc_bytes = own_crc.hton_bytes();
335 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
336 assert_eq!(&crc_bytes, &packet_b[60..64]);
337
338 let own_crc = ETH_FCS::new(packet_b);
339 println!("{:08x}", own_crc.0);
340 assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
341 }
342
343 #[test]
344 fn crc32_update() {
345 let full_data = &[
346 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00,
347 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78,
348 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c,
350 ];
351
352 let (part_a, part_b) = full_data.split_at(16);
353 let crc_partially = ETH_FCS::new(part_a).update(part_b);
354
355 let crc_full = ETH_FCS::new(full_data);
356
357 assert_eq!(crc_full.0, crc_partially.0);
358 }
359}
diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs
new file mode 100644
index 000000000..7d20a7401
--- /dev/null
+++ b/embassy-net-adin1110/src/crc8.rs
@@ -0,0 +1,53 @@
1/// CRC-8/ITU
2const CRC8X_TABLE: [u8; 256] = [
3 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e,
4 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb,
5 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8,
6 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6,
7 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d,
8 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50,
9 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95,
10 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
11 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f,
12 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a,
13 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e,
14 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
15 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc,
16 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
17];
18
19/// Calculate the crc of a pease of data.
20pub fn crc8(data: &[u8]) -> u8 {
21 data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
22}
23
24#[cfg(test)]
25mod tests {
26 use ::crc::{Crc, CRC_8_SMBUS};
27
28 use super::crc8;
29
30 #[test]
31 fn spi_header_crc8() {
32 let data = &[0x80, 0x00];
33
34 let c = Crc::<u8>::new(&CRC_8_SMBUS);
35 let mut dig = c.digest();
36 dig.update(data);
37 let sw_crc = dig.finalize();
38
39 let own_crc = crc8(data);
40
41 assert_eq!(own_crc, sw_crc);
42 assert_eq!(own_crc, 182);
43
44 let data = &[0x80, 0x01];
45 let mut dig = c.digest();
46 dig.update(data);
47 let sw_crc = dig.finalize();
48 let own_crc = crc8(data);
49
50 assert_eq!(own_crc, sw_crc);
51 assert_eq!(own_crc, 177);
52 }
53}
diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs
new file mode 100644
index 000000000..12737c690
--- /dev/null
+++ b/embassy-net-adin1110/src/fmt.rs
@@ -0,0 +1,254 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86macro_rules! unreachable {
87 ($($x:tt)*) => {
88 {
89 #[cfg(not(feature = "defmt"))]
90 ::core::unreachable!($($x)*);
91 #[cfg(feature = "defmt")]
92 ::defmt::unreachable!($($x)*);
93 }
94 };
95}
96
97macro_rules! panic {
98 ($($x:tt)*) => {
99 {
100 #[cfg(not(feature = "defmt"))]
101 ::core::panic!($($x)*);
102 #[cfg(feature = "defmt")]
103 ::defmt::panic!($($x)*);
104 }
105 };
106}
107
108macro_rules! trace {
109 ($s:literal $(, $x:expr)* $(,)?) => {
110 {
111 #[cfg(feature = "log")]
112 ::log::trace!($s $(, $x)*);
113 #[cfg(feature = "defmt")]
114 ::defmt::trace!($s $(, $x)*);
115 #[cfg(not(any(feature = "log", feature="defmt")))]
116 let _ignored = ($( & $x ),*);
117 }
118 };
119}
120
121macro_rules! debug {
122 ($s:literal $(, $x:expr)* $(,)?) => {
123 {
124 #[cfg(feature = "log")]
125 ::log::debug!($s $(, $x)*);
126 #[cfg(feature = "defmt")]
127 ::defmt::debug!($s $(, $x)*);
128 #[cfg(not(any(feature = "log", feature="defmt")))]
129 let _ignored = ($( & $x ),*);
130 }
131 };
132}
133
134macro_rules! info {
135 ($s:literal $(, $x:expr)* $(,)?) => {
136 {
137 #[cfg(feature = "log")]
138 ::log::info!($s $(, $x)*);
139 #[cfg(feature = "defmt")]
140 ::defmt::info!($s $(, $x)*);
141 #[cfg(not(any(feature = "log", feature="defmt")))]
142 let _ignored = ($( & $x ),*);
143 }
144 };
145}
146
147macro_rules! warn {
148 ($s:literal $(, $x:expr)* $(,)?) => {
149 {
150 #[cfg(feature = "log")]
151 ::log::warn!($s $(, $x)*);
152 #[cfg(feature = "defmt")]
153 ::defmt::warn!($s $(, $x)*);
154 #[cfg(not(any(feature = "log", feature="defmt")))]
155 let _ignored = ($( & $x ),*);
156 }
157 };
158}
159
160macro_rules! error {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::error!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::error!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ignored = ($( & $x ),*);
169 }
170 };
171}
172
173#[cfg(feature = "defmt")]
174macro_rules! unwrap {
175 ($($x:tt)*) => {
176 ::defmt::unwrap!($($x)*)
177 };
178}
179
180#[cfg(not(feature = "defmt"))]
181macro_rules! unwrap {
182 ($arg:expr) => {
183 match $crate::fmt::Try::into_result($arg) {
184 ::core::result::Result::Ok(t) => t,
185 ::core::result::Result::Err(e) => {
186 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
187 }
188 }
189 };
190 ($arg:expr, $($msg:expr),+ $(,)? ) => {
191 match $crate::fmt::Try::into_result($arg) {
192 ::core::result::Result::Ok(t) => t,
193 ::core::result::Result::Err(e) => {
194 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
195 }
196 }
197 }
198}
199
200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
201pub struct NoneError;
202
203pub trait Try {
204 type Ok;
205 type Error;
206 fn into_result(self) -> Result<Self::Ok, Self::Error>;
207}
208
209impl<T> Try for Option<T> {
210 type Ok = T;
211 type Error = NoneError;
212
213 #[inline]
214 fn into_result(self) -> Result<T, NoneError> {
215 self.ok_or(NoneError)
216 }
217}
218
219impl<T, E> Try for Result<T, E> {
220 type Ok = T;
221 type Error = E;
222
223 #[inline]
224 fn into_result(self) -> Self {
225 self
226 }
227}
228
229pub struct Bytes<'a>(pub &'a [u8]);
230
231impl<'a> Debug for Bytes<'a> {
232 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233 write!(f, "{:#02x?}", self.0)
234 }
235}
236
237impl<'a> Display for Bytes<'a> {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 write!(f, "{:#02x?}", self.0)
240 }
241}
242
243impl<'a> LowerHex for Bytes<'a> {
244 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245 write!(f, "{:#02x?}", self.0)
246 }
247}
248
249#[cfg(feature = "defmt")]
250impl<'a> defmt::Format for Bytes<'a> {
251 fn format(&self, fmt: defmt::Formatter) {
252 defmt::write!(fmt, "{:02x}", self.0)
253 }
254}
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs
new file mode 100644
index 000000000..53f361284
--- /dev/null
+++ b/embassy-net-adin1110/src/lib.rs
@@ -0,0 +1,1323 @@
1#![deny(clippy::pedantic)]
2#![feature(async_fn_in_trait)]
3#![cfg_attr(not(any(test, feature = "std")), no_std)]
4#![allow(clippy::module_name_repetitions)]
5#![allow(clippy::missing_errors_doc)]
6#![allow(clippy::missing_panics_doc)]
7#![doc = include_str!("../README.md")]
8
9// must go first!
10mod fmt;
11
12mod crc32;
13mod crc8;
14mod mdio;
15mod phy;
16mod regs;
17
18use ch::driver::LinkState;
19pub use crc32::ETH_FCS;
20use crc8::crc8;
21use embassy_futures::select::{select, Either};
22use embassy_net_driver_channel as ch;
23use embassy_time::{Duration, Timer};
24use embedded_hal_1::digital::OutputPin;
25use embedded_hal_async::digital::Wait;
26use embedded_hal_async::spi::{Error, Operation, SpiDevice};
27use heapless::Vec;
28pub use mdio::MdioBus;
29pub use phy::{Phy10BaseT1x, RegsC22, RegsC45};
30pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
31
32use crate::fmt::Bytes;
33use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
34
35/// ADIN1110 intern PHY ID
36pub const PHYID: u32 = 0x0283_BC91;
37
38/// Error values ADIN1110
39#[derive(Debug)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41#[allow(non_camel_case_types)]
42pub enum AdinError<E> {
43 /// SPI-BUS Error
44 Spi(E),
45 /// Ethernet FCS error
46 FCS,
47 /// SPI Header CRC error
48 SPI_CRC,
49 /// Received or sended ethernet packet is too big
50 PACKET_TOO_BIG,
51 /// Received or sended ethernet packet is too small
52 PACKET_TOO_SMALL,
53 /// MDIO transaction timeout
54 MDIO_ACC_TIMEOUT,
55}
56
57/// Type alias `Result` type with `AdinError` as error type.
58pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>;
59
60/// Internet PHY address
61pub const MDIO_PHY_ADDR: u8 = 0x01;
62
63/// Maximum Transmission Unit
64pub const MTU: usize = 1514;
65
66/// Max SPI/Frame buffer size
67pub const MAX_BUFF: usize = 2048;
68
69const DONT_CARE_BYTE: u8 = 0x00;
70const TURN_AROUND_BYTE: u8 = 0x00;
71
72/// Packet minimal frame/packet length
73const ETH_MIN_LEN: usize = 64;
74/// Ethernet `Frame Check Sequence` length
75const FCS_LEN: usize = 4;
76/// Packet minimal frame/packet length without `Frame Check Sequence` length
77const ETH_MIN_WITHOUT_FCS_LEN: usize = ETH_MIN_LEN - FCS_LEN;
78
79/// SPI Header, contains SPI action and register id.
80const SPI_HEADER_LEN: usize = 2;
81/// SPI Header CRC length
82const SPI_HEADER_CRC_LEN: usize = 1;
83/// SPI Header Turn Around length
84const SPI_HEADER_TA_LEN: usize = 1;
85/// Frame Header length
86const FRAME_HEADER_LEN: usize = 2;
87/// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write.
88const SPI_SPACE_MULTIPULE: usize = 3;
89
90/// P1 = 0x00, P2 = 0x01
91const PORT_ID_BYTE: u8 = 0x00;
92
93/// Type alias for the embassy-net driver for ADIN1110
94pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
95
96/// Internal state for the embassy-net integration.
97pub struct State<const N_RX: usize, const N_TX: usize> {
98 ch_state: ch::State<MTU, N_RX, N_TX>,
99}
100impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
101 /// Create a new `State`.
102 #[must_use]
103 pub const fn new() -> Self {
104 Self {
105 ch_state: ch::State::new(),
106 }
107 }
108}
109
110/// ADIN1110 embassy-net driver
111#[derive(Debug)]
112pub struct ADIN1110<SPI> {
113 /// SPI bus
114 spi: SPI,
115 /// Enable CRC on SPI transfer.
116 /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled.
117 spi_crc: bool,
118 /// Append FCS by the application of transmit packet, false = FCS is appended by the MAC, true = FCS appended by the application.
119 append_fcs_on_tx: bool,
120}
121
122impl<SPI: SpiDevice> ADIN1110<SPI> {
123 /// Create a new ADIN1110 instance.
124 pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self {
125 Self {
126 spi,
127 spi_crc,
128 append_fcs_on_tx,
129 }
130 }
131
132 /// Read a SPI register
133 pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SPI::Error> {
134 let mut tx_buf = Vec::<u8, 16>::new();
135
136 let mut spi_hdr = SpiHeader(0);
137 spi_hdr.set_control(true);
138 spi_hdr.set_addr(reg);
139 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
140
141 if self.spi_crc {
142 // Add CRC for header data
143 let _ = tx_buf.push(crc8(&tx_buf));
144 }
145
146 // Turn around byte, give the chip the time to access/setup the answer data.
147 let _ = tx_buf.push(TURN_AROUND_BYTE);
148
149 let mut rx_buf = [0; 5];
150
151 let spi_read_len = if self.spi_crc { rx_buf.len() } else { rx_buf.len() - 1 };
152
153 let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])];
154
155 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
156
157 if self.spi_crc {
158 let crc = crc8(&rx_buf[0..4]);
159 if crc != rx_buf[4] {
160 return Err(AdinError::SPI_CRC);
161 }
162 }
163
164 let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap());
165
166 trace!("REG Read {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf));
167
168 Ok(value)
169 }
170
171 /// Write a SPI register
172 pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SPI::Error> {
173 let mut tx_buf = Vec::<u8, 16>::new();
174
175 let mut spi_hdr = SpiHeader(0);
176 spi_hdr.set_control(true);
177 spi_hdr.set_write(true);
178 spi_hdr.set_addr(reg);
179 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
180
181 if self.spi_crc {
182 // Add CRC for header data
183 let _ = tx_buf.push(crc8(&tx_buf));
184 }
185
186 let val = value.to_be_bytes();
187 let _ = tx_buf.extend_from_slice(val.as_slice());
188
189 if self.spi_crc {
190 // Add CRC for header data
191 let _ = tx_buf.push(crc8(val.as_slice()));
192 }
193
194 trace!("REG Write {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf));
195
196 self.spi.write(&tx_buf).await.map_err(AdinError::Spi)
197 }
198
199 /// helper function for write to `MDIO_ACC` register and wait for ready!
200 async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult<u32, SPI::Error> {
201 self.write_reg(sr::MDIO_ACC, mdio_acc_val).await?;
202
203 // TODO: Add proper timeout!
204 for _ in 0..100_000 {
205 let val = self.read_reg(sr::MDIO_ACC).await?;
206 if val & 0x8000_0000 != 0 {
207 return Ok(val);
208 }
209 }
210
211 Err(AdinError::MDIO_ACC_TIMEOUT)
212 }
213
214 /// Read out fifo ethernet packet memory received via the wire.
215 pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult<usize, SPI::Error> {
216 const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN;
217 const TAIL_LEN: usize = FCS_LEN + SPI_SPACE_MULTIPULE;
218
219 let mut tx_buf = Vec::<u8, HEAD_LEN>::new();
220
221 // Size of the frame, also includes the `frame header` and `FCS`.
222 let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize;
223
224 if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN {
225 return Err(AdinError::PACKET_TOO_SMALL);
226 }
227
228 let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN;
229
230 if packet_size > frame.len() {
231 trace!("MAX: {} WANT: {}", frame.len(), packet_size);
232 return Err(AdinError::PACKET_TOO_BIG);
233 }
234
235 let mut spi_hdr = SpiHeader(0);
236 spi_hdr.set_control(true);
237 spi_hdr.set_addr(sr::RX);
238 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
239
240 if self.spi_crc {
241 // Add CRC for header data
242 let _ = tx_buf.push(crc8(&tx_buf));
243 }
244
245 // Turn around byte, TODO: Unknown that this is.
246 let _ = tx_buf.push(TURN_AROUND_BYTE);
247
248 let mut frame_header = [0, 0];
249 let mut fcs_and_extra = [0; TAIL_LEN];
250
251 // Packet read of write to the MAC packet buffer must be a multipul of 4!
252 let tail_size = (fifo_frame_size & 0x03) + FCS_LEN;
253
254 let mut spi_op = [
255 Operation::Write(&tx_buf),
256 Operation::Read(&mut frame_header),
257 Operation::Read(&mut frame[0..packet_size]),
258 Operation::Read(&mut fcs_and_extra[0..tail_size]),
259 ];
260
261 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
262
263 // According to register `CONFIG2`, bit 5 `CRC_APPEND` discription:
264 // "Similarly, on receive, the CRC32 is forwarded with the frame to the host where the host must verify it is correct."
265 // The application must allways check the FCS. It seems that the MAC/PHY has no option to handle this.
266 let fcs_calc = ETH_FCS::new(&frame[0..packet_size]);
267
268 if fcs_calc.hton_bytes() == fcs_and_extra[0..4] {
269 Ok(packet_size)
270 } else {
271 Err(AdinError::FCS)
272 }
273 }
274
275 /// Write to fifo ethernet packet memory send over the wire.
276 pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> {
277 const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN;
278 const TAIL_LEN: usize = ETH_MIN_LEN - FCS_LEN + FCS_LEN + SPI_SPACE_MULTIPULE;
279
280 if frame.len() < (6 + 6 + 2) {
281 return Err(AdinError::PACKET_TOO_SMALL);
282 }
283 if frame.len() > (MAX_BUFF - FRAME_HEADER_LEN) {
284 return Err(AdinError::PACKET_TOO_BIG);
285 }
286
287 // SPI HEADER + [OPTIONAL SPI CRC] + FRAME HEADER
288 let mut head_data = Vec::<u8, HEAD_LEN>::new();
289 // [OPTIONAL PAD DATA] + FCS + [OPTINAL BYTES MAKE SPI FRAME EVEN]
290 let mut tail_data = Vec::<u8, TAIL_LEN>::new();
291
292 let mut spi_hdr = SpiHeader(0);
293 spi_hdr.set_control(true);
294 spi_hdr.set_write(true);
295 spi_hdr.set_addr(sr::TX);
296
297 head_data
298 .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice())
299 .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
300
301 if self.spi_crc {
302 // Add CRC for header data
303 head_data
304 .push(crc8(&head_data[0..2]))
305 .map_err(|_| AdinError::PACKET_TOO_BIG)?;
306 }
307
308 // Add port number, ADIN1110 its fixed to zero/P1, but for ADIN2111 has two ports.
309 head_data
310 .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice())
311 .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
312
313 // ADIN1110 MAC and PHY don´t accept ethernet packet smaller than 64 bytes.
314 // So padded the data minus the FCS, FCS is automatilly added to by the MAC.
315 if frame.len() < ETH_MIN_WITHOUT_FCS_LEN {
316 let _ = tail_data.resize(ETH_MIN_WITHOUT_FCS_LEN - frame.len(), 0x00);
317 }
318
319 // Append FCS by the application
320 if self.append_fcs_on_tx {
321 let mut frame_fcs = ETH_FCS::new(frame);
322
323 if !tail_data.is_empty() {
324 frame_fcs = frame_fcs.update(&tail_data);
325 }
326
327 let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice());
328 }
329
330 // len = frame_size + optional padding + 2 bytes Frame header
331 let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN;
332
333 let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?;
334
335 // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes!
336 let pad_len = send_len_orig & 0x03;
337 if pad_len != 0 {
338 let spi_pad_len = 4 - pad_len + tail_data.len();
339 let _ = tail_data.resize(spi_pad_len, DONT_CARE_BYTE);
340 }
341
342 self.write_reg(sr::TX_FSIZE, send_len).await?;
343
344 trace!(
345 "TX: hdr {} [{}] {}-{}-{} SIZE: {}",
346 head_data.len(),
347 frame.len(),
348 Bytes(head_data.as_slice()),
349 Bytes(frame),
350 Bytes(tail_data.as_slice()),
351 send_len,
352 );
353
354 let mut transaction = [
355 Operation::Write(head_data.as_slice()),
356 Operation::Write(frame),
357 Operation::Write(tail_data.as_slice()),
358 ];
359
360 self.spi.transaction(&mut transaction).await.map_err(AdinError::Spi)
361 }
362
363 /// Programs the mac address in the mac filters.
364 /// Also set the boardcast address.
365 /// The chip supports 2 priority queues but current code doesn't support this mode.
366 pub async fn set_mac_addr(&mut self, mac: &[u8; 6]) -> AEResult<(), SPI::Error> {
367 let mac_high_part = u16::from_be_bytes(mac[0..2].try_into().unwrap());
368 let mac_low_part = u32::from_be_bytes(mac[2..6].try_into().unwrap());
369
370 // program our mac address in the mac address filter
371 self.write_reg(sr::ADDR_FILT_UPR0, (1 << 16) | (1 << 30) | u32::from(mac_high_part))
372 .await?;
373 self.write_reg(sr::ADDR_FILT_LWR0, mac_low_part).await?;
374
375 self.write_reg(sr::ADDR_MSK_UPR0, u32::from(mac_high_part)).await?;
376 self.write_reg(sr::ADDR_MSK_LWR0, mac_low_part).await?;
377
378 // Also program broadcast address in the mac address filter
379 self.write_reg(sr::ADDR_FILT_UPR1, (1 << 16) | (1 << 30) | 0xFFFF)
380 .await?;
381 self.write_reg(sr::ADDR_FILT_LWR1, 0xFFFF_FFFF).await?;
382 self.write_reg(sr::ADDR_MSK_UPR1, 0xFFFF).await?;
383 self.write_reg(sr::ADDR_MSK_LWR1, 0xFFFF_FFFF).await?;
384
385 Ok(())
386 }
387}
388
389impl<SPI: SpiDevice> mdio::MdioBus for ADIN1110<SPI> {
390 type Error = AdinError<SPI::Error>;
391
392 /// Read from the PHY Registers as Clause 22.
393 async fn read_cl22(&mut self, phy_id: u8, reg: u8) -> Result<u16, Self::Error> {
394 let mdio_acc_val: u32 =
395 (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x3 << 26);
396
397 // Result is in the lower half of the answer.
398 #[allow(clippy::cast_possible_truncation)]
399 self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16)
400 }
401
402 /// Read from the PHY Registers as Clause 45.
403 async fn read_cl45(&mut self, phy_id: u8, regc45: (u8, u16)) -> Result<u16, Self::Error> {
404 let mdio_acc_val = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | u32::from(regc45.1);
405
406 self.write_mdio_acc_reg(mdio_acc_val).await?;
407
408 let mdio_acc_val = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | (0x03 << 26);
409
410 // Result is in the lower half of the answer.
411 #[allow(clippy::cast_possible_truncation)]
412 self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16)
413 }
414
415 /// Write to the PHY Registers as Clause 22.
416 async fn write_cl22(&mut self, phy_id: u8, reg: u8, val: u16) -> Result<(), Self::Error> {
417 let mdio_acc_val: u32 =
418 (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x1 << 26) | u32::from(val);
419
420 self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ())
421 }
422
423 /// Write to the PHY Registers as Clause 45.
424 async fn write_cl45(&mut self, phy_id: u8, regc45: (u8, u16), value: u16) -> AEResult<(), SPI::Error> {
425 let phy_id = u32::from(phy_id & 0x1F) << 21;
426 let dev_addr = u32::from(regc45.0 & 0x1F) << 16;
427 let reg = u32::from(regc45.1);
428
429 let mdio_acc_val: u32 = phy_id | dev_addr | reg;
430 self.write_mdio_acc_reg(mdio_acc_val).await?;
431
432 let mdio_acc_val: u32 = phy_id | dev_addr | (0x01 << 26) | u32::from(value);
433 self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ())
434 }
435}
436
437/// Background runner for the ADIN1110.
438///
439/// You must call `.run()` in a background task for the ADIN1110 to operate.
440pub struct Runner<'d, SPI, INT, RST> {
441 mac: ADIN1110<SPI>,
442 ch: ch::Runner<'d, MTU>,
443 int: INT,
444 is_link_up: bool,
445 _reset: RST,
446}
447
448impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
449 #[allow(clippy::too_many_lines)]
450 pub async fn run(mut self) -> ! {
451 loop {
452 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
453
454 loop {
455 debug!("Waiting for interrupts");
456 match select(self.int.wait_for_low(), tx_chan.tx_buf()).await {
457 Either::First(_) => {
458 let mut status1_clr = Status1(0);
459 let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap());
460
461 while status1.p1_rx_rdy() {
462 debug!("alloc RX packet buffer");
463 match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await {
464 // Handle frames that needs to transmit from the wire.
465 // Note: rx_chan.rx_buf() channel don´t accept new request
466 // when the tx_chan is full. So these will be handled
467 // automaticly.
468 Either::First(frame) => match self.mac.read_fifo(frame).await {
469 Ok(n) => {
470 rx_chan.rx_done(n);
471 }
472 Err(e) => match e {
473 AdinError::PACKET_TOO_BIG => {
474 error!("RX Packet too big, DROP");
475 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap();
476 }
477 AdinError::PACKET_TOO_SMALL => {
478 error!("RX Packet too small, DROP");
479 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap();
480 }
481 AdinError::Spi(e) => {
482 error!("RX Spi error {}", e.kind());
483 }
484 e => {
485 error!("RX Error {:?}", e);
486 }
487 },
488 },
489 Either::Second(frame) => {
490 // Handle frames that needs to transmit to the wire.
491 self.mac.write_fifo(frame).await.unwrap();
492 tx_chan.tx_done();
493 }
494 }
495 status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap());
496 }
497
498 let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap());
499 if status1.0 & !0x1b != 0 {
500 error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0);
501 }
502
503 if status1.tx_rdy() {
504 status1_clr.set_tx_rdy(true);
505 trace!("TX_DONE");
506 }
507
508 if status1.link_change() {
509 let link = status1.p1_link_status();
510 self.is_link_up = link;
511
512 if link {
513 let link_status = self
514 .mac
515 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA7::AN_STATUS_EXTRA.into())
516 .await
517 .unwrap();
518
519 let volt = if link_status & (0b11 << 5) == (0b11 << 5) {
520 "2.4"
521 } else {
522 "1.0"
523 };
524
525 let mse = self
526 .mac
527 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1::MSE_VAL.into())
528 .await
529 .unwrap();
530
531 info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse);
532 } else {
533 info!("LINK Changed: Link Down");
534 }
535
536 state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down });
537 status1_clr.set_link_change(true);
538 }
539
540 if status1.tx_ecc_err() {
541 error!("SPI TX_ECC_ERR error, CLEAR TX FIFO");
542 self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap();
543 status1_clr.set_tx_ecc_err(true);
544 }
545
546 if status1.rx_ecc_err() {
547 error!("SPI RX_ECC_ERR error");
548 status1_clr.set_rx_ecc_err(true);
549 }
550
551 if status1.spi_err() {
552 error!("SPI SPI_ERR CRC error");
553 status1_clr.set_spi_err(true);
554 }
555
556 if status0.phyint() {
557 let crsm_irq_st = self
558 .mac
559 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into())
560 .await
561 .unwrap();
562
563 let phy_irq_st = self
564 .mac
565 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into())
566 .await
567 .unwrap();
568
569 warn!(
570 "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}",
571 crsm_irq_st, phy_irq_st
572 );
573 }
574
575 if status0.txfcse() {
576 error!("Ethernet Frame FCS and calc FCS don't match!");
577 }
578
579 // Clear status0
580 self.mac.write_reg(sr::STATUS0, 0xFFF).await.unwrap();
581 self.mac.write_reg(sr::STATUS1, status1_clr.0).await.unwrap();
582 }
583 Either::Second(packet) => {
584 // Handle frames that needs to transmit to the wire.
585 self.mac.write_fifo(packet).await.unwrap();
586 tx_chan.tx_done();
587 }
588 }
589 }
590 }
591 }
592}
593
594/// Obtain a driver for using the ADIN1110 with [`embassy-net`](crates.io/crates/embassy-net).
595pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
596 mac_addr: [u8; 6],
597 state: &'_ mut State<N_RX, N_TX>,
598 spi_dev: SPI,
599 int: INT,
600 mut reset: RST,
601 spi_crc: bool,
602 append_fcs_on_tx: bool,
603) -> (Device<'_>, Runner<'_, SPI, INT, RST>) {
604 use crate::regs::{IMask0, IMask1};
605
606 info!("INIT ADIN1110");
607
608 // Reset sequence
609 reset.set_low().unwrap();
610
611 // Wait t1: 20-43mS
612 Timer::after(Duration::from_millis(30)).await;
613
614 reset.set_high().unwrap();
615
616 // Wait t3: 50mS
617 Timer::after(Duration::from_millis(50)).await;
618
619 // Create device
620 let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
621
622 // Check PHYID
623 let id = mac.read_reg(sr::PHYID).await.unwrap();
624 assert_eq!(id, PHYID);
625
626 debug!("SPE: CHIP MAC/ID: {:08x}", id);
627
628 #[cfg(any(feature = "defmt", feature = "log"))]
629 {
630 let adin_phy = Phy10BaseT1x::default();
631 let phy_id = adin_phy.get_id(&mut mac).await.unwrap();
632 debug!("SPE: CHIP: PHY ID: {:08x}", phy_id);
633 }
634
635 let mi_control = mac.read_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8).await.unwrap();
636 debug!("SPE CHIP PHY MI_CONTROL {:04x}", mi_control);
637 if mi_control & 0x0800 != 0 {
638 let val = mi_control & !0x0800;
639 debug!("SPE CHIP PHY MI_CONTROL Disable PowerDown");
640 mac.write_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8, val)
641 .await
642 .unwrap();
643 }
644
645 // Config0
646 let mut config0 = Config0(0x0000_0006);
647 config0.set_txfcsve(mac.append_fcs_on_tx);
648 mac.write_reg(sr::CONFIG0, config0.0).await.unwrap();
649
650 // Config2
651 let mut config2 = Config2(0x0000_0800);
652 // crc_append must be disable if tx_fcs_validation_enable is true!
653 config2.set_crc_append(!mac.append_fcs_on_tx);
654 mac.write_reg(sr::CONFIG2, config2.0).await.unwrap();
655
656 // Pin Mux Config 1
657 let led_val = (0b11 << 6) | (0b11 << 4); // | (0b00 << 1);
658 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::DIGIO_PINMUX.into(), led_val)
659 .await
660 .unwrap();
661
662 let mut led_pol = LedPolarity(0);
663 led_pol.set_led1_polarity(LedPol::ActiveLow);
664 led_pol.set_led0_polarity(LedPol::ActiveLow);
665
666 // Led Polarity Regisgere Active Low
667 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_POLARITY.into(), led_pol.0)
668 .await
669 .unwrap();
670
671 // Led Both On
672 let mut led_cntr = LedCntrl(0x0);
673
674 // LED1: Yellow
675 led_cntr.set_led1_en(true);
676 led_cntr.set_led1_function(LedFunc::TxLevel2P4);
677 // LED0: Green
678 led_cntr.set_led0_en(true);
679 led_cntr.set_led0_function(LedFunc::LinkupTxRxActicity);
680
681 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_CNTRL.into(), led_cntr.0)
682 .await
683 .unwrap();
684
685 // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE
686 // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR
687 // Have to clear the mask the enable it.
688 let mut imask0_val = IMask0(0x0000_1FBF);
689 imask0_val.set_txfcsem(false);
690 imask0_val.set_phyintm(false);
691 imask0_val.set_txboem(false);
692 imask0_val.set_rxboem(false);
693 imask0_val.set_txpem(false);
694
695 mac.write_reg(sr::IMASK0, imask0_val.0).await.unwrap();
696
697 // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE
698 // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR
699 // Have to clear the mask the enable it.
700 let mut imask1_val = IMask1(0x43FA_1F1A);
701 imask1_val.set_link_change_mask(false);
702 imask1_val.set_p1_rx_rdy_mask(false);
703 imask1_val.set_spi_err_mask(false);
704 imask1_val.set_tx_ecc_err_mask(false);
705 imask1_val.set_rx_ecc_err_mask(false);
706
707 mac.write_reg(sr::IMASK1, imask1_val.0).await.unwrap();
708
709 // Program mac address but also sets mac filters.
710 mac.set_mac_addr(&mac_addr).await.unwrap();
711
712 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr));
713 (
714 device,
715 Runner {
716 ch: runner,
717 mac,
718 int,
719 is_link_up: false,
720 _reset: reset,
721 },
722 )
723}
724
725#[allow(clippy::similar_names)]
726#[cfg(test)]
727mod tests {
728 use core::convert::Infallible;
729
730 use embedded_hal_1::digital::{ErrorType, OutputPin};
731 use embedded_hal_async::delay::DelayUs;
732 use embedded_hal_bus::spi::ExclusiveDevice;
733 use embedded_hal_mock::common::Generic;
734 use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
735
736 #[derive(Debug, Default)]
737 struct CsPinMock {
738 pub high: u32,
739 pub low: u32,
740 }
741 impl OutputPin for CsPinMock {
742 fn set_low(&mut self) -> Result<(), Self::Error> {
743 self.low += 1;
744 Ok(())
745 }
746
747 fn set_high(&mut self) -> Result<(), Self::Error> {
748 self.high += 1;
749 Ok(())
750 }
751 }
752 impl ErrorType for CsPinMock {
753 type Error = Infallible;
754 }
755
756 use super::*;
757
758 // TODO: This is currently a workaround unit `ExclusiveDevice` is moved to `embedded-hal-bus`
759 // see https://github.com/rust-embedded/embedded-hal/pull/462#issuecomment-1560014426
760 struct MockDelay {}
761
762 impl DelayUs for MockDelay {
763 async fn delay_us(&mut self, _us: u32) {
764 todo!()
765 }
766
767 async fn delay_ms(&mut self, _ms: u32) {
768 todo!()
769 }
770 }
771
772 struct TestHarnass {
773 spe: ADIN1110<ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>>,
774 spi: Generic<SpiTransaction>,
775 }
776
777 impl TestHarnass {
778 pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self {
779 let cs = CsPinMock::default();
780 let delay = MockDelay {};
781 let spi = SpiMock::new(expectations);
782 let spi_dev: ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay> =
783 ExclusiveDevice::new(spi.clone(), cs, delay);
784 let spe: ADIN1110<
785 ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>,
786 > = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
787
788 Self { spe, spi }
789 }
790
791 pub fn done(&mut self) {
792 self.spi.done();
793 }
794 }
795
796 #[futures_test::test]
797 async fn mac_read_registers_without_crc() {
798 // Configure expectations
799 let expectations = [
800 // 1st
801 SpiTransaction::write_vec(vec![0x80, 0x01, TURN_AROUND_BYTE]),
802 SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91]),
803 SpiTransaction::flush(),
804 // 2nd
805 SpiTransaction::write_vec(vec![0x80, 0x02, TURN_AROUND_BYTE]),
806 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]),
807 SpiTransaction::flush(),
808 ];
809
810 // Create TestHarnass
811 let mut th = TestHarnass::new(&expectations, false, true);
812
813 // Read PHIID
814 let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
815 assert_eq!(val, 0x0283_BC91);
816
817 // Read CAPAVILITY
818 let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
819 assert_eq!(val, 0x0000_06C3);
820
821 // Mark end of the SPI test.
822 th.done();
823 }
824
825 #[futures_test::test]
826 async fn mac_read_registers_with_crc() {
827 // Configure expectations
828 let expectations = [
829 // 1st
830 SpiTransaction::write_vec(vec![0x80, 0x01, 177, TURN_AROUND_BYTE]),
831 SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91, 215]),
832 SpiTransaction::flush(),
833 // 2nd
834 SpiTransaction::write_vec(vec![0x80, 0x02, 184, TURN_AROUND_BYTE]),
835 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]),
836 SpiTransaction::flush(),
837 ];
838
839 // Create TestHarnass
840 let mut th = TestHarnass::new(&expectations, true, true);
841
842 assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215);
843 assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57);
844
845 // Read PHIID
846 let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
847 assert_eq!(val, 0x0283_BC91);
848
849 // Read CAPAVILITY
850 let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
851 assert_eq!(val, 0x0000_06C3);
852
853 // Mark end of the SPI test.
854 th.done();
855 }
856
857 #[futures_test::test]
858 async fn mac_write_registers_without_crc() {
859 // Configure expectations
860 let expectations = [
861 SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]),
862 SpiTransaction::flush(),
863 ];
864
865 // Create TestHarnass
866 let mut th = TestHarnass::new(&expectations, false, true);
867
868 // Write reg: 0x1FFF
869 assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
870
871 // Mark end of the SPI test.
872 th.done();
873 }
874
875 #[futures_test::test]
876 async fn mac_write_registers_with_crc() {
877 // Configure expectations
878 let expectations = [
879 SpiTransaction::write_vec(vec![0xA0, 0x09, 39, 0x12, 0x34, 0x56, 0x78, 28]),
880 SpiTransaction::flush(),
881 ];
882
883 // Create TestHarnass
884 let mut th = TestHarnass::new(&expectations, true, true);
885
886 // Write reg: 0x1FFF
887 assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
888
889 // Mark end of the SPI test.
890 th.done();
891 }
892
893 #[futures_test::test]
894 async fn write_packet_to_fifo_minimal_with_crc() {
895 // Configure expectations
896 let mut expectations = vec![];
897
898 // Write TX_SIZE reg
899 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201]));
900 expectations.push(SpiTransaction::flush());
901
902 // Write TX reg.
903 // SPI Header + optional CRC + Frame Header
904 expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
905 // Packet data
906 let packet = [0xFF_u8; 60];
907 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
908
909 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
910 // Padding
911 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
912 tail.resize(padding_len, 0x00);
913 }
914 // Packet FCS + optinal padding
915 tail.extend_from_slice(&[77, 241, 140, 244, DONT_CARE_BYTE, DONT_CARE_BYTE]);
916
917 expectations.push(SpiTransaction::write_vec(tail));
918 expectations.push(SpiTransaction::flush());
919
920 // Create TestHarnass
921 let mut th = TestHarnass::new(&expectations, true, true);
922
923 assert!(th.spe.write_fifo(&packet).await.is_ok());
924
925 // Mark end of the SPI test.
926 th.done();
927 }
928
929 #[futures_test::test]
930 async fn write_packet_to_fifo_minimal_with_crc_without_fcs() {
931 // Configure expectations
932 let mut expectations = vec![];
933
934 // Write TX_SIZE reg
935 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 62, 186]));
936 expectations.push(SpiTransaction::flush());
937
938 // Write TX reg.
939 // SPI Header + optional CRC + Frame Header
940 expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
941 // Packet data
942 let packet = [0xFF_u8; 60];
943 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
944
945 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
946 // Padding
947 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
948 tail.resize(padding_len, 0x00);
949 }
950 // Packet FCS + optinal padding
951 tail.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE]);
952
953 expectations.push(SpiTransaction::write_vec(tail));
954 expectations.push(SpiTransaction::flush());
955
956 // Create TestHarnass
957 let mut th = TestHarnass::new(&expectations, true, false);
958
959 assert!(th.spe.write_fifo(&packet).await.is_ok());
960
961 // Mark end of the SPI test.
962 th.done();
963 }
964
965 #[futures_test::test]
966 async fn write_packet_to_fifo_max_mtu_with_crc() {
967 assert_eq!(MTU, 1514);
968 // Configure expectations
969 let mut expectations = vec![];
970
971 // Write TX_SIZE reg
972 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 5, 240, 159]));
973 expectations.push(SpiTransaction::flush());
974
975 // Write TX reg.
976 // SPI Header + optional CRC + Frame Header
977 expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
978 // Packet data
979 let packet = [0xAA_u8; MTU];
980 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
981
982 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
983 // Padding
984 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
985 tail.resize(padding_len, 0x00);
986 }
987 // Packet FCS + optinal padding
988 tail.extend_from_slice(&[49, 196, 205, 160]);
989
990 expectations.push(SpiTransaction::write_vec(tail));
991 expectations.push(SpiTransaction::flush());
992
993 // Create TestHarnass
994 let mut th = TestHarnass::new(&expectations, true, true);
995
996 assert!(th.spe.write_fifo(&packet).await.is_ok());
997
998 // Mark end of the SPI test.
999 th.done();
1000 }
1001
1002 #[futures_test::test]
1003 async fn write_packet_to_fifo_invalid_lengths() {
1004 assert_eq!(MTU, 1514);
1005
1006 // Configure expectations
1007 let expectations = vec![];
1008
1009 // Max packet size = MAX_BUFF - FRAME_HEADER_LEN
1010 let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1];
1011
1012 // Create TestHarnass
1013 let mut th = TestHarnass::new(&expectations, true, true);
1014
1015 // minimal
1016 assert!(matches!(
1017 th.spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await,
1018 Err(AdinError::PACKET_TOO_SMALL)
1019 ));
1020
1021 // max + 1
1022 assert!(matches!(
1023 th.spe.write_fifo(&packet).await,
1024 Err(AdinError::PACKET_TOO_BIG)
1025 ));
1026
1027 // Mark end of the SPI test.
1028 th.done();
1029 }
1030
1031 #[futures_test::test]
1032 async fn write_packet_to_fifo_arp_46bytes_with_crc() {
1033 // Configure expectations
1034 let mut expectations = vec![];
1035
1036 // Write TX_SIZE reg
1037 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201]));
1038 expectations.push(SpiTransaction::flush());
1039
1040 // Write TX reg.
1041 // Header
1042 expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
1043 // Packet data
1044 let packet = [
1045 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154,
1046 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1,
1047 ];
1048 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
1049
1050 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1051 // Padding
1052 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
1053 tail.resize(padding_len, 0x00);
1054 }
1055 // Packet FCS + optinal padding
1056 tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]);
1057
1058 expectations.push(SpiTransaction::write_vec(tail));
1059 expectations.push(SpiTransaction::flush());
1060
1061 // Create TestHarnass
1062 let mut th = TestHarnass::new(&expectations, true, true);
1063
1064 assert!(th.spe.write_fifo(&packet).await.is_ok());
1065
1066 // Mark end of the SPI test.
1067 th.done();
1068 }
1069
1070 #[futures_test::test]
1071 async fn write_packet_to_fifo_arp_46bytes_without_crc() {
1072 // Configure expectations
1073 let mut expectations = vec![];
1074
1075 // Write TX_SIZE reg
1076 expectations.push(SpiTransaction::write_vec(vec![160, 48, 0, 0, 0, 66]));
1077 expectations.push(SpiTransaction::flush());
1078
1079 // Write TX reg.
1080 // SPI Header + Frame Header
1081 expectations.push(SpiTransaction::write_vec(vec![160, 49, 0, 0]));
1082 // Packet data
1083 let packet = [
1084 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154,
1085 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1,
1086 ];
1087 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
1088
1089 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1090 // Padding
1091 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
1092 tail.resize(padding_len, 0x00);
1093 }
1094 // Packet FCS + optinal padding
1095 tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]);
1096
1097 expectations.push(SpiTransaction::write_vec(tail));
1098 expectations.push(SpiTransaction::flush());
1099
1100 // Create TestHarnass
1101 let mut th = TestHarnass::new(&expectations, false, true);
1102
1103 assert!(th.spe.write_fifo(&packet).await.is_ok());
1104
1105 // Mark end of the SPI test.
1106 th.done();
1107 }
1108
1109 #[futures_test::test]
1110 async fn read_packet_from_fifo_packet_too_big_for_frame_buffer() {
1111 // Configure expectations
1112 let mut expectations = vec![];
1113
1114 // Read RX_SIZE reg
1115 let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1116 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1117 rx_size_vec.push(crc8(&rx_size_vec));
1118
1119 expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]));
1120 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1121 expectations.push(SpiTransaction::flush());
1122
1123 let mut frame = [0; MTU];
1124
1125 // Create TestHarnass
1126 let mut th = TestHarnass::new(&expectations, true, true);
1127
1128 let ret = th.spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await;
1129 assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG)));
1130
1131 // Mark end of the SPI test.
1132 th.done();
1133 }
1134
1135 #[futures_test::test]
1136 async fn read_packet_from_fifo_packet_too_small() {
1137 // Configure expectations
1138 let mut expectations = vec![];
1139
1140 // This value is importen for this test!
1141 assert_eq!(ETH_MIN_LEN, 64);
1142
1143 // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` - 1
1144 let packet = [0; 64 - FCS_LEN - 1];
1145
1146 // Read RX_SIZE reg
1147 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1148 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1149 rx_size_vec.push(crc8(&rx_size_vec));
1150
1151 expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]));
1152 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1153 expectations.push(SpiTransaction::flush());
1154
1155 let mut frame = [0; MTU];
1156
1157 // Create TestHarnass
1158 let mut th = TestHarnass::new(&expectations, true, true);
1159
1160 let ret = th.spe.read_fifo(&mut frame).await;
1161 assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL)));
1162
1163 // Mark end of the SPI test.
1164 th.done();
1165 }
1166
1167 #[futures_test::test]
1168 async fn read_packet_from_fifo_packet_corrupted_fcs() {
1169 let mut frame = [0; MTU];
1170 // Configure expectations
1171 let mut expectations = vec![];
1172
1173 let packet = [0xDE; 60];
1174 let crc_en = true;
1175
1176 // Read RX_SIZE reg
1177 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1178 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1179 if crc_en {
1180 rx_size_vec.push(crc8(&rx_size_vec));
1181 }
1182
1183 // SPI Header with CRC
1184 let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE];
1185 if !crc_en {
1186 // remove the CRC on idx 2
1187 rx_fsize.swap_remove(2);
1188 }
1189 expectations.push(SpiTransaction::write_vec(rx_fsize));
1190 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1191 expectations.push(SpiTransaction::flush());
1192
1193 // Read RX reg, SPI Header with CRC
1194 let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE];
1195 if !crc_en {
1196 // remove the CRC on idx 2
1197 rx_reg.swap_remove(2);
1198 }
1199 expectations.push(SpiTransaction::write_vec(rx_reg));
1200 // Frame Header
1201 expectations.push(SpiTransaction::read_vec(vec![0, 0]));
1202 // Packet data
1203 expectations.push(SpiTransaction::read_vec(packet.to_vec()));
1204
1205 let packet_crc = ETH_FCS::new(&packet);
1206
1207 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1208
1209 tail.extend_from_slice(&packet_crc.hton_bytes());
1210 // increase last byte with 1.
1211 if let Some(crc) = tail.last_mut() {
1212 *crc = crc.wrapping_add(1);
1213 }
1214
1215 // Need extra bytes?
1216 let pad = (packet.len() + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
1217 if pad != 0 {
1218 // Packet FCS + optinal padding
1219 tail.resize(tail.len() + pad, DONT_CARE_BYTE);
1220 }
1221
1222 expectations.push(SpiTransaction::read_vec(tail));
1223 expectations.push(SpiTransaction::flush());
1224
1225 // Create TestHarnass
1226 let mut th = TestHarnass::new(&expectations, crc_en, false);
1227
1228 let ret = th.spe.read_fifo(&mut frame).await.expect_err("Error!");
1229 assert!(matches!(ret, AdinError::FCS));
1230
1231 // Mark end of the SPI test.
1232 th.done();
1233 }
1234
1235 #[futures_test::test]
1236 async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() {
1237 let packet_buffer = [0; MTU];
1238 let mut frame = [0; MTU];
1239 let mut expectations = std::vec::Vec::with_capacity(16);
1240
1241 // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN`
1242 for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] {
1243 for crc_en in [false, true] {
1244 expectations.clear();
1245
1246 let packet = &packet_buffer[0..packet_size];
1247
1248 // Read RX_SIZE reg
1249 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1250 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1251 if crc_en {
1252 rx_size_vec.push(crc8(&rx_size_vec));
1253 }
1254
1255 // SPI Header with CRC
1256 let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE];
1257 if !crc_en {
1258 // remove the CRC on idx 2
1259 rx_fsize.swap_remove(2);
1260 }
1261 expectations.push(SpiTransaction::write_vec(rx_fsize));
1262 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1263 expectations.push(SpiTransaction::flush());
1264
1265 // Read RX reg, SPI Header with CRC
1266 let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE];
1267 if !crc_en {
1268 // remove the CRC on idx 2
1269 rx_reg.swap_remove(2);
1270 }
1271 expectations.push(SpiTransaction::write_vec(rx_reg));
1272 // Frame Header
1273 expectations.push(SpiTransaction::read_vec(vec![0, 0]));
1274 // Packet data
1275 expectations.push(SpiTransaction::read_vec(packet.to_vec()));
1276
1277 let packet_crc = ETH_FCS::new(packet);
1278
1279 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1280
1281 tail.extend_from_slice(&packet_crc.hton_bytes());
1282
1283 // Need extra bytes?
1284 let pad = (packet_size + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
1285 if pad != 0 {
1286 // Packet FCS + optinal padding
1287 tail.resize(tail.len() + pad, DONT_CARE_BYTE);
1288 }
1289
1290 expectations.push(SpiTransaction::read_vec(tail));
1291 expectations.push(SpiTransaction::flush());
1292
1293 // Create TestHarnass
1294 let mut th = TestHarnass::new(&expectations, crc_en, false);
1295
1296 let ret = th.spe.read_fifo(&mut frame).await.expect("Error!");
1297 assert_eq!(ret, packet_size);
1298
1299 // Mark end of the SPI test.
1300 th.done();
1301 }
1302 }
1303 }
1304
1305 #[futures_test::test]
1306 async fn spi_crc_error() {
1307 // Configure expectations
1308 let expectations = vec![
1309 SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]),
1310 SpiTransaction::read_vec(vec![0x00, 0x00, 0x00, 0x00, 0xDD]),
1311 SpiTransaction::flush(),
1312 ];
1313
1314 // Create TestHarnass
1315 let mut th = TestHarnass::new(&expectations, true, false);
1316
1317 let ret = th.spe.read_reg(sr::RX_FSIZE).await;
1318 assert!(matches!(dbg!(ret), Err(AdinError::SPI_CRC)));
1319
1320 // Mark end of the SPI test.
1321 th.done();
1322 }
1323}
diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs
new file mode 100644
index 000000000..1ae5f0043
--- /dev/null
+++ b/embassy-net-adin1110/src/mdio.rs
@@ -0,0 +1,176 @@
1/// PHY Address: (0..=0x1F), 5-bits long.
2#[allow(dead_code)]
3type PhyAddr = u8;
4
5/// PHY Register: (0..=0x1F), 5-bits long.
6#[allow(dead_code)]
7type RegC22 = u8;
8
9/// PHY Register Clause 45.
10#[allow(dead_code)]
11type RegC45 = u16;
12
13/// PHY Register Value
14#[allow(dead_code)]
15type RegVal = u16;
16
17#[allow(dead_code)]
18const REG13: RegC22 = 13;
19#[allow(dead_code)]
20const REG14: RegC22 = 14;
21
22#[allow(dead_code)]
23const PHYADDR_MASK: u8 = 0x1f;
24#[allow(dead_code)]
25const DEV_MASK: u8 = 0x1f;
26
27#[allow(dead_code)]
28#[repr(u16)]
29enum Reg13Op {
30 Addr = 0b00 << 14,
31 Write = 0b01 << 14,
32 PostReadIncAddr = 0b10 << 14,
33 Read = 0b11 << 14,
34}
35
36/// `MdioBus` trait
37/// Driver needs to implement the Clause 22
38/// Optional Clause 45 is the device supports this.
39///
40/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
41pub trait MdioBus {
42 type Error;
43
44 /// Read, Clause 22
45 async fn read_cl22(&mut self, phy_id: PhyAddr, reg: RegC22) -> Result<RegVal, Self::Error>;
46
47 /// Write, Clause 22
48 async fn write_cl22(&mut self, phy_id: PhyAddr, reg: RegC22, reg_val: RegVal) -> Result<(), Self::Error>;
49
50 /// Read, Clause 45
51 /// This is the default implementation.
52 /// Many hardware these days support direct Clause 45 operations.
53 /// Implement this function when your hardware supports it.
54 async fn read_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45)) -> Result<RegVal, Self::Error> {
55 // Write FN
56 let val = (Reg13Op::Addr as RegVal) | RegVal::from(regc45.0 & DEV_MASK);
57
58 self.write_cl22(phy_id, REG13, val).await?;
59 // Write Addr
60 self.write_cl22(phy_id, REG14, regc45.1).await?;
61
62 // Write FN
63 let val = (Reg13Op::Read as RegVal) | RegVal::from(regc45.0 & DEV_MASK);
64 self.write_cl22(phy_id, REG13, val).await?;
65 // Write Addr
66 self.read_cl22(phy_id, REG14).await
67 }
68
69 /// Write, Clause 45
70 /// This is the default implementation.
71 /// Many hardware these days support direct Clause 45 operations.
72 /// Implement this function when your hardware supports it.
73 async fn write_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45), reg_val: RegVal) -> Result<(), Self::Error> {
74 let dev_addr = RegVal::from(regc45.0 & DEV_MASK);
75 let reg = regc45.1;
76
77 // Write FN
78 let val = (Reg13Op::Addr as RegVal) | dev_addr;
79 self.write_cl22(phy_id, REG13, val).await?;
80 // Write Addr
81 self.write_cl22(phy_id, REG14, reg).await?;
82
83 // Write FN
84 let val = (Reg13Op::Write as RegVal) | dev_addr;
85 self.write_cl22(phy_id, REG13, val).await?;
86 // Write Addr
87 self.write_cl22(phy_id, REG14, reg_val).await
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use core::convert::Infallible;
94
95 use super::{MdioBus, PhyAddr, RegC22, RegVal};
96
97 #[derive(Debug, PartialEq, Eq)]
98 enum A {
99 Read(PhyAddr, RegC22),
100 Write(PhyAddr, RegC22, RegVal),
101 }
102
103 struct MockMdioBus(Vec<A>);
104
105 impl MockMdioBus {
106 pub fn clear(&mut self) {
107 self.0.clear();
108 }
109 }
110
111 impl MdioBus for MockMdioBus {
112 type Error = Infallible;
113
114 async fn write_cl22(
115 &mut self,
116 phy_id: super::PhyAddr,
117 reg: super::RegC22,
118 reg_val: super::RegVal,
119 ) -> Result<(), Self::Error> {
120 self.0.push(A::Write(phy_id, reg, reg_val));
121 Ok(())
122 }
123
124 async fn read_cl22(
125 &mut self,
126 phy_id: super::PhyAddr,
127 reg: super::RegC22,
128 ) -> Result<super::RegVal, Self::Error> {
129 self.0.push(A::Read(phy_id, reg));
130 Ok(0)
131 }
132 }
133
134 #[futures_test::test]
135 async fn read_test() {
136 let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
137
138 mdiobus.clear();
139 mdiobus.read_cl22(0x01, 0x00).await.unwrap();
140 assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]);
141
142 mdiobus.clear();
143 mdiobus.read_cl45(0x01, (0xBB, 0x1234)).await.unwrap();
144 assert_eq!(
145 mdiobus.0,
146 vec![
147 #[allow(clippy::identity_op)]
148 A::Write(0x01, 13, (0b00 << 14) | 27),
149 A::Write(0x01, 14, 0x1234),
150 A::Write(0x01, 13, (0b11 << 14) | 27),
151 A::Read(0x01, 14)
152 ]
153 );
154 }
155
156 #[futures_test::test]
157 async fn write_test() {
158 let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
159
160 mdiobus.clear();
161 mdiobus.write_cl22(0x01, 0x00, 0xABCD).await.unwrap();
162 assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]);
163
164 mdiobus.clear();
165 mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).await.unwrap();
166 assert_eq!(
167 mdiobus.0,
168 vec![
169 A::Write(0x01, 13, 27),
170 A::Write(0x01, 14, 0x1234),
171 A::Write(0x01, 13, (0b01 << 14) | 27),
172 A::Write(0x01, 14, 0xABCD)
173 ]
174 );
175 }
176}
diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs
new file mode 100644
index 000000000..d54d843d2
--- /dev/null
+++ b/embassy-net-adin1110/src/phy.rs
@@ -0,0 +1,143 @@
1use crate::mdio::MdioBus;
2
3#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
4#[repr(u8)]
5/// Clause 22 Registers
6pub enum RegsC22 {
7 /// MII Control Register
8 CONTROL = 0x00,
9 /// MII Status Register
10 STATUS = 0x01,
11 /// PHY Identifier 1 Register
12 PHY_ID1 = 0x02,
13 /// PHY Identifier 2 Register.
14 PHY_ID2 = 0x03,
15}
16
17/// Clause 45 Registers
18#[allow(non_snake_case, dead_code)]
19pub mod RegsC45 {
20 /// Device Address: 0x01
21 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
22 #[repr(u16)]
23 pub enum DA1 {
24 /// PMA/PMD Control 1 Register
25 PMA_PMD_CNTRL1 = 0x0000,
26 /// PMA/PMD Status 1 Register
27 PMA_PMD_STAT1 = 0x0001,
28 /// MSE Value Register
29 MSE_VAL = 0x830B,
30 }
31
32 impl DA1 {
33 #[must_use]
34 pub fn into(self) -> (u8, u16) {
35 (0x01, self as u16)
36 }
37 }
38
39 /// Device Address: 0x03
40 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
41 #[repr(u16)]
42 pub enum DA3 {
43 /// PCS Control 1 Register
44 PCS_CNTRL1 = 0x0000,
45 /// PCS Status 1 Register
46 PCS_STAT1 = 0x0001,
47 /// PCS Status 2 Register
48 PCS_STAT2 = 0x0008,
49 }
50
51 impl DA3 {
52 #[must_use]
53 pub fn into(self) -> (u8, u16) {
54 (0x03, self as u16)
55 }
56 }
57
58 /// Device Address: 0x07
59 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
60 #[repr(u16)]
61 pub enum DA7 {
62 /// Extra Autonegotiation Status Register
63 AN_STATUS_EXTRA = 0x8001,
64 }
65
66 impl DA7 {
67 #[must_use]
68 pub fn into(self) -> (u8, u16) {
69 (0x07, self as u16)
70 }
71 }
72
73 /// Device Address: 0x1E
74 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
75 #[repr(u16)]
76 pub enum DA1E {
77 /// System Interrupt Status Register
78 CRSM_IRQ_STATUS = 0x0010,
79 /// System Interrupt Mask Register
80 CRSM_IRQ_MASK = 0x0020,
81 /// Pin Mux Configuration 1 Register
82 DIGIO_PINMUX = 0x8c56,
83 /// LED Control Register.
84 LED_CNTRL = 0x8C82,
85 /// LED Polarity Register
86 LED_POLARITY = 0x8C83,
87 }
88
89 impl DA1E {
90 #[must_use]
91 pub fn into(self) -> (u8, u16) {
92 (0x1e, self as u16)
93 }
94 }
95
96 /// Device Address: 0x1F
97 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
98 #[repr(u16)]
99 pub enum DA1F {
100 /// PHY Subsystem Interrupt Status Register
101 PHY_SYBSYS_IRQ_STATUS = 0x0011,
102 /// PHY Subsystem Interrupt Mask Register
103 PHY_SYBSYS_IRQ_MASK = 0x0021,
104 }
105
106 impl DA1F {
107 #[must_use]
108 pub fn into(self) -> (u8, u16) {
109 (0x1f, self as u16)
110 }
111 }
112}
113
114/// 10-BASE-T1x PHY functions.
115pub struct Phy10BaseT1x(u8);
116
117impl Default for Phy10BaseT1x {
118 fn default() -> Self {
119 Self(0x01)
120 }
121}
122
123impl Phy10BaseT1x {
124 /// Get the both parts of the PHYID.
125 pub async fn get_id<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u32, MDE>
126 where
127 MDIOBUS: MdioBus<Error = MDE>,
128 MDE: core::fmt::Debug,
129 {
130 let mut phyid = u32::from(mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await?) << 16;
131 phyid |= u32::from(mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await?);
132 Ok(phyid)
133 }
134
135 /// Get the Mean Squared Error Value.
136 pub async fn get_sqi<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u16, MDE>
137 where
138 MDIOBUS: MdioBus<Error = MDE>,
139 MDE: core::fmt::Debug,
140 {
141 mdiobus.read_cl45(self.0, RegsC45::DA1::MSE_VAL.into()).await
142 }
143}
diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs
new file mode 100644
index 000000000..beaf9466e
--- /dev/null
+++ b/embassy-net-adin1110/src/regs.rs
@@ -0,0 +1,416 @@
1use core::fmt::{Debug, Display};
2
3use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
4
5#[allow(non_camel_case_types)]
6#[derive(Debug, Copy, Clone)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8#[repr(u16)]
9/// SPI REGISTER DETAILS
10/// Table 38.
11pub enum SpiRegisters {
12 IDVER = 0x00,
13 PHYID = 0x01,
14 CAPABILITY = 0x02,
15 RESET = 0x03,
16 CONFIG0 = 0x04,
17 CONFIG2 = 0x06,
18 STATUS0 = 0x08,
19 STATUS1 = 0x09,
20 IMASK0 = 0x0C,
21 IMASK1 = 0x0D,
22 MDIO_ACC = 0x20,
23 TX_FSIZE = 0x30,
24 TX = 0x31,
25 TX_SPACE = 0x32,
26 FIFO_CLR = 0x36,
27 ADDR_FILT_UPR0 = 0x50,
28 ADDR_FILT_LWR0 = 0x51,
29 ADDR_FILT_UPR1 = 0x52,
30 ADDR_FILT_LWR1 = 0x53,
31 ADDR_MSK_LWR0 = 0x70,
32 ADDR_MSK_UPR0 = 0x71,
33 ADDR_MSK_LWR1 = 0x72,
34 ADDR_MSK_UPR1 = 0x73,
35 RX_FSIZE = 0x90,
36 RX = 0x91,
37}
38
39impl Display for SpiRegisters {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 write!(f, "{self:?}")
42 }
43}
44
45impl From<SpiRegisters> for u16 {
46 fn from(val: SpiRegisters) -> Self {
47 val as u16
48 }
49}
50
51impl From<u16> for SpiRegisters {
52 fn from(value: u16) -> Self {
53 match value {
54 0x00 => Self::IDVER,
55 0x01 => Self::PHYID,
56 0x02 => Self::CAPABILITY,
57 0x03 => Self::RESET,
58 0x04 => Self::CONFIG0,
59 0x06 => Self::CONFIG2,
60 0x08 => Self::STATUS0,
61 0x09 => Self::STATUS1,
62 0x0C => Self::IMASK0,
63 0x0D => Self::IMASK1,
64 0x20 => Self::MDIO_ACC,
65 0x30 => Self::TX_FSIZE,
66 0x31 => Self::TX,
67 0x32 => Self::TX_SPACE,
68 0x36 => Self::FIFO_CLR,
69 0x50 => Self::ADDR_FILT_UPR0,
70 0x51 => Self::ADDR_FILT_LWR0,
71 0x52 => Self::ADDR_FILT_UPR1,
72 0x53 => Self::ADDR_FILT_LWR1,
73 0x70 => Self::ADDR_MSK_LWR0,
74 0x71 => Self::ADDR_MSK_UPR0,
75 0x72 => Self::ADDR_MSK_LWR1,
76 0x73 => Self::ADDR_MSK_UPR1,
77 0x90 => Self::RX_FSIZE,
78 0x91 => Self::RX,
79 e => panic!("Unknown value {}", e),
80 }
81 }
82}
83
84// Register definitions
85bitfield! {
86 /// Status0 Register bits
87 pub struct Status0(u32);
88 impl Debug;
89 u32;
90 /// Control Data Protection Error
91 pub cdpe, _ : 12;
92 /// Transmit Frame Check Squence Error
93 pub txfcse, _: 11;
94 /// Transmit Time Stamp Capture Available C
95 pub ttscac, _ : 10;
96 /// Transmit Time Stamp Capture Available B
97 pub ttscab, _ : 9;
98 /// Transmit Time Stamp Capture Available A
99 pub ttscaa, _ : 8;
100 /// PHY Interrupt for Port 1
101 pub phyint, _ : 7;
102 /// Reset Complete
103 pub resetc, _ : 6;
104 /// Header error
105 pub hdre, _ : 5;
106 /// Loss of Frame Error
107 pub lofe, _ : 4;
108 /// Receiver Buffer Overflow Error
109 pub rxboe, _ : 3;
110 /// Host Tx FIFO Under Run Error
111 pub txbue, _ : 2;
112 /// Host Tx FIFO Overflow
113 pub txboe, _ : 1;
114 /// Transmit Protocol Error
115 pub txpe, _ : 0;
116}
117
118bitfield! {
119 /// Status1 Register bits
120 pub struct Status1(u32);
121 impl Debug;
122 u32;
123 /// ECC Error on Reading the Frame Size from a Tx FIFO
124 pub tx_ecc_err, set_tx_ecc_err: 12;
125 /// ECC Error on Reading the Frame Size from an Rx FIFO
126 pub rx_ecc_err, set_rx_ecc_err : 11;
127 /// Detected an Error on an SPI Transaction
128 pub spi_err, set_spi_err: 10;
129 /// Rx MAC Interframe Gap Error
130 pub p1_rx_ifg_err, set_p1_rx_ifg_err : 8;
131 /// Port1 Rx Ready High Priority
132 pub p1_rx_rdy_hi, set_p1_rx_rdy_hi : 5;
133 /// Port 1 Rx FIFO Contains Data
134 pub p1_rx_rdy, set_p1_rx_rdy : 4;
135 /// Tx Ready
136 pub tx_rdy, set_tx_rdy : 3;
137 /// Link Status Changed
138 pub link_change, set_link_change : 1;
139 /// Port 1 Link Status
140 pub p1_link_status, _ : 0;
141}
142
143bitfield! {
144 /// Config0 Register bits
145 pub struct Config0(u32);
146 impl Debug;
147 u32;
148 /// Configuration Synchronization
149 pub sync, set_sync : 15;
150 /// Transmit Frame Check Sequence Validation Enable
151 pub txfcsve, set_txfcsve : 14;
152 /// !CS Align Receive Frame Enable
153 pub csarfe, set_csarfe : 13;
154 /// Zero Align Receive Frame Enable
155 pub zarfe, set_zarfe : 12;
156 /// Transmit Credit Threshold
157 pub tcxthresh, set_tcxthresh : 11, 10;
158 /// Transmit Cut Through Enable
159 pub txcte, set_txcte : 9;
160 /// Receive Cut Through Enable
161 pub rxcte, set_rxcte : 8;
162 /// Frame Time Stamp Enable
163 pub ftse, set_ftse : 7;
164 /// Receive Frame Time Stamp Select
165 pub ftss, set_ftss : 6;
166 /// Enable Control Data Read Write Protection
167 pub prote, set_prote : 5;
168 /// Enable TX Data Chunk Sequence and Retry
169 pub seqe, set_seqe : 4;
170 /// Chunk Payload Selector (N).
171 pub cps, set_cps : 2, 0;
172}
173
174bitfield! {
175 /// Config2 Register bits
176 pub struct Config2(u32);
177 impl Debug;
178 u32;
179 /// Assert TX_RDY When the Tx FIFO is Empty
180 pub tx_rdy_on_empty, set_tx_rdy_on_empty : 8;
181 /// Determines If the SFD is Detected in the PHY or MAC
182 pub sdf_detect_src, set_sdf_detect_src : 7;
183 /// Statistics Clear on Reading
184 pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
185 /// Enable SPI CRC
186 pub crc_append, set_crc_append : 5;
187 /// Admit Frames with IFG Errors on Port 1 (P1)
188 pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
189 /// Forward Frames Not Matching Any MAC Address to the Host
190 pub p1_fwd_unk2host, set_p1_fwd_unk2host : 2;
191 /// SPI to MDIO Bridge MDC Clock Speed
192 pub mspeed, set_mspeed : 0;
193}
194
195bitfield! {
196 /// IMASK0 Register bits
197 pub struct IMask0(u32);
198 impl Debug;
199 u32;
200 /// Control Data Protection Error Mask
201 pub cppem, set_cppem : 12;
202 /// Transmit Frame Check Sequence Error Mask
203 pub txfcsem, set_txfcsem : 11;
204 /// Transmit Time Stamp Capture Available C Mask
205 pub ttscacm, set_ttscacm : 10;
206 /// Transmit Time Stamp Capture Available B Mask
207 pub ttscabm, set_ttscabm : 9;
208 /// Transmit Time Stamp Capture Available A Mask
209 pub ttscaam, set_ttscaam : 8;
210 /// Physical Layer Interrupt Mask
211 pub phyintm, set_phyintm : 7;
212 /// RESET Complete Mask
213 pub resetcm, set_resetcm : 6;
214 /// Header Error Mask
215 pub hdrem, set_hdrem : 5;
216 /// Loss of Frame Error Mask
217 pub lofem, set_lofem : 4;
218 /// Receive Buffer Overflow Error Mask
219 pub rxboem, set_rxboem : 3;
220 /// Transmit Buffer Underflow Error Mask
221 pub txbuem, set_txbuem : 2;
222 /// Transmit Buffer Overflow Error Mask
223 pub txboem, set_txboem : 1;
224 /// Transmit Protocol Error Mask
225 pub txpem, set_txpem : 0;
226}
227
228bitfield! {
229 /// IMASK1 Register bits
230 pub struct IMask1(u32);
231 impl Debug;
232 u32;
233 /// Mask Bit for TXF_ECC_ERR
234 pub tx_ecc_err_mask, set_tx_ecc_err_mask : 12;
235 /// Mask Bit for RXF_ECC_ERR
236 pub rx_ecc_err_mask, set_rx_ecc_err_mask : 11;
237 /// Mask Bit for SPI_ERR
238 /// This field is only used with the generic SPI protocol
239 pub spi_err_mask, set_spi_err_mask : 10;
240 /// Mask Bit for RX_IFG_ERR
241 pub p1_rx_ifg_err_mask, set_p1_rx_ifg_err_mask : 8;
242 /// Mask Bit for P1_RX_RDY
243 /// This field is only used with the generic SPI protocol
244 pub p1_rx_rdy_mask, set_p1_rx_rdy_mask : 4;
245 /// Mask Bit for TX_FRM_DONE
246 /// This field is only used with the generic SPI protocol
247 pub tx_rdy_mask, set_tx_rdy_mask : 3;
248 /// Mask Bit for LINK_CHANGE
249 pub link_change_mask, set_link_change_mask : 1;
250}
251
252/// LED Functions
253#[repr(u8)]
254pub enum LedFunc {
255 LinkupTxRxActicity = 0,
256 LinkupTxActicity,
257 LinkupRxActicity,
258 LinkupOnly,
259 TxRxActivity,
260 TxActivity,
261 RxActivity,
262 LinkupRxEr,
263 LinkupRxTxEr,
264 RxEr,
265 RxTxEr,
266 TxSop,
267 RxSop,
268 On,
269 Off,
270 Blink,
271 TxLevel2P4,
272 TxLevel1P0,
273 Master,
274 Slave,
275 IncompatiableLinkCfg,
276 AnLinkGood,
277 AnComplete,
278 TsTimer,
279 LocRcvrStatus,
280 RemRcvrStatus,
281 Clk25Ref,
282 TxTCLK,
283 Clk120MHz,
284}
285
286impl From<LedFunc> for u8 {
287 fn from(val: LedFunc) -> Self {
288 val as u8
289 }
290}
291
292impl From<u8> for LedFunc {
293 fn from(value: u8) -> Self {
294 match value {
295 0 => LedFunc::LinkupTxRxActicity,
296 1 => LedFunc::LinkupTxActicity,
297 2 => LedFunc::LinkupRxActicity,
298 3 => LedFunc::LinkupOnly,
299 4 => LedFunc::TxRxActivity,
300 5 => LedFunc::TxActivity,
301 6 => LedFunc::RxActivity,
302 7 => LedFunc::LinkupRxEr,
303 8 => LedFunc::LinkupRxTxEr,
304 9 => LedFunc::RxEr,
305 10 => LedFunc::RxTxEr,
306 11 => LedFunc::TxSop,
307 12 => LedFunc::RxSop,
308 13 => LedFunc::On,
309 14 => LedFunc::Off,
310 15 => LedFunc::Blink,
311 16 => LedFunc::TxLevel2P4,
312 17 => LedFunc::TxLevel1P0,
313 18 => LedFunc::Master,
314 19 => LedFunc::Slave,
315 20 => LedFunc::IncompatiableLinkCfg,
316 21 => LedFunc::AnLinkGood,
317 22 => LedFunc::AnComplete,
318 23 => LedFunc::TsTimer,
319 24 => LedFunc::LocRcvrStatus,
320 25 => LedFunc::RemRcvrStatus,
321 26 => LedFunc::Clk25Ref,
322 27 => LedFunc::TxTCLK,
323 28 => LedFunc::Clk120MHz,
324 e => panic!("Invalid value {}", e),
325 }
326 }
327}
328
329/// LED Control Register
330#[derive(Copy, Clone, PartialEq, Eq, Hash)]
331pub struct LedCntrl(pub u16);
332bitfield_bitrange! {struct LedCntrl(u16)}
333
334impl LedCntrl {
335 bitfield_fields! {
336 u8;
337 /// LED 0 Pin Function
338 pub from into LedFunc, led0_function, set_led0_function: 4, 0;
339 /// LED 0 Mode Selection
340 pub led0_mode, set_led0_mode: 5;
341 /// Qualify Certain LED 0 Options with Link Status.
342 pub led0_link_st_qualify, set_led0_link_st_qualify: 6;
343 /// LED 0 Enable
344 pub led0_en, set_led0_en: 7;
345 /// LED 1 Pin Function
346 pub from into LedFunc, led1_function, set_led1_function: 12, 8;
347 /// /// LED 1 Mode Selection
348 pub led1_mode, set_led1_mode: 13;
349 /// Qualify Certain LED 1 Options with Link Status.
350 pub led1_link_st_qualify, set_led1_link_st_qualify: 14;
351 /// LED 1 Enable
352 pub led1_en, set_led1_en: 15;
353 }
354
355 pub fn new() -> Self {
356 LedCntrl(0)
357 }
358}
359
360// LED Polarity
361#[repr(u8)]
362pub enum LedPol {
363 AutoSense = 0,
364 ActiveHigh,
365 ActiveLow,
366}
367
368impl From<LedPol> for u8 {
369 fn from(val: LedPol) -> Self {
370 val as u8
371 }
372}
373
374impl From<u8> for LedPol {
375 fn from(value: u8) -> Self {
376 match value {
377 0 => LedPol::AutoSense,
378 1 => LedPol::ActiveHigh,
379 2 => LedPol::ActiveLow,
380 e => panic!("Invalid value {}", e),
381 }
382 }
383}
384
385/// LED Control Register
386#[derive(Copy, Clone, PartialEq, Eq, Hash)]
387pub struct LedPolarity(pub u16);
388bitfield_bitrange! {struct LedPolarity(u16)}
389
390impl LedPolarity {
391 bitfield_fields! {
392 u8;
393 /// LED 1 Polarity
394 pub from into LedPol, led1_polarity, set_led1_polarity: 3, 2;
395 /// LED 0 Polarity
396 pub from into LedPol, led0_polarity, set_led0_polarity: 1, 0;
397 }
398}
399
400/// SPI Header
401#[derive(Copy, Clone, PartialEq, Eq, Hash)]
402pub struct SpiHeader(pub u16);
403bitfield_bitrange! {struct SpiHeader(u16)}
404
405impl SpiHeader {
406 bitfield_fields! {
407 u16;
408 /// Mask Bit for TXF_ECC_ERR
409 pub control, set_control : 15;
410 pub full_duplex, set_full_duplex : 14;
411 /// Read or Write to register
412 pub write, set_write : 13;
413 /// Registers ID/addr
414 pub from into SpiRegisters, addr, set_addr: 11, 0;
415 }
416}
diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml
index bee2e3021..4588af02d 100644
--- a/embassy-net-driver-channel/Cargo.toml
+++ b/embassy-net-driver-channel/Cargo.toml
@@ -24,6 +24,6 @@ features = ["defmt"]
24defmt = { version = "0.3", optional = true } 24defmt = { version = "0.3", optional = true }
25log = { version = "0.4.14", optional = true } 25log = { version = "0.4.14", optional = true }
26 26
27embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
28embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 28embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
29embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 29embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
diff --git a/embassy-net-driver-channel/src/fmt.rs b/embassy-net-driver-channel/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-net-driver-channel/src/fmt.rs
+++ b/embassy-net-driver-channel/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs
index 076238ba0..bf7ae5217 100644
--- a/embassy-net-driver-channel/src/lib.rs
+++ b/embassy-net-driver-channel/src/lib.rs
@@ -8,11 +8,13 @@ use core::cell::RefCell;
8use core::mem::MaybeUninit; 8use core::mem::MaybeUninit;
9use core::task::{Context, Poll}; 9use core::task::{Context, Poll};
10 10
11use driver::HardwareAddress;
11pub use embassy_net_driver as driver; 12pub use embassy_net_driver as driver;
12use embassy_net_driver::{Capabilities, LinkState, Medium}; 13use embassy_net_driver::{Capabilities, LinkState, Medium};
13use embassy_sync::blocking_mutex::raw::NoopRawMutex; 14use embassy_sync::blocking_mutex::raw::NoopRawMutex;
14use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
15use embassy_sync::waitqueue::WakerRegistration; 16use embassy_sync::waitqueue::WakerRegistration;
17use embassy_sync::zerocopy_channel;
16 18
17pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { 19pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
18 rx: [PacketBuf<MTU>; N_RX], 20 rx: [PacketBuf<MTU>; N_RX],
@@ -73,6 +75,18 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
73 ) 75 )
74 } 76 }
75 77
78 pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) {
79 (
80 StateRunner { shared: self.shared },
81 RxRunner {
82 rx_chan: self.rx_chan.borrow(),
83 },
84 TxRunner {
85 tx_chan: self.tx_chan.borrow(),
86 },
87 )
88 }
89
76 pub fn state_runner(&self) -> StateRunner<'d> { 90 pub fn state_runner(&self) -> StateRunner<'d> {
77 StateRunner { shared: self.shared } 91 StateRunner { shared: self.shared }
78 } 92 }
@@ -117,24 +131,24 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
117 } 131 }
118 132
119 pub async fn tx_buf(&mut self) -> &mut [u8] { 133 pub async fn tx_buf(&mut self) -> &mut [u8] {
120 let p = self.tx_chan.recv().await; 134 let p = self.tx_chan.receive().await;
121 &mut p.buf[..p.len] 135 &mut p.buf[..p.len]
122 } 136 }
123 137
124 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { 138 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
125 let p = self.tx_chan.try_recv()?; 139 let p = self.tx_chan.try_receive()?;
126 Some(&mut p.buf[..p.len]) 140 Some(&mut p.buf[..p.len])
127 } 141 }
128 142
129 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 143 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
130 match self.tx_chan.poll_recv(cx) { 144 match self.tx_chan.poll_receive(cx) {
131 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), 145 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
132 Poll::Pending => Poll::Pending, 146 Poll::Pending => Poll::Pending,
133 } 147 }
134 } 148 }
135 149
136 pub fn tx_done(&mut self) { 150 pub fn tx_done(&mut self) {
137 self.tx_chan.recv_done(); 151 self.tx_chan.receive_done();
138 } 152 }
139} 153}
140 154
@@ -191,24 +205,24 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
191 205
192impl<'d, const MTU: usize> TxRunner<'d, MTU> { 206impl<'d, const MTU: usize> TxRunner<'d, MTU> {
193 pub async fn tx_buf(&mut self) -> &mut [u8] { 207 pub async fn tx_buf(&mut self) -> &mut [u8] {
194 let p = self.tx_chan.recv().await; 208 let p = self.tx_chan.receive().await;
195 &mut p.buf[..p.len] 209 &mut p.buf[..p.len]
196 } 210 }
197 211
198 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { 212 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
199 let p = self.tx_chan.try_recv()?; 213 let p = self.tx_chan.try_receive()?;
200 Some(&mut p.buf[..p.len]) 214 Some(&mut p.buf[..p.len])
201 } 215 }
202 216
203 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 217 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
204 match self.tx_chan.poll_recv(cx) { 218 match self.tx_chan.poll_receive(cx) {
205 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), 219 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
206 Poll::Pending => Poll::Pending, 220 Poll::Pending => Poll::Pending,
207 } 221 }
208 } 222 }
209 223
210 pub fn tx_done(&mut self) { 224 pub fn tx_done(&mut self) {
211 self.tx_chan.recv_done(); 225 self.tx_chan.receive_done();
212 } 226 }
213} 227}
214 228
@@ -218,7 +232,11 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
218) -> (Runner<'d, MTU>, Device<'d, MTU>) { 232) -> (Runner<'d, MTU>, Device<'d, MTU>) {
219 let mut caps = Capabilities::default(); 233 let mut caps = Capabilities::default();
220 caps.max_transmission_unit = MTU; 234 caps.max_transmission_unit = MTU;
221 caps.medium = Medium::Ethernet; 235 caps.medium = match &hardware_address {
236 HardwareAddress::Ethernet(_) => Medium::Ethernet,
237 HardwareAddress::Ieee802154(_) => Medium::Ieee802154,
238 HardwareAddress::Ip => Medium::Ip,
239 };
222 240
223 // safety: this is a self-referential struct, however: 241 // safety: this is a self-referential struct, however:
224 // - it can't move while the `'d` borrow is active. 242 // - it can't move while the `'d` borrow is active.
@@ -276,7 +294,7 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
276 type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ; 294 type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ;
277 295
278 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 296 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
279 if self.rx.poll_recv(cx).is_ready() && self.tx.poll_send(cx).is_ready() { 297 if self.rx.poll_receive(cx).is_ready() && self.tx.poll_send(cx).is_ready() {
280 Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() })) 298 Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() }))
281 } else { 299 } else {
282 None 300 None
@@ -320,9 +338,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
320 F: FnOnce(&mut [u8]) -> R, 338 F: FnOnce(&mut [u8]) -> R,
321 { 339 {
322 // NOTE(unwrap): we checked the queue wasn't full when creating the token. 340 // NOTE(unwrap): we checked the queue wasn't full when creating the token.
323 let pkt = unwrap!(self.rx.try_recv()); 341 let pkt = unwrap!(self.rx.try_receive());
324 let r = f(&mut pkt.buf[..pkt.len]); 342 let r = f(&mut pkt.buf[..pkt.len]);
325 self.rx.recv_done(); 343 self.rx.receive_done();
326 r 344 r
327 } 345 }
328} 346}
@@ -344,215 +362,3 @@ impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> {
344 r 362 r
345 } 363 }
346} 364}
347
348mod zerocopy_channel {
349 use core::cell::RefCell;
350 use core::future::poll_fn;
351 use core::marker::PhantomData;
352 use core::task::{Context, Poll};
353
354 use embassy_sync::blocking_mutex::raw::RawMutex;
355 use embassy_sync::blocking_mutex::Mutex;
356 use embassy_sync::waitqueue::WakerRegistration;
357
358 pub struct Channel<'a, M: RawMutex, T> {
359 buf: *mut T,
360 phantom: PhantomData<&'a mut T>,
361 state: Mutex<M, RefCell<State>>,
362 }
363
364 impl<'a, M: RawMutex, T> Channel<'a, M, T> {
365 pub fn new(buf: &'a mut [T]) -> Self {
366 let len = buf.len();
367 assert!(len != 0);
368
369 Self {
370 buf: buf.as_mut_ptr(),
371 phantom: PhantomData,
372 state: Mutex::new(RefCell::new(State {
373 len,
374 front: 0,
375 back: 0,
376 full: false,
377 send_waker: WakerRegistration::new(),
378 recv_waker: WakerRegistration::new(),
379 })),
380 }
381 }
382
383 pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) {
384 (Sender { channel: self }, Receiver { channel: self })
385 }
386 }
387
388 pub struct Sender<'a, M: RawMutex, T> {
389 channel: &'a Channel<'a, M, T>,
390 }
391
392 impl<'a, M: RawMutex, T> Sender<'a, M, T> {
393 pub fn borrow(&mut self) -> Sender<'_, M, T> {
394 Sender { channel: self.channel }
395 }
396
397 pub fn try_send(&mut self) -> Option<&mut T> {
398 self.channel.state.lock(|s| {
399 let s = &mut *s.borrow_mut();
400 match s.push_index() {
401 Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
402 None => None,
403 }
404 })
405 }
406
407 pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> {
408 self.channel.state.lock(|s| {
409 let s = &mut *s.borrow_mut();
410 match s.push_index() {
411 Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
412 None => {
413 s.recv_waker.register(cx.waker());
414 Poll::Pending
415 }
416 }
417 })
418 }
419
420 pub async fn send(&mut self) -> &mut T {
421 let i = poll_fn(|cx| {
422 self.channel.state.lock(|s| {
423 let s = &mut *s.borrow_mut();
424 match s.push_index() {
425 Some(i) => Poll::Ready(i),
426 None => {
427 s.recv_waker.register(cx.waker());
428 Poll::Pending
429 }
430 }
431 })
432 })
433 .await;
434 unsafe { &mut *self.channel.buf.add(i) }
435 }
436
437 pub fn send_done(&mut self) {
438 self.channel.state.lock(|s| s.borrow_mut().push_done())
439 }
440 }
441 pub struct Receiver<'a, M: RawMutex, T> {
442 channel: &'a Channel<'a, M, T>,
443 }
444
445 impl<'a, M: RawMutex, T> Receiver<'a, M, T> {
446 pub fn borrow(&mut self) -> Receiver<'_, M, T> {
447 Receiver { channel: self.channel }
448 }
449
450 pub fn try_recv(&mut self) -> Option<&mut T> {
451 self.channel.state.lock(|s| {
452 let s = &mut *s.borrow_mut();
453 match s.pop_index() {
454 Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
455 None => None,
456 }
457 })
458 }
459
460 pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> {
461 self.channel.state.lock(|s| {
462 let s = &mut *s.borrow_mut();
463 match s.pop_index() {
464 Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
465 None => {
466 s.send_waker.register(cx.waker());
467 Poll::Pending
468 }
469 }
470 })
471 }
472
473 pub async fn recv(&mut self) -> &mut T {
474 let i = poll_fn(|cx| {
475 self.channel.state.lock(|s| {
476 let s = &mut *s.borrow_mut();
477 match s.pop_index() {
478 Some(i) => Poll::Ready(i),
479 None => {
480 s.send_waker.register(cx.waker());
481 Poll::Pending
482 }
483 }
484 })
485 })
486 .await;
487 unsafe { &mut *self.channel.buf.add(i) }
488 }
489
490 pub fn recv_done(&mut self) {
491 self.channel.state.lock(|s| s.borrow_mut().pop_done())
492 }
493 }
494
495 struct State {
496 len: usize,
497
498 /// Front index. Always 0..=(N-1)
499 front: usize,
500 /// Back index. Always 0..=(N-1).
501 back: usize,
502
503 /// Used to distinguish "empty" and "full" cases when `front == back`.
504 /// May only be `true` if `front == back`, always `false` otherwise.
505 full: bool,
506
507 send_waker: WakerRegistration,
508 recv_waker: WakerRegistration,
509 }
510
511 impl State {
512 fn increment(&self, i: usize) -> usize {
513 if i + 1 == self.len {
514 0
515 } else {
516 i + 1
517 }
518 }
519
520 fn is_full(&self) -> bool {
521 self.full
522 }
523
524 fn is_empty(&self) -> bool {
525 self.front == self.back && !self.full
526 }
527
528 fn push_index(&mut self) -> Option<usize> {
529 match self.is_full() {
530 true => None,
531 false => Some(self.back),
532 }
533 }
534
535 fn push_done(&mut self) {
536 assert!(!self.is_full());
537 self.back = self.increment(self.back);
538 if self.back == self.front {
539 self.full = true;
540 }
541 self.send_waker.wake();
542 }
543
544 fn pop_index(&mut self) -> Option<usize> {
545 match self.is_empty() {
546 true => None,
547 false => Some(self.front),
548 }
549 }
550
551 fn pop_done(&mut self) {
552 assert!(!self.is_empty());
553 self.front = self.increment(self.front);
554 self.full = false;
555 self.recv_waker.wake();
556 }
557 }
558}
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
index e02c984e9..161d055c0 100644
--- a/embassy-net-enc28j60/Cargo.toml
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2021"
11embedded-hal = { version = "1.0.0-rc.1" } 11embedded-hal = { version = "1.0.0-rc.1" }
12embedded-hal-async = { version = "=1.0.0-rc.1" } 12embedded-hal-async = { version = "=1.0.0-rc.1" }
13embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 13embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
14embassy-time = { version = "0.1.2", path = "../embassy-time" } 14embassy-time = { version = "0.1.3", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
16 16
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
@@ -20,4 +20,4 @@ log = { version = "0.4.14", optional = true }
20[package.metadata.embassy_docs] 20[package.metadata.embassy_docs]
21src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" 21src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/"
22src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" 22src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/"
23target = "thumbv7em-none-eabi" \ No newline at end of file 23target = "thumbv7em-none-eabi"
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-net-enc28j60/src/fmt.rs
+++ b/embassy-net-enc28j60/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs
index b44cefaf2..f96a6ff14 100644
--- a/embassy-net-enc28j60/src/lib.rs
+++ b/embassy-net-enc28j60/src/lib.rs
@@ -194,10 +194,15 @@ where
194 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen()); 194 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
195 } 195 }
196 196
197 /// Returns the device's MAC address
198 pub fn address(&self) -> [u8; 6] {
199 self.mac_addr
200 }
201
197 /// Flushes the transmit buffer, ensuring all pending transmissions have completed 202 /// Flushes the transmit buffer, ensuring all pending transmissions have completed
198 /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always 203 /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
199 /// return `None` on subsequent invocations 204 /// return `None` on subsequent invocations
200 pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> { 205 pub fn receive(&mut self, buf: &mut [u8]) -> Option<usize> {
201 if self.pending_packets() == 0 { 206 if self.pending_packets() == 0 {
202 // Errata #6: we can't rely on PKTIF so we check PKTCNT 207 // Errata #6: we can't rely on PKTIF so we check PKTCNT
203 return None; 208 return None;
@@ -241,7 +246,7 @@ where
241 246
242 self.next_packet = next_packet; 247 self.next_packet = next_packet;
243 248
244 Some(&mut buf[..len as usize]) 249 Some(len as usize)
245 } 250 }
246 251
247 fn wait_tx_ready(&mut self) { 252 fn wait_tx_ready(&mut self) {
@@ -642,9 +647,8 @@ where
642 fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 647 fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
643 let rx_buf = unsafe { &mut RX_BUF }; 648 let rx_buf = unsafe { &mut RX_BUF };
644 let tx_buf = unsafe { &mut TX_BUF }; 649 let tx_buf = unsafe { &mut TX_BUF };
645 if let Some(pkt) = self.receive(rx_buf) { 650 if let Some(n) = self.receive(rx_buf) {
646 let n = pkt.len(); 651 Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self }))
647 Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
648 } else { 652 } else {
649 cx.waker().wake_by_ref(); 653 cx.waker().wake_by_ref();
650 None 654 None
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index d334cf3fe..54cd8859f 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -7,8 +7,8 @@ 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.2", path = "../embassy-time" } 10embassy-time = { version = "0.1.3", path = "../embassy-time" }
11embassy-sync = { version = "0.2.0", path = "../embassy-sync"} 11embassy-sync = { version = "0.3.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
@@ -23,4 +23,4 @@ heapless = "0.7.16"
23src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$VERSION/embassy-net-esp-hosted/src/" 23src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$VERSION/embassy-net-esp-hosted/src/"
24src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/" 24src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/"
25target = "thumbv7em-none-eabi" 25target = "thumbv7em-none-eabi"
26features = ["defmt"] \ No newline at end of file 26features = ["defmt"]
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index ce6636a8e..a4996b584 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -19,6 +19,8 @@ pub struct Control<'a> {
19} 19}
20 20
21#[allow(unused)] 21#[allow(unused)]
22#[derive(Copy, Clone, PartialEq, Eq, Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22enum WifiMode { 24enum WifiMode {
23 None = 0, 25 None = 0,
24 Sta = 1, 26 Sta = 1,
@@ -26,6 +28,18 @@ enum WifiMode {
26 ApSta = 3, 28 ApSta = 3,
27} 29}
28 30
31pub use proto::CtrlWifiSecProt as Security;
32
33#[derive(Clone, Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub struct Status {
36 pub ssid: String<32>,
37 pub bssid: [u8; 6],
38 pub rssi: i32,
39 pub channel: u32,
40 pub security: Security,
41}
42
29macro_rules! ioctl { 43macro_rules! ioctl {
30 ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => { 44 ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
31 let mut msg = proto::CtrlMsg { 45 let mut msg = proto::CtrlMsg {
@@ -34,7 +48,9 @@ macro_rules! ioctl {
34 payload: Some(proto::CtrlMsgPayload::$req_variant($req)), 48 payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
35 }; 49 };
36 $self.ioctl(&mut msg).await?; 50 $self.ioctl(&mut msg).await?;
37 let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else { 51 #[allow(unused_mut)]
52 let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload
53 else {
38 warn!("unexpected response variant"); 54 warn!("unexpected response variant");
39 return Err(Error::Internal); 55 return Err(Error::Internal);
40 }; 56 };
@@ -66,6 +82,19 @@ impl<'a> Control<'a> {
66 Ok(()) 82 Ok(())
67 } 83 }
68 84
85 pub async fn get_status(&mut self) -> Result<Status, Error> {
86 let req = proto::CtrlMsgReqGetApConfig {};
87 ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp);
88 trim_nulls(&mut resp.ssid);
89 Ok(Status {
90 ssid: resp.ssid,
91 bssid: parse_mac(&resp.bssid)?,
92 rssi: resp.rssi as _,
93 channel: resp.chnl,
94 security: resp.sec_prot,
95 })
96 }
97
69 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { 98 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
70 let req = proto::CtrlMsgReqConnectAp { 99 let req = proto::CtrlMsgReqConnectAp {
71 ssid: String::from(ssid), 100 ssid: String::from(ssid),
@@ -98,27 +127,7 @@ impl<'a> Control<'a> {
98 mode: WifiMode::Sta as _, 127 mode: WifiMode::Sta as _,
99 }; 128 };
100 ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp); 129 ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
101 130 parse_mac(&resp.mac)
102 // WHY IS THIS A STRING? WHYYYY
103 fn nibble_from_hex(b: u8) -> u8 {
104 match b {
105 b'0'..=b'9' => b - b'0',
106 b'a'..=b'f' => b + 0xa - b'a',
107 b'A'..=b'F' => b + 0xa - b'A',
108 _ => panic!("invalid hex digit {}", b),
109 }
110 }
111
112 let mac = resp.mac.as_bytes();
113 let mut res = [0; 6];
114 if mac.len() != 17 {
115 warn!("unexpected MAC respnse length");
116 return Err(Error::Internal);
117 }
118 for (i, b) in res.iter_mut().enumerate() {
119 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
120 }
121 Ok(res)
122 } 131 }
123 132
124 async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> { 133 async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
@@ -167,3 +176,35 @@ impl<'a> Control<'a> {
167 Ok(()) 176 Ok(())
168 } 177 }
169} 178}
179
180// WHY IS THIS A STRING? WHYYYY
181fn parse_mac(mac: &str) -> Result<[u8; 6], Error> {
182 fn nibble_from_hex(b: u8) -> Result<u8, Error> {
183 match b {
184 b'0'..=b'9' => Ok(b - b'0'),
185 b'a'..=b'f' => Ok(b + 0xa - b'a'),
186 b'A'..=b'F' => Ok(b + 0xa - b'A'),
187 _ => {
188 warn!("invalid hex digit {}", b);
189 Err(Error::Internal)
190 }
191 }
192 }
193
194 let mac = mac.as_bytes();
195 let mut res = [0; 6];
196 if mac.len() != 17 {
197 warn!("unexpected MAC length");
198 return Err(Error::Internal);
199 }
200 for (i, b) in res.iter_mut().enumerate() {
201 *b = (nibble_from_hex(mac[i * 3])? << 4) | nibble_from_hex(mac[i * 3 + 1])?
202 }
203 Ok(res)
204}
205
206fn trim_nulls<const N: usize>(s: &mut String<N>) {
207 while s.chars().rev().next() == Some(0 as char) {
208 s.pop();
209 }
210}
diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs
index 91984bde1..78e583c1c 100644
--- a/embassy-net-esp-hosted/src/fmt.rs
+++ b/embassy-net-esp-hosted/src/fmt.rs
@@ -93,7 +93,7 @@ macro_rules! unreachable {
93#[cfg(feature = "defmt")] 93#[cfg(feature = "defmt")]
94macro_rules! unreachable { 94macro_rules! unreachable {
95 ($($x:tt)*) => { 95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*); 96 ::defmt::unreachable!($($x)*)
97 }; 97 };
98} 98}
99 99
@@ -229,7 +229,8 @@ impl<T, E> Try for Result<T, E> {
229 } 229 }
230} 230}
231 231
232pub struct Bytes<'a>(pub &'a [u8]); 232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
233 234
234impl<'a> Debug for Bytes<'a> { 235impl<'a> Debug for Bytes<'a> {
235 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml
new file mode 100644
index 000000000..da09f780e
--- /dev/null
+++ b/embassy-net-ppp/Cargo.toml
@@ -0,0 +1,28 @@
1[package]
2name = "embassy-net-ppp"
3version = "0.1.0"
4description = "embassy-net driver for PPP over Serial"
5keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0"
8edition = "2021"
9
10[features]
11defmt = ["dep:defmt", "ppproto/defmt"]
12log = ["dep:log", "ppproto/log"]
13
14[dependencies]
15defmt = { version = "0.3", optional = true }
16log = { version = "0.4.14", optional = true }
17
18embedded-io-async = { version = "0.5.0" }
19embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
20embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
21ppproto = { version = "0.1.2"}
22embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
23
24[package.metadata.embassy_docs]
25src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/"
26src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-ppp/src/"
27target = "thumbv7em-none-eabi"
28features = ["defmt"]
diff --git a/embassy-net-ppp/README.md b/embassy-net-ppp/README.md
new file mode 100644
index 000000000..58d67395a
--- /dev/null
+++ b/embassy-net-ppp/README.md
@@ -0,0 +1,19 @@
1# `embassy-net-ppp`
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for PPP over Serial.
4
5## Interoperability
6
7This crate can run on any executor.
8
9It supports any serial port implementing [`embedded-io-async`](https://crates.io/crates/embedded-io-async).
10
11## License
12
13This work is licensed under either of
14
15- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
16 http://www.apache.org/licenses/LICENSE-2.0)
17- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
18
19at your option.
diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs
new file mode 100644
index 000000000..78e583c1c
--- /dev/null
+++ b/embassy-net-ppp/src/fmt.rs
@@ -0,0 +1,258 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86#[cfg(not(feature = "defmt"))]
87macro_rules! unreachable {
88 ($($x:tt)*) => {
89 ::core::unreachable!($($x)*)
90 };
91}
92
93#[cfg(feature = "defmt")]
94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
97 };
98}
99
100macro_rules! panic {
101 ($($x:tt)*) => {
102 {
103 #[cfg(not(feature = "defmt"))]
104 ::core::panic!($($x)*);
105 #[cfg(feature = "defmt")]
106 ::defmt::panic!($($x)*);
107 }
108 };
109}
110
111macro_rules! trace {
112 ($s:literal $(, $x:expr)* $(,)?) => {
113 {
114 #[cfg(feature = "log")]
115 ::log::trace!($s $(, $x)*);
116 #[cfg(feature = "defmt")]
117 ::defmt::trace!($s $(, $x)*);
118 #[cfg(not(any(feature = "log", feature="defmt")))]
119 let _ = ($( & $x ),*);
120 }
121 };
122}
123
124macro_rules! debug {
125 ($s:literal $(, $x:expr)* $(,)?) => {
126 {
127 #[cfg(feature = "log")]
128 ::log::debug!($s $(, $x)*);
129 #[cfg(feature = "defmt")]
130 ::defmt::debug!($s $(, $x)*);
131 #[cfg(not(any(feature = "log", feature="defmt")))]
132 let _ = ($( & $x ),*);
133 }
134 };
135}
136
137macro_rules! info {
138 ($s:literal $(, $x:expr)* $(,)?) => {
139 {
140 #[cfg(feature = "log")]
141 ::log::info!($s $(, $x)*);
142 #[cfg(feature = "defmt")]
143 ::defmt::info!($s $(, $x)*);
144 #[cfg(not(any(feature = "log", feature="defmt")))]
145 let _ = ($( & $x ),*);
146 }
147 };
148}
149
150macro_rules! warn {
151 ($s:literal $(, $x:expr)* $(,)?) => {
152 {
153 #[cfg(feature = "log")]
154 ::log::warn!($s $(, $x)*);
155 #[cfg(feature = "defmt")]
156 ::defmt::warn!($s $(, $x)*);
157 #[cfg(not(any(feature = "log", feature="defmt")))]
158 let _ = ($( & $x ),*);
159 }
160 };
161}
162
163macro_rules! error {
164 ($s:literal $(, $x:expr)* $(,)?) => {
165 {
166 #[cfg(feature = "log")]
167 ::log::error!($s $(, $x)*);
168 #[cfg(feature = "defmt")]
169 ::defmt::error!($s $(, $x)*);
170 #[cfg(not(any(feature = "log", feature="defmt")))]
171 let _ = ($( & $x ),*);
172 }
173 };
174}
175
176#[cfg(feature = "defmt")]
177macro_rules! unwrap {
178 ($($x:tt)*) => {
179 ::defmt::unwrap!($($x)*)
180 };
181}
182
183#[cfg(not(feature = "defmt"))]
184macro_rules! unwrap {
185 ($arg:expr) => {
186 match $crate::fmt::Try::into_result($arg) {
187 ::core::result::Result::Ok(t) => t,
188 ::core::result::Result::Err(e) => {
189 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
190 }
191 }
192 };
193 ($arg:expr, $($msg:expr),+ $(,)? ) => {
194 match $crate::fmt::Try::into_result($arg) {
195 ::core::result::Result::Ok(t) => t,
196 ::core::result::Result::Err(e) => {
197 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
198 }
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError;
205
206pub trait Try {
207 type Ok;
208 type Error;
209 fn into_result(self) -> Result<Self::Ok, Self::Error>;
210}
211
212impl<T> Try for Option<T> {
213 type Ok = T;
214 type Error = NoneError;
215
216 #[inline]
217 fn into_result(self) -> Result<T, NoneError> {
218 self.ok_or(NoneError)
219 }
220}
221
222impl<T, E> Try for Result<T, E> {
223 type Ok = T;
224 type Error = E;
225
226 #[inline]
227 fn into_result(self) -> Self {
228 self
229 }
230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs
new file mode 100644
index 000000000..66496ee0a
--- /dev/null
+++ b/embassy-net-ppp/src/lib.rs
@@ -0,0 +1,185 @@
1#![no_std]
2#![warn(missing_docs)]
3#![doc = include_str!("../README.md")]
4
5// must be first
6mod fmt;
7
8use core::convert::Infallible;
9use core::mem::MaybeUninit;
10
11use embassy_futures::select::{select, Either};
12use embassy_net_driver_channel as ch;
13use embassy_net_driver_channel::driver::LinkState;
14use embedded_io_async::{BufRead, Write, WriteAllError};
15use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
16pub use ppproto::{Config, Ipv4Status};
17
18const MTU: usize = 1500;
19
20/// Type alias for the embassy-net driver.
21pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
22
23/// Internal state for the embassy-net integration.
24pub struct State<const N_RX: usize, const N_TX: usize> {
25 ch_state: ch::State<MTU, N_RX, N_TX>,
26}
27
28impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
29 /// Create a new `State`.
30 pub const fn new() -> Self {
31 Self {
32 ch_state: ch::State::new(),
33 }
34 }
35}
36
37/// Background runner for the driver.
38///
39/// You must call `.run()` in a background task for the driver to operate.
40pub struct Runner<'d> {
41 ch: ch::Runner<'d, MTU>,
42}
43
44/// Error returned by [`Runner::run`].
45#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum RunError<E> {
48 /// Reading from the serial port failed.
49 Read(E),
50 /// Writing to the serial port failed.
51 Write(E),
52 /// Writing to the serial port wrote zero bytes, indicating it can't accept more data.
53 WriteZero,
54 /// Writing to the serial got EOF.
55 Eof,
56 /// PPP protocol was terminated by the peer
57 Terminated,
58}
59
60impl<E> From<WriteAllError<E>> for RunError<E> {
61 fn from(value: WriteAllError<E>) -> Self {
62 match value {
63 WriteAllError::Other(e) => Self::Write(e),
64 WriteAllError::WriteZero => Self::WriteZero,
65 }
66 }
67}
68
69impl<'d> Runner<'d> {
70 /// You must call this in a background task for the driver to operate.
71 ///
72 /// If reading/writing to the underlying serial port fails, the link state
73 /// is set to Down and the error is returned.
74 ///
75 /// It is allowed to cancel this function's future (i.e. drop it). This will terminate
76 /// the PPP connection and set the link state to Down.
77 ///
78 /// After this function returns or is canceled, you can call it again to establish
79 /// a new PPP connection.
80 pub async fn run<RW: BufRead + Write>(
81 &mut self,
82 mut rw: RW,
83 config: ppproto::Config<'_>,
84 mut on_ipv4_up: impl FnMut(Ipv4Status),
85 ) -> Result<Infallible, RunError<RW::Error>> {
86 let mut ppp = PPPoS::new(config);
87 ppp.open().unwrap();
88
89 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.borrow_split();
90 state_chan.set_link_state(LinkState::Down);
91 let _ondrop = OnDrop::new(|| state_chan.set_link_state(LinkState::Down));
92
93 let mut rx_buf = [0; 2048];
94 let mut tx_buf = [0; 2048];
95
96 let mut needs_poll = true;
97 let mut was_up = false;
98
99 loop {
100 let rx_fut = async {
101 let buf = rx_chan.rx_buf().await;
102 let rx_data = match needs_poll {
103 true => &[][..],
104 false => match rw.fill_buf().await {
105 Ok(rx_data) if rx_data.len() == 0 => return Err(RunError::Eof),
106 Ok(rx_data) => rx_data,
107 Err(e) => return Err(RunError::Read(e)),
108 },
109 };
110 Ok((buf, rx_data))
111 };
112 let tx_fut = tx_chan.tx_buf();
113 match select(rx_fut, tx_fut).await {
114 Either::First(r) => {
115 needs_poll = false;
116
117 let (buf, rx_data) = r?;
118 let n = ppp.consume(rx_data, &mut rx_buf);
119 rw.consume(n);
120
121 match ppp.poll(&mut tx_buf, &mut rx_buf) {
122 PPPoSAction::None => {}
123 PPPoSAction::Received(rg) => {
124 let pkt = &rx_buf[rg];
125 buf[..pkt.len()].copy_from_slice(pkt);
126 rx_chan.rx_done(pkt.len());
127 }
128 PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?,
129 }
130
131 let status = ppp.status();
132 match status.phase {
133 ppproto::Phase::Dead => {
134 return Err(RunError::Terminated);
135 }
136 ppproto::Phase::Open => {
137 if !was_up {
138 on_ipv4_up(status.ipv4.unwrap());
139 }
140 was_up = true;
141 state_chan.set_link_state(LinkState::Up);
142 }
143 _ => {
144 was_up = false;
145 state_chan.set_link_state(LinkState::Down);
146 }
147 }
148 }
149 Either::Second(pkt) => {
150 match ppp.send(pkt, &mut tx_buf) {
151 Ok(n) => rw.write_all(&tx_buf[..n]).await?,
152 Err(BufferFullError) => unreachable!(),
153 }
154 tx_chan.tx_done();
155 }
156 }
157 }
158 }
159}
160
161/// Create a PPP embassy-net driver instance.
162///
163/// This returns two structs:
164/// - a `Device` that you must pass to the `embassy-net` stack.
165/// - a `Runner`. You must call `.run()` on it in a background task.
166pub fn new<'a, const N_RX: usize, const N_TX: usize>(state: &'a mut State<N_RX, N_TX>) -> (Device<'a>, Runner<'a>) {
167 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ip);
168 (device, Runner { ch: runner })
169}
170
171struct OnDrop<F: FnOnce()> {
172 f: MaybeUninit<F>,
173}
174
175impl<F: FnOnce()> OnDrop<F> {
176 fn new(f: F) -> Self {
177 Self { f: MaybeUninit::new(f) }
178 }
179}
180
181impl<F: FnOnce()> Drop for OnDrop<F> {
182 fn drop(&mut self) {
183 unsafe { self.f.as_ptr().read()() }
184 }
185}
diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml
index adf0b45fc..afa0d5cd5 100644
--- a/embassy-net-wiznet/Cargo.toml
+++ b/embassy-net-wiznet/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2021"
11embedded-hal = { version = "1.0.0-rc.1" } 11embedded-hal = { version = "1.0.0-rc.1" }
12embedded-hal-async = { version = "=1.0.0-rc.1" } 12embedded-hal-async = { version = "=1.0.0-rc.1" }
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.2", path = "../embassy-time" } 14embassy-time = { version = "0.1.3", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
16defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
17 17
@@ -19,4 +19,4 @@ defmt = { version = "0.3", optional = true }
19src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" 19src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/"
20src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" 20src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/"
21target = "thumbv7em-none-eabi" 21target = "thumbv7em-none-eabi"
22features = ["defmt"] \ No newline at end of file 22features = ["defmt"]
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 0c551f204..8aca92a68 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -9,6 +9,7 @@ categories = [
9 "embedded", 9 "embedded",
10 "no-std", 10 "no-std",
11 "asynchronous", 11 "asynchronous",
12 "network-programming",
12] 13]
13 14
14[package.metadata.embassy_docs] 15[package.metadata.embassy_docs]
@@ -50,8 +51,8 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
50] } 51] }
51 52
52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 53embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
53embassy-time = { version = "0.1.2", path = "../embassy-time" } 54embassy-time = { version = "0.1.3", path = "../embassy-time" }
54embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 55embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
55embedded-io-async = { version = "0.5.0", optional = true } 56embedded-io-async = { version = "0.5.0", optional = true }
56 57
57managed = { version = "0.8.0", default-features = false, features = [ "map" ] } 58managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index d29ab8970..8c2b7d31a 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -22,13 +22,13 @@ where
22 22
23 fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 23 fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
24 self.inner 24 self.inner
25 .receive(self.cx.as_deref_mut().unwrap()) 25 .receive(unwrap!(self.cx.as_deref_mut()))
26 .map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx))) 26 .map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx)))
27 } 27 }
28 28
29 /// Construct a transmit token. 29 /// Construct a transmit token.
30 fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> { 30 fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
31 self.inner.transmit(self.cx.as_deref_mut().unwrap()).map(TxTokenAdapter) 31 self.inner.transmit(unwrap!(self.cx.as_deref_mut())).map(TxTokenAdapter)
32 } 32 }
33 33
34 /// Get a description of device capabilities. 34 /// Get a description of device capabilities.
diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-net/src/fmt.rs
+++ b/embassy-net/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 2fb34f43a..0d7ac47a2 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -3,6 +3,9 @@
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
5 5
6#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))]
7compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6");
8
6// This mod MUST go first, so that the others see its macros. 9// This mod MUST go first, so that the others see its macros.
7pub(crate) mod fmt; 10pub(crate) mod fmt;
8 11
@@ -20,7 +23,7 @@ use core::future::{poll_fn, Future};
20use core::task::{Context, Poll}; 23use core::task::{Context, Poll};
21 24
22pub use embassy_net_driver as driver; 25pub use embassy_net_driver as driver;
23use embassy_net_driver::{Driver, LinkState, Medium}; 26use embassy_net_driver::{Driver, LinkState};
24use embassy_sync::waitqueue::WakerRegistration; 27use embassy_sync::waitqueue::WakerRegistration;
25use embassy_time::{Instant, Timer}; 28use embassy_time::{Instant, Timer};
26use futures::pin_mut; 29use futures::pin_mut;
@@ -133,6 +136,8 @@ impl Default for DhcpConfig {
133} 136}
134 137
135/// Network stack configuration. 138/// Network stack configuration.
139#[derive(Debug, Clone, Default)]
140#[non_exhaustive]
136pub struct Config { 141pub struct Config {
137 /// IPv4 configuration 142 /// IPv4 configuration
138 #[cfg(feature = "proto-ipv4")] 143 #[cfg(feature = "proto-ipv4")]
@@ -163,10 +168,11 @@ impl Config {
163 } 168 }
164 } 169 }
165 170
166 /// IPv6 configuration with dynamic addressing. 171 /// IPv4 configuration with dynamic addressing.
167 /// 172 ///
168 /// # Example 173 /// # Example
169 /// ```rust 174 /// ```rust
175 /// # use embassy_net::Config;
170 /// let _cfg = Config::dhcpv4(Default::default()); 176 /// let _cfg = Config::dhcpv4(Default::default());
171 /// ``` 177 /// ```
172 #[cfg(feature = "dhcpv4")] 178 #[cfg(feature = "dhcpv4")]
@@ -181,23 +187,27 @@ impl Config {
181 187
182/// Network stack IPv4 configuration. 188/// Network stack IPv4 configuration.
183#[cfg(feature = "proto-ipv4")] 189#[cfg(feature = "proto-ipv4")]
190#[derive(Debug, Clone, Default)]
184pub enum ConfigV4 { 191pub enum ConfigV4 {
192 /// Do not configure IPv4.
193 #[default]
194 None,
185 /// Use a static IPv4 address configuration. 195 /// Use a static IPv4 address configuration.
186 Static(StaticConfigV4), 196 Static(StaticConfigV4),
187 /// Use DHCP to obtain an IP address configuration. 197 /// Use DHCP to obtain an IP address configuration.
188 #[cfg(feature = "dhcpv4")] 198 #[cfg(feature = "dhcpv4")]
189 Dhcp(DhcpConfig), 199 Dhcp(DhcpConfig),
190 /// Do not configure IPv6.
191 None,
192} 200}
193 201
194/// Network stack IPv6 configuration. 202/// Network stack IPv6 configuration.
195#[cfg(feature = "proto-ipv6")] 203#[cfg(feature = "proto-ipv6")]
204#[derive(Debug, Clone, Default)]
196pub enum ConfigV6 { 205pub enum ConfigV6 {
197 /// Use a static IPv6 address configuration.
198 Static(StaticConfigV6),
199 /// Do not configure IPv6. 206 /// Do not configure IPv6.
207 #[default]
200 None, 208 None,
209 /// Use a static IPv6 address configuration.
210 Static(StaticConfigV6),
201} 211}
202 212
203/// A network stack. 213/// A network stack.
@@ -217,6 +227,7 @@ struct Inner<D: Driver> {
217 static_v6: Option<StaticConfigV6>, 227 static_v6: Option<StaticConfigV6>,
218 #[cfg(feature = "dhcpv4")] 228 #[cfg(feature = "dhcpv4")]
219 dhcp_socket: Option<SocketHandle>, 229 dhcp_socket: Option<SocketHandle>,
230 config_waker: WakerRegistration,
220 #[cfg(feature = "dns")] 231 #[cfg(feature = "dns")]
221 dns_socket: SocketHandle, 232 dns_socket: SocketHandle,
222 #[cfg(feature = "dns")] 233 #[cfg(feature = "dns")]
@@ -240,11 +251,14 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress
240 driver::HardwareAddress::Ip => HardwareAddress::Ip, 251 driver::HardwareAddress::Ip => HardwareAddress::Ip,
241 252
242 #[allow(unreachable_patterns)] 253 #[allow(unreachable_patterns)]
243 _ => panic!("Unsupported address {:?}. Make sure to enable medium-ethernet or medium-ieee802154 in embassy-net's Cargo features.", addr), 254 _ => panic!(
255 "Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features.",
256 addr
257 ),
244 } 258 }
245} 259}
246 260
247impl<D: Driver + 'static> Stack<D> { 261impl<D: Driver> Stack<D> {
248 /// Create a new network stack. 262 /// Create a new network stack.
249 pub fn new<const SOCK: usize>( 263 pub fn new<const SOCK: usize>(
250 mut device: D, 264 mut device: D,
@@ -276,7 +290,6 @@ impl<D: Driver + 'static> Stack<D> {
276 next_local_port, 290 next_local_port,
277 }; 291 };
278 292
279 #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))]
280 let mut inner = Inner { 293 let mut inner = Inner {
281 device, 294 device,
282 link_up: false, 295 link_up: false,
@@ -286,6 +299,7 @@ impl<D: Driver + 'static> Stack<D> {
286 static_v6: None, 299 static_v6: None,
287 #[cfg(feature = "dhcpv4")] 300 #[cfg(feature = "dhcpv4")]
288 dhcp_socket: None, 301 dhcp_socket: None,
302 config_waker: WakerRegistration::new(),
289 #[cfg(feature = "dns")] 303 #[cfg(feature = "dns")]
290 dns_socket: socket.sockets.add(dns::Socket::new( 304 dns_socket: socket.sockets.add(dns::Socket::new(
291 &[], 305 &[],
@@ -295,30 +309,11 @@ impl<D: Driver + 'static> Stack<D> {
295 dns_waker: WakerRegistration::new(), 309 dns_waker: WakerRegistration::new(),
296 }; 310 };
297 311
298 #[cfg(feature = "medium-ieee802154")]
299 let _ = config;
300
301 #[cfg(feature = "proto-ipv4")] 312 #[cfg(feature = "proto-ipv4")]
302 match config.ipv4 { 313 inner.set_config_v4(&mut socket, config.ipv4);
303 ConfigV4::Static(config) => {
304 inner.apply_config_v4(&mut socket, config);
305 }
306 #[cfg(feature = "dhcpv4")]
307 ConfigV4::Dhcp(config) => {
308 let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
309 inner.apply_dhcp_config(&mut dhcp_socket, config);
310 let handle = socket.sockets.add(dhcp_socket);
311 inner.dhcp_socket = Some(handle);
312 }
313 ConfigV4::None => {}
314 }
315 #[cfg(feature = "proto-ipv6")] 314 #[cfg(feature = "proto-ipv6")]
316 match config.ipv6 { 315 inner.set_config_v6(&mut socket, config.ipv6);
317 ConfigV6::Static(config) => { 316 inner.apply_static_config(&mut socket);
318 inner.apply_config_v6(&mut socket, config);
319 }
320 ConfigV6::None => {}
321 }
322 317
323 Self { 318 Self {
324 socket: RefCell::new(socket), 319 socket: RefCell::new(socket),
@@ -371,16 +366,86 @@ impl<D: Driver + 'static> Stack<D> {
371 v4_up || v6_up 366 v4_up || v6_up
372 } 367 }
373 368
369 /// Wait for the network stack to obtain a valid IP configuration.
370 ///
371 /// ## Notes:
372 /// - Ensure [`Stack::run`] has been called before using this function.
373 ///
374 /// - This function may never return (e.g. if no configuration is obtained through DHCP).
375 /// The caller is supposed to handle a timeout for this case.
376 ///
377 /// ## Example
378 /// ```ignore
379 /// let config = embassy_net::Config::dhcpv4(Default::default());
380 ///// Init network stack
381 /// let stack = &*make_static!(embassy_net::Stack::new(
382 /// device,
383 /// config,
384 /// make_static!(embassy_net::StackResources::<2>::new()),
385 /// seed
386 /// ));
387 /// // Launch network task that runs `stack.run().await`
388 /// spawner.spawn(net_task(stack)).unwrap();
389 /// // Wait for DHCP config
390 /// stack.wait_config_up().await;
391 /// // use the network stack
392 /// // ...
393 /// ```
394 pub async fn wait_config_up(&self) {
395 // If the config is up already, we can return immediately.
396 if self.is_config_up() {
397 return;
398 }
399
400 poll_fn(|cx| {
401 if self.is_config_up() {
402 Poll::Ready(())
403 } else {
404 // If the config is not up, we register a waker that is woken up
405 // when a config is applied (static or DHCP).
406 trace!("Waiting for config up");
407
408 self.with_mut(|_, i| {
409 i.config_waker.register(cx.waker());
410 });
411
412 Poll::Pending
413 }
414 })
415 .await;
416 }
417
374 /// Get the current IPv4 configuration. 418 /// Get the current IPv4 configuration.
419 ///
420 /// If using DHCP, this will be None if DHCP hasn't been able to
421 /// acquire an IP address, or Some if it has.
375 #[cfg(feature = "proto-ipv4")] 422 #[cfg(feature = "proto-ipv4")]
376 pub fn config_v4(&self) -> Option<StaticConfigV4> { 423 pub fn config_v4(&self) -> Option<StaticConfigV4> {
377 self.with(|_s, i| i.static_v4.clone()) 424 self.with(|_, i| i.static_v4.clone())
378 } 425 }
379 426
380 /// Get the current IPv6 configuration. 427 /// Get the current IPv6 configuration.
381 #[cfg(feature = "proto-ipv6")] 428 #[cfg(feature = "proto-ipv6")]
382 pub fn config_v6(&self) -> Option<StaticConfigV6> { 429 pub fn config_v6(&self) -> Option<StaticConfigV6> {
383 self.with(|_s, i| i.static_v6.clone()) 430 self.with(|_, i| i.static_v6.clone())
431 }
432
433 /// Set the IPv4 configuration.
434 #[cfg(feature = "proto-ipv4")]
435 pub fn set_config_v4(&self, config: ConfigV4) {
436 self.with_mut(|s, i| {
437 i.set_config_v4(s, config);
438 i.apply_static_config(s);
439 })
440 }
441
442 /// Set the IPv6 configuration.
443 #[cfg(feature = "proto-ipv6")]
444 pub fn set_config_v6(&self, config: ConfigV6) {
445 self.with_mut(|s, i| {
446 i.set_config_v6(s, config);
447 i.apply_static_config(s);
448 })
384 } 449 }
385 450
386 /// Run the network stack. 451 /// Run the network stack.
@@ -490,7 +555,7 @@ impl<D: Driver + 'static> Stack<D> {
490} 555}
491 556
492#[cfg(feature = "igmp")] 557#[cfg(feature = "igmp")]
493impl<D: Driver + 'static> Stack<D> { 558impl<D: Driver> Stack<D> {
494 /// Join a multicast group. 559 /// Join a multicast group.
495 pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> 560 pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
496 where 561 where
@@ -580,168 +645,129 @@ impl SocketStack {
580 } 645 }
581} 646}
582 647
583impl<D: Driver + 'static> Inner<D> { 648impl<D: Driver> Inner<D> {
584 #[cfg(feature = "proto-ipv4")] 649 #[cfg(feature = "proto-ipv4")]
585 fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) { 650 pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
586 debug!("Acquired IP configuration:"); 651 // Handle static config.
587 652 self.static_v4 = match config.clone() {
588 debug!(" IP address: {}", config.address); 653 ConfigV4::None => None,
589 s.iface.update_ip_addrs(|addrs| { 654 #[cfg(feature = "dhcpv4")]
590 if let Some((index, _)) = addrs 655 ConfigV4::Dhcp(_) => None,
591 .iter() 656 ConfigV4::Static(c) => Some(c),
592 .enumerate() 657 };
593 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
594 {
595 addrs.remove(index);
596 }
597 addrs.push(IpCidr::Ipv4(config.address)).unwrap();
598 });
599
600 #[cfg(feature = "medium-ip")]
601 let skip_gateway = self.device.capabilities().medium != Medium::Ip;
602 #[cfg(not(feature = "medium-ip"))]
603 let skip_gateway = false;
604
605 if !skip_gateway {
606 if let Some(gateway) = config.gateway {
607 debug!(" Default gateway: {}", gateway);
608 s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap();
609 } else {
610 debug!(" Default gateway: None");
611 s.iface.routes_mut().remove_default_ipv4_route();
612 }
613 }
614 for (i, s) in config.dns_servers.iter().enumerate() {
615 debug!(" DNS server {}: {}", i, s);
616 }
617 658
618 self.static_v4 = Some(config); 659 // Handle DHCP config.
660 #[cfg(feature = "dhcpv4")]
661 match config {
662 ConfigV4::Dhcp(c) => {
663 // Create the socket if it doesn't exist.
664 if self.dhcp_socket.is_none() {
665 let socket = smoltcp::socket::dhcpv4::Socket::new();
666 let handle = _s.sockets.add(socket);
667 self.dhcp_socket = Some(handle);
668 }
619 669
620 #[cfg(feature = "dns")] 670 // Configure it
621 { 671 let socket = _s.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket));
622 self.update_dns_servers(s) 672 socket.set_ignore_naks(c.ignore_naks);
673 socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
674 socket.set_ports(c.server_port, c.client_port);
675 socket.set_retry_config(c.retry_config);
676 socket.reset();
677 }
678 _ => {
679 // Remove DHCP socket if any.
680 if let Some(socket) = self.dhcp_socket {
681 _s.sockets.remove(socket);
682 self.dhcp_socket = None;
683 }
684 }
623 } 685 }
624 } 686 }
625 687
626 /// Replaces the current IPv6 static configuration with a newly supplied config.
627 #[cfg(feature = "proto-ipv6")] 688 #[cfg(feature = "proto-ipv6")]
628 fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) { 689 pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) {
629 #[cfg(feature = "medium-ethernet")] 690 self.static_v6 = match config {
630 let medium = self.device.capabilities().medium; 691 ConfigV6::None => None,
692 ConfigV6::Static(c) => Some(c),
693 };
694 }
631 695
632 debug!("Acquired IPv6 configuration:"); 696 fn apply_static_config(&mut self, s: &mut SocketStack) {
697 let mut addrs = Vec::new();
698 #[cfg(feature = "dns")]
699 let mut dns_servers: Vec<_, 6> = Vec::new();
700 #[cfg(feature = "proto-ipv4")]
701 let mut gateway_v4 = None;
702 #[cfg(feature = "proto-ipv6")]
703 let mut gateway_v6 = None;
633 704
634 debug!(" IP address: {}", config.address); 705 #[cfg(feature = "proto-ipv4")]
635 s.iface.update_ip_addrs(|addrs| { 706 if let Some(config) = &self.static_v4 {
636 if let Some((index, _)) = addrs 707 debug!("IPv4: UP");
637 .iter() 708 debug!(" IP address: {:?}", config.address);
638 .enumerate() 709 debug!(" Default gateway: {:?}", config.gateway);
639 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv6(_)))
640 {
641 addrs.remove(index);
642 }
643 addrs.push(IpCidr::Ipv6(config.address)).unwrap();
644 });
645 710
646 #[cfg(feature = "medium-ethernet")] 711 unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok());
647 if Medium::Ethernet == medium { 712 gateway_v4 = config.gateway.into();
648 if let Some(gateway) = config.gateway { 713 #[cfg(feature = "dns")]
649 debug!(" Default gateway: {}", gateway); 714 for s in &config.dns_servers {
650 s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); 715 debug!(" DNS server: {:?}", s);
651 } else { 716 unwrap!(dns_servers.push(s.clone().into()).ok());
652 debug!(" Default gateway: None");
653 s.iface.routes_mut().remove_default_ipv6_route();
654 } 717 }
655 } 718 } else {
656 for (i, s) in config.dns_servers.iter().enumerate() { 719 info!("IPv4: DOWN");
657 debug!(" DNS server {}: {}", i, s);
658 } 720 }
659 721
660 self.static_v6 = Some(config); 722 #[cfg(feature = "proto-ipv6")]
723 if let Some(config) = &self.static_v6 {
724 debug!("IPv6: UP");
725 debug!(" IP address: {:?}", config.address);
726 debug!(" Default gateway: {:?}", config.gateway);
661 727
662 #[cfg(feature = "dns")] 728 unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok());
663 { 729 gateway_v6 = config.gateway.into();
664 self.update_dns_servers(s) 730 #[cfg(feature = "dns")]
731 for s in &config.dns_servers {
732 debug!(" DNS server: {:?}", s);
733 unwrap!(dns_servers.push(s.clone().into()).ok());
734 }
735 } else {
736 info!("IPv6: DOWN");
665 } 737 }
666 }
667 738
668 #[cfg(feature = "dns")] 739 // Apply addresses
669 fn update_dns_servers(&mut self, s: &mut SocketStack) { 740 s.iface.update_ip_addrs(|a| *a = addrs);
670 let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket);
671 741
672 let servers_v4; 742 // Apply gateways
673 #[cfg(feature = "proto-ipv4")] 743 #[cfg(feature = "proto-ipv4")]
674 { 744 if let Some(gateway) = gateway_v4 {
675 servers_v4 = self 745 unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway));
676 .static_v4 746 } else {
677 .iter() 747 s.iface.routes_mut().remove_default_ipv4_route();
678 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)));
679 };
680 #[cfg(not(feature = "proto-ipv4"))]
681 {
682 servers_v4 = core::iter::empty();
683 } 748 }
684
685 let servers_v6;
686 #[cfg(feature = "proto-ipv6")] 749 #[cfg(feature = "proto-ipv6")]
687 { 750 if let Some(gateway) = gateway_v6 {
688 servers_v6 = self 751 unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway));
689 .static_v6 752 } else {
690 .iter() 753 s.iface.routes_mut().remove_default_ipv6_route();
691 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c)));
692 } 754 }
693 #[cfg(not(feature = "proto-ipv6"))]
694 {
695 servers_v6 = core::iter::empty();
696 }
697
698 // Prefer the v6 DNS servers over the v4 servers
699 let servers: Vec<IpAddress, 6> = servers_v6.chain(servers_v4).collect();
700 socket.update_servers(&servers[..]);
701 }
702 755
703 #[cfg(feature = "dhcpv4")] 756 // Apply DNS servers
704 fn apply_dhcp_config(&self, socket: &mut smoltcp::socket::dhcpv4::Socket, config: DhcpConfig) { 757 #[cfg(feature = "dns")]
705 socket.set_ignore_naks(config.ignore_naks); 758 s.sockets
706 socket.set_max_lease_duration(config.max_lease_duration.map(crate::time::duration_to_smoltcp)); 759 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
707 socket.set_ports(config.server_port, config.client_port); 760 .update_servers(&dns_servers[..]);
708 socket.set_retry_config(config.retry_config);
709 }
710 761
711 #[cfg(feature = "dhcpv4")] 762 self.config_waker.wake();
712 fn unapply_config_v4(&mut self, s: &mut SocketStack) {
713 #[cfg(feature = "medium-ethernet")]
714 let medium = self.device.capabilities().medium;
715 debug!("Lost IP configuration");
716 s.iface.update_ip_addrs(|ip_addrs| {
717 #[cfg(feature = "proto-ipv4")]
718 if let Some((index, _)) = ip_addrs
719 .iter()
720 .enumerate()
721 .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
722 {
723 ip_addrs.remove(index);
724 }
725 });
726 #[cfg(feature = "medium-ethernet")]
727 if medium == Medium::Ethernet {
728 #[cfg(feature = "proto-ipv4")]
729 {
730 s.iface.routes_mut().remove_default_ipv4_route();
731 }
732 }
733 #[cfg(feature = "proto-ipv4")]
734 {
735 self.static_v4 = None
736 }
737 } 763 }
738 764
739 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { 765 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
740 s.waker.register(cx.waker()); 766 s.waker.register(cx.waker());
741 767
742 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] 768 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
743 if self.device.capabilities().medium == Medium::Ethernet 769 if self.device.capabilities().medium == embassy_net_driver::Medium::Ethernet
744 || self.device.capabilities().medium == Medium::Ieee802154 770 || self.device.capabilities().medium == embassy_net_driver::Medium::Ieee802154
745 { 771 {
746 s.iface 772 s.iface
747 .set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address())); 773 .set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address()));
@@ -763,6 +789,9 @@ impl<D: Driver + 'static> Inner<D> {
763 info!("link_up = {:?}", self.link_up); 789 info!("link_up = {:?}", self.link_up);
764 } 790 }
765 791
792 #[allow(unused_mut)]
793 let mut apply_config = false;
794
766 #[cfg(feature = "dhcpv4")] 795 #[cfg(feature = "dhcpv4")]
767 if let Some(dhcp_handle) = self.dhcp_socket { 796 if let Some(dhcp_handle) = self.dhcp_socket {
768 let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle); 797 let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
@@ -770,25 +799,29 @@ impl<D: Driver + 'static> Inner<D> {
770 if self.link_up { 799 if self.link_up {
771 match socket.poll() { 800 match socket.poll() {
772 None => {} 801 None => {}
773 Some(dhcpv4::Event::Deconfigured) => self.unapply_config_v4(s), 802 Some(dhcpv4::Event::Deconfigured) => {
803 self.static_v4 = None;
804 apply_config = true;
805 }
774 Some(dhcpv4::Event::Configured(config)) => { 806 Some(dhcpv4::Event::Configured(config)) => {
775 let config = StaticConfigV4 { 807 self.static_v4 = Some(StaticConfigV4 {
776 address: config.address, 808 address: config.address,
777 gateway: config.router, 809 gateway: config.router,
778 dns_servers: config.dns_servers, 810 dns_servers: config.dns_servers,
779 }; 811 });
780 self.apply_config_v4(s, config) 812 apply_config = true;
781 } 813 }
782 } 814 }
783 } else if old_link_up { 815 } else if old_link_up {
784 socket.reset(); 816 socket.reset();
785 self.unapply_config_v4(s); 817 self.static_v4 = None;
818 apply_config = true;
786 } 819 }
787 } 820 }
788 //if old_link_up || self.link_up { 821
789 // self.poll_configurator(timestamp) 822 if apply_config {
790 //} 823 self.apply_static_config(s);
791 // 824 }
792 825
793 if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { 826 if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) {
794 let t = Timer::at(instant_from_smoltcp(poll_at)); 827 let t = Timer::at(instant_from_smoltcp(poll_at));
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index c92ad2d2e..a12fd382a 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -440,7 +440,7 @@ impl<'d> TcpIo<'d> {
440 Poll::Ready(Err(Error::ConnectionReset)) 440 Poll::Ready(Err(Error::ConnectionReset))
441 } 441 }
442 } else { 442 } else {
443 Poll::Ready(match s.send(f.take().unwrap()) { 443 Poll::Ready(match s.send(unwrap!(f.take())) {
444 // Connection reset. TODO: this can also be timeouts etc, investigate. 444 // Connection reset. TODO: this can also be timeouts etc, investigate.
445 Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset), 445 Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset),
446 Ok(r) => Ok(r), 446 Ok(r) => Ok(r),
@@ -468,7 +468,7 @@ impl<'d> TcpIo<'d> {
468 Poll::Ready(Err(Error::ConnectionReset)) 468 Poll::Ready(Err(Error::ConnectionReset))
469 } 469 }
470 } else { 470 } else {
471 Poll::Ready(match s.recv(f.take().unwrap()) { 471 Poll::Ready(match s.recv(unwrap!(f.take())) {
472 // Connection reset. TODO: this can also be timeouts etc, investigate. 472 // Connection reset. TODO: this can also be timeouts etc, investigate.
473 Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => { 473 Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => {
474 Err(Error::ConnectionReset) 474 Err(Error::ConnectionReset)
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 0a5a7b8f6..61058c1ba 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -29,6 +29,8 @@ pub enum BindError {
29pub enum Error { 29pub enum Error {
30 /// No route to host. 30 /// No route to host.
31 NoRoute, 31 NoRoute,
32 /// Socket not bound to an outgoing port.
33 SocketNotBound,
32} 34}
33 35
34/// An UDP socket. 36/// An UDP socket.
@@ -155,7 +157,14 @@ impl<'a> UdpSocket<'a> {
155 s.register_send_waker(cx.waker()); 157 s.register_send_waker(cx.waker());
156 Poll::Pending 158 Poll::Pending
157 } 159 }
158 Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)), 160 Err(udp::SendError::Unaddressable) => {
161 // If no sender/outgoing port is specified, there is not really "no route"
162 if s.endpoint().port == 0 {
163 Poll::Ready(Err(Error::SocketNotBound))
164 } else {
165 Poll::Ready(Err(Error::NoRoute))
166 }
167 }
159 }) 168 })
160 } 169 }
161 170
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 67ec4eb93..3c706b473 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"]
51nrf52810 = ["nrf52810-pac", "_nrf52"] 51nrf52810 = ["nrf52810-pac", "_nrf52"]
52nrf52811 = ["nrf52811-pac", "_nrf52"] 52nrf52811 = ["nrf52811-pac", "_nrf52"]
53nrf52820 = ["nrf52820-pac", "_nrf52"] 53nrf52820 = ["nrf52820-pac", "_nrf52"]
54nrf52832 = ["nrf52832-pac", "_nrf52"] 54nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"]
55nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] 55nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
56nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] 56nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
57nrf5340-app-s = ["_nrf5340-app", "_s"] 57nrf5340-app-s = ["_nrf5340-app", "_s"]
@@ -90,9 +90,12 @@ _ppi = []
90_dppi = [] 90_dppi = []
91_gpio-p1 = [] 91_gpio-p1 = []
92 92
93# Errata workarounds
94_nrf52832_anomaly_109 = []
95
93[dependencies] 96[dependencies]
94embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } 97embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
95embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 98embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
96embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } 99embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 100embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } 101embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-nrf/src/fmt.rs
+++ b/embassy-nrf/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 7488bc085..d16b4a43b 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -86,7 +86,6 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
86 unsafe { irq.enable() }; 86 unsafe { irq.enable() };
87 87
88 let g = regs(); 88 let g = regs();
89 g.events_port.write(|w| w);
90 g.intenset.write(|w| w.port().set()); 89 g.intenset.write(|w| w.port().set());
91} 90}
92 91
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 355a00497..9c4b6569d 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -102,6 +102,7 @@ mod chip;
102#[macro_export] 102#[macro_export]
103macro_rules! bind_interrupts { 103macro_rules! bind_interrupts {
104 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 104 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
105 #[derive(Copy, Clone)]
105 $vis struct $name; 106 $vis struct $name;
106 107
107 $( 108 $(
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index d131a43dd..4828af43e 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -68,8 +68,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
68 let r = T::regs(); 68 let r = T::regs();
69 let s = T::state(); 69 let s = T::state();
70 70
71 #[cfg(feature = "_nrf52832_anomaly_109")]
72 if r.events_started.read().bits() != 0 {
73 s.waker.wake();
74 r.intenclr.write(|w| w.started().clear());
75 }
76
71 if r.events_end.read().bits() != 0 { 77 if r.events_end.read().bits() != 0 {
72 s.end_waker.wake(); 78 s.waker.wake();
73 r.intenclr.write(|w| w.end().clear()); 79 r.intenclr.write(|w| w.end().clear());
74 } 80 }
75 } 81 }
@@ -167,42 +173,10 @@ impl<'d, T: Instance> Spim<'d, T> {
167 // Enable SPIM instance. 173 // Enable SPIM instance.
168 r.enable.write(|w| w.enable().enabled()); 174 r.enable.write(|w| w.enable().enabled());
169 175
170 // Configure mode. 176 let mut spim = Self { _p: spim };
171 let mode = config.mode;
172 r.config.write(|w| {
173 match mode {
174 MODE_0 => {
175 w.order().msb_first();
176 w.cpol().active_high();
177 w.cpha().leading();
178 }
179 MODE_1 => {
180 w.order().msb_first();
181 w.cpol().active_high();
182 w.cpha().trailing();
183 }
184 MODE_2 => {
185 w.order().msb_first();
186 w.cpol().active_low();
187 w.cpha().leading();
188 }
189 MODE_3 => {
190 w.order().msb_first();
191 w.cpol().active_low();
192 w.cpha().trailing();
193 }
194 }
195 177
196 w 178 // Apply runtime peripheral configuration
197 }); 179 Self::set_config(&mut spim, &config);
198
199 // Configure frequency.
200 let frequency = config.frequency;
201 r.frequency.write(|w| w.frequency().variant(frequency));
202
203 // Set over-read character
204 let orc = config.orc;
205 r.orc.write(|w| unsafe { w.orc().bits(orc) });
206 180
207 // Disable all events interrupts 181 // Disable all events interrupts
208 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 182 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
@@ -210,7 +184,7 @@ impl<'d, T: Instance> Spim<'d, T> {
210 T::Interrupt::unpend(); 184 T::Interrupt::unpend();
211 unsafe { T::Interrupt::enable() }; 185 unsafe { T::Interrupt::enable() };
212 186
213 Self { _p: spim } 187 spim
214 } 188 }
215 189
216 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 190 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
@@ -223,14 +197,32 @@ impl<'d, T: Instance> Spim<'d, T> {
223 let r = T::regs(); 197 let r = T::regs();
224 198
225 // Set up the DMA write. 199 // Set up the DMA write.
226 let (ptr, len) = slice_ptr_parts(tx); 200 let (ptr, tx_len) = slice_ptr_parts(tx);
227 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 201 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
228 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 202 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) });
229 203
230 // Set up the DMA read. 204 // Set up the DMA read.
231 let (ptr, len) = slice_ptr_parts_mut(rx); 205 let (ptr, rx_len) = slice_ptr_parts_mut(rx);
232 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 206 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
233 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 207 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
208
209 #[cfg(feature = "_nrf52832_anomaly_109")]
210 {
211 let s = T::state();
212
213 r.events_started.reset();
214
215 // Set rx/tx buffer lengths to 0...
216 r.txd.maxcnt.reset();
217 r.rxd.maxcnt.reset();
218
219 // ...and keep track of original buffer lengths...
220 s.tx.store(tx_len as _, Ordering::Relaxed);
221 s.rx.store(rx_len as _, Ordering::Relaxed);
222
223 // ...signalling the start of the fake transfer.
224 r.intenset.write(|w| w.started().bit(true));
225 }
234 226
235 // Reset and enable the event 227 // Reset and enable the event
236 r.events_end.reset(); 228 r.events_end.reset();
@@ -245,6 +237,9 @@ impl<'d, T: Instance> Spim<'d, T> {
245 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 237 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
246 self.prepare(rx, tx)?; 238 self.prepare(rx, tx)?;
247 239
240 #[cfg(feature = "_nrf52832_anomaly_109")]
241 while let Poll::Pending = self.nrf52832_dma_workaround_status() {}
242
248 // Wait for 'end' event. 243 // Wait for 'end' event.
249 while T::regs().events_end.read().bits() == 0 {} 244 while T::regs().events_end.read().bits() == 0 {}
250 245
@@ -269,9 +264,19 @@ impl<'d, T: Instance> Spim<'d, T> {
269 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 264 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
270 self.prepare(rx, tx)?; 265 self.prepare(rx, tx)?;
271 266
267 #[cfg(feature = "_nrf52832_anomaly_109")]
268 poll_fn(|cx| {
269 let s = T::state();
270
271 s.waker.register(cx.waker());
272
273 self.nrf52832_dma_workaround_status()
274 })
275 .await;
276
272 // Wait for 'end' event. 277 // Wait for 'end' event.
273 poll_fn(|cx| { 278 poll_fn(|cx| {
274 T::state().end_waker.register(cx.waker()); 279 T::state().waker.register(cx.waker());
275 if T::regs().events_end.read().bits() != 0 { 280 if T::regs().events_end.read().bits() != 0 {
276 return Poll::Ready(()); 281 return Poll::Ready(());
277 } 282 }
@@ -362,6 +367,32 @@ impl<'d, T: Instance> Spim<'d, T> {
362 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { 367 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
363 self.async_inner_from_ram(&mut [], data).await 368 self.async_inner_from_ram(&mut [], data).await
364 } 369 }
370
371 #[cfg(feature = "_nrf52832_anomaly_109")]
372 fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
373 let r = T::regs();
374 if r.events_started.read().bits() != 0 {
375 let s = T::state();
376
377 // Handle the first "fake" transmission
378 r.events_started.reset();
379 r.events_end.reset();
380
381 // Update DMA registers with correct rx/tx buffer sizes
382 r.rxd
383 .maxcnt
384 .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
385 r.txd
386 .maxcnt
387 .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
388
389 r.intenset.write(|w| w.end().set());
390 // ... and start actual, hopefully glitch-free transmission
391 r.tasks_start.write(|w| unsafe { w.bits(1) });
392 return Poll::Ready(());
393 }
394 Poll::Pending
395 }
365} 396}
366 397
367impl<'d, T: Instance> Drop for Spim<'d, T> { 398impl<'d, T: Instance> Drop for Spim<'d, T> {
@@ -386,18 +417,29 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
386} 417}
387 418
388pub(crate) mod sealed { 419pub(crate) mod sealed {
420 #[cfg(feature = "_nrf52832_anomaly_109")]
421 use core::sync::atomic::AtomicU8;
422
389 use embassy_sync::waitqueue::AtomicWaker; 423 use embassy_sync::waitqueue::AtomicWaker;
390 424
391 use super::*; 425 use super::*;
392 426
393 pub struct State { 427 pub struct State {
394 pub end_waker: AtomicWaker, 428 pub waker: AtomicWaker,
429 #[cfg(feature = "_nrf52832_anomaly_109")]
430 pub rx: AtomicU8,
431 #[cfg(feature = "_nrf52832_anomaly_109")]
432 pub tx: AtomicU8,
395 } 433 }
396 434
397 impl State { 435 impl State {
398 pub const fn new() -> Self { 436 pub const fn new() -> Self {
399 Self { 437 Self {
400 end_waker: AtomicWaker::new(), 438 waker: AtomicWaker::new(),
439 #[cfg(feature = "_nrf52832_anomaly_109")]
440 rx: AtomicU8::new(0),
441 #[cfg(feature = "_nrf52832_anomaly_109")]
442 tx: AtomicU8::new(0),
401 } 443 }
402 } 444 }
403 } 445 }
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 212825121..e695ba6b7 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -169,47 +169,10 @@ impl<'d, T: Instance> Spis<'d, T> {
169 // Enable SPIS instance. 169 // Enable SPIS instance.
170 r.enable.write(|w| w.enable().enabled()); 170 r.enable.write(|w| w.enable().enabled());
171 171
172 // Configure mode. 172 let mut spis = Self { _p: spis };
173 let mode = config.mode;
174 r.config.write(|w| {
175 match mode {
176 MODE_0 => {
177 w.order().msb_first();
178 w.cpol().active_high();
179 w.cpha().leading();
180 }
181 MODE_1 => {
182 w.order().msb_first();
183 w.cpol().active_high();
184 w.cpha().trailing();
185 }
186 MODE_2 => {
187 w.order().msb_first();
188 w.cpol().active_low();
189 w.cpha().leading();
190 }
191 MODE_3 => {
192 w.order().msb_first();
193 w.cpol().active_low();
194 w.cpha().trailing();
195 }
196 }
197 173
198 w 174 // Apply runtime peripheral configuration
199 }); 175 Self::set_config(&mut spis, &config);
200
201 // Set over-read character.
202 let orc = config.orc;
203 r.orc.write(|w| unsafe { w.orc().bits(orc) });
204
205 // Set default character.
206 let def = config.def;
207 r.def.write(|w| unsafe { w.def().bits(def) });
208
209 // Configure auto-acquire on 'transfer end' event.
210 if config.auto_acquire {
211 r.shorts.write(|w| w.end_acquire().bit(true));
212 }
213 176
214 // Disable all events interrupts. 177 // Disable all events interrupts.
215 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 178 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
@@ -217,7 +180,7 @@ impl<'d, T: Instance> Spis<'d, T> {
217 T::Interrupt::unpend(); 180 T::Interrupt::unpend();
218 unsafe { T::Interrupt::enable() }; 181 unsafe { T::Interrupt::enable() };
219 182
220 Self { _p: spis } 183 spis
221 } 184 }
222 185
223 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 186 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index cec46d8d0..5e2998b10 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -57,7 +57,6 @@ impl<'d> Temp<'d> {
57 /// ```no_run 57 /// ```no_run
58 /// use embassy_nrf::{bind_interrupts, temp}; 58 /// use embassy_nrf::{bind_interrupts, temp};
59 /// use embassy_nrf::temp::Temp; 59 /// use embassy_nrf::temp::Temp;
60 /// use embassy_time::{Duration, Timer};
61 /// 60 ///
62 /// bind_interrupts!(struct Irqs { 61 /// bind_interrupts!(struct Irqs {
63 /// TEMP => temp::InterruptHandler; 62 /// TEMP => temp::InterruptHandler;
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index fdea480e3..fe38fb102 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -167,9 +167,10 @@ impl<'d, T: Instance> Twim<'d, T> {
167 // Enable TWIM instance. 167 // Enable TWIM instance.
168 r.enable.write(|w| w.enable().enabled()); 168 r.enable.write(|w| w.enable().enabled());
169 169
170 // Configure frequency. 170 let mut twim = Self { _p: twim };
171 r.frequency 171
172 .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); 172 // Apply runtime peripheral configuration
173 Self::set_config(&mut twim, &config);
173 174
174 // Disable all events interrupts 175 // Disable all events interrupts
175 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 176 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
@@ -177,7 +178,7 @@ impl<'d, T: Instance> Twim<'d, T> {
177 T::Interrupt::unpend(); 178 T::Interrupt::unpend();
178 unsafe { T::Interrupt::enable() }; 179 unsafe { T::Interrupt::enable() };
179 180
180 Self { _p: twim } 181 twim
181 } 182 }
182 183
183 /// Set TX buffer, checking that it is in RAM and has suitable length. 184 /// Set TX buffer, checking that it is in RAM and has suitable length.
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 60143c2b9..1147286fc 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -59,8 +59,8 @@ nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "em
59unstable-traits = ["embedded-hal-1", "embedded-hal-nb"] 59unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
60 60
61[dependencies] 61[dependencies]
62embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 62embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
63embassy-time = { version = "0.1.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 63embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
64embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 64embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
65embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 65embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
66embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 66embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@@ -89,7 +89,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional =
89embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} 89embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
90embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true} 90embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true}
91 91
92paste = "1.0"
93pio-proc = {version= "0.2" } 92pio-proc = {version= "0.2" }
94pio = {version= "0.2.1" } 93pio = {version= "0.2.1" }
95rp2040-boot2 = "0.3" 94rp2040-boot2 = "0.3"
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 7b25ecffb..220665462 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -94,6 +94,7 @@ impl ClockConfig {
94 post_div1: 6, 94 post_div1: 6,
95 post_div2: 5, 95 post_div2: 5,
96 }), 96 }),
97 delay_multiplier: 128,
97 }), 98 }),
98 ref_clk: RefClkConfig { 99 ref_clk: RefClkConfig {
99 src: RefClkSrc::Xosc, 100 src: RefClkSrc::Xosc,
@@ -203,6 +204,7 @@ pub struct XoscConfig {
203 pub hz: u32, 204 pub hz: u32,
204 pub sys_pll: Option<PllConfig>, 205 pub sys_pll: Option<PllConfig>,
205 pub usb_pll: Option<PllConfig>, 206 pub usb_pll: Option<PllConfig>,
207 pub delay_multiplier: u32,
206} 208}
207 209
208pub struct PllConfig { 210pub struct PllConfig {
@@ -363,7 +365,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
363 // start XOSC 365 // start XOSC
364 // datasheet mentions support for clock inputs into XIN, but doesn't go into 366 // datasheet mentions support for clock inputs into XIN, but doesn't go into
365 // how this is achieved. pico-sdk doesn't support this at all. 367 // how this is achieved. pico-sdk doesn't support this at all.
366 start_xosc(config.hz); 368 start_xosc(config.hz, config.delay_multiplier);
367 369
368 let pll_sys_freq = match config.sys_pll { 370 let pll_sys_freq = match config.sys_pll {
369 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), 371 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config),
@@ -624,12 +626,12 @@ pub fn clk_rtc_freq() -> u16 {
624 CLOCKS.rtc.load(Ordering::Relaxed) 626 CLOCKS.rtc.load(Ordering::Relaxed)
625} 627}
626 628
627fn start_xosc(crystal_hz: u32) { 629fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
628 pac::XOSC 630 pac::XOSC
629 .ctrl() 631 .ctrl()
630 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); 632 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
631 633
632 let startup_delay = ((crystal_hz / 1000) + 128) / 256; 634 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256;
633 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); 635 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16));
634 pac::XOSC.ctrl().write(|w| { 636 pac::XOSC.ctrl().write(|w| {
635 w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); 637 w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ);
diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-rp/src/fmt.rs
+++ b/embassy-rp/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 7a5ddd325..c358682c5 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -21,6 +21,8 @@ pub enum AbortReason {
21 NoAcknowledge, 21 NoAcknowledge,
22 /// The arbitration was lost, e.g. electrical problems with the clock signal 22 /// The arbitration was lost, e.g. electrical problems with the clock signal
23 ArbitrationLoss, 23 ArbitrationLoss,
24 /// Transmit ended with data still in fifo
25 TxNotEmpty(u16),
24 Other(u32), 26 Other(u32),
25} 27}
26 28
@@ -52,7 +54,7 @@ impl Default for Config {
52 } 54 }
53} 55}
54 56
55const FIFO_SIZE: u8 = 16; 57pub const FIFO_SIZE: u8 = 16;
56 58
57pub struct I2c<'d, T: Instance, M: Mode> { 59pub struct I2c<'d, T: Instance, M: Mode> {
58 phantom: PhantomData<(&'d mut T, M)>, 60 phantom: PhantomData<(&'d mut T, M)>,
@@ -636,6 +638,7 @@ mod eh1 {
636 Self::Abort(AbortReason::NoAcknowledge) => { 638 Self::Abort(AbortReason::NoAcknowledge) => {
637 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 639 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
638 } 640 }
641 Self::Abort(AbortReason::TxNotEmpty(_)) => embedded_hal_1::i2c::ErrorKind::Other,
639 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, 642 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other,
640 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 643 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
641 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 644 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
@@ -738,8 +741,8 @@ mod nightly {
738 } 741 }
739} 742}
740 743
741fn i2c_reserved_addr(addr: u16) -> bool { 744pub fn i2c_reserved_addr(addr: u16) -> bool {
742 (addr & 0x78) == 0 || (addr & 0x78) == 0x78 745 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
743} 746}
744 747
745mod sealed { 748mod sealed {
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs
new file mode 100644
index 000000000..6136d69c6
--- /dev/null
+++ b/embassy-rp/src/i2c_slave.rs
@@ -0,0 +1,338 @@
1use core::future;
2use core::marker::PhantomData;
3use core::task::Poll;
4
5use embassy_hal_internal::into_ref;
6use pac::i2c;
7
8use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE};
9use crate::interrupt::typelevel::{Binding, Interrupt};
10use crate::{pac, Peripheral};
11
12/// I2C error
13#[derive(Debug)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[non_exhaustive]
16pub enum Error {
17 /// I2C abort with error
18 Abort(AbortReason),
19 /// User passed in a response buffer that was 0 length
20 InvalidResponseBufferLength,
21}
22
23/// Received command
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum Command {
27 /// General Call
28 GeneralCall(usize),
29 /// Read
30 Read,
31 /// Write+read
32 WriteRead(usize),
33 /// Write
34 Write(usize),
35}
36
37/// Possible responses to responding to a read
38#[derive(Debug, Copy, Clone, Eq, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum ReadStatus {
41 /// Transaction Complete, controller naked our last byte
42 Done,
43 /// Transaction Incomplete, controller trying to read more bytes than were provided
44 NeedMoreBytes,
45 /// Transaction Complere, but controller stopped reading bytes before we ran out
46 LeftoverBytes(u16),
47}
48
49/// Slave Configuration
50#[non_exhaustive]
51#[derive(Copy, Clone)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub struct Config {
54 /// Target Address
55 pub addr: u16,
56}
57
58impl Default for Config {
59 fn default() -> Self {
60 Self { addr: 0x55 }
61 }
62}
63
64pub struct I2cSlave<'d, T: Instance> {
65 phantom: PhantomData<&'d mut T>,
66}
67
68impl<'d, T: Instance> I2cSlave<'d, T> {
69 pub fn new(
70 _peri: impl Peripheral<P = T> + 'd,
71 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
72 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
73 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
74 config: Config,
75 ) -> Self {
76 into_ref!(_peri, scl, sda);
77
78 assert!(!i2c_reserved_addr(config.addr));
79 assert!(config.addr != 0);
80
81 let p = T::regs();
82
83 let reset = T::reset();
84 crate::reset::reset(reset);
85 crate::reset::unreset_wait(reset);
86
87 p.ic_enable().write(|w| w.set_enable(false));
88
89 p.ic_sar().write(|w| w.set_ic_sar(config.addr));
90 p.ic_con().modify(|w| {
91 w.set_master_mode(false);
92 w.set_ic_slave_disable(false);
93 w.set_tx_empty_ctrl(true);
94 });
95
96 // Set FIFO watermarks to 1 to make things simpler. This is encoded
97 // by a register value of 0. Rx watermark should never change, but Tx watermark will be
98 // adjusted in operation.
99 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
100 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
101
102 // Configure SCL & SDA pins
103 scl.gpio().ctrl().write(|w| w.set_funcsel(3));
104 sda.gpio().ctrl().write(|w| w.set_funcsel(3));
105
106 scl.pad_ctrl().write(|w| {
107 w.set_schmitt(true);
108 w.set_ie(true);
109 w.set_od(false);
110 w.set_pue(true);
111 w.set_pde(false);
112 });
113 sda.pad_ctrl().write(|w| {
114 w.set_schmitt(true);
115 w.set_ie(true);
116 w.set_od(false);
117 w.set_pue(true);
118 w.set_pde(false);
119 });
120
121 // Clear interrupts
122 p.ic_clr_intr().read();
123
124 // Enable I2C block
125 p.ic_enable().write(|w| w.set_enable(true));
126
127 // mask everything initially
128 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
129 T::Interrupt::unpend();
130 unsafe { T::Interrupt::enable() };
131
132 Self { phantom: PhantomData }
133 }
134
135 /// Calls `f` to check if we are ready or not.
136 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
137 #[inline(always)]
138 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
139 where
140 F: FnMut(&mut Self) -> Poll<U>,
141 G: FnMut(&mut Self),
142 {
143 future::poll_fn(|cx| {
144 let r = f(self);
145
146 trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0);
147
148 if r.is_pending() {
149 T::waker().register(cx.waker());
150 g(self);
151 }
152
153 r
154 })
155 .await
156 }
157
158 #[inline(always)]
159 fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize {
160 let p = T::regs();
161 let len = p.ic_rxflr().read().rxflr() as usize;
162 let end = offset + len;
163 for i in offset..end {
164 buffer[i] = p.ic_data_cmd().read().dat();
165 }
166 end
167 }
168
169 #[inline(always)]
170 fn write_to_fifo(&mut self, buffer: &[u8]) {
171 let p = T::regs();
172 for byte in buffer {
173 p.ic_data_cmd().write(|w| w.set_dat(*byte));
174 }
175 }
176
177 /// Wait asynchronously for commands from an I2C master.
178 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
179 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
180 let p = T::regs();
181
182 p.ic_clr_intr().read();
183 // set rx fifo watermark to 1 byte
184 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
185
186 let mut len = 0;
187 let ret = self
188 .wait_on(
189 |me| {
190 let stat = p.ic_raw_intr_stat().read();
191 if p.ic_rxflr().read().rxflr() > 0 {
192 len = me.drain_fifo(buffer, len);
193 // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise
194 p.ic_rx_tl().write(|w| w.set_rx_tl(11));
195 }
196
197 if stat.restart_det() && stat.rd_req() {
198 Poll::Ready(Ok(Command::WriteRead(len)))
199 } else if stat.gen_call() && stat.stop_det() && len > 0 {
200 Poll::Ready(Ok(Command::GeneralCall(len)))
201 } else if stat.stop_det() {
202 Poll::Ready(Ok(Command::Write(len)))
203 } else if stat.rd_req() {
204 Poll::Ready(Ok(Command::Read))
205 } else {
206 Poll::Pending
207 }
208 },
209 |_me| {
210 p.ic_intr_mask().modify(|w| {
211 w.set_m_stop_det(true);
212 w.set_m_restart_det(true);
213 w.set_m_gen_call(true);
214 w.set_m_rd_req(true);
215 w.set_m_rx_full(true);
216 });
217 },
218 )
219 .await;
220
221 p.ic_clr_intr().read();
222
223 ret
224 }
225
226 /// Respond to an I2C master READ command, asynchronously.
227 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> {
228 let p = T::regs();
229
230 if buffer.len() == 0 {
231 return Err(Error::InvalidResponseBufferLength);
232 }
233
234 let mut chunks = buffer.chunks(FIFO_SIZE as usize);
235
236 let ret = self
237 .wait_on(
238 |me| {
239 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
240 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason {
241 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes)));
242 } else {
243 return Poll::Ready(Err(abort_reason));
244 }
245 }
246
247 if let Some(chunk) = chunks.next() {
248 me.write_to_fifo(chunk);
249
250 Poll::Pending
251 } else {
252 let stat = p.ic_raw_intr_stat().read();
253
254 if stat.rx_done() && stat.stop_det() {
255 Poll::Ready(Ok(ReadStatus::Done))
256 } else if stat.rd_req() {
257 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
258 } else {
259 Poll::Pending
260 }
261 }
262 },
263 |_me| {
264 p.ic_intr_mask().modify(|w| {
265 w.set_m_stop_det(true);
266 w.set_m_rx_done(true);
267 w.set_m_tx_empty(true);
268 w.set_m_tx_abrt(true);
269 })
270 },
271 )
272 .await;
273
274 p.ic_clr_intr().read();
275
276 ret
277 }
278
279 /// Respond to reads with the fill byte until the controller stops asking
280 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
281 loop {
282 match self.respond_to_read(&[fill]).await {
283 Ok(ReadStatus::NeedMoreBytes) => (),
284 Ok(_) => break Ok(()),
285 Err(e) => break Err(e),
286 }
287 }
288 }
289
290 /// Respond to a master read, then fill any remaining read bytes with `fill`
291 pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result<ReadStatus, Error> {
292 let resp_stat = self.respond_to_read(buffer).await?;
293
294 if resp_stat == ReadStatus::NeedMoreBytes {
295 self.respond_till_stop(fill).await?;
296 Ok(ReadStatus::Done)
297 } else {
298 Ok(resp_stat)
299 }
300 }
301
302 #[inline(always)]
303 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
304 let p = T::regs();
305 let mut abort_reason = p.ic_tx_abrt_source().read();
306
307 // Mask off fifo flush count
308 let tx_flush_cnt = abort_reason.tx_flush_cnt();
309 abort_reason.set_tx_flush_cnt(0);
310
311 // Mask off master_dis
312 abort_reason.set_abrt_master_dis(false);
313
314 if abort_reason.0 != 0 {
315 // Note clearing the abort flag also clears the reason, and this
316 // instance of flag is clear-on-read! Note also the
317 // IC_CLR_TX_ABRT register always reads as 0.
318 p.ic_clr_tx_abrt().read();
319
320 let reason = if abort_reason.abrt_7b_addr_noack()
321 | abort_reason.abrt_10addr1_noack()
322 | abort_reason.abrt_10addr2_noack()
323 {
324 AbortReason::NoAcknowledge
325 } else if abort_reason.arb_lost() {
326 AbortReason::ArbitrationLoss
327 } else if abort_reason.abrt_slvflush_txfifo() {
328 AbortReason::TxNotEmpty(tx_flush_cnt)
329 } else {
330 AbortReason::Other(abort_reason.0)
331 };
332
333 Err(Error::Abort(reason))
334 } else {
335 Ok(())
336 }
337 }
338}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 49bd3533e..c3561bbe4 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -16,6 +16,7 @@ pub mod flash;
16mod float; 16mod float;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c; 18pub mod i2c;
19pub mod i2c_slave;
19pub mod multicore; 20pub mod multicore;
20pub mod pwm; 21pub mod pwm;
21mod reset; 22mod reset;
@@ -89,7 +90,8 @@ embassy_hal_internal::interrupt_mod!(
89#[macro_export] 90#[macro_export]
90macro_rules! bind_interrupts { 91macro_rules! bind_interrupts {
91 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 92 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
92 $vis struct $name; 93 #[derive(Copy, Clone)]
94 $vis struct $name;
93 95
94 $( 96 $(
95 #[allow(non_snake_case)] 97 #[allow(non_snake_case)]
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index c09d09143..97dfce2e6 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -1079,18 +1079,43 @@ impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1079pub trait PioPin: sealed::PioPin + gpio::Pin {} 1079pub trait PioPin: sealed::PioPin + gpio::Pin {}
1080 1080
1081macro_rules! impl_pio_pin { 1081macro_rules! impl_pio_pin {
1082 ($( $num:tt )*) => { 1082 ($( $pin:ident, )*) => {
1083 $( 1083 $(
1084 paste::paste!{ 1084 impl sealed::PioPin for peripherals::$pin {}
1085 impl sealed::PioPin for peripherals::[< PIN_ $num >] {} 1085 impl PioPin for peripherals::$pin {}
1086 impl PioPin for peripherals::[< PIN_ $num >] {}
1087 }
1088 )* 1086 )*
1089 }; 1087 };
1090} 1088}
1091 1089
1092impl_pio_pin! { 1090impl_pio_pin! {
1093 0 1 2 3 4 5 6 7 8 9 1091 PIN_0,
1094 10 11 12 13 14 15 16 17 18 19 1092 PIN_1,
1095 20 21 22 23 24 25 26 27 28 29 1093 PIN_2,
1094 PIN_3,
1095 PIN_4,
1096 PIN_5,
1097 PIN_6,
1098 PIN_7,
1099 PIN_8,
1100 PIN_9,
1101 PIN_10,
1102 PIN_11,
1103 PIN_12,
1104 PIN_13,
1105 PIN_14,
1106 PIN_15,
1107 PIN_16,
1108 PIN_17,
1109 PIN_18,
1110 PIN_19,
1111 PIN_20,
1112 PIN_21,
1113 PIN_22,
1114 PIN_23,
1115 PIN_24,
1116 PIN_25,
1117 PIN_26,
1118 PIN_27,
1119 PIN_28,
1120 PIN_29,
1096} 1121}
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 96c474845..3b10b7c52 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -12,8 +12,8 @@ features = ["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.3.0", path = "../embassy-sync" }
16embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } 16embassy-time = { version = "0.1.3", 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-internal = { version = "0.1.0", path = "../embassy-hal-internal" } 18embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-stm32-wpan/src/fmt.rs
+++ b/embassy-stm32-wpan/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs
index cd32692e1..c5f2334f4 100644
--- a/embassy-stm32-wpan/src/sub/ble.rs
+++ b/embassy-stm32-wpan/src/sub/ble.rs
@@ -1,4 +1,3 @@
1use core::marker::PhantomData;
2use core::ptr; 1use core::ptr;
3 2
4use embassy_stm32::ipcc::Ipcc; 3use embassy_stm32::ipcc::Ipcc;
@@ -13,7 +12,7 @@ use crate::unsafe_linked_list::LinkedListNode;
13use crate::{channels, evt}; 12use crate::{channels, evt};
14 13
15pub struct Ble { 14pub struct Ble {
16 phantom: PhantomData<Ble>, 15 _private: (),
17} 16}
18 17
19impl Ble { 18impl Ble {
@@ -29,7 +28,7 @@ impl Ble {
29 }); 28 });
30 } 29 }
31 30
32 Self { phantom: PhantomData } 31 Self { _private: () }
33 } 32 }
34 /// `HW_IPCC_BLE_EvtNot` 33 /// `HW_IPCC_BLE_EvtNot`
35 pub async fn tl_read(&self) -> EvtBox<Self> { 34 pub async fn tl_read(&self) -> EvtBox<Self> {
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
index b0cf0248a..baf4da979 100644
--- a/embassy-stm32-wpan/src/sub/mac.rs
+++ b/embassy-stm32-wpan/src/sub/mac.rs
@@ -1,5 +1,4 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::ptr; 2use core::ptr;
4use core::sync::atomic::{AtomicBool, Ordering}; 3use core::sync::atomic::{AtomicBool, Ordering};
5use core::task::Poll; 4use core::task::Poll;
@@ -21,12 +20,12 @@ static MAC_WAKER: AtomicWaker = AtomicWaker::new();
21static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); 20static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
22 21
23pub struct Mac { 22pub struct Mac {
24 phantom: PhantomData<Mac>, 23 _private: (),
25} 24}
26 25
27impl Mac { 26impl Mac {
28 pub(crate) fn new() -> Self { 27 pub(crate) fn new() -> Self {
29 Self { phantom: PhantomData } 28 Self { _private: () }
30 } 29 }
31 30
32 /// `HW_IPCC_MAC_802_15_4_EvtNot` 31 /// `HW_IPCC_MAC_802_15_4_EvtNot`
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
index da05ad1dd..4e4d2f854 100644
--- a/embassy-stm32-wpan/src/sub/mm.rs
+++ b/embassy-stm32-wpan/src/sub/mm.rs
@@ -1,6 +1,5 @@
1//! Memory manager routines 1//! Memory manager routines
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::mem::MaybeUninit; 3use core::mem::MaybeUninit;
5use core::task::Poll; 4use core::task::Poll;
6 5
@@ -21,7 +20,7 @@ static MM_WAKER: AtomicWaker = AtomicWaker::new();
21static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); 20static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
22 21
23pub struct MemoryManager { 22pub struct MemoryManager {
24 phantom: PhantomData<MemoryManager>, 23 _private: (),
25} 24}
26 25
27impl MemoryManager { 26impl MemoryManager {
@@ -44,7 +43,7 @@ impl MemoryManager {
44 }); 43 });
45 } 44 }
46 45
47 Self { phantom: PhantomData } 46 Self { _private: () }
48 } 47 }
49 48
50 pub async fn run_queue(&self) { 49 pub async fn run_queue(&self) {
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
index c17fd531d..bd2ea3f74 100644
--- a/embassy-stm32-wpan/src/sub/sys.rs
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -1,4 +1,3 @@
1use core::marker::PhantomData;
2use core::ptr; 1use core::ptr;
3 2
4use crate::cmd::CmdPacket; 3use crate::cmd::CmdPacket;
@@ -12,7 +11,7 @@ use crate::unsafe_linked_list::LinkedListNode;
12use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; 11use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
13 12
14pub struct Sys { 13pub struct Sys {
15 phantom: PhantomData<Sys>, 14 _private: (),
16} 15}
17 16
18impl Sys { 17impl Sys {
@@ -27,7 +26,7 @@ impl Sys {
27 }); 26 });
28 } 27 }
29 28
30 Self { phantom: PhantomData } 29 Self { _private: () }
31 } 30 }
32 31
33 /// Returns CPU2 wireless firmware information (if present). 32 /// Returns CPU2 wireless firmware information (if present).
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 612a54f25..1ef92430f 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -8,31 +8,32 @@ license = "MIT OR Apache-2.0"
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" 8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" 9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/"
10 10
11features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] 11features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"]
12flavors = [ 12flavors = [
13 { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, 13 { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" },
14 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, 14 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
15 { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, 15 { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" },
16 { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, 16 { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" },
17 { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi" }, 17 { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power"] },
18 { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, 18 { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" },
19 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, 19 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" },
20 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, 20 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" },
21 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, 21 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
22 { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" }, 22 { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" },
23 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, 23 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
24 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" }, 24 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] },
25 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, 25 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
26 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, 26 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
27 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, 27 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" },
28 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, 28 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
29 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, 29 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
30 { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
30 { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, 31 { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
31] 32]
32 33
33[dependencies] 34[dependencies]
34embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 35embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
35embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } 36embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
36embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 37embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
37embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } 38embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
38embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 39embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@@ -58,11 +59,11 @@ sdio-host = "0.5.0"
58embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
59critical-section = "1.1" 60critical-section = "1.1"
60atomic-polyfill = "1.0.1" 61atomic-polyfill = "1.0.1"
61stm32-metapac = "12" 62stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130" }
62vcell = "0.1.3" 63vcell = "0.1.3"
63bxcan = "0.7.0" 64bxcan = "0.7.0"
64nb = "1.0.0" 65nb = "1.0.0"
65stm32-fmc = "0.2.4" 66stm32-fmc = "0.3.0"
66seq-macro = "0.3.0" 67seq-macro = "0.3.0"
67cfg-if = "1.0.0" 68cfg-if = "1.0.0"
68embedded-io = { version = "0.5.0" } 69embedded-io = { version = "0.5.0" }
@@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
77[build-dependencies] 78[build-dependencies]
78proc-macro2 = "1.0.36" 79proc-macro2 = "1.0.36"
79quote = "1.0.15" 80quote = "1.0.15"
80stm32-metapac = { path = "../../stm32-data-generated/stm32-metapac", default-features = false, features = ["metadata"]} 81stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130", default-features = false, features = ["metadata"]}
81 82
82[features] 83[features]
83default = ["rt"] 84default = ["rt"]
@@ -1454,6 +1455,10 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ]
1454stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ] 1455stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ]
1455stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ] 1456stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ]
1456stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ] 1457stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ]
1458stm32wba52ce = [ "stm32-metapac/stm32wba52ce" ]
1459stm32wba52cg = [ "stm32-metapac/stm32wba52cg" ]
1460stm32wba52ke = [ "stm32-metapac/stm32wba52ke" ]
1461stm32wba52kg = [ "stm32-metapac/stm32wba52kg" ]
1457stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] 1462stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ]
1458stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] 1463stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ]
1459stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] 1464stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 1b86dad7a..ccc9210df 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -308,13 +308,11 @@ fn main() {
308 // ======== 308 // ========
309 // Generate RccPeripheral impls 309 // Generate RccPeripheral impls
310 310
311 let refcounted_peripherals = HashSet::from(["usart", "adc"]);
312 let mut refcount_statics = HashSet::new();
313
311 for p in METADATA.peripherals { 314 for p in METADATA.peripherals {
312 // generating RccPeripheral impl for H7 ADC3 would result in bad frequency 315 if !singletons.contains(&p.name.to_string()) {
313 if !singletons.contains(&p.name.to_string())
314 || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7"))
315 || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3"))
316 || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4"))
317 {
318 continue; 316 continue;
319 } 317 }
320 318
@@ -344,11 +342,36 @@ fn main() {
344 TokenStream::new() 342 TokenStream::new()
345 }; 343 };
346 344
345 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
347 let pname = format_ident!("{}", p.name); 346 let pname = format_ident!("{}", p.name);
348 let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); 347 let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
349 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); 348 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
350 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); 349 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
351 350
351 let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
352 let refcount_static =
353 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
354
355 refcount_statics.insert(refcount_static.clone());
356
357 (
358 quote! {
359 unsafe { refcount_statics::#refcount_static += 1 };
360 if unsafe { refcount_statics::#refcount_static } > 1 {
361 return;
362 }
363 },
364 quote! {
365 unsafe { refcount_statics::#refcount_static -= 1 };
366 if unsafe { refcount_statics::#refcount_static } > 0 {
367 return;
368 }
369 },
370 )
371 } else {
372 (TokenStream::new(), TokenStream::new())
373 };
374
352 g.extend(quote! { 375 g.extend(quote! {
353 impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { 376 impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
354 fn frequency() -> crate::time::Hertz { 377 fn frequency() -> crate::time::Hertz {
@@ -356,6 +379,7 @@ fn main() {
356 } 379 }
357 fn enable() { 380 fn enable() {
358 critical_section::with(|_| { 381 critical_section::with(|_| {
382 #before_enable
359 #[cfg(feature = "low-power")] 383 #[cfg(feature = "low-power")]
360 crate::rcc::clock_refcount_add(); 384 crate::rcc::clock_refcount_add();
361 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); 385 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
@@ -364,6 +388,7 @@ fn main() {
364 } 388 }
365 fn disable() { 389 fn disable() {
366 critical_section::with(|_| { 390 critical_section::with(|_| {
391 #before_disable
367 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); 392 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
368 #[cfg(feature = "low-power")] 393 #[cfg(feature = "low-power")]
369 crate::rcc::clock_refcount_sub(); 394 crate::rcc::clock_refcount_sub();
@@ -379,6 +404,19 @@ fn main() {
379 } 404 }
380 } 405 }
381 406
407 let mut refcount_mod = TokenStream::new();
408 for refcount_static in refcount_statics {
409 refcount_mod.extend(quote! {
410 pub(crate) static mut #refcount_static: u8 = 0;
411 });
412 }
413
414 g.extend(quote! {
415 mod refcount_statics {
416 #refcount_mod
417 }
418 });
419
382 // ======== 420 // ========
383 // Generate fns to enable GPIO, DMA in RCC 421 // Generate fns to enable GPIO, DMA in RCC
384 422
@@ -673,6 +711,10 @@ fn main() {
673 711
674 // ADC is special 712 // ADC is special
675 if regs.kind == "adc" { 713 if regs.kind == "adc" {
714 if p.rcc.is_none() {
715 continue;
716 }
717
676 let peri = format_ident!("{}", p.name); 718 let peri = format_ident!("{}", p.name);
677 let pin_name = format_ident!("{}", pin.pin); 719 let pin_name = format_ident!("{}", pin.pin);
678 720
@@ -786,6 +828,17 @@ fn main() {
786 let mut peripherals_table: Vec<Vec<String>> = Vec::new(); 828 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
787 let mut pins_table: Vec<Vec<String>> = Vec::new(); 829 let mut pins_table: Vec<Vec<String>> = Vec::new();
788 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 830 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
831 let mut adc_common_table: Vec<Vec<String>> = Vec::new();
832
833 /*
834 If ADC3_COMMON exists, ADC3 and higher are assigned to it
835 All other ADCs are assigned to ADC_COMMON
836
837 ADC3 and higher are assigned to the adc34 clock in the table
838 The adc3_common cfg directive is added if ADC3_COMMON exists
839 */
840 let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some();
841 let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]);
789 842
790 for m in METADATA 843 for m in METADATA
791 .memory 844 .memory
@@ -823,6 +876,17 @@ fn main() {
823 } 876 }
824 } 877 }
825 878
879 if regs.kind == "adc" {
880 let (adc_common, adc_clock) = if set_adc345.contains(p.name) && has_adc3 {
881 ("ADC3_COMMON", "adc34")
882 } else {
883 ("ADC_COMMON", "adc")
884 };
885
886 let row = vec![p.name.to_string(), adc_common.to_string(), adc_clock.to_string()];
887 adc_common_table.push(row);
888 }
889
826 for irq in p.interrupts { 890 for irq in p.interrupts {
827 let row = vec![ 891 let row = vec![
828 p.name.to_string(), 892 p.name.to_string(),
@@ -901,6 +965,7 @@ fn main() {
901 make_table(&mut m, "foreach_peripheral", &peripherals_table); 965 make_table(&mut m, "foreach_peripheral", &peripherals_table);
902 make_table(&mut m, "foreach_pin", &pins_table); 966 make_table(&mut m, "foreach_pin", &pins_table);
903 make_table(&mut m, "foreach_dma_channel", &dma_channels_table); 967 make_table(&mut m, "foreach_dma_channel", &dma_channels_table);
968 make_table(&mut m, "foreach_adc", &adc_common_table);
904 969
905 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 970 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
906 let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string(); 971 let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string();
@@ -943,12 +1008,23 @@ fn main() {
943 } 1008 }
944 1009
945 // ======= 1010 // =======
1011 // ADC3_COMMON is present
1012 if has_adc3 {
1013 println!("cargo:rustc-cfg={}", "adc3_common");
1014 }
1015
1016 // =======
946 // Features for targeting groups of chips 1017 // Features for targeting groups of chips
947 1018
948 println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 1019 if &chip_name[..8] == "stm32wba" {
949 println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 1020 println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba
950 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x 1021 println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52
951 println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 1022 } else {
1023 println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4
1024 println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
1025 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
1026 println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
1027 }
952 1028
953 // Handle time-driver-XXXX features. 1029 // Handle time-driver-XXXX features.
954 if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {} 1030 if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index e577ec289..c13264819 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -1,16 +1,37 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll;
4
1use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
3 7
4use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
5use crate::rcc::get_freqs; 9use crate::rcc::get_freqs;
6use crate::time::Hertz; 10use crate::time::Hertz;
7use crate::Peripheral; 11use crate::{interrupt, Peripheral};
8 12
9pub const VDDA_CALIB_MV: u32 = 3300; 13pub const VDDA_CALIB_MV: u32 = 3300;
10pub const ADC_MAX: u32 = (1 << 12) - 1; 14pub const ADC_MAX: u32 = (1 << 12) - 1;
11// No calibration data for F103, voltage should be 1.2v 15// No calibration data for F103, voltage should be 1.2v
12pub const VREF_INT: u32 = 1200; 16pub const VREF_INT: u32 = 1200;
13 17
18/// Interrupt handler.
19pub struct InterruptHandler<T: Instance> {
20 _phantom: PhantomData<T>,
21}
22
23impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
24 unsafe fn on_interrupt() {
25 if T::regs().sr().read().eoc() {
26 T::regs().cr1().modify(|w| w.set_eocie(false));
27 } else {
28 return;
29 }
30
31 T::state().waker.wake();
32 }
33}
34
14pub struct Vref; 35pub struct Vref;
15impl<T: Instance> AdcPin<T> for Vref {} 36impl<T: Instance> AdcPin<T> for Vref {}
16impl<T: Instance> super::sealed::AdcPin<T> for Vref { 37impl<T: Instance> super::sealed::AdcPin<T> for Vref {
@@ -60,7 +81,7 @@ impl<'d, T: Instance> Adc<'d, T> {
60 } 81 }
61 82
62 fn freq() -> Hertz { 83 fn freq() -> Hertz {
63 unsafe { get_freqs() }.adc 84 unsafe { get_freqs() }.adc.unwrap()
64 } 85 }
65 86
66 pub fn sample_time_for_us(&self, us: u32) -> SampleTime { 87 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
@@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> {
95 } 116 }
96 117
97 /// Perform a single conversion. 118 /// Perform a single conversion.
98 fn convert(&mut self) -> u16 { 119 async fn convert(&mut self) -> u16 {
99 T::regs().cr2().modify(|reg| { 120 T::regs().cr2().modify(|reg| {
100 reg.set_adon(true); 121 reg.set_adon(true);
101 reg.set_swstart(true); 122 reg.set_swstart(true);
102 }); 123 });
103 while T::regs().cr2().read().swstart() {} 124 T::regs().cr1().modify(|w| w.set_eocie(true));
104 while !T::regs().sr().read().eoc() {} 125
126 poll_fn(|cx| {
127 T::state().waker.register(cx.waker());
128
129 if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() {
130 Poll::Ready(())
131 } else {
132 Poll::Pending
133 }
134 })
135 .await;
105 136
106 T::regs().dr().read().0 as u16 137 T::regs().dr().read().0 as u16
107 } 138 }
108 139
109 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 140 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
110 Self::set_channel_sample_time(pin.channel(), self.sample_time); 141 Self::set_channel_sample_time(pin.channel(), self.sample_time);
111 T::regs().cr1().modify(|reg| { 142 T::regs().cr1().modify(|reg| {
112 reg.set_scan(false); 143 reg.set_scan(false);
@@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> {
123 154
124 // Configure the channel to sample 155 // Configure the channel to sample
125 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); 156 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
126 self.convert() 157 self.convert().await
127 } 158 }
128 159
129 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 160 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> {
135 } 166 }
136 } 167 }
137} 168}
169
170impl<'d, T: Instance> Drop for Adc<'d, T> {
171 fn drop(&mut self) {
172 T::regs().cr2().modify(|reg| reg.set_adon(false));
173
174 T::disable();
175 }
176}
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
new file mode 100644
index 000000000..7c13f8106
--- /dev/null
+++ b/embassy-stm32/src/adc/f3.rs
@@ -0,0 +1,195 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll;
4
5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs;
7
8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
9use crate::interrupt::typelevel::Interrupt;
10use crate::time::Hertz;
11use crate::{interrupt, Peripheral};
12
13pub const VDDA_CALIB_MV: u32 = 3300;
14pub const ADC_MAX: u32 = (1 << 12) - 1;
15pub const VREF_INT: u32 = 1230;
16
17/// Interrupt handler.
18pub struct InterruptHandler<T: Instance> {
19 _phantom: PhantomData<T>,
20}
21
22impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
23 unsafe fn on_interrupt() {
24 if T::regs().isr().read().eoc() {
25 T::regs().ier().modify(|w| w.set_eocie(false));
26 } else {
27 return;
28 }
29
30 T::state().waker.wake();
31 }
32}
33
34pub struct Vref;
35impl<T: Instance> AdcPin<T> for Vref {}
36impl<T: Instance> super::sealed::AdcPin<T> for Vref {
37 fn channel(&self) -> u8 {
38 18
39 }
40}
41
42impl Vref {
43 /// The value that vref would be if vdda was at 3300mv
44 pub fn value(&self) -> u16 {
45 crate::pac::VREFINTCAL.data().read().value()
46 }
47}
48
49pub struct Temperature;
50impl<T: Instance> AdcPin<T> for Temperature {}
51impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
52 fn channel(&self) -> u8 {
53 16
54 }
55}
56
57impl<'d, T: Instance> Adc<'d, T> {
58 pub fn new(
59 adc: impl Peripheral<P = T> + 'd,
60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 delay: &mut impl DelayUs<u32>,
62 ) -> Self {
63 use crate::pac::adc::vals;
64
65 into_ref!(adc);
66
67 T::enable();
68 T::reset();
69
70 // Enable the adc regulator
71 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
72 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
73
74 // Wait for the regulator to stabilize
75 delay.delay_us(10);
76
77 assert!(!T::regs().cr().read().aden());
78
79 // Begin calibration
80 T::regs().cr().modify(|w| w.set_adcaldif(false));
81 T::regs().cr().modify(|w| w.set_adcal(true));
82
83 while T::regs().cr().read().adcal() {}
84
85 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
86 delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
87
88 // Enable the adc
89 T::regs().cr().modify(|w| w.set_aden(true));
90
91 // Wait until the adc is ready
92 while !T::regs().isr().read().adrdy() {}
93
94 T::Interrupt::unpend();
95 unsafe {
96 T::Interrupt::enable();
97 }
98
99 Self {
100 adc,
101 sample_time: Default::default(),
102 }
103 }
104
105 fn freq() -> Hertz {
106 <T as crate::adc::sealed::Instance>::frequency()
107 }
108
109 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
110 match us * Self::freq().0 / 1_000_000 {
111 0..=1 => SampleTime::Cycles1_5,
112 2..=4 => SampleTime::Cycles4_5,
113 5..=7 => SampleTime::Cycles7_5,
114 8..=19 => SampleTime::Cycles19_5,
115 20..=61 => SampleTime::Cycles61_5,
116 62..=181 => SampleTime::Cycles181_5,
117 _ => SampleTime::Cycles601_5,
118 }
119 }
120
121 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
122 T::common_regs().ccr().modify(|w| w.set_vrefen(true));
123
124 Vref {}
125 }
126
127 pub fn enable_temperature(&self) -> Temperature {
128 T::common_regs().ccr().modify(|w| w.set_tsen(true));
129
130 Temperature {}
131 }
132
133 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
134 self.sample_time = sample_time;
135 }
136
137 /// Perform a single conversion.
138 async fn convert(&mut self) -> u16 {
139 T::regs().isr().write(|_| {});
140 T::regs().ier().modify(|w| w.set_eocie(true));
141 T::regs().cr().modify(|w| w.set_adstart(true));
142
143 poll_fn(|cx| {
144 T::state().waker.register(cx.waker());
145
146 if T::regs().isr().read().eoc() {
147 Poll::Ready(())
148 } else {
149 Poll::Pending
150 }
151 })
152 .await;
153
154 T::regs().isr().write(|_| {});
155
156 T::regs().dr().read().rdata()
157 }
158
159 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
160 Self::set_channel_sample_time(pin.channel(), self.sample_time);
161
162 // Configure the channel to sample
163 T::regs().sqr1().write(|w| w.set_sq(0, pin.channel()));
164 self.convert().await
165 }
166
167 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
168 let sample_time = sample_time.into();
169 if ch <= 9 {
170 T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
171 } else {
172 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
173 }
174 }
175}
176
177impl<'d, T: Instance> Drop for Adc<'d, T> {
178 fn drop(&mut self) {
179 use crate::pac::adc::vals;
180
181 T::regs().cr().modify(|w| w.set_adstp(true));
182
183 while T::regs().cr().read().adstp() {}
184
185 T::regs().cr().modify(|w| w.set_addis(true));
186
187 while T::regs().cr().read().aden() {}
188
189 // Disable the adc regulator
190 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
191 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
192
193 T::disable();
194 }
195}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index e57889aa6..365738a31 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,23 +1,24 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg(not(any(adc_f3, adc_f3_v2)))] 3#[cfg(not(adc_f3_v2))]
4#[cfg_attr(adc_f1, path = "f1.rs")] 4#[cfg_attr(adc_f1, path = "f1.rs")]
5#[cfg_attr(adc_f3, path = "f3.rs")]
5#[cfg_attr(adc_v1, path = "v1.rs")] 6#[cfg_attr(adc_v1, path = "v1.rs")]
6#[cfg_attr(adc_v2, path = "v2.rs")] 7#[cfg_attr(adc_v2, path = "v2.rs")]
7#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] 8#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
8#[cfg_attr(adc_v4, path = "v4.rs")] 9#[cfg_attr(adc_v4, path = "v4.rs")]
9mod _version; 10mod _version;
10 11
11#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] 12#[cfg(not(any(adc_f1, adc_f3_v2)))]
12mod resolution; 13mod resolution;
13mod sample_time; 14mod sample_time;
14 15
15#[cfg(not(any(adc_f3, adc_f3_v2)))]
16#[allow(unused)] 16#[allow(unused)]
17#[cfg(not(adc_f3_v2))]
17pub use _version::*; 18pub use _version::*;
18#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] 19#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
19pub use resolution::Resolution; 20pub use resolution::Resolution;
20#[cfg(not(any(adc_f3, adc_f3_v2)))] 21#[cfg(not(adc_f3_v2))]
21pub use sample_time::SampleTime; 22pub use sample_time::SampleTime;
22 23
23use crate::peripherals; 24use crate::peripherals;
@@ -25,18 +26,46 @@ use crate::peripherals;
25pub struct Adc<'d, T: Instance> { 26pub struct Adc<'d, T: Instance> {
26 #[allow(unused)] 27 #[allow(unused)]
27 adc: crate::PeripheralRef<'d, T>, 28 adc: crate::PeripheralRef<'d, T>,
28 #[cfg(not(any(adc_f3, adc_f3_v2)))] 29 #[cfg(not(adc_f3_v2))]
29 sample_time: SampleTime, 30 sample_time: SampleTime,
30} 31}
31 32
32pub(crate) mod sealed { 33pub(crate) mod sealed {
33 pub trait Instance { 34 #[cfg(any(adc_f1, adc_f3, adc_v1))]
35 use embassy_sync::waitqueue::AtomicWaker;
36
37 #[cfg(any(adc_f1, adc_f3, adc_v1))]
38 pub struct State {
39 pub waker: AtomicWaker,
40 }
41
42 #[cfg(any(adc_f1, adc_f3, adc_v1))]
43 impl State {
44 pub const fn new() -> Self {
45 Self {
46 waker: AtomicWaker::new(),
47 }
48 }
49 }
50
51 pub trait InterruptableInstance {
52 type Interrupt: crate::interrupt::typelevel::Interrupt;
53 }
54
55 pub trait Instance: InterruptableInstance {
34 fn regs() -> crate::pac::adc::Adc; 56 fn regs() -> crate::pac::adc::Adc;
35 #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] 57 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
36 fn common_regs() -> crate::pac::adccommon::AdcCommon; 58 fn common_regs() -> crate::pac::adccommon::AdcCommon;
59 #[cfg(adc_f3)]
60 fn frequency() -> crate::time::Hertz;
61 #[cfg(any(adc_f1, adc_f3, adc_v1))]
62 fn state() -> &'static State;
37 } 63 }
38 64
39 pub trait AdcPin<T: Instance> { 65 pub trait AdcPin<T: Instance> {
66 #[cfg(any(adc_v1, adc_v2))]
67 fn set_as_analog(&mut self) {}
68
40 fn channel(&self) -> u8; 69 fn channel(&self) -> u8;
41 } 70 }
42 71
@@ -45,68 +74,45 @@ pub(crate) mod sealed {
45 } 74 }
46} 75}
47 76
48#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] 77#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))]
49pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 78pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
50#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] 79#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))]
51pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 80pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
52 81
53pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 82pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
54pub trait InternalChannel<T>: sealed::InternalChannel<T> {} 83pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
55 84
56#[cfg(not(stm32h7))] 85foreach_adc!(
57foreach_peripheral!( 86 ($inst:ident, $common_inst:ident, $clock:ident) => {
58 (adc, $inst:ident) => {
59 impl crate::adc::sealed::Instance for peripherals::$inst { 87 impl crate::adc::sealed::Instance for peripherals::$inst {
60 fn regs() -> crate::pac::adc::Adc { 88 fn regs() -> crate::pac::adc::Adc {
61 crate::pac::$inst 89 crate::pac::$inst
62 } 90 }
63 #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] 91
92 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
64 fn common_regs() -> crate::pac::adccommon::AdcCommon { 93 fn common_regs() -> crate::pac::adccommon::AdcCommon {
65 foreach_peripheral!{ 94 return crate::pac::$common_inst
66 (adccommon, $common_inst:ident) => {
67 return crate::pac::$common_inst
68 };
69 }
70 } 95 }
71 }
72
73 impl crate::adc::Instance for peripherals::$inst {}
74 };
75);
76 96
77#[cfg(stm32h7)] 97 #[cfg(adc_f3)]
78foreach_peripheral!( 98 fn frequency() -> crate::time::Hertz {
79 (adc, ADC3) => { 99 unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
80 impl crate::adc::sealed::Instance for peripherals::ADC3 {
81 fn regs() -> crate::pac::adc::Adc {
82 crate::pac::ADC3
83 } 100 }
84 #[cfg(all(not(adc_f1), not(adc_v1)))] 101
85 fn common_regs() -> crate::pac::adccommon::AdcCommon { 102 #[cfg(any(adc_f1, adc_f3, adc_v1))]
86 foreach_peripheral!{ 103 fn state() -> &'static sealed::State {
87 (adccommon, ADC3_COMMON) => { 104 static STATE: sealed::State = sealed::State::new();
88 return crate::pac::ADC3_COMMON 105 &STATE
89 };
90 }
91 } 106 }
92 } 107 }
93 108
94 impl crate::adc::Instance for peripherals::ADC3 {} 109 foreach_interrupt!(
95 }; 110 ($inst,adc,ADC,GLOBAL,$irq:ident) => {
96 (adc, $inst:ident) => { 111 impl sealed::InterruptableInstance for peripherals::$inst {
97 impl crate::adc::sealed::Instance for peripherals::$inst { 112 type Interrupt = crate::interrupt::typelevel::$irq;
98 fn regs() -> crate::pac::adc::Adc {
99 crate::pac::$inst
100 }
101 #[cfg(all(not(adc_f1), not(adc_v1)))]
102 fn common_regs() -> crate::pac::adccommon::AdcCommon {
103 foreach_peripheral!{
104 (adccommon, ADC_COMMON) => {
105 return crate::pac::ADC_COMMON
106 };
107 } 113 }
108 } 114 };
109 } 115 );
110 116
111 impl crate::adc::Instance for peripherals::$inst {} 117 impl crate::adc::Instance for peripherals::$inst {}
112 }; 118 };
@@ -117,6 +123,11 @@ macro_rules! impl_adc_pin {
117 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} 123 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
118 124
119 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { 125 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
126 #[cfg(any(adc_v1, adc_v2))]
127 fn set_as_analog(&mut self) {
128 <Self as crate::gpio::sealed::Pin>::set_as_analog(self);
129 }
130
120 fn channel(&self) -> u8 { 131 fn channel(&self) -> u8 {
121 $ch 132 $ch
122 } 133 }
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 67fb9b8c0..5668137b5 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,4 +1,4 @@
1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] 1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
2#[derive(Clone, Copy, Debug, Eq, PartialEq)] 2#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3pub enum Resolution { 3pub enum Resolution {
4 TwelveBit, 4 TwelveBit,
@@ -19,7 +19,7 @@ pub enum Resolution {
19 19
20impl Default for Resolution { 20impl Default for Resolution {
21 fn default() -> Self { 21 fn default() -> Self {
22 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] 22 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
23 { 23 {
24 Self::TwelveBit 24 Self::TwelveBit
25 } 25 }
@@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, 40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, 41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, 42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
43 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] 43 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, 44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
45 } 45 }
46 } 46 }
@@ -56,7 +56,7 @@ impl Resolution {
56 Resolution::TwelveBit => (1 << 12) - 1, 56 Resolution::TwelveBit => (1 << 12) - 1,
57 Resolution::TenBit => (1 << 10) - 1, 57 Resolution::TenBit => (1 << 10) - 1,
58 Resolution::EightBit => (1 << 8) - 1, 58 Resolution::EightBit => (1 << 8) - 1,
59 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] 59 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
60 Resolution::SixBit => (1 << 6) - 1, 60 Resolution::SixBit => (1 << 6) - 1,
61 } 61 }
62 } 62 }
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 5480e7a77..6a6619299 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -1,4 +1,4 @@
1#[cfg(not(any(adc_f3, adc_f3_v2)))] 1#[cfg(not(adc_f3_v2))]
2macro_rules! impl_sample_time { 2macro_rules! impl_sample_time {
3 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { 3 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
4 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] 4 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
@@ -105,3 +105,19 @@ impl_sample_time!(
105 ("810.5", Cycles810_5, CYCLES810_5) 105 ("810.5", Cycles810_5, CYCLES810_5)
106 ) 106 )
107); 107);
108
109#[cfg(adc_f3)]
110impl_sample_time!(
111 "1.5",
112 Cycles1_5,
113 (
114 ("1.5", Cycles1_5, CYCLES1_5),
115 ("2.5", Cycles2_5, CYCLES2_5),
116 ("4.5", Cycles4_5, CYCLES4_5),
117 ("7.5", Cycles7_5, CYCLES7_5),
118 ("19.5", Cycles19_5, CYCLES19_5),
119 ("61.5", Cycles61_5, CYCLES61_5),
120 ("181.5", Cycles181_5, CYCLES181_5),
121 ("601.5", Cycles601_5, CYCLES601_5)
122 )
123);
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index e8245884e..fded26e40 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -1,39 +1,65 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll;
4
1use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
3 7
4use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
9use crate::interrupt::typelevel::Interrupt;
5use crate::peripherals::ADC; 10use crate::peripherals::ADC;
6use crate::Peripheral; 11use crate::{interrupt, Peripheral};
7 12
8pub const VDDA_CALIB_MV: u32 = 3300; 13pub const VDDA_CALIB_MV: u32 = 3300;
9pub const VREF_INT: u32 = 1230; 14pub const VREF_INT: u32 = 1230;
10 15
16/// Interrupt handler.
17pub struct InterruptHandler<T: Instance> {
18 _phantom: PhantomData<T>,
19}
20
21impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
22 unsafe fn on_interrupt() {
23 if T::regs().isr().read().eoc() {
24 T::regs().ier().modify(|w| w.set_eocie(false));
25 } else {
26 return;
27 }
28
29 T::state().waker.wake();
30 }
31}
32
11pub struct Vbat; 33pub struct Vbat;
12impl InternalChannel<ADC> for Vbat {} 34impl AdcPin<ADC> for Vbat {}
13impl super::sealed::InternalChannel<ADC> for Vbat { 35impl super::sealed::AdcPin<ADC> for Vbat {
14 fn channel(&self) -> u8 { 36 fn channel(&self) -> u8 {
15 18 37 18
16 } 38 }
17} 39}
18 40
19pub struct Vref; 41pub struct Vref;
20impl InternalChannel<ADC> for Vref {} 42impl AdcPin<ADC> for Vref {}
21impl super::sealed::InternalChannel<ADC> for Vref { 43impl super::sealed::AdcPin<ADC> for Vref {
22 fn channel(&self) -> u8 { 44 fn channel(&self) -> u8 {
23 17 45 17
24 } 46 }
25} 47}
26 48
27pub struct Temperature; 49pub struct Temperature;
28impl InternalChannel<ADC> for Temperature {} 50impl AdcPin<ADC> for Temperature {}
29impl super::sealed::InternalChannel<ADC> for Temperature { 51impl super::sealed::AdcPin<ADC> for Temperature {
30 fn channel(&self) -> u8 { 52 fn channel(&self) -> u8 {
31 16 53 16
32 } 54 }
33} 55}
34 56
35impl<'d, T: Instance> Adc<'d, T> { 57impl<'d, T: Instance> Adc<'d, T> {
36 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 58 pub fn new(
59 adc: impl Peripheral<P = T> + 'd,
60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 delay: &mut impl DelayUs<u32>,
62 ) -> Self {
37 into_ref!(adc); 63 into_ref!(adc);
38 T::enable(); 64 T::enable();
39 T::reset(); 65 T::reset();
@@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> {
44 // tstab = 14 * 1/fadc 70 // tstab = 14 * 1/fadc
45 delay.delay_us(1); 71 delay.delay_us(1);
46 72
47 let s = Self { 73 // A.7.1 ADC calibration code example
74 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
75 T::regs().cr().modify(|reg| reg.set_adcal(true));
76 while T::regs().cr().read().adcal() {}
77
78 // A.7.2 ADC enable sequence code example
79 if T::regs().isr().read().adrdy() {
80 T::regs().isr().modify(|reg| reg.set_adrdy(true));
81 }
82 T::regs().cr().modify(|reg| reg.set_aden(true));
83 while !T::regs().isr().read().adrdy() {
84 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
85 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
86 // ADEN bit until the ADRDY flag goes high.
87 T::regs().cr().modify(|reg| reg.set_aden(true));
88 }
89
90 T::Interrupt::unpend();
91 unsafe {
92 T::Interrupt::enable();
93 }
94
95 Self {
48 adc, 96 adc,
49 sample_time: Default::default(), 97 sample_time: Default::default(),
50 }; 98 }
51 s.calibrate();
52 s
53 } 99 }
54 100
55 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { 101 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
@@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> {
80 Temperature 126 Temperature
81 } 127 }
82 128
83 fn calibrate(&self) {
84 // A.7.1 ADC calibration code example
85 if T::regs().cr().read().aden() {
86 T::regs().cr().modify(|reg| reg.set_addis(true));
87 }
88 while T::regs().cr().read().aden() {
89 // spin
90 }
91 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
92 T::regs().cr().modify(|reg| reg.set_adcal(true));
93 while T::regs().cr().read().adcal() {
94 // spin
95 }
96 }
97
98 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 129 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
99 self.sample_time = sample_time; 130 self.sample_time = sample_time;
100 } 131 }
@@ -103,57 +134,50 @@ impl<'d, T: Instance> Adc<'d, T> {
103 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 134 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
104 } 135 }
105 136
106 pub fn read<P>(&mut self, pin: &mut P) -> u16 137 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
107 where
108 P: AdcPin<T> + crate::gpio::sealed::Pin,
109 {
110 let channel = pin.channel(); 138 let channel = pin.channel();
111 pin.set_as_analog(); 139 pin.set_as_analog();
112 self.read_channel(channel)
113 }
114 140
115 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 141 // A.7.5 Single conversion sequence code example - Software trigger
116 let channel = channel.channel(); 142 T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
117 self.read_channel(channel)
118 }
119 143
120 fn read_channel(&mut self, channel: u8) -> u16 { 144 self.convert().await
121 // A.7.2 ADC enable sequence code example 145 }
122 if T::regs().isr().read().adrdy() {
123 T::regs().isr().modify(|reg| reg.set_adrdy(true));
124 }
125 T::regs().cr().modify(|reg| reg.set_aden(true));
126 while !T::regs().isr().read().adrdy() {
127 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
128 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
129 // ADEN bit until the ADRDY flag goes high.
130 T::regs().cr().modify(|reg| reg.set_aden(true));
131 }
132 146
147 async fn convert(&mut self) -> u16 {
133 T::regs().isr().modify(|reg| { 148 T::regs().isr().modify(|reg| {
134 reg.set_eoc(true); 149 reg.set_eoc(true);
135 reg.set_eosmp(true); 150 reg.set_eosmp(true);
136 }); 151 });
137 152
138 // A.7.5 Single conversion sequence code example - Software trigger
139 T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
140 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); 153 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
154 T::regs().ier().modify(|w| w.set_eocie(true));
141 T::regs().cr().modify(|reg| reg.set_adstart(true)); 155 T::regs().cr().modify(|reg| reg.set_adstart(true));
142 while !T::regs().isr().read().eoc() {
143 // spin
144 }
145 let value = T::regs().dr().read().0 as u16;
146 156
157 poll_fn(|cx| {
158 T::state().waker.register(cx.waker());
159
160 if T::regs().isr().read().eoc() {
161 Poll::Ready(())
162 } else {
163 Poll::Pending
164 }
165 })
166 .await;
167
168 T::regs().dr().read().data()
169 }
170}
171
172impl<'d, T: Instance> Drop for Adc<'d, T> {
173 fn drop(&mut self) {
147 // A.7.3 ADC disable code example 174 // A.7.3 ADC disable code example
148 T::regs().cr().modify(|reg| reg.set_adstp(true)); 175 T::regs().cr().modify(|reg| reg.set_adstp(true));
149 while T::regs().cr().read().adstp() { 176 while T::regs().cr().read().adstp() {}
150 // spin 177
151 }
152 T::regs().cr().modify(|reg| reg.set_addis(true)); 178 T::regs().cr().modify(|reg| reg.set_addis(true));
153 while T::regs().cr().read().aden() { 179 while T::regs().cr().read().aden() {}
154 // spin
155 }
156 180
157 value 181 T::disable();
158 } 182 }
159} 183}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 9a7acea53..a669013c9 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,7 +1,6 @@
1use embassy_hal_internal::into_ref; 1use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs; 2use embedded_hal_02::blocking::delay::DelayUs;
3 3
4use super::InternalChannel;
5use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
6use crate::peripherals::ADC1; 5use crate::peripherals::ADC1;
7use crate::time::Hertz; 6use crate::time::Hertz;
@@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
16pub const ADC_POWERUP_TIME_US: u32 = 3; 15pub const ADC_POWERUP_TIME_US: u32 = 3;
17 16
18pub struct VrefInt; 17pub struct VrefInt;
19impl InternalChannel<ADC1> for VrefInt {} 18impl AdcPin<ADC1> for VrefInt {}
20impl super::sealed::InternalChannel<ADC1> for VrefInt { 19impl super::sealed::AdcPin<ADC1> for VrefInt {
21 fn channel(&self) -> u8 { 20 fn channel(&self) -> u8 {
22 17 21 17
23 } 22 }
@@ -31,8 +30,8 @@ impl VrefInt {
31} 30}
32 31
33pub struct Temperature; 32pub struct Temperature;
34impl InternalChannel<ADC1> for Temperature {} 33impl AdcPin<ADC1> for Temperature {}
35impl super::sealed::InternalChannel<ADC1> for Temperature { 34impl super::sealed::AdcPin<ADC1> for Temperature {
36 fn channel(&self) -> u8 { 35 fn channel(&self) -> u8 {
37 cfg_if::cfg_if! { 36 cfg_if::cfg_if! {
38 if #[cfg(any(stm32f40, stm32f41))] { 37 if #[cfg(any(stm32f40, stm32f41))] {
@@ -52,8 +51,8 @@ impl Temperature {
52} 51}
53 52
54pub struct Vbat; 53pub struct Vbat;
55impl InternalChannel<ADC1> for Vbat {} 54impl AdcPin<ADC1> for Vbat {}
56impl super::sealed::InternalChannel<ADC1> for Vbat { 55impl super::sealed::AdcPin<ADC1> for Vbat {
57 fn channel(&self) -> u8 { 56 fn channel(&self) -> u8 {
58 18 57 18
59 } 58 }
@@ -102,7 +101,7 @@ where
102 let presc = Prescaler::from_pclk2(T::frequency()); 101 let presc = Prescaler::from_pclk2(T::frequency());
103 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 102 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
104 T::regs().cr2().modify(|reg| { 103 T::regs().cr2().modify(|reg| {
105 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); 104 reg.set_adon(true);
106 }); 105 });
107 106
108 delay.delay_us(ADC_POWERUP_TIME_US); 107 delay.delay_us(ADC_POWERUP_TIME_US);
@@ -125,7 +124,7 @@ where
125 /// [Adc::read_internal()] to perform conversion. 124 /// [Adc::read_internal()] to perform conversion.
126 pub fn enable_vrefint(&self) -> VrefInt { 125 pub fn enable_vrefint(&self) -> VrefInt {
127 T::common_regs().ccr().modify(|reg| { 126 T::common_regs().ccr().modify(|reg| {
128 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 127 reg.set_tsvrefe(true);
129 }); 128 });
130 129
131 VrefInt {} 130 VrefInt {}
@@ -138,7 +137,7 @@ where
138 /// temperature sensor will return vbat value. 137 /// temperature sensor will return vbat value.
139 pub fn enable_temperature(&self) -> Temperature { 138 pub fn enable_temperature(&self) -> Temperature {
140 T::common_regs().ccr().modify(|reg| { 139 T::common_regs().ccr().modify(|reg| {
141 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 140 reg.set_tsvrefe(true);
142 }); 141 });
143 142
144 Temperature {} 143 Temperature {}
@@ -148,7 +147,7 @@ where
148 /// [Adc::read_internal()] to perform conversion. 147 /// [Adc::read_internal()] to perform conversion.
149 pub fn enable_vbat(&self) -> Vbat { 148 pub fn enable_vbat(&self) -> Vbat {
150 T::common_regs().ccr().modify(|reg| { 149 T::common_regs().ccr().modify(|reg| {
151 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); 150 reg.set_vbate(true);
152 }); 151 });
153 152
154 Vbat {} 153 Vbat {}
@@ -176,22 +175,11 @@ where
176 T::regs().dr().read().0 as u16 175 T::regs().dr().read().0 as u16
177 } 176 }
178 177
179 pub fn read<P>(&mut self, pin: &mut P) -> u16 178 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
180 where
181 P: AdcPin<T>,
182 P: crate::gpio::sealed::Pin,
183 {
184 pin.set_as_analog(); 179 pin.set_as_analog();
185 180
186 self.read_channel(pin.channel())
187 }
188
189 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
190 self.read_channel(channel.channel())
191 }
192
193 fn read_channel(&mut self, channel: u8) -> u16 {
194 // Configure ADC 181 // Configure ADC
182 let channel = pin.channel();
195 183
196 // Select channel 184 // Select channel
197 T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); 185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
@@ -199,9 +187,7 @@ where
199 // Configure channel 187 // Configure channel
200 Self::set_channel_sample_time(channel, self.sample_time); 188 Self::set_channel_sample_time(channel, self.sample_time);
201 189
202 let val = self.convert(); 190 self.convert()
203
204 val
205 } 191 }
206 192
207 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 193 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@@ -216,6 +202,10 @@ where
216 202
217impl<'d, T: Instance> Drop for Adc<'d, T> { 203impl<'d, T: Instance> Drop for Adc<'d, T> {
218 fn drop(&mut self) { 204 fn drop(&mut self) {
205 T::regs().cr2().modify(|reg| {
206 reg.set_adon(false);
207 });
208
219 T::disable(); 209 T::disable();
220 } 210 }
221} 211}
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 821cc7f6a..011ecc281 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
13/// configuration. 13/// configuration.
14fn enable() { 14fn enable() {
15 critical_section::with(|_| { 15 critical_section::with(|_| {
16 #[cfg(stm32h7)] 16 #[cfg(any(stm32h7, stm32wl))]
17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); 17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
18 #[cfg(stm32g0)] 18 #[cfg(stm32g0)]
19 crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); 19 crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
@@ -26,9 +26,9 @@ pub struct VrefInt;
26impl<T: Instance> AdcPin<T> for VrefInt {} 26impl<T: Instance> AdcPin<T> for VrefInt {}
27impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { 27impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
28 fn channel(&self) -> u8 { 28 fn channel(&self) -> u8 {
29 #[cfg(not(stm32g0))] 29 #[cfg(not(adc_g0))]
30 let val = 0; 30 let val = 0;
31 #[cfg(stm32g0)] 31 #[cfg(adc_g0)]
32 let val = 13; 32 let val = 13;
33 val 33 val
34 } 34 }
@@ -38,9 +38,9 @@ pub struct Temperature;
38impl<T: Instance> AdcPin<T> for Temperature {} 38impl<T: Instance> AdcPin<T> for Temperature {}
39impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 39impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
40 fn channel(&self) -> u8 { 40 fn channel(&self) -> u8 {
41 #[cfg(not(stm32g0))] 41 #[cfg(not(adc_g0))]
42 let val = 17; 42 let val = 17;
43 #[cfg(stm32g0)] 43 #[cfg(adc_g0)]
44 let val = 12; 44 let val = 12;
45 val 45 val
46 } 46 }
@@ -50,9 +50,9 @@ pub struct Vbat;
50impl<T: Instance> AdcPin<T> for Vbat {} 50impl<T: Instance> AdcPin<T> for Vbat {}
51impl<T: Instance> super::sealed::AdcPin<T> for Vbat { 51impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
52 fn channel(&self) -> u8 { 52 fn channel(&self) -> u8 {
53 #[cfg(not(stm32g0))] 53 #[cfg(not(adc_g0))]
54 let val = 18; 54 let val = 18;
55 #[cfg(stm32g0)] 55 #[cfg(adc_g0)]
56 let val = 14; 56 let val = 14;
57 val 57 val
58 } 58 }
@@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> {
92 } 92 }
93 93
94 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { 94 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
95 #[cfg(not(adc_g0))]
95 T::common_regs().ccr().modify(|reg| { 96 T::common_regs().ccr().modify(|reg| {
96 reg.set_vrefen(true); 97 reg.set_vrefen(true);
97 }); 98 });
99 #[cfg(adc_g0)]
100 T::regs().ccr().modify(|reg| {
101 reg.set_vrefen(true);
102 });
98 103
99 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us 104 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
100 // to stabilize the internal voltage reference, we wait a little more. 105 // to stabilize the internal voltage reference, we wait a little more.
@@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> {
106 } 111 }
107 112
108 pub fn enable_temperature(&self) -> Temperature { 113 pub fn enable_temperature(&self) -> Temperature {
114 #[cfg(not(adc_g0))]
109 T::common_regs().ccr().modify(|reg| { 115 T::common_regs().ccr().modify(|reg| {
110 reg.set_ch17sel(true); 116 reg.set_ch17sel(true);
111 }); 117 });
118 #[cfg(adc_g0)]
119 T::regs().ccr().modify(|reg| {
120 reg.set_tsen(true);
121 });
112 122
113 Temperature {} 123 Temperature {}
114 } 124 }
115 125
116 pub fn enable_vbat(&self) -> Vbat { 126 pub fn enable_vbat(&self) -> Vbat {
127 #[cfg(not(adc_g0))]
117 T::common_regs().ccr().modify(|reg| { 128 T::common_regs().ccr().modify(|reg| {
118 reg.set_ch18sel(true); 129 reg.set_ch18sel(true);
119 }); 130 });
131 #[cfg(adc_g0)]
132 T::regs().ccr().modify(|reg| {
133 reg.set_vbaten(true);
134 });
120 135
121 Vbat {} 136 Vbat {}
122 } 137 }
@@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> {
126 } 141 }
127 142
128 pub fn set_resolution(&mut self, resolution: Resolution) { 143 pub fn set_resolution(&mut self, resolution: Resolution) {
129 #[cfg(not(stm32g0))] 144 #[cfg(not(adc_g0))]
130 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 145 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
131 #[cfg(stm32g0)] 146 #[cfg(adc_g0)]
132 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 147 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
133 } 148 }
134 149
@@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> {
182 Self::set_channel_sample_time(pin.channel(), self.sample_time); 197 Self::set_channel_sample_time(pin.channel(), self.sample_time);
183 198
184 // Select channel 199 // Select channel
185 #[cfg(not(stm32g0))] 200 #[cfg(not(adc_g0))]
186 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); 201 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
187 #[cfg(stm32g0)] 202 #[cfg(adc_g0)]
188 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); 203 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
189 204
190 // Some models are affected by an erratum: 205 // Some models are affected by an erratum:
@@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> {
203 val 218 val
204 } 219 }
205 220
206 #[cfg(stm32g0)] 221 #[cfg(adc_g0)]
207 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 222 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
208 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 223 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
209 } 224 }
210 225
211 #[cfg(not(stm32g0))] 226 #[cfg(not(adc_g0))]
212 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 227 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
213 let sample_time = sample_time.into(); 228 let sample_time = sample_time.into();
214 T::regs() 229 T::regs()
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 64d0f0c75..655c0cb6a 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,6 +1,5 @@
1use core::sync::atomic::{AtomicU8, Ordering};
2
3use embedded_hal_02::blocking::delay::DelayUs; 1use embedded_hal_02::blocking::delay::DelayUs;
2#[allow(unused)]
4use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; 3use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 4use pac::adccommon::vals::Presc;
6 5
@@ -13,12 +12,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
13/// VREF voltage used for factory calibration of VREFINTCAL register. 12/// VREF voltage used for factory calibration of VREFINTCAL register.
14pub const VREF_CALIB_MV: u32 = 3300; 13pub const VREF_CALIB_MV: u32 = 3300;
15 14
16// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 15/// Max single ADC operation clock frequency
16#[cfg(stm32g4)]
17const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
18#[cfg(stm32h7)]
19const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
20
21#[cfg(stm32g4)]
22const VREF_CHANNEL: u8 = 18;
23#[cfg(stm32g4)]
24const TEMP_CHANNEL: u8 = 16;
25
26#[cfg(stm32h7)]
27const VREF_CHANNEL: u8 = 19;
28#[cfg(stm32h7)]
29const TEMP_CHANNEL: u8 = 18;
30
31// TODO this should be 14 for H7a/b/35
32const VBAT_CHANNEL: u8 = 17;
33
34// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
17pub struct VrefInt; 35pub struct VrefInt;
18impl<T: Instance> InternalChannel<T> for VrefInt {} 36impl<T: Instance> InternalChannel<T> for VrefInt {}
19impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { 37impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
20 fn channel(&self) -> u8 { 38 fn channel(&self) -> u8 {
21 19 39 VREF_CHANNEL
22 } 40 }
23} 41}
24 42
@@ -26,7 +44,7 @@ pub struct Temperature;
26impl<T: Instance> InternalChannel<T> for Temperature {} 44impl<T: Instance> InternalChannel<T> for Temperature {}
27impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { 45impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
28 fn channel(&self) -> u8 { 46 fn channel(&self) -> u8 {
29 18 47 TEMP_CHANNEL
30 } 48 }
31} 49}
32 50
@@ -34,128 +52,10 @@ pub struct Vbat;
34impl<T: Instance> InternalChannel<T> for Vbat {} 52impl<T: Instance> InternalChannel<T> for Vbat {}
35impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { 53impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
36 fn channel(&self) -> u8 { 54 fn channel(&self) -> u8 {
37 // TODO this should be 14 for H7a/b/35 55 VBAT_CHANNEL
38 17
39 } 56 }
40} 57}
41 58
42static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
43
44#[cfg(stm32h7)]
45foreach_peripheral!(
46 (adc, ADC1) => {
47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
48 fn frequency() -> crate::time::Hertz {
49 critical_section::with(|_| {
50 match unsafe { crate::rcc::get_freqs() }.adc {
51 Some(ck) => ck,
52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
53 }
54 })
55 }
56
57 fn enable() {
58 critical_section::with(|_| {
59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
60 });
61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
62 }
63
64 fn disable() {
65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
66 critical_section::with(|_| {
67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
68 })
69 }
70 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
71 }
72
73 fn reset() {
74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
75 critical_section::with(|_| {
76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
78 });
79 }
80 }
81 }
82
83 impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {}
84 };
85 (adc, ADC2) => {
86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
87 fn frequency() -> crate::time::Hertz {
88 critical_section::with(|_| {
89 match unsafe { crate::rcc::get_freqs() }.adc {
90 Some(ck) => ck,
91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
92 }
93 })
94 }
95
96 fn enable() {
97 critical_section::with(|_| {
98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
99 });
100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
101 }
102
103 fn disable() {
104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
105 critical_section::with(|_| {
106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
107 })
108 }
109 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
110 }
111
112 fn reset() {
113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
114 critical_section::with(|_| {
115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
117 });
118 }
119 }
120 }
121
122 impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {}
123 };
124 (adc, ADC3) => {
125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
126 fn frequency() -> crate::time::Hertz {
127 critical_section::with(|_| {
128 match unsafe { crate::rcc::get_freqs() }.adc {
129 Some(ck) => ck,
130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
131 }
132 })
133 }
134
135 fn enable() {
136 critical_section::with(|_| {
137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
138 });
139 }
140
141 fn disable() {
142 critical_section::with(|_| {
143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
144 })
145 }
146
147 fn reset() {
148 critical_section::with(|_| {
149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
151 });
152 }
153 }
154
155 impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {}
156 };
157);
158
159// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 59// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
160// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 60// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
161#[allow(unused)] 61#[allow(unused)]
@@ -176,7 +76,7 @@ enum Prescaler {
176 76
177impl Prescaler { 77impl Prescaler {
178 fn from_ker_ck(frequency: Hertz) -> Self { 78 fn from_ker_ck(frequency: Hertz) -> Self {
179 let raw_prescaler = frequency.0 / 50_000_000; 79 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
180 match raw_prescaler { 80 match raw_prescaler {
181 0 => Self::NotDivided, 81 0 => Self::NotDivided,
182 1 => Self::DividedBy2, 82 1 => Self::DividedBy2,
@@ -237,20 +137,23 @@ impl<'d, T: Instance> Adc<'d, T> {
237 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 137 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
238 info!("ADC frequency set to {} Hz", frequency.0); 138 info!("ADC frequency set to {} Hz", frequency.0);
239 139
240 if frequency > Hertz::mhz(50) { 140 if frequency > MAX_ADC_CLK_FREQ {
241 panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information."); 141 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
242 } 142 }
243 let boost = if frequency < Hertz::khz(6_250) {
244 Boost::LT6_25
245 } else if frequency < Hertz::khz(12_500) {
246 Boost::LT12_5
247 } else if frequency < Hertz::mhz(25) {
248 Boost::LT25
249 } else {
250 Boost::LT50
251 };
252 T::regs().cr().modify(|w| w.set_boost(boost));
253 143
144 #[cfg(stm32h7)]
145 {
146 let boost = if frequency < Hertz::khz(6_250) {
147 Boost::LT6_25
148 } else if frequency < Hertz::khz(12_500) {
149 Boost::LT12_5
150 } else if frequency < Hertz::mhz(25) {
151 Boost::LT25
152 } else {
153 Boost::LT50
154 };
155 T::regs().cr().modify(|w| w.set_boost(boost));
156 }
254 let mut s = Self { 157 let mut s = Self {
255 adc, 158 adc,
256 sample_time: Default::default(), 159 sample_time: Default::default(),
@@ -379,10 +282,14 @@ impl<'d, T: Instance> Adc<'d, T> {
379 // Configure channel 282 // Configure channel
380 Self::set_channel_sample_time(channel, self.sample_time); 283 Self::set_channel_sample_time(channel, self.sample_time);
381 284
382 T::regs().cfgr2().modify(|w| w.set_lshift(0)); 285 #[cfg(stm32h7)]
383 T::regs() 286 {
384 .pcsel() 287 T::regs().cfgr2().modify(|w| w.set_lshift(0));
385 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); 288 T::regs()
289 .pcsel()
290 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
291 }
292
386 T::regs().sqr1().write(|reg| { 293 T::regs().sqr1().write(|reg| {
387 reg.set_sq(0, channel); 294 reg.set_sq(0, channel);
388 reg.set_l(0); 295 reg.set_l(0);
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index a1e0240c8..4d19103dd 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
129 129
130 #[cfg(any(eth_v1b, eth_v1c))] 130 #[cfg(any(eth_v1b, eth_v1c))]
131 critical_section::with(|_| { 131 critical_section::with(|_| {
132 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
133 RCC.ahb1enr().modify(|w| { 132 RCC.ahb1enr().modify(|w| {
134 w.set_ethen(true); 133 w.set_ethen(true);
135 w.set_ethtxen(true); 134 w.set_ethtxen(true);
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index ada495fdb..6efd40e3e 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
34 } 34 }
35} 35}
36 36
37const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
38
39pub struct Ethernet<'d, T: Instance, P: PHY> { 37pub struct Ethernet<'d, T: Instance, P: PHY> {
40 _peri: PeripheralRef<'d, T>, 38 _peri: PeripheralRef<'d, T>,
41 pub(crate) tx: TDesRing<'d>, 39 pub(crate) tx: TDesRing<'d>,
@@ -80,7 +78,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
80 // Enable the necessary Clocks 78 // Enable the necessary Clocks
81 #[cfg(not(rcc_h5))] 79 #[cfg(not(rcc_h5))]
82 critical_section::with(|_| { 80 critical_section::with(|_| {
83 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
84 crate::pac::RCC.ahb1enr().modify(|w| { 81 crate::pac::RCC.ahb1enr().modify(|w| {
85 w.set_eth1macen(true); 82 w.set_eth1macen(true);
86 w.set_eth1txen(true); 83 w.set_eth1txen(true);
@@ -102,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
102 }); 99 });
103 100
104 // RMII 101 // RMII
105 crate::pac::SBS 102 crate::pac::SYSCFG
106 .pmcr() 103 .pmcr()
107 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); 104 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
108 }); 105 });
109 106
110 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 107 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@@ -164,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
164 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? 161 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
165 dma.dmacrx_cr().modify(|w| { 162 dma.dmacrx_cr().modify(|w| {
166 w.set_rxpbl(1); // 32 ? 163 w.set_rxpbl(1); // 32 ?
167 w.set_rbsz(MTU as u16); 164 w.set_rbsz(RX_BUFFER_SIZE as u16);
168 }); 165 });
169 166
170 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 167 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 925cf39be..62f321709 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -6,7 +6,7 @@ use core::task::{Context, Poll};
6use embassy_hal_internal::impl_peripheral; 6use embassy_hal_internal::impl_peripheral;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use crate::gpio::{AnyPin, Input, Pin as GpioPin}; 9use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin};
10use crate::pac::exti::regs::Lines; 10use crate::pac::exti::regs::Lines;
11use crate::pac::EXTI; 11use crate::pac::EXTI;
12use crate::{interrupt, pac, peripherals, Peripheral}; 12use crate::{interrupt, pac, peripherals, Peripheral};
@@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio {
39} 39}
40 40
41pub unsafe fn on_irq() { 41pub unsafe fn on_irq() {
42 #[cfg(feature = "low-power")]
43 crate::low_power::on_wakeup_irq();
44
42 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] 45 #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
43 let bits = EXTI.pr(0).read().0; 46 let bits = EXTI.pr(0).read().0;
44 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] 47 #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
@@ -98,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
98 self.pin.is_low() 101 self.pin.is_low()
99 } 102 }
100 103
104 pub fn get_level(&self) -> Level {
105 self.pin.get_level()
106 }
107
101 pub async fn wait_for_high<'a>(&'a mut self) { 108 pub async fn wait_for_high<'a>(&'a mut self) {
102 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 109 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
103 if self.is_high() { 110 if self.is_high() {
@@ -364,9 +371,4 @@ pub(crate) unsafe fn init() {
364 use crate::interrupt::typelevel::Interrupt; 371 use crate::interrupt::typelevel::Interrupt;
365 372
366 foreach_exti_irq!(enable_irq); 373 foreach_exti_irq!(enable_irq);
367
368 #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))]
369 <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
370 #[cfg(stm32f1)]
371 <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
372} 374}
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-stm32/src/fmt.rs
+++ b/embassy-stm32/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index a382cb742..c709d46da 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -758,6 +758,9 @@ foreach_pin!(
758); 758);
759 759
760pub(crate) unsafe fn init() { 760pub(crate) unsafe fn init() {
761 #[cfg(afio)]
762 <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
763
761 crate::_generated::init_gpio(); 764 crate::_generated::init_gpio();
762} 765}
763 766
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 31c488144..c47b0c092 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -8,6 +8,8 @@ pub use traits::Instance;
8#[allow(unused_imports)] 8#[allow(unused_imports)]
9use crate::gpio::sealed::{AFType, Pin}; 9use crate::gpio::sealed::{AFType, Pin};
10use crate::gpio::AnyPin; 10use crate::gpio::AnyPin;
11#[cfg(stm32f334)]
12use crate::rcc::get_freqs;
11use crate::time::Hertz; 13use crate::time::Hertz;
12use crate::Peripheral; 14use crate::Peripheral;
13 15
@@ -158,17 +160,29 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
158 T::enable(); 160 T::enable();
159 <T as crate::rcc::sealed::RccPeripheral>::reset(); 161 <T as crate::rcc::sealed::RccPeripheral>::reset();
160 162
161 // // Enable and and stabilize the DLL 163 #[cfg(stm32f334)]
162 // T::regs().dllcr().modify(|w| { 164 if unsafe { get_freqs() }.hrtim.is_some() {
163 // // w.set_calen(true); 165 // Enable and and stabilize the DLL
164 // // w.set_calrte(11); 166 T::regs().dllcr().modify(|w| {
165 // w.set_cal(true); 167 w.set_cal(true);
166 // }); 168 });
167 // 169
168 // debug!("wait for dll calibration"); 170 trace!("hrtim: wait for dll calibration");
169 // while !T::regs().isr().read().dllrdy() {} 171 while !T::regs().isr().read().dllrdy() {}
170 // 172
171 // debug!("dll calibration complete"); 173 trace!("hrtim: dll calibration complete");
174
175 // Enable periodic calibration
176 // Cal must be disabled before we can enable it
177 T::regs().dllcr().modify(|w| {
178 w.set_cal(false);
179 });
180
181 T::regs().dllcr().modify(|w| {
182 w.set_calen(true);
183 w.set_calrte(11);
184 });
185 }
172 186
173 Self { 187 Self {
174 _inner: tim, 188 _inner: tim,
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index 158a68862..34a363a1f 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -1,31 +1,17 @@
1use crate::rcc::sealed::RccPeripheral; 1use crate::rcc::sealed::RccPeripheral;
2use crate::time::Hertz; 2use crate::time::Hertz;
3 3
4#[repr(u8)]
4#[derive(Clone, Copy)] 5#[derive(Clone, Copy)]
5pub(crate) enum Prescaler { 6pub(crate) enum Prescaler {
6 Div1, 7 Div1 = 1,
7 Div2, 8 Div2 = 2,
8 Div4, 9 Div4 = 4,
9 Div8, 10 Div8 = 8,
10 Div16, 11 Div16 = 16,
11 Div32, 12 Div32 = 32,
12 Div64, 13 Div64 = 64,
13 Div128, 14 Div128 = 128,
14}
15
16impl From<Prescaler> for u32 {
17 fn from(val: Prescaler) -> Self {
18 match val {
19 Prescaler::Div1 => 1,
20 Prescaler::Div2 => 2,
21 Prescaler::Div4 => 4,
22 Prescaler::Div8 => 8,
23 Prescaler::Div16 => 16,
24 Prescaler::Div32 => 32,
25 Prescaler::Div64 => 64,
26 Prescaler::Div128 => 128,
27 }
28 }
29} 15}
30 16
31impl From<Prescaler> for u8 { 17impl From<Prescaler> for u8 {
@@ -72,7 +58,7 @@ impl Prescaler {
72 Prescaler::Div128, 58 Prescaler::Div128,
73 ] 59 ]
74 .iter() 60 .iter()
75 .skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val) 61 .skip_while(|psc| **psc as u32 <= val)
76 .next() 62 .next()
77 .unwrap() 63 .unwrap()
78 } 64 }
@@ -80,7 +66,7 @@ impl Prescaler {
80 pub fn compute_min_low_res(val: u32) -> Self { 66 pub fn compute_min_low_res(val: u32) -> Self {
81 *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] 67 *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128]
82 .iter() 68 .iter()
83 .skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val) 69 .skip_while(|psc| **psc as u32 <= val)
84 .next() 70 .next()
85 .unwrap() 71 .unwrap()
86 } 72 }
@@ -92,97 +78,90 @@ pub(crate) mod sealed {
92 pub trait Instance: RccPeripheral { 78 pub trait Instance: RccPeripheral {
93 fn regs() -> crate::pac::hrtim::Hrtim; 79 fn regs() -> crate::pac::hrtim::Hrtim;
94 80
95 fn set_master_frequency(frequency: Hertz); 81 fn set_master_frequency(frequency: Hertz) {
96 82 let f = frequency.0;
97 fn set_channel_frequency(channnel: usize, frequency: Hertz); 83 #[cfg(not(stm32f334))]
98 84 let timer_f = Self::frequency().0;
99 /// Set the dead time as a proportion of max_duty 85 #[cfg(stm32f334)]
100 fn set_channel_dead_time(channnel: usize, dead_time: u16); 86 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
101
102 // fn enable_outputs(enable: bool);
103 //
104 // fn enable_channel(&mut self, channel: usize, enable: bool);
105 }
106}
107 87
108pub trait Instance: sealed::Instance + 'static {} 88 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
109 89 let psc = if Self::regs().isr().read().dllrdy() {
110foreach_interrupt! { 90 Prescaler::compute_min_high_res(psc_min)
111 ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { 91 } else {
112 impl sealed::Instance for crate::peripherals::$inst { 92 Prescaler::compute_min_low_res(psc_min)
113 fn regs() -> crate::pac::hrtim::Hrtim { 93 };
114 crate::pac::$inst
115 }
116 94
117 fn set_master_frequency(frequency: Hertz) { 95 let timer_f = 32 * (timer_f / psc as u32);
118 use crate::rcc::sealed::RccPeripheral; 96 let per: u16 = (timer_f / f) as u16;
119 97
120 let f = frequency.0; 98 let regs = Self::regs();
121 let timer_f = Self::frequency().0;
122 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
123 let psc = if Self::regs().isr().read().dllrdy() {
124 Prescaler::compute_min_high_res(psc_min)
125 } else {
126 Prescaler::compute_min_low_res(psc_min)
127 };
128 99
129 let psc_val: u32 = psc.into(); 100 regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
130 let timer_f = 32 * (timer_f / psc_val); 101 regs.mper().modify(|w| w.set_mper(per));
131 let per: u16 = (timer_f / f) as u16; 102 }
132 103
133 let regs = Self::regs(); 104 fn set_channel_frequency(channel: usize, frequency: Hertz) {
105 let f = frequency.0;
106 #[cfg(not(stm32f334))]
107 let timer_f = Self::frequency().0;
108 #[cfg(stm32f334)]
109 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
134 110
135 regs.mcr().modify(|w| w.set_ckpsc(psc.into())); 111 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
136 regs.mper().modify(|w| w.set_mper(per)); 112 let psc = if Self::regs().isr().read().dllrdy() {
137 } 113 Prescaler::compute_min_high_res(psc_min)
114 } else {
115 Prescaler::compute_min_low_res(psc_min)
116 };
138 117
139 fn set_channel_frequency(channel: usize, frequency: Hertz) { 118 let timer_f = 32 * (timer_f / psc as u32);
140 use crate::rcc::sealed::RccPeripheral; 119 let per: u16 = (timer_f / f) as u16;
141 120
142 let f = frequency.0; 121 let regs = Self::regs();
143 let timer_f = Self::frequency().0;
144 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
145 let psc = if Self::regs().isr().read().dllrdy() {
146 Prescaler::compute_min_high_res(psc_min)
147 } else {
148 Prescaler::compute_min_low_res(psc_min)
149 };
150 122
151 let psc_val: u32 = psc.into(); 123 regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
152 let timer_f = 32 * (timer_f / psc_val); 124 regs.tim(channel).per().modify(|w| w.set_per(per));
153 let per: u16 = (timer_f / f) as u16; 125 }
154 126
155 let regs = Self::regs(); 127 /// Set the dead time as a proportion of max_duty
156 128
157 regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); 129 fn set_channel_dead_time(channel: usize, dead_time: u16) {
158 regs.tim(channel).per().modify(|w| w.set_per(per)); 130 let regs = Self::regs();
159 }
160 131
161 fn set_channel_dead_time(channel: usize, dead_time: u16) { 132 let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
162 133
163 let regs = Self::regs(); 134 // The dead-time base clock runs 4 times slower than the hrtim base clock
135 // u9::MAX = 511
136 let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511);
137 let psc = if Self::regs().isr().read().dllrdy() {
138 Prescaler::compute_min_high_res(psc_min)
139 } else {
140 Prescaler::compute_min_low_res(psc_min)
141 };
164 142
165 let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); 143 let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32);
166 let psc_val: u32 = channel_psc.into();
167 144
145 regs.tim(channel).dt().modify(|w| {
146 w.set_dtprsc(psc.into());
147 w.set_dtf(dt_val as u16);
148 w.set_dtr(dt_val as u16);
149 });
150 }
168 151
169 // The dead-time base clock runs 4 times slower than the hrtim base clock 152 // fn enable_outputs(enable: bool);
170 // u9::MAX = 511 153 //
171 let psc_min = (psc_val * dead_time as u32) / (4 * 511); 154 // fn enable_channel(&mut self, channel: usize, enable: bool);
172 let psc = if Self::regs().isr().read().dllrdy() { 155 }
173 Prescaler::compute_min_high_res(psc_min) 156}
174 } else {
175 Prescaler::compute_min_low_res(psc_min)
176 };
177 157
178 let dt_psc_val: u32 = psc.into(); 158pub trait Instance: sealed::Instance + 'static {}
179 let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val);
180 159
181 regs.tim(channel).dt().modify(|w| { 160foreach_interrupt! {
182 w.set_dtprsc(psc.into()); 161 ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => {
183 w.set_dtf(dt_val as u16); 162 impl sealed::Instance for crate::peripherals::$inst {
184 w.set_dtr(dt_val as u16); 163 fn regs() -> crate::pac::hrtim::Hrtim {
185 }); 164 crate::pac::$inst
186 } 165 }
187 } 166 }
188 167
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 618d85af2..f32dd0f0c 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
339 } 339 }
340} 340}
341 341
342impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
343 fn drop(&mut self) {
344 T::disable();
345 }
346}
347
342impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 348impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
343 type Error = Error; 349 type Error = Error;
344 350
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 4327899bb..36f70e32e 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
838 } 838 }
839} 839}
840 840
841impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
842 fn drop(&mut self) {
843 T::disable();
844 }
845}
846
841mod eh02 { 847mod eh02 {
842 use super::*; 848 use super::*;
843 849
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index b5a128596..2718c96da 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -90,6 +90,7 @@ pub use crate::_generated::interrupt;
90#[macro_export] 90#[macro_export]
91macro_rules! bind_interrupts { 91macro_rules! bind_interrupts {
92 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 92 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
93 #[derive(Copy, Clone)]
93 $vis struct $name; 94 $vis struct $name;
94 95
95 $( 96 $(
@@ -119,6 +120,7 @@ pub(crate) use stm32_metapac as pac;
119use crate::interrupt::Priority; 120use crate::interrupt::Priority;
120#[cfg(feature = "rt")] 121#[cfg(feature = "rt")]
121pub use crate::pac::NVIC_PRIO_BITS; 122pub use crate::pac::NVIC_PRIO_BITS;
123use crate::rcc::sealed::RccPeripheral;
122 124
123#[non_exhaustive] 125#[non_exhaustive]
124pub struct Config { 126pub struct Config {
@@ -156,7 +158,7 @@ pub fn init(config: Config) -> Peripherals {
156 #[cfg(dbgmcu)] 158 #[cfg(dbgmcu)]
157 if config.enable_debug_during_sleep { 159 if config.enable_debug_during_sleep {
158 crate::pac::DBGMCU.cr().modify(|cr| { 160 crate::pac::DBGMCU.cr().modify(|cr| {
159 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] 161 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
160 { 162 {
161 cr.set_dbg_stop(true); 163 cr.set_dbg_stop(true);
162 cr.set_dbg_standby(true); 164 cr.set_dbg_standby(true);
@@ -181,6 +183,13 @@ pub fn init(config: Config) -> Peripherals {
181 }); 183 });
182 } 184 }
183 185
186 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
187 peripherals::SYSCFG::enable();
188 #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
189 peripherals::PWR::enable();
190 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
191 peripherals::FLASH::enable();
192
184 unsafe { 193 unsafe {
185 gpio::init(); 194 gpio::init();
186 dma::init( 195 dma::init(
@@ -199,6 +208,11 @@ pub fn init(config: Config) -> Peripherals {
199 // must be after rcc init 208 // must be after rcc init
200 #[cfg(feature = "_time-driver")] 209 #[cfg(feature = "_time-driver")]
201 time_driver::init(); 210 time_driver::init();
211
212 #[cfg(feature = "low-power")]
213 while !crate::rcc::low_power_ready() {
214 crate::rcc::clock_refcount_sub();
215 }
202 } 216 }
203 217
204 p 218 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 7814fa384..ce8afb578 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -3,45 +3,33 @@ use core::marker::PhantomData;
3 3
4use cortex_m::peripheral::SCB; 4use cortex_m::peripheral::SCB;
5use embassy_executor::*; 5use embassy_executor::*;
6use embassy_time::Duration;
7 6
8use crate::interrupt; 7use crate::interrupt;
9use crate::interrupt::typelevel::Interrupt;
10use crate::pac::EXTI;
11use crate::rcc::low_power_ready; 8use crate::rcc::low_power_ready;
9use crate::time_driver::{get_driver, RtcDriver};
12 10
13const THREAD_PENDER: usize = usize::MAX; 11const THREAD_PENDER: usize = usize::MAX;
14const THRESHOLD: Duration = Duration::from_millis(500);
15 12
16use crate::rtc::{Rtc, RtcInstant}; 13use crate::rtc::Rtc;
17 14
18static mut RTC: Option<&'static Rtc> = None; 15static mut EXECUTOR: Option<Executor> = None;
19 16
20foreach_interrupt! { 17foreach_interrupt! {
21 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 18 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
22 #[interrupt] 19 #[interrupt]
23 unsafe fn $irq() { 20 unsafe fn $irq() {
24 Executor::on_wakeup_irq(); 21 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
25 } 22 }
26 }; 23 };
27} 24}
28 25
29pub fn stop_with_rtc(rtc: &'static Rtc) { 26#[allow(dead_code)]
30 crate::interrupt::typelevel::RTC_WKUP::unpend(); 27pub(crate) unsafe fn on_wakeup_irq() {
31 unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; 28 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
32
33 EXTI.rtsr(0).modify(|w| w.set_line(22, true));
34 EXTI.imr(0).modify(|w| w.set_line(22, true));
35
36 unsafe { RTC = Some(rtc) };
37} 29}
38 30
39pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { 31pub fn stop_with_rtc(rtc: &'static Rtc) {
40 unsafe { RTC }.unwrap().start_wakeup_alarm(requested_duration) 32 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
41}
42
43pub fn stop_wakeup_alarm() -> RtcInstant {
44 unsafe { RTC }.unwrap().stop_wakeup_alarm()
45} 33}
46 34
47/// Thread mode executor, using WFE/SEV. 35/// Thread mode executor, using WFE/SEV.
@@ -57,54 +45,58 @@ pub fn stop_wakeup_alarm() -> RtcInstant {
57pub struct Executor { 45pub struct Executor {
58 inner: raw::Executor, 46 inner: raw::Executor,
59 not_send: PhantomData<*mut ()>, 47 not_send: PhantomData<*mut ()>,
48 scb: SCB,
49 time_driver: &'static RtcDriver,
60} 50}
61 51
62impl Executor { 52impl Executor {
63 /// Create a new Executor. 53 /// Create a new Executor.
64 pub fn new() -> Self { 54 pub fn take() -> &'static mut Self {
65 Self { 55 unsafe {
66 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 56 assert!(EXECUTOR.is_none());
67 not_send: PhantomData, 57
58 EXECUTOR = Some(Self {
59 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
60 not_send: PhantomData,
61 scb: cortex_m::Peripherals::steal().SCB,
62 time_driver: get_driver(),
63 });
64
65 EXECUTOR.as_mut().unwrap()
68 } 66 }
69 } 67 }
70 68
71 unsafe fn on_wakeup_irq() { 69 unsafe fn on_wakeup_irq(&mut self) {
72 info!("on wakeup irq"); 70 trace!("low power: on wakeup irq");
73 71
74 cortex_m::asm::bkpt(); 72 self.time_driver.resume_time();
73 trace!("low power: resume time");
75 } 74 }
76 75
77 fn time_until_next_alarm(&self) -> Duration { 76 pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) {
78 Duration::from_secs(3) 77 self.time_driver.set_rtc(rtc);
79 } 78
79 rtc.enable_wakeup_line();
80 80
81 fn get_scb() -> SCB { 81 trace!("low power: stop with rtc configured");
82 unsafe { cortex_m::Peripherals::steal() }.SCB
83 } 82 }
84 83
85 fn configure_pwr(&self) { 84 fn configure_pwr(&mut self) {
86 trace!("configure_pwr"); 85 trace!("low power: configure_pwr");
87 86
87 self.scb.clear_sleepdeep();
88 if !low_power_ready() { 88 if !low_power_ready() {
89 trace!("low power: configure_pwr: low power not ready");
89 return; 90 return;
90 } 91 }
91 92
92 let time_until_next_alarm = self.time_until_next_alarm(); 93 if self.time_driver.pause_time().is_err() {
93 if time_until_next_alarm < THRESHOLD { 94 trace!("low power: configure_pwr: time driver failed to pause");
94 return; 95 return;
95 } 96 }
96 97
97 trace!("low power stop required"); 98 trace!("low power: enter stop...");
98 99 self.scb.set_sleepdeep();
99 critical_section::with(|_| {
100 trace!("executor: set wakeup alarm...");
101
102 start_wakeup_alarm(time_until_next_alarm);
103
104 trace!("low power wait for rtc ready...");
105
106 Self::get_scb().set_sleepdeep();
107 });
108 } 100 }
109 101
110 /// Run the executor. 102 /// Run the executor.
@@ -126,11 +118,11 @@ impl Executor {
126 /// 118 ///
127 /// This function never returns. 119 /// This function never returns.
128 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 120 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
129 init(self.inner.spawner()); 121 init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner());
130 122
131 loop { 123 loop {
132 unsafe { 124 unsafe {
133 self.inner.poll(); 125 EXECUTOR.as_mut().unwrap().inner.poll();
134 self.configure_pwr(); 126 self.configure_pwr();
135 asm!("wfe"); 127 asm!("wfe");
136 }; 128 };
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
new file mode 100644
index 000000000..de27130f2
--- /dev/null
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -0,0 +1,176 @@
1#[allow(dead_code)]
2#[derive(Default, Clone, Copy)]
3pub enum LseDrive {
4 #[cfg(any(rtc_v2f7, rtc_v2l4))]
5 Low = 0,
6 MediumLow = 0x01,
7 #[default]
8 MediumHigh = 0x02,
9 #[cfg(any(rtc_v2f7, rtc_v2l4))]
10 High = 0x03,
11}
12
13#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
14impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
15 fn from(value: LseDrive) -> Self {
16 use crate::pac::rcc::vals::Lsedrv;
17
18 match value {
19 #[cfg(any(rtc_v2f7, rtc_v2l4))]
20 LseDrive::Low => Lsedrv::LOW,
21 LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
22 LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
23 #[cfg(any(rtc_v2f7, rtc_v2l4))]
24 LseDrive::High => Lsedrv::HIGH,
25 }
26 }
27}
28
29pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
30
31#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
32#[allow(dead_code)]
33type Bdcr = crate::pac::rcc::regs::Bdcr;
34
35#[cfg(any(rtc_v2l0, rtc_v2l1))]
36#[allow(dead_code)]
37type Bdcr = crate::pac::rcc::regs::Csr;
38
39#[allow(dead_code)]
40pub struct BackupDomain {}
41
42impl BackupDomain {
43 #[cfg(any(
44 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
45 rtc_v3u5
46 ))]
47 #[allow(dead_code, unused_variables)]
48 fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
49 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))]
50 let cr = crate::pac::PWR.cr();
51 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
52 let cr = crate::pac::PWR.cr1();
53
54 // TODO: Missing from PAC for l0 and f0?
55 #[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
56 {
57 cr.modify(|w| w.set_dbp(true));
58 while !cr.read().dbp() {}
59 }
60
61 #[cfg(any(rtc_v2l0, rtc_v2l1))]
62 let cr = crate::pac::RCC.csr();
63
64 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
65 let cr = crate::pac::RCC.bdcr();
66
67 cr.modify(|w| f(w))
68 }
69
70 #[cfg(any(
71 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
72 rtc_v3u5
73 ))]
74 #[allow(dead_code)]
75 fn read() -> Bdcr {
76 #[cfg(any(rtc_v2l0, rtc_v2l1))]
77 let r = crate::pac::RCC.csr().read();
78
79 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
80 let r = crate::pac::RCC.bdcr().read();
81
82 r
83 }
84
85 #[cfg(any(
86 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
87 rtc_v3u5
88 ))]
89 #[allow(dead_code, unused_variables)]
90 pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) {
91 if lsi {
92 #[cfg(rtc_v3u5)]
93 let csr = crate::pac::RCC.bdcr();
94
95 #[cfg(not(rtc_v3u5))]
96 let csr = crate::pac::RCC.csr();
97
98 // Disable backup domain write protection
99 Self::modify(|_| {});
100
101 #[cfg(not(any(rcc_wb, rcc_wba)))]
102 csr.modify(|w| w.set_lsion(true));
103
104 #[cfg(any(rcc_wb, rcc_wba))]
105 csr.modify(|w| w.set_lsi1on(true));
106
107 #[cfg(not(any(rcc_wb, rcc_wba)))]
108 while !csr.read().lsirdy() {}
109
110 #[cfg(any(rcc_wb, rcc_wba))]
111 while !csr.read().lsi1rdy() {}
112 }
113
114 if let Some(lse_drive) = lse {
115 Self::modify(|w| {
116 #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
117 w.set_lsedrv(lse_drive.into());
118 w.set_lseon(true);
119 });
120
121 while !Self::read().lserdy() {}
122 }
123
124 match clock_source {
125 RtcClockSource::LSI => assert!(lsi),
126 RtcClockSource::LSE => assert!(&lse.is_some()),
127 _ => {}
128 };
129
130 if clock_source == RtcClockSource::NOCLOCK {
131 // disable it
132 Self::modify(|w| {
133 #[cfg(not(rcc_wba))]
134 w.set_rtcen(false);
135 w.set_rtcsel(clock_source);
136 });
137 } else {
138 // check if it's already enabled and in the source we want.
139 let reg = Self::read();
140 let ok = reg.rtcsel() == clock_source;
141 #[cfg(not(rcc_wba))]
142 let ok = ok & reg.rtcen();
143
144 // if not, configure it.
145 if !ok {
146 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
147 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
148
149 #[cfg(not(any(rcc_l0, rcc_l1)))]
150 Self::modify(|w| w.set_bdrst(true));
151
152 Self::modify(|w| {
153 // Reset
154 #[cfg(not(any(rcc_l0, rcc_l1)))]
155 w.set_bdrst(false);
156
157 #[cfg(not(rcc_wba))]
158 w.set_rtcen(true);
159 w.set_rtcsel(clock_source);
160
161 // Restore bcdr
162 #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
163 w.set_lscosel(reg.lscosel());
164 #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
165 w.set_lscoen(reg.lscoen());
166
167 w.set_lseon(reg.lseon());
168
169 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
170 w.set_lsedrv(reg.lsedrv());
171 w.set_lsebyp(reg.lsebyp());
172 });
173 }
174 }
175 }
176}
diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs
new file mode 100644
index 000000000..495cf7fe1
--- /dev/null
+++ b/embassy-stm32/src/rcc/bus.rs
@@ -0,0 +1,56 @@
1use core::ops::Div;
2
3#[allow(unused_imports)]
4use crate::pac::rcc;
5pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
6use crate::time::Hertz;
7
8impl Div<AHBPrescaler> for Hertz {
9 type Output = Hertz;
10
11 fn div(self, rhs: AHBPrescaler) -> Self::Output {
12 let divisor = match rhs {
13 AHBPrescaler::DIV1 => 1,
14 AHBPrescaler::DIV2 => 2,
15 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
16 AHBPrescaler::DIV3 => 3,
17 AHBPrescaler::DIV4 => 4,
18 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
19 AHBPrescaler::DIV5 => 5,
20 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
21 AHBPrescaler::DIV6 => 6,
22 AHBPrescaler::DIV8 => 8,
23 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
24 AHBPrescaler::DIV10 => 10,
25 AHBPrescaler::DIV16 => 16,
26 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
27 AHBPrescaler::DIV32 => 32,
28 #[cfg(not(rcc_wba))]
29 AHBPrescaler::DIV64 => 64,
30 #[cfg(not(rcc_wba))]
31 AHBPrescaler::DIV128 => 128,
32 #[cfg(not(rcc_wba))]
33 AHBPrescaler::DIV256 => 256,
34 #[cfg(not(rcc_wba))]
35 AHBPrescaler::DIV512 => 512,
36 _ => unreachable!(),
37 };
38 Hertz(self.0 / divisor)
39 }
40}
41
42impl Div<APBPrescaler> for Hertz {
43 type Output = Hertz;
44
45 fn div(self, rhs: APBPrescaler) -> Self::Output {
46 let divisor = match rhs {
47 APBPrescaler::DIV1 => 1,
48 APBPrescaler::DIV2 => 2,
49 APBPrescaler::DIV4 => 4,
50 APBPrescaler::DIV8 => 8,
51 APBPrescaler::DIV16 => 16,
52 _ => unreachable!(),
53 };
54 Hertz(self.0 / divisor)
55 }
56}
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 6a9326347..8f45e7c0f 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -1,4 +1,4 @@
1pub use super::common::{AHBPrescaler, APBPrescaler}; 1pub use super::bus::{AHBPrescaler, APBPrescaler};
2use crate::pac::flash::vals::Latency; 2use crate::pac::flash::vals::Latency;
3use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; 3use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw};
4use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
@@ -58,8 +58,8 @@ impl Default for Config {
58 fn default() -> Config { 58 fn default() -> Config {
59 Config { 59 Config {
60 mux: ClockSrc::HSI(HSIPrescaler::NotDivided), 60 mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
61 ahb_pre: AHBPrescaler::NotDivided, 61 ahb_pre: AHBPrescaler::DIV1,
62 apb_pre: APBPrescaler::NotDivided, 62 apb_pre: APBPrescaler::DIV1,
63 } 63 }
64 } 64 }
65} 65}
@@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) {
151 } 151 }
152 152
153 let ahb_div = match config.ahb_pre { 153 let ahb_div = match config.ahb_pre {
154 AHBPrescaler::NotDivided => 1, 154 AHBPrescaler::DIV1 => 1,
155 AHBPrescaler::Div2 => 2, 155 AHBPrescaler::DIV2 => 2,
156 AHBPrescaler::Div4 => 4, 156 AHBPrescaler::DIV4 => 4,
157 AHBPrescaler::Div8 => 8, 157 AHBPrescaler::DIV8 => 8,
158 AHBPrescaler::Div16 => 16, 158 AHBPrescaler::DIV16 => 16,
159 AHBPrescaler::Div64 => 64, 159 AHBPrescaler::DIV64 => 64,
160 AHBPrescaler::Div128 => 128, 160 AHBPrescaler::DIV128 => 128,
161 AHBPrescaler::Div256 => 256, 161 AHBPrescaler::DIV256 => 256,
162 AHBPrescaler::Div512 => 512, 162 AHBPrescaler::DIV512 => 512,
163 _ => unreachable!(),
163 }; 164 };
164 let ahb_freq = sys_clk / ahb_div; 165 let ahb_freq = sys_clk / ahb_div;
165 166
166 let (apb_freq, apb_tim_freq) = match config.apb_pre { 167 let (apb_freq, apb_tim_freq) = match config.apb_pre {
167 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 168 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
168 pre => { 169 pre => {
169 let pre: Ppre = pre.into(); 170 let pre: Ppre = pre.into();
170 let pre: u8 = 1 << (pre.to_bits() - 3); 171 let pre: u8 = 1 << (pre.to_bits() - 3);
diff --git a/embassy-stm32/src/rcc/common.rs b/embassy-stm32/src/rcc/common.rs
deleted file mode 100644
index 62736a43a..000000000
--- a/embassy-stm32/src/rcc/common.rs
+++ /dev/null
@@ -1,174 +0,0 @@
1use core::ops::Div;
2
3#[allow(unused_imports)]
4use crate::pac::rcc;
5use crate::time::Hertz;
6
7/// Voltage Scale
8///
9/// Represents the voltage range feeding the CPU core. The maximum core
10/// clock frequency depends on this value.
11///
12/// Scale0 represents the highest voltage range
13#[derive(Copy, Clone, PartialEq)]
14pub enum VoltageScale {
15 Scale0,
16 Scale1,
17 #[cfg(not(any(rcc_wl5, rcc_wle)))]
18 Scale2,
19 #[cfg(not(any(rcc_wl5, rcc_wle)))]
20 Scale3,
21}
22
23/// AHB prescaler
24#[derive(Clone, Copy, PartialEq)]
25pub enum AHBPrescaler {
26 NotDivided,
27 Div2,
28 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
29 Div3,
30 Div4,
31 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
32 Div5,
33 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
34 Div6,
35 Div8,
36 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
37 Div10,
38 Div16,
39 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
40 Div32,
41 Div64,
42 Div128,
43 Div256,
44 Div512,
45}
46
47impl Div<AHBPrescaler> for Hertz {
48 type Output = Hertz;
49
50 fn div(self, rhs: AHBPrescaler) -> Self::Output {
51 let divisor = match rhs {
52 AHBPrescaler::NotDivided => 1,
53 AHBPrescaler::Div2 => 2,
54 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
55 AHBPrescaler::Div3 => 3,
56 AHBPrescaler::Div4 => 4,
57 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
58 AHBPrescaler::Div5 => 5,
59 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
60 AHBPrescaler::Div6 => 6,
61 AHBPrescaler::Div8 => 8,
62 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
63 AHBPrescaler::Div10 => 10,
64 AHBPrescaler::Div16 => 16,
65 #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
66 AHBPrescaler::Div32 => 32,
67 AHBPrescaler::Div64 => 64,
68 AHBPrescaler::Div128 => 128,
69 AHBPrescaler::Div256 => 256,
70 AHBPrescaler::Div512 => 512,
71 };
72 Hertz(self.0 / divisor)
73 }
74}
75
76#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))]
77impl From<AHBPrescaler> for rcc::vals::Hpre {
78 fn from(val: AHBPrescaler) -> rcc::vals::Hpre {
79 use rcc::vals::Hpre;
80
81 match val {
82 #[cfg(not(rcc_u5))]
83 AHBPrescaler::NotDivided => Hpre::DIV1,
84 #[cfg(rcc_u5)]
85 AHBPrescaler::NotDivided => Hpre::NONE,
86 AHBPrescaler::Div2 => Hpre::DIV2,
87 AHBPrescaler::Div4 => Hpre::DIV4,
88 AHBPrescaler::Div8 => Hpre::DIV8,
89 AHBPrescaler::Div16 => Hpre::DIV16,
90 AHBPrescaler::Div64 => Hpre::DIV64,
91 AHBPrescaler::Div128 => Hpre::DIV128,
92 AHBPrescaler::Div256 => Hpre::DIV256,
93 AHBPrescaler::Div512 => Hpre::DIV512,
94 }
95 }
96}
97
98#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
99impl From<AHBPrescaler> for u8 {
100 fn from(val: AHBPrescaler) -> u8 {
101 match val {
102 AHBPrescaler::NotDivided => 0x0,
103 AHBPrescaler::Div2 => 0x08,
104 AHBPrescaler::Div3 => 0x01,
105 AHBPrescaler::Div4 => 0x09,
106 AHBPrescaler::Div5 => 0x02,
107 AHBPrescaler::Div6 => 0x05,
108 AHBPrescaler::Div8 => 0x0a,
109 AHBPrescaler::Div10 => 0x06,
110 AHBPrescaler::Div16 => 0x0b,
111 AHBPrescaler::Div32 => 0x07,
112 AHBPrescaler::Div64 => 0x0c,
113 AHBPrescaler::Div128 => 0x0d,
114 AHBPrescaler::Div256 => 0x0e,
115 AHBPrescaler::Div512 => 0x0f,
116 }
117 }
118}
119
120/// APB prescaler
121#[derive(Clone, Copy)]
122pub enum APBPrescaler {
123 NotDivided,
124 Div2,
125 Div4,
126 Div8,
127 Div16,
128}
129
130impl Div<APBPrescaler> for Hertz {
131 type Output = Hertz;
132
133 fn div(self, rhs: APBPrescaler) -> Self::Output {
134 let divisor = match rhs {
135 APBPrescaler::NotDivided => 1,
136 APBPrescaler::Div2 => 2,
137 APBPrescaler::Div4 => 4,
138 APBPrescaler::Div8 => 8,
139 APBPrescaler::Div16 => 16,
140 };
141 Hertz(self.0 / divisor)
142 }
143}
144
145#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))]
146impl From<APBPrescaler> for rcc::vals::Ppre {
147 fn from(val: APBPrescaler) -> rcc::vals::Ppre {
148 use rcc::vals::Ppre;
149
150 match val {
151 #[cfg(not(rcc_u5))]
152 APBPrescaler::NotDivided => Ppre::DIV1,
153 #[cfg(rcc_u5)]
154 APBPrescaler::NotDivided => Ppre::NONE,
155 APBPrescaler::Div2 => Ppre::DIV2,
156 APBPrescaler::Div4 => Ppre::DIV4,
157 APBPrescaler::Div8 => Ppre::DIV8,
158 APBPrescaler::Div16 => Ppre::DIV16,
159 }
160 }
161}
162
163#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
164impl From<APBPrescaler> for u8 {
165 fn from(val: APBPrescaler) -> u8 {
166 match val {
167 APBPrescaler::NotDivided => 1,
168 APBPrescaler::Div2 => 0x04,
169 APBPrescaler::Div4 => 0x05,
170 APBPrescaler::Div8 => 0x06,
171 APBPrescaler::Div16 => 0x07,
172 }
173 }
174}
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index b6200231e..081c0c767 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) {
163 // Only needed for stm32f103? 163 // Only needed for stm32f103?
164 RCC.cfgr().modify(|w| { 164 RCC.cfgr().modify(|w| {
165 w.set_adcpre(Adcpre::from_bits(apre_bits)); 165 w.set_adcpre(Adcpre::from_bits(apre_bits));
166 w.set_ppre2(Ppre1::from_bits(ppre2_bits)); 166 w.set_ppre2(Ppre::from_bits(ppre2_bits));
167 w.set_ppre1(Ppre1::from_bits(ppre1_bits)); 167 w.set_ppre1(Ppre::from_bits(ppre1_bits));
168 w.set_hpre(Hpre::from_bits(hpre_bits)); 168 w.set_hpre(Hpre::from_bits(hpre_bits));
169 #[cfg(not(rcc_f100))] 169 #[cfg(not(rcc_f100))]
170 w.set_usbpre(Usbpre::from_bits(usbpre as u8)); 170 w.set_usbpre(Usbpre::from_bits(usbpre as u8));
@@ -184,6 +184,6 @@ pub(crate) unsafe fn init(config: Config) {
184 apb1_tim: Hertz(pclk1 * timer_mul1), 184 apb1_tim: Hertz(pclk1 * timer_mul1),
185 apb2_tim: Hertz(pclk2 * timer_mul2), 185 apb2_tim: Hertz(pclk2 * timer_mul2),
186 ahb1: Hertz(hclk), 186 ahb1: Hertz(hclk),
187 adc: Hertz(adcclk), 187 adc: Some(Hertz(adcclk)),
188 }); 188 });
189} 189}
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
index ec4ed99b8..44de5bf19 100644
--- a/embassy-stm32/src/rcc/f2.rs
+++ b/embassy-stm32/src/rcc/f2.rs
@@ -1,11 +1,13 @@
1use core::convert::TryFrom; 1use core::convert::TryFrom;
2use core::ops::{Div, Mul}; 2use core::ops::{Div, Mul};
3 3
4pub use super::common::{AHBPrescaler, APBPrescaler}; 4pub use super::bus::{AHBPrescaler, APBPrescaler};
5use crate::pac::flash::vals::Latency; 5use crate::pac::flash::vals::Latency;
6use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; 6use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw};
7use crate::pac::{FLASH, RCC}; 7use crate::pac::{FLASH, RCC};
8use crate::rcc::bd::BackupDomain;
8use crate::rcc::{set_freqs, Clocks}; 9use crate::rcc::{set_freqs, Clocks};
10use crate::rtc::RtcClockSource;
9use crate::time::Hertz; 11use crate::time::Hertz;
10 12
11/// HSI speed 13/// HSI speed
@@ -201,7 +203,20 @@ pub struct PLLClocks {
201 pub pll48_freq: Hertz, 203 pub pll48_freq: Hertz,
202} 204}
203 205
204pub use super::common::VoltageScale; 206/// Voltage range of the power supply used.
207///
208/// Used to calculate flash waitstates. See
209/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
210pub enum VoltageScale {
211 /// 2.7 to 3.6 V
212 Range0,
213 /// 2.4 to 2.7 V
214 Range1,
215 /// 2.1 to 2.4 V
216 Range2,
217 /// 1.8 to 2.1 V
218 Range3,
219}
205 220
206impl VoltageScale { 221impl VoltageScale {
207 const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> { 222 const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
@@ -209,7 +224,7 @@ impl VoltageScale {
209 // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock 224 // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
210 // frequency 225 // frequency
211 match self { 226 match self {
212 VoltageScale::Scale3 => { 227 VoltageScale::Range3 => {
213 if ahb_freq <= 16_000_000 { 228 if ahb_freq <= 16_000_000 {
214 Some(Latency::WS0) 229 Some(Latency::WS0)
215 } else if ahb_freq <= 32_000_000 { 230 } else if ahb_freq <= 32_000_000 {
@@ -230,7 +245,7 @@ impl VoltageScale {
230 None 245 None
231 } 246 }
232 } 247 }
233 VoltageScale::Scale2 => { 248 VoltageScale::Range2 => {
234 if ahb_freq <= 18_000_000 { 249 if ahb_freq <= 18_000_000 {
235 Some(Latency::WS0) 250 Some(Latency::WS0)
236 } else if ahb_freq <= 36_000_000 { 251 } else if ahb_freq <= 36_000_000 {
@@ -249,7 +264,7 @@ impl VoltageScale {
249 None 264 None
250 } 265 }
251 } 266 }
252 VoltageScale::Scale1 => { 267 VoltageScale::Range1 => {
253 if ahb_freq <= 24_000_000 { 268 if ahb_freq <= 24_000_000 {
254 Some(Latency::WS0) 269 Some(Latency::WS0)
255 } else if ahb_freq <= 48_000_000 { 270 } else if ahb_freq <= 48_000_000 {
@@ -264,7 +279,7 @@ impl VoltageScale {
264 None 279 None
265 } 280 }
266 } 281 }
267 VoltageScale::Scale0 => { 282 VoltageScale::Range0 => {
268 if ahb_freq <= 30_000_000 { 283 if ahb_freq <= 30_000_000 {
269 Some(Latency::WS0) 284 Some(Latency::WS0)
270 } else if ahb_freq <= 60_000_000 { 285 } else if ahb_freq <= 60_000_000 {
@@ -288,6 +303,9 @@ pub struct Config {
288 pub pll_mux: PLLSrc, 303 pub pll_mux: PLLSrc,
289 pub pll: PLLConfig, 304 pub pll: PLLConfig,
290 pub mux: ClockSrc, 305 pub mux: ClockSrc,
306 pub rtc: Option<RtcClockSource>,
307 pub lsi: bool,
308 pub lse: Option<Hertz>,
291 pub voltage: VoltageScale, 309 pub voltage: VoltageScale,
292 pub ahb_pre: AHBPrescaler, 310 pub ahb_pre: AHBPrescaler,
293 pub apb1_pre: APBPrescaler, 311 pub apb1_pre: APBPrescaler,
@@ -302,11 +320,14 @@ impl Default for Config {
302 hsi: true, 320 hsi: true,
303 pll_mux: PLLSrc::HSI, 321 pll_mux: PLLSrc::HSI,
304 pll: PLLConfig::default(), 322 pll: PLLConfig::default(),
305 voltage: VoltageScale::Scale3, 323 voltage: VoltageScale::Range3,
306 mux: ClockSrc::HSI, 324 mux: ClockSrc::HSI,
307 ahb_pre: AHBPrescaler::NotDivided, 325 rtc: None,
308 apb1_pre: APBPrescaler::NotDivided, 326 lsi: false,
309 apb2_pre: APBPrescaler::NotDivided, 327 lse: None,
328 ahb_pre: AHBPrescaler::DIV1,
329 apb1_pre: APBPrescaler::DIV1,
330 apb2_pre: APBPrescaler::DIV1,
310 } 331 }
311 } 332 }
312} 333}
@@ -379,7 +400,7 @@ pub(crate) unsafe fn init(config: Config) {
379 assert!(ahb_freq <= Hertz(120_000_000)); 400 assert!(ahb_freq <= Hertz(120_000_000));
380 401
381 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 402 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
382 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 403 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
383 pre => { 404 pre => {
384 let freq = ahb_freq / pre; 405 let freq = ahb_freq / pre;
385 (freq, Hertz(freq.0 * 2)) 406 (freq, Hertz(freq.0 * 2))
@@ -389,7 +410,7 @@ pub(crate) unsafe fn init(config: Config) {
389 assert!(apb1_freq <= Hertz(30_000_000)); 410 assert!(apb1_freq <= Hertz(30_000_000));
390 411
391 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 412 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
392 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 413 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
393 pre => { 414 pre => {
394 let freq = ahb_freq / pre; 415 let freq = ahb_freq / pre;
395 (freq, Hertz(freq.0 * 2)) 416 (freq, Hertz(freq.0 * 2))
@@ -414,6 +435,12 @@ pub(crate) unsafe fn init(config: Config) {
414 RCC.cr().modify(|w| w.set_hsion(false)); 435 RCC.cr().modify(|w| w.set_hsion(false));
415 } 436 }
416 437
438 BackupDomain::configure_ls(
439 config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
440 config.lsi,
441 config.lse.map(|_| Default::default()),
442 );
443
417 set_freqs(Clocks { 444 set_freqs(Clocks {
418 sys: sys_clk, 445 sys: sys_clk,
419 ahb1: ahb_freq, 446 ahb1: ahb_freq,
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
index 321270a70..630dbd4fe 100644
--- a/embassy-stm32/src/rcc/f3.rs
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -1,5 +1,7 @@
1#[cfg(rcc_f3)]
2use crate::pac::adccommon::vals::Ckmode;
1use crate::pac::flash::vals::Latency; 3use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; 4use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
3use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks}; 6use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 7use crate::time::Hertz;
@@ -10,6 +12,82 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000);
10/// LSI speed 12/// LSI speed
11pub const LSI_FREQ: Hertz = Hertz(40_000); 13pub const LSI_FREQ: Hertz = Hertz(40_000);
12 14
15impl From<AdcClockSource> for Adcpres {
16 fn from(value: AdcClockSource) -> Self {
17 match value {
18 AdcClockSource::PllDiv1 => Adcpres::DIV1,
19 AdcClockSource::PllDiv2 => Adcpres::DIV2,
20 AdcClockSource::PllDiv4 => Adcpres::DIV4,
21 AdcClockSource::PllDiv6 => Adcpres::DIV6,
22 AdcClockSource::PllDiv8 => Adcpres::DIV8,
23 AdcClockSource::PllDiv12 => Adcpres::DIV12,
24 AdcClockSource::PllDiv16 => Adcpres::DIV16,
25 AdcClockSource::PllDiv32 => Adcpres::DIV32,
26 AdcClockSource::PllDiv64 => Adcpres::DIV64,
27 AdcClockSource::PllDiv128 => Adcpres::DIV128,
28 AdcClockSource::PllDiv256 => Adcpres::DIV256,
29 _ => unreachable!(),
30 }
31 }
32}
33
34#[cfg(rcc_f3)]
35impl From<AdcClockSource> for Ckmode {
36 fn from(value: AdcClockSource) -> Self {
37 match value {
38 AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1,
39 AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2,
40 AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4,
41 _ => unreachable!(),
42 }
43 }
44}
45
46#[derive(Clone, Copy)]
47pub enum AdcClockSource {
48 PllDiv1 = 1,
49 PllDiv2 = 2,
50 PllDiv4 = 4,
51 PllDiv6 = 6,
52 PllDiv8 = 8,
53 PllDiv12 = 12,
54 PllDiv16 = 16,
55 PllDiv32 = 32,
56 PllDiv64 = 64,
57 PllDiv128 = 128,
58 PllDiv256 = 256,
59 BusDiv1,
60 BusDiv2,
61 BusDiv4,
62}
63
64impl AdcClockSource {
65 pub fn is_bus(&self) -> bool {
66 match self {
67 Self::BusDiv1 => true,
68 Self::BusDiv2 => true,
69 Self::BusDiv4 => true,
70 _ => false,
71 }
72 }
73
74 pub fn bus_div(&self) -> u32 {
75 match self {
76 Self::BusDiv1 => 1,
77 Self::BusDiv2 => 2,
78 Self::BusDiv4 => 4,
79 _ => unreachable!(),
80 }
81 }
82}
83
84#[derive(Default)]
85pub enum HrtimClockSource {
86 #[default]
87 BusClk,
88 PllClk,
89}
90
13/// Clocks configutation 91/// Clocks configutation
14#[non_exhaustive] 92#[non_exhaustive]
15#[derive(Default)] 93#[derive(Default)]
@@ -36,9 +114,20 @@ pub struct Config {
36 /// - The System clock frequency is either 48MHz or 72MHz 114 /// - The System clock frequency is either 48MHz or 72MHz
37 /// - APB1 clock has a minimum frequency of 10MHz 115 /// - APB1 clock has a minimum frequency of 10MHz
38 pub pll48: bool, 116 pub pll48: bool,
117 #[cfg(rcc_f3)]
118 /// ADC clock setup
119 /// - For AHB, a psc of 4 or less must be used
120 pub adc: Option<AdcClockSource>,
121 #[cfg(rcc_f3)]
122 /// ADC clock setup
123 /// - For AHB, a psc of 4 or less must be used
124 pub adc34: Option<AdcClockSource>,
125 #[cfg(stm32f334)]
126 pub hrtim: HrtimClockSource,
39} 127}
40 128
41// Information required to setup the PLL clock 129// Information required to setup the PLL clock
130#[derive(Clone, Copy)]
42struct PllConfig { 131struct PllConfig {
43 pll_src: Pllsrc, 132 pll_src: Pllsrc,
44 pll_mul: Pllmul, 133 pll_mul: Pllmul,
@@ -170,6 +259,65 @@ pub(crate) unsafe fn init(config: Config) {
170 }) 259 })
171 }); 260 });
172 261
262 #[cfg(rcc_f3)]
263 let adc = config.adc.map(|adc| {
264 if !adc.is_bus() {
265 RCC.cfgr2().modify(|w| {
266 // Make sure that we're using the PLL
267 pll_config.unwrap();
268 w.set_adc12pres(adc.into());
269
270 Hertz(sysclk / adc as u32)
271 })
272 } else {
273 crate::pac::ADC_COMMON.ccr().modify(|w| {
274 assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
275
276 w.set_ckmode(adc.into());
277
278 Hertz(sysclk / adc.bus_div() as u32)
279 })
280 }
281 });
282
283 #[cfg(all(rcc_f3, adc3_common))]
284 let adc34 = config.adc.map(|adc| {
285 if !adc.is_bus() {
286 RCC.cfgr2().modify(|w| {
287 // Make sure that we're using the PLL
288 pll_config.unwrap();
289 w.set_adc12pres(adc.into());
290
291 Hertz(sysclk / adc as u32)
292 })
293 } else {
294 crate::pac::ADC3_COMMON.ccr().modify(|w| {
295 assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
296
297 w.set_ckmode(adc.into());
298
299 Hertz(sysclk / adc.bus_div() as u32)
300 })
301 }
302 });
303
304 #[cfg(stm32f334)]
305 let hrtim = match config.hrtim {
306 // Must be configured after the bus is ready, otherwise it won't work
307 HrtimClockSource::BusClk => None,
308 HrtimClockSource::PllClk => {
309 use crate::pac::rcc::vals::Timsw;
310
311 // Make sure that we're using the PLL
312 pll_config.unwrap();
313 assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk));
314
315 RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
316
317 Some(Hertz(sysclk * 2))
318 }
319 };
320
173 set_freqs(Clocks { 321 set_freqs(Clocks {
174 sys: Hertz(sysclk), 322 sys: Hertz(sysclk),
175 apb1: Hertz(pclk1), 323 apb1: Hertz(pclk1),
@@ -177,6 +325,14 @@ pub(crate) unsafe fn init(config: Config) {
177 apb1_tim: Hertz(pclk1 * timer_mul1), 325 apb1_tim: Hertz(pclk1 * timer_mul1),
178 apb2_tim: Hertz(pclk2 * timer_mul2), 326 apb2_tim: Hertz(pclk2 * timer_mul2),
179 ahb1: Hertz(hclk), 327 ahb1: Hertz(hclk),
328 #[cfg(rcc_f3)]
329 adc: adc,
330 #[cfg(all(rcc_f3, adc3_common))]
331 adc34: adc34,
332 #[cfg(all(rcc_f3, not(adc3_common)))]
333 adc34: None,
334 #[cfg(stm32f334)]
335 hrtim: hrtim,
180 }); 336 });
181} 337}
182 338
@@ -201,9 +357,9 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
201 // Calculates the Multiplier and the Divisor to arrive at 357 // Calculates the Multiplier and the Divisor to arrive at
202 // the required System clock from PLL source frequency 358 // the required System clock from PLL source frequency
203 let get_mul_div = |sysclk, pllsrcclk| { 359 let get_mul_div = |sysclk, pllsrcclk| {
204 let common_div = gcd(sysclk, pllsrcclk); 360 let bus_div = gcd(sysclk, pllsrcclk);
205 let mut multiplier = sysclk / common_div; 361 let mut multiplier = sysclk / bus_div;
206 let mut divisor = pllsrcclk / common_div; 362 let mut divisor = pllsrcclk / bus_div;
207 // Minimum PLL multiplier is two 363 // Minimum PLL multiplier is two
208 if multiplier == 1 { 364 if multiplier == 1 {
209 multiplier *= 2; 365 multiplier *= 2;
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index 72bdbd5db..2c027ebed 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -3,13 +3,12 @@ use core::marker::PhantomData;
3use embassy_hal_internal::into_ref; 3use embassy_hal_internal::into_ref;
4use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; 4use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
5 5
6use super::sealed::RccPeripheral;
7use crate::gpio::sealed::AFType; 6use crate::gpio::sealed::AFType;
8use crate::gpio::Speed; 7use crate::gpio::Speed;
9use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; 8use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
10use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
10use crate::rcc::bd::{BackupDomain, RtcClockSource};
11use crate::rcc::{set_freqs, Clocks}; 11use crate::rcc::{set_freqs, Clocks};
12use crate::rtc::{Rtc, RtcClockSource};
13use crate::time::Hertz; 12use crate::time::Hertz;
14use crate::{peripherals, Peripheral}; 13use crate::{peripherals, Peripheral};
15 14
@@ -38,6 +37,8 @@ pub struct Config {
38 37
39 pub pll48: bool, 38 pub pll48: bool,
40 pub rtc: Option<RtcClockSource>, 39 pub rtc: Option<RtcClockSource>,
40 pub lsi: bool,
41 pub lse: Option<Hertz>,
41} 42}
42 43
43#[cfg(stm32f410)] 44#[cfg(stm32f410)]
@@ -360,8 +361,6 @@ fn flash_setup(sysclk: u32) {
360} 361}
361 362
362pub(crate) unsafe fn init(config: Config) { 363pub(crate) unsafe fn init(config: Config) {
363 crate::peripherals::PWR::enable();
364
365 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); 364 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
366 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); 365 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
367 let sysclk_on_pll = sysclk != pllsrcclk; 366 let sysclk_on_pll = sysclk != pllsrcclk;
@@ -501,20 +500,15 @@ pub(crate) unsafe fn init(config: Config) {
501 }) 500 })
502 }); 501 });
503 502
504 match config.rtc { 503 BackupDomain::configure_ls(
505 Some(RtcClockSource::LSI) => { 504 config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
506 RCC.csr().modify(|w| w.set_lsion(true)); 505 config.lsi,
507 while !RCC.csr().read().lsirdy() {} 506 config.lse.map(|_| Default::default()),
508 } 507 );
509 _ => {}
510 }
511
512 config.rtc.map(|clock_source| {
513 Rtc::set_clock_source(clock_source);
514 });
515 508
516 let rtc = match config.rtc { 509 let rtc = match config.rtc {
517 Some(RtcClockSource::LSI) => Some(LSI_FREQ), 510 Some(RtcClockSource::LSI) => Some(LSI_FREQ),
511 Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
518 _ => None, 512 _ => None,
519 }; 513 };
520 514
@@ -539,6 +533,7 @@ pub(crate) unsafe fn init(config: Config) {
539 pllsai: plls.pllsaiclk.map(Hertz), 533 pllsai: plls.pllsaiclk.map(Hertz),
540 534
541 rtc: rtc, 535 rtc: rtc,
536 rtc_hse: None,
542 }); 537 });
543} 538}
544 539
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 85cb9c661..f32559e26 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -1,7 +1,7 @@
1use super::sealed::RccPeripheral;
2use crate::pac::pwr::vals::Vos; 1use crate::pac::pwr::vals::Vos;
3use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; 2use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
4use crate::pac::{FLASH, PWR, RCC}; 3use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::bd::{BackupDomain, RtcClockSource};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
@@ -23,6 +23,9 @@ pub struct Config {
23 pub pclk2: Option<Hertz>, 23 pub pclk2: Option<Hertz>,
24 24
25 pub pll48: bool, 25 pub pll48: bool,
26 pub rtc: Option<RtcClockSource>,
27 pub lsi: bool,
28 pub lse: Option<Hertz>,
26} 29}
27 30
28fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { 31fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
@@ -111,8 +114,6 @@ fn flash_setup(sysclk: u32) {
111} 114}
112 115
113pub(crate) unsafe fn init(config: Config) { 116pub(crate) unsafe fn init(config: Config) {
114 crate::peripherals::PWR::enable();
115
116 if let Some(hse) = config.hse { 117 if let Some(hse) = config.hse {
117 if config.bypass_hse { 118 if config.bypass_hse {
118 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); 119 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
@@ -212,10 +213,7 @@ pub(crate) unsafe fn init(config: Config) {
212 if plls.use_pll { 213 if plls.use_pll {
213 RCC.cr().modify(|w| w.set_pllon(false)); 214 RCC.cr().modify(|w| w.set_pllon(false));
214 215
215 // enable PWR and setup VOSScale 216 // setup VOSScale
216
217 RCC.apb1enr().modify(|w| w.set_pwren(true));
218
219 let vos_scale = if sysclk <= 144_000_000 { 217 let vos_scale = if sysclk <= 144_000_000 {
220 3 218 3
221 } else if sysclk <= 168_000_000 { 219 } else if sysclk <= 168_000_000 {
@@ -265,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) {
265 }) 263 })
266 }); 264 });
267 265
266 BackupDomain::configure_ls(
267 config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
268 config.lsi,
269 config.lse.map(|_| Default::default()),
270 );
271
272 let rtc = match config.rtc {
273 Some(RtcClockSource::LSI) => Some(LSI_FREQ),
274 Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
275 _ => None,
276 };
277
268 set_freqs(Clocks { 278 set_freqs(Clocks {
269 sys: Hertz(sysclk), 279 sys: Hertz(sysclk),
270 apb1: Hertz(pclk1), 280 apb1: Hertz(pclk1),
@@ -278,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) {
278 ahb3: Hertz(hclk), 288 ahb3: Hertz(hclk),
279 289
280 pll48: plls.pll48clk.map(Hertz), 290 pll48: plls.pll48clk.map(Hertz),
291
292 rtc,
281 }); 293 });
282} 294}
283 295
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index bf2d5199e..7f0a2c7fb 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,4 +1,4 @@
1pub use super::common::{AHBPrescaler, APBPrescaler}; 1pub use super::bus::{AHBPrescaler, APBPrescaler};
2use crate::pac::flash::vals::Latency; 2use crate::pac::flash::vals::Latency;
3use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; 3use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw};
4use crate::pac::{FLASH, PWR, RCC}; 4use crate::pac::{FLASH, PWR, RCC};
@@ -186,8 +186,8 @@ impl Default for Config {
186 fn default() -> Config { 186 fn default() -> Config {
187 Config { 187 Config {
188 mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), 188 mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
189 ahb_pre: AHBPrescaler::NotDivided, 189 ahb_pre: AHBPrescaler::DIV1,
190 apb_pre: APBPrescaler::NotDivided, 190 apb_pre: APBPrescaler::DIV1,
191 low_power_run: false, 191 low_power_run: false,
192 } 192 }
193 } 193 }
@@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) {
377 let ahb_freq = Hertz(sys_clk) / config.ahb_pre; 377 let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
378 378
379 let (apb_freq, apb_tim_freq) = match config.apb_pre { 379 let (apb_freq, apb_tim_freq) = match config.apb_pre {
380 APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0), 380 APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0),
381 pre => { 381 pre => {
382 let pre: Ppre = pre.into(); 382 let pre: Ppre = pre.into();
383 let pre: u8 = 1 << (pre.to_bits() - 3); 383 let pre: u8 = 1 << (pre.to_bits() - 3);
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index dff04023e..41bebc918 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,8 +1,8 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; 2use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5pub use super::common::{AHBPrescaler, APBPrescaler}; 5pub use super::bus::{AHBPrescaler, APBPrescaler};
6use crate::pac::{PWR, RCC}; 6use crate::pac::{PWR, RCC};
7use crate::rcc::sealed::RccPeripheral; 7use crate::rcc::sealed::RccPeripheral;
8use crate::rcc::{set_freqs, Clocks}; 8use crate::rcc::{set_freqs, Clocks};
@@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
14/// LSI speed 14/// LSI speed
15pub const LSI_FREQ: Hertz = Hertz(32_000); 15pub const LSI_FREQ: Hertz = Hertz(32_000);
16 16
17#[derive(Clone, Copy)]
18pub enum AdcClockSource {
19 NoClk,
20 SysClk,
21 PllP,
22}
23
24impl AdcClockSource {
25 pub fn adcsel(&self) -> Adcsel {
26 match self {
27 AdcClockSource::NoClk => Adcsel::NOCLK,
28 AdcClockSource::SysClk => Adcsel::SYSCLK,
29 AdcClockSource::PllP => Adcsel::PLLP,
30 }
31 }
32}
33
34impl Default for AdcClockSource {
35 fn default() -> Self {
36 Self::NoClk
37 }
38}
39
17/// System clock mux source 40/// System clock mux source
18#[derive(Clone, Copy)] 41#[derive(Clone, Copy)]
19pub enum ClockSrc { 42pub enum ClockSrc {
@@ -238,59 +261,29 @@ pub struct Pll {
238 pub div_r: Option<PllR>, 261 pub div_r: Option<PllR>,
239} 262}
240 263
241impl AHBPrescaler { 264fn ahb_div(ahb: AHBPrescaler) -> u32 {
242 const fn div(self) -> u32 { 265 match ahb {
243 match self { 266 AHBPrescaler::DIV1 => 1,
244 AHBPrescaler::NotDivided => 1, 267 AHBPrescaler::DIV2 => 2,
245 AHBPrescaler::Div2 => 2, 268 AHBPrescaler::DIV4 => 4,
246 AHBPrescaler::Div4 => 4, 269 AHBPrescaler::DIV8 => 8,
247 AHBPrescaler::Div8 => 8, 270 AHBPrescaler::DIV16 => 16,
248 AHBPrescaler::Div16 => 16, 271 AHBPrescaler::DIV64 => 64,
249 AHBPrescaler::Div64 => 64, 272 AHBPrescaler::DIV128 => 128,
250 AHBPrescaler::Div128 => 128, 273 AHBPrescaler::DIV256 => 256,
251 AHBPrescaler::Div256 => 256, 274 AHBPrescaler::DIV512 => 512,
252 AHBPrescaler::Div512 => 512, 275 _ => unreachable!(),
253 }
254 } 276 }
255} 277}
256 278
257impl APBPrescaler { 279fn apb_div(apb: APBPrescaler) -> u32 {
258 const fn div(self) -> u32 { 280 match apb {
259 match self { 281 APBPrescaler::DIV1 => 1,
260 APBPrescaler::NotDivided => 1, 282 APBPrescaler::DIV2 => 2,
261 APBPrescaler::Div2 => 2, 283 APBPrescaler::DIV4 => 4,
262 APBPrescaler::Div4 => 4, 284 APBPrescaler::DIV8 => 8,
263 APBPrescaler::Div8 => 8, 285 APBPrescaler::DIV16 => 16,
264 APBPrescaler::Div16 => 16, 286 _ => unreachable!(),
265 }
266 }
267}
268
269impl Into<Ppre> for APBPrescaler {
270 fn into(self) -> Ppre {
271 match self {
272 APBPrescaler::NotDivided => Ppre::DIV1,
273 APBPrescaler::Div2 => Ppre::DIV2,
274 APBPrescaler::Div4 => Ppre::DIV4,
275 APBPrescaler::Div8 => Ppre::DIV8,
276 APBPrescaler::Div16 => Ppre::DIV16,
277 }
278 }
279}
280
281impl Into<Hpre> for AHBPrescaler {
282 fn into(self) -> Hpre {
283 match self {
284 AHBPrescaler::NotDivided => Hpre::DIV1,
285 AHBPrescaler::Div2 => Hpre::DIV2,
286 AHBPrescaler::Div4 => Hpre::DIV4,
287 AHBPrescaler::Div8 => Hpre::DIV8,
288 AHBPrescaler::Div16 => Hpre::DIV16,
289 AHBPrescaler::Div64 => Hpre::DIV64,
290 AHBPrescaler::Div128 => Hpre::DIV128,
291 AHBPrescaler::Div256 => Hpre::DIV256,
292 AHBPrescaler::Div512 => Hpre::DIV512,
293 }
294 } 287 }
295} 288}
296 289
@@ -327,6 +320,8 @@ pub struct Config {
327 pub pll: Option<Pll>, 320 pub pll: Option<Pll>,
328 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. 321 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
329 pub clock_48mhz_src: Option<Clock48MhzSrc>, 322 pub clock_48mhz_src: Option<Clock48MhzSrc>,
323 pub adc12_clock_source: AdcClockSource,
324 pub adc345_clock_source: AdcClockSource,
330} 325}
331 326
332/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. 327/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@@ -340,12 +335,14 @@ impl Default for Config {
340 fn default() -> Config { 335 fn default() -> Config {
341 Config { 336 Config {
342 mux: ClockSrc::HSI16, 337 mux: ClockSrc::HSI16,
343 ahb_pre: AHBPrescaler::NotDivided, 338 ahb_pre: AHBPrescaler::DIV1,
344 apb1_pre: APBPrescaler::NotDivided, 339 apb1_pre: APBPrescaler::DIV1,
345 apb2_pre: APBPrescaler::NotDivided, 340 apb2_pre: APBPrescaler::DIV1,
346 low_power_run: false, 341 low_power_run: false,
347 pll: None, 342 pll: None,
348 clock_48mhz_src: None, 343 clock_48mhz_src: None,
344 adc12_clock_source: Default::default(),
345 adc345_clock_source: Default::default(),
349 } 346 }
350 } 347 }
351} 348}
@@ -485,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) {
485 }); 482 });
486 483
487 let ahb_freq: u32 = match config.ahb_pre { 484 let ahb_freq: u32 = match config.ahb_pre {
488 AHBPrescaler::NotDivided => sys_clk, 485 AHBPrescaler::DIV1 => sys_clk,
489 pre => sys_clk / pre.div(), 486 pre => sys_clk / ahb_div(pre),
490 }; 487 };
491 488
492 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 489 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
493 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 490 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
494 pre => { 491 pre => {
495 let freq = ahb_freq / pre.div(); 492 let freq = ahb_freq / apb_div(pre);
496 (freq, freq * 2) 493 (freq, freq * 2)
497 } 494 }
498 }; 495 };
499 496
500 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 497 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
501 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 498 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
502 pre => { 499 pre => {
503 let freq = ahb_freq / pre.div(); 500 let freq = ahb_freq / apb_div(pre);
504 (freq, freq * 2) 501 (freq, freq * 2)
505 } 502 }
506 }; 503 };
@@ -549,6 +546,29 @@ pub(crate) unsafe fn init(config: Config) {
549 RCC.ccipr().modify(|w| w.set_clk48sel(source)); 546 RCC.ccipr().modify(|w| w.set_clk48sel(source));
550 } 547 }
551 548
549 RCC.ccipr()
550 .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel()));
551 RCC.ccipr()
552 .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
553
554 let adc12_ck = match config.adc12_clock_source {
555 AdcClockSource::NoClk => None,
556 AdcClockSource::PllP => match &pll_freq {
557 Some(pll) => pll.pll_p,
558 None => None,
559 },
560 AdcClockSource::SysClk => Some(Hertz(sys_clk)),
561 };
562
563 let adc345_ck = match config.adc345_clock_source {
564 AdcClockSource::NoClk => None,
565 AdcClockSource::PllP => match &pll_freq {
566 Some(pll) => pll.pll_p,
567 None => None,
568 },
569 AdcClockSource::SysClk => Some(Hertz(sys_clk)),
570 };
571
552 if config.low_power_run { 572 if config.low_power_run {
553 assert!(sys_clk <= 2_000_000); 573 assert!(sys_clk <= 2_000_000);
554 PWR.cr1().modify(|w| w.set_lpr(true)); 574 PWR.cr1().modify(|w| w.set_lpr(true));
@@ -562,5 +582,7 @@ pub(crate) unsafe fn init(config: Config) {
562 apb1_tim: Hertz(apb1_tim_freq), 582 apb1_tim: Hertz(apb1_tim_freq),
563 apb2: Hertz(apb2_freq), 583 apb2: Hertz(apb2_freq),
564 apb2_tim: Hertz(apb2_tim_freq), 584 apb2_tim: Hertz(apb2_tim_freq),
585 adc: adc12_ck,
586 adc34: adc345_ck,
565 }); 587 });
566} 588}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
new file mode 100644
index 000000000..43e8db22e
--- /dev/null
+++ b/embassy-stm32/src/rcc/h.rs
@@ -0,0 +1,772 @@
1use core::ops::RangeInclusive;
2
3use crate::pac;
4use crate::pac::pwr::vals::Vos;
5#[cfg(stm32h5)]
6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
10use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
11use crate::pac::{FLASH, PWR, RCC};
12use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz;
14
15/// HSI speed
16pub const HSI_FREQ: Hertz = Hertz(64_000_000);
17
18/// CSI speed
19pub const CSI_FREQ: Hertz = Hertz(4_000_000);
20
21/// HSI48 speed
22pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
23
24/// LSI speed
25pub const LSI_FREQ: Hertz = Hertz(32_000);
26
27const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
28#[cfg(any(stm32h5, pwr_h7rm0455))]
29const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000;
30#[cfg(pwr_h7rm0468)]
31const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000;
32#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
33const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000;
34
35pub use super::bus::{AHBPrescaler, APBPrescaler};
36
37#[derive(Clone, Copy, Eq, PartialEq)]
38pub enum VoltageScale {
39 Scale0,
40 Scale1,
41 Scale2,
42 Scale3,
43}
44
45#[derive(Clone, Copy, Eq, PartialEq)]
46pub enum HseMode {
47 /// crystal/ceramic oscillator (HSEBYP=0)
48 Oscillator,
49 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
50 Bypass,
51 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
52 #[cfg(any(rcc_h5, rcc_h50))]
53 BypassDigital,
54}
55
56#[derive(Clone, Copy, Eq, PartialEq)]
57pub struct Hse {
58 /// HSE frequency.
59 pub freq: Hertz,
60 /// HSE mode.
61 pub mode: HseMode,
62}
63
64#[derive(Clone, Copy, Eq, PartialEq)]
65pub enum Hsi {
66 /// 64Mhz
67 Mhz64,
68 /// 32Mhz (divided by 2)
69 Mhz32,
70 /// 16Mhz (divided by 4)
71 Mhz16,
72 /// 8Mhz (divided by 8)
73 Mhz8,
74}
75
76#[derive(Clone, Copy, Eq, PartialEq)]
77pub enum Sysclk {
78 /// HSI selected as sysclk
79 HSI,
80 /// HSE selected as sysclk
81 HSE,
82 /// CSI selected as sysclk
83 CSI,
84 /// PLL1_P selected as sysclk
85 Pll1P,
86}
87
88#[derive(Clone, Copy, Eq, PartialEq)]
89pub enum PllSource {
90 Hsi,
91 Csi,
92 Hse,
93}
94
95#[derive(Clone, Copy)]
96pub struct Pll {
97 /// Source clock selection.
98 #[cfg(stm32h5)]
99 pub source: PllSource,
100
101 /// PLL pre-divider (DIVM). Must be between 1 and 63.
102 pub prediv: u8,
103
104 /// PLL multiplication factor. Must be between 4 and 512.
105 pub mul: u16,
106
107 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
108 /// On PLL1, it must be even (in particular, it cannot be 1.)
109 pub divp: Option<u16>,
110 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
111 pub divq: Option<u16>,
112 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
113 pub divr: Option<u16>,
114}
115
116fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
117 match (tim, apb) {
118 (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
119 (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
120 (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
121 (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
122 (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
123
124 (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk,
125 (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
126 (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk,
127 (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
128 (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
129
130 _ => unreachable!(),
131 }
132}
133
134/// Timer prescaler
135#[derive(Clone, Copy, Eq, PartialEq)]
136pub enum TimerPrescaler {
137 /// The timers kernel clock is equal to hclk if PPREx corresponds to a
138 /// division by 1 or 2, else it is equal to 2*pclk
139 DefaultX2,
140
141 /// The timers kernel clock is equal to hclk if PPREx corresponds to a
142 /// division by 1, 2 or 4, else it is equal to 4*pclk
143 DefaultX4,
144}
145
146impl From<TimerPrescaler> for Timpre {
147 fn from(value: TimerPrescaler) -> Self {
148 match value {
149 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
150 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
151 }
152 }
153}
154
155/// Configuration of the core clocks
156#[non_exhaustive]
157pub struct Config {
158 pub hsi: Option<Hsi>,
159 pub hse: Option<Hse>,
160 pub csi: bool,
161 pub hsi48: bool,
162 pub sys: Sysclk,
163
164 #[cfg(stm32h7)]
165 pub pll_src: PllSource,
166
167 pub pll1: Option<Pll>,
168 pub pll2: Option<Pll>,
169 #[cfg(any(rcc_h5, stm32h7))]
170 pub pll3: Option<Pll>,
171
172 pub d1c_pre: AHBPrescaler,
173 pub ahb_pre: AHBPrescaler,
174 pub apb1_pre: APBPrescaler,
175 pub apb2_pre: APBPrescaler,
176 pub apb3_pre: APBPrescaler,
177 #[cfg(stm32h7)]
178 pub apb4_pre: APBPrescaler,
179
180 pub per_clock_source: PerClockSource,
181 pub adc_clock_source: AdcClockSource,
182 pub timer_prescaler: TimerPrescaler,
183 pub voltage_scale: VoltageScale,
184}
185
186impl Default for Config {
187 fn default() -> Self {
188 Self {
189 hsi: Some(Hsi::Mhz64),
190 hse: None,
191 csi: false,
192 hsi48: false,
193 sys: Sysclk::HSI,
194 #[cfg(stm32h7)]
195 pll_src: PllSource::Hsi,
196 pll1: None,
197 pll2: None,
198 #[cfg(any(rcc_h5, stm32h7))]
199 pll3: None,
200
201 d1c_pre: AHBPrescaler::DIV1,
202 ahb_pre: AHBPrescaler::DIV1,
203 apb1_pre: APBPrescaler::DIV1,
204 apb2_pre: APBPrescaler::DIV1,
205 apb3_pre: APBPrescaler::DIV1,
206 #[cfg(stm32h7)]
207 apb4_pre: APBPrescaler::DIV1,
208
209 per_clock_source: PerClockSource::HSI,
210 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
211 timer_prescaler: TimerPrescaler::DefaultX2,
212 voltage_scale: VoltageScale::Scale0,
213 }
214 }
215}
216
217pub(crate) unsafe fn init(config: Config) {
218 // NB. The lower bytes of CR3 can only be written once after
219 // POR, and must be written with a valid combination. Refer to
220 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
221 // `self` at the end of this method, but of course we cannot
222 // know what happened between the previous POR and here.
223 #[cfg(pwr_h7rm0433)]
224 PWR.cr3().modify(|w| {
225 w.set_scuen(true);
226 w.set_ldoen(true);
227 w.set_bypass(false);
228 });
229
230 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
231 PWR.cr3().modify(|w| {
232 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
233 // default solderbridge configuration.
234 w.set_sden(true);
235 w.set_ldoen(false);
236 });
237
238 // Validate the supply configuration. If you are stuck here, it is
239 // because the voltages on your board do not match those specified
240 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
241 // VOS = Scale 3, so check that the voltage on the VCAP pins =
242 // 1.0V.
243 #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
244 while !PWR.csr1().read().actvosrdy() {}
245
246 // Configure voltage scale.
247 #[cfg(any(pwr_h5, pwr_h50))]
248 {
249 PWR.voscr().modify(|w| {
250 w.set_vos(match config.voltage_scale {
251 VoltageScale::Scale0 => Vos::SCALE0,
252 VoltageScale::Scale1 => Vos::SCALE1,
253 VoltageScale::Scale2 => Vos::SCALE2,
254 VoltageScale::Scale3 => Vos::SCALE3,
255 })
256 });
257 while !PWR.vossr().read().vosrdy() {}
258 }
259
260 #[cfg(syscfg_h7)]
261 {
262 // in chips without the overdrive bit, we can go from any scale to any scale directly.
263 PWR.d3cr().modify(|w| {
264 w.set_vos(match config.voltage_scale {
265 VoltageScale::Scale0 => Vos::SCALE0,
266 VoltageScale::Scale1 => Vos::SCALE1,
267 VoltageScale::Scale2 => Vos::SCALE2,
268 VoltageScale::Scale3 => Vos::SCALE3,
269 })
270 });
271 while !PWR.d3cr().read().vosrdy() {}
272 }
273
274 #[cfg(syscfg_h7od)]
275 {
276 match config.voltage_scale {
277 VoltageScale::Scale0 => {
278 // to go to scale0, we must go to Scale1 first...
279 PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
280 while !PWR.d3cr().read().vosrdy() {}
281
282 // Then enable overdrive.
283 critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1)));
284 while !PWR.d3cr().read().vosrdy() {}
285 }
286 _ => {
287 // for all other scales, we can go directly.
288 PWR.d3cr().modify(|w| {
289 w.set_vos(match config.voltage_scale {
290 VoltageScale::Scale0 => unreachable!(),
291 VoltageScale::Scale1 => Vos::SCALE1,
292 VoltageScale::Scale2 => Vos::SCALE2,
293 VoltageScale::Scale3 => Vos::SCALE3,
294 })
295 });
296 while !PWR.d3cr().read().vosrdy() {}
297 }
298 }
299 }
300
301 // Configure HSI
302 let hsi = match config.hsi {
303 None => {
304 RCC.cr().modify(|w| w.set_hsion(false));
305 None
306 }
307 Some(hsi) => {
308 let (freq, hsidiv) = match hsi {
309 Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
310 Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
311 Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
312 Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
313 };
314 RCC.cr().modify(|w| {
315 w.set_hsidiv(hsidiv);
316 w.set_hsion(true);
317 });
318 while !RCC.cr().read().hsirdy() {}
319 Some(freq)
320 }
321 };
322
323 // Configure HSE
324 let hse = match config.hse {
325 None => {
326 RCC.cr().modify(|w| w.set_hseon(false));
327 None
328 }
329 Some(hse) => {
330 RCC.cr().modify(|w| {
331 w.set_hsebyp(hse.mode != HseMode::Oscillator);
332 #[cfg(any(rcc_h5, rcc_h50))]
333 w.set_hseext(match hse.mode {
334 HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG,
335 HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL,
336 });
337 });
338 RCC.cr().modify(|w| w.set_hseon(true));
339 while !RCC.cr().read().hserdy() {}
340 Some(hse.freq)
341 }
342 };
343
344 // Configure HSI48.
345 RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
346 let _hsi48 = match config.hsi48 {
347 false => None,
348 true => {
349 while !RCC.cr().read().hsi48rdy() {}
350 Some(CSI_FREQ)
351 }
352 };
353
354 // Configure CSI.
355 RCC.cr().modify(|w| w.set_csion(config.csi));
356 let csi = match config.csi {
357 false => None,
358 true => {
359 while !RCC.cr().read().csirdy() {}
360 Some(CSI_FREQ)
361 }
362 };
363
364 // Configure PLLs.
365 let pll_input = PllInput {
366 csi,
367 hse,
368 hsi,
369 #[cfg(stm32h7)]
370 source: config.pll_src,
371 };
372 let pll1 = init_pll(0, config.pll1, &pll_input);
373 let pll2 = init_pll(1, config.pll2, &pll_input);
374 #[cfg(any(rcc_h5, stm32h7))]
375 let _pll3 = init_pll(2, config.pll3, &pll_input);
376
377 // Configure sysclk
378 let (sys, sw) = match config.sys {
379 Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
380 Sysclk::HSE => (unwrap!(hse), Sw::HSE),
381 Sysclk::CSI => (unwrap!(csi), Sw::CSI),
382 Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
383 };
384
385 // Check limits.
386 #[cfg(stm32h5)]
387 let (hclk_max, pclk_max) = match config.voltage_scale {
388 VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)),
389 VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)),
390 VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
391 VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
392 };
393 #[cfg(stm32h7)]
394 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
395 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
396 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
397 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
398 VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)),
399 };
400
401 #[cfg(stm32h7)]
402 let hclk = {
403 let d1cpre_clk = sys / config.d1c_pre;
404 assert!(d1cpre_clk <= d1cpre_clk_max);
405 sys / config.ahb_pre
406 };
407 #[cfg(stm32h5)]
408 let hclk = sys / config.ahb_pre;
409 assert!(hclk <= hclk_max);
410
411 let apb1 = hclk / config.apb1_pre;
412 let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
413 assert!(apb1 <= pclk_max);
414 let apb2 = hclk / config.apb2_pre;
415 let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
416 assert!(apb2 <= pclk_max);
417 let apb3 = hclk / config.apb3_pre;
418 assert!(apb3 <= pclk_max);
419 #[cfg(stm32h7)]
420 let apb4 = hclk / config.apb4_pre;
421 #[cfg(stm32h7)]
422 assert!(apb4 <= pclk_max);
423
424 let _per_ck = match config.per_clock_source {
425 Ckpersel::HSI => hsi,
426 Ckpersel::CSI => csi,
427 Ckpersel::HSE => hse,
428 _ => unreachable!(),
429 };
430
431 #[cfg(stm32h7)]
432 let adc = match config.adc_clock_source {
433 AdcClockSource::PLL2_P => pll2.p,
434 AdcClockSource::PLL3_R => _pll3.r,
435 AdcClockSource::PER => _per_ck,
436 _ => unreachable!(),
437 };
438 #[cfg(stm32h5)]
439 let adc = match config.adc_clock_source {
440 AdcClockSource::HCLK => Some(hclk),
441 AdcClockSource::SYSCLK => Some(sys),
442 AdcClockSource::PLL2_R => pll2.r,
443 AdcClockSource::HSE => hse,
444 AdcClockSource::HSI_KER => hsi,
445 AdcClockSource::CSI_KER => csi,
446 _ => unreachable!(),
447 };
448
449 flash_setup(hclk, config.voltage_scale);
450
451 #[cfg(stm32h7)]
452 {
453 RCC.d1cfgr().modify(|w| {
454 w.set_d1cpre(config.d1c_pre);
455 w.set_d1ppre(config.apb3_pre);
456 w.set_hpre(config.ahb_pre);
457 });
458 // Ensure core prescaler value is valid before future lower core voltage
459 while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {}
460
461 RCC.d2cfgr().modify(|w| {
462 w.set_d2ppre1(config.apb1_pre);
463 w.set_d2ppre2(config.apb2_pre);
464 });
465 RCC.d3cfgr().modify(|w| {
466 w.set_d3ppre(config.apb4_pre);
467 });
468
469 RCC.d1ccipr().modify(|w| {
470 w.set_ckpersel(config.per_clock_source);
471 });
472 RCC.d3ccipr().modify(|w| {
473 w.set_adcsel(config.adc_clock_source);
474 });
475 }
476 #[cfg(stm32h5)]
477 {
478 // Set hpre
479 RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre));
480 while RCC.cfgr2().read().hpre() != config.ahb_pre {}
481
482 // set ppre
483 RCC.cfgr2().modify(|w| {
484 w.set_ppre1(config.apb1_pre);
485 w.set_ppre2(config.apb2_pre);
486 w.set_ppre3(config.apb3_pre);
487 });
488
489 RCC.ccipr5().modify(|w| {
490 w.set_ckpersel(config.per_clock_source);
491 w.set_adcdacsel(config.adc_clock_source)
492 });
493 }
494
495 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
496
497 RCC.cfgr().modify(|w| w.set_sw(sw));
498 while RCC.cfgr().read().sws() != sw {}
499
500 // IO compensation cell - Requires CSI clock and SYSCFG
501 #[cfg(stm32h7)] // TODO h5
502 if csi.is_some() {
503 // Enable the compensation cell, using back-bias voltage code
504 // provide by the cell.
505 critical_section::with(|_| {
506 pac::SYSCFG.cccsr().modify(|w| {
507 w.set_en(true);
508 w.set_cs(false);
509 w.set_hslv(false);
510 })
511 });
512 while !pac::SYSCFG.cccsr().read().ready() {}
513 }
514
515 set_freqs(Clocks {
516 sys,
517 ahb1: hclk,
518 ahb2: hclk,
519 ahb3: hclk,
520 ahb4: hclk,
521 apb1,
522 apb2,
523 apb3,
524 #[cfg(stm32h7)]
525 apb4,
526 apb1_tim,
527 apb2_tim,
528 adc: adc,
529 });
530}
531
532struct PllInput {
533 hsi: Option<Hertz>,
534 hse: Option<Hertz>,
535 csi: Option<Hertz>,
536 #[cfg(stm32h7)]
537 source: PllSource,
538}
539
540struct PllOutput {
541 p: Option<Hertz>,
542 #[allow(dead_code)]
543 q: Option<Hertz>,
544 #[allow(dead_code)]
545 r: Option<Hertz>,
546}
547
548fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
549 let Some(config) = config else {
550 // Stop PLL
551 RCC.cr().modify(|w| w.set_pllon(num, false));
552 while RCC.cr().read().pllrdy(num) {}
553
554 // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
555 #[cfg(stm32h7)]
556 RCC.pllckselr().write(|w| w.set_divm(num, 0));
557 #[cfg(stm32h5)]
558 RCC.pllcfgr(num).write(|w| w.set_divm(0));
559
560 return PllOutput {
561 p: None,
562 q: None,
563 r: None,
564 };
565 };
566
567 assert!(1 <= config.prediv && config.prediv <= 63);
568 assert!(4 <= config.mul && config.mul <= 512);
569
570 #[cfg(stm32h5)]
571 let source = config.source;
572 #[cfg(stm32h7)]
573 let source = input.source;
574
575 let (in_clk, src) = match source {
576 PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
577 PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
578 PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
579 };
580
581 let ref_clk = in_clk / config.prediv as u32;
582
583 let ref_range = match ref_clk.0 {
584 ..=1_999_999 => Pllrge::RANGE1,
585 ..=3_999_999 => Pllrge::RANGE2,
586 ..=7_999_999 => Pllrge::RANGE4,
587 ..=16_000_000 => Pllrge::RANGE8,
588 x => panic!("pll ref_clk out of range: {} mhz", x),
589 };
590
591 // The smaller range (150 to 420 MHz) must
592 // be chosen when the reference clock frequency is lower than 2 MHz.
593 let wide_allowed = ref_range != Pllrge::RANGE1;
594
595 let vco_clk = ref_clk * config.mul;
596 let vco_range = if VCO_RANGE.contains(&vco_clk.0) {
597 Pllvcosel::MEDIUMVCO
598 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) {
599 Pllvcosel::WIDEVCO
600 } else {
601 panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
602 };
603
604 let p = config.divp.map(|div| {
605 assert!(1 <= div && div <= 128);
606 if num == 0 {
607 // on PLL1, DIVP must be even.
608 assert!(div % 2 == 0);
609 }
610
611 vco_clk / div
612 });
613 let q = config.divq.map(|div| {
614 assert!(1 <= div && div <= 128);
615 vco_clk / div
616 });
617 let r = config.divr.map(|div| {
618 assert!(1 <= div && div <= 128);
619 vco_clk / div
620 });
621
622 #[cfg(stm32h5)]
623 RCC.pllcfgr(num).write(|w| {
624 w.set_pllsrc(src);
625 w.set_divm(config.prediv);
626 w.set_pllvcosel(vco_range);
627 w.set_pllrge(ref_range);
628 w.set_pllfracen(false);
629 w.set_pllpen(p.is_some());
630 w.set_pllqen(q.is_some());
631 w.set_pllren(r.is_some());
632 });
633
634 #[cfg(stm32h7)]
635 {
636 RCC.pllckselr().modify(|w| {
637 w.set_divm(num, config.prediv);
638 w.set_pllsrc(src);
639 });
640 RCC.pllcfgr().modify(|w| {
641 w.set_pllvcosel(num, vco_range);
642 w.set_pllrge(num, ref_range);
643 w.set_pllfracen(num, false);
644 w.set_divpen(num, p.is_some());
645 w.set_divqen(num, q.is_some());
646 w.set_divren(num, r.is_some());
647 });
648 }
649
650 RCC.plldivr(num).write(|w| {
651 w.set_plln(config.mul - 1);
652 w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
653 w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
654 w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
655 });
656
657 RCC.cr().modify(|w| w.set_pllon(num, true));
658 while !RCC.cr().read().pllrdy(num) {}
659
660 PllOutput { p, q, r }
661}
662
663fn flash_setup(clk: Hertz, vos: VoltageScale) {
664 // RM0481 Rev 1, table 37
665 // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
666 // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
667 // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
668 // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
669 // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
670 // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
671 // 5 2 170 to 200 MHz 210 to 250 MHz
672 #[cfg(stm32h5)]
673 let (latency, wrhighfreq) = match (vos, clk.0) {
674 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
675 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
676 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
677 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
678 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
679 (VoltageScale::Scale0, ..=250_000_000) => (5, 2),
680
681 (VoltageScale::Scale1, ..=34_000_000) => (0, 0),
682 (VoltageScale::Scale1, ..=68_000_000) => (1, 0),
683 (VoltageScale::Scale1, ..=102_000_000) => (2, 1),
684 (VoltageScale::Scale1, ..=136_000_000) => (3, 1),
685 (VoltageScale::Scale1, ..=170_000_000) => (4, 2),
686 (VoltageScale::Scale1, ..=200_000_000) => (5, 2),
687
688 (VoltageScale::Scale2, ..=30_000_000) => (0, 0),
689 (VoltageScale::Scale2, ..=60_000_000) => (1, 0),
690 (VoltageScale::Scale2, ..=90_000_000) => (2, 1),
691 (VoltageScale::Scale2, ..=120_000_000) => (3, 1),
692 (VoltageScale::Scale2, ..=150_000_000) => (4, 2),
693
694 (VoltageScale::Scale3, ..=20_000_000) => (0, 0),
695 (VoltageScale::Scale3, ..=40_000_000) => (1, 0),
696 (VoltageScale::Scale3, ..=60_000_000) => (2, 1),
697 (VoltageScale::Scale3, ..=80_000_000) => (3, 1),
698 (VoltageScale::Scale3, ..=100_000_000) => (4, 2),
699
700 _ => unreachable!(),
701 };
702
703 #[cfg(flash_h7)]
704 let (latency, wrhighfreq) = match (vos, clk.0) {
705 // VOS 0 range VCORE 1.26V - 1.40V
706 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
707 (VoltageScale::Scale0, ..=140_000_000) => (1, 1),
708 (VoltageScale::Scale0, ..=185_000_000) => (2, 1),
709 (VoltageScale::Scale0, ..=210_000_000) => (2, 2),
710 (VoltageScale::Scale0, ..=225_000_000) => (3, 2),
711 (VoltageScale::Scale0, ..=240_000_000) => (4, 2),
712 // VOS 1 range VCORE 1.15V - 1.26V
713 (VoltageScale::Scale1, ..=70_000_000) => (0, 0),
714 (VoltageScale::Scale1, ..=140_000_000) => (1, 1),
715 (VoltageScale::Scale1, ..=185_000_000) => (2, 1),
716 (VoltageScale::Scale1, ..=210_000_000) => (2, 2),
717 (VoltageScale::Scale1, ..=225_000_000) => (3, 2),
718 // VOS 2 range VCORE 1.05V - 1.15V
719 (VoltageScale::Scale2, ..=55_000_000) => (0, 0),
720 (VoltageScale::Scale2, ..=110_000_000) => (1, 1),
721 (VoltageScale::Scale2, ..=165_000_000) => (2, 1),
722 (VoltageScale::Scale2, ..=224_000_000) => (3, 2),
723 // VOS 3 range VCORE 0.95V - 1.05V
724 (VoltageScale::Scale3, ..=45_000_000) => (0, 0),
725 (VoltageScale::Scale3, ..=90_000_000) => (1, 1),
726 (VoltageScale::Scale3, ..=135_000_000) => (2, 1),
727 (VoltageScale::Scale3, ..=180_000_000) => (3, 2),
728 (VoltageScale::Scale3, ..=224_000_000) => (4, 2),
729 _ => unreachable!(),
730 };
731
732 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
733 // states and programming delay
734 #[cfg(flash_h7ab)]
735 let (latency, wrhighfreq) = match (vos, clk.0) {
736 // VOS 0 range VCORE 1.25V - 1.35V
737 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
738 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
739 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
740 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
741 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
742 (VoltageScale::Scale0, ..=252_000_000) => (5, 2),
743 (VoltageScale::Scale0, ..=280_000_000) => (6, 3),
744 // VOS 1 range VCORE 1.15V - 1.25V
745 (VoltageScale::Scale1, ..=38_000_000) => (0, 0),
746 (VoltageScale::Scale1, ..=76_000_000) => (1, 0),
747 (VoltageScale::Scale1, ..=114_000_000) => (2, 1),
748 (VoltageScale::Scale1, ..=152_000_000) => (3, 1),
749 (VoltageScale::Scale1, ..=190_000_000) => (4, 2),
750 (VoltageScale::Scale1, ..=225_000_000) => (5, 2),
751 // VOS 2 range VCORE 1.05V - 1.15V
752 (VoltageScale::Scale2, ..=34) => (0, 0),
753 (VoltageScale::Scale2, ..=68) => (1, 0),
754 (VoltageScale::Scale2, ..=102) => (2, 1),
755 (VoltageScale::Scale2, ..=136) => (3, 1),
756 (VoltageScale::Scale2, ..=160) => (4, 2),
757 // VOS 3 range VCORE 0.95V - 1.05V
758 (VoltageScale::Scale3, ..=22) => (0, 0),
759 (VoltageScale::Scale3, ..=44) => (1, 0),
760 (VoltageScale::Scale3, ..=66) => (2, 1),
761 (VoltageScale::Scale3, ..=88) => (3, 1),
762 _ => unreachable!(),
763 };
764
765 debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
766
767 FLASH.acr().write(|w| {
768 w.set_wrhighfreq(wrhighfreq);
769 w.set_latency(latency);
770 });
771 while FLASH.acr().read().latency() != latency {}
772}
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
deleted file mode 100644
index 2e72b1931..000000000
--- a/embassy-stm32/src/rcc/h5.rs
+++ /dev/null
@@ -1,511 +0,0 @@
1use core::marker::PhantomData;
2
3use stm32_metapac::rcc::vals::Timpre;
4
5use crate::pac::pwr::vals::Vos;
6use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
7use crate::pac::{FLASH, PWR, RCC};
8use crate::rcc::{set_freqs, Clocks};
9use crate::time::Hertz;
10use crate::{peripherals, Peripheral};
11
12/// HSI speed
13pub const HSI_FREQ: Hertz = Hertz(64_000_000);
14
15/// CSI speed
16pub const CSI_FREQ: Hertz = Hertz(4_000_000);
17
18/// HSI48 speed
19pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
20
21/// LSI speed
22pub const LSI_FREQ: Hertz = Hertz(32_000);
23
24const VCO_MIN: u32 = 150_000_000;
25const VCO_MAX: u32 = 420_000_000;
26const VCO_WIDE_MIN: u32 = 128_000_000;
27const VCO_WIDE_MAX: u32 = 560_000_000;
28
29pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
30
31pub enum HseMode {
32 /// crystal/ceramic oscillator (HSEBYP=0)
33 Oscillator,
34 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
35 BypassAnalog,
36 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
37 BypassDigital,
38}
39
40pub struct Hse {
41 /// HSE frequency.
42 pub freq: Hertz,
43 /// HSE mode.
44 pub mode: HseMode,
45}
46
47pub enum Hsi {
48 /// 64Mhz
49 Mhz64,
50 /// 32Mhz (divided by 2)
51 Mhz32,
52 /// 16Mhz (divided by 4)
53 Mhz16,
54 /// 8Mhz (divided by 8)
55 Mhz8,
56}
57
58pub enum Sysclk {
59 /// HSI selected as sysclk
60 HSI,
61 /// HSE selected as sysclk
62 HSE,
63 /// CSI selected as sysclk
64 CSI,
65 /// PLL1_P selected as sysclk
66 Pll1P,
67}
68
69pub enum PllSource {
70 Hsi,
71 Csi,
72 Hse,
73}
74
75pub struct Pll {
76 /// Source clock selection.
77 pub source: PllSource,
78
79 /// PLL pre-divider (DIVM). Must be between 1 and 63.
80 pub prediv: u8,
81
82 /// PLL multiplication factor. Must be between 4 and 512.
83 pub mul: u16,
84
85 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
86 /// On PLL1, it must be even (in particular, it cannot be 1.)
87 pub divp: Option<u16>,
88 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
89 pub divq: Option<u16>,
90 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
91 pub divr: Option<u16>,
92}
93
94impl APBPrescaler {
95 fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz {
96 match (tim, self) {
97 // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
98 // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2
99 (TimerPrescaler::DefaultX2, Self::NotDivided) => clk,
100 (TimerPrescaler::DefaultX2, Self::Div2) => clk,
101 (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32,
102 (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32,
103 (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32,
104 // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2
105 // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2
106 // this makes NO SENSE and is different than in the H7. Mistake in the RM??
107 (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32,
108 (TimerPrescaler::DefaultX4, Self::Div2) => clk,
109 (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32,
110 (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32,
111 (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32,
112 }
113 }
114}
115
116/// APB prescaler
117#[derive(Clone, Copy)]
118pub enum TimerPrescaler {
119 DefaultX2,
120 DefaultX4,
121}
122
123impl From<TimerPrescaler> for Timpre {
124 fn from(value: TimerPrescaler) -> Self {
125 match value {
126 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
127 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
128 }
129 }
130}
131
132/// Configuration of the core clocks
133#[non_exhaustive]
134pub struct Config {
135 pub hsi: Option<Hsi>,
136 pub hse: Option<Hse>,
137 pub csi: bool,
138 pub hsi48: bool,
139 pub sys: Sysclk,
140
141 pub pll1: Option<Pll>,
142 pub pll2: Option<Pll>,
143 #[cfg(rcc_h5)]
144 pub pll3: Option<Pll>,
145
146 pub ahb_pre: AHBPrescaler,
147 pub apb1_pre: APBPrescaler,
148 pub apb2_pre: APBPrescaler,
149 pub apb3_pre: APBPrescaler,
150 pub timer_prescaler: TimerPrescaler,
151
152 pub voltage_scale: VoltageScale,
153}
154
155impl Default for Config {
156 fn default() -> Self {
157 Self {
158 hsi: Some(Hsi::Mhz64),
159 hse: None,
160 csi: false,
161 hsi48: false,
162 sys: Sysclk::HSI,
163 pll1: None,
164 pll2: None,
165 #[cfg(rcc_h5)]
166 pll3: None,
167
168 ahb_pre: AHBPrescaler::NotDivided,
169 apb1_pre: APBPrescaler::NotDivided,
170 apb2_pre: APBPrescaler::NotDivided,
171 apb3_pre: APBPrescaler::NotDivided,
172 timer_prescaler: TimerPrescaler::DefaultX2,
173
174 voltage_scale: VoltageScale::Scale3,
175 }
176 }
177}
178
179pub(crate) mod sealed {
180 pub trait McoInstance {
181 type Source;
182 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
183 }
184}
185
186pub trait McoInstance: sealed::McoInstance + 'static {}
187
188pin_trait!(McoPin, McoInstance);
189
190macro_rules! impl_peri {
191 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
192 impl sealed::McoInstance for peripherals::$peri {
193 type Source = $source;
194
195 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
196 RCC.cfgr().modify(|w| {
197 w.$set_source(source);
198 w.$set_prescaler(prescaler);
199 });
200 }
201 }
202
203 impl McoInstance for peripherals::$peri {}
204 };
205}
206
207impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
208impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
209
210pub struct Mco<'d, T: McoInstance> {
211 phantom: PhantomData<&'d mut T>,
212}
213
214impl<'d, T: McoInstance> Mco<'d, T> {
215 pub fn new(
216 _peri: impl Peripheral<P = T> + 'd,
217 _pin: impl Peripheral<P = impl McoPin<T>> + 'd,
218 _source: T::Source,
219 ) -> Self {
220 todo!();
221 }
222}
223
224pub(crate) unsafe fn init(config: Config) {
225 let (vos, max_clk) = match config.voltage_scale {
226 VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)),
227 VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)),
228 VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)),
229 VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)),
230 };
231
232 // Configure voltage scale.
233 PWR.voscr().modify(|w| w.set_vos(vos));
234 while !PWR.vossr().read().vosrdy() {}
235
236 // Configure HSI
237 let hsi = match config.hsi {
238 None => {
239 RCC.cr().modify(|w| w.set_hsion(false));
240 None
241 }
242 Some(hsi) => {
243 let (freq, hsidiv) = match hsi {
244 Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
245 Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
246 Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
247 Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
248 };
249 RCC.cr().modify(|w| {
250 w.set_hsidiv(hsidiv);
251 w.set_hsion(true);
252 });
253 while !RCC.cr().read().hsirdy() {}
254 Some(freq)
255 }
256 };
257
258 // Configure HSE
259 let hse = match config.hse {
260 None => {
261 RCC.cr().modify(|w| w.set_hseon(false));
262 None
263 }
264 Some(hse) => {
265 let (byp, ext) = match hse.mode {
266 HseMode::Oscillator => (false, Hseext::ANALOG),
267 HseMode::BypassAnalog => (true, Hseext::ANALOG),
268 HseMode::BypassDigital => (true, Hseext::DIGITAL),
269 };
270
271 RCC.cr().modify(|w| {
272 w.set_hsebyp(byp);
273 w.set_hseext(ext);
274 });
275 RCC.cr().modify(|w| w.set_hseon(true));
276 while !RCC.cr().read().hserdy() {}
277 Some(hse.freq)
278 }
279 };
280
281 // Configure HSI48.
282 RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
283 let _hsi48 = match config.hsi48 {
284 false => None,
285 true => {
286 while !RCC.cr().read().hsi48rdy() {}
287 Some(CSI_FREQ)
288 }
289 };
290
291 // Configure CSI.
292 RCC.cr().modify(|w| w.set_csion(config.csi));
293 let csi = match config.csi {
294 false => None,
295 true => {
296 while !RCC.cr().read().csirdy() {}
297 Some(CSI_FREQ)
298 }
299 };
300
301 // Configure PLLs.
302 let pll_input = PllInput { csi, hse, hsi };
303 let pll1 = init_pll(0, config.pll1, &pll_input);
304 let _pll2 = init_pll(1, config.pll2, &pll_input);
305 #[cfg(rcc_h5)]
306 let _pll3 = init_pll(2, config.pll3, &pll_input);
307
308 // Configure sysclk
309 let (sys, sw) = match config.sys {
310 Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
311 Sysclk::HSE => (unwrap!(hse), Sw::HSE),
312 Sysclk::CSI => (unwrap!(csi), Sw::CSI),
313 Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
314 };
315 assert!(sys <= max_clk);
316
317 let hclk = sys / config.ahb_pre;
318
319 let apb1 = hclk / config.apb1_pre;
320 let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler);
321 let apb2 = hclk / config.apb2_pre;
322 let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler);
323 let apb3 = hclk / config.apb3_pre;
324
325 flash_setup(hclk, config.voltage_scale);
326
327 // Set hpre
328 let hpre = config.ahb_pre.into();
329 RCC.cfgr2().modify(|w| w.set_hpre(hpre));
330 while RCC.cfgr2().read().hpre() != hpre {}
331
332 // set ppre
333 RCC.cfgr2().modify(|w| {
334 w.set_ppre1(config.apb1_pre.into());
335 w.set_ppre2(config.apb2_pre.into());
336 w.set_ppre3(config.apb3_pre.into());
337 });
338
339 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
340
341 RCC.cfgr().modify(|w| w.set_sw(sw));
342 while RCC.cfgr().read().sws() != sw {}
343
344 set_freqs(Clocks {
345 sys,
346 ahb1: hclk,
347 ahb2: hclk,
348 ahb3: hclk,
349 ahb4: hclk,
350 apb1,
351 apb2,
352 apb3,
353 apb1_tim,
354 apb2_tim,
355 adc: None,
356 });
357}
358
359struct PllInput {
360 hsi: Option<Hertz>,
361 hse: Option<Hertz>,
362 csi: Option<Hertz>,
363}
364
365struct PllOutput {
366 p: Option<Hertz>,
367 #[allow(dead_code)]
368 q: Option<Hertz>,
369 #[allow(dead_code)]
370 r: Option<Hertz>,
371}
372
373fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
374 let Some(config) = config else {
375 // Stop PLL
376 RCC.cr().modify(|w| w.set_pllon(num, false));
377 while RCC.cr().read().pllrdy(num) {}
378
379 // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
380 RCC.pllcfgr(num).write(|w| {
381 w.set_divm(0);
382 });
383
384 return PllOutput {
385 p: None,
386 q: None,
387 r: None,
388 };
389 };
390
391 assert!(1 <= config.prediv && config.prediv <= 63);
392 assert!(4 <= config.mul && config.mul <= 512);
393
394 let (in_clk, src) = match config.source {
395 PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
396 PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
397 PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
398 };
399
400 let ref_clk = in_clk / config.prediv as u32;
401
402 let ref_range = match ref_clk.0 {
403 ..=1_999_999 => Pllrge::RANGE1,
404 ..=3_999_999 => Pllrge::RANGE2,
405 ..=7_999_999 => Pllrge::RANGE4,
406 ..=16_000_000 => Pllrge::RANGE8,
407 x => panic!("pll ref_clk out of range: {} mhz", x),
408 };
409
410 // The smaller range (150 to 420 MHz) must
411 // be chosen when the reference clock frequency is lower than 2 MHz.
412 let wide_allowed = ref_range != Pllrge::RANGE1;
413
414 let vco_clk = ref_clk * config.mul;
415 let vco_range = match vco_clk.0 {
416 VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO,
417 VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO,
418 x => panic!("pll vco_clk out of range: {} mhz", x),
419 };
420
421 let p = config.divp.map(|div| {
422 assert!(1 <= div && div <= 128);
423 if num == 0 {
424 // on PLL1, DIVP must be even.
425 assert!(div % 2 == 0);
426 }
427
428 vco_clk / div
429 });
430 let q = config.divq.map(|div| {
431 assert!(1 <= div && div <= 128);
432 vco_clk / div
433 });
434 let r = config.divr.map(|div| {
435 assert!(1 <= div && div <= 128);
436 vco_clk / div
437 });
438
439 RCC.pllcfgr(num).write(|w| {
440 w.set_pllsrc(src);
441 w.set_divm(config.prediv);
442 w.set_pllvcosel(vco_range);
443 w.set_pllrge(ref_range);
444 w.set_pllfracen(false);
445 w.set_pllpen(p.is_some());
446 w.set_pllqen(q.is_some());
447 w.set_pllren(r.is_some());
448 });
449 RCC.plldivr(num).write(|w| {
450 w.set_plln(config.mul - 1);
451 w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
452 w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
453 w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
454 });
455
456 RCC.cr().modify(|w| w.set_pllon(num, true));
457 while !RCC.cr().read().pllrdy(num) {}
458
459 PllOutput { p, q, r }
460}
461
462fn flash_setup(clk: Hertz, vos: VoltageScale) {
463 // RM0481 Rev 1, table 37
464 // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
465 // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
466 // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
467 // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
468 // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
469 // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
470 // 5 2 170 to 200 MHz 210 to 250 MHz
471
472 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
473 // states and programming delay
474 let (latency, wrhighfreq) = match (vos, clk.0) {
475 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
476 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
477 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
478 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
479 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
480 (VoltageScale::Scale0, ..=250_000_000) => (5, 2),
481
482 (VoltageScale::Scale1, ..=34_000_000) => (0, 0),
483 (VoltageScale::Scale1, ..=68_000_000) => (1, 0),
484 (VoltageScale::Scale1, ..=102_000_000) => (2, 1),
485 (VoltageScale::Scale1, ..=136_000_000) => (3, 1),
486 (VoltageScale::Scale1, ..=170_000_000) => (4, 2),
487 (VoltageScale::Scale1, ..=200_000_000) => (5, 2),
488
489 (VoltageScale::Scale2, ..=30_000_000) => (0, 0),
490 (VoltageScale::Scale2, ..=60_000_000) => (1, 0),
491 (VoltageScale::Scale2, ..=90_000_000) => (2, 1),
492 (VoltageScale::Scale2, ..=120_000_000) => (3, 1),
493 (VoltageScale::Scale2, ..=150_000_000) => (4, 2),
494
495 (VoltageScale::Scale3, ..=20_000_000) => (0, 0),
496 (VoltageScale::Scale3, ..=40_000_000) => (1, 0),
497 (VoltageScale::Scale3, ..=60_000_000) => (2, 1),
498 (VoltageScale::Scale3, ..=80_000_000) => (3, 1),
499 (VoltageScale::Scale3, ..=100_000_000) => (4, 2),
500
501 _ => unreachable!(),
502 };
503
504 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
505
506 FLASH.acr().write(|w| {
507 w.set_wrhighfreq(wrhighfreq);
508 w.set_latency(latency);
509 });
510 while FLASH.acr().read().latency() != latency {}
511}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
deleted file mode 100644
index 7fb4fb95b..000000000
--- a/embassy-stm32/src/rcc/h7.rs
+++ /dev/null
@@ -1,879 +0,0 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::into_ref;
4pub use pll::PllConfig;
5use stm32_metapac::rcc::vals::{Mco1, Mco2};
6
7use crate::gpio::sealed::AFType;
8use crate::gpio::Speed;
9use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre};
10use crate::pac::{PWR, RCC, SYSCFG};
11use crate::rcc::{set_freqs, Clocks};
12use crate::time::Hertz;
13use crate::{peripherals, Peripheral};
14
15/// HSI speed
16pub const HSI_FREQ: Hertz = Hertz(64_000_000);
17
18/// CSI speed
19pub const CSI_FREQ: Hertz = Hertz(4_000_000);
20
21/// HSI48 speed
22pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
23
24/// LSI speed
25pub const LSI_FREQ: Hertz = Hertz(32_000);
26
27pub use super::common::VoltageScale;
28
29#[derive(Clone, Copy)]
30pub enum AdcClockSource {
31 Pll2PCk,
32 Pll3RCk,
33 PerCk,
34}
35
36impl AdcClockSource {
37 pub fn adcsel(&self) -> Adcsel {
38 match self {
39 AdcClockSource::Pll2PCk => Adcsel::PLL2_P,
40 AdcClockSource::Pll3RCk => Adcsel::PLL3_R,
41 AdcClockSource::PerCk => Adcsel::PER,
42 }
43 }
44}
45
46impl Default for AdcClockSource {
47 fn default() -> Self {
48 Self::Pll2PCk
49 }
50}
51
52/// Core clock frequencies
53#[derive(Clone, Copy)]
54pub struct CoreClocks {
55 pub hclk: Hertz,
56 pub pclk1: Hertz,
57 pub pclk2: Hertz,
58 pub pclk3: Hertz,
59 pub pclk4: Hertz,
60 pub ppre1: u8,
61 pub ppre2: u8,
62 pub ppre3: u8,
63 pub ppre4: u8,
64 pub csi_ck: Option<Hertz>,
65 pub hsi_ck: Option<Hertz>,
66 pub hsi48_ck: Option<Hertz>,
67 pub lsi_ck: Option<Hertz>,
68 pub per_ck: Option<Hertz>,
69 pub hse_ck: Option<Hertz>,
70 pub pll1_p_ck: Option<Hertz>,
71 pub pll1_q_ck: Option<Hertz>,
72 pub pll1_r_ck: Option<Hertz>,
73 pub pll2_p_ck: Option<Hertz>,
74 pub pll2_q_ck: Option<Hertz>,
75 pub pll2_r_ck: Option<Hertz>,
76 pub pll3_p_ck: Option<Hertz>,
77 pub pll3_q_ck: Option<Hertz>,
78 pub pll3_r_ck: Option<Hertz>,
79 pub timx_ker_ck: Option<Hertz>,
80 pub timy_ker_ck: Option<Hertz>,
81 pub adc_ker_ck: Option<Hertz>,
82 pub sys_ck: Hertz,
83 pub c_ck: Hertz,
84}
85
86/// Configuration of the core clocks
87#[non_exhaustive]
88#[derive(Default)]
89pub struct Config {
90 pub hse: Option<Hertz>,
91 pub bypass_hse: bool,
92 pub sys_ck: Option<Hertz>,
93 pub per_ck: Option<Hertz>,
94 pub hclk: Option<Hertz>,
95 pub pclk1: Option<Hertz>,
96 pub pclk2: Option<Hertz>,
97 pub pclk3: Option<Hertz>,
98 pub pclk4: Option<Hertz>,
99 pub pll1: PllConfig,
100 pub pll2: PllConfig,
101 pub pll3: PllConfig,
102 pub adc_clock_source: AdcClockSource,
103}
104
105/// Setup traceclk
106/// Returns a pll1_r_ck
107fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
108 let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
109 // pll1_p_ck selected as system clock but pll1_r_ck not
110 // set. The traceclk mux is synchronous with the system
111 // clock mux, but has pll1_r_ck as an input. In order to
112 // keep traceclk running, we force a pll1_r_ck.
113 (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
114
115 // Either pll1 not selected as system clock, free choice
116 // of pll1_r_ck. Or pll1 is selected, assume user has set
117 // a suitable pll1_r_ck frequency.
118 _ => config.pll1.r_ck,
119 };
120 config.pll1.r_ck = pll1_r_ck;
121}
122
123/// Divider calculator for pclk 1 - 4
124///
125/// Returns real pclk, bits, ppre and the timer kernel clock
126fn ppre_calculate(
127 requested_pclk: u32,
128 hclk: u32,
129 max_pclk: u32,
130 tim_pre: Option<Timpre>,
131) -> (u32, u8, u8, Option<u32>) {
132 let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
133 0 => panic!(),
134 1 => (0b000, 1),
135 2 => (0b100, 2),
136 3..=5 => (0b101, 4),
137 6..=11 => (0b110, 8),
138 _ => (0b111, 16),
139 };
140 let real_pclk = hclk / u32::from(ppre);
141 assert!(real_pclk <= max_pclk);
142
143 let tim_ker_clk = if let Some(tim_pre) = tim_pre {
144 let clk = match (bits, tim_pre) {
145 (0b101, Timpre::DEFAULTX2) => hclk / 2,
146 (0b110, Timpre::DEFAULTX4) => hclk / 2,
147 (0b110, Timpre::DEFAULTX2) => hclk / 4,
148 (0b111, Timpre::DEFAULTX4) => hclk / 4,
149 (0b111, Timpre::DEFAULTX2) => hclk / 8,
150 _ => hclk,
151 };
152 Some(clk)
153 } else {
154 None
155 };
156 (real_pclk, bits, ppre, tim_ker_clk)
157}
158
159/// Setup sys_ck
160/// Returns sys_ck frequency, and a pll1_p_ck
161fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
162 // Compare available with wanted clocks
163 let sys_ck = config.sys_ck.unwrap_or(srcclk);
164
165 if sys_ck != srcclk {
166 // The requested system clock is not the immediately available
167 // HSE/HSI clock. Perhaps there are other ways of obtaining
168 // the requested system clock (such as `HSIDIV`) but we will
169 // ignore those for now.
170 //
171 // Therefore we must use pll1_p_ck
172 let pll1_p_ck = match config.pll1.p_ck {
173 Some(p_ck) => {
174 assert!(
175 p_ck == sys_ck,
176 "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"
177 );
178 Some(p_ck)
179 }
180 None => Some(sys_ck),
181 };
182 config.pll1.p_ck = pll1_p_ck;
183
184 (sys_ck, true)
185 } else {
186 // sys_ck is derived directly from a source clock
187 // (HSE/HSI). pll1_p_ck can be as requested
188 (sys_ck, false)
189 }
190}
191
192fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
193 use crate::pac::FLASH;
194
195 // ACLK in MHz, round down and subtract 1 from integers. eg.
196 // 61_999_999 -> 61MHz
197 // 62_000_000 -> 61MHz
198 // 62_000_001 -> 62MHz
199 let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
200
201 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
202 // states and programming delay
203 #[cfg(flash_h7)]
204 let (wait_states, progr_delay) = match vos {
205 // VOS 0 range VCORE 1.26V - 1.40V
206 VoltageScale::Scale0 => match rcc_aclk_mhz {
207 0..=69 => (0, 0),
208 70..=139 => (1, 1),
209 140..=184 => (2, 1),
210 185..=209 => (2, 2),
211 210..=224 => (3, 2),
212 225..=239 => (4, 2),
213 _ => (7, 3),
214 },
215 // VOS 1 range VCORE 1.15V - 1.26V
216 VoltageScale::Scale1 => match rcc_aclk_mhz {
217 0..=69 => (0, 0),
218 70..=139 => (1, 1),
219 140..=184 => (2, 1),
220 185..=209 => (2, 2),
221 210..=224 => (3, 2),
222 _ => (7, 3),
223 },
224 // VOS 2 range VCORE 1.05V - 1.15V
225 VoltageScale::Scale2 => match rcc_aclk_mhz {
226 0..=54 => (0, 0),
227 55..=109 => (1, 1),
228 110..=164 => (2, 1),
229 165..=224 => (3, 2),
230 _ => (7, 3),
231 },
232 // VOS 3 range VCORE 0.95V - 1.05V
233 VoltageScale::Scale3 => match rcc_aclk_mhz {
234 0..=44 => (0, 0),
235 45..=89 => (1, 1),
236 90..=134 => (2, 1),
237 135..=179 => (3, 2),
238 180..=224 => (4, 2),
239 _ => (7, 3),
240 },
241 };
242
243 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
244 // states and programming delay
245 #[cfg(flash_h7ab)]
246 let (wait_states, progr_delay) = match vos {
247 // VOS 0 range VCORE 1.25V - 1.35V
248 VoltageScale::Scale0 => match rcc_aclk_mhz {
249 0..=42 => (0, 0),
250 43..=84 => (1, 0),
251 85..=126 => (2, 1),
252 127..=168 => (3, 1),
253 169..=210 => (4, 2),
254 211..=252 => (5, 2),
255 253..=280 => (6, 3),
256 _ => (7, 3),
257 },
258 // VOS 1 range VCORE 1.15V - 1.25V
259 VoltageScale::Scale1 => match rcc_aclk_mhz {
260 0..=38 => (0, 0),
261 39..=76 => (1, 0),
262 77..=114 => (2, 1),
263 115..=152 => (3, 1),
264 153..=190 => (4, 2),
265 191..=225 => (5, 2),
266 _ => (7, 3),
267 },
268 // VOS 2 range VCORE 1.05V - 1.15V
269 VoltageScale::Scale2 => match rcc_aclk_mhz {
270 0..=34 => (0, 0),
271 35..=68 => (1, 0),
272 69..=102 => (2, 1),
273 103..=136 => (3, 1),
274 137..=160 => (4, 2),
275 _ => (7, 3),
276 },
277 // VOS 3 range VCORE 0.95V - 1.05V
278 VoltageScale::Scale3 => match rcc_aclk_mhz {
279 0..=22 => (0, 0),
280 23..=44 => (1, 0),
281 45..=66 => (2, 1),
282 67..=88 => (3, 1),
283 _ => (7, 3),
284 },
285 };
286
287 FLASH.acr().write(|w| {
288 w.set_wrhighfreq(progr_delay);
289 w.set_latency(wait_states)
290 });
291 while FLASH.acr().read().latency() != wait_states {}
292}
293
294pub enum McoClock {
295 Disabled,
296 Bypassed,
297 Divided(u8),
298}
299
300impl McoClock {
301 fn into_raw(&self) -> u8 {
302 match self {
303 McoClock::Disabled => 0,
304 McoClock::Bypassed => 1,
305 McoClock::Divided(divisor) => {
306 if *divisor > 15 {
307 panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
308 }
309 *divisor
310 }
311 }
312 }
313}
314
315#[derive(Copy, Clone)]
316pub enum Mco1Source {
317 Hsi,
318 Lse,
319 Hse,
320 Pll1Q,
321 Hsi48,
322}
323
324impl Default for Mco1Source {
325 fn default() -> Self {
326 Self::Hsi
327 }
328}
329
330pub trait McoSource {
331 type Raw;
332
333 fn into_raw(&self) -> Self::Raw;
334}
335
336impl McoSource for Mco1Source {
337 type Raw = Mco1;
338 fn into_raw(&self) -> Self::Raw {
339 match self {
340 Mco1Source::Hsi => Mco1::HSI,
341 Mco1Source::Lse => Mco1::LSE,
342 Mco1Source::Hse => Mco1::HSE,
343 Mco1Source::Pll1Q => Mco1::PLL1_Q,
344 Mco1Source::Hsi48 => Mco1::HSI48,
345 }
346 }
347}
348
349#[derive(Copy, Clone)]
350pub enum Mco2Source {
351 SysClk,
352 Pll2Q,
353 Hse,
354 Pll1Q,
355 Csi,
356 Lsi,
357}
358
359impl Default for Mco2Source {
360 fn default() -> Self {
361 Self::SysClk
362 }
363}
364
365impl McoSource for Mco2Source {
366 type Raw = Mco2;
367 fn into_raw(&self) -> Self::Raw {
368 match self {
369 Mco2Source::SysClk => Mco2::SYSCLK,
370 Mco2Source::Pll2Q => Mco2::PLL2_P,
371 Mco2Source::Hse => Mco2::HSE,
372 Mco2Source::Pll1Q => Mco2::PLL1_P,
373 Mco2Source::Csi => Mco2::CSI,
374 Mco2Source::Lsi => Mco2::LSI,
375 }
376 }
377}
378
379pub(crate) mod sealed {
380 pub trait McoInstance {
381 type Source;
382 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
383 }
384}
385
386pub trait McoInstance: sealed::McoInstance + 'static {}
387
388pin_trait!(McoPin, McoInstance);
389
390macro_rules! impl_peri {
391 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
392 impl sealed::McoInstance for peripherals::$peri {
393 type Source = $source;
394
395 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
396 RCC.cfgr().modify(|w| {
397 w.$set_source(source);
398 w.$set_prescaler(prescaler);
399 });
400 }
401 }
402
403 impl McoInstance for peripherals::$peri {}
404 };
405}
406
407impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
408impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
409
410pub struct Mco<'d, T: McoInstance> {
411 phantom: PhantomData<&'d mut T>,
412}
413
414impl<'d, T: McoInstance> Mco<'d, T> {
415 pub fn new(
416 _peri: impl Peripheral<P = T> + 'd,
417 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
418 source: impl McoSource<Raw = T::Source>,
419 prescaler: McoClock,
420 ) -> Self {
421 into_ref!(pin);
422
423 critical_section::with(|_| unsafe {
424 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
425 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
426 pin.set_speed(Speed::VeryHigh);
427 });
428
429 Self { phantom: PhantomData }
430 }
431}
432
433pub(crate) unsafe fn init(mut config: Config) {
434 // TODO make configurable?
435 let enable_overdrive = false;
436
437 // NB. The lower bytes of CR3 can only be written once after
438 // POR, and must be written with a valid combination. Refer to
439 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
440 // `self` at the end of this method, but of course we cannot
441 // know what happened between the previous POR and here.
442 #[cfg(pwr_h7)]
443 PWR.cr3().modify(|w| {
444 w.set_scuen(true);
445 w.set_ldoen(true);
446 w.set_bypass(false);
447 });
448
449 #[cfg(pwr_h7smps)]
450 PWR.cr3().modify(|w| {
451 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
452 // default solderbridge configuration.
453 w.set_sden(true);
454 w.set_ldoen(false);
455 });
456
457 // Validate the supply configuration. If you are stuck here, it is
458 // because the voltages on your board do not match those specified
459 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
460 // VOS = Scale 3, so check that the voltage on the VCAP pins =
461 // 1.0V.
462 while !PWR.csr1().read().actvosrdy() {}
463
464 // Go to Scale 1
465 PWR.d3cr().modify(|w| w.set_vos(0b11));
466 while !PWR.d3cr().read().vosrdy() {}
467
468 let pwr_vos = if !enable_overdrive {
469 VoltageScale::Scale1
470 } else {
471 critical_section::with(|_| {
472 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
473
474 SYSCFG.pwrcr().modify(|w| w.set_oden(1));
475 });
476 while !PWR.d3cr().read().vosrdy() {}
477 VoltageScale::Scale0
478 };
479
480 // Freeze the core clocks, returning a Core Clocks Distribution
481 // and Reset (CCDR) structure. The actual frequency of the clocks
482 // configured is returned in the `clocks` member of the CCDR
483 // structure.
484 //
485 // Note that `freeze` will never result in a clock _faster_ than
486 // that specified. It may result in a clock that is a factor of [1,
487 // 2) slower.
488 //
489 // `syscfg` is required to enable the I/O compensation cell.
490 //
491 // # Panics
492 //
493 // If a clock specification cannot be achieved within the
494 // hardware specification then this function will panic. This
495 // function may also panic if a clock specification can be
496 // achieved, but the mechanism for doing so is not yet
497 // implemented here.
498
499 let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks
500 let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
501
502 // Configure traceclk from PLL if needed
503 traceclk_setup(&mut config, sys_use_pll1_p);
504
505 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
506 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
507 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
508
509 let sys_ck = if sys_use_pll1_p {
510 Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
511 } else {
512 sys_ck
513 };
514
515 // This routine does not support HSIDIV != 1. To
516 // do so it would need to ensure all PLLxON bits are clear
517 // before changing the value of HSIDIV
518 let cr = RCC.cr().read();
519 assert!(cr.hsion());
520 assert!(cr.hsidiv() == Hsidiv::DIV1);
521
522 RCC.csr().modify(|w| w.set_lsion(true));
523 while !RCC.csr().read().lsirdy() {}
524
525 // per_ck from HSI by default
526 let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
527 (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
528 (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI
529 _ => (HSI_FREQ, Ckpersel::HSI), // HSI
530 };
531
532 // D1 Core Prescaler
533 // Set to 1
534 let d1cpre_bits = 0;
535 let d1cpre_div = 1;
536 let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
537
538 // Refer to part datasheet "General operating conditions"
539 // table for (rev V). We do not assert checks for earlier
540 // revisions which may have lower limits.
541 let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
542 VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
543 VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
544 VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
545 _ => (200_000_000, 100_000_000, 50_000_000),
546 };
547 assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
548
549 let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
550 assert!(rcc_hclk <= rcc_hclk_max);
551
552 // Estimate divisor
553 let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
554 0 => panic!(),
555 1 => (Hpre::DIV1, 1),
556 2 => (Hpre::DIV2, 2),
557 3..=5 => (Hpre::DIV4, 4),
558 6..=11 => (Hpre::DIV8, 8),
559 12..=39 => (Hpre::DIV16, 16),
560 40..=95 => (Hpre::DIV64, 64),
561 96..=191 => (Hpre::DIV128, 128),
562 192..=383 => (Hpre::DIV256, 256),
563 _ => (Hpre::DIV512, 512),
564 };
565 // Calculate real AXI and AHB clock
566 let rcc_hclk = sys_d1cpre_ck / hpre_div;
567 assert!(rcc_hclk <= rcc_hclk_max);
568 let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
569 // Timer prescaler selection
570 let timpre = Timpre::DEFAULTX2;
571
572 let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
573 let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
574 ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
575
576 let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
577 let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
578 ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
579
580 let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
581 let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
582
583 let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
584 let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
585
586 // Start switching clocks -------------------
587
588 // Ensure CSI is on and stable
589 RCC.cr().modify(|w| w.set_csion(true));
590 while !RCC.cr().read().csirdy() {}
591
592 // Ensure HSI48 is on and stable
593 RCC.cr().modify(|w| w.set_hsi48on(true));
594 while !RCC.cr().read().hsi48on() {}
595
596 // XXX: support MCO ?
597
598 let hse_ck = match config.hse {
599 Some(hse) => {
600 // Ensure HSE is on and stable
601 RCC.cr().modify(|w| {
602 w.set_hseon(true);
603 w.set_hsebyp(config.bypass_hse);
604 });
605 while !RCC.cr().read().hserdy() {}
606 Some(hse)
607 }
608 None => None,
609 };
610
611 let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI };
612 RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
613
614 let enable_pll = |pll| {
615 RCC.cr().modify(|w| w.set_pllon(pll, true));
616 while !RCC.cr().read().pllrdy(pll) {}
617 };
618
619 if pll1_p_ck.is_some() {
620 enable_pll(0);
621 }
622
623 if pll2_p_ck.is_some() {
624 enable_pll(1);
625 }
626
627 if pll3_p_ck.is_some() {
628 enable_pll(2);
629 }
630
631 // Core Prescaler / AHB Prescaler / APB3 Prescaler
632 RCC.d1cfgr().modify(|w| {
633 w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
634 w.set_d1ppre(Dppre::from_bits(ppre3_bits));
635 w.set_hpre(hpre_bits)
636 });
637 // Ensure core prescaler value is valid before future lower
638 // core voltage
639 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
640
641 flash_setup(rcc_aclk, pwr_vos);
642
643 // APB1 / APB2 Prescaler
644 RCC.d2cfgr().modify(|w| {
645 w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
646 w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
647 });
648
649 // APB4 Prescaler
650 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
651
652 // Peripheral Clock (per_ck)
653 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
654
655 // ADC clock MUX
656 RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
657
658 let adc_ker_ck = match config.adc_clock_source {
659 AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz),
660 AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz),
661 AdcClockSource::PerCk => Some(per_ck),
662 };
663
664 // Set timer clocks prescaler setting
665 RCC.cfgr().modify(|w| w.set_timpre(timpre));
666
667 // Select system clock source
668 let sw = match (sys_use_pll1_p, config.hse.is_some()) {
669 (true, _) => Sw::PLL1,
670 (false, true) => Sw::HSE,
671 _ => Sw::HSI,
672 };
673 RCC.cfgr().modify(|w| w.set_sw(sw));
674 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
675
676 // IO compensation cell - Requires CSI clock and SYSCFG
677 assert!(RCC.cr().read().csirdy());
678 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
679
680 // Enable the compensation cell, using back-bias voltage code
681 // provide by the cell.
682 critical_section::with(|_| {
683 SYSCFG.cccsr().modify(|w| {
684 w.set_en(true);
685 w.set_cs(false);
686 w.set_hslv(false);
687 })
688 });
689 while !SYSCFG.cccsr().read().ready() {}
690
691 let core_clocks = CoreClocks {
692 hclk: Hertz(rcc_hclk),
693 pclk1: Hertz(rcc_pclk1),
694 pclk2: Hertz(rcc_pclk2),
695 pclk3: Hertz(rcc_pclk3),
696 pclk4: Hertz(rcc_pclk4),
697 ppre1,
698 ppre2,
699 ppre3,
700 ppre4,
701 csi_ck: Some(CSI_FREQ),
702 hsi_ck: Some(HSI_FREQ),
703 hsi48_ck: Some(HSI48_FREQ),
704 lsi_ck: Some(LSI_FREQ),
705 per_ck: Some(per_ck),
706 hse_ck,
707 pll1_p_ck: pll1_p_ck.map(Hertz),
708 pll1_q_ck: pll1_q_ck.map(Hertz),
709 pll1_r_ck: pll1_r_ck.map(Hertz),
710 pll2_p_ck: pll2_p_ck.map(Hertz),
711 pll2_q_ck: pll2_q_ck.map(Hertz),
712 pll2_r_ck: pll2_r_ck.map(Hertz),
713 pll3_p_ck: pll3_p_ck.map(Hertz),
714 pll3_q_ck: pll3_q_ck.map(Hertz),
715 pll3_r_ck: pll3_r_ck.map(Hertz),
716 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
717 timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
718 adc_ker_ck,
719 sys_ck,
720 c_ck: Hertz(sys_d1cpre_ck),
721 };
722
723 set_freqs(Clocks {
724 sys: core_clocks.c_ck,
725 ahb1: core_clocks.hclk,
726 ahb2: core_clocks.hclk,
727 ahb3: core_clocks.hclk,
728 ahb4: core_clocks.hclk,
729 apb1: core_clocks.pclk1,
730 apb2: core_clocks.pclk2,
731 apb4: core_clocks.pclk4,
732 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
733 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
734 adc: core_clocks.adc_ker_ck,
735 });
736}
737
738mod pll {
739 use super::{Hertz, RCC};
740
741 const VCO_MIN: u32 = 150_000_000;
742 const VCO_MAX: u32 = 420_000_000;
743
744 #[derive(Default)]
745 pub struct PllConfig {
746 pub p_ck: Option<Hertz>,
747 pub q_ck: Option<Hertz>,
748 pub r_ck: Option<Hertz>,
749 }
750
751 pub(super) struct PllConfigResults {
752 pub ref_x_ck: u32,
753 pub pll_x_m: u32,
754 pub pll_x_p: u32,
755 pub vco_ck_target: u32,
756 }
757
758 fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
759 let pll_x_p = if plln == 0 {
760 if output > VCO_MAX / 2 {
761 1
762 } else {
763 ((VCO_MAX / output) | 1) - 1 // Must be even or unity
764 }
765 } else {
766 // Specific to PLL2/3, will subtract 1 later
767 if output > VCO_MAX / 2 {
768 1
769 } else {
770 VCO_MAX / output
771 }
772 };
773
774 let vco_ck = output * pll_x_p;
775
776 assert!(pll_x_p < 128);
777 assert!(vco_ck >= VCO_MIN);
778 assert!(vco_ck <= VCO_MAX);
779
780 (vco_ck, pll_x_p)
781 }
782
783 /// # Safety
784 ///
785 /// Must have exclusive access to the RCC register block
786 fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
787 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
788
789 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
790
791 // Input divisor, resulting in a reference clock in the range
792 // 1 to 2 MHz. Choose the highest reference clock (lowest m)
793 let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
794 assert!(pll_x_m < 64);
795
796 // Calculate resulting reference clock
797 let ref_x_ck = pll_src / pll_x_m;
798 assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
799
800 RCC.pllcfgr().modify(|w| {
801 w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
802 w.set_pllrge(plln, Pllrge::RANGE1);
803 });
804 PllConfigResults {
805 ref_x_ck,
806 pll_x_m,
807 pll_x_p,
808 vco_ck_target,
809 }
810 }
811
812 /// # Safety
813 ///
814 /// Must have exclusive access to the RCC register block
815 pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
816 use crate::pac::rcc::vals::Divp;
817
818 match config.p_ck {
819 Some(requested_output) => {
820 let config_results = vco_setup(pll_src, requested_output.0, plln);
821 let PllConfigResults {
822 ref_x_ck,
823 pll_x_m,
824 pll_x_p,
825 vco_ck_target,
826 } = config_results;
827
828 RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
829
830 // Feedback divider. Integer only
831 let pll_x_n = vco_ck_target / ref_x_ck;
832 assert!(pll_x_n >= 4);
833 assert!(pll_x_n <= 512);
834 RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16));
835
836 // No FRACN
837 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
838 let vco_ck = ref_x_ck * pll_x_n;
839
840 RCC.plldivr(plln)
841 .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
842 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
843
844 // Calulate additional output dividers
845 let q_ck = match config.q_ck {
846 Some(Hertz(ck)) if ck > 0 => {
847 let div = (vco_ck + ck - 1) / ck;
848 RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
849 RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
850 Some(vco_ck / div)
851 }
852 _ => None,
853 };
854 let r_ck = match config.r_ck {
855 Some(Hertz(ck)) if ck > 0 => {
856 let div = (vco_ck + ck - 1) / ck;
857 RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
858 RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
859 Some(vco_ck / div)
860 }
861 _ => None,
862 };
863
864 (Some(vco_ck / pll_x_p), q_ck, r_ck)
865 }
866 None => {
867 assert!(
868 config.q_ck.is_none(),
869 "Must set PLL P clock for Q clock to take effect!"
870 );
871 assert!(
872 config.r_ck.is_none(),
873 "Must set PLL P clock for R clock to take effect!"
874 );
875 (None, None, None)
876 }
877 }
878 }
879}
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index 46b58ca7c..7358be31b 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,8 +1,11 @@
1pub use super::common::{AHBPrescaler, APBPrescaler}; 1use super::bd::BackupDomain;
2pub use super::bus::{AHBPrescaler, APBPrescaler};
3use super::RtcClockSource;
4pub use crate::pac::pwr::vals::Vos as VoltageScale;
2use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; 5use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
3use crate::pac::RCC;
4#[cfg(crs)] 6#[cfg(crs)]
5use crate::pac::{crs, CRS, SYSCFG}; 7use crate::pac::{crs, CRS, SYSCFG};
8use crate::pac::{FLASH, PWR, RCC};
6use crate::rcc::{set_freqs, Clocks}; 9use crate::rcc::{set_freqs, Clocks};
7use crate::time::Hertz; 10use crate::time::Hertz;
8 11
@@ -135,6 +138,10 @@ pub struct Config {
135 pub apb2_pre: APBPrescaler, 138 pub apb2_pre: APBPrescaler,
136 #[cfg(crs)] 139 #[cfg(crs)]
137 pub enable_hsi48: bool, 140 pub enable_hsi48: bool,
141 pub rtc: Option<RtcClockSource>,
142 pub lse: Option<Hertz>,
143 pub lsi: bool,
144 pub voltage_scale: VoltageScale,
138} 145}
139 146
140impl Default for Config { 147impl Default for Config {
@@ -142,16 +149,25 @@ impl Default for Config {
142 fn default() -> Config { 149 fn default() -> Config {
143 Config { 150 Config {
144 mux: ClockSrc::MSI(MSIRange::default()), 151 mux: ClockSrc::MSI(MSIRange::default()),
145 ahb_pre: AHBPrescaler::NotDivided, 152 ahb_pre: AHBPrescaler::DIV1,
146 apb1_pre: APBPrescaler::NotDivided, 153 apb1_pre: APBPrescaler::DIV1,
147 apb2_pre: APBPrescaler::NotDivided, 154 apb2_pre: APBPrescaler::DIV1,
148 #[cfg(crs)] 155 #[cfg(crs)]
149 enable_hsi48: false, 156 enable_hsi48: false,
157 rtc: None,
158 lse: None,
159 lsi: false,
160 voltage_scale: VoltageScale::RANGE1,
150 } 161 }
151 } 162 }
152} 163}
153 164
154pub(crate) unsafe fn init(config: Config) { 165pub(crate) unsafe fn init(config: Config) {
166 // Set voltage scale
167 while PWR.csr().read().vosf() {}
168 PWR.cr().write(|w| w.set_vos(config.voltage_scale));
169 while PWR.csr().read().vosf() {}
170
155 let (sys_clk, sw) = match config.mux { 171 let (sys_clk, sw) = match config.mux {
156 ClockSrc::MSI(range) => { 172 ClockSrc::MSI(range) => {
157 // Set MSI range 173 // Set MSI range
@@ -231,6 +247,28 @@ pub(crate) unsafe fn init(config: Config) {
231 } 247 }
232 }; 248 };
233 249
250 BackupDomain::configure_ls(
251 config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
252 config.lsi,
253 config.lse.map(|_| Default::default()),
254 );
255
256 let wait_states = match config.voltage_scale {
257 VoltageScale::RANGE1 => match sys_clk {
258 ..=16_000_000 => 0,
259 _ => 1,
260 },
261 VoltageScale::RANGE2 => match sys_clk {
262 ..=8_000_000 => 0,
263 _ => 1,
264 },
265 VoltageScale::RANGE3 => 0,
266 _ => unreachable!(),
267 };
268 FLASH.acr().modify(|w| {
269 w.set_latency(wait_states != 0);
270 });
271
234 RCC.cfgr().modify(|w| { 272 RCC.cfgr().modify(|w| {
235 w.set_sw(sw); 273 w.set_sw(sw);
236 w.set_hpre(config.ahb_pre.into()); 274 w.set_hpre(config.ahb_pre.into());
@@ -239,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) {
239 }); 277 });
240 278
241 let ahb_freq: u32 = match config.ahb_pre { 279 let ahb_freq: u32 = match config.ahb_pre {
242 AHBPrescaler::NotDivided => sys_clk, 280 AHBPrescaler::DIV1 => sys_clk,
243 pre => { 281 pre => {
244 let pre: Hpre = pre.into(); 282 let pre: Hpre = pre.into();
245 let pre = 1 << (pre.to_bits() as u32 - 7); 283 let pre = 1 << (pre.to_bits() as u32 - 7);
@@ -248,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) {
248 }; 286 };
249 287
250 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 288 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
251 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 289 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
252 pre => { 290 pre => {
253 let pre: Ppre = pre.into(); 291 let pre: Ppre = pre.into();
254 let pre: u8 = 1 << (pre.to_bits() - 3); 292 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -258,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) {
258 }; 296 };
259 297
260 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 298 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
261 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 299 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
262 pre => { 300 pre => {
263 let pre: Ppre = pre.into(); 301 let pre: Ppre = pre.into();
264 let pre: u8 = 1 << (pre.to_bits() - 3); 302 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -269,13 +307,6 @@ pub(crate) unsafe fn init(config: Config) {
269 307
270 #[cfg(crs)] 308 #[cfg(crs)]
271 if config.enable_hsi48 { 309 if config.enable_hsi48 {
272 // Reset SYSCFG peripheral
273 RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
274 RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
275
276 // Enable SYSCFG peripheral
277 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
278
279 // Reset CRS peripheral 310 // Reset CRS peripheral
280 RCC.apb1rstr().modify(|w| w.set_crsrst(true)); 311 RCC.apb1rstr().modify(|w| w.set_crsrst(true));
281 RCC.apb1rstr().modify(|w| w.set_crsrst(false)); 312 RCC.apb1rstr().modify(|w| w.set_crsrst(false));
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
index bdfc5b87a..90524fb37 100644
--- a/embassy-stm32/src/rcc/l1.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -1,4 +1,4 @@
1pub use super::common::{AHBPrescaler, APBPrescaler}; 1pub use super::bus::{AHBPrescaler, APBPrescaler};
2use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; 2use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
3use crate::pac::{FLASH, RCC}; 3use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks}; 4use crate::rcc::{set_freqs, Clocks};
@@ -138,9 +138,9 @@ impl Default for Config {
138 fn default() -> Config { 138 fn default() -> Config {
139 Config { 139 Config {
140 mux: ClockSrc::MSI(MSIRange::default()), 140 mux: ClockSrc::MSI(MSIRange::default()),
141 ahb_pre: AHBPrescaler::NotDivided, 141 ahb_pre: AHBPrescaler::DIV1,
142 apb1_pre: APBPrescaler::NotDivided, 142 apb1_pre: APBPrescaler::DIV1,
143 apb2_pre: APBPrescaler::NotDivided, 143 apb2_pre: APBPrescaler::DIV1,
144 } 144 }
145 } 145 }
146} 146}
@@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) {
240 }); 240 });
241 241
242 let ahb_freq: u32 = match config.ahb_pre { 242 let ahb_freq: u32 = match config.ahb_pre {
243 AHBPrescaler::NotDivided => sys_clk, 243 AHBPrescaler::DIV1 => sys_clk,
244 pre => { 244 pre => {
245 let pre: Hpre = pre.into(); 245 let pre: Hpre = pre.into();
246 let pre = 1 << (pre.to_bits() as u32 - 7); 246 let pre = 1 << (pre.to_bits() as u32 - 7);
@@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) {
249 }; 249 };
250 250
251 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 251 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
252 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 252 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
253 pre => { 253 pre => {
254 let pre: Ppre = pre.into(); 254 let pre: Ppre = pre.into();
255 let pre: u8 = 1 << (pre.to_bits() - 3); 255 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) {
259 }; 259 };
260 260
261 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 261 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
262 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 262 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
263 pre => { 263 pre => {
264 let pre: Ppre = pre.into(); 264 let pre: Ppre = pre.into();
265 let pre: u8 = 1 << (pre.to_bits() - 3); 265 let pre: u8 = 1 << (pre.to_bits() - 3);
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index b34b8caab..6f1f7458c 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -2,15 +2,15 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::into_ref; 3use embassy_hal_internal::into_ref;
4use stm32_metapac::rcc::regs::Cfgr; 4use stm32_metapac::rcc::regs::Cfgr;
5use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; 5use stm32_metapac::rcc::vals::{Mcopre, Mcosel};
6 6
7pub use super::common::{AHBPrescaler, APBPrescaler}; 7pub use super::bus::{AHBPrescaler, APBPrescaler};
8use crate::gpio::sealed::AFType; 8use crate::gpio::sealed::AFType;
9use crate::gpio::Speed; 9use crate::gpio::Speed;
10use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; 10use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
11use crate::pac::{FLASH, PWR, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::rcc::bd::{BackupDomain, RtcClockSource};
12use crate::rcc::{set_freqs, Clocks}; 13use crate::rcc::{set_freqs, Clocks};
13use crate::rtc::{Rtc, RtcClockSource as RCS};
14use crate::time::Hertz; 14use crate::time::Hertz;
15use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
16 16
@@ -241,6 +241,8 @@ pub struct Config {
241 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] 241 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
242 pub hsi48: bool, 242 pub hsi48: bool,
243 pub rtc_mux: RtcClockSource, 243 pub rtc_mux: RtcClockSource,
244 pub lse: Option<Hertz>,
245 pub lsi: bool,
244} 246}
245 247
246impl Default for Config { 248impl Default for Config {
@@ -248,22 +250,19 @@ impl Default for Config {
248 fn default() -> Config { 250 fn default() -> Config {
249 Config { 251 Config {
250 mux: ClockSrc::MSI(MSIRange::Range6), 252 mux: ClockSrc::MSI(MSIRange::Range6),
251 ahb_pre: AHBPrescaler::NotDivided, 253 ahb_pre: AHBPrescaler::DIV1,
252 apb1_pre: APBPrescaler::NotDivided, 254 apb1_pre: APBPrescaler::DIV1,
253 apb2_pre: APBPrescaler::NotDivided, 255 apb2_pre: APBPrescaler::DIV1,
254 pllsai1: None, 256 pllsai1: None,
255 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] 257 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
256 hsi48: false, 258 hsi48: false,
257 rtc_mux: RtcClockSource::LSI32, 259 rtc_mux: RtcClockSource::LSI,
260 lsi: true,
261 lse: None,
258 } 262 }
259 } 263 }
260} 264}
261 265
262pub enum RtcClockSource {
263 LSE32,
264 LSI32,
265}
266
267pub enum McoClock { 266pub enum McoClock {
268 DIV1, 267 DIV1,
269 DIV2, 268 DIV2,
@@ -410,37 +409,7 @@ pub(crate) unsafe fn init(config: Config) {
410 while RCC.cfgr().read().sws() != Sw::MSI {} 409 while RCC.cfgr().read().sws() != Sw::MSI {}
411 } 410 }
412 411
413 RCC.apb1enr1().modify(|w| w.set_pwren(true)); 412 BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
414
415 match config.rtc_mux {
416 RtcClockSource::LSE32 => {
417 // 1. Unlock the backup domain
418 PWR.cr1().modify(|w| w.set_dbp(true));
419
420 // 2. Setup the LSE
421 RCC.bdcr().modify(|w| {
422 // Enable LSE
423 w.set_lseon(true);
424 // Max drive strength
425 // TODO: should probably be settable
426 w.set_lsedrv(Lsedrv::HIGH);
427 });
428
429 // Wait until LSE is running
430 while !RCC.bdcr().read().lserdy() {}
431
432 Rtc::set_clock_source(RCS::LSE);
433 }
434 RtcClockSource::LSI32 => {
435 // Turn on the internal 32 kHz LSI oscillator
436 RCC.csr().modify(|w| w.set_lsion(true));
437
438 // Wait until LSI is running
439 while !RCC.csr().read().lsirdy() {}
440
441 Rtc::set_clock_source(RCS::LSI);
442 }
443 }
444 413
445 let (sys_clk, sw) = match config.mux { 414 let (sys_clk, sw) = match config.mux {
446 ClockSrc::MSI(range) => { 415 ClockSrc::MSI(range) => {
@@ -451,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) {
451 w.set_msirgsel(true); 420 w.set_msirgsel(true);
452 w.set_msion(true); 421 w.set_msion(true);
453 422
454 if let RtcClockSource::LSE32 = config.rtc_mux { 423 if let RtcClockSource::LSE = config.rtc_mux {
455 // If LSE is enabled, enable calibration of MSI 424 // If LSE is enabled, enable calibration of MSI
456 w.set_msipllen(true); 425 w.set_msipllen(true);
457 } else { 426 } else {
@@ -609,7 +578,7 @@ pub(crate) unsafe fn init(config: Config) {
609 }); 578 });
610 579
611 let ahb_freq: u32 = match config.ahb_pre { 580 let ahb_freq: u32 = match config.ahb_pre {
612 AHBPrescaler::NotDivided => sys_clk, 581 AHBPrescaler::DIV1 => sys_clk,
613 pre => { 582 pre => {
614 let pre: Hpre = pre.into(); 583 let pre: Hpre = pre.into();
615 let pre = 1 << (pre.to_bits() as u32 - 7); 584 let pre = 1 << (pre.to_bits() as u32 - 7);
@@ -618,7 +587,7 @@ pub(crate) unsafe fn init(config: Config) {
618 }; 587 };
619 588
620 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 589 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
621 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 590 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
622 pre => { 591 pre => {
623 let pre: Ppre = pre.into(); 592 let pre: Ppre = pre.into();
624 let pre: u8 = 1 << (pre.to_bits() - 3); 593 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -628,7 +597,7 @@ pub(crate) unsafe fn init(config: Config) {
628 }; 597 };
629 598
630 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 599 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
631 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 600 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
632 pre => { 601 pre => {
633 let pre: Ppre = pre.into(); 602 let pre: Ppre = pre.into();
634 let pre: u8 = 1 << (pre.to_bits() - 3); 603 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -637,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) {
637 } 606 }
638 }; 607 };
639 608
640 RCC.apb1enr1().modify(|w| w.set_pwren(true));
641
642 set_freqs(Clocks { 609 set_freqs(Clocks {
643 sys: Hertz(sys_clk), 610 sys: Hertz(sys_clk),
644 ahb1: Hertz(ahb_freq), 611 ahb1: Hertz(ahb_freq),
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs
index a85e14889..652bdcb7b 100644
--- a/embassy-stm32/src/rcc/l5.rs
+++ b/embassy-stm32/src/rcc/l5.rs
@@ -1,6 +1,6 @@
1use stm32_metapac::PWR; 1use stm32_metapac::PWR;
2 2
3pub use super::common::{AHBPrescaler, APBPrescaler}; 3pub use super::bus::{AHBPrescaler, APBPrescaler};
4use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; 4use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
5use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
6use crate::rcc::{set_freqs, Clocks}; 6use crate::rcc::{set_freqs, Clocks};
@@ -238,9 +238,9 @@ impl Default for Config {
238 fn default() -> Config { 238 fn default() -> Config {
239 Config { 239 Config {
240 mux: ClockSrc::MSI(MSIRange::Range6), 240 mux: ClockSrc::MSI(MSIRange::Range6),
241 ahb_pre: AHBPrescaler::NotDivided, 241 ahb_pre: AHBPrescaler::DIV1,
242 apb1_pre: APBPrescaler::NotDivided, 242 apb1_pre: APBPrescaler::DIV1,
243 apb2_pre: APBPrescaler::NotDivided, 243 apb2_pre: APBPrescaler::DIV1,
244 pllsai1: None, 244 pllsai1: None,
245 hsi48: false, 245 hsi48: false,
246 } 246 }
@@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) {
317 317
318 let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); 318 let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
319 319
320 #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
321 assert!(freq <= 120_000_000);
322 #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))]
323 assert!(freq <= 80_000_000);
324
325 RCC.pllcfgr().write(move |w| { 320 RCC.pllcfgr().write(move |w| {
326 w.set_plln(mul.into()); 321 w.set_plln(mul.into());
327 w.set_pllm(prediv.into()); 322 w.set_pllm(prediv.into());
@@ -407,7 +402,7 @@ pub(crate) unsafe fn init(config: Config) {
407 }); 402 });
408 403
409 let ahb_freq: u32 = match config.ahb_pre { 404 let ahb_freq: u32 = match config.ahb_pre {
410 AHBPrescaler::NotDivided => sys_clk, 405 AHBPrescaler::DIV1 => sys_clk,
411 pre => { 406 pre => {
412 let pre: Hpre = pre.into(); 407 let pre: Hpre = pre.into();
413 let pre = 1 << (pre.to_bits() as u32 - 7); 408 let pre = 1 << (pre.to_bits() as u32 - 7);
@@ -416,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) {
416 }; 411 };
417 412
418 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 413 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
419 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 414 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
420 pre => { 415 pre => {
421 let pre: Ppre = pre.into(); 416 let pre: Ppre = pre.into();
422 let pre: u8 = 1 << (pre.to_bits() - 3); 417 let pre: u8 = 1 << (pre.to_bits() - 3);
@@ -426,7 +421,7 @@ pub(crate) unsafe fn init(config: Config) {
426 }; 421 };
427 422
428 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 423 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
429 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 424 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
430 pre => { 425 pre => {
431 let pre: Ppre = pre.into(); 426 let pre: Ppre = pre.into();
432 let pre: u8 = 1 << (pre.to_bits() - 3); 427 let pre: u8 = 1 << (pre.to_bits() - 3);
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
new file mode 100644
index 000000000..2453ed821
--- /dev/null
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -0,0 +1,71 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::into_ref;
4
5use crate::gpio::sealed::AFType;
6use crate::gpio::Speed;
7pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
8use crate::pac::RCC;
9use crate::{peripherals, Peripheral};
10
11pub(crate) mod sealed {
12 pub trait McoInstance {
13 type Source;
14 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
15 }
16}
17
18pub trait McoInstance: sealed::McoInstance + 'static {}
19
20pin_trait!(McoPin, McoInstance);
21
22macro_rules! impl_peri {
23 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
24 impl sealed::McoInstance for peripherals::$peri {
25 type Source = $source;
26
27 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
28 RCC.cfgr().modify(|w| {
29 w.$set_source(source);
30 w.$set_prescaler(prescaler);
31 });
32 }
33 }
34
35 impl McoInstance for peripherals::$peri {}
36 };
37}
38
39impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre);
40impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre);
41
42pub struct Mco<'d, T: McoInstance> {
43 phantom: PhantomData<&'d mut T>,
44}
45
46impl<'d, T: McoInstance> Mco<'d, T> {
47 /// Create a new MCO instance.
48 ///
49 /// `prescaler` must be between 1 and 15.
50 pub fn new(
51 _peri: impl Peripheral<P = T> + 'd,
52 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
53 source: T::Source,
54 prescaler: u8,
55 ) -> Self {
56 into_ref!(pin);
57
58 assert!(
59 1 <= prescaler && prescaler <= 15,
60 "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
61 );
62
63 critical_section::with(|_| unsafe {
64 T::apply_clock_settings(source, prescaler);
65 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
66 pin.set_speed(Speed::VeryHigh);
67 });
68
69 Self { phantom: PhantomData }
70 }
71}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 3c75923e5..9ccf2ac4f 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -1,11 +1,17 @@
1#![macro_use] 1#![macro_use]
2 2
3pub mod common;
4
5use core::mem::MaybeUninit; 3use core::mem::MaybeUninit;
6 4
5pub use crate::rcc::bd::RtcClockSource;
7use crate::time::Hertz; 6use crate::time::Hertz;
8 7
8pub(crate) mod bd;
9mod bus;
10#[cfg(any(stm32h5, stm32h7))]
11mod mco;
12#[cfg(any(stm32h5, stm32h7))]
13pub use mco::*;
14
9#[cfg_attr(rcc_f0, path = "f0.rs")] 15#[cfg_attr(rcc_f0, path = "f0.rs")]
10#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] 16#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
11#[cfg_attr(rcc_f2, path = "f2.rs")] 17#[cfg_attr(rcc_f2, path = "f2.rs")]
@@ -15,20 +21,30 @@ use crate::time::Hertz;
15#[cfg_attr(rcc_c0, path = "c0.rs")] 21#[cfg_attr(rcc_c0, path = "c0.rs")]
16#[cfg_attr(rcc_g0, path = "g0.rs")] 22#[cfg_attr(rcc_g0, path = "g0.rs")]
17#[cfg_attr(rcc_g4, path = "g4.rs")] 23#[cfg_attr(rcc_g4, path = "g4.rs")]
18#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")] 24#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")]
19#[cfg_attr(rcc_l0, path = "l0.rs")] 25#[cfg_attr(rcc_l0, path = "l0.rs")]
20#[cfg_attr(rcc_l1, path = "l1.rs")] 26#[cfg_attr(rcc_l1, path = "l1.rs")]
21#[cfg_attr(rcc_l4, path = "l4.rs")] 27#[cfg_attr(rcc_l4, path = "l4.rs")]
22#[cfg_attr(rcc_l5, path = "l5.rs")] 28#[cfg_attr(rcc_l5, path = "l5.rs")]
23#[cfg_attr(rcc_u5, path = "u5.rs")] 29#[cfg_attr(rcc_u5, path = "u5.rs")]
24#[cfg_attr(rcc_wb, path = "wb.rs")] 30#[cfg_attr(rcc_wb, path = "wb.rs")]
31#[cfg_attr(rcc_wba, path = "wba.rs")]
25#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] 32#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
26#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")]
27mod _version; 33mod _version;
28pub use _version::*; 34pub use _version::*;
29#[cfg(feature = "low-power")] 35#[cfg(feature = "low-power")]
30use atomic_polyfill::{AtomicU32, Ordering}; 36use atomic_polyfill::{AtomicU32, Ordering};
31 37
38// Model Clock Configuration
39//
40// pub struct Clocks {
41// hse: Option<Hertz>,
42// hsi: bool,
43// lse: Option<Hertz>,
44// lsi: bool,
45// rtc: RtcSource,
46// }
47
32#[derive(Clone, Copy, Debug)] 48#[derive(Clone, Copy, Debug)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))] 49#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub struct Clocks { 50pub struct Clocks {
@@ -41,16 +57,18 @@ pub struct Clocks {
41 pub apb2: Hertz, 57 pub apb2: Hertz,
42 #[cfg(not(any(rcc_c0, rcc_g0)))] 58 #[cfg(not(any(rcc_c0, rcc_g0)))]
43 pub apb2_tim: Hertz, 59 pub apb2_tim: Hertz,
44 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] 60 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))]
45 pub apb3: Hertz, 61 pub apb3: Hertz,
46 #[cfg(any(rcc_h7, rcc_h7ab))] 62 #[cfg(any(rcc_h7, rcc_h7ab))]
47 pub apb4: Hertz, 63 pub apb4: Hertz,
64 #[cfg(any(rcc_wba))]
65 pub apb7: Hertz,
48 66
49 // AHB 67 // AHB
50 pub ahb1: Hertz, 68 pub ahb1: Hertz,
51 #[cfg(any( 69 #[cfg(any(
52 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, 70 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
53 rcc_wl5, rcc_wle 71 rcc_wba, rcc_wl5, rcc_wle
54 ))] 72 ))]
55 pub ahb2: Hertz, 73 pub ahb2: Hertz,
56 #[cfg(any( 74 #[cfg(any(
@@ -58,7 +76,7 @@ pub struct Clocks {
58 rcc_wle 76 rcc_wle
59 ))] 77 ))]
60 pub ahb3: Hertz, 78 pub ahb3: Hertz,
61 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] 79 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))]
62 pub ahb4: Hertz, 80 pub ahb4: Hertz,
63 81
64 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] 82 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@@ -70,15 +88,22 @@ pub struct Clocks {
70 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 88 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
71 pub pllsai: Option<Hertz>, 89 pub pllsai: Option<Hertz>,
72 90
73 #[cfg(stm32f1)] 91 #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))]
74 pub adc: Hertz,
75
76 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
77 pub adc: Option<Hertz>, 92 pub adc: Option<Hertz>,
78 93
79 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 94 #[cfg(any(rcc_f3, rcc_g4))]
80 /// Set only if the lsi or lse is configured 95 pub adc34: Option<Hertz>,
96
97 #[cfg(stm32f334)]
98 pub hrtim: Option<Hertz>,
99
100 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))]
101 /// Set only if the lsi or lse is configured, indicates stop is supported
81 pub rtc: Option<Hertz>, 102 pub rtc: Option<Hertz>,
103
104 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
105 /// Set if the hse is configured, indicates stop is not supported
106 pub rtc_hse: Option<Hertz>,
82} 107}
83 108
84#[cfg(feature = "low-power")] 109#[cfg(feature = "low-power")]
@@ -86,6 +111,8 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0);
86 111
87#[cfg(feature = "low-power")] 112#[cfg(feature = "low-power")]
88pub fn low_power_ready() -> bool { 113pub fn low_power_ready() -> bool {
114 trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst));
115
89 CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 116 CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0
90} 117}
91 118
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index b5feeb0c4..d9a531285 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,6 +1,6 @@
1use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; 1use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw};
2 2
3pub use super::common::{AHBPrescaler, APBPrescaler}; 3pub use super::bus::{AHBPrescaler, APBPrescaler};
4use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
@@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
11/// LSI speed 11/// LSI speed
12pub const LSI_FREQ: Hertz = Hertz(32_000); 12pub const LSI_FREQ: Hertz = Hertz(32_000);
13 13
14pub use super::common::VoltageScale; 14pub use crate::pac::pwr::vals::Vos as VoltageScale;
15 15
16#[derive(Copy, Clone)] 16#[derive(Copy, Clone)]
17pub enum ClockSrc { 17pub enum ClockSrc {
@@ -119,53 +119,13 @@ impl Into<Pllm> for PllM {
119 } 119 }
120} 120}
121 121
122impl Into<u8> for AHBPrescaler {
123 fn into(self) -> u8 {
124 match self {
125 AHBPrescaler::NotDivided => 1,
126 AHBPrescaler::Div2 => 0x08,
127 AHBPrescaler::Div4 => 0x09,
128 AHBPrescaler::Div8 => 0x0a,
129 AHBPrescaler::Div16 => 0x0b,
130 AHBPrescaler::Div64 => 0x0c,
131 AHBPrescaler::Div128 => 0x0d,
132 AHBPrescaler::Div256 => 0x0e,
133 AHBPrescaler::Div512 => 0x0f,
134 }
135 }
136}
137
138impl Default for AHBPrescaler {
139 fn default() -> Self {
140 AHBPrescaler::NotDivided
141 }
142}
143
144impl Default for APBPrescaler {
145 fn default() -> Self {
146 APBPrescaler::NotDivided
147 }
148}
149
150impl Into<u8> for APBPrescaler {
151 fn into(self) -> u8 {
152 match self {
153 APBPrescaler::NotDivided => 1,
154 APBPrescaler::Div2 => 0x04,
155 APBPrescaler::Div4 => 0x05,
156 APBPrescaler::Div8 => 0x06,
157 APBPrescaler::Div16 => 0x07,
158 }
159 }
160}
161
162impl Into<Sw> for ClockSrc { 122impl Into<Sw> for ClockSrc {
163 fn into(self) -> Sw { 123 fn into(self) -> Sw {
164 match self { 124 match self {
165 ClockSrc::MSI(..) => Sw::MSIS, 125 ClockSrc::MSI(..) => Sw::MSIS,
166 ClockSrc::HSE(..) => Sw::HSE, 126 ClockSrc::HSE(..) => Sw::HSE,
167 ClockSrc::HSI16 => Sw::HSI16, 127 ClockSrc::HSI16 => Sw::HSI16,
168 ClockSrc::PLL1R(..) => Sw::PLL1R, 128 ClockSrc::PLL1R(..) => Sw::PLL1_R,
169 } 129 }
170 } 130 }
171} 131}
@@ -239,10 +199,10 @@ impl Default for Config {
239 fn default() -> Self { 199 fn default() -> Self {
240 Self { 200 Self {
241 mux: ClockSrc::MSI(MSIRange::default()), 201 mux: ClockSrc::MSI(MSIRange::default()),
242 ahb_pre: Default::default(), 202 ahb_pre: AHBPrescaler::DIV1,
243 apb1_pre: Default::default(), 203 apb1_pre: APBPrescaler::DIV1,
244 apb2_pre: Default::default(), 204 apb2_pre: APBPrescaler::DIV1,
245 apb3_pre: Default::default(), 205 apb3_pre: APBPrescaler::DIV1,
246 hsi48: false, 206 hsi48: false,
247 } 207 }
248 } 208 }
@@ -326,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) {
326 } 286 }
327 287
328 // TODO make configurable 288 // TODO make configurable
329 let power_vos = VoltageScale::Scale3; 289 let power_vos = VoltageScale::RANGE3;
330 290
331 // states and programming delay 291 // states and programming delay
332 let wait_states = match power_vos { 292 let wait_states = match power_vos {
333 // VOS 0 range VCORE 1.26V - 1.40V 293 // VOS 1 range VCORE 1.26V - 1.40V
334 VoltageScale::Scale0 => { 294 VoltageScale::RANGE1 => {
335 if sys_clk < 32_000_000 { 295 if sys_clk < 32_000_000 {
336 0 296 0
337 } else if sys_clk < 64_000_000 { 297 } else if sys_clk < 64_000_000 {
@@ -344,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) {
344 4 304 4
345 } 305 }
346 } 306 }
347 // VOS 1 range VCORE 1.15V - 1.26V 307 // VOS 2 range VCORE 1.15V - 1.26V
348 VoltageScale::Scale1 => { 308 VoltageScale::RANGE2 => {
349 if sys_clk < 30_000_000 { 309 if sys_clk < 30_000_000 {
350 0 310 0
351 } else if sys_clk < 60_000_000 { 311 } else if sys_clk < 60_000_000 {
@@ -356,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) {
356 3 316 3
357 } 317 }
358 } 318 }
359 // VOS 2 range VCORE 1.05V - 1.15V 319 // VOS 3 range VCORE 1.05V - 1.15V
360 VoltageScale::Scale2 => { 320 VoltageScale::RANGE3 => {
361 if sys_clk < 24_000_000 { 321 if sys_clk < 24_000_000 {
362 0 322 0
363 } else if sys_clk < 48_000_000 { 323 } else if sys_clk < 48_000_000 {
@@ -366,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) {
366 2 326 2
367 } 327 }
368 } 328 }
369 // VOS 3 range VCORE 0.95V - 1.05V 329 // VOS 4 range VCORE 0.95V - 1.05V
370 VoltageScale::Scale3 => { 330 VoltageScale::RANGE4 => {
371 if sys_clk < 12_000_000 { 331 if sys_clk < 12_000_000 {
372 0 332 0
373 } else { 333 } else {
@@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) {
395 }); 355 });
396 356
397 let ahb_freq: u32 = match config.ahb_pre { 357 let ahb_freq: u32 = match config.ahb_pre {
398 AHBPrescaler::NotDivided => sys_clk, 358 AHBPrescaler::DIV1 => sys_clk,
399 pre => { 359 pre => {
400 let pre: u8 = pre.into(); 360 let pre: u8 = pre.into();
401 let pre = 1 << (pre as u32 - 7); 361 let pre = 1 << (pre as u32 - 7);
@@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) {
404 }; 364 };
405 365
406 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 366 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
407 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 367 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
408 pre => { 368 pre => {
409 let pre: u8 = pre.into(); 369 let pre: u8 = pre.into();
410 let pre: u8 = 1 << (pre - 3); 370 let pre: u8 = 1 << (pre - 3);
@@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) {
414 }; 374 };
415 375
416 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 376 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
417 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 377 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
418 pre => { 378 pre => {
419 let pre: u8 = pre.into(); 379 let pre: u8 = pre.into();
420 let pre: u8 = 1 << (pre - 3); 380 let pre: u8 = 1 << (pre - 3);
@@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) {
424 }; 384 };
425 385
426 let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { 386 let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
427 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 387 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
428 pre => { 388 pre => {
429 let pre: u8 = pre.into(); 389 let pre: u8 = pre.into();
430 let pre: u8 = 1 << (pre - 3); 390 let pre: u8 = 1 << (pre - 3);
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs
index ae708b37f..ee45a342b 100644
--- a/embassy-stm32/src/rcc/wb.rs
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -1,6 +1,6 @@
1pub use super::common::{AHBPrescaler, APBPrescaler}; 1pub use super::bus::{AHBPrescaler, APBPrescaler};
2use crate::rcc::bd::{BackupDomain, RtcClockSource};
2use crate::rcc::Clocks; 3use crate::rcc::Clocks;
3use crate::rtc::{Rtc, RtcClockSource};
4use crate::time::{khz, mhz, Hertz}; 4use crate::time::{khz, mhz, Hertz};
5 5
6/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, 6/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
@@ -108,6 +108,7 @@ pub struct Pll {
108pub struct Config { 108pub struct Config {
109 pub hse: Option<Hse>, 109 pub hse: Option<Hse>,
110 pub lse: Option<Hertz>, 110 pub lse: Option<Hertz>,
111 pub lsi: bool,
111 pub sys: Sysclk, 112 pub sys: Sysclk,
112 pub mux: Option<PllMux>, 113 pub mux: Option<PllMux>,
113 pub pll48: Option<Pll48Source>, 114 pub pll48: Option<Pll48Source>,
@@ -135,7 +136,8 @@ pub const WPAN_DEFAULT: Config = Config {
135 prediv: 2, 136 prediv: 2,
136 }), 137 }),
137 pll48: None, 138 pll48: None,
138 rtc: None, 139 rtc: Some(RtcClockSource::LSE),
140 lsi: false,
139 141
140 pll: Some(Pll { 142 pll: Some(Pll {
141 mul: 12, 143 mul: 12,
@@ -145,11 +147,11 @@ pub const WPAN_DEFAULT: Config = Config {
145 }), 147 }),
146 pllsai: None, 148 pllsai: None,
147 149
148 ahb1_pre: AHBPrescaler::NotDivided, 150 ahb1_pre: AHBPrescaler::DIV1,
149 ahb2_pre: AHBPrescaler::Div2, 151 ahb2_pre: AHBPrescaler::DIV2,
150 ahb3_pre: AHBPrescaler::NotDivided, 152 ahb3_pre: AHBPrescaler::DIV1,
151 apb1_pre: APBPrescaler::NotDivided, 153 apb1_pre: APBPrescaler::DIV1,
152 apb2_pre: APBPrescaler::NotDivided, 154 apb2_pre: APBPrescaler::DIV1,
153}; 155};
154 156
155impl Default for Config { 157impl Default for Config {
@@ -164,12 +166,13 @@ impl Default for Config {
164 pll: None, 166 pll: None,
165 pllsai: None, 167 pllsai: None,
166 rtc: None, 168 rtc: None,
169 lsi: false,
167 170
168 ahb1_pre: AHBPrescaler::NotDivided, 171 ahb1_pre: AHBPrescaler::DIV1,
169 ahb2_pre: AHBPrescaler::NotDivided, 172 ahb2_pre: AHBPrescaler::DIV1,
170 ahb3_pre: AHBPrescaler::NotDivided, 173 ahb3_pre: AHBPrescaler::DIV1,
171 apb1_pre: APBPrescaler::NotDivided, 174 apb1_pre: APBPrescaler::DIV1,
172 apb2_pre: APBPrescaler::NotDivided, 175 apb2_pre: APBPrescaler::DIV1,
173 } 176 }
174 } 177 }
175} 178}
@@ -209,7 +212,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
209 }; 212 };
210 213
211 let ahb1_clk = match config.ahb1_pre { 214 let ahb1_clk = match config.ahb1_pre {
212 AHBPrescaler::NotDivided => sys_clk, 215 AHBPrescaler::DIV1 => sys_clk,
213 pre => { 216 pre => {
214 let pre: u8 = pre.into(); 217 let pre: u8 = pre.into();
215 let pre = 1u32 << (pre as u32 - 7); 218 let pre = 1u32 << (pre as u32 - 7);
@@ -218,7 +221,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
218 }; 221 };
219 222
220 let ahb2_clk = match config.ahb2_pre { 223 let ahb2_clk = match config.ahb2_pre {
221 AHBPrescaler::NotDivided => sys_clk, 224 AHBPrescaler::DIV1 => sys_clk,
222 pre => { 225 pre => {
223 let pre: u8 = pre.into(); 226 let pre: u8 = pre.into();
224 let pre = 1u32 << (pre as u32 - 7); 227 let pre = 1u32 << (pre as u32 - 7);
@@ -227,7 +230,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
227 }; 230 };
228 231
229 let ahb3_clk = match config.ahb3_pre { 232 let ahb3_clk = match config.ahb3_pre {
230 AHBPrescaler::NotDivided => sys_clk, 233 AHBPrescaler::DIV1 => sys_clk,
231 pre => { 234 pre => {
232 let pre: u8 = pre.into(); 235 let pre: u8 = pre.into();
233 let pre = 1u32 << (pre as u32 - 7); 236 let pre = 1u32 << (pre as u32 - 7);
@@ -236,7 +239,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
236 }; 239 };
237 240
238 let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { 241 let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
239 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), 242 APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
240 pre => { 243 pre => {
241 let pre: u8 = pre.into(); 244 let pre: u8 = pre.into();
242 let pre: u8 = 1 << (pre - 3); 245 let pre: u8 = 1 << (pre - 3);
@@ -246,7 +249,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
246 }; 249 };
247 250
248 let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { 251 let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
249 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), 252 APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
250 pre => { 253 pre => {
251 let pre: u8 = pre.into(); 254 let pre: u8 = pre.into();
252 let pre: u8 = 1 << (pre - 3); 255 let pre: u8 = 1 << (pre - 3);
@@ -271,11 +274,11 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
271 apb1_tim: apb1_tim_clk, 274 apb1_tim: apb1_tim_clk,
272 apb2_tim: apb2_tim_clk, 275 apb2_tim: apb2_tim_clk,
273 rtc: rtc_clk, 276 rtc: rtc_clk,
277 rtc_hse: None,
274 } 278 }
275} 279}
276 280
277pub(crate) fn configure_clocks(config: &Config) { 281pub(crate) fn configure_clocks(config: &Config) {
278 let pwr = crate::pac::PWR;
279 let rcc = crate::pac::RCC; 282 let rcc = crate::pac::RCC;
280 283
281 let needs_hsi = if let Some(pll_mux) = &config.mux { 284 let needs_hsi = if let Some(pll_mux) = &config.mux {
@@ -292,29 +295,13 @@ pub(crate) fn configure_clocks(config: &Config) {
292 while !rcc.cr().read().hsirdy() {} 295 while !rcc.cr().read().hsirdy() {}
293 } 296 }
294 297
295 let needs_lsi = if let Some(rtc_mux) = &config.rtc { 298 rcc.cfgr().modify(|w| w.set_stopwuck(true));
296 *rtc_mux == RtcClockSource::LSI
297 } else {
298 false
299 };
300
301 if needs_lsi {
302 rcc.csr().modify(|w| w.set_lsi1on(true));
303
304 while !rcc.csr().read().lsi1rdy() {}
305 }
306 299
307 match &config.lse { 300 BackupDomain::configure_ls(
308 Some(_) => { 301 config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
309 rcc.cfgr().modify(|w| w.set_stopwuck(true)); 302 config.lsi,
310 303 config.lse.map(|_| Default::default()),
311 pwr.cr1().modify(|w| w.set_dbp(true)); 304 );
312 pwr.cr1().modify(|w| w.set_dbp(true));
313
314 rcc.bdcr().modify(|w| w.set_lseon(true));
315 }
316 _ => {}
317 }
318 305
319 match &config.hse { 306 match &config.hse {
320 Some(hse) => { 307 Some(hse) => {
@@ -374,6 +361,4 @@ pub(crate) fn configure_clocks(config: &Config) {
374 w.set_c2hpre(config.ahb2_pre.into()); 361 w.set_c2hpre(config.ahb2_pre.into());
375 w.set_shdhpre(config.ahb3_pre.into()); 362 w.set_shdhpre(config.ahb3_pre.into());
376 }); 363 });
377
378 config.rtc.map(|clock_source| Rtc::set_clock_source(clock_source));
379} 364}
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
new file mode 100644
index 000000000..c5d7ab62f
--- /dev/null
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -0,0 +1,154 @@
1use stm32_metapac::rcc::vals::{Pllsrc, Sw};
2
3use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz;
6
7/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9
10/// LSI speed
11pub const LSI_FREQ: Hertz = Hertz(32_000);
12
13pub use crate::pac::pwr::vals::Vos as VoltageScale;
14pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
15
16#[derive(Copy, Clone)]
17pub enum ClockSrc {
18 HSE(Hertz),
19 HSI16,
20}
21
22#[derive(Clone, Copy, Debug)]
23pub enum PllSrc {
24 HSE(Hertz),
25 HSI16,
26}
27
28impl Into<Pllsrc> for PllSrc {
29 fn into(self) -> Pllsrc {
30 match self {
31 PllSrc::HSE(..) => Pllsrc::HSE32,
32 PllSrc::HSI16 => Pllsrc::HSI16,
33 }
34 }
35}
36
37impl Into<Sw> for ClockSrc {
38 fn into(self) -> Sw {
39 match self {
40 ClockSrc::HSE(..) => Sw::HSE32,
41 ClockSrc::HSI16 => Sw::HSI16,
42 }
43 }
44}
45
46#[derive(Copy, Clone)]
47pub struct Config {
48 pub mux: ClockSrc,
49 pub ahb_pre: AHBPrescaler,
50 pub apb1_pre: APBPrescaler,
51 pub apb2_pre: APBPrescaler,
52 pub apb7_pre: APBPrescaler,
53}
54
55impl Default for Config {
56 fn default() -> Self {
57 Self {
58 mux: ClockSrc::HSI16,
59 ahb_pre: AHBPrescaler::DIV1,
60 apb1_pre: APBPrescaler::DIV1,
61 apb2_pre: APBPrescaler::DIV1,
62 apb7_pre: APBPrescaler::DIV1,
63 }
64 }
65}
66
67pub(crate) unsafe fn init(config: Config) {
68 let sys_clk = match config.mux {
69 ClockSrc::HSE(freq) => {
70 RCC.cr().write(|w| w.set_hseon(true));
71 while !RCC.cr().read().hserdy() {}
72
73 freq
74 }
75 ClockSrc::HSI16 => {
76 RCC.cr().write(|w| w.set_hsion(true));
77 while !RCC.cr().read().hsirdy() {}
78
79 HSI_FREQ
80 }
81 };
82
83 // TODO make configurable
84 let power_vos = VoltageScale::RANGE1;
85
86 // states and programming delay
87 let wait_states = match power_vos {
88 VoltageScale::RANGE1 => match sys_clk.0 {
89 ..=32_000_000 => 0,
90 ..=64_000_000 => 1,
91 ..=96_000_000 => 2,
92 ..=100_000_000 => 3,
93 _ => 4,
94 },
95 VoltageScale::RANGE2 => match sys_clk.0 {
96 ..=8_000_000 => 0,
97 ..=16_000_000 => 1,
98 _ => 2,
99 },
100 };
101
102 FLASH.acr().modify(|w| {
103 w.set_latency(wait_states);
104 });
105
106 RCC.cfgr1().modify(|w| {
107 w.set_sw(config.mux.into());
108 });
109
110 RCC.cfgr2().modify(|w| {
111 w.set_hpre(config.ahb_pre.into());
112 w.set_ppre1(config.apb1_pre.into());
113 w.set_ppre2(config.apb2_pre.into());
114 });
115
116 RCC.cfgr3().modify(|w| {
117 w.set_ppre7(config.apb7_pre.into());
118 });
119
120 let ahb_freq = sys_clk / config.ahb_pre;
121 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
122 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
123 pre => {
124 let freq = ahb_freq / pre;
125 (freq, freq * 2u32)
126 }
127 };
128 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
129 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
130 pre => {
131 let freq = ahb_freq / pre;
132 (freq, freq * 2u32)
133 }
134 };
135 let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre {
136 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
137 pre => {
138 let freq = ahb_freq / pre;
139 (freq, freq * 2u32)
140 }
141 };
142
143 set_freqs(Clocks {
144 sys: sys_clk,
145 ahb1: ahb_freq,
146 ahb2: ahb_freq,
147 ahb4: ahb_freq,
148 apb1: apb1_freq,
149 apb2: apb2_freq,
150 apb7: apb7_freq,
151 apb1_tim: apb1_tim_freq,
152 apb2_tim: apb2_tim_freq,
153 });
154}
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs
index f1dd2bd7e..6643d278a 100644
--- a/embassy-stm32/src/rcc/wl.rs
+++ b/embassy-stm32/src/rcc/wl.rs
@@ -1,8 +1,9 @@
1pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; 1pub use super::bus::{AHBPrescaler, APBPrescaler};
2use crate::pac::pwr::vals::Dbp; 2pub use crate::pac::pwr::vals::Vos as VoltageScale;
3use crate::pac::{FLASH, PWR, RCC}; 3use crate::pac::rcc::vals::Adcsel;
4use crate::pac::{FLASH, RCC};
5use crate::rcc::bd::{BackupDomain, RtcClockSource};
4use crate::rcc::{set_freqs, Clocks}; 6use crate::rcc::{set_freqs, Clocks};
5use crate::rtc::{Rtc, RtcClockSource as RCS};
6use crate::time::Hertz; 7use crate::time::Hertz;
7 8
8/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, 9/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
@@ -75,9 +76,9 @@ impl MSIRange {
75 76
76 fn vos(&self) -> VoltageScale { 77 fn vos(&self) -> VoltageScale {
77 if self > &MSIRange::Range8 { 78 if self > &MSIRange::Range8 {
78 VoltageScale::Scale0 79 VoltageScale::RANGE1
79 } else { 80 } else {
80 VoltageScale::Scale1 81 VoltageScale::RANGE2
81 } 82 }
82 } 83 }
83} 84}
@@ -107,6 +108,29 @@ impl Into<u8> for MSIRange {
107 } 108 }
108} 109}
109 110
111#[derive(Clone, Copy)]
112pub enum AdcClockSource {
113 HSI16,
114 PLLPCLK,
115 SYSCLK,
116}
117
118impl AdcClockSource {
119 pub fn adcsel(&self) -> Adcsel {
120 match self {
121 AdcClockSource::HSI16 => Adcsel::HSI16,
122 AdcClockSource::PLLPCLK => Adcsel::PLLPCLK,
123 AdcClockSource::SYSCLK => Adcsel::SYSCLK,
124 }
125 }
126}
127
128impl Default for AdcClockSource {
129 fn default() -> Self {
130 Self::HSI16
131 }
132}
133
110/// Clocks configutation 134/// Clocks configutation
111pub struct Config { 135pub struct Config {
112 pub mux: ClockSrc, 136 pub mux: ClockSrc,
@@ -114,9 +138,10 @@ pub struct Config {
114 pub shd_ahb_pre: AHBPrescaler, 138 pub shd_ahb_pre: AHBPrescaler,
115 pub apb1_pre: APBPrescaler, 139 pub apb1_pre: APBPrescaler,
116 pub apb2_pre: APBPrescaler, 140 pub apb2_pre: APBPrescaler,
117 pub enable_lsi: bool,
118 pub enable_rtc_apb: bool,
119 pub rtc_mux: RtcClockSource, 141 pub rtc_mux: RtcClockSource,
142 pub lse: Option<Hertz>,
143 pub lsi: bool,
144 pub adc_clock_source: AdcClockSource,
120} 145}
121 146
122impl Default for Config { 147impl Default for Config {
@@ -124,22 +149,18 @@ impl Default for Config {
124 fn default() -> Config { 149 fn default() -> Config {
125 Config { 150 Config {
126 mux: ClockSrc::MSI(MSIRange::default()), 151 mux: ClockSrc::MSI(MSIRange::default()),
127 ahb_pre: AHBPrescaler::NotDivided, 152 ahb_pre: AHBPrescaler::DIV1,
128 shd_ahb_pre: AHBPrescaler::NotDivided, 153 shd_ahb_pre: AHBPrescaler::DIV1,
129 apb1_pre: APBPrescaler::NotDivided, 154 apb1_pre: APBPrescaler::DIV1,
130 apb2_pre: APBPrescaler::NotDivided, 155 apb2_pre: APBPrescaler::DIV1,
131 enable_lsi: false, 156 rtc_mux: RtcClockSource::LSI,
132 enable_rtc_apb: false, 157 lsi: true,
133 rtc_mux: RtcClockSource::LSI32, 158 lse: None,
159 adc_clock_source: AdcClockSource::default(),
134 } 160 }
135 } 161 }
136} 162}
137 163
138pub enum RtcClockSource {
139 LSE32,
140 LSI32,
141}
142
143#[repr(u8)] 164#[repr(u8)]
144pub enum Lsedrv { 165pub enum Lsedrv {
145 Low = 0, 166 Low = 0,
@@ -150,13 +171,13 @@ pub enum Lsedrv {
150 171
151pub(crate) unsafe fn init(config: Config) { 172pub(crate) unsafe fn init(config: Config) {
152 let (sys_clk, sw, vos) = match config.mux { 173 let (sys_clk, sw, vos) = match config.mux {
153 ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1), 174 ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2),
154 ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0), 175 ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1),
155 ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), 176 ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
156 }; 177 };
157 178
158 let ahb_freq: u32 = match config.ahb_pre { 179 let ahb_freq: u32 = match config.ahb_pre {
159 AHBPrescaler::NotDivided => sys_clk, 180 AHBPrescaler::DIV1 => sys_clk,
160 pre => { 181 pre => {
161 let pre: u8 = pre.into(); 182 let pre: u8 = pre.into();
162 let pre = 1 << (pre as u32 - 7); 183 let pre = 1 << (pre as u32 - 7);
@@ -165,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
165 }; 186 };
166 187
167 let shd_ahb_freq: u32 = match config.shd_ahb_pre { 188 let shd_ahb_freq: u32 = match config.shd_ahb_pre {
168 AHBPrescaler::NotDivided => sys_clk, 189 AHBPrescaler::DIV1 => sys_clk,
169 pre => { 190 pre => {
170 let pre: u8 = pre.into(); 191 let pre: u8 = pre.into();
171 let pre = 1 << (pre as u32 - 7); 192 let pre = 1 << (pre as u32 - 7);
@@ -174,7 +195,7 @@ pub(crate) unsafe fn init(config: Config) {
174 }; 195 };
175 196
176 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 197 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
177 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 198 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
178 pre => { 199 pre => {
179 let pre: u8 = pre.into(); 200 let pre: u8 = pre.into();
180 let pre: u8 = 1 << (pre - 3); 201 let pre: u8 = 1 << (pre - 3);
@@ -184,7 +205,7 @@ pub(crate) unsafe fn init(config: Config) {
184 }; 205 };
185 206
186 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 207 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
187 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 208 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
188 pre => { 209 pre => {
189 let pre: u8 = pre.into(); 210 let pre: u8 = pre.into();
190 let pre: u8 = 1 << (pre - 3); 211 let pre: u8 = 1 << (pre - 3);
@@ -196,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) {
196 // Adjust flash latency 217 // Adjust flash latency
197 let flash_clk_src_freq: u32 = shd_ahb_freq; 218 let flash_clk_src_freq: u32 = shd_ahb_freq;
198 let ws = match vos { 219 let ws = match vos {
199 VoltageScale::Scale0 => match flash_clk_src_freq { 220 VoltageScale::RANGE1 => match flash_clk_src_freq {
200 0..=18_000_000 => 0b000, 221 0..=18_000_000 => 0b000,
201 18_000_001..=36_000_000 => 0b001, 222 18_000_001..=36_000_000 => 0b001,
202 _ => 0b010, 223 _ => 0b010,
203 }, 224 },
204 VoltageScale::Scale1 => match flash_clk_src_freq { 225 VoltageScale::RANGE2 => match flash_clk_src_freq {
205 0..=6_000_000 => 0b000, 226 0..=6_000_000 => 0b000,
206 6_000_001..=12_000_000 => 0b001, 227 6_000_001..=12_000_000 => 0b001,
207 _ => 0b010, 228 _ => 0b010,
208 }, 229 },
230 _ => unreachable!(),
209 }; 231 };
210 232
211 FLASH.acr().modify(|w| { 233 FLASH.acr().modify(|w| {
@@ -214,35 +236,8 @@ pub(crate) unsafe fn init(config: Config) {
214 236
215 while FLASH.acr().read().latency() != ws {} 237 while FLASH.acr().read().latency() != ws {}
216 238
217 match config.rtc_mux { 239 // Enables the LSI if configured
218 RtcClockSource::LSE32 => { 240 BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
219 // 1. Unlock the backup domain
220 PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
221
222 // 2. Setup the LSE
223 RCC.bdcr().modify(|w| {
224 // Enable LSE
225 w.set_lseon(true);
226 // Max drive strength
227 // TODO: should probably be settable
228 w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented
229 });
230
231 // Wait until LSE is running
232 while !RCC.bdcr().read().lserdy() {}
233
234 Rtc::set_clock_source(RCS::LSE);
235 }
236 RtcClockSource::LSI32 => {
237 // Turn on the internal 32 kHz LSI oscillator
238 RCC.csr().modify(|w| w.set_lsion(true));
239
240 // Wait until LSI is running
241 while !RCC.csr().read().lsirdy() {}
242
243 Rtc::set_clock_source(RCS::LSI);
244 }
245 }
246 241
247 match config.mux { 242 match config.mux {
248 ClockSrc::HSI16 => { 243 ClockSrc::HSI16 => {
@@ -266,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
266 w.set_msirange(range.into()); 261 w.set_msirange(range.into());
267 w.set_msion(true); 262 w.set_msion(true);
268 263
269 if let RtcClockSource::LSE32 = config.rtc_mux { 264 if let RtcClockSource::LSE = config.rtc_mux {
270 // If LSE is enabled, enable calibration of MSI 265 // If LSE is enabled, enable calibration of MSI
271 w.set_msipllen(true); 266 w.set_msipllen(true);
272 } else { 267 } else {
@@ -277,16 +272,8 @@ pub(crate) unsafe fn init(config: Config) {
277 } 272 }
278 } 273 }
279 274
280 if config.enable_rtc_apb {
281 // enable peripheral clock for communication
282 crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
283
284 // read to allow the pwr clock to enable
285 crate::pac::PWR.cr1().read();
286 }
287
288 RCC.extcfgr().modify(|w| { 275 RCC.extcfgr().modify(|w| {
289 if config.shd_ahb_pre == AHBPrescaler::NotDivided { 276 if config.shd_ahb_pre == AHBPrescaler::DIV1 {
290 w.set_shdhpre(0); 277 w.set_shdhpre(0);
291 } else { 278 } else {
292 w.set_shdhpre(config.shd_ahb_pre.into()); 279 w.set_shdhpre(config.shd_ahb_pre.into());
@@ -295,24 +282,15 @@ pub(crate) unsafe fn init(config: Config) {
295 282
296 RCC.cfgr().modify(|w| { 283 RCC.cfgr().modify(|w| {
297 w.set_sw(sw.into()); 284 w.set_sw(sw.into());
298 if config.ahb_pre == AHBPrescaler::NotDivided { 285 w.set_hpre(config.ahb_pre);
299 w.set_hpre(0);
300 } else {
301 w.set_hpre(config.ahb_pre.into());
302 }
303 w.set_ppre1(config.apb1_pre.into()); 286 w.set_ppre1(config.apb1_pre.into());
304 w.set_ppre2(config.apb2_pre.into()); 287 w.set_ppre2(config.apb2_pre.into());
305 }); 288 });
306 289
307 // TODO: switch voltage range 290 // ADC clock MUX
291 RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
308 292
309 if config.enable_lsi { 293 // TODO: switch voltage range
310 let csr = RCC.csr().read();
311 if !csr.lsion() {
312 RCC.csr().modify(|w| w.set_lsion(true));
313 while !RCC.csr().read().lsirdy() {}
314 }
315 }
316 294
317 set_freqs(Clocks { 295 set_freqs(Clocks {
318 sys: Hertz(sys_clk), 296 sys: Hertz(sys_clk),
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 30816e436..0979dce8c 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> {
119 119
120 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 120 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
121 for chunk in dest.chunks_mut(4) { 121 for chunk in dest.chunks_mut(4) {
122 let bits = T::regs().sr().read(); 122 let mut bits = T::regs().sr().read();
123 if !bits.seis() && !bits.ceis() && !bits.drdy() {
124 // wait for interrupt
125 poll_fn(|cx| {
126 // quick check to avoid registration if already done.
127 let bits = T::regs().sr().read();
128 if bits.drdy() || bits.seis() || bits.ceis() {
129 return Poll::Ready(());
130 }
131 RNG_WAKER.register(cx.waker());
132 T::regs().cr().modify(|reg| reg.set_ie(true));
133 // Need to check condition **after** `register` to avoid a race
134 // condition that would result in lost notifications.
135 let bits = T::regs().sr().read();
136 if bits.drdy() || bits.seis() || bits.ceis() {
137 Poll::Ready(())
138 } else {
139 Poll::Pending
140 }
141 })
142 .await;
143
144 // Re-read the status register after wait.
145 bits = T::regs().sr().read()
146 }
123 if bits.seis() { 147 if bits.seis() {
124 // in case of noise-source or seed error we try to recover here 148 // in case of noise-source or seed error we try to recover here
125 // but we must not use the data in DR and we return an error 149 // but we must not use the data in DR and we return an error
@@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> {
143 for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { 167 for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) {
144 *dest = *src 168 *dest = *src
145 } 169 }
146 } else {
147 // wait for interrupt
148 poll_fn(|cx| {
149 // quick check to avoid registration if already done.
150 let bits = T::regs().sr().read();
151 if bits.drdy() || bits.seis() || bits.ceis() {
152 return Poll::Ready(());
153 }
154 RNG_WAKER.register(cx.waker());
155 T::regs().cr().modify(|reg| reg.set_ie(true));
156 // Need to check condition **after** `register` to avoid a race
157 // condition that would result in lost notifications.
158 let bits = T::regs().sr().read();
159 if bits.drdy() || bits.seis() || bits.ceis() {
160 Poll::Ready(())
161 } else {
162 Poll::Pending
163 }
164 })
165 .await;
166 } 170 }
167 } 171 }
168 172
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index a9c48d88d..3efe9be5d 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -89,7 +89,7 @@ pub enum DayOfWeek {
89#[cfg(feature = "chrono")] 89#[cfg(feature = "chrono")]
90impl From<chrono::Weekday> for DayOfWeek { 90impl From<chrono::Weekday> for DayOfWeek {
91 fn from(weekday: Weekday) -> Self { 91 fn from(weekday: Weekday) -> Self {
92 day_of_week_from_u8(weekday.number_from_monday() as u8).unwrap() 92 day_of_week_from_u8(weekday.num_days_from_monday() as u8).unwrap()
93 } 93 }
94} 94}
95 95
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index a6102077a..73b78f253 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -1,7 +1,17 @@
1//! RTC peripheral abstraction 1//! RTC peripheral abstraction
2mod datetime; 2mod datetime;
3 3
4#[cfg(feature = "low-power")]
5use core::cell::Cell;
6
7#[cfg(feature = "low-power")]
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9#[cfg(feature = "low-power")]
10use embassy_sync::blocking_mutex::Mutex;
11
4pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 12pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
13pub use crate::rcc::RtcClockSource;
14use crate::time::Hertz;
5 15
6/// refer to AN4759 to compare features of RTC2 and RTC3 16/// refer to AN4759 to compare features of RTC2 and RTC3
7#[cfg_attr(any(rtc_v1), path = "v1.rs")] 17#[cfg_attr(any(rtc_v1), path = "v1.rs")]
@@ -30,60 +40,99 @@ pub enum RtcError {
30 NotRunning, 40 NotRunning,
31} 41}
32 42
33/// RTC Abstraction 43#[cfg(feature = "low-power")]
34pub struct Rtc { 44/// Represents an instant in time that can be substracted to compute a duration
35 rtc_config: RtcConfig, 45struct RtcInstant {
46 second: u8,
47 subsecond: u16,
36} 48}
37 49
38#[derive(Copy, Clone, Debug, PartialEq)] 50#[cfg(all(feature = "low-power", feature = "defmt"))]
39#[repr(u8)] 51impl defmt::Format for RtcInstant {
40pub enum RtcClockSource { 52 fn format(&self, fmt: defmt::Formatter) {
41 /// 00: No clock 53 defmt::write!(
42 NoClock = 0b00, 54 fmt,
43 /// 01: LSE oscillator clock used as RTC clock 55 "{}:{}",
44 LSE = 0b01, 56 self.second,
45 /// 10: LSI oscillator clock used as RTC clock 57 RTC::regs().prer().read().prediv_s() - self.subsecond,
46 LSI = 0b10, 58 )
47 /// 11: HSE oscillator clock divided by 32 used as RTC clock 59 }
48 HSE = 0b11, 60}
61
62#[cfg(feature = "low-power")]
63impl core::ops::Sub for RtcInstant {
64 type Output = embassy_time::Duration;
65
66 fn sub(self, rhs: Self) -> Self::Output {
67 use embassy_time::{Duration, TICK_HZ};
68
69 let second = if self.second < rhs.second {
70 self.second + 60
71 } else {
72 self.second
73 };
74
75 let psc = RTC::regs().prer().read().prediv_s() as u32;
76
77 let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
78 let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
79 let rtc_ticks = self_ticks - other_ticks;
80
81 Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
82 }
83}
84
85pub struct RtcTimeProvider {
86 _private: (),
87}
88
89impl RtcTimeProvider {
90 /// Return the current datetime.
91 ///
92 /// # Errors
93 ///
94 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
95 pub fn now(&self) -> Result<DateTime, RtcError> {
96 let r = RTC::regs();
97 let tr = r.tr().read();
98 let second = bcd2_to_byte((tr.st(), tr.su()));
99 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
100 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
101 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
102 // calendar shadow registers until RTC_DR is read.
103 let dr = r.dr().read();
104
105 let weekday = dr.wdu();
106 let day = bcd2_to_byte((dr.dt(), dr.du()));
107 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
108 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
109
110 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
111 }
112}
113
114/// RTC Abstraction
115pub struct Rtc {
116 #[cfg(feature = "low-power")]
117 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
118 #[cfg(not(feature = "low-power"))]
119 _private: (),
49} 120}
50 121
122#[non_exhaustive]
51#[derive(Copy, Clone, PartialEq)] 123#[derive(Copy, Clone, PartialEq)]
52pub struct RtcConfig { 124pub struct RtcConfig {
53 /// Asynchronous prescaler factor 125 /// The subsecond counter frequency; default is 256
54 /// This is the asynchronous division factor: 126 ///
55 /// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) 127 /// A high counter frequency may impact stop power consumption
56 /// ck_apre drives the subsecond register 128 pub frequency: Hertz,
57 async_prescaler: u8,
58 /// Synchronous prescaler factor
59 /// This is the synchronous division factor:
60 /// ck_spre frequency = ck_apre frequency/(PREDIV_S+1)
61 /// ck_spre must be 1Hz
62 sync_prescaler: u16,
63} 129}
64 130
65impl Default for RtcConfig { 131impl Default for RtcConfig {
66 /// LSI with prescalers assuming 32.768 kHz. 132 /// LSI with prescalers assuming 32.768 kHz.
67 /// Raw sub-seconds in 1/256. 133 /// Raw sub-seconds in 1/256.
68 fn default() -> Self { 134 fn default() -> Self {
69 RtcConfig { 135 RtcConfig { frequency: Hertz(256) }
70 async_prescaler: 127,
71 sync_prescaler: 255,
72 }
73 }
74}
75
76impl RtcConfig {
77 /// Set the asynchronous prescaler of RTC config
78 pub fn async_prescaler(mut self, prescaler: u8) -> Self {
79 self.async_prescaler = prescaler;
80 self
81 }
82
83 /// Set the synchronous prescaler of RTC config
84 pub fn sync_prescaler(mut self, prescaler: u16) -> Self {
85 self.sync_prescaler = prescaler;
86 self
87 } 136 }
88} 137}
89 138
@@ -106,16 +155,44 @@ impl Default for RtcCalibrationCyclePeriod {
106 155
107impl Rtc { 156impl Rtc {
108 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 157 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
109 RTC::enable_peripheral_clk(); 158 #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))]
159 <RTC as crate::rcc::sealed::RccPeripheral>::enable();
160
161 let mut this = Self {
162 #[cfg(feature = "low-power")]
163 stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
164 #[cfg(not(feature = "low-power"))]
165 _private: (),
166 };
167
168 let frequency = Self::frequency();
169 let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8;
170 let sync_psc = (rtc_config.frequency.0 - 1) as u16;
110 171
111 let mut rtc_struct = Self { rtc_config }; 172 this.configure(async_psc, sync_psc);
112 173
113 Self::enable(); 174 this
175 }
176
177 fn frequency() -> Hertz {
178 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
179 let freqs = unsafe { crate::rcc::get_freqs() };
180
181 // Load the clock frequency from the rcc mod, if supported
182 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
183 match freqs.rtc {
184 Some(hertz) => hertz,
185 None => freqs.rtc_hse.unwrap(),
186 }
114 187
115 rtc_struct.configure(rtc_config); 188 // Assume the default value, if not supported
116 rtc_struct.rtc_config = rtc_config; 189 #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))]
190 Hertz(32_768)
191 }
117 192
118 rtc_struct 193 /// Acquire a [`RtcTimeProvider`] instance.
194 pub const fn time_provider(&self) -> RtcTimeProvider {
195 RtcTimeProvider { _private: () }
119 } 196 }
120 197
121 /// Set the datetime to a new value. 198 /// Set the datetime to a new value.
@@ -130,27 +207,27 @@ impl Rtc {
130 Ok(()) 207 Ok(())
131 } 208 }
132 209
210 #[cfg(feature = "low-power")]
211 /// Return the current instant.
212 fn instant(&self) -> RtcInstant {
213 let r = RTC::regs();
214 let tr = r.tr().read();
215 let subsecond = r.ssr().read().ss();
216 let second = bcd2_to_byte((tr.st(), tr.su()));
217
218 // Unlock the registers
219 r.dr().read();
220
221 RtcInstant { second, subsecond }
222 }
223
133 /// Return the current datetime. 224 /// Return the current datetime.
134 /// 225 ///
135 /// # Errors 226 /// # Errors
136 /// 227 ///
137 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 228 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
138 pub fn now(&self) -> Result<DateTime, RtcError> { 229 pub fn now(&self) -> Result<DateTime, RtcError> {
139 let r = RTC::regs(); 230 self.time_provider().now()
140 let tr = r.tr().read();
141 let second = bcd2_to_byte((tr.st(), tr.su()));
142 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
143 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
144 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
145 // calendar shadow registers until RTC_DR is read.
146 let dr = r.dr().read();
147
148 let weekday = dr.wdu();
149 let day = bcd2_to_byte((dr.dt(), dr.du()));
150 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
151 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
152
153 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
154 } 231 }
155 232
156 /// Check if daylight savings time is active. 233 /// Check if daylight savings time is active.
@@ -166,10 +243,6 @@ impl Rtc {
166 }) 243 })
167 } 244 }
168 245
169 pub fn get_config(&self) -> RtcConfig {
170 self.rtc_config
171 }
172
173 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; 246 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT;
174 247
175 /// Read content of the backup register. 248 /// Read content of the backup register.
@@ -215,12 +288,16 @@ pub(crate) mod sealed {
215 pub trait Instance { 288 pub trait Instance {
216 const BACKUP_REGISTER_COUNT: usize; 289 const BACKUP_REGISTER_COUNT: usize;
217 290
291 #[cfg(feature = "low-power")]
292 const EXTI_WAKEUP_LINE: usize;
293
294 #[cfg(feature = "low-power")]
295 type WakeupInterrupt: crate::interrupt::typelevel::Interrupt;
296
218 fn regs() -> Rtc { 297 fn regs() -> Rtc {
219 crate::pac::RTC 298 crate::pac::RTC
220 } 299 }
221 300
222 fn enable_peripheral_clk() {}
223
224 /// Read content of the backup register. 301 /// Read content of the backup register.
225 /// 302 ///
226 /// The registers retain their values during wakes from standby mode or system resets. They also 303 /// The registers retain their values during wakes from standby mode or system resets. They also
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index bcb127ecb..4608d3114 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -1,77 +1,21 @@
1use stm32_metapac::rtc::vals::{Init, Osel, Pol}; 1use stm32_metapac::rtc::vals::{Init, Osel, Pol};
2 2
3use super::{sealed, RtcClockSource, RtcConfig}; 3use super::sealed;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC; 5use crate::peripherals::RTC;
6use crate::rtc::sealed::Instance; 6use crate::rtc::sealed::Instance;
7 7
8#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
9pub struct RtcInstant {
10 ssr: u16,
11 st: u8,
12}
13
14#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
15impl RtcInstant {
16 pub fn now() -> Self {
17 // TODO: read value twice
18 use crate::rtc::bcd2_to_byte;
19
20 let tr = RTC::regs().tr().read();
21 let tr2 = RTC::regs().tr().read();
22 let ssr = RTC::regs().ssr().read().ss();
23 let ssr2 = RTC::regs().ssr().read().ss();
24
25 let st = bcd2_to_byte((tr.st(), tr.su()));
26 let st2 = bcd2_to_byte((tr2.st(), tr2.su()));
27
28 assert!(st == st2);
29 assert!(ssr == ssr2);
30
31 let _ = RTC::regs().dr().read();
32
33 trace!("ssr: {}", ssr);
34 trace!("st: {}", st);
35
36 Self { ssr, st }
37 }
38}
39
40#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
41impl core::ops::Sub for RtcInstant {
42 type Output = embassy_time::Duration;
43
44 fn sub(self, rhs: Self) -> Self::Output {
45 use embassy_time::{Duration, TICK_HZ};
46
47 let st = if self.st < rhs.st { self.st + 60 } else { self.st };
48
49 // TODO: read prescaler
50
51 let self_ticks = st as u32 * 256 + (255 - self.ssr as u32);
52 let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32);
53 let rtc_ticks = self_ticks - other_ticks;
54
55 trace!("self, other, rtc ticks: {}, {}, {}", self_ticks, other_ticks, rtc_ticks);
56
57 Duration::from_ticks(
58 ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32)))
59 * TICK_HZ as u32) as u32
60 / 256u32) as u64,
61 )
62 }
63}
64
65#[allow(dead_code)] 8#[allow(dead_code)]
9#[repr(u8)]
66#[derive(Clone, Copy, Debug)] 10#[derive(Clone, Copy, Debug)]
67pub(crate) enum WakeupPrescaler { 11pub(crate) enum WakeupPrescaler {
68 Div2, 12 Div2 = 2,
69 Div4, 13 Div4 = 4,
70 Div8, 14 Div8 = 8,
71 Div16, 15 Div16 = 16,
72} 16}
73 17
74#[cfg(any(stm32wb, stm32f4))] 18#[cfg(any(stm32wb, stm32f4, stm32l0))]
75impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 19impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
76 fn from(val: WakeupPrescaler) -> Self { 20 fn from(val: WakeupPrescaler) -> Self {
77 use crate::pac::rtc::vals::Wucksel; 21 use crate::pac::rtc::vals::Wucksel;
@@ -85,7 +29,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
85 } 29 }
86} 30}
87 31
88#[cfg(any(stm32wb, stm32f4))] 32#[cfg(any(stm32wb, stm32f4, stm32l0))]
89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 33impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 34 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
91 use crate::pac::rtc::vals::Wucksel; 35 use crate::pac::rtc::vals::Wucksel;
@@ -100,17 +44,6 @@ impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
100 } 44 }
101} 45}
102 46
103impl From<WakeupPrescaler> for u32 {
104 fn from(val: WakeupPrescaler) -> Self {
105 match val {
106 WakeupPrescaler::Div2 => 2,
107 WakeupPrescaler::Div4 => 4,
108 WakeupPrescaler::Div8 => 8,
109 WakeupPrescaler::Div16 => 16,
110 }
111 }
112}
113
114#[allow(dead_code)] 47#[allow(dead_code)]
115impl WakeupPrescaler { 48impl WakeupPrescaler {
116 pub fn compute_min(val: u32) -> Self { 49 pub fn compute_min(val: u32) -> Self {
@@ -121,158 +54,100 @@ impl WakeupPrescaler {
121 WakeupPrescaler::Div16, 54 WakeupPrescaler::Div16,
122 ] 55 ]
123 .iter() 56 .iter()
124 .skip_while(|psc| <WakeupPrescaler as Into<u32>>::into(**psc) <= val) 57 .skip_while(|psc| **psc as u32 <= val)
125 .next() 58 .next()
126 .unwrap_or(&WakeupPrescaler::Div16) 59 .unwrap_or(&WakeupPrescaler::Div16)
127 } 60 }
128} 61}
129 62
130impl super::Rtc { 63impl super::Rtc {
131 fn unlock_registers() { 64 #[cfg(feature = "low-power")]
132 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] 65 /// start the wakeup alarm and wtih a duration that is as close to but less than
133 let cr = crate::pac::PWR.cr(); 66 /// the requested duration, and record the instant the wakeup alarm was started
134 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] 67 pub(crate) fn start_wakeup_alarm(
135 let cr = crate::pac::PWR.cr1(); 68 &self,
136 69 requested_duration: embassy_time::Duration,
137 // TODO: Missing from PAC for l0 and f0? 70 cs: critical_section::CriticalSection,
138 #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] 71 ) {
139 {
140 if !cr.read().dbp() {
141 cr.modify(|w| w.set_dbp(true));
142 while !cr.read().dbp() {}
143 }
144 }
145 }
146
147 #[allow(dead_code)]
148 #[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
149 /// start the wakeup alarm and return the actual duration of the alarm
150 /// the actual duration will be the closest value possible that is less
151 /// than the requested duration.
152 ///
153 /// note: this api is exposed for testing purposes until low power is implemented.
154 /// it is not intended to be public
155 pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant {
156 use embassy_time::{Duration, TICK_HZ}; 72 use embassy_time::{Duration, TICK_HZ};
157 73
158 use crate::rcc::get_freqs; 74 // Panic if the rcc mod knows we're not using low-power rtc
75 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
76 unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
159 77
160 let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; 78 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
161 79 let rtc_hz = Self::frequency().0 as u64;
162 let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; 80 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
163 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); 81 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
164 82
165 // adjust the rtc ticks to the prescaler 83 // adjust the rtc ticks to the prescaler and subtract one rtc tick
166 let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64); 84 let rtc_ticks = rtc_ticks / prescaler as u64;
167 let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { 85 let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
168 u16::MAX - 1
169 } else {
170 rtc_ticks as u16
171 };
172
173 let duration = Duration::from_ticks(
174 rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz,
175 );
176
177 trace!("set wakeup timer for {} ms", duration.as_millis());
178 86
179 self.write(false, |regs| { 87 self.write(false, |regs| {
180 regs.cr().modify(|w| w.set_wutie(true));
181
182 regs.cr().modify(|w| w.set_wute(false)); 88 regs.cr().modify(|w| w.set_wute(false));
183 regs.isr().modify(|w| w.set_wutf(false)); 89 regs.isr().modify(|w| w.set_wutf(false));
184 while !regs.isr().read().wutwf() {} 90 while !regs.isr().read().wutwf() {}
185 91
186 regs.cr().modify(|w| w.set_wucksel(prescaler.into())); 92 regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
93 regs.wutr().write(|w| w.set_wut(rtc_ticks));
187 regs.cr().modify(|w| w.set_wute(true)); 94 regs.cr().modify(|w| w.set_wute(true));
95 regs.cr().modify(|w| w.set_wutie(true));
188 }); 96 });
189 97
190 RtcInstant::now() 98 trace!(
99 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
100 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
101 prescaler as u32,
102 rtc_ticks,
103 self.instant(),
104 );
105
106 assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())
191 } 107 }
192 108
193 #[allow(dead_code)] 109 #[cfg(feature = "low-power")]
194 #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] 110 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
195 /// stop the wakeup alarm and return the time remaining 111 /// was called, otherwise none
196 /// 112 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
197 /// note: this api is exposed for testing purposes until low power is implemented. 113 use crate::interrupt::typelevel::Interrupt;
198 /// it is not intended to be public 114
199 pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { 115 trace!("rtc: stop wakeup alarm at {}", self.instant());
200 trace!("disable wakeup timer...");
201 116
202 self.write(false, |regs| { 117 self.write(false, |regs| {
118 regs.cr().modify(|w| w.set_wutie(false));
203 regs.cr().modify(|w| w.set_wute(false)); 119 regs.cr().modify(|w| w.set_wute(false));
204 regs.isr().modify(|w| w.set_wutf(false)); 120 regs.isr().modify(|w| w.set_wutf(false));
205 });
206
207 RtcInstant::now()
208 }
209
210 #[allow(dead_code)]
211 pub(crate) fn set_clock_source(clock_source: RtcClockSource) {
212 #[cfg(not(rtc_v2wb))]
213 use stm32_metapac::rcc::vals::Rtcsel;
214 121
215 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 122 crate::pac::EXTI
216 let cr = crate::pac::RCC.bdcr(); 123 .pr(0)
217 #[cfg(any(rtc_v2l0, rtc_v2l1))] 124 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
218 let cr = crate::pac::RCC.csr();
219 125
220 Self::unlock_registers(); 126 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
221
222 cr.modify(|w| {
223 // Select RTC source
224 #[cfg(not(rtc_v2wb))]
225 w.set_rtcsel(Rtcsel::from_bits(clock_source as u8));
226 #[cfg(rtc_v2wb)]
227 w.set_rtcsel(clock_source as u8);
228 }); 127 });
229 }
230 128
231 pub(super) fn enable() { 129 if let Some(stop_time) = self.stop_time.borrow(cs).take() {
232 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 130 Some(self.instant() - stop_time)
233 let reg = crate::pac::RCC.bdcr().read(); 131 } else {
234 #[cfg(any(rtc_v2l0, rtc_v2l1))] 132 None
235 let reg = crate::pac::RCC.csr().read(); 133 }
236 134 }
237 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
238 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
239
240 if !reg.rtcen() {
241 Self::unlock_registers();
242
243 #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))]
244 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
245 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
246 let cr = crate::pac::RCC.bdcr();
247 #[cfg(any(rtc_v2l0, rtc_v2l1))]
248 let cr = crate::pac::RCC.csr();
249
250 cr.modify(|w| {
251 // Reset
252 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
253 w.set_bdrst(false);
254
255 w.set_rtcen(true);
256 w.set_rtcsel(reg.rtcsel());
257 135
258 // Restore bcdr 136 #[cfg(feature = "low-power")]
259 #[cfg(any(rtc_v2l4, rtc_v2wb))] 137 pub(crate) fn enable_wakeup_line(&self) {
260 w.set_lscosel(reg.lscosel()); 138 use crate::interrupt::typelevel::Interrupt;
261 #[cfg(any(rtc_v2l4, rtc_v2wb))] 139 use crate::pac::EXTI;
262 w.set_lscoen(reg.lscoen());
263 140
264 w.set_lseon(reg.lseon()); 141 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
142 unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
265 143
266 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] 144 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
267 w.set_lsedrv(reg.lsedrv()); 145 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
268 w.set_lsebyp(reg.lsebyp());
269 });
270 }
271 } 146 }
272 147
273 /// Applies the RTC config 148 /// Applies the RTC config
274 /// It this changes the RTC clock source the time will be reset 149 /// It this changes the RTC clock source the time will be reset
275 pub(super) fn configure(&mut self, rtc_config: RtcConfig) { 150 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
276 self.write(true, |rtc| { 151 self.write(true, |rtc| {
277 rtc.cr().modify(|w| { 152 rtc.cr().modify(|w| {
278 #[cfg(rtc_v2f2)] 153 #[cfg(rtc_v2f2)]
@@ -284,8 +159,8 @@ impl super::Rtc {
284 }); 159 });
285 160
286 rtc.prer().modify(|w| { 161 rtc.prer().modify(|w| {
287 w.set_prediv_s(rtc_config.sync_prescaler); 162 w.set_prediv_s(sync_psc);
288 w.set_prediv_a(rtc_config.async_prescaler); 163 w.set_prediv_a(async_psc);
289 }); 164 });
290 }); 165 });
291 } 166 }
@@ -390,21 +265,17 @@ impl super::Rtc {
390impl sealed::Instance for crate::peripherals::RTC { 265impl sealed::Instance for crate::peripherals::RTC {
391 const BACKUP_REGISTER_COUNT: usize = 20; 266 const BACKUP_REGISTER_COUNT: usize = 20;
392 267
393 fn enable_peripheral_clk() { 268 #[cfg(all(feature = "low-power", stm32f4))]
394 #[cfg(any(rtc_v2l4, rtc_v2wb))] 269 const EXTI_WAKEUP_LINE: usize = 22;
395 {
396 // enable peripheral clock for communication
397 crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
398 270
399 // read to allow the pwr clock to enable 271 #[cfg(all(feature = "low-power", stm32l0))]
400 crate::pac::PWR.cr1().read(); 272 const EXTI_WAKEUP_LINE: usize = 20;
401 } 273
402 #[cfg(any(rtc_v2f2))] 274 #[cfg(all(feature = "low-power", stm32f4))]
403 { 275 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
404 crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); 276
405 crate::pac::PWR.cr().read(); 277 #[cfg(all(feature = "low-power", stm32l0))]
406 } 278 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
407 }
408 279
409 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { 280 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
410 if register < Self::BACKUP_REGISTER_COUNT { 281 if register < Self::BACKUP_REGISTER_COUNT {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 3297303ee..a6b2655d8 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,77 +1,14 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType};
2 2
3use super::{sealed, RtcCalibrationCyclePeriod, RtcClockSource, RtcConfig}; 3use super::{sealed, RtcCalibrationCyclePeriod};
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC; 5use crate::peripherals::RTC;
6use crate::rtc::sealed::Instance; 6use crate::rtc::sealed::Instance;
7 7
8impl super::Rtc { 8impl super::Rtc {
9 fn unlock_registers() {
10 // Unlock the backup domain
11 #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
12 {
13 if !crate::pac::PWR.cr1().read().dbp() {
14 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
15 while !crate::pac::PWR.cr1().read().dbp() {}
16 }
17 }
18 #[cfg(any(rcc_wl5, rcc_wle))]
19 {
20 use crate::pac::pwr::vals::Dbp;
21
22 if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {
23 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
24 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
25 }
26 }
27 }
28
29 #[allow(dead_code)]
30 pub(crate) fn set_clock_source(clock_source: RtcClockSource) {
31 let clock_source = clock_source as u8;
32 #[cfg(not(any(rcc_wl5, rcc_wle)))]
33 let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source);
34
35 Self::unlock_registers();
36
37 crate::pac::RCC.bdcr().modify(|w| {
38 // Select RTC source
39 w.set_rtcsel(clock_source);
40 });
41 }
42
43 pub(super) fn enable() {
44 let bdcr = crate::pac::RCC.bdcr();
45
46 let reg = bdcr.read();
47 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
48
49 if !reg.rtcen() {
50 Self::unlock_registers();
51
52 bdcr.modify(|w| w.set_bdrst(true));
53
54 bdcr.modify(|w| {
55 // Reset
56 w.set_bdrst(false);
57
58 w.set_rtcen(true);
59 w.set_rtcsel(reg.rtcsel());
60
61 // Restore bcdr
62 w.set_lscosel(reg.lscosel());
63 w.set_lscoen(reg.lscoen());
64
65 w.set_lseon(reg.lseon());
66 w.set_lsedrv(reg.lsedrv());
67 w.set_lsebyp(reg.lsebyp());
68 });
69 }
70 }
71
72 /// Applies the RTC config 9 /// Applies the RTC config
73 /// It this changes the RTC clock source the time will be reset 10 /// It this changes the RTC clock source the time will be reset
74 pub(super) fn configure(&mut self, rtc_config: RtcConfig) { 11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
75 self.write(true, |rtc| { 12 self.write(true, |rtc| {
76 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
77 w.set_fmt(Fmt::TWENTYFOURHOUR); 14 w.set_fmt(Fmt::TWENTYFOURHOUR);
@@ -80,8 +17,8 @@ impl super::Rtc {
80 }); 17 });
81 18
82 rtc.prer().modify(|w| { 19 rtc.prer().modify(|w| {
83 w.set_prediv_s(rtc_config.sync_prescaler); 20 w.set_prediv_s(sync_psc);
84 w.set_prediv_a(rtc_config.async_prescaler); 21 w.set_prediv_a(async_psc);
85 }); 22 });
86 23
87 // TODO: configuration for output pins 24 // TODO: configuration for output pins
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 6b532363c..9fb380fd6 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -33,6 +33,8 @@ impl<T: Instance> InterruptHandler<T> {
33 w.set_dtimeoutie(enable); 33 w.set_dtimeoutie(enable);
34 w.set_dataendie(enable); 34 w.set_dataendie(enable);
35 35
36 #[cfg(sdmmc_v1)]
37 w.set_stbiterre(enable);
36 #[cfg(sdmmc_v2)] 38 #[cfg(sdmmc_v2)]
37 w.set_dabortie(enable); 39 w.set_dabortie(enable);
38 }); 40 });
@@ -102,6 +104,8 @@ pub enum Error {
102 BadClock, 104 BadClock,
103 SignalingSwitchFailed, 105 SignalingSwitchFailed,
104 PeripheralBusy, 106 PeripheralBusy,
107 #[cfg(sdmmc_v1)]
108 StBitErr,
105} 109}
106 110
107/// A SD command 111/// A SD command
@@ -707,9 +711,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
707 711
708 if status.dcrcfail() { 712 if status.dcrcfail() {
709 return Poll::Ready(Err(Error::Crc)); 713 return Poll::Ready(Err(Error::Crc));
710 } else if status.dtimeout() { 714 }
715 if status.dtimeout() {
711 return Poll::Ready(Err(Error::Timeout)); 716 return Poll::Ready(Err(Error::Timeout));
712 } else if status.dataend() { 717 }
718 #[cfg(sdmmc_v1)]
719 if status.stbiterr() {
720 return Poll::Ready(Err(Error::StBitErr));
721 }
722 if status.dataend() {
713 return Poll::Ready(Ok(())); 723 return Poll::Ready(Ok(()));
714 } 724 }
715 Poll::Pending 725 Poll::Pending
@@ -782,9 +792,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
782 792
783 if status.dcrcfail() { 793 if status.dcrcfail() {
784 return Poll::Ready(Err(Error::Crc)); 794 return Poll::Ready(Err(Error::Crc));
785 } else if status.dtimeout() { 795 }
796 if status.dtimeout() {
786 return Poll::Ready(Err(Error::Timeout)); 797 return Poll::Ready(Err(Error::Timeout));
787 } else if status.dataend() { 798 }
799 #[cfg(sdmmc_v1)]
800 if status.stbiterr() {
801 return Poll::Ready(Err(Error::StBitErr));
802 }
803 if status.dataend() {
788 return Poll::Ready(Ok(())); 804 return Poll::Ready(Ok(()));
789 } 805 }
790 Poll::Pending 806 Poll::Pending
@@ -836,6 +852,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
836 w.set_dataendc(true); 852 w.set_dataendc(true);
837 w.set_dbckendc(true); 853 w.set_dbckendc(true);
838 w.set_sdioitc(true); 854 w.set_sdioitc(true);
855 #[cfg(sdmmc_v1)]
856 w.set_stbiterrc(true);
839 857
840 #[cfg(sdmmc_v2)] 858 #[cfg(sdmmc_v2)]
841 { 859 {
@@ -873,9 +891,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
873 891
874 if status.dcrcfail() { 892 if status.dcrcfail() {
875 return Poll::Ready(Err(Error::Crc)); 893 return Poll::Ready(Err(Error::Crc));
876 } else if status.dtimeout() { 894 }
895 if status.dtimeout() {
877 return Poll::Ready(Err(Error::Timeout)); 896 return Poll::Ready(Err(Error::Timeout));
878 } else if status.dataend() { 897 }
898 #[cfg(sdmmc_v1)]
899 if status.stbiterr() {
900 return Poll::Ready(Err(Error::StBitErr));
901 }
902 if status.dataend() {
879 return Poll::Ready(Ok(())); 903 return Poll::Ready(Ok(()));
880 } 904 }
881 Poll::Pending 905 Poll::Pending
@@ -1156,9 +1180,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1156 1180
1157 if status.dcrcfail() { 1181 if status.dcrcfail() {
1158 return Poll::Ready(Err(Error::Crc)); 1182 return Poll::Ready(Err(Error::Crc));
1159 } else if status.dtimeout() { 1183 }
1184 if status.dtimeout() {
1160 return Poll::Ready(Err(Error::Timeout)); 1185 return Poll::Ready(Err(Error::Timeout));
1161 } else if status.dataend() { 1186 }
1187 #[cfg(sdmmc_v1)]
1188 if status.stbiterr() {
1189 return Poll::Ready(Err(Error::StBitErr));
1190 }
1191 if status.dataend() {
1162 return Poll::Ready(Ok(())); 1192 return Poll::Ready(Ok(()));
1163 } 1193 }
1164 Poll::Pending 1194 Poll::Pending
@@ -1207,9 +1237,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1207 1237
1208 if status.dcrcfail() { 1238 if status.dcrcfail() {
1209 return Poll::Ready(Err(Error::Crc)); 1239 return Poll::Ready(Err(Error::Crc));
1210 } else if status.dtimeout() { 1240 }
1241 if status.dtimeout() {
1211 return Poll::Ready(Err(Error::Timeout)); 1242 return Poll::Ready(Err(Error::Timeout));
1212 } else if status.dataend() { 1243 }
1244 #[cfg(sdmmc_v1)]
1245 if status.stbiterr() {
1246 return Poll::Ready(Err(Error::StBitErr));
1247 }
1248 if status.dataend() {
1213 return Poll::Ready(Ok(())); 1249 return Poll::Ready(Ok(()));
1214 } 1250 }
1215 Poll::Pending 1251 Poll::Pending
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index e2bc8d7f2..f40bce784 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -323,7 +323,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
323 } 323 }
324 324
325 /// Reconfigures it with the supplied config. 325 /// Reconfigures it with the supplied config.
326 pub fn reconfigure(&mut self, config: Config) { 326 pub fn set_config(&mut self, config: Config) {
327 let cpha = config.raw_phase(); 327 let cpha = config.raw_phase();
328 let cpol = config.raw_polarity(); 328 let cpol = config.raw_polarity();
329 329
@@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
646 self.sck.as_ref().map(|x| x.set_as_disconnected()); 646 self.sck.as_ref().map(|x| x.set_as_disconnected());
647 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 647 self.mosi.as_ref().map(|x| x.set_as_disconnected());
648 self.miso.as_ref().map(|x| x.set_as_disconnected()); 648 self.miso.as_ref().map(|x| x.set_as_disconnected());
649
650 T::disable();
649 } 651 }
650} 652}
651 653
@@ -1060,6 +1062,6 @@ foreach_peripheral!(
1060impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { 1062impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> {
1061 type Config = Config; 1063 type Config = Config;
1062 fn set_config(&mut self, config: &Self::Config) { 1064 fn set_config(&mut self, config: &Self::Config) {
1063 self.reconfigure(*config); 1065 self.set_config(*config);
1064 } 1066 }
1065} 1067}
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 2622442f4..5b01937f5 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -14,6 +14,8 @@ use stm32_metapac::timer::regs;
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::timer::vals; 15use crate::pac::timer::vals;
16use crate::rcc::sealed::RccPeripheral; 16use crate::rcc::sealed::RccPeripheral;
17#[cfg(feature = "low-power")]
18use crate::rtc::Rtc;
17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; 19use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
18use crate::{interrupt, peripherals}; 20use crate::{interrupt, peripherals};
19 21
@@ -130,12 +132,14 @@ impl AlarmState {
130 } 132 }
131} 133}
132 134
133struct RtcDriver { 135pub(crate) struct RtcDriver {
134 /// Number of 2^15 periods elapsed since boot. 136 /// Number of 2^15 periods elapsed since boot.
135 period: AtomicU32, 137 period: AtomicU32,
136 alarm_count: AtomicU8, 138 alarm_count: AtomicU8,
137 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 139 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
138 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, 140 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
141 #[cfg(feature = "low-power")]
142 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
139} 143}
140 144
141const ALARM_STATE_NEW: AlarmState = AlarmState::new(); 145const ALARM_STATE_NEW: AlarmState = AlarmState::new();
@@ -144,6 +148,8 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
144 period: AtomicU32::new(0), 148 period: AtomicU32::new(0),
145 alarm_count: AtomicU8::new(0), 149 alarm_count: AtomicU8::new(0),
146 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), 150 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
151 #[cfg(feature = "low-power")]
152 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
147}); 153});
148 154
149impl RtcDriver { 155impl RtcDriver {
@@ -259,6 +265,127 @@ impl RtcDriver {
259 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; 265 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
260 f(alarm.ctx.get()); 266 f(alarm.ctx.get());
261 } 267 }
268
269 /*
270 Low-power private functions: all operate within a critical seciton
271 */
272
273 #[cfg(feature = "low-power")]
274 /// Compute the approximate amount of time until the next alarm
275 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
276 let now = self.now() + 32;
277
278 embassy_time::Duration::from_ticks(
279 self.alarms
280 .borrow(cs)
281 .iter()
282 .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now))
283 .min()
284 .unwrap_or(u64::MAX),
285 )
286 }
287
288 #[cfg(feature = "low-power")]
289 /// Add the given offset to the current time
290 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
291 let offset = offset.as_ticks();
292 let cnt = T::regs_gp16().cnt().read().cnt() as u32;
293 let period = self.period.load(Ordering::SeqCst);
294
295 // Correct the race, if it exists
296 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
297 period + 1
298 } else {
299 period
300 };
301
302 // Normalize to the full overflow
303 let period = (period / 2) * 2;
304
305 // Add the offset
306 let period = period + 2 * (offset / u16::MAX as u64) as u32;
307 let cnt = cnt + (offset % u16::MAX as u64) as u32;
308
309 let (cnt, period) = if cnt > u16::MAX as u32 {
310 (cnt - u16::MAX as u32, period + 2)
311 } else {
312 (cnt, period)
313 };
314
315 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
316
317 self.period.store(period, Ordering::SeqCst);
318 T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
319
320 // Now, recompute all alarms
321 for i in 0..ALARM_COUNT {
322 let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
323 let alarm = self.get_alarm(cs, alarm_handle);
324
325 self.set_alarm(alarm_handle, alarm.timestamp.get());
326 }
327 }
328
329 #[cfg(feature = "low-power")]
330 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
331 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
332 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) {
333 self.add_time(offset, cs);
334 }
335 }
336
337 /*
338 Low-power public functions: all create a critical section
339 */
340 #[cfg(feature = "low-power")]
341 /// Set the rtc but panic if it's already been set
342 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
343 critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
344 }
345
346 #[cfg(feature = "low-power")]
347 /// Pause the timer if ready; return err if not
348 pub(crate) fn pause_time(&self) -> Result<(), ()> {
349 critical_section::with(|cs| {
350 /*
351 If the wakeup timer is currently running, then we need to stop it and
352 add the elapsed time to the current time, as this will impact the result
353 of `time_until_next_alarm`.
354 */
355 self.stop_wakeup_alarm(cs);
356
357 let time_until_next_alarm = self.time_until_next_alarm(cs);
358 if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
359 Err(())
360 } else {
361 self.rtc
362 .borrow(cs)
363 .get()
364 .unwrap()
365 .start_wakeup_alarm(time_until_next_alarm, cs);
366
367 T::regs_gp16().cr1().modify(|w| w.set_cen(false));
368
369 Ok(())
370 }
371 })
372 }
373
374 #[cfg(feature = "low-power")]
375 /// Resume the timer with the given offset
376 pub(crate) fn resume_time(&self) {
377 if T::regs_gp16().cr1().read().cen() {
378 // Time isn't currently stopped
379
380 return;
381 }
382
383 critical_section::with(|cs| {
384 self.stop_wakeup_alarm(cs);
385
386 T::regs_gp16().cr1().modify(|w| w.set_cen(true));
387 })
388 }
262} 389}
263 390
264impl Driver for RtcDriver { 391impl Driver for RtcDriver {
@@ -329,6 +456,11 @@ impl Driver for RtcDriver {
329 } 456 }
330} 457}
331 458
459#[cfg(feature = "low-power")]
460pub(crate) fn get_driver() -> &'static RtcDriver {
461 &DRIVER
462}
463
332pub(crate) fn init() { 464pub(crate) fn init() {
333 DRIVER.init() 465 DRIVER.init()
334} 466}
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 4ffb2a289..1d642ed37 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,4 +1,5 @@
1pub mod complementary_pwm; 1pub mod complementary_pwm;
2pub mod qei;
2pub mod simple_pwm; 3pub mod simple_pwm;
3 4
4use stm32_metapac::timer::vals; 5use stm32_metapac::timer::vals;
@@ -14,6 +15,7 @@ pub mod low_level {
14} 15}
15 16
16pub(crate) mod sealed { 17pub(crate) mod sealed {
18
17 use super::*; 19 use super::*;
18 pub trait Basic16bitInstance: RccPeripheral { 20 pub trait Basic16bitInstance: RccPeripheral {
19 type Interrupt: interrupt::typelevel::Interrupt; 21 type Interrupt: interrupt::typelevel::Interrupt;
@@ -31,10 +33,16 @@ pub(crate) mod sealed {
31 fn clear_update_interrupt(&mut self) -> bool; 33 fn clear_update_interrupt(&mut self) -> bool;
32 34
33 fn enable_update_interrupt(&mut self, enable: bool); 35 fn enable_update_interrupt(&mut self, enable: bool);
36
37 fn set_autoreload_preload(&mut self, enable: vals::Arpe);
34 } 38 }
35 39
36 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 40 pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
37 fn regs_gp16() -> crate::pac::timer::TimGp16; 41 fn regs_gp16() -> crate::pac::timer::TimGp16;
42
43 fn set_count_direction(&mut self, direction: vals::Dir);
44
45 fn set_clock_division(&mut self, ckd: vals::Ckd);
38 } 46 }
39 47
40 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { 48 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
@@ -48,6 +56,18 @@ pub(crate) mod sealed {
48 } 56 }
49 57
50 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { 58 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
59 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
60
61 fn clear_input_interrupt(&mut self, channel: Channel);
62
63 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
64
65 fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
66
67 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
68
69 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
70
51 /// Global output enable. Does not do anything on non-advanced timers. 71 /// Global output enable. Does not do anything on non-advanced timers.
52 fn enable_outputs(&mut self, enable: bool); 72 fn enable_outputs(&mut self, enable: bool);
53 73
@@ -59,6 +79,8 @@ pub(crate) mod sealed {
59 79
60 fn set_compare_value(&mut self, channel: Channel, value: u16); 80 fn set_compare_value(&mut self, channel: Channel, value: u16);
61 81
82 fn get_capture_value(&mut self, channel: Channel) -> u16;
83
62 fn get_max_compare_value(&self) -> u16; 84 fn get_max_compare_value(&self) -> u16;
63 } 85 }
64 86
@@ -73,6 +95,18 @@ pub(crate) mod sealed {
73 } 95 }
74 96
75 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { 97 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
98 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
99
100 fn clear_input_interrupt(&mut self, channel: Channel);
101
102 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
103
104 fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
105
106 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
107
108 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
109
76 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 110 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
77 111
78 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); 112 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
@@ -81,6 +115,8 @@ pub(crate) mod sealed {
81 115
82 fn set_compare_value(&mut self, channel: Channel, value: u32); 116 fn set_compare_value(&mut self, channel: Channel, value: u32);
83 117
118 fn get_capture_value(&mut self, channel: Channel) -> u32;
119
84 fn get_max_compare_value(&self) -> u32; 120 fn get_max_compare_value(&self) -> u32;
85 } 121 }
86} 122}
@@ -105,6 +141,30 @@ impl Channel {
105} 141}
106 142
107#[derive(Clone, Copy)] 143#[derive(Clone, Copy)]
144pub enum InputCaptureMode {
145 Rising,
146 Falling,
147 BothEdges,
148}
149
150#[derive(Clone, Copy)]
151pub enum InputTISelection {
152 Normal,
153 Alternate,
154 TRC,
155}
156
157impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
158 fn from(tisel: InputTISelection) -> Self {
159 match tisel {
160 InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
161 InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
162 InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
163 }
164 }
165}
166
167#[derive(Clone, Copy)]
108pub enum OutputCompareMode { 168pub enum OutputCompareMode {
109 Frozen, 169 Frozen,
110 ActiveOnMatch, 170 ActiveOnMatch,
@@ -211,6 +271,7 @@ macro_rules! impl_basic_16bit_timer {
211 use core::convert::TryInto; 271 use core::convert::TryInto;
212 let f = frequency.0; 272 let f = frequency.0;
213 let timer_f = Self::frequency().0; 273 let timer_f = Self::frequency().0;
274 assert!(f > 0);
214 let pclk_ticks_per_timer_period = timer_f / f; 275 let pclk_ticks_per_timer_period = timer_f / f;
215 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); 276 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
216 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); 277 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
@@ -240,6 +301,10 @@ macro_rules! impl_basic_16bit_timer {
240 fn enable_update_interrupt(&mut self, enable: bool) { 301 fn enable_update_interrupt(&mut self, enable: bool) {
241 Self::regs().dier().write(|r| r.set_uie(enable)); 302 Self::regs().dier().write(|r| r.set_uie(enable));
242 } 303 }
304
305 fn set_autoreload_preload(&mut self, enable: vals::Arpe) {
306 Self::regs().cr1().modify(|r| r.set_arpe(enable));
307 }
243 } 308 }
244 }; 309 };
245} 310}
@@ -255,6 +320,7 @@ macro_rules! impl_32bit_timer {
255 fn set_frequency(&mut self, frequency: Hertz) { 320 fn set_frequency(&mut self, frequency: Hertz) {
256 use core::convert::TryInto; 321 use core::convert::TryInto;
257 let f = frequency.0; 322 let f = frequency.0;
323 assert!(f > 0);
258 let timer_f = Self::frequency().0; 324 let timer_f = Self::frequency().0;
259 let pclk_ticks_per_timer_period = (timer_f / f) as u64; 325 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
260 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); 326 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
@@ -276,6 +342,59 @@ macro_rules! impl_32bit_timer {
276macro_rules! impl_compare_capable_16bit { 342macro_rules! impl_compare_capable_16bit {
277 ($inst:ident) => { 343 ($inst:ident) => {
278 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 344 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
345 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
346 use sealed::GeneralPurpose16bitInstance;
347 let raw_channel = channel.raw();
348 Self::regs_gp16()
349 .ccmr_input(raw_channel / 2)
350 .modify(|r| r.set_icf(raw_channel % 2, icf));
351 }
352
353 fn clear_input_interrupt(&mut self, channel: Channel) {
354 use sealed::GeneralPurpose16bitInstance;
355 Self::regs_gp16()
356 .sr()
357 .modify(|r| r.set_ccif(channel.raw(), false));
358 }
359
360 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
361 use sealed::GeneralPurpose16bitInstance;
362 Self::regs_gp16()
363 .dier()
364 .modify(|r| r.set_ccie(channel.raw(), enable));
365 }
366 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
367 use sealed::GeneralPurpose16bitInstance;
368 let raw_channel = channel.raw();
369 Self::regs_gp16()
370 .ccmr_input(raw_channel / 2)
371 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
372 }
373
374 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
375 use sealed::GeneralPurpose16bitInstance;
376 let raw_channel = channel.raw();
377 Self::regs_gp16()
378 .ccmr_input(raw_channel / 2)
379 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
380 }
381 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
382 use sealed::GeneralPurpose16bitInstance;
383 Self::regs_gp16().ccer().modify(|r| match mode {
384 InputCaptureMode::Rising => {
385 r.set_ccnp(channel.raw(), false);
386 r.set_ccp(channel.raw(), false);
387 }
388 InputCaptureMode::Falling => {
389 r.set_ccnp(channel.raw(), false);
390 r.set_ccp(channel.raw(), true);
391 }
392 InputCaptureMode::BothEdges => {
393 r.set_ccnp(channel.raw(), true);
394 r.set_ccp(channel.raw(), true);
395 }
396 });
397 }
279 fn enable_outputs(&mut self, _enable: bool) {} 398 fn enable_outputs(&mut self, _enable: bool) {}
280 399
281 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 400 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
@@ -305,6 +424,11 @@ macro_rules! impl_compare_capable_16bit {
305 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 424 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
306 } 425 }
307 426
427 fn get_capture_value(&mut self, channel: Channel) -> u16 {
428 use sealed::GeneralPurpose16bitInstance;
429 Self::regs_gp16().ccr(channel.raw()).read().ccr()
430 }
431
308 fn get_max_compare_value(&self) -> u16 { 432 fn get_max_compare_value(&self) -> u16 {
309 use sealed::GeneralPurpose16bitInstance; 433 use sealed::GeneralPurpose16bitInstance;
310 Self::regs_gp16().arr().read().arr() 434 Self::regs_gp16().arr().read().arr()
@@ -329,6 +453,14 @@ foreach_interrupt! {
329 fn regs_gp16() -> crate::pac::timer::TimGp16 { 453 fn regs_gp16() -> crate::pac::timer::TimGp16 {
330 crate::pac::$inst 454 crate::pac::$inst
331 } 455 }
456
457 fn set_count_direction(&mut self, direction: vals::Dir) {
458 Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
459 }
460
461 fn set_clock_division(&mut self, ckd: vals::Ckd) {
462 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
463 }
332 } 464 }
333 }; 465 };
334 466
@@ -343,6 +475,59 @@ foreach_interrupt! {
343 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} 475 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
344 476
345 impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { 477 impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
478 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
479 use sealed::GeneralPurpose32bitInstance;
480 let raw_channel = channel.raw();
481 Self::regs_gp32()
482 .ccmr_input(raw_channel / 2)
483 .modify(|r| r.set_icf(raw_channel % 2, icf));
484 }
485
486 fn clear_input_interrupt(&mut self, channel: Channel) {
487 use sealed::GeneralPurpose32bitInstance;
488 Self::regs_gp32()
489 .sr()
490 .modify(|r| r.set_ccif(channel.raw(), false));
491 }
492 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
493 use sealed::GeneralPurpose32bitInstance;
494 Self::regs_gp32()
495 .dier()
496 .modify(|r| r.set_ccie(channel.raw(), enable));
497 }
498 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
499 use crate::timer::sealed::GeneralPurpose32bitInstance;
500 let raw_channel = channel.raw();
501 Self::regs_gp32()
502 .ccmr_input(raw_channel / 2)
503 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
504 }
505
506 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
507 use crate::timer::sealed::GeneralPurpose32bitInstance;
508 let raw_channel = channel.raw();
509 Self::regs_gp32()
510 .ccmr_input(raw_channel / 2)
511 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
512 }
513
514 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
515 use crate::timer::sealed::GeneralPurpose32bitInstance;
516 Self::regs_gp32().ccer().modify(|r| match mode {
517 InputCaptureMode::Rising => {
518 r.set_ccnp(channel.raw(), false);
519 r.set_ccp(channel.raw(), false);
520 }
521 InputCaptureMode::Falling => {
522 r.set_ccnp(channel.raw(), false);
523 r.set_ccp(channel.raw(), true);
524 }
525 InputCaptureMode::BothEdges => {
526 r.set_ccnp(channel.raw(), true);
527 r.set_ccp(channel.raw(), true);
528 }
529 });
530 }
346 fn set_output_compare_mode( 531 fn set_output_compare_mode(
347 &mut self, 532 &mut self,
348 channel: Channel, 533 channel: Channel,
@@ -370,6 +555,11 @@ foreach_interrupt! {
370 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 555 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
371 } 556 }
372 557
558 fn get_capture_value(&mut self, channel: Channel) -> u32 {
559 use crate::timer::sealed::GeneralPurpose32bitInstance;
560 Self::regs_gp32().ccr(channel.raw()).read().ccr()
561 }
562
373 fn get_max_compare_value(&self) -> u32 { 563 fn get_max_compare_value(&self) -> u32 {
374 use crate::timer::sealed::GeneralPurpose32bitInstance; 564 use crate::timer::sealed::GeneralPurpose32bitInstance;
375 Self::regs_gp32().arr().read().arr() as u32 565 Self::regs_gp32().arr().read().arr() as u32
@@ -380,6 +570,14 @@ foreach_interrupt! {
380 fn regs_gp16() -> crate::pac::timer::TimGp16 { 570 fn regs_gp16() -> crate::pac::timer::TimGp16 {
381 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 571 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
382 } 572 }
573
574 fn set_count_direction(&mut self, direction: vals::Dir) {
575 Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
576 }
577
578 fn set_clock_division(&mut self, ckd: vals::Ckd) {
579 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
580 }
383 } 581 }
384 }; 582 };
385 583
@@ -396,6 +594,14 @@ foreach_interrupt! {
396 fn regs_gp16() -> crate::pac::timer::TimGp16 { 594 fn regs_gp16() -> crate::pac::timer::TimGp16 {
397 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 595 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
398 } 596 }
597
598 fn set_count_direction(&mut self, direction: vals::Dir) {
599 Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
600 }
601
602 fn set_clock_division(&mut self, ckd: vals::Ckd) {
603 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
604 }
399 } 605 }
400 606
401 impl sealed::AdvancedControlInstance for crate::peripherals::$inst { 607 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
@@ -405,6 +611,57 @@ foreach_interrupt! {
405 } 611 }
406 612
407 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 613 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
614 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
615 use crate::timer::sealed::AdvancedControlInstance;
616 let raw_channel = channel.raw();
617 Self::regs_advanced()
618 .ccmr_input(raw_channel / 2)
619 .modify(|r| r.set_icf(raw_channel % 2, icf));
620 }
621
622 fn clear_input_interrupt(&mut self, channel: Channel) {
623 use crate::timer::sealed::AdvancedControlInstance;
624 Self::regs_advanced()
625 .sr()
626 .modify(|r| r.set_ccif(channel.raw(), false));
627 }
628 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
629 use crate::timer::sealed::AdvancedControlInstance;
630 Self::regs_advanced()
631 .dier()
632 .modify(|r| r.set_ccie(channel.raw(), enable));
633 }
634 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
635 use crate::timer::sealed::AdvancedControlInstance;
636 let raw_channel = channel.raw();
637 Self::regs_advanced()
638 .ccmr_input(raw_channel / 2)
639 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
640 }
641 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
642 use crate::timer::sealed::AdvancedControlInstance;
643 let raw_channel = channel.raw();
644 Self::regs_advanced()
645 .ccmr_input(raw_channel / 2)
646 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
647 }
648 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
649 use crate::timer::sealed::AdvancedControlInstance;
650 Self::regs_advanced().ccer().modify(|r| match mode {
651 InputCaptureMode::Rising => {
652 r.set_ccnp(channel.raw(), false);
653 r.set_ccp(channel.raw(), false);
654 }
655 InputCaptureMode::Falling => {
656 r.set_ccnp(channel.raw(), false);
657 r.set_ccp(channel.raw(), true);
658 }
659 InputCaptureMode::BothEdges => {
660 r.set_ccnp(channel.raw(), true);
661 r.set_ccp(channel.raw(), true);
662 }
663 });
664 }
408 fn enable_outputs(&mut self, enable: bool) { 665 fn enable_outputs(&mut self, enable: bool) {
409 use crate::timer::sealed::AdvancedControlInstance; 666 use crate::timer::sealed::AdvancedControlInstance;
410 let r = Self::regs_advanced(); 667 let r = Self::regs_advanced();
@@ -437,6 +694,11 @@ foreach_interrupt! {
437 .modify(|w| w.set_cce(channel.raw(), enable)); 694 .modify(|w| w.set_cce(channel.raw(), enable));
438 } 695 }
439 696
697 fn get_capture_value(&mut self, channel: Channel) -> u16 {
698 use crate::timer::sealed::AdvancedControlInstance;
699 Self::regs_advanced().ccr(channel.raw()).read().ccr()
700 }
701
440 fn set_compare_value(&mut self, channel: Channel, value: u16) { 702 fn set_compare_value(&mut self, channel: Channel, value: u16) {
441 use crate::timer::sealed::AdvancedControlInstance; 703 use crate::timer::sealed::AdvancedControlInstance;
442 Self::regs_advanced() 704 Self::regs_advanced()
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
new file mode 100644
index 000000000..15f2c3a79
--- /dev/null
+++ b/embassy-stm32/src/timer/qei.rs
@@ -0,0 +1,96 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::{into_ref, PeripheralRef};
4
5use super::*;
6use crate::gpio::sealed::AFType;
7use crate::gpio::AnyPin;
8use crate::Peripheral;
9
10pub enum Direction {
11 Upcounting,
12 Downcounting,
13}
14
15pub struct Ch1;
16pub struct Ch2;
17
18pub struct QeiPin<'d, Perip, Channel> {
19 _pin: PeripheralRef<'d, AnyPin>,
20 phantom: PhantomData<(Perip, Channel)>,
21}
22
23macro_rules! channel_impl {
24 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
25 impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> {
26 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
27 into_ref!(pin);
28 critical_section::with(|_| {
29 pin.set_low();
30 pin.set_as_af(pin.af_num(), AFType::Input);
31 #[cfg(gpio_v2)]
32 pin.set_speed(crate::gpio::Speed::VeryHigh);
33 });
34 QeiPin {
35 _pin: pin.map_into(),
36 phantom: PhantomData,
37 }
38 }
39 }
40 };
41}
42
43channel_impl!(new_ch1, Ch1, Channel1Pin);
44channel_impl!(new_ch2, Ch2, Channel2Pin);
45
46pub struct Qei<'d, T> {
47 _inner: PeripheralRef<'d, T>,
48}
49
50impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
51 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
52 Self::new_inner(tim)
53 }
54
55 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
56 into_ref!(tim);
57
58 T::enable();
59 <T as crate::rcc::sealed::RccPeripheral>::reset();
60
61 // Configure TxC1 and TxC2 as captures
62 T::regs_gp16().ccmr_input(0).modify(|w| {
63 w.set_ccs(0, vals::CcmrInputCcs::TI4);
64 w.set_ccs(1, vals::CcmrInputCcs::TI4);
65 });
66
67 // enable and configure to capture on rising edge
68 T::regs_gp16().ccer().modify(|w| {
69 w.set_cce(0, true);
70 w.set_cce(1, true);
71
72 w.set_ccp(0, false);
73 w.set_ccp(1, false);
74 });
75
76 T::regs_gp16().smcr().modify(|w| {
77 w.set_sms(vals::Sms::ENCODER_MODE_3);
78 });
79
80 T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX));
81 T::regs_gp16().cr1().modify(|w| w.set_cen(true));
82
83 Self { _inner: tim }
84 }
85
86 pub fn read_direction(&self) -> Direction {
87 match T::regs_gp16().cr1().read().dir() {
88 vals::Dir::DOWN => Direction::Downcounting,
89 vals::Dir::UP => Direction::Upcounting,
90 }
91 }
92
93 pub fn count(&self) -> u16 {
94 T::regs_gp16().cnt().read().cnt()
95 }
96}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 596d40bf9..e2d6e42af 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -114,6 +114,30 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
114 phantom: PhantomData<&'d mut T>, 114 phantom: PhantomData<&'d mut T>,
115} 115}
116 116
117impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> {
118 type Config = Config;
119
120 fn set_config(&mut self, config: &Self::Config) {
121 unwrap!(self.set_config(config))
122 }
123}
124
125impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> {
126 type Config = Config;
127
128 fn set_config(&mut self, config: &Self::Config) {
129 unwrap!(self.set_config(config))
130 }
131}
132
133impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
134 type Config = Config;
135
136 fn set_config(&mut self, config: &Self::Config) {
137 unwrap!(self.set_config(config))
138 }
139}
140
117impl<'d, T: BasicInstance> BufferedUart<'d, T> { 141impl<'d, T: BasicInstance> BufferedUart<'d, T> {
118 pub fn new( 142 pub fn new(
119 peri: impl Peripheral<P = T> + 'd, 143 peri: impl Peripheral<P = T> + 'd,
@@ -123,7 +147,9 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
123 tx_buffer: &'d mut [u8], 147 tx_buffer: &'d mut [u8],
124 rx_buffer: &'d mut [u8], 148 rx_buffer: &'d mut [u8],
125 config: Config, 149 config: Config,
126 ) -> BufferedUart<'d, T> { 150 ) -> Result<Self, ConfigError> {
151 // UartRx and UartTx have one refcount ea.
152 T::enable();
127 T::enable(); 153 T::enable();
128 T::reset(); 154 T::reset();
129 155
@@ -140,9 +166,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
140 tx_buffer: &'d mut [u8], 166 tx_buffer: &'d mut [u8],
141 rx_buffer: &'d mut [u8], 167 rx_buffer: &'d mut [u8],
142 config: Config, 168 config: Config,
143 ) -> BufferedUart<'d, T> { 169 ) -> Result<Self, ConfigError> {
144 into_ref!(cts, rts); 170 into_ref!(cts, rts);
145 171
172 // UartRx and UartTx have one refcount ea.
173 T::enable();
146 T::enable(); 174 T::enable();
147 T::reset(); 175 T::reset();
148 176
@@ -166,9 +194,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
166 tx_buffer: &'d mut [u8], 194 tx_buffer: &'d mut [u8],
167 rx_buffer: &'d mut [u8], 195 rx_buffer: &'d mut [u8],
168 config: Config, 196 config: Config,
169 ) -> BufferedUart<'d, T> { 197 ) -> Result<Self, ConfigError> {
170 into_ref!(de); 198 into_ref!(de);
171 199
200 // UartRx and UartTx have one refcount ea.
201 T::enable();
172 T::enable(); 202 T::enable();
173 T::reset(); 203 T::reset();
174 204
@@ -187,7 +217,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
187 tx_buffer: &'d mut [u8], 217 tx_buffer: &'d mut [u8],
188 rx_buffer: &'d mut [u8], 218 rx_buffer: &'d mut [u8],
189 config: Config, 219 config: Config,
190 ) -> BufferedUart<'d, T> { 220 ) -> Result<Self, ConfigError> {
191 into_ref!(_peri, rx, tx); 221 into_ref!(_peri, rx, tx);
192 222
193 let state = T::buffered_state(); 223 let state = T::buffered_state();
@@ -200,7 +230,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
200 rx.set_as_af(rx.af_num(), AFType::Input); 230 rx.set_as_af(rx.af_num(), AFType::Input);
201 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 231 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
202 232
203 configure(r, &config, T::frequency(), T::KIND, true, true); 233 configure(r, &config, T::frequency(), T::KIND, true, true)?;
204 234
205 r.cr1().modify(|w| { 235 r.cr1().modify(|w| {
206 #[cfg(lpuart_v2)] 236 #[cfg(lpuart_v2)]
@@ -213,15 +243,19 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
213 T::Interrupt::unpend(); 243 T::Interrupt::unpend();
214 unsafe { T::Interrupt::enable() }; 244 unsafe { T::Interrupt::enable() };
215 245
216 Self { 246 Ok(Self {
217 rx: BufferedUartRx { phantom: PhantomData }, 247 rx: BufferedUartRx { phantom: PhantomData },
218 tx: BufferedUartTx { phantom: PhantomData }, 248 tx: BufferedUartTx { phantom: PhantomData },
219 } 249 })
220 } 250 }
221 251
222 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { 252 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
223 (self.tx, self.rx) 253 (self.tx, self.rx)
224 } 254 }
255
256 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
257 reconfigure::<T>(config)
258 }
225} 259}
226 260
227impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { 261impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
@@ -298,6 +332,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
298 T::Interrupt::pend(); 332 T::Interrupt::pend();
299 } 333 }
300 } 334 }
335
336 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
337 reconfigure::<T>(config)
338 }
301} 339}
302 340
303impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { 341impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
@@ -368,6 +406,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
368 } 406 }
369 } 407 }
370 } 408 }
409
410 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
411 reconfigure::<T>(config)
412 }
371} 413}
372 414
373impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { 415impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
@@ -382,6 +424,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
382 T::Interrupt::disable(); 424 T::Interrupt::disable();
383 } 425 }
384 } 426 }
427
428 T::disable();
385 } 429 }
386} 430}
387 431
@@ -397,12 +441,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
397 T::Interrupt::disable(); 441 T::Interrupt::disable();
398 } 442 }
399 } 443 }
400 }
401}
402 444
403impl embedded_io_async::Error for Error { 445 T::disable();
404 fn kind(&self) -> embedded_io_async::ErrorKind {
405 embedded_io_async::ErrorKind::Other
406 } 446 }
407} 447}
408 448
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 255ddfd4b..9835f1ace 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -5,6 +5,7 @@ use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::drop::OnDrop; 9use embassy_hal_internal::drop::OnDrop;
9use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
10use futures::future::{select, Either}; 11use futures::future::{select, Either};
@@ -12,11 +13,10 @@ use futures::future::{select, Either};
12use crate::dma::{NoDma, Transfer}; 13use crate::dma::{NoDma, Transfer};
13use crate::gpio::sealed::AFType; 14use crate::gpio::sealed::AFType;
14use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
15#[cfg(not(any(usart_v1, usart_v2)))]
16#[allow(unused_imports)] 16#[allow(unused_imports)]
17#[cfg(not(any(usart_v1, usart_v2)))]
17use crate::pac::usart::regs::Isr as Sr; 18use crate::pac::usart::regs::Isr as Sr;
18#[cfg(any(usart_v1, usart_v2))] 19#[cfg(any(usart_v1, usart_v2))]
19#[allow(unused_imports)]
20use crate::pac::usart::regs::Sr; 20use crate::pac::usart::regs::Sr;
21#[cfg(not(any(usart_v1, usart_v2)))] 21#[cfg(not(any(usart_v1, usart_v2)))]
22use crate::pac::usart::Lpuart as Regs; 22use crate::pac::usart::Lpuart as Regs;
@@ -75,12 +75,14 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
75} 75}
76 76
77#[derive(Clone, Copy, PartialEq, Eq, Debug)] 77#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78pub enum DataBits { 79pub enum DataBits {
79 DataBits8, 80 DataBits8,
80 DataBits9, 81 DataBits9,
81} 82}
82 83
83#[derive(Clone, Copy, PartialEq, Eq, Debug)] 84#[derive(Clone, Copy, PartialEq, Eq, Debug)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
84pub enum Parity { 86pub enum Parity {
85 ParityNone, 87 ParityNone,
86 ParityEven, 88 ParityEven,
@@ -88,6 +90,7 @@ pub enum Parity {
88} 90}
89 91
90#[derive(Clone, Copy, PartialEq, Eq, Debug)] 92#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub enum StopBits { 94pub enum StopBits {
92 #[doc = "1 stop bit"] 95 #[doc = "1 stop bit"]
93 STOP1, 96 STOP1,
@@ -101,6 +104,14 @@ pub enum StopBits {
101 104
102#[non_exhaustive] 105#[non_exhaustive]
103#[derive(Clone, Copy, PartialEq, Eq, Debug)] 106#[derive(Clone, Copy, PartialEq, Eq, Debug)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub enum ConfigError {
109 BaudrateTooLow,
110 BaudrateTooHigh,
111}
112
113#[non_exhaustive]
114#[derive(Clone, Copy, PartialEq, Eq, Debug)]
104pub struct Config { 115pub struct Config {
105 pub baudrate: u32, 116 pub baudrate: u32,
106 pub data_bits: DataBits, 117 pub data_bits: DataBits,
@@ -168,11 +179,28 @@ pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
168 rx: UartRx<'d, T, RxDma>, 179 rx: UartRx<'d, T, RxDma>,
169} 180}
170 181
182impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> {
183 type Config = Config;
184
185 fn set_config(&mut self, config: &Self::Config) {
186 unwrap!(self.tx.set_config(config));
187 unwrap!(self.rx.set_config(config));
188 }
189}
190
171pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 191pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
172 phantom: PhantomData<&'d mut T>, 192 phantom: PhantomData<&'d mut T>,
173 tx_dma: PeripheralRef<'d, TxDma>, 193 tx_dma: PeripheralRef<'d, TxDma>,
174} 194}
175 195
196impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
197 type Config = Config;
198
199 fn set_config(&mut self, config: &Self::Config) {
200 unwrap!(self.set_config(config));
201 }
202}
203
176pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 204pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
177 _peri: PeripheralRef<'d, T>, 205 _peri: PeripheralRef<'d, T>,
178 rx_dma: PeripheralRef<'d, RxDma>, 206 rx_dma: PeripheralRef<'d, RxDma>,
@@ -181,6 +209,14 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
181 buffered_sr: stm32_metapac::usart::regs::Sr, 209 buffered_sr: stm32_metapac::usart::regs::Sr,
182} 210}
183 211
212impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> {
213 type Config = Config;
214
215 fn set_config(&mut self, config: &Self::Config) {
216 unwrap!(self.set_config(config));
217 }
218}
219
184impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { 220impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
185 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 221 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
186 pub fn new( 222 pub fn new(
@@ -188,7 +224,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
188 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 224 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
189 tx_dma: impl Peripheral<P = TxDma> + 'd, 225 tx_dma: impl Peripheral<P = TxDma> + 'd,
190 config: Config, 226 config: Config,
191 ) -> Self { 227 ) -> Result<Self, ConfigError> {
192 T::enable(); 228 T::enable();
193 T::reset(); 229 T::reset();
194 230
@@ -201,7 +237,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
201 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 237 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
202 tx_dma: impl Peripheral<P = TxDma> + 'd, 238 tx_dma: impl Peripheral<P = TxDma> + 'd,
203 config: Config, 239 config: Config,
204 ) -> Self { 240 ) -> Result<Self, ConfigError> {
205 into_ref!(cts); 241 into_ref!(cts);
206 242
207 T::enable(); 243 T::enable();
@@ -219,22 +255,26 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
219 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 255 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
220 tx_dma: impl Peripheral<P = TxDma> + 'd, 256 tx_dma: impl Peripheral<P = TxDma> + 'd,
221 config: Config, 257 config: Config,
222 ) -> Self { 258 ) -> Result<Self, ConfigError> {
223 into_ref!(_peri, tx, tx_dma); 259 into_ref!(_peri, tx, tx_dma);
224 260
225 let r = T::regs(); 261 let r = T::regs();
226 262
227 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 263 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
228 264
229 configure(r, &config, T::frequency(), T::KIND, false, true); 265 configure(r, &config, T::frequency(), T::KIND, false, true)?;
230 266
231 // create state once! 267 // create state once!
232 let _s = T::state(); 268 let _s = T::state();
233 269
234 Self { 270 Ok(Self {
235 tx_dma, 271 tx_dma,
236 phantom: PhantomData, 272 phantom: PhantomData,
237 } 273 })
274 }
275
276 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
277 reconfigure::<T>(config)
238 } 278 }
239 279
240 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 280 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
@@ -277,7 +317,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
277 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 317 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
278 rx_dma: impl Peripheral<P = RxDma> + 'd, 318 rx_dma: impl Peripheral<P = RxDma> + 'd,
279 config: Config, 319 config: Config,
280 ) -> Self { 320 ) -> Result<Self, ConfigError> {
281 T::enable(); 321 T::enable();
282 T::reset(); 322 T::reset();
283 323
@@ -291,7 +331,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
291 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 331 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
292 rx_dma: impl Peripheral<P = RxDma> + 'd, 332 rx_dma: impl Peripheral<P = RxDma> + 'd,
293 config: Config, 333 config: Config,
294 ) -> Self { 334 ) -> Result<Self, ConfigError> {
295 into_ref!(rts); 335 into_ref!(rts);
296 336
297 T::enable(); 337 T::enable();
@@ -310,14 +350,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
310 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 350 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
311 rx_dma: impl Peripheral<P = RxDma> + 'd, 351 rx_dma: impl Peripheral<P = RxDma> + 'd,
312 config: Config, 352 config: Config,
313 ) -> Self { 353 ) -> Result<Self, ConfigError> {
314 into_ref!(peri, rx, rx_dma); 354 into_ref!(peri, rx, rx_dma);
315 355
316 let r = T::regs(); 356 let r = T::regs();
317 357
318 rx.set_as_af(rx.af_num(), AFType::Input); 358 rx.set_as_af(rx.af_num(), AFType::Input);
319 359
320 configure(r, &config, T::frequency(), T::KIND, true, false); 360 configure(r, &config, T::frequency(), T::KIND, true, false)?;
321 361
322 T::Interrupt::unpend(); 362 T::Interrupt::unpend();
323 unsafe { T::Interrupt::enable() }; 363 unsafe { T::Interrupt::enable() };
@@ -325,13 +365,17 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
325 // create state once! 365 // create state once!
326 let _s = T::state(); 366 let _s = T::state();
327 367
328 Self { 368 Ok(Self {
329 _peri: peri, 369 _peri: peri,
330 rx_dma, 370 rx_dma,
331 detect_previous_overrun: config.detect_previous_overrun, 371 detect_previous_overrun: config.detect_previous_overrun,
332 #[cfg(any(usart_v1, usart_v2))] 372 #[cfg(any(usart_v1, usart_v2))]
333 buffered_sr: stm32_metapac::usart::regs::Sr(0), 373 buffered_sr: stm32_metapac::usart::regs::Sr(0),
334 } 374 })
375 }
376
377 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
378 reconfigure::<T>(config)
335 } 379 }
336 380
337 #[cfg(any(usart_v1, usart_v2))] 381 #[cfg(any(usart_v1, usart_v2))]
@@ -545,6 +589,13 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
545 unsafe { rdr(r).read_volatile() }; 589 unsafe { rdr(r).read_volatile() };
546 clear_interrupt_flags(r, sr); 590 clear_interrupt_flags(r, sr);
547 591
592 if enable_idle_line_detection {
593 // enable idle interrupt
594 r.cr1().modify(|w| {
595 w.set_idleie(true);
596 });
597 }
598
548 compiler_fence(Ordering::SeqCst); 599 compiler_fence(Ordering::SeqCst);
549 600
550 let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); 601 let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
@@ -618,6 +669,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
618 } 669 }
619} 670}
620 671
672impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> {
673 fn drop(&mut self) {
674 T::disable();
675 }
676}
677
678impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
679 fn drop(&mut self) {
680 T::disable();
681 }
682}
683
621impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { 684impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
622 pub fn new( 685 pub fn new(
623 peri: impl Peripheral<P = T> + 'd, 686 peri: impl Peripheral<P = T> + 'd,
@@ -627,7 +690,9 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
627 tx_dma: impl Peripheral<P = TxDma> + 'd, 690 tx_dma: impl Peripheral<P = TxDma> + 'd,
628 rx_dma: impl Peripheral<P = RxDma> + 'd, 691 rx_dma: impl Peripheral<P = RxDma> + 'd,
629 config: Config, 692 config: Config,
630 ) -> Self { 693 ) -> Result<Self, ConfigError> {
694 // UartRx and UartTx have one refcount ea.
695 T::enable();
631 T::enable(); 696 T::enable();
632 T::reset(); 697 T::reset();
633 698
@@ -644,9 +709,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
644 tx_dma: impl Peripheral<P = TxDma> + 'd, 709 tx_dma: impl Peripheral<P = TxDma> + 'd,
645 rx_dma: impl Peripheral<P = RxDma> + 'd, 710 rx_dma: impl Peripheral<P = RxDma> + 'd,
646 config: Config, 711 config: Config,
647 ) -> Self { 712 ) -> Result<Self, ConfigError> {
648 into_ref!(cts, rts); 713 into_ref!(cts, rts);
649 714
715 // UartRx and UartTx have one refcount ea.
716 T::enable();
650 T::enable(); 717 T::enable();
651 T::reset(); 718 T::reset();
652 719
@@ -669,9 +736,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
669 tx_dma: impl Peripheral<P = TxDma> + 'd, 736 tx_dma: impl Peripheral<P = TxDma> + 'd,
670 rx_dma: impl Peripheral<P = RxDma> + 'd, 737 rx_dma: impl Peripheral<P = RxDma> + 'd,
671 config: Config, 738 config: Config,
672 ) -> Self { 739 ) -> Result<Self, ConfigError> {
673 into_ref!(de); 740 into_ref!(de);
674 741
742 // UartRx and UartTx have one refcount ea.
743 T::enable();
675 T::enable(); 744 T::enable();
676 T::reset(); 745 T::reset();
677 746
@@ -689,7 +758,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
689 tx_dma: impl Peripheral<P = TxDma> + 'd, 758 tx_dma: impl Peripheral<P = TxDma> + 'd,
690 rx_dma: impl Peripheral<P = RxDma> + 'd, 759 rx_dma: impl Peripheral<P = RxDma> + 'd,
691 config: Config, 760 config: Config,
692 ) -> Self { 761 ) -> Result<Self, ConfigError> {
693 into_ref!(peri, rx, tx, tx_dma, rx_dma); 762 into_ref!(peri, rx, tx, tx_dma, rx_dma);
694 763
695 let r = T::regs(); 764 let r = T::regs();
@@ -711,7 +780,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
711 } 780 }
712 } 781 }
713 782
714 configure(r, &config, T::frequency(), T::KIND, true, true); 783 configure(r, &config, T::frequency(), T::KIND, true, true)?;
715 784
716 T::Interrupt::unpend(); 785 T::Interrupt::unpend();
717 unsafe { T::Interrupt::enable() }; 786 unsafe { T::Interrupt::enable() };
@@ -719,7 +788,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
719 // create state once! 788 // create state once!
720 let _s = T::state(); 789 let _s = T::state();
721 790
722 Self { 791 Ok(Self {
723 tx: UartTx { 792 tx: UartTx {
724 tx_dma, 793 tx_dma,
725 phantom: PhantomData, 794 phantom: PhantomData,
@@ -731,7 +800,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
731 #[cfg(any(usart_v1, usart_v2))] 800 #[cfg(any(usart_v1, usart_v2))]
732 buffered_sr: stm32_metapac::usart::regs::Sr(0), 801 buffered_sr: stm32_metapac::usart::regs::Sr(0),
733 }, 802 },
734 } 803 })
804 }
805
806 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
807 reconfigure::<T>(config)
735 } 808 }
736 809
737 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 810 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
@@ -779,7 +852,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
779 } 852 }
780} 853}
781 854
782fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { 855fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> {
856 T::Interrupt::disable();
857 let r = T::regs();
858
859 let cr = r.cr1().read();
860 configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?;
861
862 T::Interrupt::unpend();
863 unsafe { T::Interrupt::enable() };
864
865 Ok(())
866}
867
868fn configure(
869 r: Regs,
870 config: &Config,
871 pclk_freq: Hertz,
872 kind: Kind,
873 enable_rx: bool,
874 enable_tx: bool,
875) -> Result<(), ConfigError> {
783 if !enable_rx && !enable_tx { 876 if !enable_rx && !enable_tx {
784 panic!("USART: At least one of RX or TX should be enabled"); 877 panic!("USART: At least one of RX or TX should be enabled");
785 } 878 }
@@ -847,7 +940,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
847 found_brr = Some(brr); 940 found_brr = Some(brr);
848 break; 941 break;
849 } 942 }
850 panic!("USART: baudrate too high"); 943 return Err(ConfigError::BaudrateTooHigh);
851 } 944 }
852 945
853 if brr < brr_max { 946 if brr < brr_max {
@@ -859,7 +952,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
859 } 952 }
860 } 953 }
861 954
862 let brr = found_brr.expect("USART: baudrate too low"); 955 let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?;
863 956
864 #[cfg(not(usart_v1))] 957 #[cfg(not(usart_v1))]
865 let oversampling = if over8 { "8 bit" } else { "16 bit" }; 958 let oversampling = if over8 { "8 bit" } else { "16 bit" };
@@ -905,12 +998,16 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
905 }); 998 });
906 #[cfg(not(usart_v1))] 999 #[cfg(not(usart_v1))]
907 w.set_over8(vals::Over8::from_bits(over8 as _)); 1000 w.set_over8(vals::Over8::from_bits(over8 as _));
1001 #[cfg(usart_v4)]
1002 w.set_fifoen(true);
908 }); 1003 });
909 1004
910 #[cfg(not(usart_v1))] 1005 #[cfg(not(usart_v1))]
911 r.cr3().modify(|w| { 1006 r.cr3().modify(|w| {
912 w.set_onebit(config.assume_noise_free); 1007 w.set_onebit(config.assume_noise_free);
913 }); 1008 });
1009
1010 Ok(())
914} 1011}
915 1012
916mod eh02 { 1013mod eh02 {
@@ -1012,20 +1109,61 @@ mod eh1 {
1012 } 1109 }
1013} 1110}
1014 1111
1015#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 1112impl embedded_io::Error for Error {
1016mod eio { 1113 fn kind(&self) -> embedded_io::ErrorKind {
1017 use embedded_io_async::{ErrorType, Write}; 1114 embedded_io::ErrorKind::Other
1115 }
1116}
1018 1117
1019 use super::*; 1118impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma>
1119where
1120 T: BasicInstance,
1121{
1122 type Error = Error;
1123}
1020 1124
1021 impl<T, TxDma, RxDma> ErrorType for Uart<'_, T, TxDma, RxDma> 1125impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma>
1022 where 1126where
1023 T: BasicInstance, 1127 T: BasicInstance,
1024 { 1128{
1025 type Error = Error; 1129 type Error = Error;
1130}
1131
1132impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma>
1133where
1134 T: BasicInstance,
1135 TxDma: crate::usart::TxDma<T>,
1136{
1137 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1138 self.blocking_write(buf)?;
1139 Ok(buf.len())
1140 }
1141
1142 fn flush(&mut self) -> Result<(), Self::Error> {
1143 self.blocking_flush()
1144 }
1145}
1146
1147impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma>
1148where
1149 T: BasicInstance,
1150 TxDma: crate::usart::TxDma<T>,
1151{
1152 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1153 self.blocking_write(buf)?;
1154 Ok(buf.len())
1026 } 1155 }
1027 1156
1028 impl<T, TxDma, RxDma> Write for Uart<'_, T, TxDma, RxDma> 1157 fn flush(&mut self) -> Result<(), Self::Error> {
1158 self.blocking_flush()
1159 }
1160}
1161
1162#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
1163mod eio {
1164 use super::*;
1165
1166 impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma>
1029 where 1167 where
1030 T: BasicInstance, 1168 T: BasicInstance,
1031 TxDma: super::TxDma<T>, 1169 TxDma: super::TxDma<T>,
@@ -1040,14 +1178,7 @@ mod eio {
1040 } 1178 }
1041 } 1179 }
1042 1180
1043 impl<T, TxDma> ErrorType for UartTx<'_, T, TxDma> 1181 impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma>
1044 where
1045 T: BasicInstance,
1046 {
1047 type Error = Error;
1048 }
1049
1050 impl<T, TxDma> Write for UartTx<'_, T, TxDma>
1051 where 1182 where
1052 T: BasicInstance, 1183 T: BasicInstance,
1053 TxDma: super::TxDma<T>, 1184 TxDma: super::TxDma<T>,
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b3f570624..347aae7c9 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,11 +1,13 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::mem;
2use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
3use core::task::Poll; 4use core::task::Poll;
4 5
6use embassy_embedded_hal::SetConfig;
5use embassy_hal_internal::PeripheralRef; 7use embassy_hal_internal::PeripheralRef;
6use futures::future::{select, Either}; 8use futures::future::{select, Either};
7 9
8use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx}; 10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
9use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
10use crate::usart::{Regs, Sr}; 12use crate::usart::{Regs, Sr};
11 13
@@ -14,6 +16,14 @@ pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
14 ring_buf: ReadableRingBuffer<'d, RxDma, u8>, 16 ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
15} 17}
16 18
19impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUartRx<'d, T, RxDma> {
20 type Config = Config;
21
22 fn set_config(&mut self, config: &Self::Config) {
23 unwrap!(self.set_config(config));
24 }
25}
26
17impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { 27impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
18 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 28 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
19 /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the 29 /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the
@@ -24,12 +34,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
24 let request = self.rx_dma.request(); 34 let request = self.rx_dma.request();
25 let opts = Default::default(); 35 let opts = Default::default();
26 36
27 let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 37 // Safety: we forget the struct before this function returns.
38 let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
39 let _peri = unsafe { self._peri.clone_unchecked() };
28 40
29 RingBufferedUartRx { 41 let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
30 _peri: self._peri, 42
31 ring_buf, 43 // Don't disable the clock
32 } 44 mem::forget(self);
45
46 RingBufferedUartRx { _peri, ring_buf }
33 } 47 }
34} 48}
35 49
@@ -49,6 +63,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
49 Err(err) 63 Err(err)
50 } 64 }
51 65
66 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
67 self.teardown_uart();
68 reconfigure::<T>(config)
69 }
70
52 /// Start uart background receive 71 /// Start uart background receive
53 fn setup_uart(&mut self) { 72 fn setup_uart(&mut self) {
54 // fence before starting DMA. 73 // fence before starting DMA.
@@ -186,6 +205,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
186impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> { 205impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> {
187 fn drop(&mut self) { 206 fn drop(&mut self) {
188 self.teardown_uart(); 207 self.teardown_uart();
208
209 T::disable();
189 } 210 }
190} 211}
191/// Return an error result if the Sr register has errors 212/// Return an error result if the Sr register has errors
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index cef196355..b24fc74eb 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -264,10 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> {
264 let regs = T::regs(); 264 let regs = T::regs();
265 265
266 #[cfg(stm32l5)] 266 #[cfg(stm32l5)]
267 { 267 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
268 crate::peripherals::PWR::enable();
269 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
270 }
271 268
272 #[cfg(pwr_h5)] 269 #[cfg(pwr_h5)]
273 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); 270 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 348f0f79d..1fe010bbb 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -540,10 +540,7 @@ impl<'d, T: Instance> Bus<'d, T> {
540impl<'d, T: Instance> Bus<'d, T> { 540impl<'d, T: Instance> Bus<'d, T> {
541 fn init(&mut self) { 541 fn init(&mut self) {
542 #[cfg(stm32l4)] 542 #[cfg(stm32l4)]
543 { 543 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
544 crate::peripherals::PWR::enable();
545 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
546 }
547 544
548 #[cfg(stm32f7)] 545 #[cfg(stm32f7)]
549 { 546 {
@@ -618,15 +615,10 @@ impl<'d, T: Instance> Bus<'d, T> {
618 { 615 {
619 // Enable USB power 616 // Enable USB power
620 critical_section::with(|_| { 617 critical_section::with(|_| {
621 crate::pac::RCC.ahb3enr().modify(|w| {
622 w.set_pwren(true);
623 });
624 cortex_m::asm::delay(2);
625
626 crate::pac::PWR.svmcr().modify(|w| { 618 crate::pac::PWR.svmcr().modify(|w| {
627 w.set_usv(true); 619 w.set_usv(true);
628 w.set_uvmen(true); 620 w.set_uvmen(true);
629 }); 621 })
630 }); 622 });
631 623
632 // Wait for USB power to stabilize 624 // Wait for USB power to stabilize
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index a60f3f7c4..2c53dd0f8 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -5,6 +5,13 @@ 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.3.0 - 2023-09-14
9
10- switch to embedded-io 0.5
11- add api for polling channels with context
12- standardise fn names on channels
13- add zero-copy channel
14
8## 0.2.0 - 2023-04-13 15## 0.2.0 - 2023-04-13
9 16
10- pubsub: Fix messages not getting popped when the last subscriber that needed them gets dropped. 17- pubsub: Fix messages not getting popped when the last subscriber that needed them gets dropped.
@@ -19,4 +26,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19 26
20## 0.1.0 - 2022-08-26 27## 0.1.0 - 2022-08-26
21 28
22- First release \ No newline at end of file 29- First release
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index 94d6799e5..f7739f305 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-sync" 2name = "embassy-sync"
3version = "0.2.0" 3version = "0.3.0"
4edition = "2021" 4edition = "2021"
5description = "no-std, no-alloc synchronization primitives with async support" 5description = "no-std, no-alloc synchronization primitives with async support"
6repository = "https://github.com/embassy-rs/embassy" 6repository = "https://github.com/embassy-rs/embassy"
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 62ea1307d..a512e0c41 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -471,7 +471,7 @@ where
471 } 471 }
472 472
473 fn lock<R>(&self, f: impl FnOnce(&mut ChannelState<T, N>) -> R) -> R { 473 fn lock<R>(&self, f: impl FnOnce(&mut ChannelState<T, N>) -> R) -> R {
474 self.inner.lock(|rc| f(&mut *rc.borrow_mut())) 474 self.inner.lock(|rc| f(&mut *unwrap!(rc.try_borrow_mut())))
475 } 475 }
476 476
477 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> { 477 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-sync/src/fmt.rs
+++ b/embassy-sync/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 53d95d081..8a9f841ee 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -17,3 +17,4 @@ pub mod pipe;
17pub mod pubsub; 17pub mod pubsub;
18pub mod signal; 18pub mod signal;
19pub mod waitqueue; 19pub mod waitqueue;
20pub mod zerocopy_channel;
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index fcf056d36..72459d660 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -149,7 +149,7 @@ where
149{ 149{
150 fn drop(&mut self) { 150 fn drop(&mut self) {
151 self.mutex.state.lock(|s| { 151 self.mutex.state.lock(|s| {
152 let mut s = s.borrow_mut(); 152 let mut s = unwrap!(s.try_borrow_mut());
153 s.locked = false; 153 s.locked = false;
154 s.waker.wake(); 154 s.waker.wake();
155 }) 155 })
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index 21d451ea6..ec0cbbf2a 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -1,7 +1,8 @@
1//! Async byte stream pipe. 1//! Async byte stream pipe.
2 2
3use core::cell::RefCell; 3use core::cell::{RefCell, UnsafeCell};
4use core::future::Future; 4use core::future::Future;
5use core::ops::Range;
5use core::pin::Pin; 6use core::pin::Pin;
6use core::task::{Context, Poll}; 7use core::task::{Context, Poll};
7 8
@@ -82,17 +83,6 @@ where
82 pipe: &'p Pipe<M, N>, 83 pipe: &'p Pipe<M, N>,
83} 84}
84 85
85impl<'p, M, const N: usize> Clone for Reader<'p, M, N>
86where
87 M: RawMutex,
88{
89 fn clone(&self) -> Self {
90 Reader { pipe: self.pipe }
91 }
92}
93
94impl<'p, M, const N: usize> Copy for Reader<'p, M, N> where M: RawMutex {}
95
96impl<'p, M, const N: usize> Reader<'p, M, N> 86impl<'p, M, const N: usize> Reader<'p, M, N>
97where 87where
98 M: RawMutex, 88 M: RawMutex,
@@ -110,6 +100,29 @@ where
110 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> { 100 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> {
111 self.pipe.try_read(buf) 101 self.pipe.try_read(buf)
112 } 102 }
103
104 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
105 ///
106 /// If no bytes are currently available to read, this function waits until at least one byte is available.
107 ///
108 /// If the reader is at end-of-file (EOF), an empty slice is returned.
109 pub fn fill_buf(&mut self) -> FillBufFuture<'_, M, N> {
110 FillBufFuture { pipe: Some(self.pipe) }
111 }
112
113 /// Try returning contents of the internal buffer.
114 ///
115 /// If no bytes are currently available to read, this function returns `Err(TryReadError::Empty)`.
116 ///
117 /// If the reader is at end-of-file (EOF), an empty slice is returned.
118 pub fn try_fill_buf(&mut self) -> Result<&[u8], TryReadError> {
119 unsafe { self.pipe.try_fill_buf_with_context(None) }
120 }
121
122 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
123 pub fn consume(&mut self, amt: usize) {
124 self.pipe.consume(amt)
125 }
113} 126}
114 127
115/// Future returned by [`Pipe::read`] and [`Reader::read`]. 128/// Future returned by [`Pipe::read`] and [`Reader::read`].
@@ -138,6 +151,35 @@ where
138 151
139impl<'p, M, const N: usize> Unpin for ReadFuture<'p, M, N> where M: RawMutex {} 152impl<'p, M, const N: usize> Unpin for ReadFuture<'p, M, N> where M: RawMutex {}
140 153
154/// Future returned by [`Pipe::fill_buf`] and [`Reader::fill_buf`].
155#[must_use = "futures do nothing unless you `.await` or poll them"]
156pub struct FillBufFuture<'p, M, const N: usize>
157where
158 M: RawMutex,
159{
160 pipe: Option<&'p Pipe<M, N>>,
161}
162
163impl<'p, M, const N: usize> Future for FillBufFuture<'p, M, N>
164where
165 M: RawMutex,
166{
167 type Output = &'p [u8];
168
169 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
170 let pipe = self.pipe.take().unwrap();
171 match unsafe { pipe.try_fill_buf_with_context(Some(cx)) } {
172 Ok(buf) => Poll::Ready(buf),
173 Err(TryReadError::Empty) => {
174 self.pipe = Some(pipe);
175 Poll::Pending
176 }
177 }
178 }
179}
180
181impl<'p, M, const N: usize> Unpin for FillBufFuture<'p, M, N> where M: RawMutex {}
182
141/// Error returned by [`try_read`](Pipe::try_read). 183/// Error returned by [`try_read`](Pipe::try_read).
142#[derive(PartialEq, Eq, Clone, Copy, Debug)] 184#[derive(PartialEq, Eq, Clone, Copy, Debug)]
143#[cfg_attr(feature = "defmt", derive(defmt::Format))] 185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -162,67 +204,24 @@ struct PipeState<const N: usize> {
162 write_waker: WakerRegistration, 204 write_waker: WakerRegistration,
163} 205}
164 206
165impl<const N: usize> PipeState<N> { 207#[repr(transparent)]
166 const fn new() -> Self { 208struct Buffer<const N: usize>(UnsafeCell<[u8; N]>);
167 PipeState {
168 buffer: RingBuffer::new(),
169 read_waker: WakerRegistration::new(),
170 write_waker: WakerRegistration::new(),
171 }
172 }
173
174 fn clear(&mut self) {
175 self.buffer.clear();
176 self.write_waker.wake();
177 }
178
179 fn try_read(&mut self, buf: &mut [u8]) -> Result<usize, TryReadError> {
180 self.try_read_with_context(None, buf)
181 }
182
183 fn try_read_with_context(&mut self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result<usize, TryReadError> {
184 if self.buffer.is_full() {
185 self.write_waker.wake();
186 }
187
188 let available = self.buffer.pop_buf();
189 if available.is_empty() {
190 if let Some(cx) = cx {
191 self.read_waker.register(cx.waker());
192 }
193 return Err(TryReadError::Empty);
194 }
195
196 let n = available.len().min(buf.len());
197 buf[..n].copy_from_slice(&available[..n]);
198 self.buffer.pop(n);
199 Ok(n)
200 }
201 209
202 fn try_write(&mut self, buf: &[u8]) -> Result<usize, TryWriteError> { 210impl<const N: usize> Buffer<N> {
203 self.try_write_with_context(None, buf) 211 unsafe fn get<'a>(&self, r: Range<usize>) -> &'a [u8] {
212 let p = self.0.get() as *const u8;
213 core::slice::from_raw_parts(p.add(r.start), r.end - r.start)
204 } 214 }
205 215
206 fn try_write_with_context(&mut self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result<usize, TryWriteError> { 216 unsafe fn get_mut<'a>(&self, r: Range<usize>) -> &'a mut [u8] {
207 if self.buffer.is_empty() { 217 let p = self.0.get() as *mut u8;
208 self.read_waker.wake(); 218 core::slice::from_raw_parts_mut(p.add(r.start), r.end - r.start)
209 }
210
211 let available = self.buffer.push_buf();
212 if available.is_empty() {
213 if let Some(cx) = cx {
214 self.write_waker.register(cx.waker());
215 }
216 return Err(TryWriteError::Full);
217 }
218
219 let n = available.len().min(buf.len());
220 available[..n].copy_from_slice(&buf[..n]);
221 self.buffer.push(n);
222 Ok(n)
223 } 219 }
224} 220}
225 221
222unsafe impl<const N: usize> Send for Buffer<N> {}
223unsafe impl<const N: usize> Sync for Buffer<N> {}
224
226/// A bounded byte-oriented pipe for communicating between asynchronous tasks 225/// A bounded byte-oriented pipe for communicating between asynchronous tasks
227/// with backpressure. 226/// with backpressure.
228/// 227///
@@ -234,6 +233,7 @@ pub struct Pipe<M, const N: usize>
234where 233where
235 M: RawMutex, 234 M: RawMutex,
236{ 235{
236 buf: Buffer<N>,
237 inner: Mutex<M, RefCell<PipeState<N>>>, 237 inner: Mutex<M, RefCell<PipeState<N>>>,
238} 238}
239 239
@@ -252,7 +252,12 @@ where
252 /// ``` 252 /// ```
253 pub const fn new() -> Self { 253 pub const fn new() -> Self {
254 Self { 254 Self {
255 inner: Mutex::new(RefCell::new(PipeState::new())), 255 buf: Buffer(UnsafeCell::new([0; N])),
256 inner: Mutex::new(RefCell::new(PipeState {
257 buffer: RingBuffer::new(),
258 read_waker: WakerRegistration::new(),
259 write_waker: WakerRegistration::new(),
260 })),
256 } 261 }
257 } 262 }
258 263
@@ -261,21 +266,91 @@ where
261 } 266 }
262 267
263 fn try_read_with_context(&self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result<usize, TryReadError> { 268 fn try_read_with_context(&self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result<usize, TryReadError> {
264 self.lock(|c| c.try_read_with_context(cx, buf)) 269 self.inner.lock(|rc: &RefCell<PipeState<N>>| {
270 let s = &mut *rc.borrow_mut();
271
272 if s.buffer.is_full() {
273 s.write_waker.wake();
274 }
275
276 let available = unsafe { self.buf.get(s.buffer.pop_buf()) };
277 if available.is_empty() {
278 if let Some(cx) = cx {
279 s.read_waker.register(cx.waker());
280 }
281 return Err(TryReadError::Empty);
282 }
283
284 let n = available.len().min(buf.len());
285 buf[..n].copy_from_slice(&available[..n]);
286 s.buffer.pop(n);
287 Ok(n)
288 })
265 } 289 }
266 290
267 fn try_write_with_context(&self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result<usize, TryWriteError> { 291 // safety: While the returned slice is alive,
268 self.lock(|c| c.try_write_with_context(cx, buf)) 292 // no `read` or `consume` methods in the pipe must be called.
293 unsafe fn try_fill_buf_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<&[u8], TryReadError> {
294 self.inner.lock(|rc: &RefCell<PipeState<N>>| {
295 let s = &mut *rc.borrow_mut();
296
297 if s.buffer.is_full() {
298 s.write_waker.wake();
299 }
300
301 let available = unsafe { self.buf.get(s.buffer.pop_buf()) };
302 if available.is_empty() {
303 if let Some(cx) = cx {
304 s.read_waker.register(cx.waker());
305 }
306 return Err(TryReadError::Empty);
307 }
308
309 Ok(available)
310 })
269 } 311 }
270 312
271 /// Get a writer for this pipe. 313 fn consume(&self, amt: usize) {
272 pub fn writer(&self) -> Writer<'_, M, N> { 314 self.inner.lock(|rc: &RefCell<PipeState<N>>| {
273 Writer { pipe: self } 315 let s = &mut *rc.borrow_mut();
316 let available = s.buffer.pop_buf();
317 assert!(amt <= available.len());
318 s.buffer.pop(amt);
319 })
274 } 320 }
275 321
276 /// Get a reader for this pipe. 322 fn try_write_with_context(&self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result<usize, TryWriteError> {
277 pub fn reader(&self) -> Reader<'_, M, N> { 323 self.inner.lock(|rc: &RefCell<PipeState<N>>| {
278 Reader { pipe: self } 324 let s = &mut *rc.borrow_mut();
325
326 if s.buffer.is_empty() {
327 s.read_waker.wake();
328 }
329
330 let available = unsafe { self.buf.get_mut(s.buffer.push_buf()) };
331 if available.is_empty() {
332 if let Some(cx) = cx {
333 s.write_waker.register(cx.waker());
334 }
335 return Err(TryWriteError::Full);
336 }
337
338 let n = available.len().min(buf.len());
339 available[..n].copy_from_slice(&buf[..n]);
340 s.buffer.push(n);
341 Ok(n)
342 })
343 }
344
345 /// Split this pipe into a BufRead-capable reader and a writer.
346 ///
347 /// The reader and writer borrow the current pipe mutably, so it is not
348 /// possible to use it directly while they exist. This is needed because
349 /// implementing `BufRead` requires there is a single reader.
350 ///
351 /// The writer is cloneable, the reader is not.
352 pub fn split(&mut self) -> (Reader<'_, M, N>, Writer<'_, M, N>) {
353 (Reader { pipe: self }, Writer { pipe: self })
279 } 354 }
280 355
281 /// Write some bytes to the pipe. 356 /// Write some bytes to the pipe.
@@ -312,7 +387,7 @@ where
312 /// or return an error if the pipe is empty. See [`write`](Self::write) for a variant 387 /// or return an error if the pipe is empty. See [`write`](Self::write) for a variant
313 /// that waits instead of returning an error. 388 /// that waits instead of returning an error.
314 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> { 389 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> {
315 self.lock(|c| c.try_write(buf)) 390 self.try_write_with_context(None, buf)
316 } 391 }
317 392
318 /// Read some bytes from the pipe. 393 /// Read some bytes from the pipe.
@@ -339,12 +414,17 @@ where
339 /// or return an error if the pipe is empty. See [`read`](Self::read) for a variant 414 /// or return an error if the pipe is empty. See [`read`](Self::read) for a variant
340 /// that waits instead of returning an error. 415 /// that waits instead of returning an error.
341 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> { 416 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> {
342 self.lock(|c| c.try_read(buf)) 417 self.try_read_with_context(None, buf)
343 } 418 }
344 419
345 /// Clear the data in the pipe's buffer. 420 /// Clear the data in the pipe's buffer.
346 pub fn clear(&self) { 421 pub fn clear(&self) {
347 self.lock(|c| c.clear()) 422 self.inner.lock(|rc: &RefCell<PipeState<N>>| {
423 let s = &mut *rc.borrow_mut();
424
425 s.buffer.clear();
426 s.write_waker.wake();
427 })
348 } 428 }
349 429
350 /// Return whether the pipe is full (no free space in the buffer) 430 /// Return whether the pipe is full (no free space in the buffer)
@@ -433,6 +513,16 @@ mod io_impls {
433 } 513 }
434 } 514 }
435 515
516 impl<M: RawMutex, const N: usize> embedded_io_async::BufRead for Reader<'_, M, N> {
517 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
518 Ok(Reader::fill_buf(self).await)
519 }
520
521 fn consume(&mut self, amt: usize) {
522 Reader::consume(self, amt)
523 }
524 }
525
436 impl<M: RawMutex, const N: usize> embedded_io_async::ErrorType for Writer<'_, M, N> { 526 impl<M: RawMutex, const N: usize> embedded_io_async::ErrorType for Writer<'_, M, N> {
437 type Error = Infallible; 527 type Error = Infallible;
438 } 528 }
@@ -457,43 +547,39 @@ mod tests {
457 use super::*; 547 use super::*;
458 use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; 548 use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
459 549
460 fn capacity<const N: usize>(c: &PipeState<N>) -> usize {
461 N - c.buffer.len()
462 }
463
464 #[test] 550 #[test]
465 fn writing_once() { 551 fn writing_once() {
466 let mut c = PipeState::<3>::new(); 552 let c = Pipe::<NoopRawMutex, 3>::new();
467 assert!(c.try_write(&[1]).is_ok()); 553 assert!(c.try_write(&[1]).is_ok());
468 assert_eq!(capacity(&c), 2); 554 assert_eq!(c.free_capacity(), 2);
469 } 555 }
470 556
471 #[test] 557 #[test]
472 fn writing_when_full() { 558 fn writing_when_full() {
473 let mut c = PipeState::<3>::new(); 559 let c = Pipe::<NoopRawMutex, 3>::new();
474 assert_eq!(c.try_write(&[42]), Ok(1)); 560 assert_eq!(c.try_write(&[42]), Ok(1));
475 assert_eq!(c.try_write(&[43]), Ok(1)); 561 assert_eq!(c.try_write(&[43]), Ok(1));
476 assert_eq!(c.try_write(&[44]), Ok(1)); 562 assert_eq!(c.try_write(&[44]), Ok(1));
477 assert_eq!(c.try_write(&[45]), Err(TryWriteError::Full)); 563 assert_eq!(c.try_write(&[45]), Err(TryWriteError::Full));
478 assert_eq!(capacity(&c), 0); 564 assert_eq!(c.free_capacity(), 0);
479 } 565 }
480 566
481 #[test] 567 #[test]
482 fn receiving_once_with_one_send() { 568 fn receiving_once_with_one_send() {
483 let mut c = PipeState::<3>::new(); 569 let c = Pipe::<NoopRawMutex, 3>::new();
484 assert!(c.try_write(&[42]).is_ok()); 570 assert!(c.try_write(&[42]).is_ok());
485 let mut buf = [0; 16]; 571 let mut buf = [0; 16];
486 assert_eq!(c.try_read(&mut buf), Ok(1)); 572 assert_eq!(c.try_read(&mut buf), Ok(1));
487 assert_eq!(buf[0], 42); 573 assert_eq!(buf[0], 42);
488 assert_eq!(capacity(&c), 3); 574 assert_eq!(c.free_capacity(), 3);
489 } 575 }
490 576
491 #[test] 577 #[test]
492 fn receiving_when_empty() { 578 fn receiving_when_empty() {
493 let mut c = PipeState::<3>::new(); 579 let c = Pipe::<NoopRawMutex, 3>::new();
494 let mut buf = [0; 16]; 580 let mut buf = [0; 16];
495 assert_eq!(c.try_read(&mut buf), Err(TryReadError::Empty)); 581 assert_eq!(c.try_read(&mut buf), Err(TryReadError::Empty));
496 assert_eq!(capacity(&c), 3); 582 assert_eq!(c.free_capacity(), 3);
497 } 583 }
498 584
499 #[test] 585 #[test]
@@ -506,13 +592,37 @@ mod tests {
506 } 592 }
507 593
508 #[test] 594 #[test]
509 fn cloning() { 595 fn read_buf() {
510 let c = Pipe::<NoopRawMutex, 3>::new(); 596 let mut c = Pipe::<NoopRawMutex, 3>::new();
511 let r1 = c.reader(); 597 let (mut r, w) = c.split();
512 let w1 = c.writer(); 598 assert!(w.try_write(&[42, 43]).is_ok());
599 let buf = r.try_fill_buf().unwrap();
600 assert_eq!(buf, &[42, 43]);
601 let buf = r.try_fill_buf().unwrap();
602 assert_eq!(buf, &[42, 43]);
603 r.consume(1);
604 let buf = r.try_fill_buf().unwrap();
605 assert_eq!(buf, &[43]);
606 r.consume(1);
607 assert_eq!(r.try_fill_buf(), Err(TryReadError::Empty));
608 assert_eq!(w.try_write(&[44, 45, 46]), Ok(1));
609 assert_eq!(w.try_write(&[45, 46]), Ok(2));
610 let buf = r.try_fill_buf().unwrap();
611 assert_eq!(buf, &[44]); // only one byte due to wraparound.
612 r.consume(1);
613 let buf = r.try_fill_buf().unwrap();
614 assert_eq!(buf, &[45, 46]);
615 assert!(w.try_write(&[47]).is_ok());
616 let buf = r.try_fill_buf().unwrap();
617 assert_eq!(buf, &[45, 46, 47]);
618 r.consume(3);
619 }
513 620
514 let _ = r1.clone(); 621 #[test]
515 let _ = w1.clone(); 622 fn writer_is_cloneable() {
623 let mut c = Pipe::<NoopRawMutex, 3>::new();
624 let (_r, w) = c.split();
625 let _ = w.clone();
516 } 626 }
517 627
518 #[futures_test::test] 628 #[futures_test::test]
diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs
index 521084024..d95ffa7c9 100644
--- a/embassy-sync/src/ring_buffer.rs
+++ b/embassy-sync/src/ring_buffer.rs
@@ -1,5 +1,6 @@
1use core::ops::Range;
2
1pub struct RingBuffer<const N: usize> { 3pub struct RingBuffer<const N: usize> {
2 buf: [u8; N],
3 start: usize, 4 start: usize,
4 end: usize, 5 end: usize,
5 empty: bool, 6 empty: bool,
@@ -8,27 +9,26 @@ pub struct RingBuffer<const N: usize> {
8impl<const N: usize> RingBuffer<N> { 9impl<const N: usize> RingBuffer<N> {
9 pub const fn new() -> Self { 10 pub const fn new() -> Self {
10 Self { 11 Self {
11 buf: [0; N],
12 start: 0, 12 start: 0,
13 end: 0, 13 end: 0,
14 empty: true, 14 empty: true,
15 } 15 }
16 } 16 }
17 17
18 pub fn push_buf(&mut self) -> &mut [u8] { 18 pub fn push_buf(&mut self) -> Range<usize> {
19 if self.start == self.end && !self.empty { 19 if self.start == self.end && !self.empty {
20 trace!(" ringbuf: push_buf empty"); 20 trace!(" ringbuf: push_buf empty");
21 return &mut self.buf[..0]; 21 return 0..0;
22 } 22 }
23 23
24 let n = if self.start <= self.end { 24 let n = if self.start <= self.end {
25 self.buf.len() - self.end 25 N - self.end
26 } else { 26 } else {
27 self.start - self.end 27 self.start - self.end
28 }; 28 };
29 29
30 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); 30 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
31 &mut self.buf[self.end..self.end + n] 31 self.end..self.end + n
32 } 32 }
33 33
34 pub fn push(&mut self, n: usize) { 34 pub fn push(&mut self, n: usize) {
@@ -41,20 +41,20 @@ impl<const N: usize> RingBuffer<N> {
41 self.empty = false; 41 self.empty = false;
42 } 42 }
43 43
44 pub fn pop_buf(&mut self) -> &mut [u8] { 44 pub fn pop_buf(&mut self) -> Range<usize> {
45 if self.empty { 45 if self.empty {
46 trace!(" ringbuf: pop_buf empty"); 46 trace!(" ringbuf: pop_buf empty");
47 return &mut self.buf[..0]; 47 return 0..0;
48 } 48 }
49 49
50 let n = if self.end <= self.start { 50 let n = if self.end <= self.start {
51 self.buf.len() - self.start 51 N - self.start
52 } else { 52 } else {
53 self.end - self.start 53 self.end - self.start
54 }; 54 };
55 55
56 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); 56 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
57 &mut self.buf[self.start..self.start + n] 57 self.start..self.start + n
58 } 58 }
59 59
60 pub fn pop(&mut self, n: usize) { 60 pub fn pop(&mut self, n: usize) {
@@ -93,8 +93,8 @@ impl<const N: usize> RingBuffer<N> {
93 } 93 }
94 94
95 fn wrap(&self, n: usize) -> usize { 95 fn wrap(&self, n: usize) -> usize {
96 assert!(n <= self.buf.len()); 96 assert!(n <= N);
97 if n == self.buf.len() { 97 if n == N {
98 0 98 0
99 } else { 99 } else {
100 n 100 n
@@ -110,37 +110,29 @@ mod tests {
110 fn push_pop() { 110 fn push_pop() {
111 let mut rb: RingBuffer<4> = RingBuffer::new(); 111 let mut rb: RingBuffer<4> = RingBuffer::new();
112 let buf = rb.push_buf(); 112 let buf = rb.push_buf();
113 assert_eq!(4, buf.len()); 113 assert_eq!(0..4, buf);
114 buf[0] = 1;
115 buf[1] = 2;
116 buf[2] = 3;
117 buf[3] = 4;
118 rb.push(4); 114 rb.push(4);
119 115
120 let buf = rb.pop_buf(); 116 let buf = rb.pop_buf();
121 assert_eq!(4, buf.len()); 117 assert_eq!(0..4, buf);
122 assert_eq!(1, buf[0]);
123 rb.pop(1); 118 rb.pop(1);
124 119
125 let buf = rb.pop_buf(); 120 let buf = rb.pop_buf();
126 assert_eq!(3, buf.len()); 121 assert_eq!(1..4, buf);
127 assert_eq!(2, buf[0]);
128 rb.pop(1); 122 rb.pop(1);
129 123
130 let buf = rb.pop_buf(); 124 let buf = rb.pop_buf();
131 assert_eq!(2, buf.len()); 125 assert_eq!(2..4, buf);
132 assert_eq!(3, buf[0]);
133 rb.pop(1); 126 rb.pop(1);
134 127
135 let buf = rb.pop_buf(); 128 let buf = rb.pop_buf();
136 assert_eq!(1, buf.len()); 129 assert_eq!(3..4, buf);
137 assert_eq!(4, buf[0]);
138 rb.pop(1); 130 rb.pop(1);
139 131
140 let buf = rb.pop_buf(); 132 let buf = rb.pop_buf();
141 assert_eq!(0, buf.len()); 133 assert_eq!(0..0, buf);
142 134
143 let buf = rb.push_buf(); 135 let buf = rb.push_buf();
144 assert_eq!(4, buf.len()); 136 assert_eq!(0..4, buf);
145 } 137 }
146} 138}
diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs
new file mode 100644
index 000000000..f704cbd5d
--- /dev/null
+++ b/embassy-sync/src/zerocopy_channel.rs
@@ -0,0 +1,260 @@
1//! A zero-copy queue for sending values between asynchronous tasks.
2//!
3//! It can be used concurrently by multiple producers (senders) and multiple
4//! consumers (receivers), i.e. it is an "MPMC channel".
5//!
6//! Receivers are competing for messages. So a message that is received by
7//! one receiver is not received by any other.
8//!
9//! This queue takes a Mutex type so that various
10//! targets can be attained. For example, a ThreadModeMutex can be used
11//! for single-core Cortex-M targets where messages are only passed
12//! between tasks running in thread mode. Similarly, a CriticalSectionMutex
13//! can also be used for single-core targets where messages are to be
14//! passed from exception mode e.g. out of an interrupt handler.
15//!
16//! This module provides a bounded channel that has a limit on the number of
17//! messages that it can store, and if this limit is reached, trying to send
18//! another message will result in an error being returned.
19
20use core::cell::RefCell;
21use core::future::poll_fn;
22use core::marker::PhantomData;
23use core::task::{Context, Poll};
24
25use crate::blocking_mutex::raw::RawMutex;
26use crate::blocking_mutex::Mutex;
27use crate::waitqueue::WakerRegistration;
28
29/// A bounded zero-copy channel for communicating between asynchronous tasks
30/// with backpressure.
31///
32/// The channel will buffer up to the provided number of messages. Once the
33/// buffer is full, attempts to `send` new messages will wait until a message is
34/// received from the channel.
35///
36/// All data sent will become available in the same order as it was sent.
37///
38/// The channel requires a buffer of recyclable elements. Writing to the channel is done through
39/// an `&mut T`.
40pub struct Channel<'a, M: RawMutex, T> {
41 buf: *mut T,
42 phantom: PhantomData<&'a mut T>,
43 state: Mutex<M, RefCell<State>>,
44}
45
46impl<'a, M: RawMutex, T> Channel<'a, M, T> {
47 /// Initialize a new [`Channel`].
48 ///
49 /// The provided buffer will be used and reused by the channel's logic, and thus dictates the
50 /// channel's capacity.
51 pub fn new(buf: &'a mut [T]) -> Self {
52 let len = buf.len();
53 assert!(len != 0);
54
55 Self {
56 buf: buf.as_mut_ptr(),
57 phantom: PhantomData,
58 state: Mutex::new(RefCell::new(State {
59 len,
60 front: 0,
61 back: 0,
62 full: false,
63 send_waker: WakerRegistration::new(),
64 receive_waker: WakerRegistration::new(),
65 })),
66 }
67 }
68
69 /// Creates a [`Sender`] and [`Receiver`] from an existing channel.
70 ///
71 /// Further Senders and Receivers can be created through [`Sender::borrow`] and
72 /// [`Receiver::borrow`] respectively.
73 pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) {
74 (Sender { channel: self }, Receiver { channel: self })
75 }
76}
77
78/// Send-only access to a [`Channel`].
79pub struct Sender<'a, M: RawMutex, T> {
80 channel: &'a Channel<'a, M, T>,
81}
82
83impl<'a, M: RawMutex, T> Sender<'a, M, T> {
84 /// Creates one further [`Sender`] over the same channel.
85 pub fn borrow(&mut self) -> Sender<'_, M, T> {
86 Sender { channel: self.channel }
87 }
88
89 /// Attempts to send a value over the channel.
90 pub fn try_send(&mut self) -> Option<&mut T> {
91 self.channel.state.lock(|s| {
92 let s = &mut *s.borrow_mut();
93 match s.push_index() {
94 Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
95 None => None,
96 }
97 })
98 }
99
100 /// Attempts to send a value over the channel.
101 pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> {
102 self.channel.state.lock(|s| {
103 let s = &mut *s.borrow_mut();
104 match s.push_index() {
105 Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
106 None => {
107 s.receive_waker.register(cx.waker());
108 Poll::Pending
109 }
110 }
111 })
112 }
113
114 /// Asynchronously send a value over the channel.
115 pub async fn send(&mut self) -> &mut T {
116 let i = poll_fn(|cx| {
117 self.channel.state.lock(|s| {
118 let s = &mut *s.borrow_mut();
119 match s.push_index() {
120 Some(i) => Poll::Ready(i),
121 None => {
122 s.receive_waker.register(cx.waker());
123 Poll::Pending
124 }
125 }
126 })
127 })
128 .await;
129 unsafe { &mut *self.channel.buf.add(i) }
130 }
131
132 /// Notify the channel that the sending of the value has been finalized.
133 pub fn send_done(&mut self) {
134 self.channel.state.lock(|s| s.borrow_mut().push_done())
135 }
136}
137
138/// Receive-only access to a [`Channel`].
139pub struct Receiver<'a, M: RawMutex, T> {
140 channel: &'a Channel<'a, M, T>,
141}
142
143impl<'a, M: RawMutex, T> Receiver<'a, M, T> {
144 /// Creates one further [`Sender`] over the same channel.
145 pub fn borrow(&mut self) -> Receiver<'_, M, T> {
146 Receiver { channel: self.channel }
147 }
148
149 /// Attempts to receive a value over the channel.
150 pub fn try_receive(&mut self) -> Option<&mut T> {
151 self.channel.state.lock(|s| {
152 let s = &mut *s.borrow_mut();
153 match s.pop_index() {
154 Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
155 None => None,
156 }
157 })
158 }
159
160 /// Attempts to asynchronously receive a value over the channel.
161 pub fn poll_receive(&mut self, cx: &mut Context) -> Poll<&mut T> {
162 self.channel.state.lock(|s| {
163 let s = &mut *s.borrow_mut();
164 match s.pop_index() {
165 Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
166 None => {
167 s.send_waker.register(cx.waker());
168 Poll::Pending
169 }
170 }
171 })
172 }
173
174 /// Asynchronously receive a value over the channel.
175 pub async fn receive(&mut self) -> &mut T {
176 let i = poll_fn(|cx| {
177 self.channel.state.lock(|s| {
178 let s = &mut *s.borrow_mut();
179 match s.pop_index() {
180 Some(i) => Poll::Ready(i),
181 None => {
182 s.send_waker.register(cx.waker());
183 Poll::Pending
184 }
185 }
186 })
187 })
188 .await;
189 unsafe { &mut *self.channel.buf.add(i) }
190 }
191
192 /// Notify the channel that the receiving of the value has been finalized.
193 pub fn receive_done(&mut self) {
194 self.channel.state.lock(|s| s.borrow_mut().pop_done())
195 }
196}
197
198struct State {
199 len: usize,
200
201 /// Front index. Always 0..=(N-1)
202 front: usize,
203 /// Back index. Always 0..=(N-1).
204 back: usize,
205
206 /// Used to distinguish "empty" and "full" cases when `front == back`.
207 /// May only be `true` if `front == back`, always `false` otherwise.
208 full: bool,
209
210 send_waker: WakerRegistration,
211 receive_waker: WakerRegistration,
212}
213
214impl State {
215 fn increment(&self, i: usize) -> usize {
216 if i + 1 == self.len {
217 0
218 } else {
219 i + 1
220 }
221 }
222
223 fn is_full(&self) -> bool {
224 self.full
225 }
226
227 fn is_empty(&self) -> bool {
228 self.front == self.back && !self.full
229 }
230
231 fn push_index(&mut self) -> Option<usize> {
232 match self.is_full() {
233 true => None,
234 false => Some(self.back),
235 }
236 }
237
238 fn push_done(&mut self) {
239 assert!(!self.is_full());
240 self.back = self.increment(self.back);
241 if self.back == self.front {
242 self.full = true;
243 }
244 self.send_waker.wake();
245 }
246
247 fn pop_index(&mut self) -> Option<usize> {
248 match self.is_empty() {
249 true => None,
250 false => Some(self.front),
251 }
252 }
253
254 fn pop_done(&mut self) {
255 assert!(!self.is_empty());
256 self.front = self.increment(self.front);
257 self.full = false;
258 self.receive_waker.wake();
259 }
260}
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index 26640d930..e3b38455c 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -5,6 +5,15 @@ 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.4 - ???
9
10- Added more tick rates
11
12## 0.1.3 - 2023-08-28
13
14- Update `embedded-hal-async` to `1.0.0-rc.1`
15- Update `embedded-hal v1` to `1.0.0-rc.1`
16
8## 0.1.2 - 2023-07-05 17## 0.1.2 - 2023-07-05
9 18
10- Update `embedded-hal-async` to `0.2.0-alpha.2`. 19- Update `embedded-hal-async` to `0.2.0-alpha.2`.
@@ -26,4 +35,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
26 35
27## 0.1.0 - 2022-08-26 36## 0.1.0 - 2022-08-26
28 37
29- First release \ No newline at end of file 38- First release
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 00d31d30f..8f034a9de 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.2" 3version = "0.1.4"
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"
@@ -145,6 +145,68 @@ tick-hz-384_000_000 = []
145tick-hz-512_000_000 = [] 145tick-hz-512_000_000 = []
146tick-hz-576_000_000 = [] 146tick-hz-576_000_000 = []
147tick-hz-768_000_000 = [] 147tick-hz-768_000_000 = []
148tick-hz-20_000_000 = []
149tick-hz-30_000_000 = []
150tick-hz-40_000_000 = []
151tick-hz-50_000_000 = []
152tick-hz-60_000_000 = []
153tick-hz-70_000_000 = []
154tick-hz-80_000_000 = []
155tick-hz-90_000_000 = []
156tick-hz-110_000_000 = []
157tick-hz-120_000_000 = []
158tick-hz-130_000_000 = []
159tick-hz-140_000_000 = []
160tick-hz-150_000_000 = []
161tick-hz-160_000_000 = []
162tick-hz-170_000_000 = []
163tick-hz-180_000_000 = []
164tick-hz-190_000_000 = []
165tick-hz-200_000_000 = []
166tick-hz-210_000_000 = []
167tick-hz-220_000_000 = []
168tick-hz-230_000_000 = []
169tick-hz-240_000_000 = []
170tick-hz-250_000_000 = []
171tick-hz-260_000_000 = []
172tick-hz-270_000_000 = []
173tick-hz-280_000_000 = []
174tick-hz-290_000_000 = []
175tick-hz-300_000_000 = []
176tick-hz-320_000_000 = []
177tick-hz-340_000_000 = []
178tick-hz-360_000_000 = []
179tick-hz-380_000_000 = []
180tick-hz-400_000_000 = []
181tick-hz-420_000_000 = []
182tick-hz-440_000_000 = []
183tick-hz-460_000_000 = []
184tick-hz-480_000_000 = []
185tick-hz-500_000_000 = []
186tick-hz-520_000_000 = []
187tick-hz-540_000_000 = []
188tick-hz-560_000_000 = []
189tick-hz-580_000_000 = []
190tick-hz-600_000_000 = []
191tick-hz-620_000_000 = []
192tick-hz-640_000_000 = []
193tick-hz-660_000_000 = []
194tick-hz-680_000_000 = []
195tick-hz-700_000_000 = []
196tick-hz-720_000_000 = []
197tick-hz-740_000_000 = []
198tick-hz-760_000_000 = []
199tick-hz-780_000_000 = []
200tick-hz-800_000_000 = []
201tick-hz-820_000_000 = []
202tick-hz-840_000_000 = []
203tick-hz-860_000_000 = []
204tick-hz-880_000_000 = []
205tick-hz-900_000_000 = []
206tick-hz-920_000_000 = []
207tick-hz-940_000_000 = []
208tick-hz-960_000_000 = []
209tick-hz-980_000_000 = []
148# END TICKS 210# END TICKS
149 211
150[dependencies] 212[dependencies]
diff --git a/embassy-time/gen_tick.py b/embassy-time/gen_tick.py
index 15e65187b..67a4c79c8 100644
--- a/embassy-time/gen_tick.py
+++ b/embassy-time/gen_tick.py
@@ -17,6 +17,10 @@ for i in range(1, 10):
17 ticks.append(2**i * 1000000) 17 ticks.append(2**i * 1000000)
18 ticks.append(2**i * 9 // 8 * 1000000) 18 ticks.append(2**i * 9 // 8 * 1000000)
19 ticks.append(2**i * 3 // 2 * 1000000) 19 ticks.append(2**i * 3 // 2 * 1000000)
20for i in range(1, 30):
21 ticks.append(10 * i * 1_000_000)
22for i in range(15, 50):
23 ticks.append(20 * i * 1_000_000)
20 24
21seen = set() 25seen = set()
22ticks = [x for x in ticks if not (x in seen or seen.add(x))] 26ticks = [x for x in ticks if not (x in seen or seen.add(x))]
diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-time/src/fmt.rs
+++ b/embassy-time/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs
index 44f226f62..5571cdd15 100644
--- a/embassy-time/src/instant.rs
+++ b/embassy-time/src/instant.rs
@@ -71,7 +71,7 @@ impl Instant {
71 /// Panics on over/underflow. 71 /// Panics on over/underflow.
72 pub fn duration_since(&self, earlier: Instant) -> Duration { 72 pub fn duration_since(&self, earlier: Instant) -> Duration {
73 Duration { 73 Duration {
74 ticks: self.ticks.checked_sub(earlier.ticks).unwrap(), 74 ticks: unwrap!(self.ticks.checked_sub(earlier.ticks)),
75 } 75 }
76 } 76 }
77 77
diff --git a/embassy-time/src/tick.rs b/embassy-time/src/tick.rs
index 608bc44f1..be544181a 100644
--- a/embassy-time/src/tick.rs
+++ b/embassy-time/src/tick.rs
@@ -156,6 +156,130 @@ pub const TICK_HZ: u64 = 512_000_000;
156pub const TICK_HZ: u64 = 576_000_000; 156pub const TICK_HZ: u64 = 576_000_000;
157#[cfg(feature = "tick-hz-768_000_000")] 157#[cfg(feature = "tick-hz-768_000_000")]
158pub const TICK_HZ: u64 = 768_000_000; 158pub const TICK_HZ: u64 = 768_000_000;
159#[cfg(feature = "tick-hz-20_000_000")]
160pub const TICK_HZ: u64 = 20_000_000;
161#[cfg(feature = "tick-hz-30_000_000")]
162pub const TICK_HZ: u64 = 30_000_000;
163#[cfg(feature = "tick-hz-40_000_000")]
164pub const TICK_HZ: u64 = 40_000_000;
165#[cfg(feature = "tick-hz-50_000_000")]
166pub const TICK_HZ: u64 = 50_000_000;
167#[cfg(feature = "tick-hz-60_000_000")]
168pub const TICK_HZ: u64 = 60_000_000;
169#[cfg(feature = "tick-hz-70_000_000")]
170pub const TICK_HZ: u64 = 70_000_000;
171#[cfg(feature = "tick-hz-80_000_000")]
172pub const TICK_HZ: u64 = 80_000_000;
173#[cfg(feature = "tick-hz-90_000_000")]
174pub const TICK_HZ: u64 = 90_000_000;
175#[cfg(feature = "tick-hz-110_000_000")]
176pub const TICK_HZ: u64 = 110_000_000;
177#[cfg(feature = "tick-hz-120_000_000")]
178pub const TICK_HZ: u64 = 120_000_000;
179#[cfg(feature = "tick-hz-130_000_000")]
180pub const TICK_HZ: u64 = 130_000_000;
181#[cfg(feature = "tick-hz-140_000_000")]
182pub const TICK_HZ: u64 = 140_000_000;
183#[cfg(feature = "tick-hz-150_000_000")]
184pub const TICK_HZ: u64 = 150_000_000;
185#[cfg(feature = "tick-hz-160_000_000")]
186pub const TICK_HZ: u64 = 160_000_000;
187#[cfg(feature = "tick-hz-170_000_000")]
188pub const TICK_HZ: u64 = 170_000_000;
189#[cfg(feature = "tick-hz-180_000_000")]
190pub const TICK_HZ: u64 = 180_000_000;
191#[cfg(feature = "tick-hz-190_000_000")]
192pub const TICK_HZ: u64 = 190_000_000;
193#[cfg(feature = "tick-hz-200_000_000")]
194pub const TICK_HZ: u64 = 200_000_000;
195#[cfg(feature = "tick-hz-210_000_000")]
196pub const TICK_HZ: u64 = 210_000_000;
197#[cfg(feature = "tick-hz-220_000_000")]
198pub const TICK_HZ: u64 = 220_000_000;
199#[cfg(feature = "tick-hz-230_000_000")]
200pub const TICK_HZ: u64 = 230_000_000;
201#[cfg(feature = "tick-hz-240_000_000")]
202pub const TICK_HZ: u64 = 240_000_000;
203#[cfg(feature = "tick-hz-250_000_000")]
204pub const TICK_HZ: u64 = 250_000_000;
205#[cfg(feature = "tick-hz-260_000_000")]
206pub const TICK_HZ: u64 = 260_000_000;
207#[cfg(feature = "tick-hz-270_000_000")]
208pub const TICK_HZ: u64 = 270_000_000;
209#[cfg(feature = "tick-hz-280_000_000")]
210pub const TICK_HZ: u64 = 280_000_000;
211#[cfg(feature = "tick-hz-290_000_000")]
212pub const TICK_HZ: u64 = 290_000_000;
213#[cfg(feature = "tick-hz-300_000_000")]
214pub const TICK_HZ: u64 = 300_000_000;
215#[cfg(feature = "tick-hz-320_000_000")]
216pub const TICK_HZ: u64 = 320_000_000;
217#[cfg(feature = "tick-hz-340_000_000")]
218pub const TICK_HZ: u64 = 340_000_000;
219#[cfg(feature = "tick-hz-360_000_000")]
220pub const TICK_HZ: u64 = 360_000_000;
221#[cfg(feature = "tick-hz-380_000_000")]
222pub const TICK_HZ: u64 = 380_000_000;
223#[cfg(feature = "tick-hz-400_000_000")]
224pub const TICK_HZ: u64 = 400_000_000;
225#[cfg(feature = "tick-hz-420_000_000")]
226pub const TICK_HZ: u64 = 420_000_000;
227#[cfg(feature = "tick-hz-440_000_000")]
228pub const TICK_HZ: u64 = 440_000_000;
229#[cfg(feature = "tick-hz-460_000_000")]
230pub const TICK_HZ: u64 = 460_000_000;
231#[cfg(feature = "tick-hz-480_000_000")]
232pub const TICK_HZ: u64 = 480_000_000;
233#[cfg(feature = "tick-hz-500_000_000")]
234pub const TICK_HZ: u64 = 500_000_000;
235#[cfg(feature = "tick-hz-520_000_000")]
236pub const TICK_HZ: u64 = 520_000_000;
237#[cfg(feature = "tick-hz-540_000_000")]
238pub const TICK_HZ: u64 = 540_000_000;
239#[cfg(feature = "tick-hz-560_000_000")]
240pub const TICK_HZ: u64 = 560_000_000;
241#[cfg(feature = "tick-hz-580_000_000")]
242pub const TICK_HZ: u64 = 580_000_000;
243#[cfg(feature = "tick-hz-600_000_000")]
244pub const TICK_HZ: u64 = 600_000_000;
245#[cfg(feature = "tick-hz-620_000_000")]
246pub const TICK_HZ: u64 = 620_000_000;
247#[cfg(feature = "tick-hz-640_000_000")]
248pub const TICK_HZ: u64 = 640_000_000;
249#[cfg(feature = "tick-hz-660_000_000")]
250pub const TICK_HZ: u64 = 660_000_000;
251#[cfg(feature = "tick-hz-680_000_000")]
252pub const TICK_HZ: u64 = 680_000_000;
253#[cfg(feature = "tick-hz-700_000_000")]
254pub const TICK_HZ: u64 = 700_000_000;
255#[cfg(feature = "tick-hz-720_000_000")]
256pub const TICK_HZ: u64 = 720_000_000;
257#[cfg(feature = "tick-hz-740_000_000")]
258pub const TICK_HZ: u64 = 740_000_000;
259#[cfg(feature = "tick-hz-760_000_000")]
260pub const TICK_HZ: u64 = 760_000_000;
261#[cfg(feature = "tick-hz-780_000_000")]
262pub const TICK_HZ: u64 = 780_000_000;
263#[cfg(feature = "tick-hz-800_000_000")]
264pub const TICK_HZ: u64 = 800_000_000;
265#[cfg(feature = "tick-hz-820_000_000")]
266pub const TICK_HZ: u64 = 820_000_000;
267#[cfg(feature = "tick-hz-840_000_000")]
268pub const TICK_HZ: u64 = 840_000_000;
269#[cfg(feature = "tick-hz-860_000_000")]
270pub const TICK_HZ: u64 = 860_000_000;
271#[cfg(feature = "tick-hz-880_000_000")]
272pub const TICK_HZ: u64 = 880_000_000;
273#[cfg(feature = "tick-hz-900_000_000")]
274pub const TICK_HZ: u64 = 900_000_000;
275#[cfg(feature = "tick-hz-920_000_000")]
276pub const TICK_HZ: u64 = 920_000_000;
277#[cfg(feature = "tick-hz-940_000_000")]
278pub const TICK_HZ: u64 = 940_000_000;
279#[cfg(feature = "tick-hz-960_000_000")]
280pub const TICK_HZ: u64 = 960_000_000;
281#[cfg(feature = "tick-hz-980_000_000")]
282pub const TICK_HZ: u64 = 980_000_000;
159#[cfg(not(any( 283#[cfg(not(any(
160 feature = "tick-hz-1", 284 feature = "tick-hz-1",
161 feature = "tick-hz-10", 285 feature = "tick-hz-10",
@@ -235,5 +359,67 @@ pub const TICK_HZ: u64 = 768_000_000;
235 feature = "tick-hz-512_000_000", 359 feature = "tick-hz-512_000_000",
236 feature = "tick-hz-576_000_000", 360 feature = "tick-hz-576_000_000",
237 feature = "tick-hz-768_000_000", 361 feature = "tick-hz-768_000_000",
362 feature = "tick-hz-20_000_000",
363 feature = "tick-hz-30_000_000",
364 feature = "tick-hz-40_000_000",
365 feature = "tick-hz-50_000_000",
366 feature = "tick-hz-60_000_000",
367 feature = "tick-hz-70_000_000",
368 feature = "tick-hz-80_000_000",
369 feature = "tick-hz-90_000_000",
370 feature = "tick-hz-110_000_000",
371 feature = "tick-hz-120_000_000",
372 feature = "tick-hz-130_000_000",
373 feature = "tick-hz-140_000_000",
374 feature = "tick-hz-150_000_000",
375 feature = "tick-hz-160_000_000",
376 feature = "tick-hz-170_000_000",
377 feature = "tick-hz-180_000_000",
378 feature = "tick-hz-190_000_000",
379 feature = "tick-hz-200_000_000",
380 feature = "tick-hz-210_000_000",
381 feature = "tick-hz-220_000_000",
382 feature = "tick-hz-230_000_000",
383 feature = "tick-hz-240_000_000",
384 feature = "tick-hz-250_000_000",
385 feature = "tick-hz-260_000_000",
386 feature = "tick-hz-270_000_000",
387 feature = "tick-hz-280_000_000",
388 feature = "tick-hz-290_000_000",
389 feature = "tick-hz-300_000_000",
390 feature = "tick-hz-320_000_000",
391 feature = "tick-hz-340_000_000",
392 feature = "tick-hz-360_000_000",
393 feature = "tick-hz-380_000_000",
394 feature = "tick-hz-400_000_000",
395 feature = "tick-hz-420_000_000",
396 feature = "tick-hz-440_000_000",
397 feature = "tick-hz-460_000_000",
398 feature = "tick-hz-480_000_000",
399 feature = "tick-hz-500_000_000",
400 feature = "tick-hz-520_000_000",
401 feature = "tick-hz-540_000_000",
402 feature = "tick-hz-560_000_000",
403 feature = "tick-hz-580_000_000",
404 feature = "tick-hz-600_000_000",
405 feature = "tick-hz-620_000_000",
406 feature = "tick-hz-640_000_000",
407 feature = "tick-hz-660_000_000",
408 feature = "tick-hz-680_000_000",
409 feature = "tick-hz-700_000_000",
410 feature = "tick-hz-720_000_000",
411 feature = "tick-hz-740_000_000",
412 feature = "tick-hz-760_000_000",
413 feature = "tick-hz-780_000_000",
414 feature = "tick-hz-800_000_000",
415 feature = "tick-hz-820_000_000",
416 feature = "tick-hz-840_000_000",
417 feature = "tick-hz-860_000_000",
418 feature = "tick-hz-880_000_000",
419 feature = "tick-hz-900_000_000",
420 feature = "tick-hz-920_000_000",
421 feature = "tick-hz-940_000_000",
422 feature = "tick-hz-960_000_000",
423 feature = "tick-hz-980_000_000",
238)))] 424)))]
239pub const TICK_HZ: u64 = 1_000_000; 425pub const TICK_HZ: u64 = 1_000_000;
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs
index ad5026e62..07ddf473f 100644
--- a/embassy-time/src/timer.rs
+++ b/embassy-time/src/timer.rs
@@ -133,7 +133,13 @@ impl Ticker {
133 Self { expires_at, duration } 133 Self { expires_at, duration }
134 } 134 }
135 135
136 /// Waits for the next tick 136 /// Resets the ticker back to its original state.
137 /// This causes the ticker to go back to zero, even if the current tick isn't over yet.
138 pub fn reset(&mut self) {
139 self.expires_at = Instant::now() + self.duration;
140 }
141
142 /// Waits for the next tick.
137 pub fn next(&mut self) -> impl Future<Output = ()> + '_ { 143 pub fn next(&mut self) -> impl Future<Output = ()> + '_ {
138 poll_fn(|cx| { 144 poll_fn(|cx| {
139 if self.expires_at <= Instant::now() { 145 if self.expires_at <= Instant::now() {
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
index 0f91cd36d..944a48a5e 100644
--- a/embassy-usb-logger/Cargo.toml
+++ b/embassy-usb-logger/Cargo.toml
@@ -10,7 +10,7 @@ target = "thumbv7em-none-eabi"
10 10
11[dependencies] 11[dependencies]
12embassy-usb = { version = "0.1.0", path = "../embassy-usb" } 12embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
13embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 13embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
14embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
15futures = { version = "0.3", default-features = false } 15futures = { version = "0.3", default-features = false }
16static_cell = "1" 16static_cell = "1"
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 03cf96a1d..0e7e0e708 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -41,7 +41,7 @@ max-handler-count-8 = []
41[dependencies] 41[dependencies]
42embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 42embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
43embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } 43embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
44embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 44embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
45embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } 45embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
46 46
47defmt = { version = "0.3", optional = true } 47defmt = { version = "0.3", optional = true }
diff --git a/embassy-usb/src/fmt.rs b/embassy-usb/src/fmt.rs
index 066970813..78e583c1c 100644
--- a/embassy-usb/src/fmt.rs
+++ b/embassy-usb/src/fmt.rs
@@ -1,6 +1,8 @@
1#![macro_use] 1#![macro_use]
2#![allow(unused_macros)] 2#![allow(unused_macros)]
3 3
4use core::fmt::{Debug, Display, LowerHex};
5
4#[cfg(all(feature = "defmt", feature = "log"))] 6#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
6 8
@@ -81,14 +83,17 @@ macro_rules! todo {
81 }; 83 };
82} 84}
83 85
86#[cfg(not(feature = "defmt"))]
84macro_rules! unreachable { 87macro_rules! unreachable {
85 ($($x:tt)*) => { 88 ($($x:tt)*) => {
86 { 89 ::core::unreachable!($($x)*)
87 #[cfg(not(feature = "defmt"))] 90 };
88 ::core::unreachable!($($x)*); 91}
89 #[cfg(feature = "defmt")] 92
90 ::defmt::unreachable!($($x)*); 93#[cfg(feature = "defmt")]
91 } 94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
92 }; 97 };
93} 98}
94 99
@@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
223 self 228 self
224 } 229 }
225} 230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 46ce7ba9b..435a33919 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.3", 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 be85f4437..01cfc5994 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -27,6 +27,7 @@ default = ["panic-reset"]
27debug = [ 27debug = [
28 "embassy-rp/defmt", 28 "embassy-rp/defmt",
29 "embassy-boot-rp/defmt", 29 "embassy-boot-rp/defmt",
30 "embassy-sync/defmt",
30 "panic-probe" 31 "panic-probe"
31] 32]
32skip-include = [] 33skip-include = []
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 15fdaca82..a4602a7ed 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -38,7 +38,7 @@ async fn main(_s: Spawner) {
38 let flash = Mutex::new(RefCell::new(flash)); 38 let flash = Mutex::new(RefCell::new(flash));
39 39
40 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 40 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
41 let mut aligned = AlignedBuffer([0; 4]); 41 let mut aligned = AlignedBuffer([0; 1]);
42 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); 42 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
43 43
44 Timer::after(Duration::from_secs(5)).await; 44 Timer::after(Duration::from_secs(5)).await;
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index ea8789332..a0649cf83 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -25,5 +25,6 @@ defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt",
28] 29]
29skip-include = [] 30skip-include = []
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index b39bc2922..ca1c0c424 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -26,5 +26,6 @@ defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt",
29] 30]
30skip-include = [] 31skip-include = []
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index f015b2cae..e50c8c415 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -26,5 +26,6 @@ defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt",
29] 30]
30skip-include = [] 31skip-include = []
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index f221e1de7..1f1a0f3cf 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -25,5 +25,6 @@ defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt",
28] 29]
29skip-include = [] 30skip-include = []
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 2896afa3e..45b12813e 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -25,5 +25,6 @@ defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt",
28] 29]
29skip-include = [] 30skip-include = []
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 50d8967a1..d0d0d0fbe 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -25,5 +25,6 @@ defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt",
28] 29]
29skip-include = [] 30skip-include = []
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 275414391..3265b9f1a 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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" }
@@ -25,5 +25,6 @@ defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt",
28] 29]
29skip-include = [] 30skip-include = []
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index 40656f359..42391778d 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -25,7 +25,7 @@ defmt = [
25softdevice = [ 25softdevice = [
26 "embassy-boot-nrf/softdevice", 26 "embassy-boot-nrf/softdevice",
27] 27]
28debug = ["defmt-rtt"] 28debug = ["defmt-rtt", "defmt"]
29 29
30[profile.dev] 30[profile.dev]
31debug = 2 31debug = 2
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 6436f2fee..9175768d6 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -24,7 +24,7 @@ defmt = [
24 "embassy-boot-stm32/defmt", 24 "embassy-boot-stm32/defmt",
25 "embassy-stm32/defmt", 25 "embassy-stm32/defmt",
26] 26]
27debug = ["defmt-rtt"] 27debug = ["defmt-rtt", "defmt"]
28 28
29[profile.dev] 29[profile.dev]
30debug = 2 30debug = 2
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index b06722f5c..e402e49f4 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -16,9 +16,9 @@ log = [
16] 16]
17 17
18[dependencies] 18[dependencies]
19embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } 19embassy-sync = { version = "0.3.0", path = "../../embassy-sync" }
20embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } 20embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
21embassy-time = { version = "0.1.2", path = "../../embassy-time" } 21embassy-time = { version = "0.1.3", 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 715f1ecfe..c588b807e 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
8rtic = { version = "2", features = ["thumbv7-backend"] } 8rtic = { 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.3.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } 12embassy-time = { version = "0.1.3", 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 1b2f1eb11..d45e006c7 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -29,18 +29,18 @@ nightly = [
29 29
30[dependencies] 30[dependencies]
31embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 31embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
32embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 32embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
33embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 33embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
34embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 34embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
35embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 35embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
36embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } 36embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
37embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } 37embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
38embedded-io = { version = "0.5.0", features = ["defmt-03"] } 38embedded-io = { version = "0.5.0", features = ["defmt-03"] }
39embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] } 39embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] }
40embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } 40embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
41lora-phy = { version = "1", optional = true } 41lora-phy = { version = "2", optional = true }
42lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } 42lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
43lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } 43lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"], optional = true }
44embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } 44embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
45embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"], optional = true } 45embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"], optional = true }
46 46
@@ -65,6 +65,3 @@ microfft = "0.5.0"
65 65
66[profile.release] 66[profile.release]
67debug = 2 67debug = 2
68
69[patch.crates-io]
70lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file
diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs
index beca061ed..3a98133c9 100644
--- a/examples/nrf52840/src/bin/lora_cad.rs
+++ b/examples/nrf52840/src/bin/lora_cad.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 let iv = 41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); 42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { 45 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
diff --git a/examples/nrf52840/src/bin/lora_lorawan.rs b/examples/nrf52840/src/bin/lora_lorawan.rs
index c953680c6..666330ba1 100644
--- a/examples/nrf52840/src/bin/lora_lorawan.rs
+++ b/examples/nrf52840/src/bin/lora_lorawan.rs
@@ -20,6 +20,7 @@ use lora_phy::LoRa;
20use lorawan::default_crypto::DefaultFactory as Crypto; 20use lorawan::default_crypto::DefaultFactory as Crypto;
21use lorawan_device::async_device::lora_radio::LoRaRadio; 21use lorawan_device::async_device::lora_radio::LoRaRadio;
22use lorawan_device::async_device::{region, Device, JoinMode}; 22use lorawan_device::async_device::{region, Device, JoinMode};
23use lorawan_device::{AppEui, AppKey, DevEui};
23use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
24 25
25const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region 26const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
@@ -47,10 +48,8 @@ async fn main(_spawner: Spawner) {
47 let iv = 48 let iv =
48 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); 49 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
49 50
50 let mut delay = Delay;
51
52 let lora = { 51 let lora = {
53 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, &mut delay).await { 52 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, Delay).await {
54 Ok(l) => l, 53 Ok(l) => l,
55 Err(err) => { 54 Err(err) => {
56 info!("Radio error = {}", err); 55 info!("Radio error = {}", err);
@@ -68,9 +67,9 @@ async fn main(_spawner: Spawner) {
68 // TODO: Adjust the EUI and Keys according to your network credentials 67 // TODO: Adjust the EUI and Keys according to your network credentials
69 match device 68 match device
70 .join(&JoinMode::OTAA { 69 .join(&JoinMode::OTAA {
71 deveui: [0, 0, 0, 0, 0, 0, 0, 0], 70 deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
72 appeui: [0, 0, 0, 0, 0, 0, 0, 0], 71 appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
73 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 72 appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
74 }) 73 })
75 .await 74 .await
76 { 75 {
diff --git a/examples/nrf52840/src/bin/lora_p2p_receive.rs b/examples/nrf52840/src/bin/lora_p2p_receive.rs
index 563fe42ec..1d293c6bf 100644
--- a/examples/nrf52840/src/bin/lora_p2p_receive.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_receive.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 let iv = 41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); 42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { 45 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
@@ -88,7 +86,7 @@ async fn main(_spawner: Spawner) {
88 }; 86 };
89 87
90 match lora 88 match lora
91 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) 89 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false)
92 .await 90 .await
93 { 91 {
94 Ok(()) => {} 92 Ok(()) => {}
diff --git a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
index 1fd8f61a2..eee4d20e7 100644
--- a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 let iv = 41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); 42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { 45 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
@@ -92,14 +90,12 @@ async fn main(_spawner: Spawner) {
92 .prepare_for_rx( 90 .prepare_for_rx(
93 &mdltn_params, 91 &mdltn_params,
94 &rx_pkt_params, 92 &rx_pkt_params,
93 None,
95 Some(&DutyCycleParams { 94 Some(&DutyCycleParams {
96 rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s 95 rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s
97 sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s 96 sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s
98 }), 97 }),
99 false, 98 false,
100 false,
101 0,
102 0,
103 ) 99 )
104 .await 100 .await
105 { 101 {
diff --git a/examples/nrf52840/src/bin/lora_p2p_send.rs b/examples/nrf52840/src/bin/lora_p2p_send.rs
index 1c8bbc27a..676221a27 100644
--- a/examples/nrf52840/src/bin/lora_p2p_send.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_send.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 let iv = 41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); 42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { 45 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
@@ -97,7 +95,7 @@ async fn main(_spawner: Spawner) {
97 } 95 }
98 }; 96 };
99 97
100 match lora.sleep(&mut delay).await { 98 match lora.sleep(false).await {
101 Ok(()) => info!("Sleep successful"), 99 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err), 100 Err(err) => info!("Sleep unsuccessful = {}", err),
103 } 101 }
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 4968a79aa..86d969ed5 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = [ 9embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = [
10 "defmt", 10 "defmt",
11] } 11] }
12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", 12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread",
@@ -14,7 +14,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature
14 "defmt", 14 "defmt",
15 "integrated-timers", 15 "integrated-timers",
16] } 16] }
17embassy-time = { version = "0.1.2", path = "../../embassy-time", features = [ 17embassy-time = { version = "0.1.3", 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 3efc804ac..2677e0402 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.1.3", 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"] }
@@ -17,9 +17,9 @@ embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", fea
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
19embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } 19embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] }
20lora-phy = { version = "1" } 20lora-phy = { version = "2" }
21lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } 21lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] }
22lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } 22lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"] }
23cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 23cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
24cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 24cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
25 25
@@ -55,6 +55,3 @@ rand = { version = "0.8.5", default-features = false }
55 55
56[profile.release] 56[profile.release]
57debug = 2 57debug = 2
58
59[patch.crates-io]
60lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
new file mode 100644
index 000000000..7de300fb8
--- /dev/null
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -0,0 +1,118 @@
1//! This example shows how to use the 2040 as an i2c slave.
2#![no_std]
3#![no_main]
4#![feature(type_alias_impl_trait)]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave};
10use embassy_time::{Duration, Timer};
11use embedded_hal_async::i2c::I2c;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
16 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
17});
18
19const DEV_ADDR: u8 = 0x42;
20
21#[embassy_executor::task]
22async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
23 info!("Device start");
24
25 let mut state = 0;
26
27 loop {
28 let mut buf = [0u8; 128];
29 match dev.listen(&mut buf).await {
30 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]),
31 Ok(i2c_slave::Command::Read) => loop {
32 match dev.respond_to_read(&[state]).await {
33 Ok(x) => match x {
34 i2c_slave::ReadStatus::Done => break,
35 i2c_slave::ReadStatus::NeedMoreBytes => (),
36 i2c_slave::ReadStatus::LeftoverBytes(x) => {
37 info!("tried to write {} extra bytes", x);
38 break;
39 }
40 },
41 Err(e) => error!("error while responding {}", e),
42 }
43 },
44 Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]),
45 Ok(i2c_slave::Command::WriteRead(len)) => {
46 info!("device recieved write read: {:x}", buf[..len]);
47 match buf[0] {
48 // Set the state
49 0xC2 => {
50 state = buf[1];
51 match dev.respond_and_fill(&[state], 0x00).await {
52 Ok(read_status) => info!("response read status {}", read_status),
53 Err(e) => error!("error while responding {}", e),
54 }
55 }
56 // Reset State
57 0xC8 => {
58 state = 0;
59 match dev.respond_and_fill(&[state], 0x00).await {
60 Ok(read_status) => info!("response read status {}", read_status),
61 Err(e) => error!("error while responding {}", e),
62 }
63 }
64 x => error!("Invalid Write Read {:x}", x),
65 }
66 }
67 Err(e) => error!("{}", e),
68 }
69 }
70}
71
72#[embassy_executor::task]
73async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
74 info!("Controller start");
75
76 loop {
77 let mut resp_buff = [0u8; 2];
78 for i in 0..10 {
79 match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await {
80 Ok(_) => info!("write_read response: {}", resp_buff),
81 Err(e) => error!("Error writing {}", e),
82 }
83
84 Timer::after(Duration::from_millis(100)).await;
85 }
86 match con.read(DEV_ADDR, &mut resp_buff).await {
87 Ok(_) => info!("read response: {}", resp_buff),
88 Err(e) => error!("Error writing {}", e),
89 }
90 match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await {
91 Ok(_) => info!("write_read response: {}", resp_buff),
92 Err(e) => error!("Error writing {}", e),
93 }
94 Timer::after(Duration::from_millis(100)).await;
95 }
96}
97
98#[embassy_executor::main]
99async fn main(spawner: Spawner) {
100 let p = embassy_rp::init(Default::default());
101 info!("Hello World!");
102
103 let d_sda = p.PIN_3;
104 let d_scl = p.PIN_2;
105 let mut config = i2c_slave::Config::default();
106 config.addr = DEV_ADDR as u16;
107 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
108
109 unwrap!(spawner.spawn(device_task(device)));
110
111 let c_sda = p.PIN_1;
112 let c_scl = p.PIN_0;
113 let mut config = i2c::Config::default();
114 config.frequency = 5_000;
115 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
116
117 unwrap!(spawner.spawn(controller_task(controller)));
118}
diff --git a/examples/rp/src/bin/lora_lorawan.rs b/examples/rp/src/bin/lora_lorawan.rs
index d631fafa1..e7e81863e 100644
--- a/examples/rp/src/bin/lora_lorawan.rs
+++ b/examples/rp/src/bin/lora_lorawan.rs
@@ -19,6 +19,7 @@ use lora_phy::LoRa;
19use lorawan::default_crypto::DefaultFactory as Crypto; 19use lorawan::default_crypto::DefaultFactory as Crypto;
20use lorawan_device::async_device::lora_radio::LoRaRadio; 20use lorawan_device::async_device::lora_radio::LoRaRadio;
21use lorawan_device::async_device::{region, Device, JoinMode}; 21use lorawan_device::async_device::{region, Device, JoinMode};
22use lorawan_device::{AppEui, AppKey, DevEui};
22use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
23 24
24const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region 25const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
@@ -39,16 +40,8 @@ async fn main(_spawner: Spawner) {
39 40
40 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); 41 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
41 42
42 let mut delay = Delay;
43
44 let lora = { 43 let lora = {
45 match LoRa::new( 44 match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), true, Delay).await {
46 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
47 true,
48 &mut delay,
49 )
50 .await
51 {
52 Ok(l) => l, 45 Ok(l) => l,
53 Err(err) => { 46 Err(err) => {
54 info!("Radio error = {}", err); 47 info!("Radio error = {}", err);
@@ -66,9 +59,9 @@ async fn main(_spawner: Spawner) {
66 // TODO: Adjust the EUI and Keys according to your network credentials 59 // TODO: Adjust the EUI and Keys according to your network credentials
67 match device 60 match device
68 .join(&JoinMode::OTAA { 61 .join(&JoinMode::OTAA {
69 deveui: [0, 0, 0, 0, 0, 0, 0, 0], 62 deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
70 appeui: [0, 0, 0, 0, 0, 0, 0, 0], 63 appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
71 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 64 appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
72 }) 65 })
73 .await 66 .await
74 { 67 {
diff --git a/examples/rp/src/bin/lora_p2p_receive.rs b/examples/rp/src/bin/lora_p2p_receive.rs
index 396d669de..5891826fd 100644
--- a/examples/rp/src/bin/lora_p2p_receive.rs
+++ b/examples/rp/src/bin/lora_p2p_receive.rs
@@ -35,16 +35,8 @@ async fn main(_spawner: Spawner) {
35 35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); 36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37 37
38 let mut delay = Delay;
39
40 let mut lora = { 38 let mut lora = {
41 match LoRa::new( 39 match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await {
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l, 40 Ok(l) => l,
49 Err(err) => { 41 Err(err) => {
50 info!("Radio error = {}", err); 42 info!("Radio error = {}", err);
@@ -83,7 +75,7 @@ async fn main(_spawner: Spawner) {
83 }; 75 };
84 76
85 match lora 77 match lora
86 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) 78 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false)
87 .await 79 .await
88 { 80 {
89 Ok(()) => {} 81 Ok(()) => {}
diff --git a/examples/rp/src/bin/lora_p2p_send.rs b/examples/rp/src/bin/lora_p2p_send.rs
index a0f70fa5c..94bdb4e92 100644
--- a/examples/rp/src/bin/lora_p2p_send.rs
+++ b/examples/rp/src/bin/lora_p2p_send.rs
@@ -35,16 +35,8 @@ async fn main(_spawner: Spawner) {
35 35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); 36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37 37
38 let mut delay = Delay;
39
40 let mut lora = { 38 let mut lora = {
41 match LoRa::new( 39 match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await {
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l, 40 Ok(l) => l,
49 Err(err) => { 41 Err(err) => {
50 info!("Radio error = {}", err); 42 info!("Radio error = {}", err);
@@ -97,7 +89,7 @@ async fn main(_spawner: Spawner) {
97 } 89 }
98 }; 90 };
99 91
100 match lora.sleep(&mut delay).await { 92 match lora.sleep(false).await {
101 Ok(()) => info!("Sleep successful"), 93 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err), 94 Err(err) => info!("Sleep unsuccessful = {}", err),
103 } 95 }
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
index b54cc92f6..e31aa62a2 100644
--- a/examples/rp/src/bin/lora_p2p_send_multicore.rs
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -69,16 +69,9 @@ async fn core1_task(
69 iv: GenericSx126xInterfaceVariant<Output<'static, AnyPin>, Input<'static, AnyPin>>, 69 iv: GenericSx126xInterfaceVariant<Output<'static, AnyPin>, Input<'static, AnyPin>>,
70) { 70) {
71 info!("Hello from core 1"); 71 info!("Hello from core 1");
72 let mut delay = Delay;
73 72
74 let mut lora = { 73 let mut lora = {
75 match LoRa::new( 74 match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await {
76 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
77 false,
78 &mut delay,
79 )
80 .await
81 {
82 Ok(l) => l, 75 Ok(l) => l,
83 Err(err) => { 76 Err(err) => {
84 info!("Radio error = {}", err); 77 info!("Radio error = {}", err);
@@ -132,7 +125,7 @@ async fn core1_task(
132 } 125 }
133 }; 126 };
134 127
135 match lora.sleep(&mut delay).await { 128 match lora.sleep(false).await {
136 Ok(()) => info!("Sleep successful"), 129 Ok(()) => info!("Sleep successful"),
137 Err(err) => info!("Sleep unsuccessful = {}", err), 130 Err(err) => info!("Sleep unsuccessful = {}", err),
138 } 131 }
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index 707c99b78..aa9e52cbd 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -91,13 +91,11 @@ async fn main(_spawner: Spawner) {
91 let (mut uart_tx, mut uart_rx) = uart.split(); 91 let (mut uart_tx, mut uart_rx) = uart.split();
92 92
93 // Pipe setup 93 // Pipe setup
94 let usb_pipe: Pipe<NoopRawMutex, 20> = Pipe::new(); 94 let mut usb_pipe: Pipe<NoopRawMutex, 20> = Pipe::new();
95 let mut usb_pipe_writer = usb_pipe.writer(); 95 let (mut usb_pipe_reader, mut usb_pipe_writer) = usb_pipe.split();
96 let mut usb_pipe_reader = usb_pipe.reader();
97 96
98 let uart_pipe: Pipe<NoopRawMutex, 20> = Pipe::new(); 97 let mut uart_pipe: Pipe<NoopRawMutex, 20> = Pipe::new();
99 let mut uart_pipe_writer = uart_pipe.writer(); 98 let (mut uart_pipe_reader, mut uart_pipe_writer) = uart_pipe.split();
100 let mut uart_pipe_reader = uart_pipe.reader();
101 99
102 let (mut usb_tx, mut usb_rx) = class.split(); 100 let (mut usb_tx, mut usb_rx) = class.split();
103 101
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index bc87016ec..5c0c60246 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -138,8 +138,9 @@ async fn main(_spawner: Spawner) {
138 const NUM_LEDS: usize = 1; 138 const NUM_LEDS: usize = 1;
139 let mut data = [RGB8::default(); NUM_LEDS]; 139 let mut data = [RGB8::default(); NUM_LEDS];
140 140
141 // For the thing plus, use pin 8 141 // Common neopixel pins:
142 // For the feather, use pin 16 142 // Thing plus: 8
143 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4
143 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); 144 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
144 145
145 // Loop forever making RGB values and pushing them out to the WS2812. 146 // Loop forever making RGB values and pushing them out to the WS2812.
@@ -152,7 +153,7 @@ async fn main(_spawner: Spawner) {
152 } 153 }
153 ws2812.write(&data).await; 154 ws2812.write(&data).await;
154 155
155 Timer::after(Duration::from_micros(5)).await; 156 Timer::after(Duration::from_millis(10)).await;
156 } 157 }
157 } 158 }
158} 159}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 0d4d5fa12..e54f36980 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -5,14 +5,16 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "std", "nightly"] } 10embassy-time = { version = "0.1.3", 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", "proto-ipv6"] } 11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
13embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]}
13embedded-io-async = { version = "0.5.0" } 14embedded-io-async = { version = "0.5.0" }
14embedded-io-adapters = { version = "0.5.0", features = ["futures-03"] } 15embedded-io-adapters = { version = "0.5.0", features = ["futures-03"] }
15critical-section = { version = "1.1", features = ["std"] } 16critical-section = { version = "1.1", features = ["std"] }
17smoltcp = { version = "0.10.0", features = ["dns-max-server-count-4"] }
16 18
17async-io = "1.6.0" 19async-io = "1.6.0"
18env_logger = "0.9.0" 20env_logger = "0.9.0"
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
new file mode 100644
index 000000000..9cf6e19df
--- /dev/null
+++ b/examples/std/src/bin/net_ppp.rs
@@ -0,0 +1,218 @@
1//! Testing against pppd:
2//!
3//! echo myuser $(hostname) mypass 192.168.7.10 >> /etc/ppp/pap-secrets
4//! socat -v -x PTY,link=pty1,rawer PTY,link=pty2,rawer
5//! sudo pppd $PWD/pty1 115200 192.168.7.1: ms-dns 8.8.4.4 ms-dns 8.8.8.8 nodetach debug local persist silent noproxyarp
6//! RUST_LOG=trace cargo run --bin net_ppp -- --device pty2
7//! ping 192.168.7.10
8//! nc 192.168.7.10 1234
9
10#![feature(type_alias_impl_trait)]
11#![feature(async_fn_in_trait, impl_trait_projections)]
12
13#[path = "../serial_port.rs"]
14mod serial_port;
15
16use async_io::Async;
17use clap::Parser;
18use embassy_executor::{Executor, Spawner};
19use embassy_net::tcp::TcpSocket;
20use embassy_net::{Config, ConfigV4, Ipv4Address, Ipv4Cidr, Stack, StackResources};
21use embassy_net_ppp::Runner;
22use embedded_io_async::Write;
23use futures::io::BufReader;
24use heapless::Vec;
25use log::*;
26use nix::sys::termios;
27use rand_core::{OsRng, RngCore};
28use static_cell::{make_static, StaticCell};
29
30use crate::serial_port::SerialPort;
31
32#[derive(Parser)]
33#[clap(version = "1.0")]
34struct Opts {
35 /// Serial port device name
36 #[clap(short, long)]
37 device: String,
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::task]
46async fn ppp_task(
47 stack: &'static Stack<embassy_net_ppp::Device<'static>>,
48 mut runner: Runner<'static>,
49 port: SerialPort,
50) -> ! {
51 let port = Async::new(port).unwrap();
52 let port = BufReader::new(port);
53 let port = adapter::FromFutures::new(port);
54
55 let config = embassy_net_ppp::Config {
56 username: b"myuser",
57 password: b"mypass",
58 };
59
60 runner
61 .run(port, config, |ipv4| {
62 let Some(addr) = ipv4.address else {
63 warn!("PPP did not provide an IP address.");
64 return;
65 };
66 let mut dns_servers = Vec::new();
67 for s in ipv4.dns_servers.iter().flatten() {
68 let _ = dns_servers.push(Ipv4Address::from_bytes(&s.0));
69 }
70 let config = ConfigV4::Static(embassy_net::StaticConfigV4 {
71 address: Ipv4Cidr::new(Ipv4Address::from_bytes(&addr.0), 0),
72 gateway: None,
73 dns_servers,
74 });
75 stack.set_config_v4(config);
76 })
77 .await
78 .unwrap();
79 unreachable!()
80}
81
82#[embassy_executor::task]
83async fn main_task(spawner: Spawner) {
84 let opts: Opts = Opts::parse();
85
86 // Open serial port
87 let baudrate = termios::BaudRate::B115200;
88 let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap();
89
90 // Init network device
91 let state = make_static!(embassy_net_ppp::State::<4, 4>::new());
92 let (device, runner) = embassy_net_ppp::new(state);
93
94 // Generate random seed
95 let mut seed = [0; 8];
96 OsRng.fill_bytes(&mut seed);
97 let seed = u64::from_le_bytes(seed);
98
99 // Init network stack
100 let stack = &*make_static!(Stack::new(
101 device,
102 Config::default(), // don't configure IP yet
103 make_static!(StackResources::<3>::new()),
104 seed
105 ));
106
107 // Launch network task
108 spawner.spawn(net_task(stack)).unwrap();
109 spawner.spawn(ppp_task(stack, runner, port)).unwrap();
110
111 // Then we can use it!
112 let mut rx_buffer = [0; 4096];
113 let mut tx_buffer = [0; 4096];
114 let mut buf = [0; 4096];
115
116 loop {
117 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
118 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
119
120 info!("Listening on TCP:1234...");
121 if let Err(e) = socket.accept(1234).await {
122 warn!("accept error: {:?}", e);
123 continue;
124 }
125
126 info!("Received connection from {:?}", socket.remote_endpoint());
127
128 loop {
129 let n = match socket.read(&mut buf).await {
130 Ok(0) => {
131 warn!("read EOF");
132 break;
133 }
134 Ok(n) => n,
135 Err(e) => {
136 warn!("read error: {:?}", e);
137 break;
138 }
139 };
140
141 info!("rxd {:02x?}", &buf[..n]);
142
143 match socket.write_all(&buf[..n]).await {
144 Ok(()) => {}
145 Err(e) => {
146 warn!("write error: {:?}", e);
147 break;
148 }
149 };
150 }
151 }
152}
153
154static EXECUTOR: StaticCell<Executor> = StaticCell::new();
155
156fn main() {
157 env_logger::builder()
158 .filter_level(log::LevelFilter::Trace)
159 .filter_module("polling", log::LevelFilter::Info)
160 .filter_module("async_io", log::LevelFilter::Info)
161 .format_timestamp_nanos()
162 .init();
163
164 let executor = EXECUTOR.init(Executor::new());
165 executor.run(|spawner| {
166 spawner.spawn(main_task(spawner)).unwrap();
167 });
168}
169
170mod adapter {
171 use core::future::poll_fn;
172 use core::pin::Pin;
173
174 use futures::AsyncBufReadExt;
175
176 /// Adapter from `futures::io` traits.
177 #[derive(Clone)]
178 pub struct FromFutures<T: ?Sized> {
179 inner: T,
180 }
181
182 impl<T> FromFutures<T> {
183 /// Create a new adapter.
184 pub fn new(inner: T) -> Self {
185 Self { inner }
186 }
187 }
188
189 impl<T: ?Sized> embedded_io_async::ErrorType for FromFutures<T> {
190 type Error = std::io::Error;
191 }
192
193 impl<T: futures::io::AsyncRead + Unpin + ?Sized> embedded_io_async::Read for FromFutures<T> {
194 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
195 poll_fn(|cx| Pin::new(&mut self.inner).poll_read(cx, buf)).await
196 }
197 }
198
199 impl<T: futures::io::AsyncBufRead + Unpin + ?Sized> embedded_io_async::BufRead for FromFutures<T> {
200 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
201 self.inner.fill_buf().await
202 }
203
204 fn consume(&mut self, amt: usize) {
205 Pin::new(&mut self.inner).consume(amt)
206 }
207 }
208
209 impl<T: futures::io::AsyncWrite + Unpin + ?Sized> embedded_io_async::Write for FromFutures<T> {
210 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
211 poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await
212 }
213
214 async fn flush(&mut self) -> Result<(), Self::Error> {
215 poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await
216 }
217 }
218}
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 9d188513a..89ecc4995 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32c031c6 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index ca9ab1cf8..db9a24d73 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -14,9 +14,9 @@ cortex-m-rt = "0.7.0"
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
16panic-probe = "0.3" 16panic-probe = "0.3"
17embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 17embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
18embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 18embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
19embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 19embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
20static_cell = { version = "1.1", features = ["nightly"]} 20static_cell = { version = "1.1", features = ["nightly"]}
21 21
22[profile.release] 22[profile.release]
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index 8ed9f98f8..1564ecfc0 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -5,20 +5,26 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime}; 7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::peripherals::ADC;
9use embassy_stm32::{adc, bind_interrupts};
8use embassy_time::{Delay, Duration, Timer}; 10use embassy_time::{Delay, Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
13bind_interrupts!(struct Irqs {
14 ADC1_COMP => adc::InterruptHandler<ADC>;
15});
16
11#[embassy_executor::main] 17#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!"); 20 info!("Hello World!");
15 21
16 let mut adc = Adc::new(p.ADC, &mut Delay); 22 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
17 adc.set_sample_time(SampleTime::Cycles71_5); 23 adc.set_sample_time(SampleTime::Cycles71_5);
18 let mut pin = p.PA1; 24 let mut pin = p.PA1;
19 25
20 let mut vrefint = adc.enable_vref(&mut Delay); 26 let mut vrefint = adc.enable_vref(&mut Delay);
21 let vrefint_sample = adc.read_internal(&mut vrefint); 27 let vrefint_sample = adc.read(&mut vrefint).await;
22 let convert_to_millivolts = |sample| { 28 let convert_to_millivolts = |sample| {
23 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf 29 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
24 // 6.3.4 Embedded reference voltage 30 // 6.3.4 Embedded reference voltage
@@ -28,7 +34,7 @@ async fn main(_spawner: Spawner) {
28 }; 34 };
29 35
30 loop { 36 loop {
31 let v = adc.read(&mut pin); 37 let v = adc.read(&mut pin).await;
32 info!("--> {} - {} mV", v, convert_to_millivolts(v)); 38 info!("--> {} - {} mV", v, convert_to_millivolts(v));
33 Timer::after(Duration::from_millis(100)).await; 39 Timer::after(Duration::from_millis(100)).await;
34 } 40 }
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 16796841e..b032ba817 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f103c8 to your chip name, if necessary. 8# Change stm32f103c8 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index ed59e2799..30947c3c2 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -5,9 +5,15 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::Adc; 7use embassy_stm32::adc::Adc;
8use embassy_stm32::peripherals::ADC1;
9use embassy_stm32::{adc, bind_interrupts};
8use embassy_time::{Delay, Duration, Timer}; 10use embassy_time::{Delay, Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
13bind_interrupts!(struct Irqs {
14 ADC1_2 => adc::InterruptHandler<ADC1>;
15});
16
11#[embassy_executor::main] 17#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
@@ -17,7 +23,7 @@ async fn main(_spawner: Spawner) {
17 let mut pin = p.PB1; 23 let mut pin = p.PB1;
18 24
19 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref(&mut Delay);
20 let vrefint_sample = adc.read(&mut vrefint); 26 let vrefint_sample = adc.read(&mut vrefint).await;
21 let convert_to_millivolts = |sample| { 27 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf 28 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
23 // 5.3.4 Embedded reference voltage 29 // 5.3.4 Embedded reference voltage
@@ -27,7 +33,7 @@ async fn main(_spawner: Spawner) {
27 }; 33 };
28 34
29 loop { 35 loop {
30 let v = adc.read(&mut pin); 36 let v = adc.read(&mut pin).await;
31 info!("--> {} - {} mV", v, convert_to_millivolts(v)); 37 info!("--> {} - {} mV", v, convert_to_millivolts(v));
32 Timer::after(Duration::from_millis(100)).await; 38 Timer::after(Duration::from_millis(100)).await;
33 } 39 }
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 54eadd1a9..1314b6b12 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f207zg to your chip name, if necessary. 8# Change stm32f207zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs
index 17f09538c..894937614 100644
--- a/examples/stm32f2/src/bin/pll.rs
+++ b/examples/stm32f2/src/bin/pll.rs
@@ -39,9 +39,9 @@ async fn main(_spawner: Spawner) {
39 // System clock comes from PLL (= the 120 MHz main PLL output) 39 // System clock comes from PLL (= the 120 MHz main PLL output)
40 config.rcc.mux = ClockSrc::PLL; 40 config.rcc.mux = ClockSrc::PLL;
41 // 120 MHz / 4 = 30 MHz APB1 frequency 41 // 120 MHz / 4 = 30 MHz APB1 frequency
42 config.rcc.apb1_pre = APBPrescaler::Div4; 42 config.rcc.apb1_pre = APBPrescaler::DIV4;
43 // 120 MHz / 2 = 60 MHz APB2 frequency 43 // 120 MHz / 2 = 60 MHz APB2 frequency
44 config.rcc.apb2_pre = APBPrescaler::Div2; 44 config.rcc.apb2_pre = APBPrescaler::DIV2;
45 45
46 let _p = embassy_stm32::init(config); 46 let _p = embassy_stm32::init(config);
47 47
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 5d8f5f74c..534e783de 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f303ze to your chip name, if necessary. 8# Change stm32f303ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 85f01a69e..ce8c212ae 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let config = Config::default(); 24 let config = Config::default();
25 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config); 25 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap();
26 26
27 for n in 0u32.. { 27 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 28 let mut s: String<128> = String::new();
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 65183b88f..239c58b34 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
new file mode 100644
index 000000000..ed246a7db
--- /dev/null
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -0,0 +1,56 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::peripherals::ADC1;
9use embassy_stm32::rcc::AdcClockSource;
10use embassy_stm32::time::mhz;
11use embassy_stm32::{adc, bind_interrupts, Config};
12use embassy_time::{Delay, Duration, Timer};
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 ADC1_2 => adc::InterruptHandler<ADC1>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! {
21 let mut config = Config::default();
22 config.rcc.sysclk = Some(mhz(64));
23 config.rcc.hclk = Some(mhz(64));
24 config.rcc.pclk1 = Some(mhz(32));
25 config.rcc.pclk2 = Some(mhz(64));
26 config.rcc.adc = Some(AdcClockSource::PllDiv1);
27
28 let mut p = embassy_stm32::init(config);
29
30 info!("create adc...");
31
32 let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay);
33
34 adc.set_sample_time(SampleTime::Cycles601_5);
35
36 info!("enable vrefint...");
37
38 let mut vrefint = adc.enable_vref(&mut Delay);
39 let mut temperature = adc.enable_temperature();
40
41 loop {
42 let vref = adc.read(&mut vrefint).await;
43 info!("read vref: {} (should be {})", vref, vrefint.value());
44
45 let temp = adc.read(&mut temperature).await;
46 info!("read temperature: {}", temp);
47
48 let pin = adc.read(&mut p.PA0).await;
49 info!("read pin: {}", pin);
50
51 let pin_mv = (pin as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095;
52 info!("computed pin mv: {}", pin_mv);
53
54 Timer::after(Duration::from_millis(500)).await;
55 }
56}
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 2660b10c5..aebc421b3 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -5,6 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::hrtim::*; 7use embassy_stm32::hrtim::*;
8use embassy_stm32::rcc::HrtimClockSource;
8use embassy_stm32::time::{khz, mhz}; 9use embassy_stm32::time::{khz, mhz};
9use embassy_stm32::Config; 10use embassy_stm32::Config;
10use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
@@ -17,6 +18,7 @@ async fn main(_spawner: Spawner) {
17 config.rcc.hclk = Some(mhz(64)); 18 config.rcc.hclk = Some(mhz(64));
18 config.rcc.pclk1 = Some(mhz(32)); 19 config.rcc.pclk1 = Some(mhz(32));
19 config.rcc.pclk2 = Some(mhz(64)); 20 config.rcc.pclk2 = Some(mhz(64));
21 config.rcc.hrtim = HrtimClockSource::PllClk;
20 22
21 let p = embassy_stm32::init(config); 23 let p = embassy_stm32::init(config);
22 info!("Hello World!"); 24 info!("Hello World!");
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index ed456c5cb..4b4fb479b 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-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"] } 9embassy-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"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
15 15
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 1c9a0b35d..dd10385c4 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 // Startup delay can be combined to the maximum of either 24 // Startup delay can be combined to the maximum of either
25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); 25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
26 26
27 let vrefint_sample = adc.read_internal(&mut vrefint); 27 let vrefint_sample = adc.read(&mut vrefint);
28 28
29 let convert_to_millivolts = |sample| { 29 let convert_to_millivolts = |sample| {
30 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf 30 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
@@ -55,12 +55,12 @@ async fn main(_spawner: Spawner) {
55 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); 55 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
56 56
57 // Read internal temperature 57 // Read internal temperature
58 let v = adc.read_internal(&mut temp); 58 let v = adc.read(&mut temp);
59 let celcius = convert_to_celcius(v); 59 let celcius = convert_to_celcius(v);
60 info!("Internal temp: {} ({} C)", v, celcius); 60 info!("Internal temp: {} ({} C)", v, celcius);
61 61
62 // Read internal voltage reference 62 // Read internal voltage reference
63 let v = adc.read_internal(&mut vrefint); 63 let v = adc.read(&mut vrefint);
64 info!("VrefInt: {}", v); 64 info!("VrefInt: {}", v);
65 65
66 Timer::after(Duration::from_millis(100)).await; 66 Timer::after(Duration::from_millis(100)).await;
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 393e60b73..16bf5d949 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -79,7 +79,10 @@ async fn main(spawner: Spawner) -> ! {
79 )); 79 ));
80 80
81 // Launch network task 81 // Launch network task
82 unwrap!(spawner.spawn(net_task(&stack))); 82 unwrap!(spawner.spawn(net_task(stack)));
83
84 // Ensure DHCP configuration is up before trying connect
85 stack.wait_config_up().await;
83 86
84 info!("Network task initialized"); 87 info!("Network task initialized");
85 88
@@ -97,6 +100,7 @@ async fn main(spawner: Spawner) -> ! {
97 let r = socket.connect(remote_endpoint).await; 100 let r = socket.connect(remote_endpoint).await;
98 if let Err(e) = r { 101 if let Err(e) = r {
99 info!("connect error: {:?}", e); 102 info!("connect error: {:?}", e);
103 Timer::after(Duration::from_secs(1)).await;
100 continue; 104 continue;
101 } 105 }
102 info!("connected!"); 106 info!("connected!");
@@ -105,7 +109,7 @@ async fn main(spawner: Spawner) -> ! {
105 let r = socket.write_all(&buf).await; 109 let r = socket.write_all(&buf).await;
106 if let Err(e) = r { 110 if let Err(e) = r {
107 info!("write error: {:?}", e); 111 info!("write error: {:?}", e);
108 continue; 112 break;
109 } 113 }
110 Timer::after(Duration::from_secs(1)).await; 114 Timer::after(Duration::from_secs(1)).await;
111 } 115 }
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index 0eca58203..e33746008 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -5,13 +5,18 @@
5use chrono::{NaiveDate, NaiveDateTime}; 5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::rtc::{Rtc, RtcConfig}; 8use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig};
9use embassy_stm32::Config;
9use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
12#[embassy_executor::main] 13#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 15 let mut config = Config::default();
16 config.rcc.lsi = true;
17 config.rcc.rtc = Option::Some(RtcClockSource::LSI);
18 let p = embassy_stm32::init(config);
19
15 info!("Hello World!"); 20 info!("Hello World!");
16 21
17 let now = NaiveDate::from_ymd_opt(2020, 5, 15) 22 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
@@ -23,8 +28,11 @@ async fn main(_spawner: Spawner) {
23 28
24 rtc.set_datetime(now.into()).expect("datetime not set"); 29 rtc.set_datetime(now.into()).expect("datetime not set");
25 30
26 // In reality the delay would be much longer 31 loop {
27 Timer::after(Duration::from_millis(20000)).await; 32 let now: NaiveDateTime = rtc.now().unwrap().into();
33
34 info!("{}", now.timestamp());
28 35
29 let _then: NaiveDateTime = rtc.now().unwrap().into(); 36 Timer::after(Duration::from_millis(1000)).await;
37 }
30} 38}
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 7680fe845..45e94715f 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -20,7 +20,7 @@ fn main() -> ! {
20 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
21 21
22 let config = Config::default(); 22 let config = Config::default();
23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config); 23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap();
24 24
25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
26 info!("wrote Hello, starting echo"); 26 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs
index c0a64d94b..71abc2893 100644
--- a/examples/stm32f4/src/bin/usart_buffered.rs
+++ b/examples/stm32f4/src/bin/usart_buffered.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 22
23 let mut tx_buf = [0u8; 32]; 23 let mut tx_buf = [0u8; 32];
24 let mut rx_buf = [0u8; 32]; 24 let mut rx_buf = [0u8; 32];
25 let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config); 25 let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config).unwrap();
26 26
27 loop { 27 loop {
28 let buf = buf_usart.fill_buf().await.unwrap(); 28 let buf = buf_usart.fill_buf().await.unwrap();
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index 3408ec370..dca25a78c 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let config = Config::default(); 24 let config = Config::default();
25 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config); 25 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap();
26 26
27 for n in 0u32.. { 27 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 28 let mut s: String<128> = String::new();
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index b658a9640..bf8f413d8 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32f767zi to your chip name, if necessary. 8# Change stm32f767zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
14embedded-io-async = { version = "0.5.0" } 14embedded-io-async = { version = "0.5.0" }
15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 70b3b2a75..bc4ed2892 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 let mut pin = p.PA3; 17 let mut pin = p.PA3;
18 18
19 let mut vrefint = adc.enable_vrefint(); 19 let mut vrefint = adc.enable_vrefint();
20 let vrefint_sample = adc.read_internal(&mut vrefint); 20 let vrefint_sample = adc.read(&mut vrefint);
21 let convert_to_millivolts = |sample| { 21 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf 22 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
23 // 6.3.27 Reference voltage 23 // 6.3.27 Reference voltage
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index f0e280c35..93c97c8ee 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -80,7 +80,10 @@ async fn main(spawner: Spawner) -> ! {
80 )); 80 ));
81 81
82 // Launch network task 82 // Launch network task
83 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(stack)));
84
85 // Ensure DHCP configuration is up before trying connect
86 stack.wait_config_up().await;
84 87
85 info!("Network task initialized"); 88 info!("Network task initialized");
86 89
@@ -98,6 +101,7 @@ async fn main(spawner: Spawner) -> ! {
98 let r = socket.connect(remote_endpoint).await; 101 let r = socket.connect(remote_endpoint).await;
99 if let Err(e) = r { 102 if let Err(e) = r {
100 info!("connect error: {:?}", e); 103 info!("connect error: {:?}", e);
104 Timer::after(Duration::from_secs(1)).await;
101 continue; 105 continue;
102 } 106 }
103 info!("connected!"); 107 info!("connected!");
@@ -106,7 +110,7 @@ async fn main(spawner: Spawner) -> ! {
106 let r = socket.write_all(&buf).await; 110 let r = socket.write_all(&buf).await;
107 if let Err(e) = r { 111 if let Err(e) = r {
108 info!("write error: {:?}", e); 112 info!("write error: {:?}", e);
109 continue; 113 break;
110 } 114 }
111 Timer::after(Duration::from_secs(1)).await; 115 Timer::after(Duration::from_secs(1)).await;
112 } 116 }
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index 4700287a7..ba064081e 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs {
20async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
21 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
22 let config = Config::default(); 22 let config = Config::default();
23 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config); 23 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap();
24 24
25 for n in 0u32.. { 25 for n in 0u32.. {
26 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 4e88151a5..b4b423d58 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32g071rb to your chip name, if necessary. 8# Change stm32g071rb to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 7bb05dbc8..59da06283 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -7,10 +7,12 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32g491re to your chip name, if necessary. 8# Change stm32g491re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15usbd-hid = "0.6.0"
14 16
15defmt = "0.3" 17defmt = "0.3"
16defmt-rtt = "0.4" 18defmt-rtt = "0.4"
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
new file mode 100644
index 000000000..a792748bc
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
9use embassy_stm32::Config;
10use embassy_time::{Delay, Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let mut config = Config::default();
16
17 config.rcc.pll = Some(Pll {
18 source: PllSrc::HSI16,
19 prediv_m: PllM::Div4,
20 mul_n: PllN::Mul85,
21 div_p: None,
22 div_q: None,
23 // Main system clock at 170 MHz
24 div_r: Some(PllR::Div2),
25 });
26
27 config.rcc.adc12_clock_source = AdcClockSource::SysClk;
28 config.rcc.mux = ClockSrc::PLL;
29
30 let mut p = embassy_stm32::init(config);
31 info!("Hello World!");
32
33 let mut adc = Adc::new(p.ADC2, &mut Delay);
34 adc.set_sample_time(SampleTime::Cycles32_5);
35
36 loop {
37 let measured = adc.read(&mut p.PA7);
38 info!("measured: {}", measured);
39 Timer::after(Duration::from_millis(500)).await;
40 }
41}
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index f7a1de63e..42a426185 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32h563zi to your chip name, if necessary. 8# Change stm32h563zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embedded-io-async = { version = "0.5.0" } 14embedded-io-async = { version = "0.5.0" }
15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -29,7 +29,7 @@ heapless = { version = "0.7.5", default-features = false }
29rand_core = "0.6.3" 29rand_core = "0.6.3"
30critical-section = "1.1" 30critical-section = "1.1"
31micromath = "2.0.0" 31micromath = "2.0.0"
32stm32-fmc = "0.2.4" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.0" 33embedded-storage = "0.3.0"
34static_cell = { version = "1.1", features = ["nightly"]} 34static_cell = { version = "1.1", features = ["nightly"]}
35 35
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 763520ab8..4e92d0647 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -48,10 +48,10 @@ async fn main(spawner: Spawner) -> ! {
48 divq: Some(2), 48 divq: Some(2),
49 divr: None, 49 divr: None,
50 }); 50 });
51 config.rcc.ahb_pre = AHBPrescaler::NotDivided; 51 config.rcc.ahb_pre = AHBPrescaler::DIV1;
52 config.rcc.apb1_pre = APBPrescaler::NotDivided; 52 config.rcc.apb1_pre = APBPrescaler::DIV1;
53 config.rcc.apb2_pre = APBPrescaler::NotDivided; 53 config.rcc.apb2_pre = APBPrescaler::DIV1;
54 config.rcc.apb3_pre = APBPrescaler::NotDivided; 54 config.rcc.apb3_pre = APBPrescaler::DIV1;
55 config.rcc.sys = Sysclk::Pll1P; 55 config.rcc.sys = Sysclk::Pll1P;
56 config.rcc.voltage_scale = VoltageScale::Scale0; 56 config.rcc.voltage_scale = VoltageScale::Scale0;
57 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
@@ -101,6 +101,9 @@ async fn main(spawner: Spawner) -> ! {
101 // Launch network task 101 // Launch network task
102 unwrap!(spawner.spawn(net_task(&stack))); 102 unwrap!(spawner.spawn(net_task(&stack)));
103 103
104 // Ensure DHCP configuration is up before trying connect
105 stack.wait_config_up().await;
106
104 info!("Network task initialized"); 107 info!("Network task initialized");
105 108
106 // Then we can use it! 109 // Then we can use it!
@@ -125,7 +128,7 @@ async fn main(spawner: Spawner) -> ! {
125 let r = socket.write_all(b"Hello\n").await; 128 let r = socket.write_all(b"Hello\n").await;
126 if let Err(e) = r { 129 if let Err(e) = r {
127 info!("write error: {:?}", e); 130 info!("write error: {:?}", e);
128 continue; 131 break;
129 } 132 }
130 Timer::after(Duration::from_secs(1)).await; 133 Timer::after(Duration::from_secs(1)).await;
131 } 134 }
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
index 0abb94abb..db04d4e55 100644
--- a/examples/stm32h5/src/bin/usart.rs
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -20,7 +20,7 @@ async fn main_task() {
20 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
21 21
22 let config = Config::default(); 22 let config = Config::default();
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); 23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap();
24 24
25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
26 info!("wrote Hello, starting echo"); 26 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
index 48264f884..bafe50839 100644
--- a/examples/stm32h5/src/bin/usart_dma.rs
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -23,7 +23,7 @@ async fn main_task() {
23 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
24 24
25 let config = Config::default(); 25 let config = Config::default();
26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config); 26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap();
27 27
28 for n in 0u32.. { 28 for n in 0u32.. {
29 let mut s: String<128> = String::new(); 29 let mut s: String<128> = String::new();
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index a6b2e690b..d9037c014 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
36 info!("Hello World!"); 36 info!("Hello World!");
37 37
38 let config = Config::default(); 38 let config = Config::default();
39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config); 39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); 40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
41 41
42 let (mut tx, rx) = usart.split(); 42 let (mut tx, rx) = usart.split();
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 336eed644..cbe540a06 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -35,10 +35,10 @@ async fn main(_spawner: Spawner) {
35 divq: None, 35 divq: None,
36 divr: None, 36 divr: None,
37 }); 37 });
38 config.rcc.ahb_pre = AHBPrescaler::Div2; 38 config.rcc.ahb_pre = AHBPrescaler::DIV2;
39 config.rcc.apb1_pre = APBPrescaler::Div4; 39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::Div2; 40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.apb3_pre = APBPrescaler::Div4; 41 config.rcc.apb3_pre = APBPrescaler::DIV4;
42 config.rcc.sys = Sysclk::Pll1P; 42 config.rcc.sys = Sysclk::Pll1P;
43 config.rcc.voltage_scale = VoltageScale::Scale0; 43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 1ee11b07f..c1d49963c 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embedded-io-async = { version = "0.5.0" } 14embedded-io-async = { version = "0.5.0" }
15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -29,7 +29,7 @@ heapless = { version = "0.7.5", default-features = false }
29rand_core = "0.6.3" 29rand_core = "0.6.3"
30critical-section = "1.1" 30critical-section = "1.1"
31micromath = "2.0.0" 31micromath = "2.0.0"
32stm32-fmc = "0.2.4" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.0" 33embedded-storage = "0.3.0"
34static_cell = { version = "1.1", features = ["nightly"]} 34static_cell = { version = "1.1", features = ["nightly"]}
35 35
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index 0e1e28c72..77922d4bc 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -5,8 +5,6 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime}; 7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::rcc::AdcClockSource;
9use embassy_stm32::time::mhz;
10use embassy_stm32::Config; 8use embassy_stm32::Config;
11use embassy_time::{Delay, Duration, Timer}; 9use embassy_time::{Delay, Duration, Timer};
12use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -14,10 +12,34 @@ use {defmt_rtt as _, panic_probe as _};
14#[embassy_executor::main] 12#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
16 let mut config = Config::default(); 14 let mut config = Config::default();
17 config.rcc.sys_ck = Some(mhz(400)); 15 {
18 config.rcc.hclk = Some(mhz(200)); 16 use embassy_stm32::rcc::*;
19 config.rcc.per_ck = Some(mhz(64)); 17 config.rcc.hsi = Some(Hsi::Mhz64);
20 config.rcc.adc_clock_source = AdcClockSource::PerCk; 18 config.rcc.csi = true;
19 config.rcc.pll_src = PllSource::Hsi;
20 config.rcc.pll1 = Some(Pll {
21 prediv: 4,
22 mul: 50,
23 divp: Some(2),
24 divq: Some(8), // SPI1 cksel defaults to pll1_q
25 divr: None,
26 });
27 config.rcc.pll2 = Some(Pll {
28 prediv: 4,
29 mul: 50,
30 divp: Some(8), // 100mhz
31 divq: None,
32 divr: None,
33 });
34 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
35 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
36 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.voltage_scale = VoltageScale::Scale1;
41 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
42 }
21 let mut p = embassy_stm32::init(config); 43 let mut p = embassy_stm32::init(config);
22 44
23 info!("Hello World!"); 45 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 6f75a0630..de8ddc292 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -6,8 +6,8 @@ use embassy_executor::Spawner;
6use embassy_stm32::dcmi::{self, *}; 6use embassy_stm32::dcmi::{self, *};
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::i2c::I2c; 8use embassy_stm32::i2c::I2c;
9use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 9use embassy_stm32::rcc::{Mco, Mco1Source};
10use embassy_stm32::time::{khz, mhz}; 10use embassy_stm32::time::khz;
11use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; 11use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use ov7725::*; 13use ov7725::*;
@@ -26,17 +26,30 @@ bind_interrupts!(struct Irqs {
26#[embassy_executor::main] 26#[embassy_executor::main]
27async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
28 let mut config = Config::default(); 28 let mut config = Config::default();
29 config.rcc.sys_ck = Some(mhz(400)); 29 {
30 config.rcc.hclk = Some(mhz(400)); 30 use embassy_stm32::rcc::*;
31 config.rcc.pll1.q_ck = Some(mhz(100)); 31 config.rcc.hsi = Some(Hsi::Mhz64);
32 config.rcc.pclk1 = Some(mhz(100)); 32 config.rcc.csi = true;
33 config.rcc.pclk2 = Some(mhz(100)); 33 config.rcc.pll_src = PllSource::Hsi;
34 config.rcc.pclk3 = Some(mhz(100)); 34 config.rcc.pll1 = Some(Pll {
35 config.rcc.pclk4 = Some(mhz(100)); 35 prediv: 4,
36 mul: 50,
37 divp: Some(2),
38 divq: Some(8), // 100mhz
39 divr: None,
40 });
41 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
42 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
43 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
45 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
46 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.voltage_scale = VoltageScale::Scale1;
48 }
36 let p = embassy_stm32::init(config); 49 let p = embassy_stm32::init(config);
37 50
38 defmt::info!("Hello World!"); 51 defmt::info!("Hello World!");
39 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); 52 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3);
40 53
41 let mut led = Output::new(p.PE3, Level::High, Speed::Low); 54 let mut led = Output::new(p.PE3, Level::High, Speed::Low);
42 let cam_i2c = I2c::new( 55 let cam_i2c = I2c::new(
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index ee078286b..93df7a319 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -6,7 +6,6 @@ use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::time::mhz;
10use embassy_stm32::Config; 9use embassy_stm32::Config;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -15,9 +14,34 @@ fn main() -> ! {
15 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
16 15
17 let mut config = Config::default(); 16 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 17 {
19 config.rcc.hclk = Some(mhz(200)); 18 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 19 config.rcc.hsi = Some(Hsi::Mhz64);
20 config.rcc.csi = true;
21 config.rcc.pll_src = PllSource::Hsi;
22 config.rcc.pll1 = Some(Pll {
23 prediv: 4,
24 mul: 50,
25 divp: Some(2),
26 divq: Some(8), // SPI1 cksel defaults to pll1_q
27 divr: None,
28 });
29 config.rcc.pll2 = Some(Pll {
30 prediv: 4,
31 mul: 50,
32 divp: Some(8), // 100mhz
33 divq: None,
34 divr: None,
35 });
36 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
37 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
38 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
44 }
21 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
22 46
23 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 47 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index a9cb5d1ed..8c921abca 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::dac::{DacChannel, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7}; 9use embassy_stm32::peripherals::{TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::{mhz, Hertz}; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance; 12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext; 13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -22,9 +22,34 @@ pub type Dac2Type =
22#[embassy_executor::main] 22#[embassy_executor::main]
23async fn main(spawner: Spawner) { 23async fn main(spawner: Spawner) {
24 let mut config = embassy_stm32::Config::default(); 24 let mut config = embassy_stm32::Config::default();
25 config.rcc.sys_ck = Some(mhz(400)); 25 {
26 config.rcc.hclk = Some(mhz(100)); 26 use embassy_stm32::rcc::*;
27 config.rcc.pll1.q_ck = Some(mhz(100)); 27 config.rcc.hsi = Some(Hsi::Mhz64);
28 config.rcc.csi = true;
29 config.rcc.pll_src = PllSource::Hsi;
30 config.rcc.pll1 = Some(Pll {
31 prediv: 4,
32 mul: 50,
33 divp: Some(2),
34 divq: Some(8), // SPI1 cksel defaults to pll1_q
35 divr: None,
36 });
37 config.rcc.pll2 = Some(Pll {
38 prediv: 4,
39 mul: 50,
40 divp: Some(8), // 100mhz
41 divq: None,
42 divr: None,
43 });
44 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.voltage_scale = VoltageScale::Scale1;
51 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
52 }
28 53
29 // Initialize the board and obtain a Peripherals instance 54 // Initialize the board and obtain a Peripherals instance
30 let p: embassy_stm32::Peripherals = embassy_stm32::init(config); 55 let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 26a386e49..1b5d71ed3 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -10,7 +10,6 @@ use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
@@ -33,9 +32,27 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
33#[embassy_executor::main] 32#[embassy_executor::main]
34async fn main(spawner: Spawner) -> ! { 33async fn main(spawner: Spawner) -> ! {
35 let mut config = Config::default(); 34 let mut config = Config::default();
36 config.rcc.sys_ck = Some(mhz(400)); 35 {
37 config.rcc.hclk = Some(mhz(200)); 36 use embassy_stm32::rcc::*;
38 config.rcc.pll1.q_ck = Some(mhz(100)); 37 config.rcc.hsi = Some(Hsi::Mhz64);
38 config.rcc.csi = true;
39 config.rcc.hsi48 = true; // needed for RNG
40 config.rcc.pll_src = PllSource::Hsi;
41 config.rcc.pll1 = Some(Pll {
42 prediv: 4,
43 mul: 50,
44 divp: Some(2),
45 divq: None,
46 divr: None,
47 });
48 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
49 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
50 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.voltage_scale = VoltageScale::Scale1;
55 }
39 let p = embassy_stm32::init(config); 56 let p = embassy_stm32::init(config);
40 info!("Hello World!"); 57 info!("Hello World!");
41 58
@@ -83,6 +100,9 @@ async fn main(spawner: Spawner) -> ! {
83 // Launch network task 100 // Launch network task
84 unwrap!(spawner.spawn(net_task(&stack))); 101 unwrap!(spawner.spawn(net_task(&stack)));
85 102
103 // Ensure DHCP configuration is up before trying connect
104 stack.wait_config_up().await;
105
86 info!("Network task initialized"); 106 info!("Network task initialized");
87 107
88 // Then we can use it! 108 // Then we can use it!
@@ -99,6 +119,7 @@ async fn main(spawner: Spawner) -> ! {
99 let r = socket.connect(remote_endpoint).await; 119 let r = socket.connect(remote_endpoint).await;
100 if let Err(e) = r { 120 if let Err(e) = r {
101 info!("connect error: {:?}", e); 121 info!("connect error: {:?}", e);
122 Timer::after(Duration::from_secs(1)).await;
102 continue; 123 continue;
103 } 124 }
104 info!("connected!"); 125 info!("connected!");
@@ -106,7 +127,7 @@ async fn main(spawner: Spawner) -> ! {
106 let r = socket.write_all(b"Hello\n").await; 127 let r = socket.write_all(b"Hello\n").await;
107 if let Err(e) = r { 128 if let Err(e) = r {
108 info!("write error: {:?}", e); 129 info!("write error: {:?}", e);
109 continue; 130 break;
110 } 131 }
111 Timer::after(Duration::from_secs(1)).await; 132 Timer::after(Duration::from_secs(1)).await;
112 } 133 }
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 6664410c8..3abd31c73 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -10,7 +10,6 @@ use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
@@ -34,9 +33,27 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
34#[embassy_executor::main] 33#[embassy_executor::main]
35async fn main(spawner: Spawner) -> ! { 34async fn main(spawner: Spawner) -> ! {
36 let mut config = Config::default(); 35 let mut config = Config::default();
37 config.rcc.sys_ck = Some(mhz(400)); 36 {
38 config.rcc.hclk = Some(mhz(200)); 37 use embassy_stm32::rcc::*;
39 config.rcc.pll1.q_ck = Some(mhz(100)); 38 config.rcc.hsi = Some(Hsi::Mhz64);
39 config.rcc.csi = true;
40 config.rcc.hsi48 = true; // needed for RNG
41 config.rcc.pll_src = PllSource::Hsi;
42 config.rcc.pll1 = Some(Pll {
43 prediv: 4,
44 mul: 50,
45 divp: Some(2),
46 divq: None,
47 divr: None,
48 });
49 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
50 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
51 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
55 config.rcc.voltage_scale = VoltageScale::Scale1;
56 }
40 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
41 info!("Hello World!"); 58 info!("Hello World!");
42 59
@@ -82,12 +99,12 @@ async fn main(spawner: Spawner) -> ! {
82 )); 99 ));
83 100
84 // Launch network task 101 // Launch network task
85 unwrap!(spawner.spawn(net_task(&stack))); 102 unwrap!(spawner.spawn(net_task(stack)));
86 103
87 info!("Network task initialized"); 104 // Ensure DHCP configuration is up before trying connect
105 stack.wait_config_up().await;
88 106
89 // To ensure DHCP configuration before trying connect 107 info!("Network task initialized");
90 Timer::after(Duration::from_secs(20)).await;
91 108
92 static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 109 static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new();
93 let client = TcpClient::new(&stack, &STATE); 110 let client = TcpClient::new(&stack, &STATE);
@@ -108,7 +125,7 @@ async fn main(spawner: Spawner) -> ! {
108 let r = connection.write_all(b"Hello\n").await; 125 let r = connection.write_all(b"Hello\n").await;
109 if let Err(e) = r { 126 if let Err(e) = r {
110 info!("write error: {:?}", e); 127 info!("write error: {:?}", e);
111 continue; 128 break;
112 } 129 }
113 Timer::after(Duration::from_secs(1)).await; 130 Timer::after(Duration::from_secs(1)).await;
114 } 131 }
diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs
index 85c690fe6..de0b351df 100644
--- a/examples/stm32h7/src/bin/fmc.rs
+++ b/examples/stm32h7/src/bin/fmc.rs
@@ -5,7 +5,6 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::fmc::Fmc; 7use embassy_stm32::fmc::Fmc;
8use embassy_stm32::time::mhz;
9use embassy_stm32::Config; 8use embassy_stm32::Config;
10use embassy_time::{Delay, Duration, Timer}; 9use embassy_time::{Delay, Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -13,9 +12,26 @@ use {defmt_rtt as _, panic_probe as _};
13#[embassy_executor::main] 12#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 14 let mut config = Config::default();
16 config.rcc.sys_ck = Some(mhz(400)); 15 {
17 config.rcc.hclk = Some(mhz(200)); 16 use embassy_stm32::rcc::*;
18 config.rcc.pll1.q_ck = Some(mhz(100)); 17 config.rcc.hsi = Some(Hsi::Mhz64);
18 config.rcc.csi = true;
19 config.rcc.pll_src = PllSource::Hsi;
20 config.rcc.pll1 = Some(Pll {
21 prediv: 4,
22 mul: 50,
23 divp: Some(2),
24 divq: Some(8), // 100mhz
25 divr: None,
26 });
27 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
28 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
29 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
30 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
31 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
32 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
33 config.rcc.voltage_scale = VoltageScale::Scale1;
34 }
19 let p = embassy_stm32::init(config); 35 let p = embassy_stm32::init(config);
20 36
21 info!("Hello World!"); 37 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 45b0872b5..a1e955c39 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -6,7 +6,7 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::low_level::AFType; 7use embassy_stm32::gpio::low_level::AFType;
8use embassy_stm32::gpio::Speed; 8use embassy_stm32::gpio::Speed;
9use embassy_stm32::time::{khz, mhz, Hertz}; 9use embassy_stm32::time::{khz, Hertz};
10use embassy_stm32::timer::*; 10use embassy_stm32::timer::*;
11use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; 11use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
@@ -15,13 +15,27 @@ use {defmt_rtt as _, panic_probe as _};
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 18 {
19 config.rcc.hclk = Some(mhz(400)); 19 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.hsi = Some(Hsi::Mhz64);
21 config.rcc.pclk1 = Some(mhz(100)); 21 config.rcc.csi = true;
22 config.rcc.pclk2 = Some(mhz(100)); 22 config.rcc.hsi48 = true; // needed for RNG
23 config.rcc.pclk3 = Some(mhz(100)); 23 config.rcc.pll_src = PllSource::Hsi;
24 config.rcc.pclk4 = Some(mhz(100)); 24 config.rcc.pll1 = Some(Pll {
25 prediv: 4,
26 mul: 50,
27 divp: Some(2),
28 divq: Some(8), // 100 Mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 }
25 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
26 40
27 info!("Hello World!"); 41 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs
index 036455d5e..9d6d805ae 100644
--- a/examples/stm32h7/src/bin/mco.rs
+++ b/examples/stm32h7/src/bin/mco.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 8use embassy_stm32::rcc::{Mco, Mco1Source};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 16
17 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 17 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
18 18
19 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(8)); 19 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8);
20 20
21 loop { 21 loop {
22 info!("high"); 22 info!("high");
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index aa5ec1bcf..5c8e57aa2 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::OutputType; 7use embassy_stm32::gpio::OutputType;
8use embassy_stm32::time::{khz, mhz}; 8use embassy_stm32::time::khz;
9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
10use embassy_stm32::timer::Channel; 10use embassy_stm32::timer::Channel;
11use embassy_stm32::Config; 11use embassy_stm32::Config;
@@ -15,13 +15,26 @@ use {defmt_rtt as _, panic_probe as _};
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 18 {
19 config.rcc.hclk = Some(mhz(400)); 19 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.hsi = Some(Hsi::Mhz64);
21 config.rcc.pclk1 = Some(mhz(100)); 21 config.rcc.csi = true;
22 config.rcc.pclk2 = Some(mhz(100)); 22 config.rcc.pll_src = PllSource::Hsi;
23 config.rcc.pclk3 = Some(mhz(100)); 23 config.rcc.pll1 = Some(Pll {
24 config.rcc.pclk4 = Some(mhz(100)); 24 prediv: 4,
25 mul: 50,
26 divp: Some(2),
27 divq: None,
28 divr: None,
29 });
30 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
31 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
32 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
33 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.voltage_scale = VoltageScale::Scale1;
37 }
25 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
26 info!("Hello World!"); 39 info!("Hello World!");
27 40
diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs
index 7c8c50eca..af1d6ebb8 100644
--- a/examples/stm32h7/src/bin/rng.rs
+++ b/examples/stm32h7/src/bin/rng.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs { 11bind_interrupts!(struct Irqs {
@@ -14,7 +14,9 @@ bind_interrupts!(struct Irqs {
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let p = embassy_stm32::init(Default::default()); 17 let mut config = Config::default();
18 config.rcc.hsi48 = true; // needed for RNG.
19 let p = embassy_stm32::init(config);
18 info!("Hello World!"); 20 info!("Hello World!");
19 21
20 let mut rng = Rng::new(p.RNG, Irqs); 22 let mut rng = Rng::new(p.RNG, Irqs);
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index ce91b6b1c..752aefdf7 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -16,7 +16,26 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) -> ! { 17async fn main(_spawner: Spawner) -> ! {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 config.rcc.sys_ck = Some(mhz(200)); 19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.hsi = Some(Hsi::Mhz64);
22 config.rcc.csi = true;
23 config.rcc.pll_src = PllSource::Hsi;
24 config.rcc.pll1 = Some(Pll {
25 prediv: 4,
26 mul: 50,
27 divp: Some(2),
28 divq: Some(4), // default clock chosen by SDMMCSEL. 200 Mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 }
20 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
21 info!("Hello World!"); 40 info!("Hello World!");
22 41
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index 28bba2b8d..9fe46f031 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -38,9 +38,26 @@ fn main() -> ! {
38 info!("Hello World!"); 38 info!("Hello World!");
39 39
40 let mut config = Config::default(); 40 let mut config = Config::default();
41 config.rcc.sys_ck = Some(mhz(400)); 41 {
42 config.rcc.hclk = Some(mhz(200)); 42 use embassy_stm32::rcc::*;
43 config.rcc.pll1.q_ck = Some(mhz(100)); 43 config.rcc.hsi = Some(Hsi::Mhz64);
44 config.rcc.csi = true;
45 config.rcc.pll_src = PllSource::Hsi;
46 config.rcc.pll1 = Some(Pll {
47 prediv: 4,
48 mul: 50,
49 divp: Some(2),
50 divq: Some(4), // used by SPI3. 100Mhz.
51 divr: None,
52 });
53 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
54 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
55 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
56 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
57 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
58 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
59 config.rcc.voltage_scale = VoltageScale::Scale1;
60 }
44 let p = embassy_stm32::init(config); 61 let p = embassy_stm32::init(config);
45 62
46 let mut spi_config = spi::Config::default(); 63 let mut spi_config = spi::Config::default();
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index f6e30cfa5..88d65d5be 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -34,9 +34,26 @@ fn main() -> ! {
34 info!("Hello World!"); 34 info!("Hello World!");
35 35
36 let mut config = Config::default(); 36 let mut config = Config::default();
37 config.rcc.sys_ck = Some(mhz(400)); 37 {
38 config.rcc.hclk = Some(mhz(200)); 38 use embassy_stm32::rcc::*;
39 config.rcc.pll1.q_ck = Some(mhz(100)); 39 config.rcc.hsi = Some(Hsi::Mhz64);
40 config.rcc.csi = true;
41 config.rcc.pll_src = PllSource::Hsi;
42 config.rcc.pll1 = Some(Pll {
43 prediv: 4,
44 mul: 50,
45 divp: Some(2),
46 divq: Some(4), // used by SPI3. 100Mhz.
47 divr: None,
48 });
49 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
50 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
51 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
55 config.rcc.voltage_scale = VoltageScale::Scale1;
56 }
40 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
41 58
42 let mut spi_config = spi::Config::default(); 59 let mut spi_config = spi::Config::default();
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index 0abb94abb..db04d4e55 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -20,7 +20,7 @@ async fn main_task() {
20 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
21 21
22 let config = Config::default(); 22 let config = Config::default();
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); 23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap();
24 24
25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
26 info!("wrote Hello, starting echo"); 26 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index f1fe7fce6..249050fd1 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -23,7 +23,7 @@ async fn main_task() {
23 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
24 24
25 let config = Config::default(); 25 let config = Config::default();
26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config); 26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap();
27 27
28 for n in 0u32.. { 28 for n in 0u32.. {
29 let mut s: String<128> = String::new(); 29 let mut s: String<128> = String::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index aa0753450..61c9f1954 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
36 info!("Hello World!"); 36 info!("Hello World!");
37 37
38 let config = Config::default(); 38 let config = Config::default();
39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config); 39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap();
40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); 40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
41 41
42 let (mut tx, rx) = usart.split(); 42 let (mut tx, rx) = usart.split();
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index 97291f60c..14de43568 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz;
8use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,9 +21,27 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.sys_ck = Some(mhz(400)); 24 {
26 config.rcc.hclk = Some(mhz(200)); 25 use embassy_stm32::rcc::*;
27 config.rcc.pll1.q_ck = Some(mhz(100)); 26 config.rcc.hsi = Some(Hsi::Mhz64);
27 config.rcc.csi = true;
28 config.rcc.hsi48 = true; // needed for USB
29 config.rcc.pll_src = PllSource::Hsi;
30 config.rcc.pll1 = Some(Pll {
31 prediv: 4,
32 mul: 50,
33 divp: Some(2),
34 divq: None,
35 divr: None,
36 });
37 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
38 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
39 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.voltage_scale = VoltageScale::Scale1;
44 }
28 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
29 46
30 // Create the driver, from the HAL. 47 // Create the driver, from the HAL.
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index d4e0da0bb..502ebfc8d 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -12,13 +12,13 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab
12[dependencies] 12[dependencies]
13# Change stm32l072cz to your chip name, if necessary. 13# Change stm32l072cz to your chip name, if necessary.
14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } 18embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
19lora-phy = { version = "1", optional = true } 19lora-phy = { version = "2", optional = true }
20lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } 20lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
21lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } 21lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"], optional = true }
22 22
23defmt = "0.3" 23defmt = "0.3"
24defmt-rtt = "0.4" 24defmt-rtt = "0.4"
@@ -37,6 +37,3 @@ static_cell = "1.1"
37 37
38[profile.release] 38[profile.release]
39debug = 2 39debug = 2
40
41[patch.crates-io]
42lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file
diff --git a/examples/stm32l0/src/bin/lora_cad.rs b/examples/stm32l0/src/bin/lora_cad.rs
index 7729b4163..900848fd8 100644
--- a/examples/stm32l0/src/bin/lora_cad.rs
+++ b/examples/stm32l0/src/bin/lora_cad.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 41
42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); 42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { 45 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
diff --git a/examples/stm32l0/src/bin/lora_lorawan.rs b/examples/stm32l0/src/bin/lora_lorawan.rs
index 10608aebf..7a93737e1 100644
--- a/examples/stm32l0/src/bin/lora_lorawan.rs
+++ b/examples/stm32l0/src/bin/lora_lorawan.rs
@@ -21,6 +21,7 @@ use lora_phy::LoRa;
21use lorawan::default_crypto::DefaultFactory as Crypto; 21use lorawan::default_crypto::DefaultFactory as Crypto;
22use lorawan_device::async_device::lora_radio::LoRaRadio; 22use lorawan_device::async_device::lora_radio::LoRaRadio;
23use lorawan_device::async_device::{region, Device, JoinMode}; 23use lorawan_device::async_device::{region, Device, JoinMode};
24use lorawan_device::{AppEui, AppKey, DevEui};
24use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
25 26
26bind_interrupts!(struct Irqs { 27bind_interrupts!(struct Irqs {
@@ -50,10 +51,8 @@ async fn main(_spawner: Spawner) {
50 51
51 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); 52 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
52 53
53 let mut delay = Delay;
54
55 let lora = { 54 let lora = {
56 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), true, &mut delay).await { 55 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), true, Delay).await {
57 Ok(l) => l, 56 Ok(l) => l,
58 Err(err) => { 57 Err(err) => {
59 info!("Radio error = {}", err); 58 info!("Radio error = {}", err);
@@ -71,9 +70,9 @@ async fn main(_spawner: Spawner) {
71 // TODO: Adjust the EUI and Keys according to your network credentials 70 // TODO: Adjust the EUI and Keys according to your network credentials
72 match device 71 match device
73 .join(&JoinMode::OTAA { 72 .join(&JoinMode::OTAA {
74 deveui: [0, 0, 0, 0, 0, 0, 0, 0], 73 deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
75 appeui: [0, 0, 0, 0, 0, 0, 0, 0], 74 appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
76 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 75 appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
77 }) 76 })
78 .await 77 .await
79 { 78 {
diff --git a/examples/stm32l0/src/bin/lora_p2p_receive.rs b/examples/stm32l0/src/bin/lora_p2p_receive.rs
index 0f9f60952..edd14bb81 100644
--- a/examples/stm32l0/src/bin/lora_p2p_receive.rs
+++ b/examples/stm32l0/src/bin/lora_p2p_receive.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 41
42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); 42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { 45 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
@@ -88,7 +86,7 @@ async fn main(_spawner: Spawner) {
88 }; 86 };
89 87
90 match lora 88 match lora
91 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) 89 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false)
92 .await 90 .await
93 { 91 {
94 Ok(()) => {} 92 Ok(()) => {}
diff --git a/examples/stm32l0/src/bin/lora_p2p_send.rs b/examples/stm32l0/src/bin/lora_p2p_send.rs
index c85c3c2b6..23cc1c6f7 100644
--- a/examples/stm32l0/src/bin/lora_p2p_send.rs
+++ b/examples/stm32l0/src/bin/lora_p2p_send.rs
@@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) {
41 41
42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); 42 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
43 43
44 let mut delay = Delay;
45
46 let mut lora = { 44 let mut lora = {
47 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { 45 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await {
48 Ok(l) => l, 46 Ok(l) => l,
49 Err(err) => { 47 Err(err) => {
50 info!("Radio error = {}", err); 48 info!("Radio error = {}", err);
@@ -97,7 +95,7 @@ async fn main(_spawner: Spawner) {
97 } 95 }
98 }; 96 };
99 97
100 match lora.sleep(&mut delay).await { 98 match lora.sleep(false).await {
101 Ok(()) => info!("Sleep successful"), 99 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err), 100 Err(err) => info!("Sleep unsuccessful = {}", err),
103 } 101 }
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs
index eae8f3452..62c9b5595 100644
--- a/examples/stm32l0/src/bin/usart_dma.rs
+++ b/examples/stm32l0/src/bin/usart_dma.rs
@@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
18 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()); 18 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()).unwrap();
19 19
20 usart.write(b"Hello Embassy World!\r\n").await.unwrap(); 20 usart.write(b"Hello Embassy World!\r\n").await.unwrap();
21 info!("wrote Hello, starting echo"); 21 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs
index f5dabcc42..5107a1a0a 100644
--- a/examples/stm32l0/src/bin/usart_irq.rs
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -18,13 +18,11 @@ async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hi!"); 19 info!("Hi!");
20 20
21 static mut TX_BUFFER: [u8; 8] = [0; 8];
22 static mut RX_BUFFER: [u8; 256] = [0; 256];
23
24 let mut config = Config::default(); 21 let mut config = Config::default();
25 config.baudrate = 9600; 22 config.baudrate = 9600;
26 23 let mut tx_buf = [0u8; 256];
27 let mut usart = unsafe { BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) }; 24 let mut rx_buf = [0u8; 256];
25 let mut usart = BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, config).unwrap();
28 26
29 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); 27 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
30 info!("wrote Hello, starting echo"); 28 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 192fd3e39..a75275a0b 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.3", 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/config.toml b/examples/stm32l4/.cargo/config.toml
index 36e74e5a5..db3a7ceff 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,7 @@
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-rs run --chip STM32L4S5VI" 5runner = "probe-run --chip STM32L4S5QI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index f552a6109..59e89c537 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -1,17 +1,22 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l4-examples" 3name = "embassy-stm32l4-examples"
4version = "0.1.0" 4version = "0.1.1"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embedded-io-async = { version = "0.5.0", features = ["defmt-03"] }
19embedded-io = { version = "0.5.0", features = ["defmt-03"] }
15 20
16defmt = "0.3" 21defmt = "0.3"
17defmt-rtt = "0.4" 22defmt-rtt = "0.4"
@@ -21,10 +26,13 @@ cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 26embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } 27embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
23embedded-hal-async = { version = "=1.0.0-rc.1" } 28embedded-hal-async = { version = "=1.0.0-rc.1" }
29embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
24panic-probe = { version = "0.3", features = ["print-defmt"] } 30panic-probe = { version = "0.3", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26heapless = { version = "0.7.5", default-features = false } 32heapless = { version = "0.7.5", default-features = false }
27chrono = { version = "^0.4", default-features = false } 33chrono = { version = "^0.4", default-features = false }
34rand = { version = "0.8.5", default-features = false }
35static_cell = {version = "1.1", features = ["nightly"]}
28 36
29micromath = "2.0.0" 37micromath = "2.0.0"
30 38
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index 294ea456c..eb1eed012 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -23,7 +23,8 @@ async fn main(_spawner: Spawner) {
23 PLLMul::Mul20, 23 PLLMul::Mul20,
24 None, 24 None,
25 ); 25 );
26 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32; 26 config.rcc.lse = Some(Hertz(32_768));
27 config.rcc.rtc_mux = rcc::RtcClockSource::LSE;
27 embassy_stm32::init(config) 28 embassy_stm32::init(config)
28 }; 29 };
29 info!("Hello World!"); 30 info!("Hello World!");
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
new file mode 100644
index 000000000..287521582
--- /dev/null
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -0,0 +1,450 @@
1#![deny(clippy::pedantic)]
2#![allow(clippy::doc_markdown)]
3#![no_main]
4#![no_std]
5// Needed unitl https://github.com/rust-lang/rust/issues/63063 is stablised.
6#![feature(type_alias_impl_trait)]
7#![feature(associated_type_bounds)]
8#![allow(clippy::missing_errors_doc)]
9
10// This example works on a ANALOG DEVICE EVAL-ADIN110EBZ board.
11// Settings switch S201 "HW CFG":
12// - Without SPI CRC: OFF-ON-OFF-OFF-OFF
13// - With SPI CRC: ON -ON-OFF-OFF-OFF
14// Settings switch S303 "uC CFG":
15// - CFG0: On = static ip, Off = Dhcp
16// - CFG1: Ethernet `FCS` on TX path: On, Off
17// The webserver shows the actual temperature of the onboard i2c temp sensor.
18
19use core::marker::PhantomData;
20use core::sync::atomic::{AtomicI32, Ordering};
21
22use defmt::{error, info, println, unwrap, Format};
23use defmt_rtt as _; // global logger
24use embassy_executor::Spawner;
25use embassy_futures::select::{select, Either};
26use embassy_futures::yield_now;
27use embassy_net::tcp::TcpSocket;
28use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
29use embassy_time::{Delay, Duration, Ticker, Timer};
30use embedded_hal_async::i2c::I2c as I2cBus;
31use embedded_io::Write as bWrite;
32use embedded_io_async::Write;
33use hal::gpio::{Input, Level, Output, Speed};
34use hal::i2c::{self, I2c};
35use hal::rcc::{self};
36use hal::rng::{self, Rng};
37use hal::{bind_interrupts, exti, pac, peripherals};
38use heapless::Vec;
39use rand::RngCore;
40use static_cell::make_static;
41use {embassy_stm32 as hal, panic_probe as _};
42
43bind_interrupts!(struct Irqs {
44 I2C3_EV => i2c::InterruptHandler<peripherals::I2C3>;
45 RNG => rng::InterruptHandler<peripherals::RNG>;
46});
47
48use embassy_net_adin1110::{self, Device, Runner, ADIN1110};
49use embedded_hal_bus::spi::ExclusiveDevice;
50use hal::gpio::Pull;
51use hal::i2c::Config as I2C_Config;
52use hal::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv};
53use hal::spi::{Config as SPI_Config, Spi};
54use hal::time::Hertz;
55
56// Basic settings
57// MAC-address used by the adin1110
58const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
59// Static IP settings
60const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
61// Listen port for the webserver
62const HTTP_LISTEN_PORT: u16 = 80;
63
64pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>;
65pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static, peripherals::PB12>, Delay>;
66pub type SpeInt = exti::ExtiInput<'static, peripherals::PB11>;
67pub type SpeRst = Output<'static, peripherals::PC7>;
68pub type Adin1110T = ADIN1110<SpeSpiCs>;
69pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>;
70
71static TEMP: AtomicI32 = AtomicI32::new(0);
72
73#[embassy_executor::main]
74async fn main(spawner: Spawner) {
75 defmt::println!("Start main()");
76
77 let mut config = embassy_stm32::Config::default();
78
79 // 80Mhz clock (Source: 8 / SrcDiv: 1 * PLLMul 20 / ClkDiv 2)
80 // 80MHz highest frequency for flash 0 wait.
81 config.rcc.mux = ClockSrc::PLL(
82 PLLSource::HSE(Hertz(8_000_000)),
83 PLLClkDiv::Div2,
84 PLLSrcDiv::Div1,
85 PLLMul::Mul20,
86 None,
87 );
88 config.rcc.hsi48 = true; // needed for rng
89 config.rcc.rtc_mux = rcc::RtcClockSource::LSI;
90
91 let dp = embassy_stm32::init(config);
92
93 // RM0432rev9, 5.1.2: Independent I/O supply rail
94 // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and
95 // therefore are not available. The isolation must be removed before using any I/O from
96 // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present
97 pac::PWR.cr2().modify(|w| w.set_iosv(true));
98
99 let reset_status = pac::RCC.bdcr().read().0;
100 defmt::println!("bdcr before: 0x{:X}", reset_status);
101
102 defmt::println!("Setup IO pins");
103
104 // Setup LEDs
105 let _led_uc1_green = Output::new(dp.PC13, Level::Low, Speed::Low);
106 let mut led_uc2_red = Output::new(dp.PE2, Level::High, Speed::Low);
107 let led_uc3_yellow = Output::new(dp.PE6, Level::High, Speed::Low);
108 let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low);
109
110 // Read the uc_cfg switches
111 let uc_cfg0 = Input::new(dp.PB2, Pull::None);
112 let uc_cfg1 = Input::new(dp.PF11, Pull::None);
113 let _uc_cfg2 = Input::new(dp.PG6, Pull::None);
114 let _uc_cfg3 = Input::new(dp.PG11, Pull::None);
115
116 // Setup I2C pins
117 let temp_sens_i2c = I2c::new(
118 dp.I2C3,
119 dp.PG7,
120 dp.PG8,
121 Irqs,
122 dp.DMA1_CH6,
123 dp.DMA1_CH7,
124 Hertz(100_000),
125 I2C_Config::default(),
126 );
127
128 // Setup IO and SPI for the SPE chip
129 let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low);
130 let spe_cfg0 = Input::new(dp.PC8, Pull::None);
131 let spe_cfg1 = Input::new(dp.PC9, Pull::None);
132 let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low);
133
134 let spe_int = Input::new(dp.PB11, Pull::None);
135 let spe_int = exti::ExtiInput::new(spe_int, dp.EXTI11);
136
137 let spe_spi_cs_n = Output::new(dp.PB12, Level::High, Speed::High);
138 let spe_spi_sclk = dp.PB13;
139 let spe_spi_miso = dp.PB14;
140 let spe_spi_mosi = dp.PB15;
141
142 // Don't turn the clock to high, clock must fit within the system clock as we get a runtime panic.
143 let mut spi_config = SPI_Config::default();
144 spi_config.frequency = Hertz(25_000_000);
145
146 let spe_spi: SpeSpi = Spi::new(
147 dp.SPI2,
148 spe_spi_sclk,
149 spe_spi_mosi,
150 spe_spi_miso,
151 dp.DMA1_CH1,
152 dp.DMA1_CH2,
153 spi_config,
154 );
155 let spe_spi = SpeSpiCs::new(spe_spi, spe_spi_cs_n, Delay);
156
157 let cfg0_without_crc = spe_cfg0.is_high();
158 let cfg1_spi_mode = spe_cfg1.is_high();
159 let uc_cfg1_fcs_en = uc_cfg1.is_low();
160
161 defmt::println!(
162 "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{} FCS-{}",
163 cfg1_spi_mode,
164 cfg0_without_crc,
165 uc_cfg1_fcs_en
166 );
167
168 // Check the SPI mode selected with the "HW CFG" dip-switch
169 if !cfg1_spi_mode {
170 error!("Driver doesn´t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\"");
171 loop {
172 led_uc2_red.toggle();
173 Timer::after(Duration::from_hz(10)).await;
174 }
175 };
176
177 let state = make_static!(embassy_net_adin1110::State::<8, 8>::new());
178
179 let (device, runner) = embassy_net_adin1110::new(
180 MAC,
181 state,
182 spe_spi,
183 spe_int,
184 spe_reset_n,
185 !cfg0_without_crc,
186 uc_cfg1_fcs_en,
187 )
188 .await;
189
190 // Start task blink_led
191 unwrap!(spawner.spawn(heartbeat_led(led_uc3_yellow)));
192 // Start task temperature measurement
193 unwrap!(spawner.spawn(temp_task(temp_sens_i2c, led_uc4_blue)));
194 // Start ethernet task
195 unwrap!(spawner.spawn(ethernet_task(runner)));
196
197 let mut rng = Rng::new(dp.RNG, Irqs);
198 // Generate random seed
199 let seed = rng.next_u64();
200
201 let ip_cfg = if uc_cfg0.is_low() {
202 println!("Waiting for DHCP...");
203 let dhcp4_config = embassy_net::DhcpConfig::default();
204 embassy_net::Config::dhcpv4(dhcp4_config)
205 } else {
206 embassy_net::Config::ipv4_static(StaticConfigV4 {
207 address: IP_ADDRESS,
208 gateway: None,
209 dns_servers: Vec::new(),
210 })
211 };
212
213 // Init network stack
214 let stack = &*make_static!(Stack::new(
215 device,
216 ip_cfg,
217 make_static!(StackResources::<2>::new()),
218 seed
219 ));
220
221 // Launch network task
222 unwrap!(spawner.spawn(net_task(stack)));
223
224 let cfg = wait_for_config(stack).await;
225 let local_addr = cfg.address.address();
226
227 // Then we can use it!
228 let mut rx_buffer = [0; 4096];
229 let mut tx_buffer = [0; 4096];
230 let mut mb_buf = [0; 4096];
231 loop {
232 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
233 socket.set_timeout(Some(Duration::from_secs(1)));
234
235 info!("Listening on http://{}:{}...", local_addr, HTTP_LISTEN_PORT);
236 if let Err(e) = socket.accept(HTTP_LISTEN_PORT).await {
237 defmt::error!("accept error: {:?}", e);
238 continue;
239 }
240
241 loop {
242 let _n = match socket.read(&mut mb_buf).await {
243 Ok(0) => {
244 defmt::info!("read EOF");
245 break;
246 }
247 Ok(n) => n,
248 Err(e) => {
249 defmt::error!("{:?}", e);
250 break;
251 }
252 };
253 led_uc2_red.set_low();
254
255 let status_line = "HTTP/1.1 200 OK";
256 let contents = PAGE;
257 let length = contents.len();
258
259 let _ = write!(
260 &mut mb_buf[..],
261 "{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}\r\n\0"
262 );
263 let loc = mb_buf.iter().position(|v| *v == b'#').unwrap();
264
265 let temp = TEMP.load(Ordering::Relaxed);
266 let cel = temp / 1000;
267 let mcel = temp % 1000;
268
269 info!("{}.{}", cel, mcel);
270
271 let _ = write!(&mut mb_buf[loc..loc + 7], "{cel}.{mcel}");
272
273 let n = mb_buf.iter().position(|v| *v == 0).unwrap();
274
275 if let Err(e) = socket.write_all(&mb_buf[..n]).await {
276 error!("write error: {:?}", e);
277 break;
278 }
279
280 led_uc2_red.set_high();
281 }
282 }
283}
284
285async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
286 loop {
287 if let Some(config) = stack.config_v4() {
288 return config;
289 }
290 yield_now().await;
291 }
292}
293
294#[embassy_executor::task]
295async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) {
296 let mut tmr = Ticker::every(Duration::from_hz(3));
297 loop {
298 led.toggle();
299 tmr.next().await;
300 }
301}
302
303// ADT7422
304#[embassy_executor::task]
305async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static, peripherals::PG15>) -> ! {
306 let mut tmr = Ticker::every(Duration::from_hz(1));
307 let mut temp_sens = ADT7422::new(temp_dev_i2c, 0x48).unwrap();
308
309 loop {
310 led.set_low();
311 match select(temp_sens.read_temp(), Timer::after(Duration::from_millis(500))).await {
312 Either::First(i2c_ret) => match i2c_ret {
313 Ok(value) => {
314 led.set_high();
315 let temp = i32::from(value);
316 println!("TEMP: {:04x}, {}", temp, temp * 78 / 10);
317 TEMP.store(temp * 78 / 10, Ordering::Relaxed);
318 }
319 Err(e) => defmt::println!("ADT7422: {}", e),
320 },
321 Either::Second(_) => println!("Timeout"),
322 }
323
324 tmr.next().await;
325 }
326}
327
328#[embassy_executor::task]
329async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! {
330 runner.run().await
331}
332
333#[embassy_executor::task]
334async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
335 stack.run().await
336}
337
338// same panicking *behavior* as `panic-probe` but doesn't print a panic message
339// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
340#[defmt::panic_handler]
341fn panic() -> ! {
342 cortex_m::asm::udf()
343}
344
345#[allow(non_camel_case_types)]
346#[repr(C)]
347pub enum Registers {
348 Temp_MSB = 0x00,
349 Temp_LSB,
350 Status,
351 Cfg,
352 T_HIGH_MSB,
353 T_HIGH_LSB,
354 T_LOW_MSB,
355 T_LOW_LSB,
356 T_CRIT_MSB,
357 T_CRIT_LSB,
358 T_HYST,
359 ID,
360 SW_RESET = 0x2F,
361}
362
363pub struct ADT7422<'d, BUS: I2cBus> {
364 addr: u8,
365 phantom: PhantomData<&'d ()>,
366 bus: BUS,
367}
368
369#[derive(Debug, Format)]
370pub enum Error<I2cError: Format> {
371 I2c(I2cError),
372 Address,
373}
374
375impl<'d, BUS> ADT7422<'d, BUS>
376where
377 BUS: I2cBus,
378 BUS::Error: Format,
379{
380 pub fn new(bus: BUS, addr: u8) -> Result<Self, Error<BUS::Error>> {
381 if !(0x48..=0x4A).contains(&addr) {
382 return Err(Error::Address);
383 }
384
385 Ok(Self {
386 bus,
387 phantom: PhantomData,
388 addr,
389 })
390 }
391
392 pub async fn init(&mut self) -> Result<(), Error<BUS::Error>> {
393 let mut cfg = 0b000_0000;
394 // if self.int.is_some() {
395 // // Set 1 SPS mode
396 // cfg |= 0b10 << 5;
397 // } else {
398 // One shot mode
399 cfg |= 0b01 << 5;
400 // }
401
402 self.write_cfg(cfg).await
403 }
404
405 pub async fn read(&mut self, reg: Registers) -> Result<u8, Error<BUS::Error>> {
406 let mut buffer = [0u8; 1];
407 self.bus
408 .write_read(self.addr, &[reg as u8], &mut buffer)
409 .await
410 .map_err(Error::I2c)?;
411 Ok(buffer[0])
412 }
413
414 pub async fn write_cfg(&mut self, cfg: u8) -> Result<(), Error<BUS::Error>> {
415 let buf = [Registers::Cfg as u8, cfg];
416 self.bus.write(self.addr, &buf).await.map_err(Error::I2c)
417 }
418
419 pub async fn read_temp(&mut self) -> Result<i16, Error<BUS::Error>> {
420 let mut buffer = [0u8; 2];
421
422 // if let Some(int) = &mut self.int {
423 // // Wait for interrupt
424 // int.wait_for_low().await.unwrap();
425 // } else {
426 // Start: One shot
427 let cfg = 0b01 << 5;
428 self.write_cfg(cfg).await?;
429 Timer::after(Duration::from_millis(250)).await;
430 self.bus
431 .write_read(self.addr, &[Registers::Temp_MSB as u8], &mut buffer)
432 .await
433 .map_err(Error::I2c)?;
434 Ok(i16::from_be_bytes(buffer))
435 }
436}
437
438// Web page
439const PAGE: &str = r#"<!DOCTYPE html>
440<html lang="en">
441 <head>
442 <meta charset="utf-8">
443 <meta http-equiv="refresh" content="1" >
444 <title>ADIN1110 with Rust</title>
445 </head>
446 <body>
447 <p>EVAL-ADIN1110EBZ</p>
448 <table><td>Temp Sensor ADT7422:</td><td> #00.00 &deg;C</td></table>
449 </body>
450</html>"#;
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index beb5ec558..f4da6b5ae 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -19,7 +19,7 @@ fn main() -> ! {
19 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
20 20
21 let config = Config::default(); 21 let config = Config::default();
22 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config); 22 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap();
23 23
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 25 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index b7d4cb01e..2f3b2a0f0 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let config = Config::default(); 24 let config = Config::default();
25 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config); 25 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap();
26 26
27 for n in 0u32.. { 27 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 28 let mut s: String<128> = String::new();
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index b46c25701..583e1a776 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index f928e7a6c..e361856c5 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u585ai to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
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"
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index f58a5189e..320678ddc 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0"
8# Change stm32wb55rg to your chip name in both dependencies, if necessary. 8# Change stm32wb55rg to your chip name in both dependencies, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ieee802154", "nightly"], optional=true } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
15 15
16defmt = "0.3" 16defmt = "0.3"
17defmt-rtt = "0.4" 17defmt-rtt = "0.4"
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index ea150c67e..e58da8e35 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
36 36
37 - Obtain a NUCLEO-STM32WB55 from your preferred supplier. 37 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
38 - Download and Install STM32CubeProgrammer. 38 - Download and Install STM32CubeProgrammer.
39 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from 39 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from
40 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x 40 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
41 - Open STM32CubeProgrammer 41 - Open STM32CubeProgrammer
42 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. 42 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
@@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) {
45 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file 45 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
46 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 46 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
47 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the 47 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
48 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. 48 stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address.
49 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 49 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
50 - Select "Start Wireless Stack". 50 - Select "Start Wireless Stack".
51 - Disconnect from the device. 51 - Disconnect from the device.
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index dd67249c7..80e835c1d 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
44 44
45 - Obtain a NUCLEO-STM32WB55 from your preferred supplier. 45 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
46 - Download and Install STM32CubeProgrammer. 46 - Download and Install STM32CubeProgrammer.
47 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from 47 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from
48 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x 48 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
49 - Open STM32CubeProgrammer 49 - Open STM32CubeProgrammer
50 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. 50 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
@@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) {
53 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file 53 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
54 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 54 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
55 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the 55 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
56 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. 56 stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address.
57 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 57 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
58 - Select "Start Wireless Stack". 58 - Select "Start Wireless Stack".
59 - Disconnect from the device. 59 - Disconnect from the device.
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index fc49c3c4a..2f53f5df8 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 23
24 - Obtain a NUCLEO-STM32WB55 from your preferred supplier. 24 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
25 - Download and Install STM32CubeProgrammer. 25 - Download and Install STM32CubeProgrammer.
26 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from 26 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from
27 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x 27 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
28 - Open STM32CubeProgrammer 28 - Open STM32CubeProgrammer
29 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. 29 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
@@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) {
32 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file 32 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
33 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 33 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
34 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the 34 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
35 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. 35 stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address.
36 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 36 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
37 - Select "Start Wireless Stack". 37 - Select "Start Wireless Stack".
38 - Disconnect from the device. 38 - Disconnect from the device.
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 5745ebd02..12c6aeebb 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 22
23 - Obtain a NUCLEO-STM32WB55 from your preferred supplier. 23 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
24 - Download and Install STM32CubeProgrammer. 24 - Download and Install STM32CubeProgrammer.
25 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from 25 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from
26 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x 26 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
27 - Open STM32CubeProgrammer 27 - Open STM32CubeProgrammer
28 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. 28 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
@@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
31 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file 31 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
32 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 32 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
33 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the 33 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
34 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. 34 stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address.
35 - Select that file, the memory address, "verify download", and then "Firmware Upgrade". 35 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
36 - Select "Start Wireless Stack". 36 - Select "Start Wireless Stack".
37 - Disconnect from the device. 37 - Disconnect from the device.
diff --git a/examples/stm32wba/.cargo/config.toml b/examples/stm32wba/.cargo/config.toml
new file mode 100644
index 000000000..477413397
--- /dev/null
+++ b/examples/stm32wba/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip STM32WBA52CGUxT"
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
new file mode 100644
index 000000000..26fcce26b
--- /dev/null
+++ b/examples/stm32wba/Cargo.toml
@@ -0,0 +1,26 @@
1[package]
2edition = "2021"
3name = "embassy-stm32wba-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
13
14defmt = "0.3"
15defmt-rtt = "0.4"
16
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.7.5", default-features = false }
23static_cell = { version = "1.1", features = ["nightly"]}
24
25[profile.release]
26debug = 2
diff --git a/examples/stm32wba/build.rs b/examples/stm32wba/build.rs
new file mode 100644
index 000000000..8fc6faab8
--- /dev/null
+++ b/examples/stm32wba/build.rs
@@ -0,0 +1,10 @@
1use std::error::Error;
2
3fn main() -> Result<(), Box<dyn Error>> {
4 println!("cargo:rerun-if-changed=link.x");
5 println!("cargo:rustc-link-arg-bins=--nmagic");
6 println!("cargo:rustc-link-arg-bins=-Tlink.x");
7 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
8
9 Ok(())
10}
diff --git a/examples/stm32wba/src/bin/blinky.rs b/examples/stm32wba/src/bin/blinky.rs
new file mode 100644
index 000000000..530746296
--- /dev/null
+++ b/examples/stm32wba/src/bin/blinky.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut led = Output::new(p.PB4, Level::High, Speed::Low);
17
18 loop {
19 info!("high");
20 led.set_high();
21 Timer::after(Duration::from_millis(500)).await;
22
23 info!("low");
24 led.set_low();
25 Timer::after(Duration::from_millis(500)).await;
26 }
27}
diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs
new file mode 100644
index 000000000..ef32d4c4a
--- /dev/null
+++ b/examples/stm32wba/src/bin/button_exti.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::exti::ExtiInput;
8use embassy_stm32::gpio::{Input, Pull};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let button = Input::new(p.PC13, Pull::Up);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18
19 info!("Press the USER button...");
20
21 loop {
22 button.wait_for_falling_edge().await;
23 info!("Pressed!");
24 button.wait_for_rising_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 1c771ddce..f47a9a906 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -7,14 +7,14 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Change stm32wl55jc-cm4 to your chip name, if necessary. 8# Change stm32wl55jc-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } 14embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
15lora-phy = { version = "1" } 15lora-phy = { version = "2" }
16lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } 16lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] }
17lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } 17lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"] }
18 18
19defmt = "0.3" 19defmt = "0.3"
20defmt-rtt = "0.4" 20defmt-rtt = "0.4"
@@ -30,6 +30,3 @@ chrono = { version = "^0.4", default-features = false }
30 30
31[profile.release] 31[profile.release]
32debug = 2 32debug = 2
33
34[patch.crates-io]
35lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file
diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs
index 2c9c98861..fb2495326 100644
--- a/examples/stm32wl/src/bin/lora_lorawan.rs
+++ b/examples/stm32wl/src/bin/lora_lorawan.rs
@@ -20,6 +20,7 @@ use lora_phy::LoRa;
20use lorawan::default_crypto::DefaultFactory as Crypto; 20use lorawan::default_crypto::DefaultFactory as Crypto;
21use lorawan_device::async_device::lora_radio::LoRaRadio; 21use lorawan_device::async_device::lora_radio::LoRaRadio;
22use lorawan_device::async_device::{region, Device, JoinMode}; 22use lorawan_device::async_device::{region, Device, JoinMode};
23use lorawan_device::{AppEui, AppKey, DevEui};
23use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
24 25
25const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region 26const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
@@ -33,7 +34,7 @@ bind_interrupts!(struct Irqs{
33async fn main(_spawner: Spawner) { 34async fn main(_spawner: Spawner) {
34 let mut config = embassy_stm32::Config::default(); 35 let mut config = embassy_stm32::Config::default();
35 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; 36 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
36 config.rcc.enable_lsi = true; // enable RNG 37 config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI;
37 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
38 39
39 pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); 40 pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));
@@ -46,10 +47,8 @@ async fn main(_spawner: Spawner) {
46 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); 47 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
47 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); 48 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
48 49
49 let mut delay = Delay;
50
51 let lora = { 50 let lora = {
52 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), true, &mut delay).await { 51 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), true, Delay).await {
53 Ok(l) => l, 52 Ok(l) => l,
54 Err(err) => { 53 Err(err) => {
55 info!("Radio error = {}", err); 54 info!("Radio error = {}", err);
@@ -66,9 +65,9 @@ async fn main(_spawner: Spawner) {
66 // TODO: Adjust the EUI and Keys according to your network credentials 65 // TODO: Adjust the EUI and Keys according to your network credentials
67 match device 66 match device
68 .join(&JoinMode::OTAA { 67 .join(&JoinMode::OTAA {
69 deveui: [0, 0, 0, 0, 0, 0, 0, 0], 68 deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
70 appeui: [0, 0, 0, 0, 0, 0, 0, 0], 69 appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]),
71 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 70 appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
72 }) 71 })
73 .await 72 .await
74 { 73 {
diff --git a/examples/stm32wl/src/bin/lora_p2p_receive.rs b/examples/stm32wl/src/bin/lora_p2p_receive.rs
index d3f051b1c..3d8c31ff3 100644
--- a/examples/stm32wl/src/bin/lora_p2p_receive.rs
+++ b/examples/stm32wl/src/bin/lora_p2p_receive.rs
@@ -37,10 +37,8 @@ async fn main(_spawner: Spawner) {
37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); 37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); 38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
39 39
40 let mut delay = Delay;
41
42 let mut lora = { 40 let mut lora = {
43 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await { 41 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, Delay).await {
44 Ok(l) => l, 42 Ok(l) => l,
45 Err(err) => { 43 Err(err) => {
46 info!("Radio error = {}", err); 44 info!("Radio error = {}", err);
@@ -84,7 +82,7 @@ async fn main(_spawner: Spawner) {
84 }; 82 };
85 83
86 match lora 84 match lora
87 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) 85 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false)
88 .await 86 .await
89 { 87 {
90 Ok(()) => {} 88 Ok(()) => {}
diff --git a/examples/stm32wl/src/bin/lora_p2p_send.rs b/examples/stm32wl/src/bin/lora_p2p_send.rs
index fc5205c85..fbd0b0320 100644
--- a/examples/stm32wl/src/bin/lora_p2p_send.rs
+++ b/examples/stm32wl/src/bin/lora_p2p_send.rs
@@ -37,10 +37,8 @@ async fn main(_spawner: Spawner) {
37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); 37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); 38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
39 39
40 let mut delay = Delay;
41
42 let mut lora = { 40 let mut lora = {
43 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await { 41 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, Delay).await {
44 Ok(l) => l, 42 Ok(l) => l,
45 Err(err) => { 43 Err(err) => {
46 info!("Radio error = {}", err); 44 info!("Radio error = {}", err);
@@ -93,7 +91,7 @@ async fn main(_spawner: Spawner) {
93 } 91 }
94 }; 92 };
95 93
96 match lora.sleep(&mut delay).await { 94 match lora.sleep(false).await {
97 Ok(()) => info!("Sleep successful"), 95 Ok(()) => info!("Sleep successful"),
98 Err(err) => info!("Sleep unsuccessful = {}", err), 96 Err(err) => info!("Sleep unsuccessful = {}", err),
99 } 97 }
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 592e65f40..18eeac4fa 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs{
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = embassy_stm32::Config::default(); 17 let mut config = embassy_stm32::Config::default();
18 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; 18 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
19 config.rcc.enable_lsi = true; //Needed for RNG to work 19 config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI;
20 20
21 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
22 pac::RCC.ccipr().modify(|w| { 22 pac::RCC.ccipr().modify(|w| {
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index fb1bc6e3d..11734e4b6 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -5,8 +5,9 @@
5use chrono::{NaiveDate, NaiveDateTime}; 5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::rcc::{self, ClockSrc}; 8use embassy_stm32::rcc::ClockSrc;
9use embassy_stm32::rtc::{Rtc, RtcConfig}; 9use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig};
10use embassy_stm32::time::Hertz;
10use embassy_stm32::Config; 11use embassy_stm32::Config;
11use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -16,8 +17,8 @@ async fn main(_spawner: Spawner) {
16 let p = { 17 let p = {
17 let mut config = Config::default(); 18 let mut config = Config::default();
18 config.rcc.mux = ClockSrc::HSE32; 19 config.rcc.mux = ClockSrc::HSE32;
19 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32; 20 config.rcc.lse = Some(Hertz(32_768));
20 config.rcc.enable_rtc_apb = true; 21 config.rcc.rtc_mux = RtcClockSource::LSE;
21 embassy_stm32::init(config) 22 embassy_stm32::init(config)
22 }; 23 };
23 info!("Hello World!"); 24 info!("Hello World!");
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index 07b0f9d2c..2c9b7c691 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -33,10 +33,10 @@ async fn main(_spawner: Spawner) {
33 config2.baudrate = 9600; 33 config2.baudrate = 9600;
34 34
35 //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0 35 //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0
36 let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1); 36 let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1).unwrap();
37 37
38 //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0 38 //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0
39 let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2); 39 let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2).unwrap();
40 40
41 unwrap!(usart1.write(b"Hello Embassy World!\r\n").await); 41 unwrap!(usart1.write(b"Hello Embassy World!\r\n").await);
42 unwrap!(usart2.write(b"Hello Embassy World!\r\n").await); 42 unwrap!(usart2.write(b"Hello Embassy World!\r\n").await);
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 5b206d716..12b2e2bd4 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8crate-type = ["cdylib"] 8crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } 13embassy-time = { version = "0.1.3", 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/tests/nrf/.cargo/config.toml b/tests/nrf/.cargo/config.toml
index 03995f963..9d6b0313a 100644
--- a/tests/nrf/.cargo/config.toml
+++ b/tests/nrf/.cargo/config.toml
@@ -6,4 +6,4 @@ runner = "teleprobe client run"
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
7 7
8[env] 8[env]
9DEFMT_LOG = "trace" 9DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info"
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 4e31bed59..08fe1a4b5 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8teleprobe-meta = "1" 8teleprobe-meta = "1"
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", "nightly"] } 11embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.1.3", 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-async = { version = "0.5.0" } 15embedded-io-async = { version = "0.5.0" }
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"] }
@@ -19,10 +19,11 @@ embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60",
19embedded-hal-async = { version = "1.0.0-rc.1" } 19embedded-hal-async = { version = "1.0.0-rc.1" }
20embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } 20embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] }
21static_cell = { version = "1.1", features = [ "nightly" ] } 21static_cell = { version = "1.1", features = [ "nightly" ] }
22perf-client = { path = "../perf-client" }
22 23
23defmt = "0.3" 24defmt = "0.3"
24defmt-rtt = "0.4" 25defmt-rtt = "0.4"
25 26
26cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 27cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
27cortex-m-rt = "0.7.0" 28cortex-m-rt = "0.7.0"
28panic-probe = { version = "0.3", features = ["print-defmt"] } \ No newline at end of file 29panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
index 0446d39ac..60d30a2ff 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -4,17 +4,15 @@
4teleprobe_meta::target!(b"ak-gwe-r7"); 4teleprobe_meta::target!(b"ak-gwe-r7");
5teleprobe_meta::timeout!(120); 5teleprobe_meta::timeout!(120);
6 6
7use defmt::{error, info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_net::{Stack, StackResources};
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Ipv4Address, Stack, StackResources};
12use embassy_net_enc28j60::Enc28j60; 10use embassy_net_enc28j60::Enc28j60;
13use embassy_nrf::gpio::{Level, Output, OutputDrive}; 11use embassy_nrf::gpio::{Level, Output, OutputDrive};
14use embassy_nrf::rng::Rng; 12use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim}; 13use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals}; 14use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Delay, Duration, Timer}; 15use embassy_time::Delay;
18use embedded_hal_bus::spi::ExclusiveDevice; 16use embedded_hal_bus::spi::ExclusiveDevice;
19use static_cell::make_static; 17use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
@@ -79,172 +77,16 @@ async fn main(spawner: Spawner) {
79 77
80 unwrap!(spawner.spawn(net_task(stack))); 78 unwrap!(spawner.spawn(net_task(stack)));
81 79
82 info!("Waiting for DHCP up..."); 80 perf_client::run(
83 while stack.config_v4().is_none() { 81 stack,
84 Timer::after(Duration::from_millis(100)).await; 82 perf_client::Expected {
85 } 83 down_kbps: 200,
86 info!("IP addressing up!"); 84 up_kbps: 200,
87 85 updown_kbps: 150,
88 let down = test_download(stack).await; 86 },
89 let up = test_upload(stack).await; 87 )
90 let updown = test_upload_download(stack).await; 88 .await;
91
92 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
93 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
94 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
95 89
96 info!("Test OK"); 90 info!("Test OK");
97 cortex_m::asm::bkpt(); 91 cortex_m::asm::bkpt();
98} 92}
99
100const TEST_DURATION: usize = 10;
101const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 200;
102const TEST_EXPECTED_UPLOAD_KBPS: usize = 200;
103const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150;
104const RX_BUFFER_SIZE: usize = 4096;
105const TX_BUFFER_SIZE: usize = 4096;
106const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
107const DOWNLOAD_PORT: u16 = 4321;
108const UPLOAD_PORT: u16 = 4322;
109const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
110
111async fn test_download(stack: &'static Stack<MyDriver>) -> usize {
112 info!("Testing download...");
113
114 let mut rx_buffer = [0; RX_BUFFER_SIZE];
115 let mut tx_buffer = [0; TX_BUFFER_SIZE];
116 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
117 socket.set_timeout(Some(Duration::from_secs(10)));
118
119 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
120 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
121 error!("connect error: {:?}", e);
122 return 0;
123 }
124 info!("connected, testing...");
125
126 let mut rx_buf = [0; 4096];
127 let mut total: usize = 0;
128 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
129 loop {
130 match socket.read(&mut rx_buf).await {
131 Ok(0) => {
132 error!("read EOF");
133 return 0;
134 }
135 Ok(n) => total += n,
136 Err(e) => {
137 error!("read error: {:?}", e);
138 return 0;
139 }
140 }
141 }
142 })
143 .await
144 .ok();
145
146 let kbps = (total + 512) / 1024 / TEST_DURATION;
147 info!("download: {} kB/s", kbps);
148 kbps
149}
150
151async fn test_upload(stack: &'static Stack<MyDriver>) -> usize {
152 info!("Testing upload...");
153
154 let mut rx_buffer = [0; RX_BUFFER_SIZE];
155 let mut tx_buffer = [0; TX_BUFFER_SIZE];
156 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
157 socket.set_timeout(Some(Duration::from_secs(10)));
158
159 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
160 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
161 error!("connect error: {:?}", e);
162 return 0;
163 }
164 info!("connected, testing...");
165
166 let buf = [0; 4096];
167 let mut total: usize = 0;
168 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
169 loop {
170 match socket.write(&buf).await {
171 Ok(0) => {
172 error!("write zero?!??!?!");
173 return 0;
174 }
175 Ok(n) => total += n,
176 Err(e) => {
177 error!("write error: {:?}", e);
178 return 0;
179 }
180 }
181 }
182 })
183 .await
184 .ok();
185
186 let kbps = (total + 512) / 1024 / TEST_DURATION;
187 info!("upload: {} kB/s", kbps);
188 kbps
189}
190
191async fn test_upload_download(stack: &'static Stack<MyDriver>) -> usize {
192 info!("Testing upload+download...");
193
194 let mut rx_buffer = [0; RX_BUFFER_SIZE];
195 let mut tx_buffer = [0; TX_BUFFER_SIZE];
196 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
197 socket.set_timeout(Some(Duration::from_secs(10)));
198
199 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
200 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
201 error!("connect error: {:?}", e);
202 return 0;
203 }
204 info!("connected, testing...");
205
206 let (mut reader, mut writer) = socket.split();
207
208 let tx_buf = [0; 4096];
209 let mut rx_buf = [0; 4096];
210 let mut total: usize = 0;
211 let tx_fut = async {
212 loop {
213 match writer.write(&tx_buf).await {
214 Ok(0) => {
215 error!("write zero?!??!?!");
216 return 0;
217 }
218 Ok(_) => {}
219 Err(e) => {
220 error!("write error: {:?}", e);
221 return 0;
222 }
223 }
224 }
225 };
226
227 let rx_fut = async {
228 loop {
229 match reader.read(&mut rx_buf).await {
230 Ok(0) => {
231 error!("read EOF");
232 return 0;
233 }
234 Ok(n) => total += n,
235 Err(e) => {
236 error!("read error: {:?}", e);
237 return 0;
238 }
239 }
240 }
241 };
242
243 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
244 .await
245 .ok();
246
247 let kbps = (total + 512) / 1024 / TEST_DURATION;
248 info!("upload+download: {} kB/s", kbps);
249 kbps
250}
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index 97ebafec8..9eee39ccf 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -4,16 +4,14 @@
4teleprobe_meta::target!(b"nrf52840-dk"); 4teleprobe_meta::target!(b"nrf52840-dk");
5teleprobe_meta::timeout!(120); 5teleprobe_meta::timeout!(120);
6 6
7use defmt::{error, info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_net::{Config, Stack, StackResources};
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Config, Ipv4Address, Stack, StackResources};
12use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; 10use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
13use embassy_nrf::rng::Rng; 11use embassy_nrf::rng::Rng;
14use embassy_nrf::spim::{self, Spim}; 12use embassy_nrf::spim::{self, Spim};
15use embassy_nrf::{bind_interrupts, peripherals}; 13use embassy_nrf::{bind_interrupts, peripherals};
16use embassy_time::{with_timeout, Delay, Duration, Timer}; 14use embassy_time::Delay;
17use embedded_hal_bus::spi::ExclusiveDevice; 15use embedded_hal_bus::spi::ExclusiveDevice;
18use static_cell::make_static; 16use static_cell::make_static;
19use {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 _};
@@ -23,6 +21,10 @@ bind_interrupts!(struct Irqs {
23 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; 21 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
24}); 22});
25 23
24// Test-only wifi network, no internet access!
25const WIFI_NETWORK: &str = "EmbassyTest";
26const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
27
26#[embassy_executor::task] 28#[embassy_executor::task]
27async fn wifi_task( 29async fn wifi_task(
28 runner: hosted::Runner< 30 runner: hosted::Runner<
@@ -92,176 +94,16 @@ async fn main(spawner: Spawner) {
92 94
93 unwrap!(spawner.spawn(net_task(stack))); 95 unwrap!(spawner.spawn(net_task(stack)));
94 96
95 info!("Waiting for DHCP up..."); 97 perf_client::run(
96 while stack.config_v4().is_none() { 98 stack,
97 Timer::after(Duration::from_millis(100)).await; 99 perf_client::Expected {
98 } 100 down_kbps: 50,
99 info!("IP addressing up!"); 101 up_kbps: 50,
100 102 updown_kbps: 50,
101 let down = test_download(stack).await; 103 },
102 let up = test_upload(stack).await; 104 )
103 let updown = test_upload_download(stack).await; 105 .await;
104
105 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
106 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
107 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
108 106
109 info!("Test OK"); 107 info!("Test OK");
110 cortex_m::asm::bkpt(); 108 cortex_m::asm::bkpt();
111} 109}
112
113// Test-only wifi network, no internet access!
114const WIFI_NETWORK: &str = "EmbassyTest";
115const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
116
117const TEST_DURATION: usize = 10;
118const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 50;
119const TEST_EXPECTED_UPLOAD_KBPS: usize = 50;
120const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 50;
121const RX_BUFFER_SIZE: usize = 4096;
122const TX_BUFFER_SIZE: usize = 4096;
123const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
124const DOWNLOAD_PORT: u16 = 4321;
125const UPLOAD_PORT: u16 = 4322;
126const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
127
128async fn test_download(stack: &'static Stack<MyDriver>) -> usize {
129 info!("Testing download...");
130
131 let mut rx_buffer = [0; RX_BUFFER_SIZE];
132 let mut tx_buffer = [0; TX_BUFFER_SIZE];
133 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
134 socket.set_timeout(Some(Duration::from_secs(10)));
135
136 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
137 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
138 error!("connect error: {:?}", e);
139 return 0;
140 }
141 info!("connected, testing...");
142
143 let mut rx_buf = [0; 4096];
144 let mut total: usize = 0;
145 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
146 loop {
147 match socket.read(&mut rx_buf).await {
148 Ok(0) => {
149 error!("read EOF");
150 return 0;
151 }
152 Ok(n) => total += n,
153 Err(e) => {
154 error!("read error: {:?}", e);
155 return 0;
156 }
157 }
158 }
159 })
160 .await
161 .ok();
162
163 let kbps = (total + 512) / 1024 / TEST_DURATION;
164 info!("download: {} kB/s", kbps);
165 kbps
166}
167
168async fn test_upload(stack: &'static Stack<MyDriver>) -> usize {
169 info!("Testing upload...");
170
171 let mut rx_buffer = [0; RX_BUFFER_SIZE];
172 let mut tx_buffer = [0; TX_BUFFER_SIZE];
173 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
174 socket.set_timeout(Some(Duration::from_secs(10)));
175
176 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
177 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
178 error!("connect error: {:?}", e);
179 return 0;
180 }
181 info!("connected, testing...");
182
183 let buf = [0; 4096];
184 let mut total: usize = 0;
185 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
186 loop {
187 match socket.write(&buf).await {
188 Ok(0) => {
189 error!("write zero?!??!?!");
190 return 0;
191 }
192 Ok(n) => total += n,
193 Err(e) => {
194 error!("write error: {:?}", e);
195 return 0;
196 }
197 }
198 }
199 })
200 .await
201 .ok();
202
203 let kbps = (total + 512) / 1024 / TEST_DURATION;
204 info!("upload: {} kB/s", kbps);
205 kbps
206}
207
208async fn test_upload_download(stack: &'static Stack<MyDriver>) -> usize {
209 info!("Testing upload+download...");
210
211 let mut rx_buffer = [0; RX_BUFFER_SIZE];
212 let mut tx_buffer = [0; TX_BUFFER_SIZE];
213 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
214 socket.set_timeout(Some(Duration::from_secs(10)));
215
216 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
217 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
218 error!("connect error: {:?}", e);
219 return 0;
220 }
221 info!("connected, testing...");
222
223 let (mut reader, mut writer) = socket.split();
224
225 let tx_buf = [0; 4096];
226 let mut rx_buf = [0; 4096];
227 let mut total: usize = 0;
228 let tx_fut = async {
229 loop {
230 match writer.write(&tx_buf).await {
231 Ok(0) => {
232 error!("write zero?!??!?!");
233 return 0;
234 }
235 Ok(_) => {}
236 Err(e) => {
237 error!("write error: {:?}", e);
238 return 0;
239 }
240 }
241 }
242 };
243
244 let rx_fut = async {
245 loop {
246 match reader.read(&mut rx_buf).await {
247 Ok(0) => {
248 error!("read EOF");
249 return 0;
250 }
251 Ok(n) => total += n,
252 Err(e) => {
253 error!("read error: {:?}", e);
254 return 0;
255 }
256 }
257 }
258 };
259
260 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
261 .await
262 .ok();
263
264 let kbps = (total + 512) / 1024 / TEST_DURATION;
265 info!("upload+download: {} kB/s", kbps);
266 kbps
267}
diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml
new file mode 100644
index 000000000..3284664d9
--- /dev/null
+++ b/tests/perf-client/Cargo.toml
@@ -0,0 +1,12 @@
1[package]
2name = "perf-client"
3version = "0.1.0"
4edition = "2021"
5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
8[dependencies]
9embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] }
10embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] }
11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
12defmt = "0.3.0"
diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs
new file mode 100644
index 000000000..a36147dbb
--- /dev/null
+++ b/tests/perf-client/src/lib.rs
@@ -0,0 +1,179 @@
1#![no_std]
2
3use defmt::{assert, *};
4use embassy_futures::join::join;
5use embassy_net::driver::Driver;
6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack};
8use embassy_time::{with_timeout, Duration, Timer};
9
10pub struct Expected {
11 pub down_kbps: usize,
12 pub up_kbps: usize,
13 pub updown_kbps: usize,
14}
15
16pub async fn run<D: Driver>(stack: &Stack<D>, expected: Expected) {
17 info!("Waiting for DHCP up...");
18 while stack.config_v4().is_none() {
19 Timer::after(Duration::from_millis(100)).await;
20 }
21 info!("IP addressing up!");
22
23 let down = test_download(stack).await;
24 let up = test_upload(stack).await;
25 let updown = test_upload_download(stack).await;
26
27 assert!(down > expected.down_kbps);
28 assert!(up > expected.up_kbps);
29 assert!(updown > expected.updown_kbps);
30}
31
32const TEST_DURATION: usize = 10;
33const RX_BUFFER_SIZE: usize = 4096;
34const TX_BUFFER_SIZE: usize = 4096;
35const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
36const DOWNLOAD_PORT: u16 = 4321;
37const UPLOAD_PORT: u16 = 4322;
38const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
39
40async fn test_download<D: Driver>(stack: &Stack<D>) -> usize {
41 info!("Testing download...");
42
43 let mut rx_buffer = [0; RX_BUFFER_SIZE];
44 let mut tx_buffer = [0; TX_BUFFER_SIZE];
45 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
46 socket.set_timeout(Some(Duration::from_secs(10)));
47
48 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
49 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
50 error!("connect error: {:?}", e);
51 return 0;
52 }
53 info!("connected, testing...");
54
55 let mut rx_buf = [0; 4096];
56 let mut total: usize = 0;
57 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
58 loop {
59 match socket.read(&mut rx_buf).await {
60 Ok(0) => {
61 error!("read EOF");
62 return 0;
63 }
64 Ok(n) => total += n,
65 Err(e) => {
66 error!("read error: {:?}", e);
67 return 0;
68 }
69 }
70 }
71 })
72 .await
73 .ok();
74
75 let kbps = (total + 512) / 1024 / TEST_DURATION;
76 info!("download: {} kB/s", kbps);
77 kbps
78}
79
80async fn test_upload<D: Driver>(stack: &Stack<D>) -> usize {
81 info!("Testing upload...");
82
83 let mut rx_buffer = [0; RX_BUFFER_SIZE];
84 let mut tx_buffer = [0; TX_BUFFER_SIZE];
85 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
86 socket.set_timeout(Some(Duration::from_secs(10)));
87
88 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
89 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
90 error!("connect error: {:?}", e);
91 return 0;
92 }
93 info!("connected, testing...");
94
95 let buf = [0; 4096];
96 let mut total: usize = 0;
97 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
98 loop {
99 match socket.write(&buf).await {
100 Ok(0) => {
101 error!("write zero?!??!?!");
102 return 0;
103 }
104 Ok(n) => total += n,
105 Err(e) => {
106 error!("write error: {:?}", e);
107 return 0;
108 }
109 }
110 }
111 })
112 .await
113 .ok();
114
115 let kbps = (total + 512) / 1024 / TEST_DURATION;
116 info!("upload: {} kB/s", kbps);
117 kbps
118}
119
120async fn test_upload_download<D: Driver>(stack: &Stack<D>) -> usize {
121 info!("Testing upload+download...");
122
123 let mut rx_buffer = [0; RX_BUFFER_SIZE];
124 let mut tx_buffer = [0; TX_BUFFER_SIZE];
125 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
126 socket.set_timeout(Some(Duration::from_secs(10)));
127
128 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
129 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
130 error!("connect error: {:?}", e);
131 return 0;
132 }
133 info!("connected, testing...");
134
135 let (mut reader, mut writer) = socket.split();
136
137 let tx_buf = [0; 4096];
138 let mut rx_buf = [0; 4096];
139 let mut total: usize = 0;
140 let tx_fut = async {
141 loop {
142 match writer.write(&tx_buf).await {
143 Ok(0) => {
144 error!("write zero?!??!?!");
145 return 0;
146 }
147 Ok(_) => {}
148 Err(e) => {
149 error!("write error: {:?}", e);
150 return 0;
151 }
152 }
153 }
154 };
155
156 let rx_fut = async {
157 loop {
158 match reader.read(&mut rx_buf).await {
159 Ok(0) => {
160 error!("read EOF");
161 return 0;
162 }
163 Ok(n) => total += n,
164 Err(e) => {
165 error!("read error: {:?}", e);
166 return 0;
167 }
168 }
169 }
170 };
171
172 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
173 .await
174 .ok();
175
176 let kbps = (total + 512) / 1024 / TEST_DURATION;
177 info!("upload+download: {} kB/s", kbps);
178 kbps
179}
diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml
index be610b1c5..490f037b9 100644
--- a/tests/riscv32/Cargo.toml
+++ b/tests/riscv32/Cargo.toml
@@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
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.3.0", path = "../../embassy-sync" }
10embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] } 10embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] }
11embassy-time = { version = "0.1.2", path = "../../embassy-time" } 11embassy-time = { version = "0.1.3", 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/config.toml b/tests/rp/.cargo/config.toml
index bc92e788b..40b5d7000 100644
--- a/tests/rp/.cargo/config.toml
+++ b/tests/rp/.cargo/config.toml
@@ -19,4 +19,4 @@ rustflags = [
19target = "thumbv6m-none-eabi" 19target = "thumbv6m-none-eabi"
20 20
21[env] 21[env]
22DEFMT_LOG = "trace" 22DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info"
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index c494b66ee..8bb0de6c6 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -7,15 +7,16 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8teleprobe-meta = "1.1" 8teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] }
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"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 17cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
18cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 18cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
19perf-client = { path = "../perf-client" }
19 20
20defmt = "0.3.0" 21defmt = "0.3.0"
21defmt-rtt = "0.4" 22defmt-rtt = "0.4"
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 1c665f95d..de29c06dd 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -4,16 +4,13 @@
4teleprobe_meta::target!(b"rpi-pico"); 4teleprobe_meta::target!(b"rpi-pico");
5 5
6use cyw43_pio::PioSpi; 6use cyw43_pio::PioSpi;
7use defmt::{assert, panic, *}; 7use defmt::{panic, *};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_net::{Config, Stack, StackResources};
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Config, Ipv4Address, Stack, StackResources};
12use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
13use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 11use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
14use embassy_rp::pio::{InterruptHandler, Pio}; 12use embassy_rp::pio::{InterruptHandler, Pio};
15use embassy_rp::{bind_interrupts, rom_data}; 13use embassy_rp::{bind_interrupts, rom_data};
16use embassy_time::{with_timeout, Duration, Timer};
17use static_cell::make_static; 14use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
19 16
@@ -23,6 +20,10 @@ bind_interrupts!(struct Irqs {
23 20
24teleprobe_meta::timeout!(120); 21teleprobe_meta::timeout!(120);
25 22
23// Test-only wifi network, no internet access!
24const WIFI_NETWORK: &str = "EmbassyTest";
25const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
26
26#[embassy_executor::task] 27#[embassy_executor::task]
27async fn wifi_task( 28async fn wifi_task(
28 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>>,
@@ -88,176 +89,16 @@ async fn main(spawner: Spawner) {
88 } 89 }
89 } 90 }
90 91
91 info!("Waiting for DHCP up..."); 92 perf_client::run(
92 while stack.config_v4().is_none() { 93 stack,
93 Timer::after(Duration::from_millis(100)).await; 94 perf_client::Expected {
94 } 95 down_kbps: 300,
95 info!("IP addressing up!"); 96 up_kbps: 300,
96 97 updown_kbps: 300,
97 let down = test_download(stack).await; 98 },
98 let up = test_upload(stack).await; 99 )
99 let updown = test_upload_download(stack).await; 100 .await;
100
101 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
102 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
103 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
104 101
105 info!("Test OK"); 102 info!("Test OK");
106 cortex_m::asm::bkpt(); 103 cortex_m::asm::bkpt();
107} 104}
108
109// Test-only wifi network, no internet access!
110const WIFI_NETWORK: &str = "EmbassyTest";
111const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
112
113const TEST_DURATION: usize = 10;
114const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300;
115const TEST_EXPECTED_UPLOAD_KBPS: usize = 300;
116const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300;
117const RX_BUFFER_SIZE: usize = 4096;
118const TX_BUFFER_SIZE: usize = 4096;
119const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
120const DOWNLOAD_PORT: u16 = 4321;
121const UPLOAD_PORT: u16 = 4322;
122const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
123
124async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
125 info!("Testing download...");
126
127 let mut rx_buffer = [0; RX_BUFFER_SIZE];
128 let mut tx_buffer = [0; TX_BUFFER_SIZE];
129 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
130 socket.set_timeout(Some(Duration::from_secs(10)));
131
132 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
133 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
134 error!("connect error: {:?}", e);
135 return 0;
136 }
137 info!("connected, testing...");
138
139 let mut rx_buf = [0; 4096];
140 let mut total: usize = 0;
141 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
142 loop {
143 match socket.read(&mut rx_buf).await {
144 Ok(0) => {
145 error!("read EOF");
146 return 0;
147 }
148 Ok(n) => total += n,
149 Err(e) => {
150 error!("read error: {:?}", e);
151 return 0;
152 }
153 }
154 }
155 })
156 .await
157 .ok();
158
159 let kbps = (total + 512) / 1024 / TEST_DURATION;
160 info!("download: {} kB/s", kbps);
161 kbps
162}
163
164async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
165 info!("Testing upload...");
166
167 let mut rx_buffer = [0; RX_BUFFER_SIZE];
168 let mut tx_buffer = [0; TX_BUFFER_SIZE];
169 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
170 socket.set_timeout(Some(Duration::from_secs(10)));
171
172 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
173 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
174 error!("connect error: {:?}", e);
175 return 0;
176 }
177 info!("connected, testing...");
178
179 let buf = [0; 4096];
180 let mut total: usize = 0;
181 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
182 loop {
183 match socket.write(&buf).await {
184 Ok(0) => {
185 error!("write zero?!??!?!");
186 return 0;
187 }
188 Ok(n) => total += n,
189 Err(e) => {
190 error!("write error: {:?}", e);
191 return 0;
192 }
193 }
194 }
195 })
196 .await
197 .ok();
198
199 let kbps = (total + 512) / 1024 / TEST_DURATION;
200 info!("upload: {} kB/s", kbps);
201 kbps
202}
203
204async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
205 info!("Testing upload+download...");
206
207 let mut rx_buffer = [0; RX_BUFFER_SIZE];
208 let mut tx_buffer = [0; TX_BUFFER_SIZE];
209 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
210 socket.set_timeout(Some(Duration::from_secs(10)));
211
212 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
213 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
214 error!("connect error: {:?}", e);
215 return 0;
216 }
217 info!("connected, testing...");
218
219 let (mut reader, mut writer) = socket.split();
220
221 let tx_buf = [0; 4096];
222 let mut rx_buf = [0; 4096];
223 let mut total: usize = 0;
224 let tx_fut = async {
225 loop {
226 match writer.write(&tx_buf).await {
227 Ok(0) => {
228 error!("write zero?!??!?!");
229 return 0;
230 }
231 Ok(_) => {}
232 Err(e) => {
233 error!("write error: {:?}", e);
234 return 0;
235 }
236 }
237 }
238 };
239
240 let rx_fut = async {
241 loop {
242 match reader.read(&mut rx_buf).await {
243 Ok(0) => {
244 error!("read EOF");
245 return 0;
246 }
247 Ok(n) => total += n,
248 Err(e) => {
249 error!("read error: {:?}", e);
250 return 0;
251 }
252 }
253 }
254 };
255
256 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
257 .await
258 .ok();
259
260 let kbps = (total + 512) / 1024 / TEST_DURATION;
261 info!("upload+download: {} kB/s", kbps);
262 kbps
263}
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
index faa8638c0..a4d253b3c 100644
--- a/tests/rp/src/bin/ethernet_w5100s_perf.rs
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -4,18 +4,16 @@
4teleprobe_meta::target!(b"w5100s-evb-pico"); 4teleprobe_meta::target!(b"w5100s-evb-pico");
5teleprobe_meta::timeout!(120); 5teleprobe_meta::timeout!(120);
6 6
7use defmt::{assert, *}; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_net::{Stack, StackResources};
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Ipv4Address, Stack, StackResources};
12use embassy_net_wiznet::chip::W5100S; 10use embassy_net_wiznet::chip::W5100S;
13use embassy_net_wiznet::*; 11use embassy_net_wiznet::*;
14use embassy_rp::clocks::RoscRng; 12use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull}; 13use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 14use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 15use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{with_timeout, Delay, Duration, Timer}; 16use embassy_time::Delay;
19use embedded_hal_bus::spi::ExclusiveDevice; 17use embedded_hal_bus::spi::ExclusiveDevice;
20use rand::RngCore; 18use rand::RngCore;
21use static_cell::make_static; 19use static_cell::make_static;
@@ -78,172 +76,16 @@ async fn main(spawner: Spawner) {
78 // Launch network task 76 // Launch network task
79 unwrap!(spawner.spawn(net_task(&stack))); 77 unwrap!(spawner.spawn(net_task(&stack)));
80 78
81 info!("Waiting for DHCP up..."); 79 perf_client::run(
82 while stack.config_v4().is_none() { 80 stack,
83 Timer::after(Duration::from_millis(100)).await; 81 perf_client::Expected {
84 } 82 down_kbps: 500,
85 info!("IP addressing up!"); 83 up_kbps: 500,
86 84 updown_kbps: 300,
87 let down = test_download(stack).await; 85 },
88 let up = test_upload(stack).await; 86 )
89 let updown = test_upload_download(stack).await; 87 .await;
90
91 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
92 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
93 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
94 88
95 info!("Test OK"); 89 info!("Test OK");
96 cortex_m::asm::bkpt(); 90 cortex_m::asm::bkpt();
97} 91}
98
99const TEST_DURATION: usize = 10;
100const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 500;
101const TEST_EXPECTED_UPLOAD_KBPS: usize = 500;
102const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300;
103const RX_BUFFER_SIZE: usize = 4096;
104const TX_BUFFER_SIZE: usize = 4096;
105const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
106const DOWNLOAD_PORT: u16 = 4321;
107const UPLOAD_PORT: u16 = 4322;
108const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
109
110async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
111 info!("Testing download...");
112
113 let mut rx_buffer = [0; RX_BUFFER_SIZE];
114 let mut tx_buffer = [0; TX_BUFFER_SIZE];
115 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
116 socket.set_timeout(Some(Duration::from_secs(10)));
117
118 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
119 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
120 error!("connect error: {:?}", e);
121 return 0;
122 }
123 info!("connected, testing...");
124
125 let mut rx_buf = [0; 4096];
126 let mut total: usize = 0;
127 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
128 loop {
129 match socket.read(&mut rx_buf).await {
130 Ok(0) => {
131 error!("read EOF");
132 return 0;
133 }
134 Ok(n) => total += n,
135 Err(e) => {
136 error!("read error: {:?}", e);
137 return 0;
138 }
139 }
140 }
141 })
142 .await
143 .ok();
144
145 let kbps = (total + 512) / 1024 / TEST_DURATION;
146 info!("download: {} kB/s", kbps);
147 kbps
148}
149
150async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
151 info!("Testing upload...");
152
153 let mut rx_buffer = [0; RX_BUFFER_SIZE];
154 let mut tx_buffer = [0; TX_BUFFER_SIZE];
155 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
156 socket.set_timeout(Some(Duration::from_secs(10)));
157
158 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
159 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
160 error!("connect error: {:?}", e);
161 return 0;
162 }
163 info!("connected, testing...");
164
165 let buf = [0; 4096];
166 let mut total: usize = 0;
167 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
168 loop {
169 match socket.write(&buf).await {
170 Ok(0) => {
171 error!("write zero?!??!?!");
172 return 0;
173 }
174 Ok(n) => total += n,
175 Err(e) => {
176 error!("write error: {:?}", e);
177 return 0;
178 }
179 }
180 }
181 })
182 .await
183 .ok();
184
185 let kbps = (total + 512) / 1024 / TEST_DURATION;
186 info!("upload: {} kB/s", kbps);
187 kbps
188}
189
190async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
191 info!("Testing upload+download...");
192
193 let mut rx_buffer = [0; RX_BUFFER_SIZE];
194 let mut tx_buffer = [0; TX_BUFFER_SIZE];
195 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
196 socket.set_timeout(Some(Duration::from_secs(10)));
197
198 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
199 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
200 error!("connect error: {:?}", e);
201 return 0;
202 }
203 info!("connected, testing...");
204
205 let (mut reader, mut writer) = socket.split();
206
207 let tx_buf = [0; 4096];
208 let mut rx_buf = [0; 4096];
209 let mut total: usize = 0;
210 let tx_fut = async {
211 loop {
212 match writer.write(&tx_buf).await {
213 Ok(0) => {
214 error!("write zero?!??!?!");
215 return 0;
216 }
217 Ok(_) => {}
218 Err(e) => {
219 error!("write error: {:?}", e);
220 return 0;
221 }
222 }
223 }
224 };
225
226 let rx_fut = async {
227 loop {
228 match reader.read(&mut rx_buf).await {
229 Ok(0) => {
230 error!("read EOF");
231 return 0;
232 }
233 Ok(n) => total += n,
234 Err(e) => {
235 error!("read error: {:?}", e);
236 return 0;
237 }
238 }
239 }
240 };
241
242 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
243 .await
244 .ok();
245
246 let kbps = (total + 512) / 1024 / TEST_DURATION;
247 info!("upload+download: {} kB/s", kbps);
248 kbps
249}
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
new file mode 100644
index 000000000..425f2d086
--- /dev/null
+++ b/tests/rp/src/bin/i2c.rs
@@ -0,0 +1,212 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"rpi-pico");
5
6use defmt::{assert_eq, info, panic, unwrap};
7use embassy_executor::Executor;
8use embassy_executor::_export::StaticCell;
9use embassy_rp::multicore::{spawn_core1, Stack};
10use embassy_rp::peripherals::{I2C0, I2C1};
11use embassy_rp::{bind_interrupts, i2c, i2c_slave};
12use embedded_hal_1::i2c::Operation;
13use embedded_hal_async::i2c::I2c;
14use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _};
15
16static mut CORE1_STACK: Stack<1024> = Stack::new();
17static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
18static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
19
20use crate::i2c::AbortReason;
21
22bind_interrupts!(struct Irqs {
23 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
24 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
25});
26
27const DEV_ADDR: u8 = 0x42;
28
29#[embassy_executor::task]
30async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
31 info!("Device start");
32
33 let mut count = 0xD0;
34
35 loop {
36 let mut buf = [0u8; 128];
37 match dev.listen(&mut buf).await {
38 Ok(i2c_slave::Command::GeneralCall(len)) => {
39 assert_eq!(buf[..len], [0xCA, 0x11], "recieving the general call failed");
40 info!("General Call - OK");
41 }
42 Ok(i2c_slave::Command::Read) => {
43 loop {
44 match dev.respond_to_read(&[count]).await {
45 Ok(x) => match x {
46 i2c_slave::ReadStatus::Done => break,
47 i2c_slave::ReadStatus::NeedMoreBytes => count += 1,
48 i2c_slave::ReadStatus::LeftoverBytes(x) => {
49 info!("tried to write {} extra bytes", x);
50 break;
51 }
52 },
53 Err(e) => match e {
54 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
55 _ => panic!("{}", e),
56 },
57 }
58 }
59 count += 1;
60 }
61 Ok(i2c_slave::Command::Write(len)) => match len {
62 1 => {
63 assert_eq!(buf[..len], [0xAA], "recieving a single byte failed");
64 info!("Single Byte Write - OK")
65 }
66 4 => {
67 assert_eq!(buf[..len], [0xAA, 0xBB, 0xCC, 0xDD], "recieving 4 bytes failed");
68 info!("4 Byte Write - OK")
69 }
70 32 => {
71 assert_eq!(
72 buf[..len],
73 [
74 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
75 25, 26, 27, 28, 29, 30, 31
76 ],
77 "recieving 32 bytes failed"
78 );
79 info!("32 Byte Write - OK")
80 }
81 _ => panic!("Invalid write length {}", len),
82 },
83 Ok(i2c_slave::Command::WriteRead(len)) => {
84 info!("device recieved write read: {:x}", buf[..len]);
85 match buf[0] {
86 0xC2 => {
87 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
88 dev.respond_to_read(&resp_buff).await.unwrap();
89 }
90 0xC8 => {
91 let mut resp_buff = [0u8; 32];
92 for i in 0..32 {
93 resp_buff[i] = i as u8;
94 }
95 dev.respond_to_read(&resp_buff).await.unwrap();
96 }
97 x => panic!("Invalid Write Read {:x}", x),
98 }
99 }
100 Err(e) => match e {
101 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
102 _ => panic!("{}", e),
103 },
104 }
105 }
106}
107
108#[embassy_executor::task]
109async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
110 info!("Device start");
111
112 {
113 let buf = [0xCA, 0x11];
114 con.write(0u16, &buf).await.unwrap();
115 info!("Controler general call write");
116 embassy_futures::yield_now().await;
117 }
118
119 {
120 let mut buf = [0u8];
121 con.read(DEV_ADDR, &mut buf).await.unwrap();
122 assert_eq!(buf, [0xD0], "single byte read failed");
123 info!("single byte read - OK");
124 embassy_futures::yield_now().await;
125 }
126
127 {
128 let mut buf = [0u8; 4];
129 con.read(DEV_ADDR, &mut buf).await.unwrap();
130 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "single byte read failed");
131 info!("4 byte read - OK");
132 embassy_futures::yield_now().await;
133 }
134
135 {
136 let buf = [0xAA];
137 con.write(DEV_ADDR, &buf).await.unwrap();
138 info!("Controler single byte write");
139 embassy_futures::yield_now().await;
140 }
141
142 {
143 let buf = [0xAA, 0xBB, 0xCC, 0xDD];
144 con.write(DEV_ADDR, &buf).await.unwrap();
145 info!("Controler 4 byte write");
146 embassy_futures::yield_now().await;
147 }
148
149 {
150 let mut buf = [0u8; 32];
151 for i in 0..32 {
152 buf[i] = i as u8;
153 }
154 con.write(DEV_ADDR, &buf).await.unwrap();
155 info!("Controler 32 byte write");
156 embassy_futures::yield_now().await;
157 }
158
159 {
160 let mut buf = [0u8; 4];
161 let mut ops = [Operation::Write(&[0xC2]), Operation::Read(&mut buf)];
162 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
163 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "write_read failed");
164 info!("write_read - OK");
165 embassy_futures::yield_now().await;
166 }
167
168 {
169 let mut buf = [0u8; 32];
170 let mut ops = [Operation::Write(&[0xC8]), Operation::Read(&mut buf)];
171 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
172 assert_eq!(
173 buf,
174 [
175 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
176 28, 29, 30, 31
177 ],
178 "write_read of 32 bytes failed"
179 );
180 info!("large write_read - OK")
181 }
182
183 info!("Test OK");
184 cortex_m::asm::bkpt();
185}
186
187#[cortex_m_rt::entry]
188fn main() -> ! {
189 let p = embassy_rp::init(Default::default());
190 info!("Hello World!");
191
192 let d_sda = p.PIN_19;
193 let d_scl = p.PIN_18;
194 let mut config = i2c_slave::Config::default();
195 config.addr = DEV_ADDR as u16;
196 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
197
198 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
199 let executor1 = EXECUTOR1.init(Executor::new());
200 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device))));
201 });
202
203 let executor0 = EXECUTOR0.init(Executor::new());
204
205 let c_sda = p.PIN_21;
206 let c_scl = p.PIN_20;
207 let mut config = i2c::Config::default();
208 config.frequency = 5_000;
209 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
210
211 executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller))));
212}
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
index 07761b01c..2e3f055d4 100644
--- a/tests/stm32/.cargo/config.toml
+++ b/tests/stm32/.cargo/config.toml
@@ -14,7 +14,10 @@ rustflags = [
14] 14]
15 15
16[build] 16[build]
17target = "thumbv7m-none-eabi" 17target = "thumbv6m-none-eabi"
18#target = "thumbv7m-none-eabi"
19#target = "thumbv7em-none-eabi"
20#target = "thumbv8m.main-none-eabihf"
18 21
19[env] 22[env]
20DEFMT_LOG = "trace" \ No newline at end of file 23DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" \ No newline at end of file
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 754356cb5..bfe5bc823 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -7,7 +7,7 @@ autobins = false
7 7
8[features] 8[features]
9stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill 9stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
10stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" 10stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc"
11stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo 11stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # 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
@@ -15,8 +15,14 @@ stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "dac-adc-pin"] # Nu
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # 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
18stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo
19stm32l152re = ["embassy-stm32/stm32l152re", "not-gpdma"] # Nucleo
20stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "not-gpdma"] # Nucleo
21stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "not-gpdma"] # Nucleo
22stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo
18 23
19sdmmc = [] 24sdmmc = []
25stop = ["embassy-stm32/low-power"]
20chrono = ["embassy-stm32/chrono", "dep:chrono"] 26chrono = ["embassy-stm32/chrono", "dep:chrono"]
21can = [] 27can = []
22ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] 28ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
@@ -28,9 +34,9 @@ dac-adc-pin = []
28[dependencies] 34[dependencies]
29teleprobe-meta = "1" 35teleprobe-meta = "1"
30 36
31embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 37embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
32embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 38embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
33embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } 39embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
34embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 40embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
35embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 41embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
36embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } 42embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
@@ -47,6 +53,7 @@ micromath = "2.0.0"
47panic-probe = { version = "0.3.0", features = ["print-defmt"] } 53panic-probe = { version = "0.3.0", features = ["print-defmt"] }
48rand_core = { version = "0.6", default-features = false } 54rand_core = { version = "0.6", default-features = false }
49rand_chacha = { version = "0.3", default-features = false } 55rand_chacha = { version = "0.3", default-features = false }
56static_cell = {version = "1.1", features = ["nightly"] }
50 57
51chrono = { version = "^0.4", default-features = false, optional = true} 58chrono = { version = "^0.4", default-features = false, optional = true}
52 59
@@ -88,6 +95,11 @@ path = "src/bin/spi_dma.rs"
88required-features = [] 95required-features = []
89 96
90[[bin]] 97[[bin]]
98name = "stop"
99path = "src/bin/stop.rs"
100required-features = [ "stop", "chrono",]
101
102[[bin]]
91name = "timer" 103name = "timer"
92path = "src/bin/timer.rs" 104path = "src/bin/timer.rs"
93required-features = [] 105required-features = []
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index 2e71954d7..9aabf8541 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -12,7 +12,8 @@ fn main() -> Result<(), Box<dyn Error>> {
12 if cfg!(any( 12 if cfg!(any(
13 feature = "stm32f103c8", 13 feature = "stm32f103c8",
14 feature = "stm32c031c6", 14 feature = "stm32c031c6",
15 feature = "stm32wb55rg" 15 feature = "stm32wb55rg",
16 feature = "stm32l073rz",
16 )) { 17 )) {
17 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 18 println!("cargo:rustc-link-arg-bins=-Tlink.x");
18 println!("cargo:rerun-if-changed=link.x"); 19 println!("cargo:rerun-if-changed=link.x");
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index aad174431..49d9a60f7 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -16,24 +16,8 @@ async fn main(_spawner: Spawner) {
16 16
17 // Arduino pins D0 and D1 17 // Arduino pins D0 and D1
18 // They're connected together with a 1K resistor. 18 // They're connected together with a 1K resistor.
19 #[cfg(feature = "stm32f103c8")] 19 let mut a = peri!(p, UART_RX);
20 let (mut a, mut b) = (p.PA9, p.PA10); 20 let mut b = peri!(p, UART_TX);
21 #[cfg(feature = "stm32g491re")]
22 let (mut a, mut b) = (p.PC4, p.PC5);
23 #[cfg(feature = "stm32g071rb")]
24 let (mut a, mut b) = (p.PC4, p.PC5);
25 #[cfg(feature = "stm32f429zi")]
26 let (mut a, mut b) = (p.PG14, p.PG9);
27 #[cfg(feature = "stm32wb55rg")]
28 let (mut a, mut b) = (p.PA3, p.PA2);
29 #[cfg(feature = "stm32h755zi")]
30 let (mut a, mut b) = (p.PB6, p.PB7);
31 #[cfg(feature = "stm32u585ai")]
32 let (mut a, mut b) = (p.PD9, p.PD8);
33 #[cfg(feature = "stm32h563zi")]
34 let (mut a, mut b) = (p.PB6, p.PB7);
35 #[cfg(feature = "stm32c031c6")]
36 let (mut a, mut b) = (p.PB6, p.PB7);
37 21
38 // Test initial output 22 // Test initial output
39 { 23 {
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 7df415b44..22be6fac5 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -10,14 +10,17 @@ use chrono::{NaiveDate, NaiveDateTime};
10use common::*; 10use common::*;
11use defmt::assert; 11use defmt::assert;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; 13use embassy_stm32::rcc::RtcClockSource;
14use embassy_stm32::rtc::{Rtc, RtcConfig};
15use embassy_stm32::time::Hertz;
14use embassy_time::{Duration, Timer}; 16use embassy_time::{Duration, Timer};
15 17
16#[embassy_executor::main] 18#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
18 let mut config = config(); 20 let mut config = config();
19 21
20 config.rcc.rtc = Some(RtcClockSource::LSI); 22 config.rcc.lse = Some(Hertz(32_768));
23 config.rcc.rtc = Some(RtcClockSource::LSE);
21 24
22 let p = embassy_stm32::init(config); 25 let p = embassy_stm32::init(config);
23 info!("Hello World!"); 26 info!("Hello World!");
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index e51dd5bf2..b0fb75d69 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -16,24 +16,10 @@ async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(config()); 16 let p = embassy_stm32::init(config());
17 info!("Hello World!"); 17 info!("Hello World!");
18 18
19 #[cfg(feature = "stm32f103c8")] 19 let spi = peri!(p, SPI);
20 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); 20 let sck = peri!(p, SPI_SCK);
21 #[cfg(feature = "stm32f429zi")] 21 let mosi = peri!(p, SPI_MOSI);
22 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); 22 let miso = peri!(p, SPI_MISO);
23 #[cfg(feature = "stm32h755zi")]
24 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PB5, p.PA6);
25 #[cfg(feature = "stm32g491re")]
26 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
27 #[cfg(feature = "stm32g071rb")]
28 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
29 #[cfg(feature = "stm32wb55rg")]
30 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
31 #[cfg(feature = "stm32u585ai")]
32 let (spi, sck, mosi, miso) = (p.SPI1, p.PE13, p.PE15, p.PE14);
33 #[cfg(feature = "stm32h563zi")]
34 let (spi, sck, mosi, miso) = (p.SPI4, p.PE12, p.PE14, p.PE13);
35 #[cfg(feature = "stm32c031c6")]
36 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
37 23
38 let mut spi_config = spi::Config::default(); 24 let mut spi_config = spi::Config::default();
39 spi_config.frequency = Hertz(1_000_000); 25 spi_config.frequency = Hertz(1_000_000);
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index d45cbe45b..212cfae5d 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -15,24 +15,12 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(config()); 15 let p = embassy_stm32::init(config());
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 #[cfg(feature = "stm32f103c8")] 18 let spi = peri!(p, SPI);
19 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); 19 let sck = peri!(p, SPI_SCK);
20 #[cfg(feature = "stm32f429zi")] 20 let mosi = peri!(p, SPI_MOSI);
21 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); 21 let miso = peri!(p, SPI_MISO);
22 #[cfg(feature = "stm32h755zi")] 22 let tx_dma = peri!(p, SPI_TX_DMA);
23 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); 23 let rx_dma = peri!(p, SPI_RX_DMA);
24 #[cfg(feature = "stm32g491re")]
25 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
26 #[cfg(feature = "stm32g071rb")]
27 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
28 #[cfg(feature = "stm32wb55rg")]
29 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
30 #[cfg(feature = "stm32u585ai")]
31 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1);
32 #[cfg(feature = "stm32h563zi")]
33 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI4, p.PE12, p.PE14, p.PE13, p.GPDMA1_CH0, p.GPDMA1_CH1);
34 #[cfg(feature = "stm32c031c6")]
35 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
36 24
37 let mut spi_config = spi::Config::default(); 25 let mut spi_config = spi::Config::default();
38 spi_config.frequency = Hertz(1_000_000); 26 spi_config.frequency = Hertz(1_000_000);
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
new file mode 100644
index 000000000..48d59b794
--- /dev/null
+++ b/tests/stm32/src/bin/stop.rs
@@ -0,0 +1,71 @@
1// required-features: stop,chrono
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use chrono::NaiveDate;
10use common::*;
11use cortex_m_rt::entry;
12use embassy_executor::Spawner;
13use embassy_stm32::low_power::{stop_with_rtc, Executor};
14use embassy_stm32::rcc::RtcClockSource;
15use embassy_stm32::rtc::{Rtc, RtcConfig};
16use embassy_stm32::time::Hertz;
17use embassy_time::{Duration, Timer};
18use static_cell::make_static;
19
20#[entry]
21fn main() -> ! {
22 Executor::take().run(|spawner| {
23 unwrap!(spawner.spawn(async_main(spawner)));
24 });
25}
26
27#[embassy_executor::task]
28async fn task_1() {
29 for _ in 0..9 {
30 info!("task 1: waiting for 500ms...");
31 Timer::after(Duration::from_millis(500)).await;
32 }
33}
34
35#[embassy_executor::task]
36async fn task_2() {
37 for _ in 0..5 {
38 info!("task 2: waiting for 1000ms...");
39 Timer::after(Duration::from_millis(1000)).await;
40 }
41
42 info!("Test OK");
43 cortex_m::asm::bkpt();
44}
45
46#[embassy_executor::task]
47async fn async_main(spawner: Spawner) {
48 let mut config = config();
49
50 config.rcc.lse = Some(Hertz(32_768));
51 config.rcc.rtc = Some(RtcClockSource::LSE);
52
53 let p = embassy_stm32::init(config);
54 info!("Hello World!");
55
56 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
57 .unwrap()
58 .and_hms_opt(10, 30, 15)
59 .unwrap();
60
61 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
62
63 rtc.set_datetime(now.into()).expect("datetime not set");
64
65 let rtc = make_static!(rtc);
66
67 stop_with_rtc(rtc);
68
69 spawner.spawn(task_1()).unwrap();
70 spawner.spawn(task_2()).unwrap();
71}
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 394005b82..74a81b4ec 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -5,38 +5,11 @@
5mod common; 5mod common;
6 6
7use common::*; 7use common::*;
8use defmt::assert_eq; 8use defmt::{assert, assert_eq, unreachable};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
11use embassy_stm32::usart::{Config, Error, Uart}; 11use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
12use embassy_stm32::{bind_interrupts, peripherals, usart}; 12use embassy_time::{block_for, Duration, Instant};
13use embassy_time::{Duration, Instant};
14
15#[cfg(any(
16 feature = "stm32f103c8",
17 feature = "stm32g491re",
18 feature = "stm32g071rb",
19 feature = "stm32h755zi",
20 feature = "stm32c031c6",
21))]
22bind_interrupts!(struct Irqs {
23 USART1 => usart::InterruptHandler<peripherals::USART1>;
24});
25
26#[cfg(feature = "stm32u585ai")]
27bind_interrupts!(struct Irqs {
28 USART3 => usart::InterruptHandler<peripherals::USART3>;
29});
30
31#[cfg(feature = "stm32f429zi")]
32bind_interrupts!(struct Irqs {
33 USART6 => usart::InterruptHandler<peripherals::USART6>;
34});
35
36#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
37bind_interrupts!(struct Irqs {
38 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
39});
40 13
41#[embassy_executor::main] 14#[embassy_executor::main]
42async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
@@ -45,28 +18,14 @@ async fn main(_spawner: Spawner) {
45 18
46 // Arduino pins D0 and D1 19 // Arduino pins D0 and D1
47 // They're connected together with a 1K resistor. 20 // They're connected together with a 1K resistor.
48 #[cfg(feature = "stm32f103c8")] 21 let mut usart = peri!(p, UART);
49 let (mut tx, mut rx, mut usart) = (p.PA9, p.PA10, p.USART1); 22 let mut rx = peri!(p, UART_RX);
50 #[cfg(feature = "stm32g491re")] 23 let mut tx = peri!(p, UART_TX);
51 let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1); 24 let irq = irqs!(UART);
52 #[cfg(feature = "stm32g071rb")]
53 let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1);
54 #[cfg(feature = "stm32f429zi")]
55 let (mut tx, mut rx, mut usart) = (p.PG14, p.PG9, p.USART6);
56 #[cfg(feature = "stm32wb55rg")]
57 let (mut tx, mut rx, mut usart) = (p.PA2, p.PA3, p.LPUART1);
58 #[cfg(feature = "stm32h755zi")]
59 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1);
60 #[cfg(feature = "stm32u585ai")]
61 let (mut tx, mut rx, mut usart) = (p.PD8, p.PD9, p.USART3);
62 #[cfg(feature = "stm32h563zi")]
63 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.LPUART1);
64 #[cfg(feature = "stm32c031c6")]
65 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1);
66 25
67 { 26 {
68 let config = Config::default(); 27 let config = Config::default();
69 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); 28 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap();
70 29
71 // We can't send too many bytes, they have to fit in the FIFO. 30 // We can't send too many bytes, they have to fit in the FIFO.
72 // This is because we aren't sending+receiving at the same time. 31 // This is because we aren't sending+receiving at the same time.
@@ -82,13 +41,19 @@ async fn main(_spawner: Spawner) {
82 // Test error handling with with an overflow error 41 // Test error handling with with an overflow error
83 { 42 {
84 let config = Config::default(); 43 let config = Config::default();
85 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); 44 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap();
86 45
87 // Send enough bytes to fill the RX FIFOs off all USART versions. 46 // Send enough bytes to fill the RX FIFOs off all USART versions.
88 let data = [0xC0, 0xDE, 0x12, 0x23, 0x34]; 47 let data = [0; 64];
89 usart.blocking_write(&data).unwrap(); 48 usart.blocking_write(&data).unwrap();
90 usart.blocking_flush().unwrap(); 49 usart.blocking_flush().unwrap();
91 50
51 // USART can still take up to 1 bit time (?) to receive the last byte
52 // that we just flushed, so wait a bit.
53 // otherwise, we might clear the overrun flag from an *earlier* byte and
54 // it gets set again when receiving the last byte is done.
55 block_for(Duration::from_millis(1));
56
92 // The error should be reported first. 57 // The error should be reported first.
93 let mut buf = [0; 1]; 58 let mut buf = [0; 1];
94 let err = usart.blocking_read(&mut buf); 59 let err = usart.blocking_read(&mut buf);
@@ -101,22 +66,25 @@ async fn main(_spawner: Spawner) {
101 66
102 // Test that baudrate divider is calculated correctly. 67 // Test that baudrate divider is calculated correctly.
103 // Do it by comparing the time it takes to send a known number of bytes. 68 // Do it by comparing the time it takes to send a known number of bytes.
104 for baudrate in [ 69 for baudrate in [300, 9600, 115200, 250_000, 337_934, 1_000_000, 2_000_000] {
105 300,
106 9600,
107 115200,
108 250_000,
109 337_934,
110 #[cfg(not(feature = "stm32f103c8"))]
111 1_000_000,
112 #[cfg(not(feature = "stm32f103c8"))]
113 2_000_000,
114 ] {
115 info!("testing baudrate {}", baudrate); 70 info!("testing baudrate {}", baudrate);
116 71
117 let mut config = Config::default(); 72 let mut config = Config::default();
118 config.baudrate = baudrate; 73 config.baudrate = baudrate;
119 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); 74 let mut usart = match Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config) {
75 Ok(x) => x,
76 Err(ConfigError::BaudrateTooHigh) => {
77 info!("baudrate too high");
78 assert!(baudrate >= 1_000_000);
79 continue;
80 }
81 Err(ConfigError::BaudrateTooLow) => {
82 info!("baudrate too low");
83 assert!(baudrate <= 300);
84 continue;
85 }
86 Err(_) => unreachable!(),
87 };
120 88
121 let n = (baudrate as usize / 100).max(64); 89 let n = (baudrate as usize / 100).max(64);
122 90
@@ -124,6 +92,7 @@ async fn main(_spawner: Spawner) {
124 for _ in 0..n { 92 for _ in 0..n {
125 usart.blocking_write(&[0x00]).unwrap(); 93 usart.blocking_write(&[0x00]).unwrap();
126 } 94 }
95 usart.blocking_flush().unwrap();
127 let dur = Instant::now() - start; 96 let dur = Instant::now() - start;
128 let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64)); 97 let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
129 let fuzz = want_dur / 5; 98 let fuzz = want_dur / 5;
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index c34d9574b..1421f6605 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -9,33 +9,6 @@ use defmt::assert_eq;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_futures::join::join; 10use embassy_futures::join::join;
11use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
12use embassy_stm32::{bind_interrupts, peripherals, usart};
13
14#[cfg(any(
15 feature = "stm32f103c8",
16 feature = "stm32g491re",
17 feature = "stm32g071rb",
18 feature = "stm32h755zi",
19 feature = "stm32c031c6",
20))]
21bind_interrupts!(struct Irqs {
22 USART1 => usart::InterruptHandler<peripherals::USART1>;
23});
24
25#[cfg(feature = "stm32u585ai")]
26bind_interrupts!(struct Irqs {
27 USART3 => usart::InterruptHandler<peripherals::USART3>;
28});
29
30#[cfg(feature = "stm32f429zi")]
31bind_interrupts!(struct Irqs {
32 USART6 => usart::InterruptHandler<peripherals::USART6>;
33});
34
35#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
36bind_interrupts!(struct Irqs {
37 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
38});
39 12
40#[embassy_executor::main] 13#[embassy_executor::main]
41async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
@@ -44,27 +17,15 @@ async fn main(_spawner: Spawner) {
44 17
45 // Arduino pins D0 and D1 18 // Arduino pins D0 and D1
46 // They're connected together with a 1K resistor. 19 // They're connected together with a 1K resistor.
47 #[cfg(feature = "stm32f103c8")] 20 let usart = peri!(p, UART);
48 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, Irqs, p.DMA1_CH4, p.DMA1_CH5); 21 let rx = peri!(p, UART_RX);
49 #[cfg(feature = "stm32g491re")] 22 let tx = peri!(p, UART_TX);
50 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); 23 let rx_dma = peri!(p, UART_RX_DMA);
51 #[cfg(feature = "stm32g071rb")] 24 let tx_dma = peri!(p, UART_TX_DMA);
52 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); 25 let irq = irqs!(UART);
53 #[cfg(feature = "stm32f429zi")]
54 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, Irqs, p.DMA2_CH6, p.DMA2_CH1);
55 #[cfg(feature = "stm32wb55rg")]
56 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
57 #[cfg(feature = "stm32h755zi")]
58 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH0, p.DMA1_CH1);
59 #[cfg(feature = "stm32u585ai")]
60 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1);
61 #[cfg(feature = "stm32h563zi")]
62 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.LPUART1, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1);
63 #[cfg(feature = "stm32c031c6")]
64 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
65 26
66 let config = Config::default(); 27 let config = Config::default();
67 let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); 28 let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config).unwrap();
68 29
69 const LEN: usize = 128; 30 const LEN: usize = 128;
70 let mut tx_buf = [0; LEN]; 31 let mut tx_buf = [0; LEN];
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index c8dd2643b..1ee7e596d 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -10,87 +10,10 @@ use common::*;
10use defmt::{assert_eq, panic}; 10use defmt::{assert_eq, panic};
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; 12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
13use embassy_stm32::{bind_interrupts, peripherals, usart};
14use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
15use rand_chacha::ChaCha8Rng; 14use rand_chacha::ChaCha8Rng;
16use rand_core::{RngCore, SeedableRng}; 15use rand_core::{RngCore, SeedableRng};
17 16
18#[cfg(any(
19 feature = "stm32f103c8",
20 feature = "stm32g491re",
21 feature = "stm32g071rb",
22 feature = "stm32h755zi",
23 feature = "stm32c031c6",
24))]
25bind_interrupts!(struct Irqs {
26 USART1 => usart::InterruptHandler<peripherals::USART1>;
27});
28
29#[cfg(feature = "stm32u585ai")]
30bind_interrupts!(struct Irqs {
31 USART3 => usart::InterruptHandler<peripherals::USART3>;
32});
33
34#[cfg(feature = "stm32f429zi")]
35bind_interrupts!(struct Irqs {
36 USART1 => usart::InterruptHandler<peripherals::USART1>;
37 USART6 => usart::InterruptHandler<peripherals::USART6>;
38});
39
40#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
41bind_interrupts!(struct Irqs {
42 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
43});
44
45#[cfg(feature = "stm32f103c8")]
46mod board {
47 pub type Uart = embassy_stm32::peripherals::USART1;
48 pub type TxDma = embassy_stm32::peripherals::DMA1_CH4;
49 pub type RxDma = embassy_stm32::peripherals::DMA1_CH5;
50}
51#[cfg(feature = "stm32g491re")]
52mod board {
53 pub type Uart = embassy_stm32::peripherals::USART1;
54 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
55 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
56}
57#[cfg(feature = "stm32g071rb")]
58mod board {
59 pub type Uart = embassy_stm32::peripherals::USART1;
60 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
61 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
62}
63#[cfg(feature = "stm32f429zi")]
64mod board {
65 pub type Uart = embassy_stm32::peripherals::USART6;
66 pub type TxDma = embassy_stm32::peripherals::DMA2_CH6;
67 pub type RxDma = embassy_stm32::peripherals::DMA2_CH1;
68}
69#[cfg(feature = "stm32wb55rg")]
70mod board {
71 pub type Uart = embassy_stm32::peripherals::LPUART1;
72 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
73 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
74}
75#[cfg(feature = "stm32h755zi")]
76mod board {
77 pub type Uart = embassy_stm32::peripherals::USART1;
78 pub type TxDma = embassy_stm32::peripherals::DMA1_CH0;
79 pub type RxDma = embassy_stm32::peripherals::DMA1_CH1;
80}
81#[cfg(feature = "stm32u585ai")]
82mod board {
83 pub type Uart = embassy_stm32::peripherals::USART3;
84 pub type TxDma = embassy_stm32::peripherals::GPDMA1_CH0;
85 pub type RxDma = embassy_stm32::peripherals::GPDMA1_CH1;
86}
87#[cfg(feature = "stm32c031c6")]
88mod board {
89 pub type Uart = embassy_stm32::peripherals::USART1;
90 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
91 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
92}
93
94const DMA_BUF_SIZE: usize = 256; 17const DMA_BUF_SIZE: usize = 256;
95 18
96#[embassy_executor::main] 19#[embassy_executor::main]
@@ -100,22 +23,12 @@ async fn main(spawner: Spawner) {
100 23
101 // Arduino pins D0 and D1 24 // Arduino pins D0 and D1
102 // They're connected together with a 1K resistor. 25 // They're connected together with a 1K resistor.
103 #[cfg(feature = "stm32f103c8")] 26 let usart = peri!(p, UART);
104 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); 27 let rx = peri!(p, UART_RX);
105 #[cfg(feature = "stm32g491re")] 28 let tx = peri!(p, UART_TX);
106 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); 29 let rx_dma = peri!(p, UART_RX_DMA);
107 #[cfg(feature = "stm32g071rb")] 30 let tx_dma = peri!(p, UART_TX_DMA);
108 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); 31 let irq = irqs!(UART);
109 #[cfg(feature = "stm32f429zi")]
110 let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1);
111 #[cfg(feature = "stm32wb55rg")]
112 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2);
113 #[cfg(feature = "stm32h755zi")]
114 let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1);
115 #[cfg(feature = "stm32u585ai")]
116 let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1);
117 #[cfg(feature = "stm32c031c6")]
118 let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
119 32
120 // To run this test, use the saturating_serial test utility to saturate the serial port 33 // To run this test, use the saturating_serial test utility to saturate the serial port
121 34
@@ -127,7 +40,7 @@ async fn main(spawner: Spawner) {
127 config.stop_bits = StopBits::STOP1; 40 config.stop_bits = StopBits::STOP1;
128 config.parity = Parity::ParityNone; 41 config.parity = Parity::ParityNone;
129 42
130 let usart = Uart::new(usart, rx, tx, Irqs, tx_dma, rx_dma, config); 43 let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config).unwrap();
131 let (tx, rx) = usart.split(); 44 let (tx, rx) = usart.split();
132 static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; 45 static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE];
133 let dma_buf = unsafe { DMA_BUF.as_mut() }; 46 let dma_buf = unsafe { DMA_BUF.as_mut() };
@@ -139,7 +52,7 @@ async fn main(spawner: Spawner) {
139} 52}
140 53
141#[embassy_executor::task] 54#[embassy_executor::task]
142async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { 55async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) {
143 // workaround https://github.com/embassy-rs/embassy/issues/1426 56 // workaround https://github.com/embassy-rs/embassy/issues/1426
144 Timer::after(Duration::from_millis(100) as _).await; 57 Timer::after(Duration::from_millis(100) as _).await;
145 58
@@ -162,7 +75,7 @@ async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
162} 75}
163 76
164#[embassy_executor::task] 77#[embassy_executor::task]
165async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::RxDma>) { 78async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART, peris::UART_RX_DMA>) {
166 info!("Ready to receive..."); 79 info!("Ready to receive...");
167 80
168 let mut rng = ChaCha8Rng::seed_from_u64(1337); 81 let mut rng = ChaCha8Rng::seed_from_u64(1337);
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index ca5cb43ac..9c0b8c39e 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -24,6 +24,131 @@ teleprobe_meta::target!(b"iot-stm32u585ai");
24teleprobe_meta::target!(b"nucleo-stm32h563zi"); 24teleprobe_meta::target!(b"nucleo-stm32h563zi");
25#[cfg(feature = "stm32c031c6")] 25#[cfg(feature = "stm32c031c6")]
26teleprobe_meta::target!(b"nucleo-stm32c031c6"); 26teleprobe_meta::target!(b"nucleo-stm32c031c6");
27#[cfg(feature = "stm32l073rz")]
28teleprobe_meta::target!(b"nucleo-stm32l073rz");
29#[cfg(feature = "stm32l152re")]
30teleprobe_meta::target!(b"nucleo-stm32l152re");
31#[cfg(feature = "stm32l4a6zg")]
32teleprobe_meta::target!(b"nucleo-stm32l4a6zg");
33#[cfg(feature = "stm32l4r5zi")]
34teleprobe_meta::target!(b"nucleo-stm32l4r5zi");
35#[cfg(feature = "stm32l552ze")]
36teleprobe_meta::target!(b"nucleo-stm32l552ze");
37
38macro_rules! define_peris {
39 ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => {
40 #[allow(unused_macros)]
41 macro_rules! peri {
42 $(
43 ($p:expr, $name) => {
44 $p.$peri
45 };
46 )*
47 }
48 #[allow(unused_macros)]
49 macro_rules! irqs {
50 $(
51 ($irq_name) => {{
52 embassy_stm32::bind_interrupts!(struct Irqs $irq_code);
53 Irqs
54 }};
55 )*
56 }
57
58 #[allow(unused)]
59 #[allow(non_camel_case_types)]
60 pub mod peris {
61 $(
62 pub type $name = embassy_stm32::peripherals::$peri;
63 )*
64 }
65 };
66}
67
68#[cfg(feature = "stm32f103c8")]
69define_peris!(
70 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
71 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
72 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
73);
74#[cfg(feature = "stm32g491re")]
75define_peris!(
76 UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
77 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
78 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
79);
80#[cfg(feature = "stm32g071rb")]
81define_peris!(
82 UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
83 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
84 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
85);
86#[cfg(feature = "stm32f429zi")]
87define_peris!(
88 UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1,
89 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
90 @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;},
91);
92#[cfg(feature = "stm32wb55rg")]
93define_peris!(
94 UART = LPUART1, UART_TX = PA2, UART_RX = PA3, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
95 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
96 @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::LPUART1>;},
97);
98#[cfg(feature = "stm32h755zi")]
99define_peris!(
100 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1,
101 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1,
102 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
103);
104#[cfg(feature = "stm32u585ai")]
105define_peris!(
106 UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1,
107 SPI = SPI1, SPI_SCK = PE13, SPI_MOSI = PE15, SPI_MISO = PE14, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1,
108 @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
109);
110#[cfg(feature = "stm32h563zi")]
111define_peris!(
112 UART = LPUART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1,
113 SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1,
114 @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::LPUART1>;},
115);
116#[cfg(feature = "stm32c031c6")]
117define_peris!(
118 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
119 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
120 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
121);
122#[cfg(feature = "stm32l4a6zg")]
123define_peris!(
124 UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3,
125 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
126 @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
127);
128#[cfg(feature = "stm32l4r5zi")]
129define_peris!(
130 UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
131 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
132 @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
133);
134#[cfg(feature = "stm32l073rz")]
135define_peris!(
136 UART = USART4, UART_TX = PA0, UART_RX = PA1, UART_TX_DMA = DMA1_CH3, UART_RX_DMA = DMA1_CH2,
137 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
138 @irq UART = {USART4_5 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART4>;},
139);
140#[cfg(feature = "stm32l152re")]
141define_peris!(
142 UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3,
143 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
144 @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
145);
146#[cfg(feature = "stm32l552ze")]
147define_peris!(
148 UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
149 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
150 @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
151);
27 152
28pub fn config() -> Config { 153pub fn config() -> Config {
29 #[allow(unused_mut)] 154 #[allow(unused_mut)]
@@ -31,14 +156,86 @@ pub fn config() -> Config {
31 156
32 #[cfg(feature = "stm32h755zi")] 157 #[cfg(feature = "stm32h755zi")]
33 { 158 {
34 config.rcc.sys_ck = Some(Hertz(400_000_000)); 159 use embassy_stm32::rcc::*;
35 config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); 160 config.rcc.hsi = Some(Hsi::Mhz64);
36 config.rcc.adc_clock_source = embassy_stm32::rcc::AdcClockSource::PerCk; 161 config.rcc.csi = true;
162 config.rcc.pll_src = PllSource::Hsi;
163 config.rcc.pll1 = Some(Pll {
164 prediv: 4,
165 mul: 50,
166 divp: Some(2),
167 divq: Some(8), // SPI1 cksel defaults to pll1_q
168 divr: None,
169 });
170 config.rcc.pll2 = Some(Pll {
171 prediv: 4,
172 mul: 50,
173 divp: Some(8), // 100mhz
174 divq: None,
175 divr: None,
176 });
177 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
178 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
179 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
180 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
181 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
182 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
183 config.rcc.voltage_scale = VoltageScale::Scale1;
184 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
185 }
186
187 #[cfg(any(feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
188 {
189 use embassy_stm32::rcc::*;
190 config.rcc.mux = ClockSrc::PLL(
191 // 72Mhz clock (16 / 1 * 18 / 4)
192 PLLSource::HSI16,
193 PLLClkDiv::Div4,
194 PLLSrcDiv::Div1,
195 PLLMul::Mul18,
196 Some(PLLClkDiv::Div6), // 48Mhz (16 / 1 * 18 / 6)
197 );
198 }
199
200 #[cfg(any(feature = "stm32l552ze"))]
201 {
202 use embassy_stm32::rcc::*;
203 config.rcc.mux = ClockSrc::PLL(
204 // 110Mhz clock (16 / 4 * 55 / 2)
205 PLLSource::HSI16,
206 PLLClkDiv::Div2,
207 PLLSrcDiv::Div4,
208 PLLMul::Mul55,
209 None,
210 );
37 } 211 }
38 212
39 #[cfg(feature = "stm32u585ai")] 213 #[cfg(feature = "stm32u585ai")]
40 { 214 {
41 config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz); 215 use embassy_stm32::rcc::*;
216 config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
217 }
218
219 #[cfg(feature = "stm32l073rz")]
220 {
221 use embassy_stm32::rcc::*;
222 config.rcc.mux = ClockSrc::PLL(
223 // 32Mhz clock (16 * 4 / 2)
224 PLLSource::HSI16,
225 PLLMul::Mul4,
226 PLLDiv::Div2,
227 );
228 }
229
230 #[cfg(any(feature = "stm32l152re"))]
231 {
232 use embassy_stm32::rcc::*;
233 config.rcc.mux = ClockSrc::PLL(
234 // 32Mhz clock (16 * 4 / 2)
235 PLLSource::HSI,
236 PLLMul::Mul4,
237 PLLDiv::Div2,
238 );
42 } 239 }
43 240
44 config 241 config